davix-0.8.0/0000755000000000000000000000000014121063464011331 5ustar rootrootdavix-0.8.0/version.cmake.in0000644000000000000000000000026514121063315014423 0ustar rootrootset(VERSION_MAJOR @VERSION_MAJOR@) set(VERSION_MINOR @VERSION_MINOR@) set(VERSION_PATCH @VERSION_PATCH@) set(VERSION_MINIPATCH @VERSION_MINIPATCH@) set(VERSION_FULL @VERSION_FULL@) davix-0.8.0/CMakeLists.txt0000644000000000000000000001305214121063315014065 0ustar rootroot#------------------------------------------------------------------------------- # Initialize #------------------------------------------------------------------------------- cmake_minimum_required (VERSION 3.0) project (davix) #------------------------------------------------------------------------------- # Find the python executable to use during the build #------------------------------------------------------------------------------- find_package(PythonInterp REQUIRED) #------------------------------------------------------------------------------- # Regenerate include/davix/features.hpp and version.cmake at _build_ time #------------------------------------------------------------------------------- add_custom_target(GenerateVersionInfo ALL DEPENDS Version) add_custom_command( OUTPUT Version COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genversion.py --template include/davix/features.hpp.in --out include/davix/features.hpp COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genversion.py --template version.cmake.in --out version.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) #------------------------------------------------------------------------------- # Regenerate version.cmake at _configure_ time. Important since the above # only regenerates it at compile time. #------------------------------------------------------------------------------- execute_process( COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genversion.py --template version.cmake.in --out version.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) #------------------------------------------------------------------------------- # Include version.cmake. Whenever the version changes, ie you commit or tag, # the following happens: # - Next time you run 'make', version.cmake is updated. # - The next 'make' will detect version.cmake was changed, and cmake will # reconfigure itself. # # A bit hacky. #------------------------------------------------------------------------------- include(${CMAKE_CURRENT_SOURCE_DIR}/release.cmake REQUIRED) include(${CMAKE_CURRENT_SOURCE_DIR}/version.cmake OPTIONAL) message("Configuring cmake for davix version: ${VERSION_FULL}") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") option(SHARED_LIBRARY "generate shared library" TRUE) option(STATIC_LIBRARY "generate static library" FALSE) # build type if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to RelWithDebInfo") set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif(NOT CMAKE_BUILD_TYPE) # load module include(DefineInstallationPaths REQUIRED) include(ReleaseDebugAutoFlags REQUIRED) include(CMakeGeneratePkgConfig REQUIRED) include(MacroAddDoxygen REQUIRED) include(CMakeCXX11Support REQUIRED) include(PortabilityGNUCheck REQUIRED) set(OUTPUT_NAME_DAVIX "davix") # components option(ENABLE_TOOLS "enable or disable tools " TRUE) option(ENABLE_HTML_DOCS "enable or disable generation of HTML documentation" FALSE) option(EMBEDDED_LIBCURL "Use embedded libcurl" TRUE) option(LIBCURL_BACKEND_BY_DEFAULT "Use libcurl by default" FALSE) # features option(ENABLE_IPV6 "enable or disable IPv6 support " TRUE) option(ENABLE_TCP_NODELAY "enable or disable tcp_nodelay" TRUE) option(ENABLE_THIRD_PARTY_COPY "enable or disable third party copy support" FALSE) # tests option(BENCH_TESTS "enable or disable the bench tests" FALSE) option(DAVIX_TESTS "Flag to disable the building of all tests" TRUE) # libs checks find_package(Threads) # openssl find_package(OpenSSL) SET(LIBSSL_PKG_LIBRARIES "${OPENSSL_LIBRARIES}") SET(LIBSSL_PKG_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}") find_package(LibXml2) set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR}) #const set(HAVE_OPENSSL 1) set(NE_HAVE_SSL 1) add_subdirectory(deps) #libuuid if(NOT APPLE) find_package(uuid) endif() ## general defs add_definitions( -D_GNU_SOURCE) # GNU source, import LFS, etc... add_definitions( -D__DAVIX_INSIDE__) # protection flag add_definitions( -D__STDC_LIMIT_MACROS ) # C99 limit macros set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAG_ENABLE}") #------------------------------------------------------------------------------- # Are we using system, or embedded libcurl? #------------------------------------------------------------------------------- if(EMBEDDED_LIBCURL) include(buildCurl REQUIRED) buildCurl() endif() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/deps/libneon/src/ ${UUID_INCLUDE_DIRS}) include_directories(${CMAKE_SOURCE_DIR}/include/davix) add_subdirectory (src) add_subdirectory (doc) if(EXISTS "${CMAKE_SOURCE_DIR}/dist/CMakeLists.txt") add_subdirectory (dist) endif() if(DAVIX_TESTS) add_subdirectory (test) endif() ############################################################################# ## headers configure_file("${CMAKE_SOURCE_DIR}/include/davix/features.hpp.in" "${CMAKE_SOURCE_DIR}/include/davix/features.hpp" @ONLY) install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/davix/ DESTINATION ${INCLUDE_INSTALL_DIR}/davix PATTERN "*.in" EXCLUDE) ############################################################################## ## Doc file install(FILES RELEASE-NOTES.md LICENSE DESTINATION ${DOC_INSTALL_DIR}/) # install release notes ####################################################### # Configure an 'uninstall' target CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) # ADD_CUSTOM_TARGET(uninstall # "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") davix-0.8.0/test/0000755000000000000000000000000014121063315012303 5ustar rootrootdavix-0.8.0/test/TestcaseHandler.hpp0000644000000000000000000000736714121063315016102 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_TESTCASE_HANDLER_HPP #define DAVIX_TEST_TESTCASE_HANDLER_HPP #include #include #include #include namespace Davix { class DavixError; } class TermFormat { public: static std::string blue(const std::string &msg); static std::string green(const std::string &msg); static std::string purple(const std::string &msg); static std::string red(const std::string &msg); }; class TestcaseHandler { public: //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- TestcaseHandler(TestcaseHandler *parent = NULL); //---------------------------------------------------------------------------- // Set name //---------------------------------------------------------------------------- void setName(const std::string &name); //---------------------------------------------------------------------------- // Log info //---------------------------------------------------------------------------- void info(const std::string &msg); //---------------------------------------------------------------------------- // Check condition //---------------------------------------------------------------------------- void check(bool check, const std::string &msg); //---------------------------------------------------------------------------- // Log successful check //---------------------------------------------------------------------------- void pass(const std::string &msg); //---------------------------------------------------------------------------- // Log error, fail the test //---------------------------------------------------------------------------- void fail(const std::string &msg); //---------------------------------------------------------------------------- // Get nest level //---------------------------------------------------------------------------- size_t getNestLevel() const; //---------------------------------------------------------------------------- // Test ok so far? //---------------------------------------------------------------------------- bool ok() const; //---------------------------------------------------------------------------- // Ensure no davix error occured //---------------------------------------------------------------------------- bool checkDavixError(Davix::DavixError **err); //---------------------------------------------------------------------------- // Make child //---------------------------------------------------------------------------- TestcaseHandler& makeChild(); private: std::string mTestcaseName; TestcaseHandler *mParent; bool mFailed; size_t mLevel; std::string mLinePrefix; std::string mLinePrefixLog; std::vector> mChildren; }; #endif davix-0.8.0/test/CMakeLists.txt0000644000000000000000000000073514121063315015050 0ustar rootroot# main file for src # force RPATH usage for easy test execution set(CMAKE_SKIP_RPATH OFF CACHE BOOL "" FORCE) include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src/) link_directories(${PROJECT_BINARY_DIR}/src/) set(TEST_CRED_PATH "${CMAKE_CURRENT_SOURCE_DIR}/certs/my_keycert.p12") set(TEST_CRED_PASS "testpass") add_subdirectory(unit) add_subdirectory(slow-unit) add_subdirectory(functional) add_subdirectory(root-tests) add_subdirectory(bench) davix-0.8.0/test/run-in-mock.sh0000755000000000000000000000333714121063315015007 0ustar rootroot#!/usr/bin/env bash # Must be run from the top-level directory of the repository # ie ~/dev/davix, NOT ~/dev/davix/test # Defaults MOCK_CONFIG_DIR="/etc/mock" MOCK_ROOT="epel-6-x86_64" SKIP_INIT=0 OUTPUT_DIR="$PWD/test-results" # Get parameters while [ -n "$1" ]; do case "$1" in "--configdir") shift MOCK_CONFIG_DIR=$1 ;; "--root") shift MOCK_ROOT=$1 ;; "--skip-init") SKIP_INIT=1 ;; "--output") shift OUTPUT_DIR=$1 ;; *) echo "Unknown parameter $1" exit 1 ;; esac shift done # Feedback echo "# Mock config dir: ${MOCK_CONFIG_DIR}" echo "# Mock root: ${MOCK_ROOT}" # Run inside mock function mock_cmd() { /usr/bin/mock -v --configdir "${MOCK_CONFIG_DIR}" -r "${MOCK_ROOT}" --disable-plugin=tmpfs "$@" } # Prepare environment if [ $SKIP_INIT == 0 ]; then mock_cmd clean mock_cmd init else echo "Skipping initialization" fi # Install deps mock_cmd install cmake git yum-utils abi-compliance-checker doxygen gsoap-devel libxml2-devel openssl-devel voms-clients libuuid-devel MOCK_HOME="/builddir" # copy grid-security and vomses mock_cmd chroot "rm -rf /etc/grid-security /etc/vomses" mock_cmd --copyin "/etc/grid-security" "/etc/grid-security" mock_cmd --copyin "/etc/vomses" "/etc/vomses" # Copy davix codebase to chroot mock_cmd chroot "rm -rf $MOCK_HOME/davix" mock_cmd --copyin "$PWD" "$MOCK_HOME/davix" # run tests mock_cmd chroot "cd $MOCK_HOME/davix && test/run-tests.sh" # Recover logs mkdir -p "${OUTPUT_DIR}" rm -rf "${OUTPUT_DIR}/Testing" mock_cmd --copyout "$MOCK_HOME/davix/build/Testing" "${OUTPUT_DIR}/Testing" davix-0.8.0/test/bench_inputfile_gen.sh0000755000000000000000000000063314121063315016633 0ustar rootroot#!/bin/bash # # Generates an input file for davix-bench, containing a fixed number of line, with 2 random numbers on each line. # echo "Running script..." for i in {1..100}; do n=$(shuf -i 1-10000 -n 1); m=$(shuf -i 1-$n -n 1); echo "$n $m">>../build/test/bench/inputfile.txt; done #for i in {1..10000}; # do n=$(( (RANDOM % 10000) +1)); m=$(( (RANDOM % n) +1)); # echo "$n $m">>inputfile.txt; #done davix-0.8.0/test/drunk-server/0000755000000000000000000000000014121063315014732 5ustar rootrootdavix-0.8.0/test/drunk-server/EventFD.hh0000644000000000000000000000431714121063315016553 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_EVENT_FD_HPP #define DAVIX_TEST_EVENT_FD_HPP #include #include #include #include #include class EventFD { public: EventFD() { int status = pipe(fildes); if(status != 0) { std::cerr << "davix: CRITICAL: Could not obtain file descriptors for EventFD class, errno = " << errno << std::endl; std::abort(); } for(size_t i = 0; i < 2; i++) { int flags = fcntl(fildes[i], F_GETFL, 0); int status = fcntl(fildes[i], F_SETFL, flags | O_NONBLOCK); if(status != 0) { std::cerr << "davix: CRITICAL: Could not set file descriptor as non-blocking" << std::endl; std::abort(); } } } ~EventFD() { close(); } void close() { ::close(fildes[0]); ::close(fildes[1]); } void notify() { char val = 1; int rc = write(fildes[1], &val, sizeof(val)); if (rc != sizeof(val)) { std::cerr << "davix: CRITICAL: could not write to EventFD pipe, return code " << rc << ": " << strerror(errno) << std::endl; } } inline int getFD() const { return fildes[0]; } void clear() { while(true) { char buffer[128]; int rc = ::read(fildes[0], buffer, 64); if(rc <= 0) { break; } } } private: int fildes[2]; }; #endif davix-0.8.0/test/drunk-server/Synchronized.hpp0000644000000000000000000000235714121063315020131 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_SYNCHRONIZED_HPP #define DAVIX_TEST_SYNCHRONIZED_HPP #include template class Synchronized { public: T get() { std::lock_guard lock(_mtx); return _val; } void set(const T& v) { std::lock_guard lock(_mtx); _val = v; } private: std::mutex _mtx; T _val; }; #endif davix-0.8.0/test/drunk-server/LineReader.hpp0000644000000000000000000000361314121063315017460 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_LINE_READER_HPP #define DAVIX_TEST_LINE_READER_HPP #include #include #include #include "DrunkServer.hpp" //------------------------------------------------------------------------------ // Wrap a connection object, allow more comfortable reading of the contents //------------------------------------------------------------------------------ class LineReader { public: //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- LineReader(DrunkServer::Connection *conn); //---------------------------------------------------------------------------- // Consume a single line from the link. // Returns 0 on "no available data", negative on error. //---------------------------------------------------------------------------- int consumeLine(std::string &output); private: DrunkServer::Connection *_conn; std::ostringstream _ss; }; #endif davix-0.8.0/test/drunk-server/LineReader.cpp0000644000000000000000000000336314121063315017455 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "LineReader.hpp" //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ LineReader::LineReader(DrunkServer::Connection *c) : _conn(c) {} //------------------------------------------------------------------------------ // Consume a single line from the link. // Returns 0 on "no available data", negative on error. //------------------------------------------------------------------------------ int LineReader::consumeLine(std::string &output) { char buff[10]; while(true) { buff[0] = '\0'; buff[1] = '\0'; int retval = _conn->read(buff, 1); if(retval != 1) { return retval; } _ss << buff[0]; if(buff[0] == '\n') { output = _ss.str(); _ss.str(std::string()); return 1; } } } davix-0.8.0/test/drunk-server/AssistedThread.hh0000644000000000000000000001714514121063315020172 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_ASSISTED_THREAD_HPP #define DAVIX_TEST_ASSISTED_THREAD_HPP #include "Synchronized.hpp" #include #include #include #include #include //------------------------------------------------------------------------------ // C++ threads offer no easy way to stop a thread once it's started. Signalling // "stop" to a (potentially sleeping) background thread involves a subtle dance // involving a mutex, condition variable, and possibly an atomic. // // Doing this correctly for every thread is a huge pain, which this class // tries to alleviate. // // How to create a thread: Just like std::thread, ie // AssistedThread(&SomeClass::SomeFunction, this, some_int_value) // // The function will receive a thread assistant object as *one extra* // parameter *at the end*, for example: // // void SomeClass::SomeFunction(int some_int_value, ThreadAssistant &assistant) // // The assistant object can then be used to check if thread termination has been // requested, or sleep for a specified amount of time but wake up immediatelly // the moment termination is requested. // // A common pattern for background threads is then: // while(!assistant.terminationRequested()) { // doStuff(); // assistant.sleep_for(std::chrono::seconds(1)); // } //------------------------------------------------------------------------------ class AssistedThread; //------------------------------------------------------------------------------ //! Class ThreadAssistant //------------------------------------------------------------------------------ class ThreadAssistant { public: void reset() { stopFlag.set(false); terminationCallbacks.clear(); } void requestTermination() { std::lock_guard lock(mtx); if(!stopFlag.get()) { stopFlag.set(true); notifier.notify_all(); for(size_t i = 0; i < terminationCallbacks.size(); i++) { terminationCallbacks[i](); } } } void registerCallback(std::function callable) { std::lock_guard lock(mtx); terminationCallbacks.emplace_back(std::move(callable)); if(stopFlag.get()) { //------------------------------------------------------------------------ // Careful here.. This is a race condition where thread termination has // already been requested, even though we're not done yet registering // callbacks, apparently. // // Let's simply call the callback ourselves. //------------------------------------------------------------------------ (terminationCallbacks.back())(); } } void dropCallbacks() { std::lock_guard lock(mtx); terminationCallbacks.clear(); } bool terminationRequested() { return stopFlag.get(); } template void wait_for(T duration) { std::unique_lock lock(mtx); if(stopFlag.get()) return; notifier.wait_for(lock, duration); } template void wait_until(T duration) { std::unique_lock lock(mtx); if(stopFlag.get()) return; notifier.wait_until(lock, duration); } //---------------------------------------------------------------------------- // Ok, this is a bit weird: Consider an AssistedThread which "owns" or // coordinates a bunch of other threads: // // void Coordinator(ThreadAssistant &assistant) { // AssistedThread worker1( ... ); // AssistedThread worker2( ... ); // AssistedThread worker3( ... ); // // worker1.blockUntilThreadJoins(); // worker2.blockUntilThreadJoins(); // worker3.blockUntilThreadJoins(); // } // // We would like that any requests to shut down Coordinator propagate to all // workers. Otherwise, since Coordinator blocks waiting for the workers to // terminate, its own early termination signal would get ignored. // // propagateTerminationSignal does just this. In the above example, call: // assistant.propagateTerminationSignal(worker1); // assistant.propagateTerminationSignal(worker2); // assistant.propagateTerminationSignal(worker3); // // And the moment Coordinator is asked to terminate, all registered threads // will, too. // // NOTE: assistant object must belong to a different thread! //---------------------------------------------------------------------------- void propagateTerminationSignal(AssistedThread &thread); private: // Private constructor - only AssistedThread can create such an object. ThreadAssistant(bool flag) { stopFlag.set(flag); } friend class AssistedThread; Synchronized stopFlag; std::mutex mtx; std::condition_variable notifier; std::vector> terminationCallbacks; }; class AssistedThread { public: //---------------------------------------------------------------------------- //! null constructor, no underlying thread //---------------------------------------------------------------------------- AssistedThread() : assistant(new ThreadAssistant(true)), joined(true) { } //---------------------------------------------------------------------------- // universal references, perfect forwarding, variadic template // (C++ is intensifying) //---------------------------------------------------------------------------- template AssistedThread(Args&&... args) : assistant(new ThreadAssistant(false)), joined(false), th(std::forward(args)..., std::ref(*assistant)) { } // No assignment, no copying AssistedThread& operator=(const AssistedThread&) = delete; // Moving is allowed. AssistedThread(AssistedThread&& other) { assistant = std::move(other.assistant); joined = other.joined; th = std::move(other.th); other.joined = true; } template void reset(Args&&... args) { join(); assistant.get()->reset(); joined = false; th = std::thread(std::forward(args)..., std::ref(*assistant)); } virtual ~AssistedThread() { join(); } void stop() { if(joined) return; assistant->requestTermination(); } void join() { if(joined) return; stop(); blockUntilThreadJoins(); } // Different meaning than join, which explicitly asks the thread to // terminate. Here, we simply wait until the thread exits on its own. void blockUntilThreadJoins() { if(joined) return; th.join(); joined = true; } void registerCallback(std::function callable) { assistant->registerCallback(std::move(callable)); } void dropCallbacks() { assistant->dropCallbacks(); } private: std::unique_ptr assistant; bool joined; std::thread th; }; inline void ThreadAssistant::propagateTerminationSignal(AssistedThread &thread) { registerCallback(std::bind(&AssistedThread::stop, &thread)); } #endif davix-0.8.0/test/drunk-server/Interactors.cpp0000644000000000000000000001021414121063315017731 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "Interactors.hpp" #include "LineReader.hpp" #include //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ BasicInteractor::~BasicInteractor() {} //------------------------------------------------------------------------------ // Take over the specified connection - call only once. Should spawn a // thread in the background for reading / writing on the socket. //------------------------------------------------------------------------------ void BasicInteractor::handleConnection(std::unique_ptr conn) { _conn = std::move(conn); _reader.reset(new LineReader(_conn.get())); _thread.reset(&BasicInteractor::main, this); } //------------------------------------------------------------------------------ // Consume single reader line //------------------------------------------------------------------------------ std::string BasicInteractor::consumeLine() { std::string out; _reader->consumeLine(out); return out; } //------------------------------------------------------------------------------ // Run interacting thread //------------------------------------------------------------------------------ void ConnectionShutdownInteractor::main(ThreadAssistant &assistant) { _reader.reset(); _conn.reset(); } //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ SingleShotInteractor::SingleShotInteractor(const std::string &expectedReq, const std::string &response) : _expected_request(expectedReq), _response(response) {} //------------------------------------------------------------------------------ // Split utility function - move to common header eventually //------------------------------------------------------------------------------ static std::vector split(std::string data, std::string token) { std::vector output; size_t pos = std::string::npos; do { pos = data.find(token); output.push_back(data.substr(0, pos)); if(std::string::npos != pos) data = data.substr(pos + token.size()); } while (std::string::npos != pos); return output; } //------------------------------------------------------------------------------ // Run interacting thread //------------------------------------------------------------------------------ void SingleShotInteractor::main(ThreadAssistant &assistant) { std::vector lines = split(_expected_request, "\r\n"); for(size_t i = 0; i < lines.size(); i++) { if(i == lines.size() - 1 && lines[i].empty()) { break; } std::string line = consumeLine(); std::cerr << "CONSUMED: " << line << std::endl; lines[i] += "\r\n"; if(line != lines[i]) { std::cerr << "MISMATCH" << std::endl; std::cerr << "'" << line << "'" << std::endl; std::cerr << "'" << lines[i] << "'" << std::endl; return; } } std::cout << "WRITING RESPONSE" << std::endl; if(_conn->write(_response) != _response.size()) { std::cout << "Error when writing response" << std::endl; return; } std::cout << "Response written successfully" << std::endl; _is_ok = true; } davix-0.8.0/test/drunk-server/ConnectionInitiator.hpp0000644000000000000000000000365214121063315021433 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_CONNECTION_INITIATOR_HPP #define DAVIX_TEST_CONNECTION_INITIATOR_HPP #include //------------------------------------------------------------------------------ // Class to initiate a synchronous TCP connection towards the specified // host+port. After a successful connection, we do _not_ manage the lifetime // of the file descriptor. //------------------------------------------------------------------------------ class ConnectionInitiator { public: //---------------------------------------------------------------------------- // Connect to a host:port combination, resolve hostname manually. //---------------------------------------------------------------------------- ConnectionInitiator(const std::string &hostname, int port); bool ok() { return (fd > 0) && (localerrno == 0) && (error.empty()); } int getFd() { return fd; } int getErrno() { return localerrno; } std::string getError() { return error; } private: int fd; int localerrno; std::string error; }; #endif davix-0.8.0/test/drunk-server/DrunkServer.cpp0000644000000000000000000001601614121063315017714 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "DrunkServer.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() //------------------------------------------------------------------------------ // Start listening for incoming connections on the given port. //------------------------------------------------------------------------------ DrunkServer::DrunkServer(int port) { struct addrinfo hints, *servinfo, *p; int rv, yes = 1; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, SSTR(port).c_str(), &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); exit(1); } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((_socketFd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("socket"); continue; } if (setsockopt(_socketFd, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } if (bind(_socketFd, p->ai_addr, p->ai_addrlen) == -1) { ::close(_socketFd); perror("bind"); continue; } break; } freeaddrinfo(servinfo); // all done with this structure if (p == NULL) { fprintf(stderr, "server: failed to bind\n"); exit(1); } if (::listen(_socketFd, 10) == -1) { perror("listen"); exit(1); } _acceptor_thread.reset(&DrunkServer::runAcceptorThread, this); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ DrunkServer::~DrunkServer() { ::shutdown(_socketFd, SHUT_RDWR); // kill the socket _shutdown_fd.notify(); ::close(_socketFd); } //------------------------------------------------------------------------------ // Accept a connection - if no clients connect within the given timeout, // we give up and return NULL. //------------------------------------------------------------------------------ std::unique_ptr DrunkServer::accept(int timeoutSeconds) { std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds); while(std::chrono::system_clock::now() < deadline) { std::unique_lock lock(_mtx); if(_overflowFds.size() > 0) { int clientFd = _overflowFds.front(); std::unique_ptr conn = std::unique_ptr(new Connection(clientFd)); _overflowFds.pop_front(); return std::move(conn); } _cv.wait_until(lock, deadline); } return {}; } //------------------------------------------------------------------------------ // Auto-accept next connection with the given interactor //------------------------------------------------------------------------------ void DrunkServer::autoAcceptNext(Interactor *intr) { std::lock_guard lock(_mtx); _interactors.emplace_back(intr); } //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ DrunkServer::Connection::Connection(int fd) : _fd(fd) {} //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- DrunkServer::Connection::~Connection() { ::shutdown(_fd, SHUT_RDWR); ::close(_fd); } //------------------------------------------------------------------------------ // Read into buffer //------------------------------------------------------------------------------ ssize_t DrunkServer::Connection::read(char* buf, size_t count) { return ::read(_fd, buf, count); } //------------------------------------------------------------------------------ // Read into string //------------------------------------------------------------------------------ ssize_t DrunkServer::Connection::read(std::string &buf, size_t count) { buf.resize(count); ssize_t out = read( (char*) buf.c_str(), count); if(out > 0) { buf.resize(out); } return out; } //------------------------------------------------------------------------------ // Write //------------------------------------------------------------------------------ ssize_t DrunkServer::Connection::write(const char* buf, size_t count) { return ::write(_fd, buf, count); } //------------------------------------------------------------------------------ // Write string //------------------------------------------------------------------------------ ssize_t DrunkServer::Connection::write(const std::string &buf) { return write(buf.c_str(), buf.size()); } //------------------------------------------------------------------------------ // Run acceptor thread //------------------------------------------------------------------------------ void DrunkServer::runAcceptorThread(ThreadAssistant &assistant) { while(!assistant.terminationRequested()) { struct pollfd polls[2]; polls[0].fd = _socketFd; polls[0].events = POLLIN; polls[0].revents = 0; polls[1].fd = _shutdown_fd.getFD(); polls[1].events = POLLIN; polls[1].revents = 0; int rpoll = poll(polls, 2, -1); if(polls[1].revents != 0 || rpoll < 0) { return; } struct sockaddr_in remote; socklen_t remoteSize = sizeof(remote); int fd = ::accept(_socketFd, (struct sockaddr*) &remote, &remoteSize); if(fd < 0) { return; } std::unique_lock lock(_mtx); if(!_interactors.empty()) { Interactor *interactor = _interactors.front(); _interactors.pop_front(); lock.unlock(); interactor->handleConnection(std::unique_ptr(new Connection(fd))); } else { _overflowFds.emplace_back(fd); _cv.notify_one(); } } } davix-0.8.0/test/drunk-server/Interactors.hpp0000644000000000000000000000754514121063315017753 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_INTERACTORS_HPP #define DAVIX_TEST_INTERACTORS_HPP #include "AssistedThread.hh" #include "DrunkServer.hpp" class LineReader; //------------------------------------------------------------------------------ // A step-up from Interactor interface, offers a better API //------------------------------------------------------------------------------ class BasicInteractor : public Interactor { public: //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- virtual ~BasicInteractor(); //---------------------------------------------------------------------------- // Take over the specified connection - call only once. Should spawn a // thread in the background for reading / writing on the socket. //---------------------------------------------------------------------------- virtual void handleConnection(std::unique_ptr conn); //---------------------------------------------------------------------------- // Run interacting thread //---------------------------------------------------------------------------- virtual void main(ThreadAssistant &assistant) = 0; protected: std::unique_ptr _conn; std::unique_ptr _reader; AssistedThread _thread; //---------------------------------------------------------------------------- // Consume single reader line //---------------------------------------------------------------------------- std::string consumeLine(); }; //------------------------------------------------------------------------------ // ConnectionShutdownInteractor: Shut down the connection right after a client // connects. //------------------------------------------------------------------------------ class ConnectionShutdownInteractor : public BasicInteractor { public: //---------------------------------------------------------------------------- // Run interacting thread //---------------------------------------------------------------------------- void main(ThreadAssistant &assistant); }; //------------------------------------------------------------------------------ // Single-shot interactor - just a single request and response //------------------------------------------------------------------------------ class SingleShotInteractor : public BasicInteractor { public: //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- SingleShotInteractor(const std::string &expectedReq, const std::string &response); //---------------------------------------------------------------------------- // Run interacting thread //---------------------------------------------------------------------------- void main(ThreadAssistant &assistant); protected: std::string _expected_request; std::string _response; }; #endif davix-0.8.0/test/drunk-server/DrunkServer.hpp0000644000000000000000000001343214121063315017720 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_DRUNK_SERVER_HPP #define DAVIX_TEST_DRUNK_SERVER_HPP #include "AssistedThread.hh" #include "EventFD.hh" #include #include #include #include #include #include #include class Interactor; //------------------------------------------------------------------------------ // A barebones server to be used for testing davix. //------------------------------------------------------------------------------ class DrunkServer { public: //---------------------------------------------------------------------------- // Start listening for incoming connections on the given port. //---------------------------------------------------------------------------- DrunkServer(int port); //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- ~DrunkServer(); //---------------------------------------------------------------------------- // A Connection class, returned by DrunkServer when a client connects. //---------------------------------------------------------------------------- class Connection { public: //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- Connection(int fd); //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- ~Connection(); //-------------------------------------------------------------------------- // Read into buffer //-------------------------------------------------------------------------- ssize_t read(char* buf, size_t count); //-------------------------------------------------------------------------- // Read into string //-------------------------------------------------------------------------- ssize_t read(std::string &buf, size_t count); //-------------------------------------------------------------------------- // Write //-------------------------------------------------------------------------- ssize_t write(const char* buf, size_t count); //-------------------------------------------------------------------------- // Write string //-------------------------------------------------------------------------- ssize_t write(const std::string &buf); private: int _fd; }; //---------------------------------------------------------------------------- // Accept a connection - if no clients connect within the given timeout, // we give up and return NULL. //---------------------------------------------------------------------------- std::unique_ptr accept(int timeoutSeconds); //---------------------------------------------------------------------------- // Auto-accept next connection with the given interactor //---------------------------------------------------------------------------- void autoAcceptNext(Interactor *intr); private: //---------------------------------------------------------------------------- // Run acceptor thread //---------------------------------------------------------------------------- void runAcceptorThread(ThreadAssistant &assistant); int _port; int _socketFd; AssistedThread _acceptor_thread; EventFD _shutdown_fd; std::deque _overflowFds; std::deque _interactors; std::mutex _mtx; std::condition_variable _cv; }; //------------------------------------------------------------------------------ // An Interactor class that fully handles a specific client connection //------------------------------------------------------------------------------ class Interactor { public: //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- Interactor() : _is_ok(false) {} //---------------------------------------------------------------------------- // Virtual destructor //---------------------------------------------------------------------------- virtual ~Interactor() {} //---------------------------------------------------------------------------- // Take over the specified connection - call only once. Should spawn a // thread in the background for reading / writing on the socket. //---------------------------------------------------------------------------- virtual void handleConnection(std::unique_ptr conn) = 0; //---------------------------------------------------------------------------- // Was the interaction ok? //---------------------------------------------------------------------------- bool ok() const { return _is_ok; } protected: bool _is_ok; }; #endif davix-0.8.0/test/drunk-server/ConnectionInitiator.cpp0000644000000000000000000000517314121063315021426 0ustar rootroot /* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "ConnectionInitiator.hpp" #include #include #include #include #include #include #include #include #include #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() inline std::string q(const std::string &str) { return SSTR("'" << str << "'"); } ConnectionInitiator::ConnectionInitiator(const std::string &hostname, int port) { fd = -1; localerrno = 0; struct addrinfo hints, *servinfo, *p; int rv; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; if ((rv = getaddrinfo(hostname.c_str(), SSTR(port).c_str(), &hints, &servinfo)) != 0) { localerrno = rv; error = SSTR("error when resolving " << q(hostname) << ": " << gai_strerror(rv)); return; } // loop through all the results and connect to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { continue; } if (::connect(fd, p->ai_addr, p->ai_addrlen) == -1) { localerrno = errno; close(fd); fd = -1; continue; } break; } freeaddrinfo(servinfo); if (p == NULL) { error = SSTR("Unable to connect to " << q(hostname) << ":" << port); fd = -1; return; } // clear any transient errors which might have occured while trying to connect localerrno = 0; // make socket non-blocking rv = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); if(rv != 0) { localerrno = errno; error = SSTR("Unable to make socket non-blocking"); fd = -1; } } davix-0.8.0/test/slow-unit/0000755000000000000000000000000014121063315014244 5ustar rootrootdavix-0.8.0/test/slow-unit/CMakeLists.txt0000644000000000000000000000157214121063315017011 0ustar rootroot#------------------------------------------------------------------------------- # Make gtest / gmock available for all targets that need it #------------------------------------------------------------------------------- set(BUILD_SHARED_LIBS OFF) set(GTEST "${CMAKE_SOURCE_DIR}/deps/googletest/googletest/") set(GTEST_BINARY_DIR "${CMAKE_BINARY_DIR}/deps/googletest/googletest/") add_executable(davix-slow-unit-tests ../drunk-server/ConnectionInitiator.cpp ../drunk-server/DrunkServer.cpp ../drunk-server/Interactors.cpp ../drunk-server/LineReader.cpp drunk-server.cpp standalone-request.cpp ) target_include_directories(davix-slow-unit-tests PRIVATE ${PROJECT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${GTEST}/include ) target_link_libraries(davix-slow-unit-tests davix_tool_lib libdavix gtest_main ${CMAKE_THREAD_LIBS_INIT} ${LIBSSL_PKG_LIBRARIES} ) davix-0.8.0/test/slow-unit/test-utils.hpp0000644000000000000000000000562214121063315017077 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef DAVIX_TEST_UTILS_HPP #define DAVIX_TEST_UTILS_HPP #include "../drunk-server/DrunkServer.hpp" #include #include #include #include #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() inline std::string getCurlUserAgent() { return SSTR("User-Agent: " << Davix::RequestParams().getUserAgent() << " libcurl/7.69.0-DEV\r\n"); } inline std::string getDefaultUserAgent() { return SSTR("User-Agent: " << Davix::RequestParams().getUserAgent() << " neon/0.0.29\r\n"); } class DavixTestFixture : public ::testing::Test { public: DavixTestFixture() : _drunk_server(new DrunkServer(22222)), _uri("http://localhost:22222/"), _verb("GET"), _flags(0) {} std::unique_ptr makeStandaloneNeonReq() { return std::unique_ptr( new Davix::StandaloneNeonRequest(_factory.getNeon(), true, _boundHooks, _uri, _verb, _params, _headers, _flags, NULL, _deadline) ); } std::unique_ptr makeStandaloneCurlReq() { return std::unique_ptr( new Davix::StandaloneCurlRequest(_factory.getCurl(), true, _boundHooks, _uri, _verb, _params, _headers, _flags, NULL, _deadline) ); } void setConnectionTimeout(std::chrono::seconds dur) { struct timespec tm; tm.tv_sec = dur.count(); tm.tv_nsec = 0; _params.setConnectionTimeout(&tm); } void setDeadlineFromNow(std::chrono::milliseconds dur) { _deadline = Davix::Chrono::Clock(Davix::Chrono::Clock::Monolitic).now() + Davix::Chrono::Duration::milliseconds(dur.count()); } protected: std::unique_ptr _drunk_server; Davix::SessionFactory _factory; Davix::BoundHooks _boundHooks; Davix::Uri _uri; std::string _verb; Davix::RequestParams _params; std::vector _headers; Davix::Chrono::TimePoint _deadline; int _flags; }; #endif davix-0.8.0/test/slow-unit/standalone-request.cpp0000644000000000000000000002314714121063315020575 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include "../drunk-server/DrunkServer.hpp" #include "../drunk-server/LineReader.hpp" #include "../drunk-server/Interactors.hpp" #include "test-utils.hpp" #include #define DBG(message) std::cerr << __FILE__ << ":" << __LINE__ << " -- " << #message << " = " << message << std::endl; using namespace Davix; class Standalone_Neon_Request : public DavixTestFixture {}; class Standalone_Curl_Request : public DavixTestFixture {}; TEST_F(Standalone_Neon_Request, BasicSanity) { _headers.push_back(HeaderLine("I like", "Turtles")); _uri = Uri("http://localhost:22222/chickens"); SingleShotInteractor inter( SSTR("GET /chickens HTTP/1.1\r\n" << getDefaultUserAgent() << "Keep-Alive: \r\n" << "Connection: Keep-Alive\r\n" << "TE: trailers\r\n" << "Host: localhost:22222\r\n" << "I like: Turtles\r\n" << "\r\n"), SSTR("HTTP/1.1 200 OK\r\n" << "Date: Mon, 07 Oct 2019 14:02:25 GMT\r\n" << "Content-Type: ayy/lmao\r\n" << "Content-Length: 19\r\n" << "\r\n" << "I like turtles too.\r\n") ); _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneNeonReq(); ASSERT_FALSE(request->isRecycledSession()); ASSERT_EQ(request->getState(), RequestState::kNotStarted); ASSERT_TRUE(request->startRequest().ok()); ASSERT_EQ(request->getState(), RequestState::kStarted); ASSERT_EQ(request->getStatusCode(), 200); std::string headerLine; ASSERT_TRUE(request->getAnswerHeader("Content-Type", headerLine)); ASSERT_EQ(headerLine, "ayy/lmao"); Uri redirect; ASSERT_FALSE(request->obtainRedirectedLocation(redirect).ok()); sleep(1); // yes this is a hack to be replaced char buffer[2048]; Status st; ASSERT_EQ(request->readBlock(buffer, 2048, st), 19); ASSERT_TRUE(st.ok()); ASSERT_EQ(std::string(buffer, 19), "I like turtles too."); ASSERT_EQ(request->readBlock(buffer, 2048, st), 0); ASSERT_TRUE(st.ok()); ASSERT_EQ(request->getState(), RequestState::kStarted); st = request->endRequest(); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_TRUE(st.ok()); ASSERT_TRUE(inter.ok()); ASSERT_EQ(request->getStatusCode(), 200); ASSERT_FALSE(request->isRecycledSession()); } TEST_F(Standalone_Curl_Request, BasicSanity) { _headers.push_back(HeaderLine("I like", "Turtles")); _uri = Uri("http://localhost:22222/chickens"); SingleShotInteractor inter( SSTR("GET /chickens HTTP/1.1\r\n" << "Host: localhost:22222\r\n" << "Accept: */*\r\n" << "I like: Turtles\r\n"), SSTR("HTTP/1.1 200 OK\r\n" << "Date: Mon, 07 Oct 2019 14:02:25 GMT\r\n" << "Content-Type: ayy/lmao\r\n" << "Content-Length: 19\r\n" << "\r\n" << "I like turtles too.\r\n") ); _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneCurlReq(); ASSERT_FALSE(request->isRecycledSession()); ASSERT_EQ(request->getState(), RequestState::kNotStarted); ASSERT_TRUE(request->startRequest().ok()); ASSERT_EQ(request->getState(), RequestState::kStarted); ASSERT_EQ(request->getStatusCode(), 200); std::string headerLine; ASSERT_TRUE(request->getAnswerHeader("Content-Type", headerLine)); ASSERT_EQ(headerLine, "ayy/lmao"); Uri redirect; ASSERT_FALSE(request->obtainRedirectedLocation(redirect).ok()); sleep(1); // yes this is a hack to be replaced char buffer[2048]; Status st; ASSERT_EQ(request->readBlock(buffer, 2048, st), 19); ASSERT_TRUE(st.ok()); ASSERT_EQ(std::string(buffer, 19), "I like turtles too."); ASSERT_EQ(request->readBlock(buffer, 2048, st), 0); ASSERT_TRUE(st.ok()); ASSERT_EQ(request->getState(), RequestState::kStarted); st = request->endRequest(); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_TRUE(st.ok()); ASSERT_TRUE(inter.ok()); ASSERT_EQ(request->getStatusCode(), 200); ASSERT_FALSE(request->isRecycledSession()); } TEST_F(Standalone_Neon_Request, Redirect) { _uri = Uri("http://localhost:22222/test"); SingleShotInteractor inter( SSTR("GET /test HTTP/1.1\r\n" << getDefaultUserAgent() << "Keep-Alive: \r\n" << "Connection: Keep-Alive\r\n" << "TE: trailers\r\n" << "Host: localhost:22222\r\n" << "\r\n"), SSTR("HTTP/1.1 307 Temporary Redirect\r\n" << "Date: Mon, 07 Oct 2019 14:02:25 GMT\r\n" << "LoCaTiON: https://example.com/redirect-test\r\n" << "\r\n") ); _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneNeonReq(); ASSERT_TRUE(request->startRequest().ok()); std::string headerLine; ASSERT_TRUE(request->getAnswerHeader("LoCaTiON", headerLine)); ASSERT_EQ(headerLine, "https://example.com/redirect-test"); ASSERT_EQ(request->getStatusCode(), 307); ASSERT_TRUE(request->endRequest().ok()); Uri uri; ASSERT_TRUE(request->obtainRedirectedLocation(uri).ok()); ASSERT_EQ(uri.getString(), "https://example.com/redirect-test"); } TEST_F(Standalone_Curl_Request, Redirect) { _uri = Uri("http://localhost:22222/test"); SingleShotInteractor inter( SSTR("GET /test HTTP/1.1\r\n" << "Host: localhost:22222\r\n" << "Accept: */*\r\n" << getCurlUserAgent() << "\r\n"), SSTR("HTTP/1.1 307 Temporary Redirect\r\n" << "Date: Mon, 07 Oct 2019 14:02:25 GMT\r\n" << "LoCaTiON: https://example.com/redirect-test\r\n" << "Content-Length: 0\r\n" << "\r\n") ); _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneCurlReq(); ASSERT_TRUE(request->startRequest().ok()); std::string headerLine; ASSERT_TRUE(request->getAnswerHeader("LoCaTiON", headerLine)); ASSERT_EQ(headerLine, "https://example.com/redirect-test"); ASSERT_EQ(request->getStatusCode(), 307); ASSERT_TRUE(request->endRequest().ok()); Uri uri; ASSERT_TRUE(request->obtainRedirectedLocation(uri).ok()); ASSERT_EQ(uri.getString(), "https://example.com/redirect-test"); } TEST_F(Standalone_Curl_Request, NetworkError) { setConnectionTimeout(std::chrono::seconds(1)); ConnectionShutdownInteractor inter; _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneCurlReq(); ASSERT_EQ(request->getState(), RequestState::kNotStarted); Status st = request->startRequest(); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_FALSE(st.ok()); ASSERT_EQ(st.getScope(), "Davix::HttpRequest"); ASSERT_EQ(st.getCode(), StatusCode::ConnectionProblem); ASSERT_EQ(st.getErrorMessage(), "curl error (52): Server returned nothing (no headers, no data)"); ASSERT_EQ(request->getSessionError(), "curl error (52): Server returned nothing (no headers, no data)"); ASSERT_EQ(request->getStatusCode(), 0); _drunk_server.reset(); } TEST_F(Standalone_Neon_Request, NetworkError) { setConnectionTimeout(std::chrono::seconds(1)); ConnectionShutdownInteractor inter; _drunk_server->autoAcceptNext(&inter); std::unique_ptr request = makeStandaloneNeonReq(); ASSERT_EQ(request->getState(), RequestState::kNotStarted); Status st = request->startRequest(); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_FALSE(st.ok()); ASSERT_EQ(st.getScope(), "Davix::HttpRequest"); ASSERT_EQ(st.getCode(), StatusCode::ConnectionProblem); ASSERT_EQ(st.getErrorMessage(), "(Neon): Could not read status line: connection was closed by server"); ASSERT_EQ(request->getSessionError(), "Could not read status line: connection was closed by server"); ASSERT_EQ(request->getStatusCode(), 0); _drunk_server.reset(); } TEST_F(Standalone_Curl_Request, StopNoStart) { std::unique_ptr request = makeStandaloneCurlReq(); ASSERT_EQ(request->getState(), RequestState::kNotStarted); ASSERT_TRUE(request->endRequest().ok()); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_EQ(request->getStatusCode(), 0); } TEST_F(Standalone_Neon_Request, StopNoStart) { std::unique_ptr request = makeStandaloneNeonReq(); ASSERT_EQ(request->getState(), RequestState::kNotStarted); ASSERT_TRUE(request->endRequest().ok()); ASSERT_EQ(request->getState(), RequestState::kFinished); ASSERT_EQ(request->getStatusCode(), 0); } davix-0.8.0/test/slow-unit/drunk-server.cpp0000644000000000000000000000312414121063315017377 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "../drunk-server/DrunkServer.hpp" #include "../drunk-server/ConnectionInitiator.hpp" TEST(DrunkServer, NoClients) { DrunkServer ds(22222); std::unique_ptr conn = ds.accept(1); ASSERT_FALSE(conn); } TEST(DrunkServer, ClientInteraction) { DrunkServer ds(22222); ConnectionInitiator initiator("localhost", 22222); std::unique_ptr connSrv = ds.accept(1); ASSERT_TRUE(connSrv); std::unique_ptr connCl(new DrunkServer::Connection(initiator.getFd())); ASSERT_EQ(connCl->write("hey there"), 9); std::string buff; ASSERT_EQ(connSrv->read(buff, 9), 9); ASSERT_EQ(buff, "hey there"); } davix-0.8.0/test/bench/0000755000000000000000000000000014121063315013362 5ustar rootrootdavix-0.8.0/test/bench/CMakeLists.txt0000644000000000000000000000161614121063315016126 0ustar rootroot# main file for src if(BENCH_TESTS) LIST(APPEND src_davix_bench "davix_bench.cpp" "chunk_queue.cpp") #include_directories(/usr/include/davix) add_executable(davix-bench ${src_davix_bench}) target_link_libraries(davix-bench libdavix ${CMAKE_THREAD_LIBS_INIT}) function(test_read url opt input) add_test(test_bench_read_${url} davix-bench ${opt} ${url} ${input}) endfunction(test_read url opt) function(test_vector_read url opt input) add_test(test_bench_vector_read_${url} davix-bench ${opt} ${url} ${input}) endfunction(test_vector_read url opt) function(test_thread_read url opt input) add_test(test_bench_thread_read_${url} davix-bench ${opt} ${url} ${input}) endfunction(test_thread_read url opt) function(test_write url opt input) add_test(test_bench_write_${url} davix-bench ${opt} ${url} ${input}) endfunction(test_write url opt) include(ctest_bench.cmake) endif(BENCH_TESTS) davix-0.8.0/test/bench/chunk_queue.h0000644000000000000000000000136014121063315016047 0ustar rootroot#ifndef CHUNK_QUEUE #define CHUNK_QUEUE #include #include #include #define DEFAULT_WAIT_TIME 5 const int STARTED = 1; const int STOPPED = 2; class ChunkQueue { public: ChunkQueue(); ~ChunkQueue(); struct worktoken { long length; long offset; DAVIX_FD* fd; }; void pushOp(long len, long oset, DAVIX_FD* davfd); struct worktoken *getOp(); void StopThreads(); int GetQueueSize(); int GetQueueState(); void SetQueueState(int new_state); private: /// Queue of the pending operations std::deque workqueue; pthread_mutex_t workmutex; pthread_cond_t popconvar; pthread_cond_t pushconvar; int state; }; #endif davix-0.8.0/test/bench/davix_bench.cpp0000644000000000000000000007050514121063315016347 0ustar rootroot#include #include #include #include #include #include #include #include #include #include "chunk_queue.h" #define BUFFER_SIZE 100 // in MB #define MAX_READ_PER_LOOP 20480 using namespace Davix; using namespace std; // command line options struct Options { RequestParams params; char mode; int vec_size; int no_of_thread; bool check; bool debug; bool silent; bool hasinputfile; std::vector vec_arg; std::string inputfile; Options() : params(), mode(), vec_size(), no_of_thread(), check(false), debug(false), silent(false), hasinputfile(false), vec_arg(), inputfile() { } }; // producer thread arguments struct ProducerArgs { long* length; long* offset; int nread; DAVIX_FD* fd; ChunkQueue* cq; }; // reader threads arguments struct ReaderArgs { DAVIX_FD* fd; ChunkQueue* cq; struct Options* opts; DavPosix* infile; bool* iserror; long* totalreadscount; long long* totalbytesread; pthread_mutex_t* mutex; }; int ParseOptions(int argc, char* argv[], Options & p); void PrintUsage(); int ReadSome(long *offs, long *lens, int maxnread, long long &totalbytes, bool &last_iter, Options &p, ifstream& in_file); void errorPrint(DavixError ** err); void* ThreadRead(void* args); void* PopulateQueue(void* args); int main(int argc, char* argv[]) { void *buffer = NULL; timeval tv; double starttime = 0, openphasetime = 0, endtime = 0, closetime = 0; Options opts; DAVIX_FD* fd; Context context; DavixError* tmp_err = NULL; string summarypref = "$$$"; string opt_type = "read"; string filepath; bool iserror = false; bool last_batch = false; DavPosix* infile = new DavPosix(&context); std::vector filename; std::vector davfd_vec; std::vector fd_vec; std::vector dfile_vec; std::vector DavErr_vec; int file_count = 0; long long totalbytesread = 0, prevtotalbytesread = 0, totalbytestoprocess = 0; long totalreadscount = 0, totalwritecount = 0, totalbyteswritten = 0; int ret = -1; ChunkQueue cq; // enable grid mode context.loadModule("grid"); gettimeofday(&tv, 0); starttime = tv.tv_sec + tv.tv_usec / 1000000.0; closetime = openphasetime = starttime; ParseOptions(argc, argv, opts); buffer = malloc(BUFFER_SIZE*1024*1024); cout << endl; bool isURL = !(opts.vec_arg[0].find("http") == string::npos); if(isURL) { switch(opts.mode) { case 'r': case 't': case 'v': { cout << "Opening - " << opts.vec_arg[0] << " --------------------- "; if((fd = infile->open(NULL, opts.vec_arg[0], O_RDONLY, &tmp_err)) != NULL) { cout << "success" << endl; davfd_vec.push_back(fd); filename.push_back(opts.vec_arg[0]); file_count++; } else { cout << "Failed" << endl << endl; if(tmp_err != NULL) { DavErr_vec.push_back(*tmp_err); errorPrint(&tmp_err); } iserror = true; } break; } case 'w': { cout << "Creating Davix file - " << opts.vec_arg[0] << endl; DavFile f(context, opts.vec_arg[0]); dfile_vec.push_back(f); filename.push_back(opts.vec_arg[0]); file_count++; break; } default: { cerr << endl << "Invaild option." << endl; PrintUsage(); exit(-1); } } // switch } // isURL else //isfile { ifstream files(opts.vec_arg[0].c_str() ); files >> filepath; switch(opts.mode) { case 'r': case 't': case 'v': { while(!files.eof() && files.good() ) { if(!filepath.empty() ) { cout << "Opening - " << filepath << " --------------------- "; if((fd = infile->open(NULL, filepath, O_RDONLY, &tmp_err)) != NULL) { cout << "Success" << endl; davfd_vec.push_back(fd); filename.push_back(filepath); file_count++; } else { cout << "Failed" << endl << endl; if(tmp_err != NULL) { DavErr_vec.push_back(*tmp_err); errorPrint(&tmp_err); } iserror = true; } } files >> filepath; } // while file break; } case 'w': { if(!files.good() ) // empty, file is write target { cout << "Creating Davix file - " << opts.vec_arg[0] << endl; DavFile f(context, opts.vec_arg[0]); dfile_vec.push_back(f); filename.push_back(filepath); file_count++; } else // file has content, read them { while(!files.eof() && files.good() ) { if(!filepath.empty() ) { cout << "Creating Davix file - " << filepath << endl; DavFile f(context, filepath); dfile_vec.push_back(f); filename.push_back(filepath); file_count++; } files >> filepath; } // while } break; } default: { cerr << endl << "Invaild option." << endl; PrintUsage(); exit(-1); } } // switch } // isfile gettimeofday(&tv, 0); openphasetime = tv.tv_sec + tv.tv_usec / 1000000.0; cout << endl; long long bytes_read = 0; int ntoread = 0; int maxtoread = MAX_READ_PER_LOOP; long v_offsets[MAX_READ_PER_LOOP]; long v_lens[MAX_READ_PER_LOOP]; DavIOVecInput inVec[opts.vec_size]; DavIOVecOuput outVec[opts.vec_size]; // Davix doesn't support remote pwrite yet, write to tmp file before uploading to simulate the effect std::FILE* tmpf = std::tmpfile(); int fdd = fileno(tmpf); ifstream input; if(opts.hasinputfile == true) { input.open(opts.inputfile.c_str(),ios::in); if(!input) { std::cerr << endl << "Cannot open input file."; return -1; } } while((ntoread = ReadSome(v_offsets, v_lens, maxtoread, totalbytestoprocess, last_batch, opts, input))) { cout << "."; switch(opts.mode) { case 'r': // non-vectored read { for(int i = 0; i < file_count; ++i) { cout << endl << "Reading - " << filename[i] << endl << endl; for(int j = 0; j < ntoread; j++) { bytes_read = infile->pread(davfd_vec[i], buffer, v_lens[j], v_offsets[j], &tmp_err); if(tmp_err != NULL) { DavErr_vec.push_back(*tmp_err); errorPrint(&tmp_err); iserror = true; break; } if(bytes_read <= 0) { cerr << "---Read (" << j+1 << " of " << ntoread << ") " << v_lens[j] << "@" << v_offsets[j] << " returned " << bytes_read << endl; iserror = true; break; } if(!opts.silent) { printf("%20s %-20ld", "Offset: ", v_offsets[j]); printf("%s %-20ld", "Length: ", v_lens[j]); printf("%s %-20lld\n", "Read: ", bytes_read); } totalbytesread += bytes_read; totalreadscount++; // do byte check here if(opts.check == true) { for(int k = 0; k < v_lens[j]; k++) { if(((k + v_offsets[j]) % 256) != ((unsigned char *)buffer)[k]) { cerr << "%Byte check -- Error in the file offset: " << k + v_offsets << " buffer: " << (int)((unsigned char *)buffer)[k] << " expected: " << (k+v_offsets[j]) % 256 << endl; iserror = true; break; } } if(!iserror && !opts.silent) { cout << "$Byte check -- Passed." << endl; } } } } break; } case 't': // threaded read { for(int i = 0; i < file_count; ++i) { cq.SetQueueState(STARTED); pthread_mutex_t mutex; cout << endl << "Reading - " << filename[i] << endl << endl; pthread_mutex_init(&mutex,0); // populate producer args ProducerArgs tk_args; tk_args.length = v_lens; tk_args.offset = v_offsets; tk_args.fd = davfd_vec[i]; tk_args.cq = &cq; tk_args.nread = ntoread; pthread_t producer; pthread_create(&producer, NULL, PopulateQueue, &tk_args); // populate reader args ReaderArgs r_args; r_args.fd = davfd_vec[i]; r_args.cq = &cq; r_args.opts = &opts; r_args.infile = infile; r_args.iserror = &iserror; r_args.totalreadscount = &totalreadscount; r_args.totalbytesread = &totalbytesread; r_args.mutex = &mutex; pthread_t read_thread[opts.no_of_thread]; for(int ii = 0; ii < opts.no_of_thread; ++ii) { pthread_create(&read_thread[ii], NULL, ThreadRead, &r_args); } for(int j = 0; j < opts.no_of_thread; ++j) { pthread_join(read_thread[j], NULL); cq.StopThreads(); } pthread_join(producer, NULL); pthread_mutex_destroy(&mutex); } break; } case 'v': // vectored read for(int i = 0; i < file_count; ++i) { cout << endl << "Reading - " << filename[i] << endl; cout << "Vector size - " << opts.vec_size << endl << endl; int no_of_input = ntoread; int vec_size = 0; for(int j = 0; j < ntoread;) { if(no_of_input > opts.vec_size) { vec_size = opts.vec_size; } else { vec_size = no_of_input; } for(int k = 0; k < vec_size; k++) { if( (k+j) >= MAX_READ_PER_LOOP) { break; } inVec[k].diov_offset = v_offsets[k+j]; inVec[k].diov_size = v_lens[k+j]; inVec[k].diov_buffer = buffer; if(!opts.silent) { printf("%20s %-20ld", "Offset: ", v_offsets[k+j]); printf("%s %-20ld\n", "Length: ", v_lens[k+j]); } } bytes_read = infile->preadVec(davfd_vec[i], inVec, outVec, vec_size, &tmp_err); if(tmp_err != NULL) { DavErr_vec.push_back(*tmp_err); errorPrint(&tmp_err); iserror = true; break; } if(bytes_read <= 0) { cerr << "---Read (" << j+1 << " of " << ntoread << ") " << v_lens[j] << "@" << v_offsets[j] << " returned " << bytes_read << endl; iserror = true; break; } if(!opts.silent) { printf("\n%20s %-20lld\n\n", "Read: ", bytes_read); } totalbytesread += bytes_read; totalreadscount++; no_of_input -= opts.vec_size; j += opts.vec_size; } } break; case 'w': // write { for(int i = 0; i < file_count; ++i) { // if file already exists, delete it. dfile_vec[i].deletion(&opts.params, NULL); int retval = 0; DavFile df_tmp(context, filename[i]); for(int j = 0; j < ntoread; j++) { for(int k = 0; k < v_lens[j]; k++) { ((unsigned char *)buffer)[k] = (v_offsets[j]+k) % 256; } ret = pwrite(fdd, buffer, v_lens[j], v_offsets[j]); if (ret <= 0) { cout << endl << "---Write (" << j+1 << " of " << ntoread << ") " << v_lens[j] << "@" << v_offsets[j] << " returned " << ret << endl; iserror = true; break; } if(retval != 0) { cerr << "DavFile write error: putFromFd" << endl; exit(-1); } if(!opts.silent) { printf("%20s %-20ld", "Offset: ", v_offsets[j]); printf("%s %-20ld\n", "Length: ", v_lens[j]); } } fseek(tmpf,0,SEEK_END); int size = ftell(tmpf); // upload only if this is the last iteration of the input loop if(last_batch == true) { retval = df_tmp.putFromFd(&opts.params, fdd, size, &tmp_err); if(tmp_err != NULL) { DavErr_vec.push_back(*tmp_err); errorPrint(&tmp_err); iserror = true; continue; } totalbyteswritten += size; totalwritecount++; cout << endl << "Write run completed on " << filename[i] << endl << endl; } } break; } default: { cerr << endl << "Option not reconised." << endl; PrintUsage(); exit(-1); break; } }// switch if (iserror && prevtotalbytesread) { totalbytesread = prevtotalbytesread; break; } prevtotalbytesread = totalbytesread; }// while ReadSome gettimeofday(&tv, 0); closetime = tv.tv_sec + tv.tv_usec / 1000000.0; cout << endl << "--- Closing all files." << endl; for(unsigned int i = 0; i < davfd_vec.size(); ++i) { infile->close(davfd_vec[i], &tmp_err); } close(fdd); delete(infile); cout << "--- Clearing pointer vector." << endl; davfd_vec.clear(); cout << "--- Freeing buffer." << endl; free(buffer); gettimeofday(&tv, 0); endtime = tv.tv_sec + tv.tv_usec / 1000000.0; if (iserror) summarypref = "%%%"; cout << fixed; cout << endl << "Summary ----------------------------" << endl; cout << summarypref << " Start time: " << starttime << endl; cout << summarypref << " Last open time: " << openphasetime << endl; cout << summarypref << " Close time: " << closetime << endl; cout << summarypref << " End time: " << endtime << endl; cout << summarypref << " Open elapsed: " << openphasetime - starttime << endl; cout << summarypref << " Data transfer elapsed: " << closetime - openphasetime << endl; cout << summarypref << " Close elapsed: " << endtime - closetime << endl; cout << summarypref << " Total elapsed: " << endtime - starttime << endl; if(opts.mode == 'w') { cout << summarypref << " Total bytes written: " << totalbyteswritten << endl; cout << summarypref << " Max bytes written per sec: " << totalbyteswritten / (closetime - openphasetime) << endl; cout << summarypref << " Effective bytes written per sec: " << totalbyteswritten / (endtime - starttime) << endl; cout << summarypref << " Write count: " << totalwritecount << endl; } else { cout << summarypref << " Total bytes to process: " << totalbytestoprocess * file_count << endl; cout << summarypref << " Total bytes read: " << totalbytesread << endl; cout << summarypref << " Max bytes read per sec: " << totalbytesread / (closetime - openphasetime) << endl; cout << summarypref << " Effective bytes read per sec: " << totalbytesread / (endtime - starttime) << endl; cout << summarypref << " Successful read count: " << totalreadscount << endl; switch(opts.mode) { case 'v': cout << summarypref << " Vector size: " << opts.vec_size << endl; break; case 't': cout << summarypref << " Number of thread(s): " << opts.no_of_thread << endl; break; } } cout << summarypref << " Opened file count: " << file_count << endl; cout << endl; // print out any unique ocurrence of DavixError if(!DavErr_vec.empty() ) { int err_code = 0; std::vector err_code_vec; err_code = DavErr_vec[0].getStatus(); err_code_vec.push_back(err_code); std::cerr << "Total DavixError: " << DavErr_vec.size() << endl << "Printing error type(s) -" << endl; std::cerr << "("<< DavErr_vec[0].getErrScope() <<") Error: "<< DavErr_vec[0].getErrMsg() << std::endl << std::endl; for(unsigned int z = 1; z < DavErr_vec.size(); ++z) { err_code = DavErr_vec[z].getStatus(); if (std::find(err_code_vec.begin(), err_code_vec.end(), err_code) == err_code_vec.end()) { err_code_vec.push_back(err_code); std::cerr << "("<< DavErr_vec[z].getErrScope() <<") Error: "<< DavErr_vec[z].getErrMsg() << std::endl << std::endl; } } DavErr_vec.clear(); } return 0; }// end of main //=================================================================================================================== //==================================================FUNCTIONS======================================================== //=================================================================================================================== void errorPrint(DavixError ** err) { if(err && *err){ std::cerr << "("<< (*err)->getErrScope() <<") Error: "<< (*err)->getErrMsg() << std::endl << std::endl; DavixError::clearError(err); } } int ReadSome(long *offs, long *lens, int maxnread, long long &totalbytes, bool &last_iter, Options &p, ifstream& in_file) { if(p.hasinputfile) { for (int i = 0; i < maxnread;) { lens[i] = -1; offs[i] = -1; if (in_file.eof()) { last_iter = true; return i; } in_file >> lens[i] >> offs[i]; if(lens[i] > (BUFFER_SIZE*1024*1024) ) { std::cerr << endl << "Length exceeds buffer size @ length: " << lens[i] << ", buffer: " << BUFFER_SIZE*1024*1024 << endl << endl; exit(-1); } if ((lens[i] > 0) && (offs[i] >= 0)) { totalbytes += lens[i]; i++; } } return maxnread; } else { for (int i = 0; i < maxnread;) { lens[i] = -1; offs[i] = -1; if (cin.eof()) { last_iter = true; return i; } cin >> lens[i] >> offs[i]; if(lens[i] > (BUFFER_SIZE*1024*1024) ) { std::cerr << endl << "Length exceeds buffer size @ length: " << lens[i] << ", buffer: " << BUFFER_SIZE*1024*1024 << endl << endl; exit(-1); } if ((lens[i] > 0) && (offs[i] >= 0)) { totalbytes += lens[i]; i++; } } return maxnread; } } int ParseOptions(int argc, char* argv[], Options & p) { const std::string arg_tool_main= "srwdchv:t:i:"; int ret = 0; if(argc < 2) { PrintUsage(); exit(-1); } while((ret = getopt(argc, argv, arg_tool_main.c_str() )) > 0) { switch(ret) { case 'r': p.mode = ret; break; case 'v': p.mode = ret; p.vec_size = atoi(optarg); if(p.vec_size <= 0) { std::cerr << endl << "Vector size must be a positive integer." << endl << endl; exit(-1); } break; case 't': p.mode = ret; p.no_of_thread = atoi(optarg); if(p.no_of_thread <= 0) { std::cerr << endl << "Number of threads must be a positive integer." << endl << endl; exit(-1); } case 'w': p.mode = ret; break; case 'h': PrintUsage(); exit(0); break; case 'c': p.check = true; break; case 'd': p.debug = true; davix_set_log_level(15); break; case 's': p.silent = true; break; case 'i': p.hasinputfile = true; p.inputfile = optarg; break; default: PrintUsage(); exit(-1); }// switch }// while getopt ret = -1; for(int i = optind; i < argc; ++i) { p.vec_arg.push_back(argv[i]); ret = 0; } if(ret != 0 && p.mode != 'h') { PrintUsage(); exit(-1); } return ret; } void* PopulateQueue(void* args) { ProducerArgs* tk = static_cast(args); for(int i = 0; i < tk->nread; ++i) { tk->cq->pushOp(tk->length[i], tk->offset[i], tk->fd); } while(true) { if(tk->cq->GetQueueSize() == 0) { // signal all workers to exit tk->cq->StopThreads(); break; } } return 0; } void* ThreadRead(void* args) { long long bytes_read = 0; void *buffer = NULL; DavixError* tmp_err = NULL; buffer = malloc(BUFFER_SIZE*1024*1024); ReaderArgs* rd = static_cast(args); while( rd->cq->GetQueueState() != STOPPED) { ChunkQueue::worktoken* tk = rd->cq->getOp(); bytes_read = rd->infile->pread(rd->fd, buffer, tk->length, tk->offset, &tmp_err); if(!rd->opts->silent) { printf("%20s %-20ld", "Offset: ", tk->offset); printf("%s %-20ld", "Length: ", tk->length); printf("%s %-20lld\n", "Read: ", bytes_read); } if (bytes_read <= 0) { cout << "---Read " << tk->length << "@" << tk->offset << " returned " << bytes_read << endl; *rd->iserror = true; errorPrint(&tmp_err); delete(tk); continue; } delete(tk); pthread_mutex_lock(rd->mutex); (*rd->totalbytesread) += bytes_read; (*rd->totalreadscount)++; pthread_mutex_unlock(rd->mutex); } free(buffer); return 0; } void PrintUsage() { std::cout << endl << endl << "This programme gets from the standard input a sequence of" << endl << " (one for each line, with less than " << BUFFER_SIZE << "MB in byte)" << endl << " and performs the corresponding read requests towards the given URL or to ALL" << endl << " the URLS contained in the given file." << endl << endl << "Usage: davix-bench [OPTIONS ...] \n" << endl << " Options:" << endl << " -h Display help and usage." << endl << " -r Non-vectored read." << endl << " -vn Vectored read of vector size n." << endl << " -tn Concurrent read of n threads." << endl << " -d Debug mode." << endl << " -s Silent mode." << endl << " -w Write mode, create file which is compatible with the -c option." << endl << " -i Read input from file instead of standard input." << endl << " -c Verify if the value of the byte at offset i is i%256. Valid only for the non-vectored(r) read mode." << endl << endl; } davix-0.8.0/test/bench/ctest_bench.cmake0000644000000000000000000000223614121063315016650 0ustar rootroot## ctest script file for automated bench tests for davix # message (" Setup tests parameters... ") set(INPUT_FILE "-iinputfile.txt") set(READ_OPT "-r") set(READ_VECTOR_OPT "-v50") set(READ_THREAD_OPT "-t4") set(WRITE_OPT "-w") set(http_desy_base "https://vm-dcache-deploy6.desy.de:2880/dteam/davix-tests" CACHE STRING "dCache test instance to use") set(http_lcgdm_base "https://lxfsra04a04.cern.ch/dpm/cern.ch/home/dteam" CACHE STRING "DPM test instance to use" ) set(http_lcgdm_base_write "https://lxfsra04a04.cern.ch/dpm/cern.ch/home/dteam/davix_bench_writetest" CACHE STRING "DPM test instance to use" ) # DPM tests test_read("${http_lcgdm_base}" "${READ_OPT}" "${INPUT_FILE}") test_vector_read("${http_lcgdm_base}" "${READ_VECTOR_OPT}" "${INPUT_FILE}") test_thread_read("${http_lcgdm_base}" "${READ_THREAD_OPT}" "${INPUT_FILE}") test_write("${http_lcgdm_base_write}" "${WRITE_OPT}" "${INPUT_FILE}") test_read("${http_desy_base}" "${READ_OPT}" "${INPUT_FILE}") test_vector_read("${http_desy_base}" "${READ_VECTOR_OPT}" "${INPUT_FILE}") test_thread_read("${http_desy_base}" "${READ_THREAD_OPT}" "${INPUT_FILE}") test_write("${http_desy_base}" "${WRITE_OPT}" "${INPUT_FILE}") davix-0.8.0/test/bench/chunk_queue.cpp0000644000000000000000000000443514121063315016410 0ustar rootroot#include "chunk_queue.h" #include #include #include ChunkQueue::ChunkQueue() { pthread_mutex_init(&workmutex, NULL); pthread_cond_init(&popconvar, NULL); pthread_cond_init(&pushconvar, NULL); state = STARTED; } ChunkQueue::~ChunkQueue() { for(unsigned int i = 0; i < workqueue.size(); ++i) { delete(workqueue[i]); } } void ChunkQueue::pushOp(long len, long oset, DAVIX_FD* davfd) { struct timespec to; bool pushed = false; pthread_mutex_lock(&workmutex); to.tv_sec = time(NULL) + DEFAULT_WAIT_TIME; to.tv_nsec = 0; while(!pushed) { if(workqueue.size() < 1000) { worktoken* tk = new(worktoken); tk->length = len; tk->offset = oset; tk->fd = davfd; workqueue.push_back(tk); pushed = true; break; } int rc = pthread_cond_timedwait(&pushconvar, &workmutex, &to); if(rc == ETIMEDOUT) { std::cerr << std::endl << "pushOp() timed out." << std::endl; break; } } //signal worker, job available pthread_mutex_unlock(&workmutex); pthread_cond_signal(&popconvar); } struct ChunkQueue::worktoken *ChunkQueue::getOp() { struct worktoken* mytk = 0; struct timespec to; pthread_mutex_lock(&workmutex); to.tv_sec = time(NULL) + DEFAULT_WAIT_TIME; to.tv_nsec = 0; while(!mytk) { if(workqueue.size() > 0) { mytk = workqueue.front(); workqueue.pop_front(); break; } int rc = pthread_cond_timedwait(&popconvar, &workmutex, &to); if(rc == ETIMEDOUT) { std::cerr << std::endl << "getOp() timed out." << std::endl; break; } } pthread_mutex_unlock(&workmutex); // there is now room in the workqueue, signal producer pthread_cond_signal(&pushconvar); return (mytk); } void ChunkQueue::StopThreads() { state = STOPPED; pthread_cond_broadcast(&pushconvar); pthread_cond_broadcast(&popconvar); } int ChunkQueue::GetQueueSize() { return workqueue.size(); } int ChunkQueue::GetQueueState() { return state; } void ChunkQueue::SetQueueState(int new_state) { state = new_state; } davix-0.8.0/test/root-tests/0000755000000000000000000000000014121063315014426 5ustar rootrootdavix-0.8.0/test/root-tests/h2fastnew_main.cpp0000644000000000000000000000340714121063315020043 0ustar rootroot#include #include "Riostream.h" #include "TROOT.h" #include "TDavixFile.h" #include "TFile.h" #include "TNetFile.h" #include "TRandom.h" #include "TTree.h" #include "TTreeCache.h" #include "TTreePerfStats.h" #include "TBranch.h" #include "TClonesArray.h" #include "TStopwatch.h" #include "TTreeCacheUnzip.h" #include "TEnv.h" #include #include #include void h2fast(const char *url , Bool_t draw=kFALSE, Long64_t cachesize=10000000, Int_t learn=1) { // gEnv->SetValue("TFile.DavixLog", 10); // gDebug= 0x02; TStopwatch sw; TTree* T = NULL; sw.Start(); Long64_t oldb = TFile::GetFileBytesRead(); TFile *f = TFile::Open(url); if (!f || f->IsZombie()) { printf("File h1big.root does not exist\n"); exit (-1); } // TTreeCacheUnzip::SetParallelUnzip(TTreeCacheUnzip::kEnable); T= (TTree*)f->Get("h42"); Long64_t nentries = T->GetEntries(); T->SetCacheSize(cachesize); TTreeCache::SetLearnEntries(learn); TFileCacheRead *tpf = f->GetCacheRead(); //tpf->SetEntryRange(0,nentries); if (draw) T->Draw("rawtr","E33>20"); else { TBranch *brawtr = T->GetBranch("rawtr"); TBranch *bE33 = T->GetBranch("E33"); Float_t E33; bE33->SetAddress(&E33); for (Long64_t i=0;iLoadTree(i); bE33->GetEntry(i); if (E33 > 0) brawtr->GetEntry(i); } } if (tpf) tpf->Print(); printf("Bytes read = %lld\n",TFile::GetFileBytesRead()-oldb); printf("Real Time = %7.3f s, CPUtime = %7.3f s\n",sw.RealTime(),sw.CpuTime()); delete T; delete f; } int main(int argc, char** argv){ if(argc <2 ){ std::cout << "Usage: " << (char*) argv[0] << " [remote_url] " << std::endl; return -1; } h2fast(argv[1]); return 0; } davix-0.8.0/test/root-tests/CMakeLists.txt0000644000000000000000000000207614121063315017173 0ustar rootroot option(ROOT_TESTS "Root functional test execution " FALSE) if(ROOT_TESTS) ## the root tests are compatibility tests with the ROOT analysis framework (http://root.cern.ch/) ## The root tests need to be compiled and executed : ## - the ROOT framework ## - a valid proxy credential for the dteam VO find_package(ROOT REQUIRED) add_definitions(-Wall) add_definitions( ${INTERN_ROOT_CONFIG_CFLAGS} -lTreePlayer) link_directories( ${ROOT_LIBRARY_DIR}) include_directories( ${ROOT_INCLUDE_DIR}) add_executable(test_event "h2fastnew_main.cpp") target_link_libraries(test_event ${ROOT_LIBRARIES} TreePlayer) function(test_root_event name url) add_test(test_root_event_${name} test_event ${url}) endfunction(test_root_event name url) ## official root website test_root_event(root_website http://root.cern.ch/files/h1big.root) ## DPM test https test_root_event(root_DPM_testbed https://lxfsra04a04.cern.ch/dpm/cern.ch/home/dteam/h1big.root) ## Dcache test http test_root_event(root_dCache_testbed http://vm-dcache-deploy6.desy.de:2881/dteam/h1big.root) endif(ROOT_TESTS) davix-0.8.0/test/certs/0000755000000000000000000000000014121063315013423 5ustar rootrootdavix-0.8.0/test/certs/my_keycert.p120000644000000000000000000000343214121063315016124 0ustar rootroot0‚0‚Ü *†H†÷  ‚Í‚É0‚Å0‚— *†H†÷  ‚ˆ0‚„0‚} *†H†÷ 0 *†H†÷  0k®3 UŒZ«€‚PØÔdy’ä?!hÞ?h”rŒ@â@fâþÑêÒ`,‡Ì|;><ÇU“œª=¯¾¢íB"'èC@me6þ Áÿî½í—£Ÿê@ƒ“Où˜áÃ.¯LÉ5áò:ý`’BF©Ó=óEÞ)U†ú *Ón)ýÞk¨d#ˆ¨BÖ ¥Íü}sÎtôS;âÀXÊE`Ópí.À—°ñ9*WÄ;!î…þ6¤~@ûç)®ï¨×©ŠHœe§–d ´ÓUO‘ùY;qÒ5%SÊ'D©m8·Rýµø{ࣟ‹[ŠË”/¨9Ǩ¾K×ÇT!° ò™÷?ÿªBRd°AÐL´"N‘dÜ@bõt3è¥ð¡ÕåPýŽÿ›üœì¥L†›ïÉ”0F ÙŽþUö­K„ºÐTߨÖf¬\+Á+êh¹ÏŠ£Ò'—“ï?ÿ»‚7Пxqõ$²¼,q£_AòG\Ë£oÛO«DQ4|ûÖ˜Éj (’G}ö0Ý$poøÔ¿|²äûô]=î=¬N¤"OeÉzz±–›šøª`”á_Ï)lAs«bz „_À¶ÀS‹ºbìþiDZ @Ôûn“¼U¾²5FxÕò«a›£F­58–ÓhPÅdØ?f­Â#н· ½ÏØp”¯E¯œ†] ÁËqBe]™] õ[?k2¸œ4@O+z‡GÀù‡ÍDV *¹ÑÀ´áäNx ÑâüAl© D’ 0ÌÜ8ÈþÚuVuêÀ¿:è0‚& *†H†÷  ‚‚0‚0‚  *†H†÷   ‚¦0‚¢0 *†H†÷  0”àúÛóžO‚€Æ2ÃBéuà›áØ@åô¢Z)D°N ù 1—l l;Èq9ˆ~åÜV¿T)ªõr]¡È8DL4A¦¼5ŸïêÆª}oj<ðš RVµ9ˆ+¢=‘síÝ)¶í&QÝ®ÉDg£6ž‘Ø­5»ýÇÿ÷+‰Ô·}sÕÃzôïÐ@¦-•óÑžŠ‰uîŸÞ{†ÇeÒ¸‡hFi«_Ê@ù”6vúî£;ÌïvÈßÃ÷¥©¢jäµ"Æ8ñ¼à¶2–´å9ŠÇ`1»¯!“i.s8“ ‘IPñ"[“•Ø±Š˜•<ç ÒŠçx·Sÿ&<ÈωÅwèeXV{Ý$»3ÔΤä>èÈH‰¸å³c˜]¯cPE±FŠdlãÁ‚)I1p=:_ÓL $\îÄ¥*.cT5™‘îät¾gŸ¸ü=+_ဈøæ}0f*Ò»`±ö”} ŸlZ èâÏ•âúRÝqŠãN#ÂC½Ÿ œ™gîCÀ[<ÑÝS‘xÊMîeI2ׯç’áï•Ö‹jF[uQhh³MK¯òÅÏ0Áƒzê¤íÞ¨”sÛNt `æ(™ÅÑÊeÈ=üÆYܺ"[L9lÌph‘$ò[¶Š”ÏÊžˆJâÛx+mD°–ç6óa=/_Æ÷º°Yï?!¥ªùs@í?¯²K4õ5²jrœÂWY'âõuúj9v2­æÉt^®ìf¼EÙˆ$¯àu'™6³ú»°ÂbÍyGˆü¶)®Õ±‰_ÜœÖ6ëNFa×Vèø²¦„5IN¯6æ¾þHY\—b͌ɩQÀù{ûƒ¾K¿ñI!rù»h— V<+ÿz5ïí 1R0# *†H†÷  1*AXrA›DlÝê=Â1uɤ)0+ *†H†÷  1My Certificate010!0 +kÑí™Vÿ!WŠ é5iy ÛGË؃‘'L‹davix-0.8.0/test/run-tests.sh0000755000000000000000000000131514121063315014606 0ustar rootroot#!/usr/bin/env bash set -e # Please note: You need to have a credentials directory at the top level # of the repository in order to run the functional tests. # # The credentials directory must contain a valid VOMS proxy certificate, AWS as well # as Azure credentials. # # Please contact the maintainer if you need advice on how to run the tests. # # You need to run this script while being at the top level of the repository, # and not in $REPO/tests CORES=$(grep -c ^processor /proc/cpuinfo) git submodule update --recursive --init credentials/obtain-proxy.sh rm -rf build mkdir build cd build cmake -DENABLE_THIRD_PARTY_COPY=TRUE .. make -j $CORES # make abi-check (ctest --no-compress-output -T Test || true) davix-0.8.0/test/TestcaseHandler.cpp0000644000000000000000000001560614121063315016070 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "TestcaseHandler.hpp" #include #include #include #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() //------------------------------------------------------------------------------ // TermFormat: red //------------------------------------------------------------------------------ std::string TermFormat::red(const std::string &msg) { std::ostringstream ss; ss << "\033[91;1m" << msg << "\033[0m"; return ss.str(); } //------------------------------------------------------------------------------ // TermFormat: green //------------------------------------------------------------------------------ std::string TermFormat::green(const std::string &msg) { std::ostringstream ss; ss << "\033[92;1m" << msg << "\033[0m"; return ss.str(); } //------------------------------------------------------------------------------ // TermFormat: Blue //------------------------------------------------------------------------------ std::string TermFormat::blue(const std::string &msg) { std::ostringstream ss; ss << "\033[94;1m" << msg << "\033[0m"; return ss.str(); } //------------------------------------------------------------------------------ // TermFormat: purple //------------------------------------------------------------------------------ std::string TermFormat::purple(const std::string &msg) { std::ostringstream ss; ss << "\033[95;1m" << msg << "\033[0m"; return ss.str(); } //------------------------------------------------------------------------------ // Split utility function - move to common header eventually //------------------------------------------------------------------------------ static std::vector split(std::string data, std::string token) { std::vector output; size_t pos = std::string::npos; do { pos = data.find(token); output.push_back(data.substr(0, pos)); if(std::string::npos != pos) data = data.substr(pos + token.size()); } while (std::string::npos != pos); return output; } //------------------------------------------------------------------------------ // Multiply string //------------------------------------------------------------------------------ static std::string multiplyString(const std::string &s, size_t times) { std::ostringstream ss; for(size_t i = 0; i < times; i++) { ss << s; } return ss.str(); } //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ TestcaseHandler::TestcaseHandler(TestcaseHandler *parent) : mParent(parent), mFailed(false) { if(mParent) { mLevel = mParent->getNestLevel() + 1; } else { mLevel = 0; } mLinePrefix = multiplyString(" ", mLevel * 4); mLinePrefixLog = multiplyString(" ", (mLevel+1) * 4); } //------------------------------------------------------------------------------ // Set name //------------------------------------------------------------------------------ void TestcaseHandler::setName(const std::string &name) { mTestcaseName = name; std::cout << mLinePrefix << TermFormat::blue("[TEST] ") << name << std::endl; } //------------------------------------------------------------------------------ // Log info //------------------------------------------------------------------------------ void TestcaseHandler::info(const std::string &msg) { std::vector parts = split(msg, "\n"); std::ostringstream ss; for(size_t i = 0; i < parts.size(); i++) { ss << mLinePrefixLog << parts[i] << std::endl; } std::cout << ss.str(); } //------------------------------------------------------------------------------ // Log successful check //------------------------------------------------------------------------------ void TestcaseHandler::pass(const std::string &msg) { std::cout << mLinePrefixLog << TermFormat::green("[OK] ") << msg << std::endl; } //------------------------------------------------------------------------------ // Log error, fail the test //------------------------------------------------------------------------------ void TestcaseHandler::fail(const std::string &msg) { mFailed = true; std::vector parts = split(msg, "\n"); std::ostringstream ss; for(size_t i = 0; i < parts.size(); i++) { ss << mLinePrefixLog << TermFormat::red("[FAIL] ") << parts[i] << std::endl; } std::cout << ss.str(); } //------------------------------------------------------------------------------ // Check condition //------------------------------------------------------------------------------ void TestcaseHandler::check(bool test, const std::string &msg) { if(test) { pass(msg); } else { fail(msg); } } //------------------------------------------------------------------------------ // Get nest level //------------------------------------------------------------------------------ size_t TestcaseHandler::getNestLevel() const { return mLevel; } //------------------------------------------------------------------------------ // Test ok so far? //------------------------------------------------------------------------------ bool TestcaseHandler::ok() const { if(mFailed) { return false; } for(size_t i = 0; i < mChildren.size(); i++) { if(!mChildren[i]->ok()) { return false; } } return true; } //------------------------------------------------------------------------------ // Make child //------------------------------------------------------------------------------ TestcaseHandler& TestcaseHandler::makeChild() { mChildren.emplace_back(new TestcaseHandler(this)); return *(mChildren.back().get()); } //------------------------------------------------------------------------------ // Ensure no davix error occured //------------------------------------------------------------------------------ bool TestcaseHandler::checkDavixError(Davix::DavixError **err) { if(err && *err) { this->fail(SSTR("DavixError: " << (*err)->getErrMsg())); return false; } return true; } davix-0.8.0/test/unit/0000755000000000000000000000000014121063315013262 5ustar rootrootdavix-0.8.0/test/unit/context.cpp0000644000000000000000000000752214121063315015460 0ustar rootroot#include #include #include // instanciate and play with gates TEST(ContextTest, CreateDelete){ Davix::Context c1; Davix::Context* c2 = c1.clone(); ASSERT_TRUE(c2 != NULL); Davix::Context* c3 = c1.clone(); delete c2; delete c3; } TEST(RequestParametersTest, CreateDelete){ Davix::RequestParams params; ASSERT_EQ(params.getSSLCACheck(), true); ASSERT_EQ(params.getOperationTimeout()->tv_sec, DAVIX_DEFAULT_OPS_TIMEOUT); ASSERT_EQ(params.getConnectionTimeout()->tv_sec, DAVIX_DEFAULT_CONN_TIMEOUT); ASSERT_TRUE((params.getClientCertCallbackX509().second == NULL)); ASSERT_TRUE((params.getClientCertCallbackX509().first == NULL)); ASSERT_TRUE( params.getTransparentRedirectionSupport()); params.setSSLCAcheck(false); struct timespec timeout_co, timeout_ops; timeout_co.tv_sec =10; timeout_co.tv_nsec=99; timeout_ops.tv_sec=20; timeout_ops.tv_nsec=0xFF; ASSERT_EQ(params.getSSLCACheck(), false); params.setOperationTimeout(&timeout_co); ASSERT_EQ(params.getOperationTimeout()->tv_sec, 10); params.setConnectionTimeout(&timeout_ops); ASSERT_EQ(params.getConnectionTimeout()->tv_sec, 20); params.setTransparentRedirectionSupport(false); ASSERT_FALSE( params.getTransparentRedirectionSupport()); Davix::RequestParams p2(¶ms); Davix::RequestParams p3(p2); ASSERT_EQ(p2.getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p3.getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p2.getConnectionTimeout()->tv_sec, 20); ASSERT_EQ(p3.getConnectionTimeout()->tv_sec, 20); ASSERT_FALSE( p2.getTransparentRedirectionSupport()); Davix::RequestParams p4 = p3; // test deep copy ASSERT_EQ(p2.getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p3.getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p4.getConnectionTimeout()->tv_sec, 20); } TEST(RequestParametersTest, CreateDeleteDyn){ Davix::RequestParams* params = new Davix::RequestParams(); ASSERT_EQ(params->getSSLCACheck(), true); ASSERT_EQ(params->getOperationTimeout()->tv_sec, DAVIX_DEFAULT_OPS_TIMEOUT); ASSERT_EQ(params->getConnectionTimeout()->tv_sec, DAVIX_DEFAULT_CONN_TIMEOUT); ASSERT_TRUE(params->getClientCertCallbackX509().second == NULL); ASSERT_TRUE(params->getClientCertCallbackX509().first == NULL); params->setSSLCAcheck(false); struct timespec timeout_co, timeout_ops; timeout_co.tv_sec =10; timeout_co.tv_nsec=99; timeout_ops.tv_sec=20; timeout_ops.tv_nsec=0xFF; ASSERT_EQ(params->getSSLCACheck(), false); params->setOperationTimeout(&timeout_co); ASSERT_EQ(params->getOperationTimeout()->tv_sec, 10); params->setConnectionTimeout(&timeout_ops); ASSERT_EQ(params->getConnectionTimeout()->tv_sec, 20); Davix::RequestParams *p2 = new Davix::RequestParams(params); Davix::RequestParams *p3 = new Davix::RequestParams(*p2); Davix::RequestParams p4(params); Davix::RequestParams p5(*p3); ASSERT_EQ(p2->getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p3->getOperationTimeout()->tv_sec, 10); ASSERT_EQ(p2->getConnectionTimeout()->tv_sec, 20); ASSERT_EQ(p3->getConnectionTimeout()->tv_sec, 20); delete params; delete p2; delete p3; } TEST(DavixErrorTest, CreateDelete){ Davix::DavixError err("test_dav_scope", Davix::StatusCode::IsNotADirectory, " problem"); ASSERT_EQ(err.getErrMsg(), " problem"); ASSERT_EQ(err.getStatus(), Davix::StatusCode::IsNotADirectory); Davix::DavixError * err2=NULL; Davix::DavixError::setupError(&err2,"test_dav_scope2", Davix::StatusCode::ConnectionProblem, "connexion problem"); ASSERT_EQ(err2->getErrMsg(), "connexion problem"); ASSERT_EQ(err2->getStatus(), Davix::StatusCode::ConnectionProblem); Davix::DavixError::clearError(&err2); Davix::DavixError::clearError(&err2); } davix-0.8.0/test/unit/CMakeLists.txt0000644000000000000000000000241314121063315016022 0ustar rootroot#------------------------------------------------------------------------------- # Make gtest / gmock available for all targets that need it #------------------------------------------------------------------------------- set(BUILD_SHARED_LIBS OFF) set(GTEST "${CMAKE_SOURCE_DIR}/deps/googletest/googletest/") set(GTEST_BINARY_DIR "${CMAKE_BINARY_DIR}/deps/googletest/googletest/") add_subdirectory("${GTEST}" "${GTEST_BINARY_DIR}") add_definitions( -DTEST_VALID_CERT="${TEST_CRED_PATH}" -DTEST_VALID_CERT_PASS="${TEST_CRED_PASS}") add_executable(davix-unit-tests ../drunk-server/DrunkServer.cpp cache.cpp chrono.cpp config-parser.cpp content-provider.cpp context.cpp datetime.cpp digest-extractor.cpp gcloud.cpp metalink-replica.cpp neon.cpp parser.cpp response-buffer.cpp session-factory.cpp session.cpp status.cpp testcert.cpp typeconv.cpp utils.cpp xml-parser.cpp ) target_include_directories(davix-unit-tests PRIVATE ${PROJECT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${GTEST}/include ) target_link_libraries(davix-unit-tests davix_tool_lib libdavix gtest_main ${CMAKE_THREAD_LIBS_INIT} ${LIBSSL_PKG_LIBRARIES} ) install(TARGETS davix-unit-tests DESTINATION ${BIN_INSTALL_DIR}/) add_test(unit-tests davix-unit-tests) davix-0.8.0/test/unit/parser.cpp0000644000000000000000000005463714121063315015301 0ustar rootroot#include #include #include #include using namespace Davix; char normal_vector_range_cstr[] = "2894597227-2894599011,2894600789-2894601667,2894616262-2894617140,2894619865-2894623464,2906287380-2906491436,2907014445-2907025728,2907228889-2907232035,2913226796-2913239685,2913337799-2913538354," "2920341488-2920341660,2920376486-2920376595,2920377869-2920377987,2920398615-2920398721,2920400327-2920400537,2920407068-2920407263,2920534929-2920547408,2921309945-2921313091,2921314945-2921315052,2921353972-29" "21354079,2921355415-2921355519,2921381888-2921382006,2921385811-2921385927,2921386275-2921386384,2923832488-2923835417,2923842762-2923845463,2924345912-2924347518,2924350009-2924351321,2924382902-2924383512,2924" "429449-2924432057,2924516324-2924530870,2924556078-2924561911,2924634939-2924667831,2924698529-2924708631,2924718737-2924738719,2924778907-2924800458,2924878902-2924889766,2924898497-2924907906,2925060054-292507" "1537,2925082948-2925094376,2925120965-2925136938,2925148273-2925158039,2925178780-2925189684,2925374210-2925385276,2925801184-2925810640,2925970960-2926032309,2926283634-2926317832,2926329105-2926340581,29265320" "22-2926541735,2926546946-2926552967,2926597986-2926610425,2926638816-2926644264,2926651300-2926658488,2926813925-2926848245,2927386412-2927397410,2933217130-2933259050,2933262387-2933302854,2933329834-2933334347" ",2933338835-2933343477,2933349022-2933358181,2933365316-2933466065,2933626155-2933770574,2933848103-2933862205,2933917894-2933955396,2934057518-2934258138,2935669360-2935844362,2935849059-2935877127,2935879476-2" "935885804,2935908849-2935941795,2935944191-2936003068,2936005415-2936088351,2936197558-2936205691,2936213456-2936221551,2936225112-2936228755,2936247929-2936256670,2936263673-2936280963,2940282303-2940294386,294" "4698750-2945205175,2945396985-2945397107,2945766398-2945766731,2945775515-2945780462,2946147455-2946150395,2946230445-2946234636,2946241098-2946252531,2946282324-2946298429,2946436685-2946452956,2946532686-29465" "36848,2946641704-2946673847,2946760945-2946793165,2946920499-2946924499,2947274177-2947275056,2947277728-2947279512,2947281290-2947282168,2947296763-2947297641,2947300366-2947303965,2958286340-2958492725,2959848059-2959860798" ",2959958124-2959961270,2966061833-2966074209,2966170876-2966372789,2973222698-2973222869,2973257655-2973257764,2973259043-2973259152,2973279662-2973279768,2973281374-2973281589,2973288114-2973288312,2973318356-2973328837,2973425694-2973428840," "2976471316-2976474220,2976481466-2976484169,2976983761-2976985381,2976987860-2976989172,2977019939-2977020545,2977064174-2977066750,2977146792-2977160755,2977185134-2977190682,2977262055-2977293837,2977323593-2977333439," "2977343224-2977362718,2977401793-2977422570,2977498630-2977509169,2977517744-2977526878,2977675930-2977687013,2977698033-2977709079,2977734868-2977750346,2977761310-2977770807,2977790863-2977801395,2977978772-2977989474,2978389575-2978398709," "2978552485-2978610681,2978850242-2978883265,2978894197-2978905293,2979090337-2979099769,2979104869-2979110654,2979154473-2979166708,2979194475-2979199737,2979206487-2979213303,2979363203-2979396434,2979916534-2979927163,2985820683-2985863430,2985866696-2985907937,2985935195-2985939801,2985944387-2985949123,2985954606-2985963642,2985970585-2986073297,2986244661-2986391877,2986471584-2986486117,2986542589-2986580155,2986682014-2986886459,2988278869-2988447401,2988452088-2988479695,2988482035-2988488170,2988510304-2988542091,2988544463-2988601553,2988603898-2988684202,2988788984-2988796734,2988804177-2988811923,2988815352-2988818817,2988837573-2988845953,2988852643-2988869416,2992871574-2992883478,2996506775-2996965110,2997190827-2997190949,2997548560-2997548924,2997557956-2997563036,2997937427-2997941053,2998021650-2998025988,2998032525-2998044002,2998073943-2998090372,2998232114-2998248632,2998327934-2998332159,2998438036-2998470383,2998558645-2998591384,2998720455-2998724414,2999082210-2999083089,2999085761-2999087545,2999089323-2999090201,2999104796-2999105674,2999108399-2999111998, 2694452992-2694465611,2746390592-2746402250,2798560058-2798571419,2804195110-2804400838,2805751552-2805762858,2805859068-2805862214,2811940340-2811950464,2812046764-2812251087,2813703640-2813703814," "2819114229-2819114338,2819115652-2819115761,2819136413-2819136519,2819138125-2819138337,2819144814-2819145015,2819174973-2819186728,2819283826-2819286972,2819288838-2819288945,2819327826-2819327933,2819329269-28" "19329373,2819355743-2819355871,2819359717-2819359834,2819360180-2819360297,2821830034-2821832958,2821840349-2821843110,2822362368-2822363981,2822366454-2822367777,2822397860-2822398458,2822440809-2822443382,2822" "521209-2822534994,2822558999-2822564556,2822635102-2822666100,2822695336-2822705027,2822714640-2822733567,2822771618-2822791908,2822866132-2822876379,2822884625-2822893492,2823041407-2823052245,2823062999-282307" "3783,2823098969-2823114083,2823124792-2823134031,2823153653-2823163909,2823338124-2823348557,2823738948-2823747837,2823898889-2823955268,2824190305-2824222631,2824233317-2824244161,2824425048-2824434424,28244394" "86-2824445166,2824488577-2824500792,2824528659-2824533870,2824540565-2824547393,2824694274-2824726649,2825235071-2825245434,2831022985-2831065125,2831068370-2831108767,2831135652-2831140188,2831144741-2831149437" ",2831154915-2831163895,2831170853-2831272511,2831440783-2831586337,2831665263-2831679584,2831735448-2831773114,2831873965-2832075890,2833445981-2833611751,2833616420-2833643532,2833645857-2833651889,2833673852-2" "833705305,2833707683-2833764157,2833766480-2833845088,2833947916-2833955670,2833963034-2833970747,2833974199-2833977678,2833996116-2834004435,2834011055-2834027584,2837963479-2837975148,2841911291-2842391545,284" "2581999-2842582121,2842937329-2842937678,2842946394-2842951289,2843325409-2843329045,2843408591-2843412887,2843419493-2843431179,2843461534-2843478329,2843621898-2843638611,2843718479-2843722767,2843830205-28438" "63003,2843952215-2843985337,2844117237-2844121570,2844474125-2844475004,2844477676-2844479460,2844481238-2844482116,2844496711-2844497589,2844500314-2844503913,2849752576-2849764487,2855338133-2855542823,2856891" "989-2856907940,2863121983-2863135646,2863232633-2863431065,2864879845-2864880018,2864915167-2864915280,2864916579-2864916688,2864937365-2864937471,2864939077-2864939290,2864945837-2864946035,2870336419-287035218" "1,2870354035-2870354142,2870393010-2870393117,2870394453-2870394557,2870420895-2870421012"; char singular_vector_range_cstr[] = "2894597227-2894599011,2894600789-2894601667,2894616262-2894617140,2894619865-2894623464,2906287380-2906491436,2907014445-2907025728,2907228889-2907232035,2913226796-2913239685,2913337799-2913538354," "2920341488-2920341660,2920376486-2920376595,2920377869-2920377987,2920398615-2920398721,2920400327-2920400537,2920407068-2920407263,2920534929-2920547408,2921309945-2921313091,2921314945-2921315052,2921353972-29" "21354079,2921355415-2921355519,2921381888-2921382006,2921385811-2921385927,2921386275-2921386384,2923832488-2923835417,2923842762-2923845463,2924345912-2924347518,2924350009-2924351321,2924382902-2924383512,2924" "429449-2924432057,2924516324-2924530870,2924556078-2924561911,2924634939-2924667831,2924698529-2924708631,2924718737-2924738719,2924778907-2924800458,2924878902-2924889766,2924898497-2924907906,2925060054-292507" "1537,2925082948-2925094376,2925120965-2925136938,2925148273-2925158039,2925178780-2925189684,2925374210-2925385276,2925801184-2925810640,2925970960-2926032309,2926283634-2926317832,2926329105-2926340581,29265320" "22-2926541735,2926546946-2926552967,2926597986-2926610425,2926638816-2926644264,2926651300-2926658488,2926813925-2926848245,2927386412-2927397410,2933217130-2933259050,2933262387-2933302854,2933329834-2933334347" ",2933338835-2933343477,2933349022-2933358181,2933365316-2933466065,2933626155-2933770574,2933848103-2933862205,2933917894-2933955396,2934057518-2934258138,2935669360-2935844362,2935849059-2935877127,2935879476-2" "935885804,2935908849-2935941795,2935944191-2936003068,2936005415-2936088351,2936197558-2936205691,2936213456-2936221551,2936225112-2936228755,2936247929-2936256670,2936263673-2936280963,2940282303-2940294386,294" "4698750-2945205175,2945396985-2945397107,2945766398-2945766731,2945775515-2945780462,2946147455-2946150395,2946230445-2946234636,2946241098-2946252531,2946282324-2946298429,2946436685-2946452956,2946532686-29465" "36848,2946641704-2946673847,2946760945-2946793165,2946920499-2946924499,2947274177-2947275056,2947277728-2947279512,2947281290-2947282168,2947296763-2947297641,2947300366-2947303965,2958286340-2958492725,2959848059-2959860798" ",2959958124-2959961270,2966061833-2966074209,2966170876-2966372789,2973222698-2973222869,2973257655-2973257764,2973259043-2973259152,2973279662-2973279768,2973281374-2973281589,2973288114-2973288312,2973318356-2973328837,2973425694-2973428840," "2976471316-2976474220,2976481466-2976484169,2976983761-2976985381,2976987860-2976989172,2977019939-2977020545,2977064174-2977066750,2977146792-2977160755,2977185134-2977190682,2977262055-2977293837,2977323593-2977333439," "2977343224-2977362718,2977401793-2977422570,2977498630-2977509169,2977517744-2977526878,2977675930-2977687013,2977698033-2977709079,2977734868-2977750346,2977761310-2977770807,2977790863-2977801395,2977978772-2977989474,2978389575-2978398709," "2978552485-2978610681,2978850242-2978883265,2978894197-2978905293,2979090337-2979099769,2979104869-2979110654,2979154473-2979166708,2979194475-2979199737,2979206487-2979213303,2979363203-2979396434,2979916534-2979927163,2985820683-2985863430,2985866696-2985907937,2985935195-2985939801,2985944387-2985949123,2985954606-2985963642,2985970585-2986073297,2986244661-2986391877,2986471584-2986486117,2986542589-2986580155,2986682014-2986886459,2988278869-2988447401,2988452088-2988479695,2988482035-2988488170,2988510304-2988542091,2988544463-2988601553,2988603898-2988684202,2988788984-2988796734,2988804177-2988811923,2988815352-2988818817,2988837573-2988845953,2988852643-2988869416,2992871574-2992883478,2996506775-2996965110,2997190827-2997190949,2997548560-2997548924,2997557956-2997563036,2997937427-2997941053,2998021650-2998025988,2998032525-2998044002,2998073943-2998090372,2998232114-2998248632,2998327934-2998332159,2998438036-2998470383,2998558645-2998591384,2998720455-2998724414,2999082210-2999083089,2999085761-2999087545,2999089323-2999090201,2999104796-2999105674,2999108399-2999111998, 2694452992-2694465611,2746390592-2746402250,2798560058-2798571419,2804195110-2804400838,2805751552-2805762858,2805859068-2805862214,2811940340-2811950464,2812046764-2812251087,2813703640-2813703814," "2819114229-2819114338,2819115652-2819115761,2819136413-2819136519,2819138125-2819138337,2819144814-2819145015,2819174973-2819186728,2819283826-2819286972,2819288838-2819288945,2819327826-2819327933,2819329269-28" "19329373,2819355743-2819355871,2819359717-2819359834,2819360180-2819360297,2821830034-2821832958,2821840349-2821843110,2822362368-2822363981,2822366454-2822367777,2822397860-2822398458,2822440809-2822443382,2822" "521209-2822534994,2822558999-2822564556,2822635102-2822666100,2822695336-2822705027,2822714640-2822733567,2822771618-2822791908,2822866132-2822876379,2822884625-2822893492,2823041407-2823052245,2823062999-282307" "3783,2823098969-2823114083,2823124792-2823134031,2823153653-2823163909,2823338124-2823348557,2823738948-2823747837,2823898889-2823955268,2824190305-2824222631,2824233317-2824244161,2824425048-2824434424,28244394" "86-2824445166,2824488577-2824500792,2824528659-2824533870,2824540565-2824547393,2824694274-2824726649,2825235071-2825245434,2831022985-2831065125,2831068370-2831108767,2831135652-2831140188,2831144741-2831149437" ",2831154915-2831163895,2831170853-2831272511,2831440783-2831586337,2831665263-2831679584,2831735448-2831773114,2831873965-2832075890,2833445981-2833611751,2833616420-2833643532,2833645857-2833651889,2833673852-2" "833705305,2833707683-2833764157,2833766480-2833845088,2833947916-2833955670,2833963034-2833970747,2833974199-2833977678,2833996116-2834004435,2834011055-2834027584,2837963479-2837975148,2841911291-2842391545,284" "2581999-2842582121,2842937329-2842937678,2842946394-2842951289,2843325409-2843329045,2843408591-2843412887,2843419493-2843431179,2843461534-2843478329,2843621898-2843638611,2843718479-2843722767,2843830205-28438" "63003,2843952215-2843985337,2844117237-2844121570,2844474125-2844475004,2844477676-2844479460,2844481238-2844482116,2844496711-2844497589,2844500314-2844503913,2849752576-2849764487,2855338133-2855542823,2856891" "989-2856907940,2863121983-2863135646,2863232633-2863431065,2864879845-2864880018,2864915167-2864915280,2864916579-2864916688,2864937365-2864937471,2864939077-2864939290,2864945837-2864946035,2870336419-287035218" "1,2870354035-2870354142,2870393010-2870393117,2870394453-2870394557,2870420895-2870421012,2870424812-2870424933,2870425283-2870425398,2872897076-2872899957,2872907320-2872910179,2873421207-2873422827,2873425312-" "2873426624,2873459902-2873460505,2873501613-2873504138,2873579634-2873593015,2873616270-2873621691,2873690666-2873720736,2873749003-2873758321,2873767613-2873785919,2873822523-2873842126,2873914014-2873923939,28" "73932161-2873940985,2874086014-2874096421,2874106823-2874117213,2874141572-2874156207,2874166520-2874175394,2874194283-2874204212,2874372723-2874382807,2874761523-2874770206,2874918539-2874973443,2875202781-2875" "234075,2875244393-2875254892,2875429805-2875438930,2875443796-2875449344,2875491430-2875503320,2875530432-2875535526,2875541928-2875548496,2875690125-2875721370,2876213600-2876223621,2881893880-2881936152,288193" "9433-2881980116,2882007211-2882011755,2882016296-2882021005,2882026484-2882035590,2882042577-2882144346,2882313188-2882459082,2882537928-2882552213,2882608291-2882645978,2882747765-2882950560,2884257342-28844154" "78,2884420113-2884446503,2884448822-2884454634,2884475526-2884505692,2884508048-2884562124,2884564433-2884639476,2884735800-2884743363,2884750668-2884758224,2884761726-2884765245,2884783598-2884791660,2884798311" "-2884814319,2888674449-2888686751,2892050274-2892515560,2892708900-2892709022,2893068732-2893069081,2893077811-2893082715,2893451044-2893454294,2893534657-2893538912,2893545469-2893557026,2893587035-2893603411,2" "893744017-2893760682,2893840332-2893844616,2893950557-2893982883,2894070929-2894103592,2894232130-2894235963,2894593676-2894594555"; int parse_range(std::istringstream & stream, size_t & n, dav_off_t & begin, dav_off_t & end){ std::string part; char trash; if(stream.eof()) return -1; std::getline(stream, part, ','); std::istringstream ss(part); ss >> begin; ss >> trash; ss >> end; std::cout << "range: " << begin << " " << end << std::endl; return ++n; } // with this number of element, the result will be exactly 178 *2 = 356 elems // regression test for LCGUTIL-456 TEST(IOVecMultiPartPaser, generateSingularRangeTest){ std::string singular_vector_range(singular_vector_range_cstr); std::istringstream stream(singular_vector_range); size_t n =0; OffsetCallback generator_range( std::bind(&parse_range, std::ref(stream), std::ref(n), std::placeholders::_1, std::placeholders::_2)); std::vector< std::pair > res = generateRangeHeaders(3900, generator_range); ASSERT_EQ(356, n); ASSERT_EQ(2, res.size()); for(std::vector >::iterator it = res.begin(); it < res.end(); ++it){ ASSERT_EQ(178, it->first); ASSERT_LE(5, it->second.size()); } } // with this number of element, the result will be exactly 178 *2 = 356 elems // regression test for LCGUTIL-456 TEST(IOVecMultiPartPaser, generateNormalRangeTest){ std::string singular_vector_range(normal_vector_range_cstr); std::istringstream stream(singular_vector_range); size_t n =0; OffsetCallback generator_range( std::bind(&parse_range, std::ref(stream), std::ref(n), std::placeholders::_1, std::placeholders::_2)); std::vector< std::pair > res = generateRangeHeaders(3900, generator_range); ASSERT_EQ(287, n); ASSERT_EQ(2, res.size()); std::pair e = res.at(0); ASSERT_EQ(178, e.first); ASSERT_LE(5, e.second.size()); e = res.at(1); ASSERT_EQ(287-178, e.first); ASSERT_LE(5, e.second.size()); } TEST(IOVecMultiPartParser, headerParser){ std::string header; dav_size_t size; dav_off_t offset; header = "Content-type: application/xml"; // random generic header int ret = find_header_params((char*) header.c_str(), header.size(), &size, &offset); ASSERT_EQ(ret,0); header = "big brother is wathing you"; ret = find_header_params((char*) header.c_str(), header.size(), &size, &offset); ASSERT_EQ(ret,-1); header = "Content-Range: bytes 600-900/8000"; ret = find_header_params((char*) header.c_str(), header.size(), &size, &offset); ASSERT_EQ(1,ret); ASSERT_EQ(301, size); ASSERT_EQ(600, offset); header = "conTent-range: bytes 600-900/8000"; // break case ret = find_header_params((char*) header.c_str(), header.size(), &size, &offset); ASSERT_EQ(1,ret); ASSERT_EQ(301, size); ASSERT_EQ(600, offset); header = "conTent-range: bytes 600ssss-9e00/8000"; // break case ret = find_header_params((char*) header.c_str(), header.size(),&size, &offset); ASSERT_EQ(ret,-1); header = "Content-Range: GalaticCreditStandard 600-900/8000"; ret = find_header_params((char*) header.c_str(), header.size(), &size, &offset); ASSERT_EQ(-1,ret); } TEST(IOVecMultiPartParser, BoundaryExtract){ std::string header, boundary; DavixError* tmp_err = NULL; header = " multipart/mixed; boundary=gc0p4Jq0M2Yt08jU534c0p"; int ret = http_extract_boundary_from_content_type(header, boundary, &tmp_err); ASSERT_EQ(0,ret ); ASSERT_STREQ(boundary.c_str(), "gc0p4Jq0M2Yt08jU534c0p"); ASSERT_EQ(NULL, tmp_err); boundary = ""; header = " multipart/mixed; boundary="; ret = http_extract_boundary_from_content_type(header, boundary, &tmp_err); ASSERT_EQ(-1,ret ); DavixError::clearError(&tmp_err); boundary = ""; header = " multipart/mixed; boundary=\"helloworld\""; ret = http_extract_boundary_from_content_type(header, boundary, &tmp_err); ASSERT_EQ(0,ret ); ASSERT_STREQ(boundary.c_str(), "helloworld"); ASSERT_EQ(NULL, tmp_err); boundary = ""; header = " multipart/mixed; boundary=helloworld; some trash strng"; ret = http_extract_boundary_from_content_type(header, boundary, &tmp_err); ASSERT_EQ(0,ret ); ASSERT_STREQ(boundary.c_str(), "helloworld"); ASSERT_EQ(NULL, tmp_err); } int numb_it=0; static int callback_offset_stupid(dav_off_t & begin, dav_off_t & end){ begin = numb_it*1000+100; end=numb_it*1000+500; numb_it++; if(numb_it > 1000) return -1; return 0; } TEST(headerParser, generateRange){ std::string header; const dav_size_t max_header_size = rand()%8000+30; OffsetCallback o(callback_offset_stupid); std::vector > ranges; ranges = generateRangeHeaders(max_header_size, o); std::cout << " ranges size " << ranges.size() << std::endl; for(std::vector > ::iterator it = ranges.begin(); it < ranges.end(); it++){ ASSERT_LE(it->second.size(), max_header_size+20); ASSERT_GE(it->first, 1); std::cout << "NRange: " << (*it).first << std::endl; std::cout << "Range: " << (*it).second << std::endl; } ASSERT_LE(2, ranges.size()); } // URL parser TEST(UriTests, testRelativeUri){ Davix::Uri u("http://datagrid.lbl.gov/testdata/R/test01.data"); std::string proto_rel("//example.org/test"), abs_path("/hello/world/"), rel_path("blabla/test"); Davix::Uri res = Uri::fromRelativePath(u, proto_rel); ASSERT_EQ(StatusCode::OK, res.getStatus()); ASSERT_STREQ("http://example.org/test", res.getString().c_str()); res = Uri::fromRelativePath(u, abs_path); ASSERT_EQ(StatusCode::OK, res.getStatus()); ASSERT_STREQ("http://datagrid.lbl.gov/hello/world/", res.getString().c_str()); res = Uri::fromRelativePath(u, rel_path); ASSERT_EQ(StatusCode::OK, res.getStatus()); ASSERT_STREQ("http://datagrid.lbl.gov/testdata/R/test01.data/blabla/test", res.getString().c_str()); } TEST(UriTests, addParamWithSlashes) { Davix::Uri u("http://datagrid.lbl.gov/testdata/R/test01.data"); ASSERT_EQ(u.getString(), "http://datagrid.lbl.gov/testdata/R/test01.data"); u.addQueryParam("test1", "test2"); u.addQueryParam("test1/with/slashes", "aaa/aaa"); u.addQueryParam("test1!with?evil*chars", "aaa/aaa"); ASSERT_EQ(u.getString(), "http://datagrid.lbl.gov/testdata/R/test01.data?test1=test2&test1%2Fwith%2Fslashes=aaa%2Faaa&test1%21with%3Fevil%2Achars=aaa%2Faaa"); std::string hugeKey, hugeVal; hugeKey.resize(8000); hugeVal.resize(8000); for(uint64_t i = 0; i < 8000; i++) { hugeKey[i] = '/'; hugeVal[i] = '/'; } u.addQueryParam(hugeKey, hugeVal); } TEST(UriTests, ips) { Davix::Uri u("http://192.168.1.1/testdata/R/test01.data"); ASSERT_EQ(u.getStatus(), StatusCode::OK); ASSERT_EQ(u.getString(), "http://192.168.1.1/testdata/R/test01.data"); ASSERT_EQ(u.getPort(), 0); ASSERT_EQ(u.getHost(), "192.168.1.1"); u = Davix::Uri("http://192.168.1.1:123/testdata/R/test01.data"); ASSERT_EQ(u.getStatus(), StatusCode::OK); ASSERT_EQ(u.getString(), "http://192.168.1.1:123/testdata/R/test01.data"); ASSERT_EQ(u.getPort(), 123); ASSERT_EQ(u.getHost(), "192.168.1.1"); u = Davix::Uri("http://[2001:1458:301:a8ae::100:23]:443/testdata/R/test01.data"); ASSERT_EQ(u.getStatus(), StatusCode::OK); ASSERT_EQ(u.getString(), "http://[2001:1458:301:a8ae::100:23]:443/testdata/R/test01.data"); ASSERT_EQ(u.getPort(), 443); ASSERT_EQ(u.getHost(), "[2001:1458:301:a8ae::100:23]"); u = Davix::Uri("http://[2001:1458:301:a8ae::100:23]/testdata/R/test01.data"); ASSERT_EQ(u.getStatus(), StatusCode::OK); ASSERT_EQ(u.getString(), "http://[2001:1458:301:a8ae::100:23]/testdata/R/test01.data"); ASSERT_EQ(u.getPort(), 0); ASSERT_EQ(u.getHost(), "[2001:1458:301:a8ae::100:23]"); } davix-0.8.0/test/unit/xml-parser.cpp0000644000000000000000000007350314121063315016070 0ustar rootroot#include #include #include #include #include #include "libs/datetime/datetime_utils.hpp" #include #include #include #include #include #include #include #include #include #include const char* simple_stat_propfind_content = "" "" "" "/pnfs/desy.de/data/dteam/" "" "" "2012-10-22T07:50:51Z" "Mon, 22 Oct 2012 07:50:51 GMT" "dteam" "" "" "text/html" "000033743EFFCFC64360A82A6B0A814C2C87_-2022446850" "" "HTTP/1.1 200" "" "" ""; const char* simple_bad_content_http = "lkfsdlkfdsklmkmlkmlsfdoiretopôiptrefdlzeamllvmg" "sfdfsjgsdmbkmlbkl,,klmd848486468+4666666666666666" "sfdfsjgsdmbkmlbkl,,klmd848486468+4666666666666666" "sfdfsjgsdmbkmlbkl,,klmd848486468+4666666666666666" "sfdfsjgsdmbkmlbkl,,klmd848486468+4666666666666666" "sfdfsjgsdmbkmlbkl,,klmd848486468+4666666666666666"; const char* recursive_listing = " " " " " /pnfs/desy.de/data/dteam/" " " " " " 2012-10-22T10:50:46Z" " Mon, 22 Oct 2012 10:50:46 GMT" " dteam" " " " " " text/html" " 000033743EFFCFC64360A82A6B0A814C2C87_-2011651620" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/g2/" " " " " " 2012-10-22T01:14:23Z" " Mon, 22 Oct 2012 01:14:23 GMT" " g2" " " " " " text/html" " 000071F56A6971D444C6B923205B8A6C8B5B_-2046234581" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/generated/" " " " " " 2011-12-19T09:48:58Z" " Mon, 19 Dec 2011 09:48:58 GMT" " generated" " " " " " text/html" " 0000CF0EFBD2343E45099A3664C9E52A5035_1438212009" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/test/" " " " " " 2012-03-23T14:14:35Z" " Fri, 23 Mar 2012 14:14:35 GMT" " test" " " " " " text/html" " 00002EBC0878E36B43FE98754FC725CFFA59_1072213609" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/speed_test2/" " " " " " 2012-03-23T15:58:26Z" " Fri, 23 Mar 2012 15:58:26 GMT" " speed_test2" " " " " " text/html" " 000001C9BF5FAA6740F2BCFD7F9454C7CEF0_1078444680" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/speed_test/" " " " " " 2012-03-23T15:44:47Z" " Fri, 23 Mar 2012 15:44:47 GMT" " speed_test" " " " " " text/html" " 000003C8148BB6574B03820B3953A1E09E3E_1077625629" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/speed_test3/" " " " " " 2012-03-23T16:55:34Z" " Fri, 23 Mar 2012 16:55:34 GMT" " speed_test3" " " " " " text/html" " 0000C0F214B189464616B08D01F540445829_1081872745" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/testwrite" " " " " " 2012-03-23T16:47:11Z" " Fri, 23 Mar 2012 16:47:11 GMT" " testwrite" " 65536" " 0000DA13494AE9764029BE48D6D264AF2E0C_1081369798" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/test_dir/" " " " " " 2012-05-24T16:22:28Z" " Thu, 24 May 2012 16:22:28 GMT" " test_dir" " " " " " text/html" " 000066C9BA492C3440E081A6CF0A75479B98_2141719820" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/testgfgfgfdg9999tw3" " " " " " 2012-07-13T13:25:01Z" " Fri, 13 Jul 2012 13:25:02 GMT" " testgfgfgfdg9999tw3" " 187" " 0000AF211A13EC96400393F4769AC24CD82F_-2138860744" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/UGRtest/" " " " " " 2012-07-19T14:50:51Z" " Thu, 19 Jul 2012 14:50:51 GMT" " UGRtest" " " " " " text/html" " 00009BF2D07746D14CB4BEB74097309AB707_-1615312788" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/ugrtest/" " " " " " 2012-07-19T14:53:42Z" " Wed, 25 Jul 2012 10:01:02 GMT" " ugrtest" " " " " " text/html" " 0000D40132559B244F7597EDB2EAE617D56B_-1114301154" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/fbxtest.txt" " " " " " 2012-07-19T14:38:31Z" " Thu, 19 Jul 2012 14:38:33 GMT" " fbxtest.txt" " text/plain" " 640999" " 00004769A9ACEB1647EF8C8D6298FE1D5909_-1616050534" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/testdir/" " " " " " 2012-07-19T14:39:05Z" " Thu, 19 Jul 2012 14:39:05 GMT" " testdir" " " " " " text/html" " 0000CA3E0FFC5E684F639541654D7FD99B72_-1616018106" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/testdir8888/" " " " " " 2012-07-19T14:39:16Z" " Thu, 19 Jul 2012 14:39:16 GMT" " testdir8888" " " " " " text/html" " 0000BFDBF3DE079E407F92396F58D65FE656_-1616006747" " " " HTTP/1.1 200" " " " " " " " /pnfs/desy.de/data/dteam/testdir8889/" " " " " " 2012-07-19T14:51:35Z" " Thu, 19 Jul 2012 14:51:35 GMT" " testdir8889" " " " " " text/html" " 0000DB00326864EC43529E1CE8137A4F9A00_-1615267437" " " " HTTP/1.1 200" " " " " " "; const char * caldav_item = "" "/dteam/Wed, 18 Dec 2013 14:41:52 GMTdteam2013-12-18T14:41:52ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/foo2.txt12Sat, 16 Jul 2011 17:03:02 GMTfoo2.txt2011-07-16T17:03:02ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/foo.txt12Sat, 16 Jul 2011 06:30:51 GMTfoo.txt2011-07-16T06:30:51ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/EA-check-file-N_1-13112628794440Thu, 21 Jul 2011 15:41:19 GMTEA-check-file-N_1-13112628794442011-07-21T15:41:19ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/fpalapzorp1286144Wed, 14 Sep 2011 11:43:41 GMTfpalapzorp2011-09-14T11:43:41ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/EA-check-file-N_1-13141259875900Tue, 23 Aug 2011 18:59:47 GMTEA-check-file-N_1-13141259875902011-08-23T18:59:47ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/somefilename1286144Wed, 14 Sep 2011 14:16:03 GMTsomefilename2011-09-14T14:16:03ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found/dteam/generatedSat, 26 Feb 2011 14:39:48 GMTgenerated2011-02-26T14:39:48ZHTTP/1.1 200 OKHTTP/1.1 404 Not Found"; const char* list_item[] = { "g2", "generated", "test", "speed_test2", "speed_test", "speed_test3", "testwrite", "test_dir", "testgfgfgfdg9999tw3", "UGRtest", "ugrtest", "fbxtest.txt", "testdir", "testdir8888", "testdir8889" }; const char metalink_item_lcgdm[] = "" "" "" "" " 494391600" " " " http://datagrid.lbl.gov/testdata//L/test02.data" " " "" "" ""; const char metalink_item_generic[]= " " "" " " " " " " " example-md5-hash" " example-sha1-hash" " " " " " ftp://ftp.example1.com/example.ext" " ftp://ftp.example2.com/example.ext" " http://www.example1.com/example.ext " " http://www.example2.com/example.ext" " http://www.example3.com/example.ext " " http://www.ex.com/example.ext.torrent" " " " " " " " " " " " "; const std::string s3_xml_response = "a-random-random-bucket1000falseh1big.root2014-09-19T14:27:33.000Z"bf5b1efa7fe677965bf3ecd41e20be2a"280408881STANDARDmhellmicMartin Hellmichservices2014-10-03T14:58:12.000Z"3e73cc5c77799fd3e7a02c62474107bb"\t 19558 \tSTANDARDmhellmicMartin Hellmich"; const std::string s3_multipart_initiation_response = "" "" " example-bucket" " example-object" " EXAMPLEJZ6e0YupT2h66iePQCc9IEbYbDUy4RTpMeoSMLPRp8Z5o1u8feSRonpvnWsKKG35tI2LB9VDPiCgTy.Gq2VxQLYjrue4Nq.NBdqI-" " "; const std::string swift_xml_response = "photos/animals/photos/me.jpgb249a153f8f38b51e92916bbc6ea57ad2906image/jpeg2015-12-03T17:31:28.187370photos/plants/"; TEST(XmlParserInstance, createParser){ ASSERT_NO_THROW({ Davix::XMLSAXParser * parser = new Davix::XMLSAXParser(); delete parser; }); } TEST(XmlParserInstance, parseOneStat){ davix_set_log_level(DAVIX_LOG_ALL); Davix::DavPropXMLParser parser; ASSERT_NO_THROW({ int ret = parser.parseChunk(simple_stat_propfind_content, strlen(simple_stat_propfind_content)); if( ret !=0){ ASSERT_TRUE(false); } ASSERT_EQ(1u, parser.getProperties().size()); parser.parseChunk(NULL, 0); ASSERT_EQ(1u, parser.getProperties().size()); Davix::FileProperties f = parser.getProperties().at(0); ASSERT_TRUE(S_ISDIR(f.info.mode)); ASSERT_FALSE(S_ISLNK(f.info.mode)); ASSERT_STREQ("dteam",f.filename.c_str()); //q ASSERT_EQ(f.mtime, 1350892251L); }); } TEST(XMLParserInstance,ParseList){ ASSERT_NO_THROW({ Davix::DavPropXMLParser parser; int ret = parser.parseChunk(recursive_listing, strlen(recursive_listing)); if( ret !=0){ ASSERT_TRUE(false); } ASSERT_EQ(16u, parser.getProperties().size()); parser.parseChunk(NULL, 0); ASSERT_EQ(16u, parser.getProperties().size()); // test the parent directory stats Davix::FileProperties f = parser.getProperties().at(0); ASSERT_TRUE(S_ISDIR(f.info.mode)); ASSERT_FALSE(S_ISLNK(f.info.mode)); ASSERT_STREQ("dteam",f.filename.c_str()); for(int i =1; i < 16; ++i){ Davix::FileProperties f_local = parser.getProperties()[i]; ASSERT_STREQ(list_item[i-1], f_local.filename.c_str()); ASSERT_TRUE( f_local.info.size > 0 || S_ISDIR(f.info.mode)); } // test the children stats }); } TEST(XMLParserInstance, ParseCalDav){ ASSERT_NO_THROW({ davix_set_log_level(DAVIX_LOG_ALL); Davix::DavPropXMLParser parser; int ret = parser.parseChunk(caldav_item, strlen(caldav_item)); if( ret !=0){ ASSERT_TRUE(false); } ASSERT_GT(parser.getProperties().size(),0); }); } TEST(XmlParserInstance,parserNonWebdav){ Davix::DavPropXMLParser parser; try{ parser.parseChunk(simple_bad_content_http, strlen(simple_bad_content_http)); parser.parseChunk(NULL, 0); ASSERT_TRUE(false); }catch(Davix::DavixException & e){ std::cerr << "error : " << e.what(); ASSERT_EQ(0u, parser.getProperties().size()); ASSERT_TRUE(Davix::StatusCode::OK != e.code()); ASSERT_EQ(Davix::StatusCode::WebDavPropertiesParsingError, e.code()); } } TEST(XmlPaserInstance, destroyPartial){ davix_set_log_level(DAVIX_LOG_ALL); Davix::DavPropXMLParser* parser = new Davix::DavPropXMLParser(); ASSERT_NO_THROW({ int ret = parser->parseChunk(simple_stat_propfind_content, strlen(simple_stat_propfind_content)/2); if( ret !=0){ ASSERT_TRUE(false); } // destroy the parser with still parsing on the stack }); delete parser; } TEST(XmlMetalinkParserTest, parserMetalinkSimpl){ ASSERT_NO_THROW({ Davix::Context c; std::vector r; Davix::MetalinkParser parser(c, r); int ret = parser.parseChunk(metalink_item_lcgdm, strlen(metalink_item_lcgdm)); ASSERT_EQ(0, ret); ASSERT_EQ(1, r.size()); Davix::Uri u = r[0].getUri(); ASSERT_EQ(Davix::StatusCode::OK, u.getStatus()); ASSERT_STREQ("http://datagrid.lbl.gov/testdata//L/test02.data", u.getString().c_str()); ASSERT_EQ(494391600, parser.getSize()); }); } TEST(XmlMetalinkParserTest, parserMetalinkGeneric){ ASSERT_NO_THROW({ Davix::Context c; std::vector r; Davix::MetalinkParser parser(c, r); int ret = parser.parseChunk(metalink_item_generic, strlen(metalink_item_generic)); //std::cout << parser.getLastErr()->getErrMsg(); ASSERT_EQ(0, ret); // const Davix::Properties& p = parser.getProps(); ASSERT_EQ(8, r.size()); Davix::Uri u = r[0].getUri(); ASSERT_EQ(Davix::StatusCode::OK, u.getStatus()); ASSERT_STREQ("ftp://ftp.example1.com/example.ext", u.getString().c_str()); u = r[1].getUri(); ASSERT_STREQ("ftp://ftp.example2.com/example.ext", u.getString().c_str()); ASSERT_STREQ("ftp",u.getProtocol().c_str()); }); } TEST(XmlPTreeTest, testPTreeBase){ using namespace Davix::Xml; XmlPTree base(Attribute,"start", XmlPTree::ChildrenList(1, XmlPTree(Attribute, "hello", XmlPTree::ChildrenList(1, XmlPTree(CData, "BoB"))))); XmlPTree baseItem(Attribute, "start"); XmlPTree randomItem(Attribute, "no"); XmlPTree elem1(CData, "1"), elem2(CData, "2"), elemBob(CData, "BoB"); XmlPTree::ChildrenList l; l.push_back(elem1); l.push_back(elem2); l.push_back(elemBob); XmlPTree hello(Attribute, "hello", l), nihao(Attribute, "你好", XmlPTree::ChildrenList(1, elem1)); XmlPTree tree(Attribute, "start", XmlPTree::ChildrenList(1, hello)); ASSERT_TRUE( base.compareKey(baseItem)); ASSERT_TRUE( baseItem.compareKey(randomItem)); ASSERT_TRUE(base.compareNode(baseItem)); ASSERT_FALSE( randomItem.compareNode(baseItem)); ASSERT_FALSE(elemBob.compareNode(elem1)); ASSERT_TRUE( tree.matchTree(base)); ASSERT_FALSE( base.matchTree(tree)); ASSERT_FALSE( tree.matchTree(nihao)); } TEST(XmlPTreeTest, testPTreeChain){ using namespace Davix::Xml; XmlPTree base(Attribute,"start", XmlPTree::ChildrenList(1, XmlPTree(Attribute, "hello", XmlPTree::ChildrenList(1, XmlPTree(CData, "BoB"))))); XmlPTree baseItem(Attribute, "start"); XmlPTree randomItem(Attribute, "no"); XmlPTree helloItem(Attribute, "hello"); XmlPTree bobItem(CData, "BoB"); std::vector vec_node; std::vector res; res = base.findChain(vec_node); ASSERT_EQ(0, res.size()); vec_node.clear(); vec_node.push_back(baseItem); res = base.findChain(vec_node); ASSERT_EQ(1, res.size()); ASSERT_TRUE(res.at(0)->compareNode(baseItem)); ASSERT_EQ(res.at(0), &(base)); vec_node.clear(); // invalid nodes vec_node.push_back(randomItem); res = base.findChain(vec_node); ASSERT_EQ(0, res.size()); vec_node.clear(); vec_node.push_back(baseItem); vec_node.push_back(helloItem); vec_node.push_back(bobItem); res = base.findChain(vec_node); ASSERT_EQ(3, res.size()); ASSERT_TRUE(res.at(0)->compareNode(baseItem)); ASSERT_TRUE(res.at(1)->compareNode(helloItem)); ASSERT_TRUE(res.at(2)->compareNode(bobItem)); ASSERT_EQ(res.at(0), &(base)); ASSERT_EQ(res.at(1), &(*base.beginChildren())); ASSERT_EQ(res.at(2), &(*base.beginChildren()->beginChildren())); vec_node.clear(); vec_node.push_back(base); res = baseItem.findChain(vec_node); ASSERT_EQ(1, res.size()); ASSERT_TRUE(res.at(0)->compareNode(baseItem)); vec_node.clear(); } TEST(XmlS3parsing, TestListingBucket){ using namespace Davix; davix_set_log_level(DAVIX_LOG_ALL); S3PropParser parser; int ret = parser.parseChunk(s3_xml_response); ASSERT_EQ(ret, 0); ASSERT_EQ(3, parser.getProperties().size()); // verify name ASSERT_EQ(std::string("a-random-random-bucket"), parser.getProperties().at(0).filename); ASSERT_EQ(std::string("h1big.root"), parser.getProperties().at(1).filename); ASSERT_EQ(std::string("services"), parser.getProperties().at(2).filename); // verify size ASSERT_EQ(280408881, parser.getProperties().at(1).info.size); ASSERT_EQ(19558, parser.getProperties().at(2).info.size); } TEST(XmlMultiPartUploadInitiationResponse, BasicSanity) { using namespace Davix; davix_set_log_level(DAVIX_LOG_ALL); S3MultiPartInitiationParser parser; int ret = parser.parseChunk(s3_multipart_initiation_response); ASSERT_EQ(ret, 0); ASSERT_EQ(parser.getUploadId(), "EXAMPLEJZ6e0YupT2h66iePQCc9IEbYbDUy4RTpMeoSMLPRp8Z5o1u8feSRonpvnWsKKG35tI2LB9VDPiCgTy.Gq2VxQLYjrue4Nq.NBdqI-"); } TEST(XmlSwiftParsing, TestListingDir) { using namespace Davix; davix_set_log_level(DAVIX_LOG_ALL); SwiftPropParser parser; int ret = parser.parseChunk(swift_xml_response); ASSERT_EQ(ret, 0); ASSERT_EQ(3, parser.getProperties().size()); // verify name ASSERT_EQ(std::string("photos/animals/"), parser.getProperties().at(0).filename); ASSERT_EQ(std::string("photos/me.jpg"), parser.getProperties().at(1).filename); ASSERT_EQ(std::string("photos/plants/"), parser.getProperties().at(2).filename); // verify size ASSERT_EQ(2906, parser.getProperties().at(1).info.size); }davix-0.8.0/test/unit/metalink-replica.cpp0000644000000000000000000000345614121063315017217 0ustar rootroot#include #include #include #include TEST(MetalinkReplica, HeaderMetalinkParsing){ std::string header_key, header_value, header_key_location, header_value_torrent, header_value_invalid; Davix::Uri origin("http:////lxfsra04a04.cern.ch:80/dpm/cern.ch/home/dteam/group"), origin2("https://google.com/"); Davix::Uri u; int ret = -1; header_key = "Link"; header_key_location = "Location"; header_value = "; rel=describedby; type=\"application/metalink+xml\""; header_value_torrent = "; rel=describedby; type=\"application/x-bittorrent\"; name=\"differentname.ext\""; header_value_invalid = ""; ret = Davix::davix_metalink_header_parser(header_key, header_value, origin, u); ASSERT_EQ(ret,1); ASSERT_EQ(u.getStatus(), Davix::StatusCode::OK); ASSERT_STREQ("http://lxfsra04a04.cern.ch:80/dpm/cern.ch/home/dteam/group?metalink", u.getString().c_str()); ret = Davix::davix_metalink_header_parser(header_key, header_value, origin2, u); ASSERT_EQ(ret,1); ASSERT_EQ(u.getStatus(), Davix::StatusCode::OK); ASSERT_STREQ("https://lxfsra04a04.cern.ch:80/dpm/cern.ch/home/dteam/group?metalink", u.getString().c_str()); ret = Davix::davix_metalink_header_parser(header_key, header_value_torrent, origin, u); ASSERT_EQ(ret,0); ret = Davix::davix_metalink_header_parser(header_key_location, header_value, origin, u); ASSERT_EQ(ret, 0); ret = Davix::davix_metalink_header_parser(header_key_location, header_value_invalid, origin, u); ASSERT_EQ(ret, 0); } davix-0.8.0/test/unit/utils.cpp0000644000000000000000000002200714121063315015127 0ustar rootroot#include #include #include #include "libs/alibxx/crypto/base64.hpp" #include "libs/alibxx/crypto/hmacsha.hpp" #include #include #include #include #include using namespace std; using namespace Davix; using namespace StrUtil; TEST(StringUtils, splitok){ std::string str, delimiter; str= "hello world test"; delimiter= " "; std::vector res = tokenSplit(str, delimiter); ASSERT_EQ(3, res.size()); ASSERT_STREQ("hello", res.at(0).c_str()); str=" bytes 0-90/15872 \t"; delimiter="bytes -/\t"; res = tokenSplit(str, delimiter); ASSERT_EQ(3, res.size()); ASSERT_STREQ("0", res.at(0).c_str()); ASSERT_STREQ("90", res.at(1).c_str()); ASSERT_STREQ("15872", res.at(2).c_str()); str = " Obi;wan Kenobi.droid*pass$*"; delimiter=" ;.*$ù^°="; res = tokenSplit(str, delimiter); ASSERT_EQ(5, res.size()); ASSERT_STREQ("Obi", res.at(0).c_str()); ASSERT_STREQ("Kenobi", res.at(2).c_str()); } TEST(testBase64, cmpbase){ size_t s_buff= rand()%100000; char buff_input[s_buff]; for(size_t i = 0; i < s_buff; i++) buff_input[i]= (char) rand()%255; std::string conv = Base64::base64_encode((unsigned char*)buff_input, s_buff); // std::cout << conv << std::endl; std::string res= Base64::base64_decode(conv); ASSERT_EQ(s_buff, res.length()); ASSERT_TRUE( memcmp(buff_input, res.c_str(), s_buff) == 0); } TEST(testhmacsha1, testhmac){ const std::string data("obi wan kenobi"); const std::string key("bob dylan"); const std::string result("337a4432486ea5a175c35ed1a138d6f9dd481f15"); const std::string prod = hmac_sha1(key, data); std::ostringstream ss; ss << std::hex << prod; ASSERT_STREQ(prod.c_str(), ss.str().c_str()); } TEST(testS3, test_hash_s3){ const std::string key= "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; const std::string str("GET\n" "\n" "\n" "Tue, 27 Mar 2007 19:36:42 +0000\n" "/johnsmith/photos/puppy.jpg"); const std::string res("bWq2s1WEIj+Ydj0vQ697zp+IXMU="); const std::string hmac_str = hmac_sha1(key,str); const std::string prod = Base64::base64_encode((unsigned char*) hmac_str.c_str(), hmac_str.size()); std::cout << "hash : " << prod << std::endl; ASSERT_STREQ(res.c_str(), prod.c_str()); } TEST(testStringMode, test_mode){ mode_t m = 0755; string m_str = Tool::string_from_mode(m); //std::cout << m_str << std::endl; ASSERT_STREQ("-rwxr-xr-x", m_str.c_str()); m = 040777; m_str = Tool::string_from_mode(m); ASSERT_STREQ("drwxrwxrwx", m_str.c_str()); } TEST(testAuthS3, ReqToSign){ RequestParams params; Uri url("http://johnsmith.s3.amazonaws.com/photos/puppy.jpg"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; vec.push_back(std::pair("Date", "Tue, 27 Mar 2007 19:36:42 +0000")); S3::signRequest(params, "GET", url, vec); ASSERT_EQ(std::string("Authorization"),vec.at(1).first); ASSERT_EQ(std::string("AWS AKIAIOSFODNN7EXAMPLE:bWq2s1WEIj+Ydj0vQ697zp+IXMU="),vec.at(1).second); } TEST(testAuthS3, ReqToSignPostDelete){ RequestParams params; Uri url("http://johnsmith.s3.amazonaws.com/photos/puppy.jpg?delete"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; vec.push_back(std::pair("Date", "Tue, 27 Mar 2007 19:36:42 +0000")); S3::signRequest(params, "POST", url, vec); ASSERT_EQ(std::string("Authorization"),vec.at(1).first); ASSERT_EQ("AWS AKIAIOSFODNN7EXAMPLE:F/FLAv2x9llsMYvDJ79Sw2MuByU=", vec.at(1).second); } TEST(testAuthS3, ReqToSignAWS){ RequestParams params; Uri url("http://static.johnsmith.net:8080/db-backup.dat.gz"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; vec.push_back(HeaderLine("Date", "Tue, 27 Mar 2007 21:06:08 +0000")); vec.push_back(HeaderLine("x-amz-acl","public-read")); vec.push_back(HeaderLine("X-Amz-Meta-ReviewedBy", "joe@johnsmith.net,jane@johnsmith.net")); vec.push_back(HeaderLine("X-Amz-Meta-FileChecksum","0x02661779")); vec.push_back(HeaderLine("X-Amz-Meta-ChecksumAlgorithm", "crc32")); vec.push_back(HeaderLine("Content-Disposition","attachment; filename=database.dat")); vec.push_back(HeaderLine("Content-Encoding","gzip")); vec.push_back(HeaderLine("Content-Length","5913339")); S3::signRequest(params, "PUT", url, vec); ASSERT_EQ(std::string("Authorization"),vec.back().first); ASSERT_EQ(std::string("AWS AKIAIOSFODNN7EXAMPLE:mRp45AGRkcT9u0ssDHIkjUqmPWk="),vec.back().second); } TEST(testAuthS3, ReqToToken){ RequestParams params; Uri url("http://johnsmith.s3.amazonaws.com/photos/puppy.jpg"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; Uri u = S3::tokenizeRequest(params, "GET", url, vec, static_cast(1175139620UL)); Uri resu("http://johnsmith.s3.amazonaws.com/photos/puppy.jpg?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D&Expires=1175139620"); ASSERT_TRUE(StrUtil::compare_ncase(resu.getString(), u.getString()) ==0); } TEST(testAuthS3, ReqToTokenDelete){ RequestParams params; Uri url("http://johnsmith.s3.amazonaws.com/photos/puppy.jpg?delete"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; Uri u = S3::tokenizeRequest(params, "POST", url, vec, static_cast(1175139620UL)); ASSERT_EQ(u.getString(), "http://johnsmith.s3.amazonaws.com/photos/puppy.jpg?delete&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=fU7FkNg8QPiGj8YE62xbZuac6dQ%3D&Expires=1175139620"); } TEST(testAuthS3, ReqToTokenWithHeaders){ RequestParams params; Uri url("http://firwen-bucket.s3.amazonaws.com/testfile1234"); params.setAwsAuthorizationKeys("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "AKIAIOSFODNN7EXAMPLE"); HeaderVec vec; vec.push_back(HeaderLine("x-amz-meta-fed-acl", "adevress : rwx, furano : rwx")); Uri u = S3::tokenizeRequest(params, "PUT", url, vec, static_cast(1415835686)); Uri resu("http://firwen-bucket.s3.amazonaws.com/testfile1234?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=8DnY%2F3Te1GOcC01S6BGNHZErJMo%3d&Expires=1415835686&x-amz-meta-fed-acl=adevress%20%3a%20rwx%2c%20furano%20%3a%20rwx"); std::cout << u << "\n" << resu << std::endl; ASSERT_TRUE(StrUtil::compare_ncase(resu.getString(), u.getString()) ==0); } TEST(testAuthSwift, signUri){ RequestParams params; Uri url("https://hostname.com/containersth2873/objectfile1234"); params.setOSProjectID("21e698ff1238438fabc72e5cf9d59165"); Uri u = Swift::signURI(params, url); ASSERT_EQ(u.getString(), "https://hostname.com/v1/AUTH_21e698ff1238438fabc72e5cf9d59165/containersth2873/objectfile1234"); } TEST(CanonicalizedResourceQueryParams, BasicSanity) { //Uri url( } TEST(SessionPool, BasicSanity) { SessionPool pool; int out; pool.insert("test-1", 3); ASSERT_FALSE(pool.retrieve("test", out)); ASSERT_TRUE(pool.retrieve("test-1", out)); ASSERT_EQ(out, 3); ASSERT_FALSE(pool.retrieve("test-1", out)); pool.insert("test-2", 3); pool.insert("test-2", 4); pool.insert("test-2", 3); pool.insert("test-2", 5); ASSERT_TRUE(pool.retrieve("test-2", out)); ASSERT_EQ(out, 3); ASSERT_TRUE(pool.retrieve("test-2", out)); ASSERT_EQ(out, 4); ASSERT_TRUE(pool.retrieve("test-2", out)); ASSERT_EQ(out, 3); ASSERT_TRUE(pool.retrieve("test-2", out)); ASSERT_EQ(out, 5); } TEST(HeaderlineParser, BasicSanity) { HeaderlineParser parser(""); ASSERT_EQ(parser.getKey(), ""); ASSERT_EQ(parser.getValue(), ""); std::string buff("12345"); parser = HeaderlineParser(buff.c_str(), buff.size()+1); ASSERT_EQ(parser.getKey(), "12345"); ASSERT_EQ(parser.getValue(), ""); parser = HeaderlineParser("test"); ASSERT_EQ(parser.getKey(), "test"); ASSERT_EQ(parser.getValue(), ""); parser = HeaderlineParser("aaa: bbb"); ASSERT_EQ(parser.getKey(), "aaa"); ASSERT_EQ(parser.getValue(), "bbb"); parser = HeaderlineParser("aaa:bbb"); ASSERT_EQ(parser.getKey(), "aaa"); ASSERT_EQ(parser.getValue(), "bbb"); parser = HeaderlineParser("aaa: bbb"); ASSERT_EQ(parser.getKey(), "aaa"); ASSERT_EQ(parser.getValue(), "bbb"); parser = HeaderlineParser("aaa: bbb\r\n"); ASSERT_EQ(parser.getKey(), "aaa"); ASSERT_EQ(parser.getValue(), "bbb"); parser = HeaderlineParser("aaa: bbb\r\n"); ASSERT_EQ(parser.getKey(), "aaa"); ASSERT_EQ(parser.getValue(), "bbb"); } davix-0.8.0/test/unit/response-buffer.cpp0000644000000000000000000001546714121063315017110 0ustar rootroot/* * This File is part of Davix, The IO library for HTTP based protocols * Copyright (C) CERN 2019 * Author: Georgios Bitzes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include using namespace Davix; class Response_Buffer : public testing::TestWithParam {}; INSTANTIATE_TEST_CASE_P(Response_BufferTest, Response_Buffer, ::testing::Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 31, 32, 63, 64, 77, 256), ::testing::PrintToStringParamName()); TEST_P(Response_Buffer, BasicSanity) { std::string tmp = "abc"; ResponseBuffer buffer(GetParam()); ASSERT_EQ(buffer.size(), 0u); buffer.feed(tmp.c_str() ,3); ASSERT_EQ(buffer.size(), 3u); tmp = "12345"; buffer.feed(tmp.c_str(), 5); ASSERT_EQ(buffer.size(), 8u); tmp = "9"; buffer.feed(tmp.c_str(), 1); ASSERT_EQ(buffer.size(), 9u); tmp.resize(6); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 6u), 6u); ASSERT_EQ(tmp, "abc123"); ASSERT_EQ(buffer.size(), 3u); tmp.resize(1); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 1u), 1u); ASSERT_EQ(tmp, "4"); ASSERT_EQ(buffer.size(), 2u); tmp.resize(2); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 1000u), 2u); ASSERT_EQ(tmp, "59"); ASSERT_EQ(buffer.size(), 0u); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 1000u), 0u); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 1000u), 0u); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 1000u), 0u); tmp = "777"; buffer.feed(tmp.c_str(), 3); ASSERT_EQ(buffer.size(), 3u); tmp.resize(2); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 2u), 2u); ASSERT_EQ(tmp, "77"); ASSERT_EQ(buffer.size(), 1u); tmp = "00000"; buffer.feed(tmp.c_str(), 5); ASSERT_EQ(buffer.size(), 6u); tmp.resize(6); ASSERT_EQ(buffer.consume( (char*) tmp.c_str(), 600u), 6u); ASSERT_EQ(tmp, "700000"); ASSERT_EQ(buffer.size(), 0u); } TEST_P(Response_Buffer, AlternateFeedAndConsume) { std::string contents = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris porttitor urna in diam ultricies semper. Vivamus gravida purus eu erat condimentum, ullamcorper aliquam dui commodo. Fusce id nunc euismod mauris venenatis cursus non vel odio. Aliquam porttitor urna eget nibh cursus, eget ultricies quam sagittis. Donec pulvinar fermentum nunc, id rhoncus justo convallis sed. Donec suscipit quis lectus eget maximus. Etiam ut pharetra odio. Morbi ac nulla rhoncus, placerat quam varius, ultrices justo."; ResponseBuffer buffer(GetParam()); ASSERT_EQ(buffer.size(), 0u); std::string reconstructed; reconstructed.resize(contents.size()); size_t fed = 0; size_t consumed = 0; while(true) { size_t stride = (rand() % 10) + 0; if(stride + fed > contents.size()) { break; } buffer.feed(contents.c_str()+fed, stride); fed += stride; stride = (rand() % 10) + 0; std::string target; target.resize(stride); stride = buffer.consume( (char*) target.c_str(), stride); ::memcpy( (char*) (reconstructed.c_str()+consumed), target.c_str(), stride); consumed += stride; } // Feed the rest buffer.feed(contents.c_str()+fed, contents.size()-fed); std::string target; target.resize(contents.size()); size_t stride = buffer.consume( (char*) target.c_str(), contents.size()); ::memcpy( (char*) (reconstructed.c_str()+consumed), target.c_str(), stride); ASSERT_EQ(reconstructed.size(), contents.size()); ASSERT_EQ(reconstructed, contents); ASSERT_EQ(buffer.size(), 0u); } TEST_P(Response_Buffer, SeparateFeedAndConsume) { std::string contents = "We're no strangers to love. You know the rules and so do I. A full commitment's what I'm thinking of. You wouldn't get this from any other guy. I just wanna tell you how I'm feeling. Gotta make you understand. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry. Never gonna say goodbye. Never gonna tell a lie and hurt you. We've known each other for so long. Your heart's been aching but you're too shy to say it. Inside we both know what's been going on. We know the game and we're gonna play it. And if you ask me how I'm feeling. Don't tell me you're too blind to see. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry. Never gonna say goodbye. Never gonna tell a lie and hurt you. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry. Never gonna say goodbye. Never gonna tell a lie and hurt you. Never gonna give, never gonna give. (Give you up). (Ooh) Never gonna give, never gonna give. (Give you up). We've known each other for so long. Your heart's been aching but you're too shy to say it. Inside we both know what's been going on. We know the game and we're gonna play it. I just wanna tell you how I'm feeling. Gotta make you understand. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry. Never gonna say goodbye. Never gonna tell a lie and hurt you. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry. Never gonna say goodbye. Never gonna tell a lie and hurt you. Never gonna give you up. Never gonna let you down. Never gonna run around and desert you. Never gonna make you cry."; ResponseBuffer buffer(GetParam()); ASSERT_EQ(buffer.size(), 0u); size_t fed = 0; while(true) { size_t stride = (rand() % 10) + 0; if(stride + fed > contents.size()) { break; } buffer.feed(contents.c_str()+fed, stride); fed += stride; } // Feed the rest buffer.feed(contents.c_str()+fed, contents.size()-fed); std::string reconstructed; reconstructed.resize(contents.size()); size_t consumed = 0; while(true) { size_t stride = (rand() % 10) + 0; size_t output = buffer.consume( (char*) reconstructed.c_str()+consumed, stride); consumed += output; if(stride != 0 && output == 0) break; } ASSERT_EQ(contents.size(), consumed); ASSERT_EQ(contents, reconstructed); } davix-0.8.0/test/unit/session.cpp0000644000000000000000000000051214121063315015447 0ustar rootroot #include #include "libs/datetime/datetime_utils.hpp" #include #include TEST(SessionTest, create_session){ Davix_error * tmp_err=NULL; Davix::Context c; Davix::Context* ctxt = new Davix::Context(); ASSERT_TRUE(ctxt != NULL); ASSERT_TRUE(tmp_err==NULL); delete ctxt; } davix-0.8.0/test/unit/content-provider.cpp0000644000000000000000000001655714121063315017306 0ustar rootroot#include #include #include #include #include using namespace Davix; bool makeTemporaryFile(const std::string &path, const std::string &contents) { FILE *out = fopen(path.c_str(), "w"); bool ok = true; if(::fwrite(contents.c_str(), sizeof(char), contents.size(), out) != contents.size()) { ok = false; } if(fclose(out) != 0) { ok = false; } return ok; } TEST(ContentProvider, Fd) { ASSERT_TRUE(makeTemporaryFile("/tmp/davix-tests-tmp-file", "123456789")); int fd = ::open("/tmp/davix-tests-tmp-file", O_RDONLY); FdContentProvider provider(fd); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getErrc(), 0); ASSERT_TRUE(provider.getError().empty()); ASSERT_EQ(provider.getSize(), 9); char buffer[1024]; // Read and rewind 3 times for(size_t i = 0; i < 3; i++) { ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "123"); ASSERT_EQ(provider.pullBytes(buffer, 2), 2); ASSERT_EQ(std::string(buffer, 2), "45"); ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "678"); ASSERT_EQ(provider.pullBytes(buffer, 100), 1); ASSERT_EQ(std::string(buffer, 1), "9"); ASSERT_EQ(provider.pullBytes(buffer, 100), 0); ASSERT_EQ(provider.pullBytes(buffer, 100), 0); ASSERT_EQ(provider.pullBytes(buffer, 100), 0); ASSERT_TRUE(provider.rewind()); ASSERT_TRUE(provider.ok()); // Read everything in one go ASSERT_EQ(provider.pullBytes(buffer, 100), 9); ASSERT_EQ(std::string(buffer, 9), "123456789"); ASSERT_TRUE(provider.rewind()); ASSERT_TRUE(provider.ok()); } // rewind multiple times for(size_t i = 0; i < 10; i++) { ASSERT_TRUE(provider.rewind()); ASSERT_TRUE(provider.ok()); } // read 4 bytes ASSERT_EQ(provider.pullBytes(buffer, 4), 4); ASSERT_EQ(std::string(buffer, 4), "1234"); // .. but the fd closes.. ASSERT_EQ(close(fd), 0); ASSERT_EQ(provider.pullBytes(buffer, 3), -9); ASSERT_EQ(provider.getErrc(), 9); ASSERT_EQ(provider.getError(), "Bad file descriptor"); for(size_t i = 0; i < 10; i++) { ASSERT_FALSE(provider.ok()); ASSERT_FALSE(provider.rewind()); ASSERT_EQ(provider.pullBytes(buffer, 3), -9); } } TEST(ContentProvider, FdWithOffset) { ASSERT_TRUE(makeTemporaryFile("/tmp/davix-tests-tmp-file", "123456789")); int fd = ::open("/tmp/davix-tests-tmp-file", O_RDONLY); FdContentProvider provider(fd, 2); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 7); char buffer[1024]; // Read and rewind 3 times for(size_t i = 0; i < 3; i++) { ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "345"); ASSERT_TRUE(provider.rewind()); } provider = FdContentProvider(fd, 30); ASSERT_FALSE(provider.ok()); ASSERT_EQ(provider.getErrc(), ERANGE); ASSERT_EQ(provider.getError(), "Invalid offset (30) given, fd contains only 9 bytes"); ASSERT_FALSE(provider.rewind()); // Test with offset near the limits of the fd provider = FdContentProvider(fd, 8); for(size_t i = 0; i < 3; i++) { ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 1); ASSERT_EQ(provider.pullBytes(buffer, 3), 1); ASSERT_EQ(std::string(buffer, 1), "9"); ASSERT_TRUE(provider.rewind()); } provider = FdContentProvider(fd, 9); ASSERT_FALSE(provider.ok()); ASSERT_EQ(provider.getErrc(), ERANGE); ASSERT_EQ(provider.getError(), "Invalid offset (9) given, fd contains only 9 bytes"); ASSERT_EQ(::close(fd), 0); } TEST(ContentProvider, FdWithMaxlen) { ASSERT_TRUE(makeTemporaryFile("/tmp/davix-tests-tmp-file", "123456789")); int fd = ::open("/tmp/davix-tests-tmp-file", O_RDONLY); FdContentProvider provider(fd, 0, 5); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 5); char buffer[1024]; // Read and rewind 3 times for(size_t i = 0; i < 3; i++) { ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "123"); ASSERT_EQ(provider.pullBytes(buffer, 2), 2); ASSERT_EQ(std::string(buffer, 2), "45"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_TRUE(provider.rewind()); } ASSERT_EQ(provider.pullBytes(buffer, 100), 5); ASSERT_EQ(std::string(buffer, 5), "12345"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(::close(fd), 0); } TEST(ContentProvider, FdWithOffsetAndMaxlen) { ASSERT_TRUE(makeTemporaryFile("/tmp/davix-tests-tmp-file", "123456789")); int fd = ::open("/tmp/davix-tests-tmp-file", O_RDONLY); FdContentProvider provider(fd, 2, 5); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 5); char buffer[1024]; // Read and rewind 3 times for(size_t i = 0; i < 3; i++) { ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "345"); ASSERT_EQ(provider.pullBytes(buffer, 2), 2); ASSERT_EQ(std::string(buffer, 2), "67"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_TRUE(provider.rewind()); } ASSERT_EQ(provider.pullBytes(buffer, 100), 5); ASSERT_EQ(std::string(buffer, 5), "34567"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(::close(fd), 0); } TEST(ContentProvider, FdExcessiveLen) { ASSERT_TRUE(makeTemporaryFile("/tmp/davix-tests-tmp-file", "123456789")); int fd = ::open("/tmp/davix-tests-tmp-file", O_RDONLY); FdContentProvider provider(fd, 1, 10000); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 8); char buffer[1024]; // Read and rewind 3 times for(size_t i = 0; i < 3; i++) { ASSERT_EQ(provider.pullBytes(buffer, 100), 8); ASSERT_EQ(std::string(buffer, 8), "23456789"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_TRUE(provider.rewind()); } ASSERT_EQ(provider.pullBytes(buffer, 100), 8); ASSERT_EQ(std::string(buffer, 8), "23456789"); ASSERT_EQ(provider.pullBytes(buffer, 1), 0); ASSERT_EQ(::close(fd), 0); } TEST(ContentProvider, Buffer) { std::string sourceBuffer("123456789"); char buffer[1024]; BufferContentProvider provider(sourceBuffer.c_str(), sourceBuffer.size()); ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 9); ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "123"); ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "456"); ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "789"); ASSERT_EQ(provider.pullBytes(buffer, 3), 0); ASSERT_EQ(provider.pullBytes(buffer, 3), 0); ASSERT_EQ(provider.pullBytes(buffer, 3), 0); ASSERT_TRUE(provider.rewind()); ASSERT_EQ(provider.pullBytes(buffer, 200), 9); ASSERT_EQ(std::string(buffer, 9), "123456789"); ASSERT_EQ(provider.pullBytes(buffer, 3), 0); ASSERT_TRUE(provider.rewind()); ASSERT_EQ(provider.pullBytes(buffer, 4), 4); ASSERT_EQ(std::string(buffer, 4), "1234"); ASSERT_EQ(provider.pullBytes(buffer, 100), 5); ASSERT_EQ(std::string(buffer, 5), "56789"); ASSERT_EQ(provider.pullBytes(buffer, 100), 0); } TEST(ContentProvider, OwnedBuffer) { OwnedBufferContentProvider provider("test"); char buffer[1024]; ASSERT_TRUE(provider.ok()); ASSERT_EQ(provider.getSize(), 4); ASSERT_EQ(provider.pullBytes(buffer, 3), 3); ASSERT_EQ(std::string(buffer, 3), "tes"); }davix-0.8.0/test/unit/status.cpp0000644000000000000000000000242114121063315015310 0ustar rootroot#include #include using namespace Davix; TEST(Status, Empty) { Status st; ASSERT_TRUE(st.ok()); ASSERT_EQ(st.getErrorMessage(), ""); ASSERT_EQ(st.getCode(), StatusCode::OK); ASSERT_EQ(st.getScope(), ""); Status st2(st); ASSERT_TRUE(st2.ok()); ASSERT_EQ(st2.getErrorMessage(), ""); ASSERT_EQ(st2.getCode(), StatusCode::OK); ASSERT_EQ(st2.getScope(), ""); Status st3 = st; ASSERT_TRUE(st3.ok()); ASSERT_EQ(st3.getErrorMessage(), ""); ASSERT_EQ(st3.getCode(), StatusCode::OK); ASSERT_EQ(st3.getScope(), ""); } TEST(Status, Filled) { Status st("Davix::HttpRequest", StatusCode::IsNotADirectory, "An error message"); ASSERT_FALSE(st.ok()); ASSERT_EQ(st.getErrorMessage(), "An error message"); ASSERT_EQ(st.getCode(), StatusCode::IsNotADirectory); ASSERT_EQ(st.getScope(), "Davix::HttpRequest"); Status st2(st); ASSERT_FALSE(st2.ok()); ASSERT_EQ(st2.getErrorMessage(), "An error message"); ASSERT_EQ(st2.getCode(), StatusCode::IsNotADirectory); ASSERT_EQ(st2.getScope(), "Davix::HttpRequest"); Status st3 = st; ASSERT_FALSE(st3.ok()); ASSERT_EQ(st3.getErrorMessage(), "An error message"); ASSERT_EQ(st3.getCode(), StatusCode::IsNotADirectory); ASSERT_EQ(st3.getScope(), "Davix::HttpRequest"); } davix-0.8.0/test/unit/typeconv.cpp0000644000000000000000000000503214121063315015635 0ustar rootroot #include #include #include #include #undef A_LIB_NAMESPACE #define A_LIB_NAMESPACE Davix #include "libs/alibxx/alibxx.hpp" using namespace std; struct DummyStruct{ std::string dude; }; // instanciate and play with gates TEST(ALibxx, StringToULong){ using namespace Davix; std::string str_ulong("123456"); toType conv; unsigned long ul = conv(str_ulong); ASSERT_EQ(ul, 123456); str_ulong = "0"; ul= conv(str_ulong); ASSERT_EQ(ul, 0); try{ std::string str2 = "random string"; Davix::toType()(str2); FAIL(); }catch(TypeConvException & e){ // silent } try{ std::string str2 = "-15"; Davix::toType()(str2); FAIL(); }catch(TypeConvException & e){ // silent } unsigned long long super_long = std::numeric_limits::max(); std::ostringstream ss; ss << super_long; ss << super_long; // overflow try{ ul =toType()(ss.str()); FAIL(); }catch(...){ // silent } } // instanciate and play with gates TEST(ALibxx, StringToLong){ using namespace Davix; std::string str_long("123456"); toType conv; long l = conv(str_long); ASSERT_EQ(l, 123456); str_long = "0"; l= conv(str_long); ASSERT_EQ(l, 0); try{ std::string str2 = "random string"; Davix::toType()(str2); FAIL(); }catch(TypeConvException & e){ // silent } str_long = "-9865743"; l = conv(str_long); ASSERT_EQ(l, -9865743); } // instanciate and play with gates TEST(ALibxx, StringToInt){ using namespace Davix; std::string str_int("123456"); toType conv; int l = conv(str_int); ASSERT_EQ(l, 123456); str_int = "0"; l= conv(str_int); ASSERT_EQ(l, 0); try{ std::string str2 = "random string"; toType()(str2); FAIL(); }catch(TypeConvException & e){ // silent } str_int = "-9865743"; l = conv(str_int); ASSERT_EQ(l, -9865743); long long super_long = std::numeric_limits::max(); std::ostringstream ss; ss << super_long; ss << super_long; // overflow try{ l =toType()(ss.str()); FAIL(); }catch(...){ // silent } } davix-0.8.0/test/unit/gcloud.cpp0000644000000000000000000001166514121063315015254 0ustar rootroot#include #include #include #include #include #include #include #include using namespace std; using namespace Davix; #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() // FUN FACT: This is actually my private SSH key std::string privKey = "-----BEGIN RSA PRIVATE KEY-----\\n" "MIIEpgIBAAKCAQEAoiaxopVzTxog3x44cFJKmKZ4zPRceGU+CIuU54gMBvz0V3dk\\n" "OJw3pwY6EW3/psDPfBpIQNUawOUcS+WlG/7AYzPo5D432xAO47I1DfJ/sk7vPZF7\\n" "WBZOLwPBKShi+7BxES6blSSyE0KBISKFAE8S5r6PImQg7+6v9aKvYwjKniUAP780\\n" "6UHcgA0f2XL56xnWfVk/qX654EqWq0JYGbXPfN/zTpj5zEza59oMKSIZryoJbeZP\\n" "FYaryT4oTI5aoPk/6RuGJ4ga9LG0Xg/DCQ3dMyyAZAEpRqMyIvg+RkzodefVA7vb\\n" "y6gX+ttXFRbndEGg06tX0MXscgo9j+CngHXwAwIDAQABAoIBAQCUbULxBkiUweAR\\n" "HIKhHlK2RLwTMCNs+Y+9Frfo8DnCM84eOmV9BFJVC3gf+EaqB5hli1FUNz3UEGTE\\n" "fKOUaq8En8GxG9rZJWvbtYanC7EkMOkBvKfhTBmpI5Cu8g8ZQLte9QDplruCsb+t\\n" "6wE/9SHiIdC3tFwKBL0A5jgROTzvYI5HleWB2fc9emU9RaEjFl6eQBqd3bPPSFVo\\n" "3mUctVFEG76FMAytYSb+kLpO3aiPvMqrwOoK5N/PqaWH5bh392b14BoqaPQNidq9\\n" "XX2emrbaz7G1RswNPaOsJ6qpwWc+1zibkd3BwSdT3HdOX/7G6cUEnv5ibZ3SsY/n\\n" "5Z/89lMxAoGBAMwmQ5o2iJgwbU2Z5B1IKRNI1TExu1R8O+xEdT7VdG3aGScoFvkT\\n" "oEHmXKZtjYYgq5VwcOzSklROOUqto5VCSt2BCXwE7qms9+wspMVE7UQNh/LHdVBT\\n" "LuKrhMsuF4/E6sAHsNjip4+gZkHFiJu67DXxgS0Et4+r1suVsgtft4pfAoGBAMtV\\n" "tjvAA7pZXS/4R9V5B0UZ+mvdIRMuDHpPxnVv8Wb9VaQXxA/5tbPiClqLn6yMiKIg\\n" "ay1YzK191EoQuQMEiaNpCfT+DH0xTihU9KcWNGSD5fYZL4nVac8LhfU+V2VWvXdc\\n" "fgUjrLVLBNRDiInYNceLK36K5tqb/Z0sigSBZgTdAoGBAKDgInPbN6ceunPlqtK8\\n" "c8oDoiVjOGlqgVo91FsQoPCUZy/pMrlTkv17iFWKjXU+N5jLA+JMSg3vmsxTq05K\\n" "8G4/anb1+BF0Aed2gt4F5Ce1tgVG0xbahl8PpNTsXJrqJcfwB5fSfRL85rg77twx\\n" "4ETeLNqKFhE87EaAj87QvfVnAoGBAL6dOjmnFpeSAL7gdI7VZ5BK+yw03zW4vG/I\\n" "61XaPCZ9JNSwhtcnE0RviZ86NtSt5cR+uZqIHVAinmlUZexDS7hJ1tC5fAG8v/Ul\\n" "NziPo0v7Lg/Xqm3/B7LVrZ2q9IkGmJUVuvmcaOKHUh6etJfsfPX0LDDzi9ix1T2L\\n" "rFLu7zFtAoGBAInoW7w0uyNiFGCjoDPvHlQTGZrk2hY2lyFJQjpWqwx5qq7917gp\\n" "GQ27cF/m5ZAMDtr21CH648NIp1rrtNt9WgF9WRMVjILas558VPQgk/oiMGWS7zH/\\n" "bcg/HecqmrFwg7XyixqXxDCqKLlf8O7XzzGLAjowMRCBQiLwixtJAhUi\\n" "-----END RSA PRIVATE KEY-----\\n"; static bool startswith(const std::string &str, int start, const std::string &prefix) { if(prefix.size() > str.size() + start) return false; for(size_t i = 0; i < prefix.size(); i++) { if(str[start++] != prefix[i]) return false; } return true; } static std::string replace(const std::string &source, const std::string &target, const std::string &replacement) { std::stringstream ss; for(size_t i = 0; i < source.size(); i++) { if(startswith(source, i, target)) { ss << replacement; i += target.size() - 1; } else { ss << source[i]; } } return ss.str(); } TEST(GcloudTest, CredParsing) { gcloud::CredentialProvider credProvider; ASSERT_THROW(credProvider.fromJSONString("aaaaa"), DavixException); ASSERT_THROW(credProvider.fromJSONString(SSTR("{ \"priva_key\":\"" << privKey << "\" }")), DavixException); std::string jsonString = SSTR("{ \"client_email\": \"aaa@bb.gserviceaccount.com\", \"private_key\":\"" << privKey << "\" }"); gcloud::Credentials creds = credProvider.fromJSONString(jsonString); ASSERT_EQ(creds.getPrivateKey(), replace(privKey, "\\n", "\n")); ASSERT_EQ(creds.getClientEmail(), "aaa@bb.gserviceaccount.com"); } TEST(GcloudTest, RsaSha256Signature) { std::string unencoded = rsasha256(replace(privKey, "\\n", "\n"), "super secure message"); std::string encoded = Base64::base64_encode( (const unsigned char*) unencoded.c_str(), unencoded.size()); ASSERT_EQ(encoded, "Dqyv8/2sQyTWtVGTkxgXe0zKQGEPuK/xbhLV7tExpBPE6X4gIU5vNxIYOeK2QwgpiAN/XjEzAp9u9nZxalhyeZvf7QnXs0iiTqmmXUANHPwhWKgRHi9QG1QFONnJ8ZgSjpakQqaCXPgcXskO2zhKwY7Z91cRY42kYyCF7+aCduYOcYYbVwSUxuF6zkj/HvvGGF+eVX1+eOe59Py1mETGHv1Uf0URiCsq5W3XoU9HKl5zPX8rX/GL85w0WUUpUsyT1BcVaC3CJtpLOcHxeovO6RziyYNg5vOzsidjl0nETEtjoFIpLQva+ozok2xh2+dGHTkc9ZDkjMjZK7h/KB1s8Q=="); } TEST(GcloudTest, UrlSigning) { gcloud::CredentialProvider credProvider; gcloud::Credentials creds = credProvider.fromJSONString(SSTR("{ \"client_email\": \"aaa@bb.gserviceaccount.com\", \"private_key\":\"" << privKey << "\" }")); HeaderVec hv; Uri signedUrl = gcloud::signURIFixedTimeout(creds, "GET", Uri("https://storage.googleapis.com/random-bucket/aaaaa"), hv, 1525107409); ASSERT_EQ(signedUrl.getString(), "https://storage.googleapis.com/random-bucket/aaaaa?GoogleAccessId=aaa%40bb.gserviceaccount.com&Expires=1525107409&Signature=MaYqh3Ysjw8trX1H%2BO%2BNBxn4I3cSfKsQNJRrltH6apJpNq7AitI0YvEZ4fFoGcPhb3oz13kyxlsDB1v61%2FlFXJLUFHD6erpMubYMTEeAjw50NavcJtoXNUmHXUAnwj164ffD%2B8VQBK9UIOgcrdh3dGumsjwQe%2F7znk6TcXr6D9vkA3uRldFNNcZBnq%2Bv1rULNzi1XHm2wCvXy%2B5vXJ0%2FDsxtlfDfleC1NEcHS8vmWbsyUwFWrZUM%2BeiIjolmWL6NZpyEEMOBnNOgmi9BcSxDr0WGDEmdh6wvSUvbJzknZrKjgIj%2BH4AaYFOKsCV946mg0whkXc4F7lxpmzax5HHfqQ%3D%3D"); } davix-0.8.0/test/unit/testcert.cpp0000644000000000000000000000374014121063315015627 0ustar rootroot#include #include #include #include #include using namespace std; using namespace Davix; // instanciate and play with gates // TEST(CredTest, basicLoad){ // DavixError* tmp_err=NULL; // davix_set_log_level(DAVIX_LOG_DEBUG | DAVIX_LOG_WARNING | DAVIX_LOG_TRACE); // Context c; // X509Credential cred; // ASSERT_FALSE(cred.hasCert()); // string cert_path(TEST_VALID_CERT); // string cert_pass(TEST_VALID_CERT_PASS); // cout << " cred: " << cert_path << "pass " << cert_pass << endl; // int ret = cred.loadFromFileP12(cert_path.c_str(), cert_pass.c_str(), &tmp_err); // if(tmp_err){ // cout << "err :" << tmp_err->getErrMsg() << endl; // } // ASSERT_EQ(0, ret); // ASSERT_EQ(NULL, tmp_err); // ASSERT_TRUE(cred.hasCert()); // X509Credential cred2(cred); // ASSERT_TRUE(cred2.hasCert()); // ret = cred.loadFromFileP12("/random/stupid/path", "", &tmp_err); // ASSERT_EQ(-1, ret); // ASSERT_EQ(StatusCode::CredentialNotFound, tmp_err->getStatus()); // DavixError::clearError(&tmp_err); // ASSERT_FALSE(cred.hasCert()); // ASSERT_TRUE(cred2.hasCert()); // ret = cred.loadFromFileP12(cert_path.c_str(), "", &tmp_err); // ASSERT_EQ(-1, ret); // ASSERT_EQ(StatusCode::LoginPasswordError, tmp_err->getStatus()); // DavixError::clearError(&tmp_err); // } TEST(testAWS, awsToken){ std::string p_key("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"); std::string a_key("AKIAIOSFODNN7EXAMPLE"); std::string req("GET\n" "\n" "\n" "Tue, 27 Mar 2007 19:36:42 +0000\n" "/johnsmith/photos/puppy.jpg"); std::string token("AWS AKIAIOSFODNN7EXAMPLE:" "bWq2s1WEIj+Ydj0vQ697zp+IXMU="); std::string res = getAwsAuthorizationField(req, p_key, a_key); ASSERT_STREQ(res.c_str(), token.c_str()); } davix-0.8.0/test/unit/cache.cpp0000644000000000000000000000246614121063315015041 0ustar rootroot #include #include #include #include #undef A_LIB_NAMESPACE #define A_LIB_NAMESPACE Davix #include "libs/alibxx/alibxx.hpp" using namespace std; struct DummyStruct{ std::string dude; }; // instanciate and play with gates TEST(ALibxx, CacheTest){ Davix::Cache cache; ASSERT_TRUE(cache.find("hello").get() == NULL); std::shared_ptr dumb( new DummyStruct()); dumb->dude = "bob"; ASSERT_STREQ("bob",cache.insert("hello", dumb)->dude.c_str()); ASSERT_STREQ("bob", cache.find("hello")->dude.c_str()); ASSERT_EQ(1, cache.getSize()); ASSERT_STREQ("bob", cache.take("hello")->dude.c_str()); ASSERT_EQ(0, cache.getSize()); ASSERT_TRUE(cache.find("hello").get() == NULL); ASSERT_STREQ("bob",cache.insert("alice", dumb)->dude.c_str()); ASSERT_STREQ("bob",cache.insert("test", dumb)->dude.c_str()); ASSERT_STREQ("bob",cache.insert("john", dumb)->dude.c_str()); ASSERT_STREQ("bob", cache.find("john").get()->dude.c_str()); ASSERT_EQ(3, cache.getSize()); ASSERT_TRUE(cache.erase("john")); ASSERT_FALSE(cache.erase("john")); ASSERT_EQ(2, cache.getSize()); ASSERT_TRUE( cache.find("john").get() == NULL); cache.clear(); ASSERT_EQ(0, cache.getSize()); } davix-0.8.0/test/unit/digest-extractor.cpp0000644000000000000000000000334014121063315017256 0ustar rootroot#include #include #include using namespace Davix; TEST(ChecksumExtractor, BasicSanity) { std::string output; HeaderVec v1; ASSERT_FALSE(ChecksumExtractor::extractChecksum(v1, "md5", output)); v1.emplace_back("Digest", "md5=8dafb171a7455ee8977515d81c90bc12"); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "md5", output)); ASSERT_EQ(output, "8dafb171a7455ee8977515d81c90bc12"); v1.emplace_back("Digest", "sha=y9oivLQasBUbQ4WJqkY34g=="); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "md5", output)); ASSERT_EQ(output, "8dafb171a7455ee8977515d81c90bc12"); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "sha", output)); ASSERT_EQ(output, "cbda22bcb41ab0151b438589aa4637e2"); v1.emplace_back("Digest", "ADLER32=9600001"); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "adler32", output)); ASSERT_EQ(output, "09600001"); v1.emplace_back("Digest", "CRC32C=03da0195"); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "crc32c", output)); ASSERT_EQ(output, "03da0195"); ASSERT_FALSE(ChecksumExtractor::extractChecksum(v1, "crc32", output)); v1.emplace_back("digest", "frob=y9oivLQasBUbQ4WJqkY34g=="); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "frob", output)); ASSERT_EQ(output, "cbda22bcb41ab0151b438589aa4637e2"); } TEST(ChecksumExtractor, MultipleReturnedChecksums) { std::string output; HeaderVec v1; v1.emplace_back("Digest", "adler32=10cf712f,md5=+Tvja0I4Jp7AhrZfWO7C3A=="); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "adler32", output)); ASSERT_EQ(output, "10cf712f"); ASSERT_TRUE(ChecksumExtractor::extractChecksum(v1, "md5", output)); ASSERT_EQ(output, "f93be36b4238269ec086b65f58eec2dc"); } davix-0.8.0/test/unit/datetime.cpp0000644000000000000000000000115614121063315015565 0ustar rootroot#include #include #include "libs/datetime/datetime_utils.hpp" TEST(DateTimeTest, testConvert){ time_t res, t = time(NULL); struct tm* tmp = gmtime(&t); char buff[2048]; strftime(buff, 2048, "%Y-%m-%dT%H:%M:%SZ", tmp); printf("new iso8601 time %s \n",buff); res= parse_iso8601date(buff); ASSERT_EQ(t,res); res = parse_iso8601date("unknow invalid time"); ASSERT_EQ(-1, res); } TEST(DateTimeTest, Iso8601Test1) { // was failing on FreeBSD std::string testcase("2018-10-02T17:19:00Z"); ASSERT_EQ(parse_iso8601date(testcase.c_str()), 1538500740); } davix-0.8.0/test/unit/neon.cpp0000644000000000000000000001054714121063315014734 0ustar rootroot#include #include #include #include #include #include using namespace Davix; static const char* list_urls[] = { "http://localhost:80/", "sfdfsdfdsfds://localhost:rrrrrrr/path", "http://monurlrandom/", "www.google.com" }; static const int list_port[]={ 80, 0, 0, 80 }; static const char* list_host[] ={ "localhost", "localhost", "monurlrandom", "nothing" }; static const char* list_path[] ={ "/", "/path", "/", "nothing", }; static const char* list_proto[] ={ "http", "http", "http", "nothing" }; static bool failure[]={ false, true, false, true }; const size_t len_list= (sizeof(list_proto))/(sizeof(const char*)); TEST(testNeon, testParsing){ davix_set_log_level(DAVIX_LOG_ALL); for(size_t i=0; i < len_list; ++i){ Uri uri(list_urls[i]); if(failure[i] == false){ ASSERT_EQ(StatusCode::OK, uri.getStatus()); ASSERT_STREQ(list_proto[i], uri.getProtocol().c_str() ); ASSERT_STREQ(list_host[i], uri.getHost().c_str()); ASSERT_STREQ(list_path[i], uri.getPath().c_str()); ASSERT_EQ(list_port[i], uri.getPort()); }else{ ASSERT_EQ(StatusCode::UriParsingError, uri.getStatus()); } } } TEST(testUri, testCopyEQ){ Uri uri; std::ostringstream ss; ASSERT_EQ(uri.getStatus(), StatusCode::UriParsingError); uri = Uri("http://wikipedia.org:80/bonus?salut"); ASSERT_EQ(uri.getStatus(), StatusCode::OK); ss << uri; ASSERT_STREQ(ss.str().c_str(),uri.getString().c_str()); std::string pathAndString("http://wikipedia.org:80/bonus?salut=bob"); uri = pathAndString; std::string::reverse_iterator rit = std::find(pathAndString.rbegin(), pathAndString.rend(), '/'); std::string::iterator it = pathAndString.begin() + (pathAndString.rend() - rit); ASSERT_STREQ(uri.getPathAndQuery().c_str(), std::string(it-1, pathAndString.end()).c_str() ); Uri uri2(uri); ASSERT_TRUE(uri == uri2); } TEST(testUri, testEscape){ std::string s("http://wikipedia.org:80/bonus a toi \\ é voilù ?salut"); std::string r = Davix::Uri::unescapeString(Davix::Uri::escapeString(s)); ASSERT_STREQ(s.c_str(), r.c_str()); } TEST(testUri, testTrailingSlashes) { std::vector vec; vec.push_back("https://wikipedia.org/wiki/Example"); vec.push_back("http://example.org/test"); std::vector::iterator it; for(it = vec.begin(); it != vec.end(); it++) { std::string s = *it; std::string s2 = s + "/"; Uri uri(s); ASSERT_EQ(uri.getString(), s); uri.ensureTrailingSlash(); ASSERT_EQ(uri.getString(), s2); uri.ensureTrailingSlash(); ASSERT_EQ(uri.getString(), s2); uri.removeTrailingSlash(); ASSERT_EQ(uri.getString(), s); uri.removeTrailingSlash(); ASSERT_EQ(uri.getString(), s); } } TEST(testUri, testQueryParamExists) { std::string s("https://example.com/somepath?query1=aaa&query2=bbb&query3=cccc&query4=ddd"); Uri uri(s); ASSERT_TRUE(uri.queryParamExists("query1")); ASSERT_TRUE(uri.queryParamExists("query2")); ASSERT_TRUE(uri.queryParamExists("query3")); ASSERT_TRUE(uri.queryParamExists("query4")); ASSERT_FALSE(uri.queryParamExists("query5")); ASSERT_FALSE(uri.queryParamExists("query6")); ASSERT_FALSE(uri.queryParamExists("query")); ASSERT_FALSE(uri.queryParamExists("aaa")); ASSERT_FALSE(uri.queryParamExists("bbb")); ASSERT_FALSE(uri.queryParamExists("cccc")); ASSERT_FALSE(uri.queryParamExists("ccc")); ASSERT_FALSE(uri.queryParamExists("ddd")); ASSERT_FALSE(uri.queryParamExists("aaa&query2")); } TEST(testUri, testFragment) { Davix::Uri u("https://example.com/path?query1=aa&query2=bb#frag1=aa&frag2=bb"); ASSERT_EQ(u.getFragment(), "frag1=aa&frag2=bb"); ASSERT_TRUE(u.fragmentParamExists("frag1")); ASSERT_TRUE(u.fragmentParamExists("frag2")); ASSERT_FALSE(u.fragmentParamExists("frag3")); Davix::Uri u2("https://example.com/path?query1=aa&query2=bb"); ASSERT_EQ(u2.getFragment(), ""); ASSERT_FALSE(u2.fragmentParamExists("frag1")); Davix::Uri u3(u); ASSERT_EQ(u.getFragment(), u3.getFragment()); Davix::Uri u4 = u; ASSERT_EQ(u.getFragment(), u4.getFragment()); } davix-0.8.0/test/unit/config-parser.cpp0000644000000000000000000001064614121063315016534 0ustar rootroot#include #include #include using namespace Davix; TEST(ConfigParser, Tokenizer) { std::vector tokens; std::string err; tokens = davix_config_tokenize(" token1 \t\t\t\n\n token2 \t\t\n\n \" token3 in quotes and spaces \" ", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 3u); ASSERT_EQ(tokens[0], "token1"); ASSERT_EQ(tokens[1], "token2"); ASSERT_EQ(tokens[2], " token3 in quotes and spaces "); tokens = davix_config_tokenize("\"single token in quotes\"", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 1u); ASSERT_EQ(tokens[0], "single token in quotes"); // evil empty string tokens = davix_config_tokenize("token1 \n\t\n \"\" token3 'token4 with single quotes @@!! ' ", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 4u); ASSERT_EQ(tokens[0], "token1"); ASSERT_EQ(tokens[1], ""); ASSERT_EQ(tokens[2], "token3"); ASSERT_EQ(tokens[3], "token4 with single quotes @@!! "); // escaped quotes inside arguments tokens = davix_config_tokenize("\"\\\"\" \"token2 with \\\"escaped quotes\\\" \" ", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 2u); ASSERT_EQ(tokens[0], "\""); ASSERT_EQ(tokens[1], "token2 with \"escaped quotes\" "); // mixing quotes tokens = davix_config_tokenize("'token1 with \" quotes' \"token2 with ' quotes\" 'token3 with \\' quotes' \"token4 with \\\" quotes\"", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 4u); ASSERT_EQ(tokens[0], "token1 with \" quotes"); ASSERT_EQ(tokens[1], "token2 with ' quotes"); ASSERT_EQ(tokens[2], "token3 with ' quotes"); ASSERT_EQ(tokens[3], "token4 with \" quotes"); // mismatched quote tokens = davix_config_tokenize(" 'token1 \" ", err); ASSERT_TRUE(err != ""); ASSERT_EQ(tokens.size(), 0u); err = ""; // mismatched quote tokens = davix_config_tokenize(" \"token1 ' ", err); ASSERT_TRUE(err != ""); ASSERT_EQ(tokens.size(), 0u); err = ""; // no extra whitespace tokens = davix_config_tokenize("token1 token2", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 2u); ASSERT_EQ(tokens[0], "token1"); ASSERT_EQ(tokens[1], "token2"); // what a real file might look like tokens = davix_config_tokenize("machine dpmhead-trunk.cern.ch\n certpath /tmp/x509up_u1000", err); ASSERT_EQ(err, ""); ASSERT_EQ(tokens.size(), 4u); ASSERT_EQ(tokens[0], "machine"); ASSERT_EQ(tokens[1], "dpmhead-trunk.cern.ch"); ASSERT_EQ(tokens[2], "certpath"); ASSERT_EQ(tokens[3], "/tmp/x509up_u1000"); } TEST(ConfigParser, T1) { std::string contents; Uri uri("https://somehost/somepath/path2"); Tool::OptParams params; // no match contents = "machine myhost\n" " login \"mylogin\"\n" " password \"mypass\"\n"; ASSERT_FALSE(davix_config_apply("null", contents, uri, params)); // match contents = "machine somehost\n" " login \"mylogin\"\n" " password \"mypass\"\n"; ASSERT_TRUE(davix_config_apply("null", contents, uri, params)); ASSERT_EQ(params.userlogpasswd.first, "mylogin"); ASSERT_EQ(params.userlogpasswd.second, "mypass"); // verify that existing settings are not overwritten contents = "machine somehost\n" " login \"mylogin2\"\n" " password \"mypass2\"\n"; ASSERT_TRUE(davix_config_apply("null", contents, uri, params)); ASSERT_EQ(params.userlogpasswd.first, "mylogin"); ASSERT_EQ(params.userlogpasswd.second, "mypass"); // match for host, but not path contents = "machine somehost\n" " path /someotherpath\n" " s3accesskey key\n"; ASSERT_TRUE(davix_config_apply("null", contents, uri, params)); ASSERT_EQ(params.aws_auth.second, ""); // match for both host and path + generic host settings contents = "machine somehost\n" " s3secretkey commonkey\n" " path /someotherpath\n" " s3accesskey key\n" " path /somepath\n" " s3accesskey correctkey\n"; ASSERT_TRUE(davix_config_apply("null", contents, uri, params)); ASSERT_EQ(params.aws_auth.second, "correctkey"); ASSERT_EQ(params.aws_auth.first, "commonkey"); // match for both host and path + swift credentials contents = "machine somehost\n" " ostoken commontoken\n" " path /someotherpath\n" " osprojectid id\n" " path /somepath\n" " osprojectid correctid\n"; ASSERT_TRUE(davix_config_apply("null", contents, uri, params)); ASSERT_EQ(params.os_token, "commontoken"); ASSERT_EQ(params.os_project_id, "correctid"); } davix-0.8.0/test/unit/chrono.cpp0000644000000000000000000000223014121063315015253 0ustar rootroot#include #include #include #include #include #include #undef A_LIB_NAMESPACE #define A_LIB_NAMESPACE Davix #include "libs/alibxx/alibxx.hpp" using namespace std; // instanciate and play with gates TEST(ALibxx, ChronoTest){ using namespace Davix::Chrono; TimePoint pp; ASSERT_EQ(0, pp.toTimestamp()); pp = Clock(Clock::Monolitic).now(); TimePoint copy_time = pp; ASSERT_EQ(pp, copy_time); copy_time = copy_time + Duration(5); ASSERT_NE(copy_time, pp); ASSERT_EQ(copy_time, pp + Duration(5)); ASSERT_GE(copy_time, pp); ASSERT_GE(copy_time, pp + Duration(5)); ASSERT_GT(copy_time, pp); ASSERT_LE(copy_time, pp + Duration(5)); ASSERT_LE(copy_time, pp + Duration(10)); ASSERT_LT(copy_time, pp + Duration(10)); ASSERT_EQ(copy_time + Duration(5), pp + Duration(10)); copy_time = pp; ASSERT_EQ(copy_time, pp + Duration(10) - Duration(20) + Duration(10)); TimePoint dd; ASSERT_ANY_THROW( Duration res = dd - pp; ); Duration res = pp - dd; ASSERT_EQ( dd + res, pp); } davix-0.8.0/test/unit/session-factory.cpp0000644000000000000000000000625314121063315017124 0ustar rootroot#include #include #include #include using namespace Davix; TEST(testRedirectCache, testCacheSimple){ davix_set_log_level(DAVIX_LOG_ALL); std::shared_ptr dest(new Uri("http://sffsdfsd.com/dsffds/fsdfsdsdf")); std::shared_ptr dest2(new Uri("http://sffsdfsd.com/dsffds/fsdfsdsdf")); Uri u("http://higgs.boson/is/watchingus"); Uri u_sec("https://higgs.boson/is/watchingus"); Uri u_port("http://higgs.boson:8668/is/watchingus"); RedirectionResolver f(true); f.addRedirection("GET", u, dest); ASSERT_TRUE(f.redirectionResolve("GET", u) == dest); ASSERT_TRUE(f.redirectionResolve("GET", u_sec).get() == NULL); ASSERT_TRUE(f.redirectionResolve("GET", u_port).get() == NULL); // add redirection f.addRedirection("GET", u_port, dest2); ASSERT_TRUE(f.redirectionResolve("GET", u) != dest2); ASSERT_TRUE(f.redirectionResolve("GET", u_port) == dest2); // remove redirection f.redirectionClean("GET", u); ASSERT_TRUE(f.redirectionResolve("GET", u).get() == NULL); ASSERT_TRUE(f.redirectionResolve("GET", u_port) == dest2); } TEST(testRedirectCache, testCacheChainRedirection){ davix_set_log_level(DAVIX_LOG_ALL); Uri u("http://higgs.boson/is/watchingus"); std::shared_ptr url1(new Uri("http://sffsdfsd.com/dsffds/fsdfsdsdf")); std::shared_ptr url2(new Uri("http://server2.com/dsffds/sfdfdsfsdfdsfdsfds")); std::shared_ptr url3(new Uri("http://server2.com:8080/dsffds/sfdfdsfsdfdsfdsfds")); std::shared_ptr url4(new Uri("http://server3.com/dsffds/fsdaaaaa")); RedirectionResolver f(true); f.addRedirection("GET", u, url1); f.addRedirection("GET",*url1, url2); f.addRedirection("GET", *url2, url3); f.addRedirection("GET", *url3, url4); ASSERT_TRUE(f.redirectionResolve("GET", u) == url4); ASSERT_TRUE(f.redirectionResolve("GET", *url2) == url4); f.redirectionClean("GET", u); ASSERT_TRUE(f.redirectionResolve("GET", u).get() == NULL); ASSERT_TRUE(f.redirectionResolve("GET", *url2).get() == NULL); ASSERT_TRUE(f.redirectionResolve("GET", *url4).get() == NULL); } TEST(testRedirectCache, test_GET_HEAD){ davix_set_log_level(DAVIX_LOG_ALL); Uri u("http://higgs.boson/is/watchingus"); std::shared_ptr url1(new Uri("http://sffsdfsd.com/dsffds/fsdfsdsdf")); std::shared_ptr url2(new Uri("http://server2.com/dsffds/sfdfdsfsdfdsfdsfds")); RedirectionResolver f(true); f.addRedirection("GET", u, url1); ASSERT_TRUE(f.redirectionResolve("GET", u) == url1); ASSERT_TRUE(f.redirectionResolve("HEAD", u) == url1); ASSERT_TRUE(f.redirectionResolve("PUT", u).get() == NULL); f.redirectionClean("GET", u); ASSERT_TRUE(f.redirectionResolve("GET", u) == NULL); ASSERT_TRUE(f.redirectionResolve("HEAD", u) == NULL); f.addRedirection("PUT", u, url1); ASSERT_TRUE(f.redirectionResolve("GET", u).get() == NULL); ASSERT_TRUE(f.redirectionResolve("PUT", u) == url1); f.addRedirection("HEAD", u, url1); ASSERT_TRUE(f.redirectionResolve("GET", u) == url1); ASSERT_TRUE(f.redirectionResolve("HEAD", u) == url1); } davix-0.8.0/test/functional/0000755000000000000000000000000014121063315014445 5ustar rootrootdavix-0.8.0/test/functional/test_stat_session.cpp0000644000000000000000000000250514121063315020730 0ustar rootroot#include "test_stat_session.h" #include #include #include #include "davix_test_lib.h" using namespace Davix; int n_call=0; int main(int argc, char** argv){ if( argc < 3){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [CERTIFICATE_PATH] [url] [url] .... " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); if(argc > 2){ configure_grid_env(argv[1], p); } for(int i =2 ; i< argc; ++i){ struct stat st; if( pos.stat(&p,argv[i], &st, &tmp_err) ==0){ std::cout << "stat success" << std::endl; std::cout << " atime : " << st.st_atime << std::endl; std::cout << " mtime : " << st.st_mtime << std::endl; std::cout << " ctime : " << st.st_ctime << std::endl; std::cout << " mode : 0" << std::oct << st.st_mode << std::endl; std::cout << " len : " << st.st_size << std::endl; }else{ std::cerr << " davix_stat error " << tmp_err->getErrMsg(); return -1; } } std::cout << "authentification callback has been called " << n_call << std::endl; return 0; } davix-0.8.0/test/functional/test_stat_session.h0000644000000000000000000000010114121063315020363 0ustar rootroot#ifndef TEST_STAT_H #define TEST_STAT_H #endif // TEST_STAT_H davix-0.8.0/test/functional/CMakeLists.txt0000644000000000000000000001401414121063315017205 0ustar rootroot# main file for src set(src_davix_test_lib "davix_test_lib.cpp") #set( src_test_req "test_request.cpp") #set( src_test_checksum "test_checksum.cpp") #set( src_test_stat_session "test_stat_session.cpp") #set( src_test_rw "davix_rw_test.cpp") #set( src_test_opendir "test_opendir.cpp") #set( src_test_opendir_partial "test_opendir_partial.cpp") #set( src_test_opendirpp "test_opendirpp.cpp") #set( src_test_directory "test_directory.cpp") #set( src_test_auto_stat_mkdir_check "test_auto_stat_mkdir_check.cpp") #set( src_test_auto_rmdir_unlink_delete "test_auto_rmdir_unlink_delete.cpp") #set( src_test_valid_read_generic_simple "test_valid_read_generic_simple.cpp") #set( src_test_valid_write_read_generic_simple "test_valid_write_read_generic_simple.cpp") #set( src_test_valid_write_read_fd "test_valid_write_read_fd.cpp") #set( src_test_valid_write_read_vector_simple "test_valid_write_read_vector_simple.cpp") #set( src_tool_read_vector_simple "tool_read_vector_simple.cpp") #set( src_tool_get_replicas "tool_get_replica_simple.cpp") #set( src_test_mv "test_mv.cpp") add_library(test_davix_functional_lib STATIC ${src_davix_test_lib}) #add_executable(test_request ${src_test_req} ) #target_link_libraries(test_request libdavix test_davix_functional_lib) #add_executable(tool_read_vector_simple ${src_tool_read_vector_simple} ) #target_link_libraries(tool_read_vector_simple libdavix test_davix_functional_lib ) #add_executable(test_rw_fd ${src_test_valid_write_read_fd}) #target_link_libraries(test_rw_fd libdavix test_davix_functional_lib ) #add_executable(test_stat_auto_check ${src_test_auto_stat_mkdir_check}) #target_link_libraries(test_stat_auto_check libdavix test_davix_functional_lib) #add_executable(test_checksum ${src_test_checksum}) #target_link_libraries(test_checksum libdavix test_davix_functional_lib) #add_executable(test_auto_rmdir_unlink_delete ${src_test_auto_rmdir_unlink_delete}) #target_link_libraries(test_auto_rmdir_unlink_delete libdavix test_davix_functional_lib) #add_executable(test_stat_session ${src_test_stat_session}) #target_link_libraries(test_stat_session libdavix test_davix_functional_lib) #add_executable(test_rw ${src_test_rw}) #target_link_libraries(test_rw libdavix test_davix_functional_lib) #add_executable(test_opendir ${src_test_opendir} ) #target_link_libraries(test_opendir libdavix test_davix_functional_lib) #add_executable(test_directory ${src_test_directory} ) #target_link_libraries(test_directory libdavix test_davix_functional_lib) #add_executable(test_opendir_partial ${src_test_opendir_partial}) #target_link_libraries(test_opendir_partial libdavix test_davix_functional_lib) #add_executable(test_opendirpp ${src_test_opendirpp}) #target_link_libraries(test_opendirpp libdavix test_davix_functional_lib) #add_executable(test_valid_read_generic_simple ${src_test_valid_read_generic_simple}) #target_link_libraries(test_valid_read_generic_simple libdavix test_davix_functional_lib) #add_executable(test_valid_write_read_generic_simple ${src_test_valid_write_read_generic_simple}) #target_link_libraries(test_valid_write_read_generic_simple libdavix test_davix_functional_lib) #add_executable(test_valid_write_read_vector_simple ${src_test_valid_write_read_vector_simple}) #target_link_libraries(test_valid_write_read_vector_simple libdavix test_davix_functional_lib) #add_executable(tool_get_replicas ${src_tool_get_replicas}) #target_link_libraries(tool_get_replicas libdavix test_davix_functional_lib) #add_executable(test_mv ${src_test_mv}) #target_link_libraries(test_mv libdavix test_davix_functional_lib) add_executable(davix-tester ../TestcaseHandler.cpp davix-tester.cpp) target_link_libraries(davix-tester libdavix test_davix_functional_lib) install(TARGETS davix-tester DESTINATION ${BIN_INSTALL_DIR}/) ### DEPRECATED, to remove soon # function(test_dav_endpoint_ronly name cred) # add_test(test_stat_session_${name} test_stat_session ${cred} ${name} ${name} ${name} ${name} ${name} ${name} ${name}) # add_test(test_opendir_${name} test_opendir ${name} ${cred}) # # add_test(test_opendir_c_${name} test_opendir_c ${name} ${cred}) # add_test(test_opendirpp_${name} test_opendirpp ${name} ${cred}) # # add_test(test_stat_c_${name} test_stat_c ${name} ${cred}) # endfunction(test_dav_endpoint_ronly name cred) # function(test_dav_endpoint_rw name cred) # add_test(test_stat_session_${name} test_stat_session ${cred} ${name} ${name} ${name} ${name} ${name} ${name} ${name}) # add_test(test_opendir_${name} test_opendir ${name} ${cred}) # add_test(test_opendirpp_${name} test_opendirpp ${name} ${cred}) # add_test(test_stat_auto_check_${name} test_stat_auto_check ${name} ${cred}) # endfunction(test_dav_endpoint_rw name cred) # function(listdir_partial name size cred) # add_test(test_opendir_partial_${name} test_opendir_partial ${name} ${size} ${cred}) # endfunction(listdir_partial name size cred) # function(test_collection name cred) # add_test(test_directory_${name} test_directory ${name} ${cred}) # endfunction(test_collection name cred) # function(test_valid_read_generic url cred) # add_test(test_valid_read_generic_${url} test_valid_read_generic_simple ${url} ${cred}) # endfunction(test_valid_read_generic url cred) # function(test_valid_delete_all url cred) # add_test(test_auto_rmdir_unlink_delete_${url} test_auto_rmdir_unlink_delete ${url} ${cred}) # endfunction(test_valid_delete_all url cred) # function(test_valid_write_read_generic url cred) # add_test(test_valid_write_read_generic_simple_${url} test_valid_write_read_generic_simple ${url} ${cred}) # add_test(test_rw_fd_${url} test_rw_fd ${url} ${cred}) # add_test(test_valid_write_read_vector_simple_${url} test_valid_write_read_vector_simple ${url} ${cred}) # endfunction(test_valid_write_read_generic url cred) # function(test_replica_listing_existing url cred) # add_test(tool_get_replicas_${url} tool_get_replicas ${url} ${cred}) # endfunction(test_replica_listing_existing url cred) # function(test_rename url cred) # add_test(test_mv_${url} test_mv ${url} ${cred}) # endfunction(test_rename url cred) davix-0.8.0/test/functional/test_valid_read_generic_simple.cpp0000644000000000000000000000337614121063315023360 0ustar rootroot#include "test_stat.h" #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; Davix_fd* fd; ssize_t ret=1; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); size_t char_counter=0, chunk_counter=0; char buff[2049]={0}; if(argc > 2){ configure_grid_env(argv[2], p); } if( (fd =pos.open(&p, argv[1], O_RDONLY, &tmp_err)) == NULL){ std::cerr << " error while opening file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } // std::cout << "file content " << std::endl; while( fd && (ret = pos.read(fd, buff, 2048, &tmp_err)) > 0){ buff[ret] = '\0'; char_counter += strlen(buff); chunk_counter += ret; if(char_counter != chunk_counter){ std::cerr << " char size and read size are differents.. " << std::endl; return -1; } std::cout << buff; } std::cout << std::endl; if(tmp_err){ std::cerr << " error while readding file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } if( (ret = pos.close(fd, &tmp_err))){ std::cerr << " error while closing file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } return 0; } davix-0.8.0/test/functional/test_auto_stat_mkdir_check.cpp0000644000000000000000000000350414121063315022540 0ustar rootroot#include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [base_dir]" << std::endl; std::cout <<"\t" << argv[0] << " [base_dir] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); p.setProtocol(RequestProtocol::Webdav); if(argc > 2){ configure_grid_env(argv[2], p); } char buff[2048]; generate_random_uri(argv[1], "davix_test_stat", buff, 2048); struct stat st; // do a first stat, should return enoent std::cout << " stat enoent dir " << buff << std::endl; int ret = pos.stat(&p, buff, &st, &tmp_err); assert( ret < 0); if(tmp_err){ std::cout << " error " << (int) tmp_err->getStatus() << " msg " << tmp_err->getErrMsg() << std::endl; } assert(tmp_err && StatusCode::FileNotFound == tmp_err->getStatus()); DavixError::clearError(&tmp_err); std::cout << " create dir " << buff << std::endl; ret = pos.mkdir(&p, buff, 0755, &tmp_err); assert(0 == ret); assert(NULL == tmp_err); std::cout << " stat new dir " << std::endl; ret = pos.stat(&p, buff, &st, &tmp_err); assert(0 == ret); assert(S_ISDIR(st.st_mode)); std::cout << "stat success" << std::endl; std::cout << " atime : " << st.st_atime << std::endl; std::cout << " mtime : " << st.st_mtime << std::endl; std::cout << " ctime : " << st.st_ctime << std::endl; std::cout << " mode : 0" << std::oct << st.st_mode << std::endl; std::cout << " len : " << st.st_size << std::endl; return 0; } davix-0.8.0/test/functional/test_valid_write_read_generic_simple.cpp0000644000000000000000000000726014121063315024566 0ustar rootroot#include "test_stat.h" #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; Davix_fd* fd; ssize_t ret=1; RequestParams p; std::auto_ptr c( new Context()); // c->setSessionCaching(false); DavPosix pos(c.get()); const size_t size_content = rand()/1000000+2; char url[2048]; generate_random_uri(argv[1], "test_davix_",url, 2048); char buff_output[size_content+1]; char* buff_input = generate_random_string_content(size_content); if(argc > 2){ configure_grid_env(argv[2], p); } if( (fd =pos.open(&p, url, O_RDONLY, &tmp_err)) != NULL){ std::cerr << "Error ! open should fail, not an existing file and read only mode " << std::endl; return -1; } DavixError::clearError(&tmp_err); if( (fd =pos.open(&p, url, O_RDWR, &tmp_err)) != NULL){ std::cerr << "Error ! open should fail, not an existing file and not O_CREAT " << std::endl; return -1; } DavixError::clearError(&tmp_err); if( (fd =pos.open(&p, url, O_RDWR | O_CREAT, &tmp_err)) == NULL){ std::cerr << " open error "<< tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } // write content if( (ret = pos.write(fd, buff_input, size_content, &tmp_err)) < 0){ std::cerr << " write error "<< tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } if( pos.lseek(fd, 0,0, &tmp_err) != 0){ std::cerr << " error while lseek file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } // read content back ! off_t offset_buffer = 0; while( (ret = pos.read(fd, buff_output+ offset_buffer, 50, &tmp_err) ) > 0 && (size_t) offset_buffer < size_content){ offset_buffer += ret; } if(tmp_err){ std::cerr << " error while readding file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } buff_output[size_content] ='\0'; if(strncmp(buff_input, buff_output, size_content) !=0){ std::cerr << "content are different : FATAL ! " << std::endl; return -1; } // try partial read memset(buff_output, 0, sizeof(size_content)); off_t offset_read = size_content/2; size_t size_read = std::min(size_content - offset_read, 600); if( ( ret = pos.pread(fd, buff_output, size_read, offset_read, &tmp_err)) <0){ std::cerr << " error while pread " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } buff_output[size_read] ='\0'; if(strncmp(buff_input+offset_read, buff_output, size_read) !=0){ std::cerr << "content are different : FATAL ! " << std::endl; return -1; } if( (ret = pos.close(fd, &tmp_err))){ std::cerr << " error while closing file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } if( (fd =pos.open(&p, url, O_RDWR | O_CREAT | O_EXCL, &tmp_err)) != NULL){ std::cerr << " should fail , O_EXCL flag and file exist" << std::endl; return -1; } free(buff_input); return 0; } davix-0.8.0/test/functional/test_opendirpp.h0000644000000000000000000000011214121063315017647 0ustar rootroot#ifndef TEST_OPENDIR_H #define TEST_OPENDIR_H #endif // TEST_OPENDIR_H davix-0.8.0/test/functional/tool_get_replica_simple.cpp0000644000000000000000000000213514121063315022036 0ustar rootroot #include #include "davix_test_lib.h" using namespace Davix; #define MY_BUFFER_SIZE 65000 int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(0xff); RequestParams params; DavixError* tmp_err=NULL; Uri url(argv[1]); char * cert_path = argv[2]; if(argc > 2){ configure_grid_env(cert_path, params); } Context c; std::vector reps; File f(c, url); // delete unexisting dir, should fail reps = f.getReplicas(¶ms, &tmp_err); if(tmp_err != NULL){ std::cerr << "Error: " << tmp_err->getErrMsg() << std::endl; return -1; } if(reps.size() == 0){ std::cout << "No Replicas" << std::endl; return -1; } for(std::vector::iterator it = reps.begin(); it != reps.end(); ++it){ std::cout << "Replica " << it->getUri() << std::endl; } return 0; } davix-0.8.0/test/functional/tool_read_vector_simple.cpp0000644000000000000000000000374014121063315022060 0ustar rootroot#include "test_stat.h" #include #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; std::pair get_random_range_read(size_t total_size){ return std::pair ( (rand()%total_size-1), (rand()%total_size)/10+1); } int main(int argc, char** argv){ DavixError* tmp_err=NULL; Davix_fd* fd; ssize_t ret=1; RequestParams p; Context c; DavPosix pos(&c); if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url] " << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH]..." << std::endl; return 0; } if(argc > 2){ configure_grid_env(argv[2], p); } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); size_t vec = 10; size_t s_buff = 4096; DavIOVecInput in[vec]; DavIOVecOuput out[vec]; char buffer[vec][s_buff]; dav_size_t s[] = { 10000, 5, 20, 12 ,15 ,60, 90, 1, 88, 10}; dav_off_t off[] = { 10, 20, 2, 10 ,800 ,600, 523, 1, 0, 100}; for(size_t i = 0; i < vec; ++i){ in[i].diov_buffer= buffer[i]; in[i].diov_offset = off[i]; in[i].diov_size = s[i]; } if( (fd = pos.open(&p, argv[1], O_RDONLY, &tmp_err)) == NULL){ std::cerr << " open error : err code " << tmp_err->getStatus() << " err msg " << tmp_err->getErrMsg(); return -1; } if( ( ret = pos.preadVec(fd, in, out, vec, &tmp_err)) <0){ std::cerr << " vec read error : err code " << tmp_err->getStatus() << " err msg " << tmp_err->getErrMsg(); return -1; } for(size_t i = 0; i < vec; ++i){ std::cout << "part vector read of size " << out[i].diov_size << " with offset " << in[i].diov_offset << " :" << std::endl; std::cout << std::string((const char*) out[i].diov_buffer, out[i].diov_size) << std::endl; } return 0; } davix-0.8.0/test/functional/lorem-ipsum.h0000644000000000000000000000427014121063315017072 0ustar rootrootconst std::string testString("This is a file generated by davix tests. It is safe to delete.\n\n\n\n\n" "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\n\n" "Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\n\n" "Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\n\n" "Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat." ); davix-0.8.0/test/functional/test_opendir.h0000644000000000000000000000011214121063315017307 0ustar rootroot#ifndef TEST_OPENDIR_H #define TEST_OPENDIR_H #endif // TEST_OPENDIR_H davix-0.8.0/test/functional/test_opendir_partial.h0000644000000000000000000000011214121063315021023 0ustar rootroot#ifndef TEST_OPENDIR_H #define TEST_OPENDIR_H #endif // TEST_OPENDIR_H davix-0.8.0/test/functional/test_valid_write_read_vector_simple.cpp0000644000000000000000000000643114121063315024453 0ustar rootroot#include "test_stat.h" #include #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; std::pair get_random_range_read(size_t total_size){ return std::pair ( (rand()%total_size-1), (rand()%total_size)/10+1); } int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; Davix_fd* fd; ssize_t ret=1; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); const size_t size_content = rand()/10000000+2000; char url[2048]; generate_random_uri(argv[1], "test_davix_",url, 2048); char* buff_input = generate_random_string_content(size_content); if(argc > 2){ configure_grid_env(argv[2], p); } std::cout << " open remote file " << std::endl; if( (fd =pos.open(&p, url, O_RDWR | O_CREAT, &tmp_err)) == NULL){ std::cerr << " open error "<< tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } std::cout << " write content dir " << std::endl; // write content if( (ret = pos.write(fd, buff_input, size_content, &tmp_err)) < 0){ std::cerr << " write error "<< tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } pos.close(fd, &tmp_err); if(tmp_err){ std::cerr << " error while writing file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } if( (fd =pos.open(&p, url, O_RDWR | O_CREAT, &tmp_err)) == NULL){ std::cerr << " open error "<< tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } std::cout << " try stupid empty vector read" << std::endl; Davix::DavIOVecInput input; Davix::DavIOVecOuput output; dav_ssize_t res = pos.preadVec(fd, &input, &output, 0, &tmp_err); assert(res == 0 && tmp_err == NULL); const std::pair range_read = get_random_range_read(size_content); char buffer_read[range_read.second+1]; buffer_read[range_read.second]= '\0'; input.diov_buffer = buffer_read; input.diov_offset = range_read.first; input.diov_size = range_read.second; std::cout << " try to read one segment of "<< input.diov_size << " from " << input.diov_offset<< " offset of a content of " << size_content << std::endl; res = pos.preadVec(fd, &input, &output, 1, &tmp_err); assert( res == output.diov_size); assert( output.diov_size > 0); assert( tmp_err == NULL); assert( strncmp(buff_input +input.diov_offset, buffer_read, input.diov_size) ==0); if( (ret = pos.close(fd, &tmp_err))){ std::cerr << " error while closing file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } // delete trash file pos.unlink(&p, url, NULL); free(buff_input); return 0; } davix-0.8.0/test/functional/davix-tester.cpp0000644000000000000000000006761014121063315017602 0ustar rootroot#include #include #include #include "optionparser.h" #include #include #include #include "davix_test_lib.h" #include "utils/davix_s3_utils.hpp" #include "../TestcaseHandler.hpp" using namespace Davix; using std::placeholders::_1; #define DBG(message) std::cerr << __FILE__ << ":" << __LINE__ << " -- " << #message << " = " << message << std::endl; #define SSTR(message) static_cast(std::ostringstream().flush() << message).str() #include "lorem-ipsum.h" // define std::string teststring const std::string testfile("davix-testfile-"); #define ASSERT(assertion, msg) \ if((assertion) == false) throw std::runtime_error( SSTR(__FILE__ << ":" << __LINE__ << " (" << __func__ << "): Assertion " << #assertion << " failed.\n" << msg)) std::vector split(const std::string str, const std::string delim) { size_t prev = 0, cur; std::vector results; while((cur = str.find(delim, prev)) != std::string::npos) { results.push_back(str.substr(prev, cur-prev)); prev = cur + delim.size(); } std::string last = str.substr(prev, str.size()-prev); if(last.size() != 0) results.push_back(last); return results; } namespace Auth { enum Type {AWS, PROXY, AZURE, SWIFT, NONE, ILLEGAL}; Type fromString(const std::string &str) { if(str == "aws") return Auth::AWS; if(str == "proxy") return Auth::PROXY; if(str == "azure") return Auth::AZURE; if(str == "swift") return Auth::SWIFT; if(str == "none") return Auth::NONE; return Auth::ILLEGAL; }; }; static option::ArgStatus option_nonempty(const option::Option& option, bool msg) { if (option.arg != 0 && option.arg[0] != 0) return option::ARG_OK; if (msg) std::cout << "Option '" << option << "' requires a non-empty argument" << std::endl; return option::ARG_ILLEGAL; } namespace Opt { enum Type { UNKNOWN, HELP, AUTH, S3ACCESSKEY, S3SECRETKEY, S3REGION, AZUREKEY, S3ALTERNATE, CERT, URI, TRACE, COMMAND, OSTOKEN, OSPROJECTID, SWIFTACCOUNT}; } bool verify_options_sane(option::Parser &parse, std::vector &options) { if(parse.error()) { std::cout << "Parsing error" << std::endl; return false; } if(options[Opt::HELP]) { return false; } for(option::Option* opt = options[Opt::UNKNOWN]; opt; opt = opt->next()) { std::cout << "Unknown option: " << std::string(opt->name,opt->namelen) << "\n"; return false; } for(int i = 0; i < parse.nonOptionsCount(); ++i) { std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; return false; } return true; } std::vector parse_args(int argc, char** argv) { const option::Descriptor usage[] = { {Opt::UNKNOWN, 0, "", "", option::Arg::None, "davix functional tests runner\n" "USAGE: tester [options]\n\n" "Options:" }, {Opt::HELP, 0, "", "help", option::Arg::None, " --help \tPrint usage and exit." }, {Opt::AUTH, 0, "", "auth", option_nonempty, " --auth \t Authentication method" }, {Opt::S3ACCESSKEY, 0, "", "s3accesskey", option_nonempty, " --s3accesskey S3 access key"}, {Opt::S3SECRETKEY, 0, "", "s3secretkey", option_nonempty, " --s3secretkey S3 secret key"}, {Opt::S3REGION, 0, "", "s3region", option_nonempty, "--s3region S3 region"}, {Opt::AZUREKEY, 0, "", "azurekey", option_nonempty, "--azurekey Azure key"}, {Opt::S3ALTERNATE, 0, "", "s3alternate", option::Arg::None, "--s3alternate"}, {Opt::CERT, 0, "", "cert", option_nonempty, "--cert path to the proxy certificate to use"}, {Opt::URI, 0, "", "uri", option_nonempty, "--uri uri to test against"}, {Opt::TRACE, 0, "", "trace", option_nonempty, "--trace debug scope"}, {Opt::COMMAND, 0, "", "command", option_nonempty, "--command test to run"}, {Opt::OSTOKEN, 0, "", "ostoken", option_nonempty, "--ostoken Openstack token"}, {Opt::OSPROJECTID, 0, "", "osprojectid", option_nonempty, "--osprojectid Openstack project id"}, {Opt::SWIFTACCOUNT, 0, "", "swiftaccount", option_nonempty, "--swiftaccount Swift Account"}, {Opt::UNKNOWN, 0, "", "",option::Arg::None, "\nExamples:\n" " tester --auth proxy --uri https://storage/davix-tests --command makeCollection" }, {0,0,0,0,0,0} }; option::Stats stats(usage, argc-1, argv+1); // TODO fix argc-1 std::vector options(stats.options_max); std::vector buffer(stats.buffer_max); option::Parser parse(usage, argc-1, argv+1, &options[0], &buffer[0]); if(!verify_options_sane(parse, options)) { option::printUsage(std::cout, usage); exit(1); } return options; } std::string retrieve(const std::vector &options, const Opt::Type key) { if(!options[key]) return ""; return options[key].arg; } void authentication(const std::vector &opts, const Auth::Type &auth, RequestParams ¶ms) { if(auth == Auth::AWS) { params.setProtocol(RequestProtocol::AwsS3); ASSERT(opts[Opt::S3ACCESSKEY] != NULL, "--s3accesskey is required when using s3"); ASSERT(opts[Opt::S3SECRETKEY] != NULL, "--s3secretkey is required when using s3"); params.setAwsAuthorizationKeys(retrieve(opts, Opt::S3SECRETKEY), retrieve(opts, Opt::S3ACCESSKEY)); if(opts[Opt::S3REGION]) params.setAwsRegion(retrieve(opts, Opt::S3REGION)); if(opts[Opt::S3ALTERNATE]) params.setAwsAlternate(true); } else if(auth == Auth::PROXY) { configure_grid_env("proxy", params); } else if(auth == Auth::AZURE) { ASSERT(opts[Opt::AZUREKEY] != NULL, "--azurekey is required when using Azure"); params.setProtocol(RequestProtocol::Azure); params.setAzureKey(retrieve(opts, Opt::AZUREKEY)); } else if(auth == Auth::SWIFT) { ASSERT(opts[Opt::OSTOKEN] != NULL, "--ostoken is required when using swift"); if(opts[Opt::OSPROJECTID] == NULL && opts[Opt::SWIFTACCOUNT] == NULL) { std::cout << "--osprojectid or --swiftaccount is required when using swift" << std::endl; std::abort(); } params.setProtocol(RequestProtocol::Swift); params.setOSToken(retrieve(opts, Opt::OSTOKEN)); params.setOSProjectID(retrieve(opts, Opt::OSPROJECTID)); params.setSwiftAccount(retrieve(opts, Opt::SWIFTACCOUNT)); } else { ASSERT(false, "unknown authentication method"); } } void remove(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("Delete " << uri.getString())); // a very dangerous test.. Make sure that uri at least // contains "davix-test" in its path. bool safePath = uri.getPath().find("davix-test") != std::string::npos; handler.check(safePath, "Path is safe and contains 'davix-test'"); if(!safePath) return; Context context; try { DavFile file(context, params, uri); file.deletion(¶ms); handler.pass("Deletion successful"); } catch(const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } } void depopulate(TestcaseHandler &handler, const RequestParams ¶ms, Uri uri, int nfiles) { handler.setName(SSTR("Depopulate " << uri.getString() << ", remove " << nfiles << " files")); Context context; for(int i = 1; i <= nfiles; i++) { Uri u(uri); u.addPathSegment(SSTR(testfile << i)); remove(handler.makeChild(), params, u); } } std::string string_from_mode(mode_t mode){ const char* rmask ="xwr"; std::string str(10,'-'); str[0] = (S_ISDIR(mode))?'d':'-'; for(size_t i=0; i < 9; ++i){ str[9-i] = (( mode & (0x01 << i))?(rmask[i%3]):'-'); } return str; } void statdir(TestcaseHandler &handler, const RequestParams ¶ms, Uri uri) { handler.setName(SSTR("Stat on " << uri.getString() << ", ensure is a directory")); Context context; DavFile file(context, params, uri); StatInfo info; file.statInfo(¶ms, info); handler.info(SSTR("Mode: " << string_from_mode(info.mode))); handler.info(SSTR("Size: " << info.size)); // http / https will use a HEAD, from which we can't determine if this is // a directory or not if(uri.getProtocol() != "http" && uri.getProtocol() != "https") { handler.check(S_ISDIR(info.mode), "Ensure S_ISDIR shows a directory"); } } void makeCollection(TestcaseHandler &handler, const RequestParams ¶ms, Uri uri) { handler.setName(SSTR("Create directory on " << uri.getString())); DavixError* err = NULL; Context context; DavFile file(context, params, uri); file.makeCollection(¶ms, &err); if(!handler.checkDavixError(&err)) return; // make sure it is empty DavFile::Iterator it = file.listCollection(¶ms); handler.check(it.name() == "" && !it.next(), "Ensure newly created directory is empty"); // do a stat, make sure it's a dir statdir(handler.makeChild(), params, uri); Uri u2 = uri; u2.ensureTrailingSlash(); statdir(handler.makeChild(), params, u2); } #define NEON_S3_SIGN_DURATION 3600 //------------------------------------------------------------------------------ // stat a file through signed URI, make sure it's a file. //------------------------------------------------------------------------------ void statfileFromSignedURI(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("Stat file through signed uri on " << uri.getString())); Uri signedURI(S3::signURI(params, "GET", uri, params.getHeaders(), NEON_S3_SIGN_DURATION)); RequestParams params2(params); signedURI.httpizeProtocol(); params2.setProtocol(RequestProtocol::Http); params2.setAwsAuthorizationKeys("", ""); params2.setAwsRegion(""); params2.setAwsToken(""); Context context; DavFile file(context, params2, signedURI); StatInfo info; file.statInfo(¶ms2, info); handler.info(SSTR("Mode: " << string_from_mode(info.mode))); handler.info(SSTR("Size: " << info.size)); handler.check(!S_ISDIR(info.mode), "Ensure S_ISDIR shows a file"); } //------------------------------------------------------------------------------ // stat a file, make sure it's a file. //------------------------------------------------------------------------------ void statfile(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("Stat on " << uri.getString() << ", ensure is a file")); Context context; DavFile file(context, params, uri); StatInfo info; try { file.statInfo(¶ms, info); handler.info(SSTR("Mode: " << string_from_mode(info.mode))); handler.info(SSTR("Size: " << info.size)); handler.check(!S_ISDIR(info.mode), "Ensure S_ISDIR shows a file"); } catch(const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } if(!params.getAwsAutorizationKeys().first.empty()) { // Now try statting through the signed URL statfileFromSignedURI(handler.makeChild(), params, uri); } } void movefile(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { Uri u1(uri); Uri u2(uri); u1.addPathSegment(SSTR(testfile << 1)); u2.addPathSegment(SSTR(testfile << 1 << "-moved")); handler.setName(SSTR("Move " << u1.getString() << " to " << u2.getString())); Context context; DavFile source(context, params, u1); DavFile dest(context, params, u2); try { source.move(¶ms, dest); statfile(handler.makeChild(), params, u2); dest.move(¶ms, source); handler.pass("Move successful"); } catch(const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } } void uploadFile(TestcaseHandler &handler, Context &ctx, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("Upload testfile to " << uri.getString())); DavFile file(ctx, params, uri); try { file.put(NULL, testString.c_str(), testString.size()); handler.pass(SSTR("File " << uri.getString() << " uploaded.")); } catch(const DavixException &err) { handler.fail(SSTR("Exception: " << err.what())); } statfile(handler, params, uri); } void populate(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const int nfiles) { handler.setName(SSTR("Populate " << uri.getString() << " with " << nfiles << " files")); Context context; for(int i = 1; i <= nfiles; i++) { Uri u(uri); u.addPathSegment(SSTR(testfile << i)); uploadFile(handler.makeChild(), context, params, u); } } // count the number of files in folder void countfiles(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const int nfiles) { handler.setName(SSTR("List " << uri.getString() << ", expect " << nfiles << " files")); try { Context context; DavFile file(context, params, uri); DavFile::Iterator it = file.listCollection(¶ms); int i = 0; do { // workaround for Swift, discard the first entry which is the directory created before if(params.getProtocol() == RequestProtocol::Swift && i == 0){ it.next(); } i++; } while(it.next()); handler.check(i == nfiles, SSTR("Directory contains " << nfiles << " files")); } catch(const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } } // confirm that the files listed are the exact same ones uploaded during a populate test void listing(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const int nfiles) { handler.setName(SSTR("List " << uri.getString() << ", expect " << nfiles << " files")); try { int hits[nfiles+1]; for(int i = 0; i <= nfiles; i++) hits[i] = 0; Context context; DavFile file(context, params, uri); DavFile::Iterator it = file.listCollection(¶ms); int i = 0; do { // workaround for Swift, discard the first entry which is the directory created before if(params.getProtocol() == RequestProtocol::Swift && i == 0){ it.next(); } i++; std::string name = it.name(); // make sure the filenames are the same as the ones we uploaded if(name.size() <= testfile.size()) { handler.fail(SSTR("Unexpected filename: " << name)); return; } std::string part1 = name.substr(0, testfile.size()); std::string part2 = name.substr(testfile.size(), name.size()-1); if(part1 != testfile) { handler.fail(SSTR("Unexpected filename: " << part1)); return; } int num = atoi(part2.c_str()); if(num <= 0 || num > nfiles) { handler.fail(SSTR("Unexpected file number: " << num)); return; } hits[num]++; } while(it.next()); handler.check(i == nfiles, SSTR("Ensure directory contains " << nfiles << " files")); // count all hits to make sure all have exactly one for(int i = 1; i <= nfiles; i++) { handler.check(hits[i] == 1, SSTR("Ensure testfile #" << i << " is found")); } } catch(const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } } void checksum(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const std::string chk_algo) { handler.setName(SSTR("Get checksum of file: " << uri.getString())); try { Context context; DavFile file(context, params, uri); std::string chk; DavixError* err = NULL; file.checksum(¶ms, chk, chk_algo, &err); handler.pass(SSTR("File " << chk_algo << " checksum is " << chk)); } catch (const DavixException &exc) { handler.fail(SSTR("Exception: " << exc.what())); } } /* upload a file and move it around */ void putMoveDelete(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("Put-move-delete on " << uri.getString())); Uri u = uri; Uri u2 = uri; u.addPathSegment(SSTR(testfile << "put-move-delete")); u2.addPathSegment(SSTR(testfile << "put-move-delete-MOVED")); Context context; DavFile file(context, params, u); file.put(¶ms, testString.c_str(), testString.size()); handler.pass(SSTR("Put on " << u.getString())); DavFile movedFile(context, params, u2); file.move(¶ms, movedFile); handler.pass(SSTR("Move on " << u2.getString())); movedFile.deletion(¶ms); handler.pass(SSTR("Delete on " << u2.getString())); } //------------------------------------------------------------------------------ // Concatenate vector into a string //------------------------------------------------------------------------------ static std::string vecToString(const std::vector &vec, const std::string &delim) { std::ostringstream ss; for(size_t i = 0; i < vec.size(); i++) { ss << vec[i]; if(i != vec.size() - 1) { ss << delim; } } return ss.str(); } void preadvec(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const std::string str_ranges, std::vector options) { handler.setName(SSTR("preadvec on " << uri.getString())); handler.info(SSTR("Options: " << str_ranges << " | " << vecToString(options, ","))); Uri u = uri; std::string filename = SSTR(testfile << 1); bool noappend = false; for(std::vector::iterator it = options.begin(); it != options.end(); it++) { if(*it == "nomulti") { u.addFragmentParam("multirange", "false"); } else if(*it == "noappend") { noappend = true; } else if(it->find("nconnections=", 0) == 0) { int nconnections = atoi(it->c_str() + 13); if(nconnections <= 0) { handler.fail("Unable to parse nconnections"); return; } u.addFragmentParam("nconnections", SSTR(nconnections)); } else if(it->find("mergewindow=", 0) == 0) { int mergewindow = atoi(it->c_str() + 12); if(mergewindow <= 0) { handler.fail("Unable to parse mergewindow"); return; } u.addFragmentParam("mergewindow", SSTR(mergewindow)); } else { handler.fail(SSTR("Unknown option to preadvec: " << *it)); return; } } if(!noappend) { u.addPathSegment(filename); } std::vector ranges = split(str_ranges, ","); DavIOVecInput inVec[ranges.size()]; DavIOVecOuput outVec[ranges.size()]; std::vector> buffers; for(size_t i = 0; i < ranges.size(); i++) { std::vector parts = split(ranges[i], "-"); if(parts.size() != 2) { handler.fail(SSTR("Cannot parse range: " << ranges[i])); return; } dav_off_t start = atoi(parts[0].c_str()); dav_off_t end = atoi(parts[1].c_str()); dav_ssize_t size = end - start + 1; buffers.emplace_back(new std::string(size, ' ')); inVec[i].diov_buffer = (void*) buffers.back()->c_str(); // new char[size]; inVec[i].diov_size = size; inVec[i].diov_offset = start; } Context context; DavFile file(context, params, u); DavixError *err = NULL; file.readPartialBufferVec(¶ms, inVec, outVec, ranges.size(), &err); if(!handler.checkDavixError(&err)) return; for(size_t i = 0; i < ranges.size(); i++) { std::string chunk( (char*) outVec[i].diov_buffer, outVec[i].diov_size); handler.check(chunk.size() == inVec[i].diov_size, SSTR("Validate chunk #" << i << " size")); if(filename == SSTR(testfile << 1)) { handler.check(chunk == testString.substr(inVec[i].diov_offset, inVec[i].diov_size), SSTR("Validate chunk #" << i << " contents")); } } } void preadvec_all_opts(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, const std::string str_ranges) { handler.setName(SSTR("preadvec-all-opts on " << uri.getString() << ": " << str_ranges)); preadvec(handler.makeChild(), params, uri, str_ranges, split("mergewindow=1", ",")); preadvec(handler.makeChild(), params, uri, str_ranges, split("mergewindow=1000", ",")); preadvec(handler.makeChild(), params, uri, str_ranges, split("nomulti,mergewindow=1", ",")); preadvec(handler.makeChild(), params, uri, str_ranges, split("nomulti,mergewindow=1", ",")); } void preadvec_all(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri) { handler.setName(SSTR("preadvec-all on " << uri.getString())); preadvec_all_opts(handler.makeChild(), params, uri, "0-10,5-10,3-4,30-40,200-305,1000-1500"); preadvec_all_opts(handler.makeChild(), params, uri, "0-10,5-10"); preadvec_all_opts(handler.makeChild(), params, uri, "0-10,15-20"); } void detectwebdav(TestcaseHandler &handler, const RequestParams ¶ms, const Uri uri, bool result) { handler.setName(SSTR("Detect WebDAV support on " << uri.getString() << ", expect " << result)); Context context; DavixError *err = NULL; WebdavSupport::Type res = detect_webdav_support(context, params, uri, &err); if(result) { handler.check(res == WebdavSupport::YES, "Ensure endpoint has WebDAV support"); ASSERT(res == WebdavSupport::YES, ""); } else if(!result) { handler.check(res == WebdavSupport::NO || res == WebdavSupport::UNKNOWN, "Ensure endpoint does not have WebDAV support"); } else { handler.fail("Unknown failure"); } } void assert_args(const std::vector &cmd, int nargs) { ASSERT(cmd.size() != 0, "assert_args called with empty command!"); ASSERT(cmd.size() == nargs+1, "Wrong number of arguments to " << cmd[0] << ": " << cmd.size()-1 << ", expected: " << nargs); } bool run(int argc, char** argv) { RequestParams params; params.setOperationRetry(0); std::vector opts = parse_args(argc, argv); Auth::Type auth = Auth::fromString(retrieve(opts, Opt::AUTH)); ASSERT(opts[Opt::COMMAND] != NULL, "--command is necessary"); ASSERT(opts[Opt::URI] != NULL, "--uri is necessary"); ASSERT(auth != Auth::ILLEGAL, "--auth is necessary, and can only be one of aws, proxy, azure, none"); if(opts[Opt::TRACE]) { std::string scope = retrieve(opts, Opt::TRACE); setLogScope(0); setLogScope(scope); setLogLevel(DAVIX_LOG_TRACE); } std::vector cmd = split(retrieve(opts, Opt::COMMAND), " "); Uri uri = Uri(retrieve(opts, Opt::URI)); authentication(opts, auth, params); TestcaseHandler handler; if(cmd[0] == "makeCollection") { assert_args(cmd, 0); makeCollection(handler, params, uri); } else if(cmd[0] == "populate") { assert_args(cmd, 1); populate(handler, params, uri, atoi(cmd[1].c_str())); } else if(cmd[0] == "checksum") { assert_args(cmd, 1); checksum(handler, params, uri, cmd[1].c_str()); } else if(cmd[0] == "remove") { assert_args(cmd, 0); ASSERT(cmd.size() == 1, "Wrong number of arguments to remove"); remove(handler, params, uri); } else if(cmd[0] == "listing") { assert_args(cmd, 1); listing(handler, params, uri, atoi(cmd[1].c_str())); } else if(cmd[0] == "putMoveDelete") { assert_args(cmd, 0); ASSERT(cmd.size() == 1, "Wrong number of arguments to putMoveDelete"); putMoveDelete(handler, params, uri); } else if(cmd[0] == "depopulate") { assert_args(cmd, 1); depopulate(handler, params, uri, atoi(cmd[1].c_str())); } else if(cmd[0] == "countfiles") { assert_args(cmd, 1); countfiles(handler, params, uri, atoi(cmd[1].c_str())); } else if(cmd[0] == "statdir") { assert_args(cmd, 0); statdir(handler, params, uri); } else if(cmd[0] == "statfile") { assert_args(cmd, 0); statfile(handler, params, uri); } else if(cmd[0] == "movefile") { assert_args(cmd, 0); movefile(handler, params, uri); } else if(cmd[0] == "preadvec") { if(cmd.size() == 2) { preadvec(handler, params, uri, cmd[1], std::vector()); } else if(cmd.size() == 3) { preadvec(handler, params, uri, cmd[1], split(cmd[2], ",")); } else { handler.fail("Wrong number of arguments to preadvec"); } } else if(cmd[0] == "preadvec-all-opts") { assert_args(cmd, 1); preadvec_all_opts(handler, params, uri, cmd[1]); } else if(cmd[0] == "preadvec-all") { assert_args(cmd, 0); preadvec_all(handler, params, uri); } else if(cmd[0] == "detectwebdav") { assert_args(cmd, 1); bool expected = false; if(cmd[1] == "1") { expected = true; } else if(cmd[1] == "0") { expected = false; } else { ASSERT(false, "Unexpected input for expected result"); } detectwebdav(handler, params, uri, expected); } else if(cmd[0] == "fulltest") { assert_args(cmd, 0); handler.setName(SSTR("Full-test on " << uri.getString())); makeCollection(handler.makeChild(), params, uri); populate(handler.makeChild(), params, uri, 5); listing(handler.makeChild(), params, uri, 5); preadvec_all(handler.makeChild(), params, uri); movefile(handler.makeChild(), params, uri); depopulate(handler.makeChild(), params, uri, 3); countfiles(handler.makeChild(), params, uri, 2); remove(handler.makeChild(), params, uri); } else if(cmd[0] == "fulltest-s3") { assert_args(cmd, 0); handler.setName(SSTR("Full-test S3 on " << uri.getString())); makeCollection(handler.makeChild(), params, uri); populate(handler.makeChild(), params, uri, 5); listing(handler.makeChild(), params, uri, 5); preadvec_all(handler.makeChild(), params, uri); movefile(handler.makeChild(), params, uri); depopulate(handler.makeChild(), params, uri, 3); countfiles(handler.makeChild(), params, uri, 2); depopulate(handler.makeChild(), params, uri, 5); } else if(cmd[0] == "fulltest-azure") { assert_args(cmd, 0); handler.setName(SSTR("Full-test Azure on " << uri.getString())); populate(handler.makeChild(), params, uri, 5); statdir(handler.makeChild(), params, uri); listing(handler.makeChild(), params, uri, 5); preadvec_all(handler.makeChild(), params, uri); depopulate(handler.makeChild(), params, uri, 5); } else if(cmd[0] == "fulltest-swift") { assert_args(cmd, 0); handler.setName(SSTR("Full-test Swift on " << uri.getString())); makeCollection(handler.makeChild(), params, uri); populate(handler.makeChild(), params, uri, 5); listing(handler.makeChild(), params, uri, 5); preadvec_all(handler.makeChild(), params, uri); movefile(handler.makeChild(), params, uri); depopulate(handler.makeChild(), params, uri, 3); countfiles(handler.makeChild(), params, uri, 2); depopulate(handler.makeChild(), params, uri, 5); } else { ASSERT(false, "Unknown command: " << cmd[0]); } return handler.ok(); } int main(int argc, char** argv) { bool success = false; try { success = run(argc, argv); } catch(std::exception &e) { std::cout << e.what() << std::endl; return 1; } if(success) { return 0; } return 1; } davix-0.8.0/test/functional/test_opendir.cpp0000644000000000000000000000222614121063315017652 0ustar rootroot#include "test_opendir.h" #include #include #include #include "davix_test_lib.h" using namespace Davix; #define MY_BUFFER_SIZE 65000 int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); if(argc > 2){ configure_grid_env(argv[2], p); } DAVIX_DIR* d = pos.opendir(&p, argv[1], &tmp_err); if(d != NULL){ struct dirent * dir = NULL; int n =0; do{ dir= pos.readdir(d, &tmp_err); if(dir) std::cout << "N° " << ++n <<" file : " << dir->d_name << std::endl; }while(dir!= NULL); pos.closedir(d, NULL); } if(tmp_err){ std::cout << " listing directory error "<< tmp_err->getErrMsg() << std::endl; return -1; } return 0; } davix-0.8.0/test/functional/test_auto_rmdir_unlink_delete.cpp0000644000000000000000000000637714121063315023274 0ustar rootroot #include #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } RequestParams p; struct stat st; int res =-1; p.setProtocol(RequestProtocol::Webdav); DavixError* tmp_err=NULL; char * base_dir = argv[1]; char * cert_path = argv[2]; char buffer[2048]; if(argc > 2){ configure_grid_env(cert_path, p); } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); generate_random_uri(base_dir, "rmdir_unlink_delete_test", buffer, 2048); std::string created_dir(buffer); Context c; DavPosix pos(&c); std::cout << "verify that " << created_dir << "does not exist" << std::endl; res = pos.stat(&p, created_dir, &st, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::FileNotFound); DavixError::clearError(&tmp_err); std::cout << " verify that unlink() return enoent on not existing dir" << std::endl; res = pos.unlink(&p, created_dir, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::FileNotFound); DavixError::clearError(&tmp_err); std::cout << " verify that rmdir() return enoent on not existing dir" << std::endl; res = pos.rmdir(&p, created_dir, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::FileNotFound); DavixError::clearError(&tmp_err); std::cout << " verify that WebdavQuery::davDelete() return enoent on not existing dir" << std::endl; File f(c, created_dir); res = f.deletion(&p, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::FileNotFound); DavixError::clearError(&tmp_err); std::cout << "create " << created_dir << std::endl; res = pos.mkdir(&p, created_dir, 0755, &tmp_err); assert( res ==0 && tmp_err == NULL); std::cout << "verify that " << created_dir << "exist " << std::endl; res = pos.stat(&p, created_dir, &st, &tmp_err); assert( res == 0); assert(tmp_err == NULL); DavixError::clearError(&tmp_err); std::cout << "verify that unlink() does not delete directory " << std::endl; res = pos.unlink(&p, created_dir, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::IsADirectory); DavixError::clearError(&tmp_err); std::cout << "remove dir with rmdir() " << std::endl; res = pos.rmdir(&p, created_dir, &tmp_err); assert( res == 0); assert(tmp_err == NULL); std::cout << "verify that " << created_dir << "does not exist" << std::endl; res = pos.stat(&p, created_dir, &st, &tmp_err); assert( res != 0); assert(tmp_err && tmp_err->getStatus() == StatusCode::FileNotFound); DavixError::clearError(&tmp_err); std::cout << "create again " << created_dir << std::endl; res = pos.mkdir(&p, created_dir, 0755, &tmp_err); assert( res ==0 && tmp_err == NULL); return 0; } davix-0.8.0/test/functional/test_opendirpp.cpp0000644000000000000000000000241614121063315020213 0ustar rootroot#include "test_opendirpp.h" #include #include #include #include "davix_test_lib.h" using namespace Davix; #define MY_BUFFER_SIZE 65000 int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); Davix::DavixError* tmp_err; if(argc > 2){ configure_grid_env(argv[2], p); } DAVIX_DIR* d = pos.opendirpp(&p, argv[1], &tmp_err); if(d){ struct dirent * dir = NULL; int n =0; do{ struct stat st; dir= pos.readdirpp(d, &st, &tmp_err); if(dir) std::cout << "N° " << ++n <<" file : " << dir->d_name <<" len : " << st.st_size << " atime: "<< st.st_atime << " mode : "<< std::oct << st.st_mode; std::cout << " mtime : " << st.st_mtime ; std::cout << " ctime : " << st.st_ctime << std::endl; }while(dir!= NULL); pos.closedirpp(d, &tmp_err); } return 0; } davix-0.8.0/test/functional/test_opendir_partial.cpp0000644000000000000000000000323014121063315021362 0ustar rootroot#include "test_opendir_partial.h" #include #include #include #include #include #include #include "davix_test_lib.h" /** Execute an incomplete readdir of a directory, and verify the correct closedir with the memory cleaning */ using namespace Davix; #define MY_BUFFER_SIZE 65000 int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url] [size_to_read] " << std::endl; std::cout <<"\t" << argv[0] << " [url] [size_to_read] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); int max_read= atoi(argv[2]); std::cout << " end of the dir number " << max_read << std::endl; DavixError* tmp_err=NULL; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); if(argc > 3){ configure_grid_env(argv[3], p); } DAVIX_DIR* d = pos.opendir(&p, argv[1], &tmp_err); if(d){ struct dirent * dir = NULL; int n= 0; do{ dir= pos.readdir(d, &tmp_err); if(dir) std::cout << "N° " << n <<" file : " << dir->d_name << std::endl; n++; }while(dir!= NULL && max_read > n); if(dir == NULL){ std::cout << " Normal end of the directory, too little directory, error in the test " << std::endl; return -3; } } pos.closedir(d, NULL); if(tmp_err){ std::cout << " listing directory error "<< tmp_err->getErrMsg() << std::endl; return -1; } return 0; } davix-0.8.0/test/functional/ctest_functional.cmake0000644000000000000000000000702314121063315021015 0ustar rootroot# ctest script file for automated functional tests for davix # message (" Setup tests parameters... ") set(BASIC_LOGIN "test") set(BASIC_PASSWD "tester") set(http_dcache "http://sligo.desy.de:2880/pnfs/desy.de/data/dteam/davix-tests/" CACHE STRING "dCache test instance to use (read-only)") set(https_dpm "https://dpmhead-trunk.cern.ch/dpm/cern.ch/home/dteam/davix-tests/" CACHE STRING "DPM test instance to use") set(https_dpm_file "${https_dpm}/davix-tests/testread0011") set(dav_dpm "davs://dpmhead-trunk.cern.ch/dpm/cern.ch/home/dteam/davix-tests/" CACHE STRING "DPM test instance to use throught WebDAV protocol") set(https_dcache "https://prometheus.desy.de/VOs/dteam/" CACHE STRING "dCache test instance to use") set(http_dynaFed_base "http://federation.desy.de/fed/dynafeds_demo/everywhere/") set(http_dynaFed_file "${http_dynaFed_base}/file_1005.txt") # set(metalink_url "http://download.documentfoundation.org/libreoffice/stable/4.3.4/deb/x86_64/LibreOffice_4.3.4_Linux_x86-64_deb.tar.gz") # set(metalink3_url "http://download.documentfoundation.org/libreoffice/stable/4.3.4/deb/x86_64/LibreOffice_4.3.4_Linux_x86-64_deb_helppack_en-US.tar.gz.metalink") # set(metalink_url_direct "http://download.documentfoundation.org/libreoffice/stable/4.3.4/deb/x86_64/LibreOffice_4.3.4_Linux_x86-64_deb_helppack_en-US.tar.gz.meta4") # dCache read-only test_dav_endpoint_ronly( "${http_dcache}" "proxy") # dCache tests test_valid_write_read_generic("${https_dcache}" "proxy") test_rename("${https_dcache}" "proxy") test_dav_endpoint_rw( "${https_dcache}" "proxy") # test_valid_delete_all("${https_dcache}" "proxy") test_valid_read_generic("${https_dcache}" "proxy") test_valid_write_read_generic("${https_dcache}" "proxy") # DPM tests test_valid_write_read_generic("${https_dpm}" "proxy") test_rename("${https_dpm}" "proxy") test_dav_endpoint_rw( "${https_dpm}" "proxy") test_valid_delete_all("${https_dpm}" "proxy") test_valid_read_generic("${https_dpm}" "proxy") test_valid_write_read_generic("${https_dpm}" "proxy") # DPM Webdav test_collection("${dav_dpm}" "proxy") # Storm tests ## Disable storm test no valid gate ! #test_dav_endpoint_rw( "${http_storm_base}" "proxy") #test_valid_delete_all("${http_storm_base}" "proxy") #test_valid_read_generic("${http_storm_base}" "proxy") #test_valid_write_read_generic("${http_storm_base}" "proxy") # localhost generic server, ex : "davserver -n -D /tmp" test_dav_endpoint_rw("http://localhost:8008" "") # localhost generic server with basic auth on port 8009, # ex : "davserver -u test -p tester -P 8009 -D /tmp" test_dav_endpoint_rw("http://localhost:8009" "${BASIC_LOGIN}:${BASIC_PASSWD}") test_valid_delete_all("http://localhost:8009" "${BASIC_LOGIN}:${BASIC_PASSWD}") test_valid_delete_all("http://localhost:8008" "${CMAKE_SOURCE_DIR}/test.p12") ## generic http query test test_valid_read_generic("http://google.com" "") test_valid_read_generic("http://wikipedia.org" "") test_valid_read_generic("https://wikipedia.org" "") test_valid_read_generic("http://www.w3.org/" "") test_valid_read_generic("http://cern.ch" "") # testwith common SE test_valid_read_generic("${https_dpm}" "proxy") test_valid_delete_all("${https_dpm}" "proxy") # dynaFed test_valid_read_generic("${http_dynaFed_base}" "proxy") # test replicas listing test_replica_listing_existing("${https_dpm_file}" "proxy") test_replica_listing_existing("${http_dynaFed_file}" "proxy") # test_replica_listing_existing("${metalink_url}" "proxy") # test_replica_listing_existing("${metalink3_url}" "proxy") # test_replica_listing_existing("${metalink_url_direct}" "proxy") davix-0.8.0/test/functional/davix_test_lib.cpp0000644000000000000000000000701614121063315020155 0ustar rootroot #include "davix_test_lib.h" #include #include #include #include #include #include #include #include #include #include using namespace Davix; int mycred_auth_callback_x509(void* userdata, const SessionInfo & info, X509Credential * cred, DavixError** err){ (void) info; Davix::DavixError* tmp_err= NULL; std::string path((char*) userdata); int ret = cred->loadFromFileP12( path, "", &tmp_err); if(ret != 0){ fprintf(stderr, " FATAL authentification Error : %s", tmp_err->getErrMsg().c_str()); DavixError::propagateError(err, tmp_err); } return ret; } char* generate_random_uri(const char* uri_dir, const char* prefix, char* buff, size_t s_buff){ snprintf(buff, s_buff, "%s/%s_%d%ld%ld",uri_dir, prefix, (int)getpid() ,(long) time(NULL), (long) rand()); return buff; } Davix::Uri generate_random_uri(const Davix::Uri & url_directory, const std::string & prefix){ std::ostringstream ss; ss << url_directory << "/" << prefix << static_cast(getpid()) << static_cast(time(NULL)) << static_cast(rand()); return Davix::Uri(ss.str()); } void configure_grid_env(char * cert_path, RequestParams& p){ if(strcmp(cert_path, "proxy") == 0){ // VOMS PROXY MODE X509Credential x; std::string proxy_path; char* p_str; if ( (p_str = getenv("X509_USER_PROXY") ) != NULL ){ proxy_path = p_str; }else{ std::ostringstream ss; ss << "/tmp/x509up_u" << getuid(); proxy_path = ss.str(); } x.loadFromFilePEM(proxy_path,proxy_path,"", NULL); p.setClientCertX509(x); } else{ char login_passwd[strlen(cert_path)+1]; char* pstr; strcpy(login_passwd, cert_path); pstr = strchr(login_passwd, ':'); if( pstr != NULL){ *pstr= '\0'; pstr++; p.setClientLoginPassword(std::string(login_passwd), std::string(pstr)); } p.setClientCertCallbackX509(&mycred_auth_callback_x509, cert_path); } // add standard grid certificate for wlcg test p.addCertificateAuthorityPath("/etc/grid-security/certificates/"); // add wrong cert path for testing purpose p.addCertificateAuthorityPath("/Iamnotexisting"); p.addCertificateAuthorityPath(""); p.addCertificateAuthorityPath("/etc/group"); // add a file } char * generate_random_string_content(size_t size){ char * res = (char*) malloc(size * sizeof(char)); size_t i =0; while(i < size){ res[i]= (char) (((rand()%2)?65:97)+(rand()%26)); i++; } return res; } /* DAVIX_C_DECL_BEGIN void configure_grid_env_c(char * cert_path, davix_params_t params){ davix_error_t tmp_err=NULL; char login_passwd[strlen(cert_path)+1]; char* pstr; strcpy(login_passwd, cert_path); pstr = strchr(login_passwd, ':'); if( pstr != NULL){ *pstr= '\0'; pstr++; davix_params_set_login_passwd(params, login_passwd, pstr); }else{ davix_x509_cert_t cred = davix_x509_cert_new(); davix_x509_cert_load_from_p12(cred, cert_path, "", &tmp_err); if(tmp_err){ std::cerr << " failure when load cert : " << davix_error_msg(tmp_err) << std::endl; exit(-1); } davix_params_set_client_cert_X509(params, cred); davix_x509_cert_free(cred); } davix_params_set_ssl_check(params, false, &tmp_err); } DAVIX_C_DECL_END */ davix-0.8.0/test/functional/test_request.h0000644000000000000000000000011214121063315017337 0ustar rootroot#ifndef TEST_REQUEST_H #define TEST_REQUEST_H #endif // TEST_REQUEST_H davix-0.8.0/test/functional/test_request.cpp0000644000000000000000000000120714121063315017700 0ustar rootroot#include "test_request.h" #include using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage " << argv[0] << " [url]" << std::endl; return 0; } DavixError* tmp_err=NULL; Context c; HttpRequest r(c, argv[1], &tmp_err); if(!tmp_err) r.executeRequest(&tmp_err); if(tmp_err){ std::cerr << " error in request : " << tmp_err->getErrMsg() << std::endl; }else{ std::vector body = r.getAnswerContentVec(); std::string v(body.begin(), body.end()); std::cout << "content "<< v << std::endl; } return 0; } davix-0.8.0/test/functional/davix_rw_test.cpp0000644000000000000000000000275614121063315020045 0ustar rootroot#include "test_stat.h" #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; Davix_fd* fd; ssize_t ret=1; RequestParams p; std::auto_ptr c( new Context()); DavPosix pos(c.get()); char buff[2050]={0}; if(argc > 2){ configure_grid_env(argv[2], p); } if( (fd =pos.open(&p, argv[1], O_RDONLY, &tmp_err)) == NULL){ std::cerr << " error while opening file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } // std::cout << "file content " << std::endl; while( fd && (ret = pos.read(fd, buff, 2048, &tmp_err)) > 0){ buff[ret] = '\0'; std::cout << buff; } std::cout << std::endl; if(tmp_err){ std::cerr << " error while readding file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } if( (ret = pos.close(fd, &tmp_err))){ std::cerr << " error while closing file " << tmp_err->getErrMsg() << " code :" << (int) tmp_err->getStatus() << std::endl; return -1; } return 0; } davix-0.8.0/test/functional/davix_test_lib.h0000644000000000000000000000153414121063315017621 0ustar rootroot#ifndef DAVIX_TEST_LIB_H #define DAVIX_TEST_LIB_H #include #include int mycred_auth_callback_x509(void* userdata, const Davix::SessionInfo & info, Davix::X509Credential * cert, Davix::DavixError** err); void configure_grid_env(char * auth_args, Davix::RequestParams& p); void configure_grid_env_bis(char * auth_args, Davix::RequestParams& p); char* generate_random_uri(const char* uri_dir, const char* prefix, char* buff, size_t s_buff); Davix::Uri generate_random_uri(const Davix::Uri & url_directory, const std::string & prefix); char * generate_random_string_content(size_t size); #define DAV_ASSERT_TRUE(test, failure_msg) \ do{ \ if(! (test) ){ \ std::cerr << "f:"<< __FILE__ << ":" << __LINE__ << ": " << failure_msg << std::endl; \ exit(-1); \ } \ }while(0) #endif // DAVIX_TEST_LIB_H davix-0.8.0/test/functional/test_checksum.cpp0000644000000000000000000000162014121063315020011 0ustar rootroot #include #include #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 3){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url] [algo]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [algo] [CERTIFICATE_PATH] " << std::endl; return 0; } RequestParams p; DavixError* tmp_err=NULL; Uri u(argv[1]); char* algo = argv[2]; Context c; File f(c,u); if(argc > 3){ configure_grid_env(argv[3], p); } std::string chk; int ret = f.checksum(&p, chk, algo, &tmp_err); if(ret ==0) std::cout << algo << " "<< chk << std::endl; else std::cout << "checksum error "<< tmp_err->getErrMsg() << std::endl; return 0; } davix-0.8.0/test/functional/optionparser.h0000644000000000000000000030625714121063315017360 0ustar rootroot/* * The Lean Mean C++ Option Parser * * Copyright (C) 2012 Matthias S. Benkmann * * The "Software" in the following 2 paragraphs refers to this file containing * the code to The Lean Mean C++ Option Parser. * The "Software" does NOT refer to any other files which you * may have received alongside this file (e.g. as part of a larger project that * incorporates The Lean Mean C++ Option Parser). * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software, to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the following * conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * NOTE: It is recommended that you read the processed HTML doxygen documentation * rather than this source. If you don't know doxygen, it's like javadoc for C++. * If you don't want to install doxygen you can find a copy of the processed * documentation at * * http://optionparser.sourceforge.net/ * */ /** * @file * * @brief This is the only file required to use The Lean Mean C++ Option Parser. * Just \#include it and you're set. * * The Lean Mean C++ Option Parser handles the program's command line arguments * (argc, argv). * It supports the short and long option formats of getopt(), getopt_long() * and getopt_long_only() but has a more convenient interface. * The following features set it apart from other option parsers: * * @par Highlights: *
    *
  • It is a header-only library. Just \#include "optionparser.h" and you're set. *
  • It is freestanding. There are no dependencies whatsoever, not even the * C or C++ standard library. *
  • It has a usage message formatter that supports column alignment and * line wrapping. This aids localization because it adapts to * translated strings that are shorter or longer (even if they contain * Asian wide characters). *
  • Unlike getopt() and derivatives it doesn't force you to loop through * options sequentially. Instead you can access options directly like this: *
      *
    • Test for presence of a switch in the argument vector: * @code if ( options[QUIET] ) ... @endcode *
    • Evaluate --enable-foo/--disable-foo pair where the last one used wins: * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode *
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): * @code int verbosity = options[VERBOSE].count(); @endcode *
    • Iterate over all --file=<fname> arguments: * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) * fname = opt->arg; ... @endcode *
    • If you really want to, you can still process all arguments in order: * @code * for (int i = 0; i < p.optionsCount(); ++i) { * Option& opt = buffer[i]; * switch(opt.index()) { * case HELP: ... * case VERBOSE: ... * case FILE: fname = opt.arg; ... * case UNKNOWN: ... * @endcode *
    *
@n * Despite these features the code size remains tiny. * It is smaller than uClibc's GNU getopt() and just a * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n * (This does not include the usage formatter, of course. But you don't have to use that.) * * @par Download: * Tarball with examples and test programs: * optionparser-1.4.tar.gz @n * Just the header (this is all you really need): * optionparser.h * * @par Changelog: * Version 1.4: Fixed 2 printUsage() bugs that messed up output with small COLUMNS values @n * Version 1.3: Compatible with Microsoft Visual C++. @n * Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction * of short option characters into a special buffer. @n * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached * rather than separate. This is what GNU getopt() does and how POSIX recommends * utilities should interpret their arguments.@n * Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that * options and non-options can be mixed. See * @ref option::Parser::parse() "Parser::parse()". * * @par Feedback: * Send questions, bug reports, feature requests etc. to: optionparser-feedback (a) lists.sourceforge.net * @htmlonly @endhtmlonly * * * @par Example program: * (Note: @c option::* identifiers are links that take you to their documentation.) * @code * #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ! * #include * #include "optionparser.h" * * enum optionIndex { UNKNOWN, HELP, PLUS }; * const option::Descriptor usage[] = * { * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" * "Options:" }, * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" * " example --unknown -- --this_is_no_option\n" * " example -unk --plus -ppp file1 file2\n" }, * {0,0,0,0,0,0} * }; * * int main(int argc, char* argv[]) * { * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present * option::Stats stats(usage, argc, argv); * option::Option options[stats.options_max], buffer[stats.buffer_max]; * option::Parser parse(usage, argc, argv, options, buffer); * * if (parse.error()) * return 1; * * if (options[HELP] || argc == 0) { * option::printUsage(std::cout, usage); * return 0; * } * * std::cout << "--plus count: " << * options[PLUS].count() << "\n"; * * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) * std::cout << "Unknown option: " << opt->name << "\n"; * * for (int i = 0; i < parse.nonOptionsCount(); ++i) * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; * } * @endcode * * @par Option syntax: * @li The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports * GNU-style getopt_long() long options as well as Perl-style single-minus * long options (getopt_long_only()). * @li short options have the format @c -X where @c X is any character that fits in a char. * @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY. * @li a short option may take an argument either separate (-X foo) or * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by * registering @c X as a long option (in addition to being a short option) and * enabling single-minus long options. * @li an argument-taking short option may be grouped if it is the last in the group, e.g. * @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option). * @li a lone minus character @c '-' is not treated as an option. It is customarily used where * a file name is expected to refer to stdin or stdout. * @li long options have the format @c --option-name. * @li the option-name of a long option can be anything and include any characters. * Even @c = characters will work, but don't do that. * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous. * You can set a minimum length for abbreviations. * @li [optional] long options may begin with a single minus. The double minus form is always * accepted, too. * @li a long option may take an argument either separate ( --option arg ) or * attached ( --option=arg ). In the attached form the equals sign is mandatory. * @li an empty string can be passed as an attached long option argument: --option-name= . * Note the distinction between an empty string as argument and no argument at all. * @li an empty string is permitted as separate argument to both long and short options. * @li Arguments to both short and long options may start with a @c '-' character. E.g. * -X-X , -X -X or --long-X=-X . If @c -X * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases. * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must * be attached. * @li the special option @c -- (i.e. without a name) terminates the list of * options. Everything that follows is a non-option argument, even if it starts with * a @c '-' character. The @c -- itself will not appear in the parse results. * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to * a preceding argument-taking option, will terminate the option list and is the * first non-option argument. All following command line arguments are treated as * non-option arguments, even if they start with @c '-' . @n * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n * You can enable the GNU behaviour by passing @c true as first argument to * e.g. @ref option::Parser::parse() "Parser::parse()". * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but * aren't, are NOT treated as non-option arguments. They are treated as unknown options and * are collected into a list of unknown options for error reporting. @n * This means that in order to pass a first non-option * argument beginning with the minus character it is required to use the * @c -- special option, e.g. * @code * program -x -- --strange-filename * @endcode * In this example, @c --strange-filename is a non-option argument. If the @c -- * were omitted, it would be treated as an unknown option. @n * See @ref option::Descriptor::longopt for information on how to collect unknown options. * */ #ifndef OPTIONPARSER_H_ #define OPTIONPARSER_H_ /** @brief The namespace of The Lean Mean C++ Option Parser. */ namespace option { #ifdef _MSC_VER #include #pragma intrinsic(_BitScanReverse) struct MSC_Builtin_CLZ { static int builtin_clz(unsigned x) { unsigned long index; _BitScanReverse(&index, x); return 32-index; // int is always 32bit on Windows, even for target x64 } }; #define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x) #endif class Option; /** * @brief Possible results when checking if an argument is valid for a certain option. * * In the case that no argument is provided for an option that takes an * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent. */ enum ArgStatus { //! The option does not take an argument. ARG_NONE, //! The argument is acceptable for the option. ARG_OK, //! The argument is not acceptable but that's non-fatal because the option's argument is optional. ARG_IGNORE, //! The argument is not acceptable and that's fatal. ARG_ILLEGAL }; /** * @brief Signature of functions that check if an argument is valid for a certain type of option. * * Every Option has such a function assigned in its Descriptor. * @code * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... }; * @endcode * * A CheckArg function has the following signature: * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode * * It is used to check if a potential argument would be acceptable for the option. * It will even be called if there is no argument. In that case @c option.arg will be @c NULL. * * If @c msg is @c true and the function determines that an argument is not acceptable and * that this is a fatal error, it should output a message to the user before * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you * will get duplicate messages). * * See @ref ArgStatus for the meaning of the return values. * * While you can provide your own functions, * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice: * * @li @c Arg::None @copybrief Arg::None * @li @c Arg::Optional @copybrief Arg::Optional * */ typedef ArgStatus (*CheckArg)(const Option& option, bool msg); /** * @brief Describes an option, its help text (usage) and how it should be parsed. * * The main input when constructing an option::Parser is an array of Descriptors. * @par Example: * @code * enum OptionIndex {CREATE, ...}; * enum OptionType {DISABLE, ENABLE, OTHER}; * * const option::Descriptor usage[] = { * { CREATE, // index * OTHER, // type * "c", // shortopt * "create", // longopt * Arg::None, // check_arg * "--create Tells the program to create something." // help * } * , ... * }; * @endcode */ struct Descriptor { /** * @brief Index of this option's linked list in the array filled in by the parser. * * Command line options whose Descriptors have the same index will end up in the same * linked list in the order in which they appear on the command line. If you have * multiple long option aliases that refer to the same option, give their descriptors * the same @c index. * * If you have options that mean exactly opposite things * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same * @c index, but distinguish them through different values for @ref type. * That way they end up in the same list and you can just take the last element of the * list and use its type. This way you get the usual behaviour where switches later * on the command line override earlier ones without having to code it manually. * * @par Tip: * Use an enum rather than plain ints for better readability, as shown in the example * at Descriptor. */ const unsigned index; /** * @brief Used to distinguish between options with the same @ref index. * See @ref index for details. * * It is recommended that you use an enum rather than a plain int to make your * code more readable. */ const int type; /** * @brief Each char in this string will be accepted as a short option character. * * The string must not include the minus character @c '-' or you'll get undefined * behaviour. * * If this Descriptor should not have short option characters, use the empty * string "". NULL is not permitted here! * * See @ref longopt for more information. */ const char* const shortopt; /** * @brief The long option name (without the leading @c -- ). * * If this Descriptor should not have a long option name, use the empty * string "". NULL is not permitted here! * * While @ref shortopt allows multiple short option characters, each * Descriptor can have only a single long option name. If you have multiple * long option names referring to the same option use separate Descriptors * that have the same @ref index and @ref type. You may repeat * short option characters in such an alias Descriptor but there's no need to. * * @par Dummy Descriptors: * You can use dummy Descriptors with an * empty string for both @ref shortopt and @ref longopt to add text to * the usage that is not related to a specific option. See @ref help. * The first dummy Descriptor will be used for unknown options (see below). * * @par Unknown Option Descriptor: * The first dummy Descriptor in the list of Descriptors, * whose @ref shortopt and @ref longopt are both the empty string, will be used * as the Descriptor for unknown options. An unknown option is a string in * the argument vector that is not a lone minus @c '-' but starts with a minus * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n * Note that the dummy descriptor's @ref check_arg function @e will be called and * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL * the parsing will be aborted with Parser::error()==true. @n * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's * @ref index @e will be used to pick the linked list into which * to put the unknown option. @n * If there is no dummy descriptor, unknown options will be dropped silently. * */ const char* const longopt; /** * @brief For each option that matches @ref shortopt or @ref longopt this function * will be called to check a potential argument to the option. * * This function will be called even if there is no potential argument. In that case * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty * string. * * See @ref CheckArg for more information. */ const CheckArg check_arg; /** * @brief The usage text associated with the options in this Descriptor. * * You can use option::printUsage() to format your usage message based on * the @c help texts. You can use dummy Descriptors where * @ref shortopt and @ref longopt are both the empty string to add text to * the usage that is not related to a specific option. * * See option::printUsage() for special formatting characters you can use in * @c help to get a column layout. * * @attention * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8" * prefix to make sure string literals are properly encoded. */ const char* help; }; /** * @brief A parsed option from the command line together with its argument if it has one. * * The Parser chains all parsed options with the same Descriptor::index together * to form a linked list. This allows you to easily implement all of the common ways * of handling repeated options and enable/disable pairs. * * @li Test for presence of a switch in the argument vector: * @code if ( options[QUIET] ) ... @endcode * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins: * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): * @code int verbosity = options[VERBOSE].count(); @endcode * @li Iterate over all --file=<fname> arguments: * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) * fname = opt->arg; ... @endcode */ class Option { Option* next_; Option* prev_; public: /** * @brief Pointer to this Option's Descriptor. * * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used * for unknown options. * * @attention * @c desc==NULL signals that this Option is unused. This is the default state of * elements in the result array. You don't need to test @c desc explicitly. You * can simply write something like this: * @code * if (options[CREATE]) * { * ... * } * @endcode * This works because of operator const Option*() . */ const Descriptor* desc; /** * @brief The name of the option as used on the command line. * * The main purpose of this string is to be presented to the user in messages. * * In the case of a long option, this is the actual @c argv pointer, i.e. the first * character is a '-'. In the case of a short option this points to the option * character within the @c argv string. * * Note that in the case of a short option group or an attached option argument, this * string will contain additional characters following the actual name. Use @ref namelen * to filter out the actual option name only. * */ const char* name; /** * @brief Pointer to this Option's argument (if any). * * NULL if this option has no argument. Do not confuse this with the empty string which * is a valid argument. */ const char* arg; /** * @brief The length of the option @ref name. * * Because @ref name points into the actual @c argv string, the option name may be * followed by more characters (e.g. other short options in the same short option group). * This value is the number of bytes (not characters!) that are part of the actual name. * * For a short option, this length is always 1. For a long option this length is always * at least 2 if single minus long options are permitted and at least 3 if they are disabled. * * @note * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this * length is incorrect, because this case will be misinterpreted as a long option and the * name will therefore extend to the string's 0-terminator or a following '=" character * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you * really need to distinguish the case of a long and a short option, compare @ref name to * the @c argv pointers. A long option's @c name is always identical to one of them, * whereas a short option's is never. */ int namelen; /** * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option * is invalid (unused). * * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided * you arrange your types properly) switch on type() without testing validity first. * @code * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 }; * enum OptionIndex { FOO }; * const Descriptor usage[] = { * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, * { 0, 0, 0, 0, 0, 0 } }; * ... * switch(options[FOO].last()->type()) // no validity check required! * { * case ENABLED: ... * case DISABLED: ... // UNUSED==DISABLED ! * } * @endcode */ int type() const { return desc == 0 ? 0 : desc->type; } /** * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option * is invalid (unused). */ int index() const { return desc == 0 ? -1 : (int)desc->index; } /** * @brief Returns the number of times this Option (or others with the same Descriptor::index) * occurs in the argument vector. * * This corresponds to the number of elements in the linked list this Option is part of. * It doesn't matter on which element you call count(). The return value is always the same. * * Use this to implement cumulative options, such as -v, -vv, -vvv for * different verbosity levels. * * Returns 0 when called for an unused/invalid option. */ int count() { int c = (desc == 0 ? 0 : 1); Option* p = first(); while (!p->isLast()) { ++c; p = p->next_; }; return c; } /** * @brief Returns true iff this is the first element of the linked list. * * The first element in the linked list is the first option on the command line * that has the respective Descriptor::index value. * * Returns true for an unused/invalid option. */ bool isFirst() const { return isTagged(prev_); } /** * @brief Returns true iff this is the last element of the linked list. * * The last element in the linked list is the last option on the command line * that has the respective Descriptor::index value. * * Returns true for an unused/invalid option. */ bool isLast() const { return isTagged(next_); } /** * @brief Returns a pointer to the first element of the linked list. * * Use this when you want the first occurrence of an option on the command line to * take precedence. Note that this is not the way most programs handle options. * You should probably be using last() instead. * * @note * This method may be called on an unused/invalid option and will return a pointer to the * option itself. */ Option* first() { Option* p = this; while (!p->isFirst()) p = p->prev_; return p; } /** * @brief Returns a pointer to the last element of the linked list. * * Use this when you want the last occurrence of an option on the command line to * take precedence. This is the most common way of handling conflicting options. * * @note * This method may be called on an unused/invalid option and will return a pointer to the * option itself. * * @par Tip: * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you * can assign them the same Descriptor::index to get them into the same list. Distinguish them by * Descriptor::type and all you have to do is check last()->type() to get * the state listed last on the command line. */ Option* last() { return first()->prevwrap(); } /** * @brief Returns a pointer to the previous element of the linked list or NULL if * called on first(). * * If called on first() this method returns NULL. Otherwise it will return the * option with the same Descriptor::index that precedes this option on the command * line. */ Option* prev() { return isFirst() ? 0 : prev_; } /** * @brief Returns a pointer to the previous element of the linked list with wrap-around from * first() to last(). * * If called on first() this method returns last(). Otherwise it will return the * option with the same Descriptor::index that precedes this option on the command * line. */ Option* prevwrap() { return untag(prev_); } /** * @brief Returns a pointer to the next element of the linked list or NULL if called * on last(). * * If called on last() this method returns NULL. Otherwise it will return the * option with the same Descriptor::index that follows this option on the command * line. */ Option* next() { return isLast() ? 0 : next_; } /** * @brief Returns a pointer to the next element of the linked list with wrap-around from * last() to first(). * * If called on last() this method returns first(). Otherwise it will return the * option with the same Descriptor::index that follows this option on the command * line. */ Option* nextwrap() { return untag(next_); } /** * @brief Makes @c new_last the new last() by chaining it into the list after last(). * * It doesn't matter which element you call append() on. The new element will always * be appended to last(). * * @attention * @c new_last must not yet be part of a list, or that list will become corrupted, because * this method does not unchain @c new_last from an existing list. */ void append(Option* new_last) { Option* p = last(); Option* f = first(); p->next_ = new_last; new_last->prev_ = p; new_last->next_ = tag(f); f->prev_ = tag(new_last); } /** * @brief Casts from Option to const Option* but only if this Option is valid. * * If this Option is valid (i.e. @c desc!=NULL), returns this. * Otherwise returns NULL. This allows testing an Option directly * in an if-clause to see if it is used: * @code * if (options[CREATE]) * { * ... * } * @endcode * It also allows you to write loops like this: * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) * fname = opt->arg; ... @endcode */ operator const Option*() const { return desc ? this : 0; } /** * @brief Casts from Option to Option* but only if this Option is valid. * * If this Option is valid (i.e. @c desc!=NULL), returns this. * Otherwise returns NULL. This allows testing an Option directly * in an if-clause to see if it is used: * @code * if (options[CREATE]) * { * ... * } * @endcode * It also allows you to write loops like this: * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) * fname = opt->arg; ... @endcode */ operator Option*() { return desc ? this : 0; } /** * @brief Creates a new Option that is a one-element linked list and has NULL * @ref desc, @ref name, @ref arg and @ref namelen. */ Option() : desc(0), name(0), arg(0), namelen(0) { prev_ = tag(this); next_ = tag(this); } /** * @brief Creates a new Option that is a one-element linked list and has the given * values for @ref desc, @ref name and @ref arg. * * If @c name_ points at a character other than '-' it will be assumed to refer to a * short option and @ref namelen will be set to 1. Otherwise the length will extend to * the first '=' character or the string's 0-terminator. */ Option(const Descriptor* desc_, const char* name_, const char* arg_) { init(desc_, name_, arg_); } /** * @brief Makes @c *this a copy of @c orig except for the linked list pointers. * * After this operation @c *this will be a one-element linked list. */ void operator=(const Option& orig) { init(orig.desc, orig.name, orig.arg); } /** * @brief Makes @c *this a copy of @c orig except for the linked list pointers. * * After this operation @c *this will be a one-element linked list. */ Option(const Option& orig) { init(orig.desc, orig.name, orig.arg); } private: /** * @internal * @brief Sets the fields of this Option to the given values (extracting @c name if necessary). * * If @c name_ points at a character other than '-' it will be assumed to refer to a * short option and @ref namelen will be set to 1. Otherwise the length will extend to * the first '=' character or the string's 0-terminator. */ void init(const Descriptor* desc_, const char* name_, const char* arg_) { desc = desc_; name = name_; arg = arg_; prev_ = tag(this); next_ = tag(this); namelen = 0; if (name == 0) return; namelen = 1; if (name[0] != '-') return; while (name[namelen] != 0 && name[namelen] != '=') ++namelen; } static Option* tag(Option* ptr) { return (Option*) ((unsigned long long) ptr | 1); } static Option* untag(Option* ptr) { return (Option*) ((unsigned long long) ptr & ~1ull); } static bool isTagged(Option* ptr) { return ((unsigned long long) ptr & 1); } }; /** * @brief Functions for checking the validity of option arguments. * * @copydetails CheckArg * * The following example code * can serve as starting place for writing your own more complex CheckArg functions: * @code * struct Arg: public option::Arg * { * static void printError(const char* msg1, const option::Option& opt, const char* msg2) * { * fprintf(stderr, "ERROR: %s", msg1); * fwrite(opt.name, opt.namelen, 1, stderr); * fprintf(stderr, "%s", msg2); * } * * static option::ArgStatus Unknown(const option::Option& option, bool msg) * { * if (msg) printError("Unknown option '", option, "'\n"); * return option::ARG_ILLEGAL; * } * * static option::ArgStatus Required(const option::Option& option, bool msg) * { * if (option.arg != 0) * return option::ARG_OK; * * if (msg) printError("Option '", option, "' requires an argument\n"); * return option::ARG_ILLEGAL; * } * * static option::ArgStatus NonEmpty(const option::Option& option, bool msg) * { * if (option.arg != 0 && option.arg[0] != 0) * return option::ARG_OK; * * if (msg) printError("Option '", option, "' requires a non-empty argument\n"); * return option::ARG_ILLEGAL; * } * * static option::ArgStatus Numeric(const option::Option& option, bool msg) * { * char* endptr = 0; * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; * if (endptr != option.arg && *endptr == 0) * return option::ARG_OK; * * if (msg) printError("Option '", option, "' requires a numeric argument\n"); * return option::ARG_ILLEGAL; * } * }; * @endcode */ struct Arg { //! @brief For options that don't take an argument: Returns ARG_NONE. static ArgStatus None(const Option&, bool) { return ARG_NONE; } //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise. static ArgStatus Optional(const Option& option, bool) { if (option.arg && option.name[option.namelen] != 0) return ARG_OK; else return ARG_IGNORE; } }; /** * @brief Determines the minimum lengths of the buffer and options arrays used for Parser. * * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated. * If you don't want to use fixed size arrays (which may turn out too small, causing * command line arguments to be dropped), you can use Stats to determine the correct sizes. * Stats work cumulative. You can first pass in your default options and then the real * options and afterwards the counts will reflect the union. */ struct Stats { /** * @brief Number of elements needed for a @c buffer[] array to be used for * @ref Parser::parse() "parsing" the same argument vectors that were fed * into this Stats object. * * @note * This number is always 1 greater than the actual number needed, to give * you a sentinel element. */ unsigned buffer_max; /** * @brief Number of elements needed for an @c options[] array to be used for * @ref Parser::parse() "parsing" the same argument vectors that were fed * into this Stats object. * * @note * @li This number is always 1 greater than the actual number needed, to give * you a sentinel element. * @li This number depends only on the @c usage, not the argument vectors, because * the @c options array needs exactly one slot for each possible Descriptor::index. */ unsigned options_max; /** * @brief Creates a Stats object with counts set to 1 (for the sentinel element). */ Stats() : buffer_max(1), options_max(1) // 1 more than necessary as sentinel { } /** * @brief Creates a new Stats object and immediately updates it for the * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, * if you just want to update @ref options_max. * * @note * The calls to Stats methods must match the later calls to Parser methods. * See Parser::parse() for the meaning of the arguments. */ Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) : buffer_max(1), options_max(1) // 1 more than necessary as sentinel { add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt); } //! @brief Stats(...) with non-const argv. Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) : buffer_max(1), options_max(1) // 1 more than necessary as sentinel { add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); } //! @brief POSIX Stats(...) (gnu==false). Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) : buffer_max(1), options_max(1) // 1 more than necessary as sentinel { add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); } //! @brief POSIX Stats(...) (gnu==false) with non-const argv. Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) : buffer_max(1), options_max(1) // 1 more than necessary as sentinel { add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); } /** * @brief Updates this Stats object for the * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, * if you just want to update @ref options_max. * * @note * The calls to Stats methods must match the later calls to Parser methods. * See Parser::parse() for the meaning of the arguments. */ void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false); //! @brief add() with non-const argv. void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) { add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); } //! @brief POSIX add() (gnu==false). void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) { add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); } //! @brief POSIX add() (gnu==false) with non-const argv. void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // bool single_minus_longopt = false) { add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); } private: class CountOptionsAction; }; /** * @brief Checks argument vectors for validity and parses them into data * structures that are easier to work with. * * @par Example: * @code * int main(int argc, char* argv[]) * { * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present * option::Stats stats(usage, argc, argv); * option::Option options[stats.options_max], buffer[stats.buffer_max]; * option::Parser parse(usage, argc, argv, options, buffer); * * if (parse.error()) * return 1; * * if (options[HELP]) * ... * @endcode */ class Parser { int op_count; //!< @internal @brief see optionsCount() int nonop_count; //!< @internal @brief see nonOptionsCount() const char** nonop_args; //!< @internal @brief see nonOptions() bool err; //!< @internal @brief see error() public: /** * @brief Creates a new Parser. */ Parser() : op_count(0), nonop_count(0), nonop_args(0), err(false) { } /** * @brief Creates a new Parser and immediately parses the given argument vector. * @copydetails parse() */ Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : op_count(0), nonop_count(0), nonop_args(0), err(false) { parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } //! @brief Parser(...) with non-const argv. Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : op_count(0), nonop_count(0), nonop_args(0), err(false) { parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } //! @brief POSIX Parser(...) (gnu==false). Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : op_count(0), nonop_count(0), nonop_args(0), err(false) { parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } //! @brief POSIX Parser(...) (gnu==false) with non-const argv. Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : op_count(0), nonop_count(0), nonop_args(0), err(false) { parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } /** * @brief Parses the given argument vector. * * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will * reorder arguments so that all non-options are at the end. This is the default behaviour * of GNU getopt() but is not conforming to POSIX. @n * Note, that once the argument vector has been reordered, the @c gnu flag will have * no further effect on this argument vector. So it is enough to pass @c gnu==true when * creating Stats. * @param usage Array of Descriptor objects that describe the options to support. The last entry * of this array must have 0 in all fields. * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number * will be determined automatically. In that case the @c argv list must end with a NULL * pointer. * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv * list must be NULL to mark the end. * @param options Each entry is the first element of a linked list of Options. Each new option * that is parsed will be appended to the list specified by that Option's * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid), * it will be replaced rather than appended to. @n * The minimum length of this array is the greatest Descriptor::index value that * occurs in @c usage @e PLUS ONE. * @param buffer Each argument that is successfully parsed (including unknown arguments, if they * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this * array. parse() scans the array for the first invalid entry and begins writing at that * index. You can pass @c bufmax to limit the number of options stored. * @param min_abbr_len Passing a value min_abbr_len > 0 enables abbreviated long * options. The parser will match a prefix of a long option as if it was * the full long option (e.g. @c --foob=10 will be interpreted as if it was * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters * (not counting the @c -- ) and is unambiguous. * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true * because the ambiguity check does not consider short options and abbreviated * single minus long options will take precedence over short options. * @param single_minus_longopt Passing @c true for this option allows long options to begin with * a single minus. The double minus form will still be recognized. Note that * single minus long options take precedence over short options and short option * groups. E.g. @c -file would be interpreted as @c --file and not as * -f -i -l -e (assuming a long option named @c "file" exists). * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is * @c bufmax-1. If there are more options, they will be processed (in particular * their CheckArg will be called) but not stored. @n * If you used Stats::buffer_max to dimension this array, you can pass * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is * "large enough". * @attention * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it * is not possible for the same object to be in both arrays. For those options that are found in * both @c buffer[] and @c options[] the respective objects are independent copies. And only the * objects in @c options[] are properly linked via Option::next() and Option::prev(). * You can iterate over @c buffer[] to * process all options in the order they appear in the argument vector, but if you want access to * the other Options with the same Descriptor::index, then you @e must access the linked list via * @c options[]. You can get the linked list in options from a buffer object via something like * @c options[buffer[i].index()]. */ void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1); //! @brief parse() with non-const argv. void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) { parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } //! @brief POSIX parse() (gnu==false). void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) { parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } //! @brief POSIX parse() (gnu==false) with non-const argv. void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) { parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); } /** * @brief Returns the number of valid Option objects in @c buffer[]. * * @note * @li The returned value always reflects the number of Options in the buffer[] array used for * the most recent call to parse(). * @li The count (and the buffer[]) includes unknown options if they are collected * (see Descriptor::longopt). */ int optionsCount() { return op_count; } /** * @brief Returns the number of non-option arguments that remained at the end of the * most recent parse() that actually encountered non-option arguments. * * @note * A parse() that does not encounter non-option arguments will leave this value * as well as nonOptions() undisturbed. This means you can feed the Parser a * default argument vector that contains non-option arguments (e.g. a default filename). * Then you feed it the actual arguments from the user. If the user has supplied at * least one non-option argument, all of the non-option arguments from the default * disappear and are replaced by the user's non-option arguments. However, if the * user does not supply any non-option arguments the defaults will still be in * effect. */ int nonOptionsCount() { return nonop_count; } /** * @brief Returns a pointer to an array of non-option arguments (only valid * if nonOptionsCount() >0 ). * * @note * @li parse() does not copy arguments, so this pointer points into the actual argument * vector as passed to parse(). * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls * that actually encounter non-option arguments. A parse() call that encounters only * options, will not change nonOptions(). */ const char** nonOptions() { return nonop_args; } /** * @brief Returns nonOptions()[i] (@e without checking if i is in range!). */ const char* nonOption(int i) { return nonOptions()[i]; } /** * @brief Returns @c true if an unrecoverable error occurred while parsing options. * * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an * unrecoverable error that aborts the parse. Unknown options are only an error if * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected. * In that case if you want to exit the program if either an illegal argument * or an unknown option has been passed, use code like this * * @code * if (parser.error() || options[UNKNOWN]) * exit(1); * @endcode * */ bool error() { return err; } private: friend struct Stats; class StoreOptionAction; struct Action; /** * @internal * @brief This is the core function that does all the parsing. * @retval false iff an unrecoverable error occurred. */ static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, bool single_minus_longopt, bool print_errors, int min_abbr_len); /** * @internal * @brief Returns true iff @c st1 is a prefix of @c st2 and * in case @c st2 is longer than @c st1, then * the first additional character is '='. * * @par Examples: * @code * streq("foo", "foo=bar") == true * streq("foo", "foobar") == false * streq("foo", "foo") == true * streq("foo=bar", "foo") == false * @endcode */ static bool streq(const char* st1, const char* st2) { while (*st1 != 0) if (*st1++ != *st2++) return false; return (*st2 == 0 || *st2 == '='); } /** * @internal * @brief Like streq() but handles abbreviations. * * Returns true iff @c st1 and @c st2 have a common * prefix with the following properties: * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller). * @li (if min <= 0) its length is the same as that of @c st1 * @li within @c st2 the character following the common prefix is either '=' or end-of-string. * * Examples: * @code * streqabbr("foo", "foo=bar",) == true * streqabbr("foo", "fo=bar" , 2) == true * streqabbr("foo", "fo" , 2) == true * streqabbr("foo", "fo" , 0) == false * streqabbr("foo", "f=bar" , 2) == false * streqabbr("foo", "f" , 2) == false * streqabbr("fo" , "foo=bar",) == false * streqabbr("foo", "foobar" ,) == false * streqabbr("foo", "fobar" ,) == false * streqabbr("foo", "foo" ,) == true * @endcode */ static bool streqabbr(const char* st1, const char* st2, long long min) { const char* st1start = st1; while (*st1 != 0 && (*st1 == *st2)) { ++st1; ++st2; } return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '='); } /** * @internal * @brief Returns true iff character @c ch is contained in the string @c st. * * Returns @c true for @c ch==0 . */ static bool instr(char ch, const char* st) { while (*st != 0 && *st != ch) ++st; return *st == ch; } /** * @internal * @brief Rotates args[-count],...,args[-1],args[0] to become * args[0],args[-count],...,args[-1]. */ static void shift(const char** args, int count) { for (int i = 0; i > -count; --i) { const char* temp = args[i]; args[i] = args[i - 1]; args[i - 1] = temp; } } }; /** * @internal * @brief Interface for actions Parser::workhorse() should perform for each Option it * parses. */ struct Parser::Action { /** * @brief Called by Parser::workhorse() for each Option that has been successfully * parsed (including unknown * options if they have a Descriptor whose Descriptor::check_arg does not return * @ref ARG_ILLEGAL. * * Returns @c false iff a fatal error has occured and the parse should be aborted. */ virtual bool perform(Option&) { return true; } /** * @brief Called by Parser::workhorse() after finishing the parse. * @param numargs the number of non-option arguments remaining * @param args pointer to the first remaining non-option argument (if numargs > 0). * * @return * @c false iff a fatal error has occurred. */ virtual bool finished(int numargs, const char** args) { (void) numargs; (void) args; return true; } }; /** * @internal * @brief An Action to pass to Parser::workhorse() that will increment a counter for * each parsed Option. */ class Stats::CountOptionsAction: public Parser::Action { unsigned* buffer_max; public: /** * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each * parsed Option. */ CountOptionsAction(unsigned* buffer_max_) : buffer_max(buffer_max_) { } bool perform(Option&) { if (*buffer_max == 0x7fffffff) return false; // overflow protection: don't accept number of options that doesn't fit signed int ++*buffer_max; return true; } }; /** * @internal * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in * appropriate arrays (see Parser::parse()). */ class Parser::StoreOptionAction: public Parser::Action { Parser& parser; Option* options; Option* buffer; int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough". public: /** * @brief Creates a new StoreOption action. * @param parser_ the parser whose op_count should be updated. * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index] * @param buffer_ each Option is appended to this array as long as there's a free slot. * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough". */ StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) : parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_) { // find first empty slot in buffer (if any) int bufidx = 0; while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx]) ++bufidx; // set parser's optionCount parser.op_count = bufidx; } bool perform(Option& option) { if (bufmax < 0 || parser.op_count < bufmax) { if (parser.op_count == 0x7fffffff) return false; // overflow protection: don't accept number of options that doesn't fit signed int buffer[parser.op_count] = option; int idx = buffer[parser.op_count].desc->index; if (options[idx]) options[idx].append(buffer[parser.op_count]); else options[idx] = buffer[parser.op_count]; ++parser.op_count; } return true; // NOTE: an option that is discarded because of a full buffer is not fatal } bool finished(int numargs, const char** args) { // only overwrite non-option argument list if there's at least 1 // new non-option argument. Otherwise we keep the old list. This // makes it easy to use default non-option arguments. if (numargs > 0) { parser.nonop_count = numargs; parser.nonop_args = args; } return true; } }; inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax) { StoreOptionAction action(*this, options, buffer, bufmax); err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len); } inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len, bool single_minus_longopt) { // determine size of options array. This is the greatest index used in the usage + 1 int i = 0; while (usage[i].shortopt != 0) { if (usage[i].index + 1 >= options_max) options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel ++i; } CountOptionsAction action(&buffer_max); Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len); } inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, bool single_minus_longopt, bool print_errors, int min_abbr_len) { // protect against NULL pointer if (args == 0) numargs = 0; int nonops = 0; while (numargs != 0 && *args != 0) { const char* param = *args; // param can be --long-option, -srto or non-option argument // in POSIX mode the first non-option argument terminates the option list // a lone minus character is a non-option argument if (param[0] != '-' || param[1] == 0) { if (gnu) { ++nonops; ++args; if (numargs > 0) --numargs; continue; } else break; } // -- terminates the option list. The -- itself is skipped. if (param[1] == '-' && param[2] == 0) { shift(args, nonops); ++args; if (numargs > 0) --numargs; break; } bool handle_short_options; const char* longopt_name; if (param[1] == '-') // if --long-option { handle_short_options = false; longopt_name = param + 2; } else { handle_short_options = true; longopt_name = param + 1; //for testing a potential -long-option } bool try_single_minus_longopt = single_minus_longopt; bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid? do // loop over short options in group, for long options the body is executed only once { int idx; const char* optarg; /******************** long option **********************/ if (handle_short_options == false || try_single_minus_longopt) { idx = 0; while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name)) ++idx; if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options { int i1 = 0; while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len)) ++i1; if (usage[i1].longopt != 0) { // now test if the match is unambiguous by checking for another match int i2 = i1 + 1; while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len)) ++i2; if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx idx = i1; } } // if we found something, disable handle_short_options (only relevant if single_minus_longopt) if (usage[idx].longopt != 0) handle_short_options = false; try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group optarg = longopt_name; while (*optarg != 0 && *optarg != '=') ++optarg; if (*optarg == '=') // attached argument ++optarg; else // possibly detached argument optarg = (have_more_args ? args[1] : 0); } /************************ short option ***********************************/ if (handle_short_options) { if (*++param == 0) // point at the 1st/next option character break; // end of short option group idx = 0; while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt)) ++idx; if (param[1] == 0) // if the potential argument is separate optarg = (have_more_args ? args[1] : 0); else // if the potential argument is attached optarg = param + 1; } const Descriptor* descriptor = &usage[idx]; if (descriptor->shortopt == 0) /************** unknown option ********************/ { // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options idx = 0; while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0)) ++idx; descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]); } if (descriptor != 0) { Option option(descriptor, param, optarg); switch (descriptor->check_arg(option, print_errors)) { case ARG_ILLEGAL: return false; // fatal case ARG_OK: // skip one element of the argument vector, if it's a separated argument if (optarg != 0 && have_more_args && optarg == args[1]) { shift(args, nonops); if (numargs > 0) --numargs; ++args; } // No further short options are possible after an argument handle_short_options = false; break; case ARG_IGNORE: case ARG_NONE: option.arg = 0; break; } if (!action.perform(option)) return false; } } while (handle_short_options); shift(args, nonops); ++args; if (numargs > 0) --numargs; } // while if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number numargs = 0; // of arguments, but as a service to the user we fix this if we spot it. if (numargs < 0) // if we don't know the number of remaining non-option arguments { // we need to count them numargs = 0; while (args[numargs] != 0) ++numargs; } return action.finished(numargs + nonops, args - nonops); } /** * @internal * @brief The implementation of option::printUsage(). */ struct PrintUsageImplementation { /** * @internal * @brief Interface for Functors that write (part of) a string somewhere. */ struct IStringWriter { /** * @brief Writes the given number of chars beginning at the given pointer somewhere. */ virtual void operator()(const char*, int) { } }; /** * @internal * @brief Encapsulates a function with signature func(string, size) where * string can be initialized with a const char* and size with an int. */ template struct FunctionWriter: public IStringWriter { Function* write; virtual void operator()(const char* str, int size) { (*write)(str, size); } FunctionWriter(Function* w) : write(w) { } }; /** * @internal * @brief Encapsulates a reference to an object with a write(string, size) * method like that of @c std::ostream. */ template struct OStreamWriter: public IStringWriter { OStream& ostream; virtual void operator()(const char* str, int size) { ostream.write(str, size); } OStreamWriter(OStream& o) : ostream(o) { } }; /** * @internal * @brief Like OStreamWriter but encapsulates a @c const reference, which is * typically a temporary object of a user class. */ template struct TemporaryWriter: public IStringWriter { const Temporary& userstream; virtual void operator()(const char* str, int size) { userstream.write(str, size); } TemporaryWriter(const Temporary& u) : userstream(u) { } }; /** * @internal * @brief Encapsulates a function with the signature func(fd, string, size) (the * signature of the @c write() system call) * where fd can be initialized from an int, string from a const char* and size from an int. */ template struct SyscallWriter: public IStringWriter { Syscall* write; int fd; virtual void operator()(const char* str, int size) { (*write)(fd, str, size); } SyscallWriter(Syscall* w, int f) : write(w), fd(f) { } }; /** * @internal * @brief Encapsulates a function with the same signature as @c std::fwrite(). */ template struct StreamWriter: public IStringWriter { Function* fwrite; Stream* stream; virtual void operator()(const char* str, int size) { (*fwrite)(str, size, 1, stream); } StreamWriter(Function* w, Stream* s) : fwrite(w), stream(s) { } }; /** * @internal * @brief Sets i1 = max(i1, i2) */ static void upmax(int& i1, int i2) { i1 = (i1 >= i2 ? i1 : i2); } /** * @internal * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x * and sets @c x=want_x . * If x > want_x , a line break is output before indenting. * * @param write Spaces and possibly a line break are written via this functor to get * the desired indentation @c want_x . * @param[in,out] x the current indentation. Set to @c want_x by this method. * @param want_x the desired indentation. */ static void indent(IStringWriter& write, int& x, int want_x) { int indent = want_x - x; if (indent < 0) { write("\n", 1); indent = want_x; } if (indent > 0) { char space = ' '; for (int i = 0; i < indent; ++i) write(&space, 1); x = want_x; } } /** * @brief Returns true if ch is the unicode code point of a wide character. * * @note * The following character ranges are treated as wide * @code * 1100..115F * 2329..232A (just 2 characters!) * 2E80..A4C6 except for 303F * A960..A97C * AC00..D7FB * F900..FAFF * FE10..FE6B * FF01..FF60 * FFE0..FFE6 * 1B000...... * @endcode */ static bool isWideChar(unsigned ch) { if (ch == 0x303F) return false; return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6) || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF) || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6) || (0x1B000 <= ch)); } /** * @internal * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and * iterates over these components. * * The top-level organizational unit is the @e table. * A table begins at a Descriptor with @c help!=NULL and extends up to * a Descriptor with @c help==NULL. * * A table consists of @e rows. Due to line-wrapping and explicit breaks * a row may take multiple lines on screen. Rows within the table are separated * by \\n. They never cross Descriptor boundaries. This means a row ends either * at \\n or the 0 at the end of the help string. * * A row consists of columns/cells. Columns/cells within a row are separated by \\t. * Line breaks within a cell are marked by \\v. * * Rows in the same table need not have the same number of columns/cells. The * extreme case are interjections, which are rows that contain neither \\t nor \\v. * These are NOT treated specially by LinePartIterator, but they are treated * specially by printUsage(). * * LinePartIterator iterates through the usage at 3 levels: table, row and part. * Tables and rows are as described above. A @e part is a line within a cell. * LinePartIterator iterates through 1st parts of all cells, then through the 2nd * parts of all cells (if any),... @n * Example: The row "1 \v 3 \t 2 \v 4" has 2 cells/columns and 4 parts. * The parts will be returned in the order 1, 2, 3, 4. * * It is possible that some cells have fewer parts than others. In this case * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator * always returns the same number of parts for each column. Note that this is different * from the way rows and columns are handled. LinePartIterator does @e not guarantee that * the same number of columns will be returned for each row. * */ class LinePartIterator { const Descriptor* tablestart; //!< The 1st descriptor of the current table. const Descriptor* rowdesc; //!< The Descriptor that contains the current row. const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help. const char* ptr; //!< Ptr to current part within the current row. int col; //!< Index of current column. int len; //!< Length of the current part (that ptr points at) in BYTES int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account). int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs. int line_in_block; //!< Line index within the current cell of the current part. int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration. bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell. /** * @brief Determines the byte and character lengths of the part at @ref ptr and * stores them in @ref len and @ref screenlen respectively. */ void update_length() { screenlen = 0; for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) { ++screenlen; unsigned ch = (unsigned char) ptr[len]; if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte { // int __builtin_clz (unsigned int x) // Returns the number of leading 0-bits in x, starting at the most significant bit unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); ch = ch & mask; // mask out length bits, we don't verify their correctness while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte { ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code ++len; } // ch is the decoded unicode code point if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case ++screenlen; } } } public: //! @brief Creates an iterator for @c usage. LinePartIterator(const Descriptor usage[]) : tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0), target_line_in_block(0), hit_target_line(true) { } /** * @brief Moves iteration to the next table (if any). Has to be called once on a new * LinePartIterator to move to the 1st table. * @retval false if moving to next table failed because no further table exists. */ bool nextTable() { // If this is NOT the first time nextTable() is called after the constructor, // then skip to the next table break (i.e. a Descriptor with help == 0) if (rowdesc != 0) { while (tablestart->help != 0 && tablestart->shortopt != 0) ++tablestart; } // Find the next table after the break (if any) while (tablestart->help == 0 && tablestart->shortopt != 0) ++tablestart; restartTable(); return rowstart != 0; } /** * @brief Reset iteration to the beginning of the current table. */ void restartTable() { rowdesc = tablestart; rowstart = tablestart->help; ptr = 0; } /** * @brief Moves iteration to the next row (if any). Has to be called once after each call to * @ref nextTable() to move to the 1st row of the table. * @retval false if moving to next row failed because no further row exists. */ bool nextRow() { if (ptr == 0) { restartRow(); return rowstart != 0; } while (*ptr != 0 && *ptr != '\n') ++ptr; if (*ptr == 0) { if ((rowdesc + 1)->help == 0) // table break return false; ++rowdesc; rowstart = rowdesc->help; } else // if (*ptr == '\n') { rowstart = ptr + 1; } restartRow(); return true; } /** * @brief Reset iteration to the beginning of the current row. */ void restartRow() { ptr = rowstart; col = -1; len = 0; screenlen = 0; max_line_in_block = 0; line_in_block = 0; target_line_in_block = 0; hit_target_line = true; } /** * @brief Moves iteration to the next part (if any). Has to be called once after each call to * @ref nextRow() to move to the 1st part of the row. * @retval false if moving to next part failed because no further part exists. * * See @ref LinePartIterator for details about the iteration. */ bool next() { if (ptr == 0) return false; if (col == -1) { col = 0; update_length(); return true; } ptr += len; while (true) { switch (*ptr) { case '\v': upmax(max_line_in_block, ++line_in_block); ++ptr; break; case '\t': if (!hit_target_line) // if previous column did not have the targetline { // then "insert" a 0-length part update_length(); hit_target_line = true; return true; } hit_target_line = false; line_in_block = 0; ++col; ++ptr; break; case 0: case '\n': if (!hit_target_line) // if previous column did not have the targetline { // then "insert" a 0-length part update_length(); hit_target_line = true; return true; } if (++target_line_in_block > max_line_in_block) { update_length(); return false; } hit_target_line = false; line_in_block = 0; col = 0; ptr = rowstart; continue; default: ++ptr; continue; } // switch if (line_in_block == target_line_in_block) { update_length(); hit_target_line = true; return true; } } // while } /** * @brief Returns the index (counting from 0) of the column in which * the part pointed to by @ref data() is located. */ int column() { return col; } /** * @brief Returns the index (counting from 0) of the line within the current column * this part belongs to. */ int line() { return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line } /** * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters). */ int length() { return len; } /** * @brief Returns the width in screen columns of the part pointed to by @ref data(). * Takes multi-byte UTF-8 sequences and wide characters into account. */ int screenLength() { return screenlen; } /** * @brief Returns the current part of the iteration. */ const char* data() { return ptr; } }; /** * @internal * @brief Takes input and line wraps it, writing out one line at a time so that * it can be interleaved with output from other columns. * * The LineWrapper is used to handle the last column of each table as well as interjections. * The LineWrapper is called once for each line of output. If the data given to it fits * into the designated width of the last column it is simply written out. If there * is too much data, an appropriate split point is located and only the data up to this * split point is written out. The rest of the data is queued for the next line. * That way the last column can be line wrapped and interleaved with data from * other columns. The following example makes this clearer: * @code * Column 1,1 Column 2,1 This is a long text * Column 1,2 Column 2,2 that does not fit into * a single line. * @endcode * * The difficulty in producing this output is that the whole string * "This is a long text that does not fit into a single line" is the * 1st and only part of column 3. In order to produce the above * output the string must be output piecemeal, interleaved with * the data from the other columns. */ class LineWrapper { static const int bufmask = 15; //!< Must be a power of 2 minus 1. /** * @brief Ring buffer for length component of pair (data, length). */ int lenbuf[bufmask + 1]; /** * @brief Ring buffer for data component of pair (data, length). */ const char* datbuf[bufmask + 1]; /** * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer * assumes that the indentation has already been written when @ref process() * is called, so this value is only used when a buffer flush requires writing * additional lines of output. */ int x; /** * @brief The width of the column to line wrap. */ int width; int head; //!< @brief index for next write int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read) /** * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to * free up space. The contract of process() says that only 1 line is output. So * this variable is used to track whether something has output a line. It is * reset at the beginning of process() and checked at the end to decide if * output has already occurred or is still needed. */ bool wrote_something; bool buf_empty() { return ((tail + 1) & bufmask) == head; } bool buf_full() { return tail == head; } void buf_store(const char* data, int len) { lenbuf[head] = len; datbuf[head] = data; head = (head + 1) & bufmask; } //! @brief Call BEFORE reading ...buf[tail]. void buf_next() { tail = (tail + 1) & bufmask; } /** * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line * is flushed out of the buffer into @c write. */ void output(IStringWriter& write, const char* data, int len) { if (buf_full()) write_one_line(write); buf_store(data, len); } /** * @brief Writes a single line of output from the buffer to @c write. */ void write_one_line(IStringWriter& write) { if (wrote_something) // if we already wrote something, we need to start a new line { write("\n", 1); int _ = 0; indent(write, _, x); } if (!buf_empty()) { buf_next(); write(datbuf[tail], lenbuf[tail]); } wrote_something = true; } public: /** * @brief Writes out all remaining data from the LineWrapper using @c write. * Unlike @ref process() this method indents all lines including the first and * will output a \\n at the end (but only if something has been written). */ void flush(IStringWriter& write) { if (buf_empty()) return; int _ = 0; indent(write, _, x); wrote_something = false; while (!buf_empty()) write_one_line(write); write("\n", 1); } /** * @brief Process, wrap and output the next piece of data. * * process() will output at least one line of output. This is not necessarily * the @c data passed in. It may be data queued from a prior call to process(). * If the internal buffer is full, more than 1 line will be output. * * process() assumes that the a proper amount of indentation has already been * output. It won't write any further indentation before the 1st line. If * more than 1 line is written due to buffer constraints, the lines following * the first will be indented by this method, though. * * No \\n is written by this method after the last line that is written. * * @param write where to write the data. * @param data the new chunk of data to write. * @param len the length of the chunk of data to write. */ void process(IStringWriter& write, const char* data, int len) { wrote_something = false; while (len > 0) { if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes) { output(write, data, len); len = 0; } else // if (len > width) it's possible (but not guaranteed) that utf8len > width { int utf8width = 0; int maxi = 0; while (maxi < len && utf8width < width) { int charbytes = 1; unsigned ch = (unsigned char) data[maxi]; if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte { // int __builtin_clz (unsigned int x) // Returns the number of leading 0-bits in x, starting at the most significant bit unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); ch = ch & mask; // mask out length bits, we don't verify their correctness while ((maxi + charbytes < len) && // (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte { ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code ++charbytes; } // ch is the decoded unicode code point if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case { if (utf8width + 2 > width) break; ++utf8width; } } ++utf8width; maxi += charbytes; } // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits // onto the 1st line. If maxi == len, all characters fit on the line. if (maxi == len) { output(write, data, len); len = 0; } else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line { int i; for (i = maxi; i >= 0; --i) if (data[i] == ' ') break; if (i >= 0) { output(write, data, i); data += i + 1; len -= i + 1; } else // did not find a space to split at => split before data[maxi] { // data[maxi] is always the beginning of a character, never a continuation byte output(write, data, maxi); data += maxi; len -= maxi; } } } } if (!wrote_something) // if we didn't already write something to make space in the buffer write_one_line(write); // write at most one line of actual output } /** * @brief Constructs a LineWrapper that wraps its output to fit into * screen columns @c x1 (incl.) to @c x2 (excl.). * * @c x1 gives the indentation LineWrapper uses if it needs to indent. */ LineWrapper(int x1, int x2) : x(x1), width(x2 - x1), head(0), tail(bufmask) { if (width < 2) // because of wide characters we need at least width 2 or the code breaks width = 2; } }; /** * @internal * @brief This is the implementation that is shared between all printUsage() templates. * Because all printUsage() templates share this implementation, there is no template bloat. */ static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, // int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { if (width < 1) // protect against nonsense values width = 80; if (width > 10000) // protect against overflow in the following computation width = 10000; int last_column_min_width = ((width * last_column_min_percent) + 50) / 100; int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100; if (last_column_own_line_max_width == 0) last_column_own_line_max_width = 1; LinePartIterator part(usage); while (part.nextTable()) { /***************** Determine column widths *******************************/ const int maxcolumns = 8; // 8 columns are enough for everyone int col_width[maxcolumns]; int lastcolumn; int leftwidth; int overlong_column_threshold = 10000; do { lastcolumn = 0; for (int i = 0; i < maxcolumns; ++i) col_width[i] = 0; part.restartTable(); while (part.nextRow()) { while (part.next()) { if (part.column() < maxcolumns) { upmax(lastcolumn, part.column()); if (part.screenLength() < overlong_column_threshold) // We don't let rows that don't use table separators (\t or \v) influence // the width of column 0. This allows the user to interject section headers // or explanatory paragraphs that do not participate in the table layout. if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' || part.data()[part.length()] == '\v') upmax(col_width[part.column()], part.screenLength()); } } } /* * If the last column doesn't fit on the same * line as the other columns, we can fix that by starting it on its own line. * However we can't do this for any of the columns 0..lastcolumn-1. * If their sum exceeds the maximum width we try to fix this by iteratively * ignoring the widest line parts in the width determination until * we arrive at a series of column widths that fit into one line. * The result is a layout where everything is nicely formatted * except for a few overlong fragments. * */ leftwidth = 0; overlong_column_threshold = 0; for (int i = 0; i < lastcolumn; ++i) { leftwidth += col_width[i]; upmax(overlong_column_threshold, col_width[i]); } } while (leftwidth > width); /**************** Determine tab stops and last column handling **********************/ int tabstop[maxcolumns]; tabstop[0] = 0; for (int i = 1; i < maxcolumns; ++i) tabstop[i] = tabstop[i - 1] + col_width[i - 1]; int rightwidth = width - tabstop[lastcolumn]; bool print_last_column_on_own_line = false; if (rightwidth < last_column_min_width && // if we don't have the minimum requested width for the last column ( col_width[lastcolumn] == 0 || // and all last columns are > overlong_column_threshold rightwidth < col_width[lastcolumn] // or there is at least one last column that requires more than the space available ) ) { print_last_column_on_own_line = true; rightwidth = last_column_own_line_max_width; } // If lastcolumn == 0 we must disable print_last_column_on_own_line because // otherwise 2 copies of the last (and only) column would be output. // Actually this is just defensive programming. It is currently not // possible that lastcolumn==0 and print_last_column_on_own_line==true // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 => // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes // a bullshit value >100 for last_column_min_percent) => the above if condition // is false => print_last_column_on_own_line==false if (lastcolumn == 0) print_last_column_on_own_line = false; LineWrapper lastColumnLineWrapper(width - rightwidth, width); LineWrapper interjectionLineWrapper(0, width); part.restartTable(); /***************** Print out all rows of the table *************************************/ while (part.nextRow()) { int x = -1; while (part.next()) { if (part.column() > lastcolumn) continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1) if (part.column() == 0) { if (x >= 0) write("\n", 1); x = 0; } indent(write, x, tabstop[part.column()]); if ((part.column() < lastcolumn) && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' || part.data()[part.length()] == '\v')) { write(part.data(), part.length()); x += part.screenLength(); } else // either part.column() == lastcolumn or we are in the special case of // an interjection that doesn't contain \v or \t { // NOTE: This code block is not necessarily executed for // each line, because some rows may have fewer columns. LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper; if (!print_last_column_on_own_line || part.column() != lastcolumn) lineWrapper.process(write, part.data(), part.length()); } } // while if (print_last_column_on_own_line) { part.restartRow(); while (part.next()) { if (part.column() == lastcolumn) { write("\n", 1); int _ = 0; indent(write, _, width - rightwidth); lastColumnLineWrapper.process(write, part.data(), part.length()); } } } write("\n", 1); lastColumnLineWrapper.flush(write); interjectionLineWrapper.flush(write); } } } } ; /** * @brief Outputs a nicely formatted usage string with support for multi-column formatting * and line-wrapping. * * printUsage() takes the @c help texts of a Descriptor[] array and formats them into * a usage message, wrapping lines to achieve the desired output width. * * Table formatting: * * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables * are used to align elements in the output. * * @code * // Without a table. The explanatory texts are not aligned. * -c, --create |Creates something. * -k, --kill |Destroys something. * * // With table formatting. The explanatory texts are aligned. * -c, --create |Creates something. * -k, --kill |Destroys something. * @endcode * * Table formatting removes the need to pad help texts manually with spaces to achieve * alignment. To create a table, simply insert \\t (tab) characters to separate the cells * within a row. * * @code * const option::Descriptor usage[] = { * {..., "-c, --create \tCreates something." }, * {..., "-k, --kill \tDestroys something." }, ... * @endcode * * Note that you must include the minimum amount of space desired between cells yourself. * Table formatting will insert further spaces as needed to achieve alignment. * * You can insert line breaks within cells by using \\v (vertical tab). * * @code * const option::Descriptor usage[] = { * {..., "-c,\v--create \tCreates\vsomething." }, * {..., "-k,\v--kill \tDestroys\vsomething." }, ... * * // results in * * -c, Creates * --create something. * -k, Destroys * --kill something. * @endcode * * You can mix lines that do not use \\t or \\v with those that do. The plain * lines will not mess up the table layout. Alignment of the table columns will * be maintained even across these interjections. * * @code * const option::Descriptor usage[] = { * {..., "-c, --create \tCreates something." }, * {..., "----------------------------------" }, * {..., "-k, --kill \tDestroys something." }, ... * * // results in * * -c, --create Creates something. * ---------------------------------- * -k, --kill Destroys something. * @endcode * * You can have multiple tables within the same usage whose columns are * aligned independently. Simply insert a dummy Descriptor with @c help==0. * * @code * const option::Descriptor usage[] = { * {..., "Long options:" }, * {..., "--very-long-option \tDoes something long." }, * {..., "--ultra-super-mega-long-option \tTakes forever to complete." }, * {..., 0 }, // ---------- table break ----------- * {..., "Short options:" }, * {..., "-s \tShort." }, * {..., "-q \tQuick." }, ... * * // results in * * Long options: * --very-long-option Does something long. * --ultra-super-mega-long-option Takes forever to complete. * Short options: * -s Short. * -q Quick. * * // Without the table break it would be * * Long options: * --very-long-option Does something long. * --ultra-super-mega-long-option Takes forever to complete. * Short options: * -s Short. * -q Quick. * @endcode * * Output methods: * * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for * output in the first argument(s) to printUsage(). Because printUsage() is implemented as * a set of template functions, you have great flexibility in your choice of output * method. The following example demonstrates typical uses. Anything that's similar enough * will work. * * @code * #include // write() * #include // cout * #include // ostringstream * #include // fwrite() * using namespace std; * * void my_write(const char* str, int size) { * fwrite(str, size, 1, stdout); * } * * struct MyWriter { * void write(const char* buf, size_t size) const { * fwrite(str, size, 1, stdout); * } * }; * * struct MyWriteFunctor { * void operator()(const char* buf, size_t size) { * fwrite(str, size, 1, stdout); * } * }; * ... * printUsage(my_write, usage); // custom write function * printUsage(MyWriter(), usage); // temporary of a custom class * MyWriter writer; * printUsage(writer, usage); // custom class object * MyWriteFunctor wfunctor; * printUsage(&wfunctor, usage); // custom functor * printUsage(write, 1, usage); // write() to file descriptor 1 * printUsage(cout, usage); // an ostream& * printUsage(fwrite, stdout, usage); // fwrite() to stdout * ostringstream sstr; * printUsage(sstr, usage); // an ostringstream& * * @endcode * * @par Notes: * @li the @c write() method of a class that is to be passed as a temporary * as @c MyWriter() is in the example, must be a @c const method, because * temporary objects are passed as const reference. This only applies to * temporary objects that are created and destroyed in the same statement. * If you create an object like @c writer in the example, this restriction * does not apply. * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer. * This differs from the way functors are passed to e.g. the STL algorithms. * @li All printUsage() templates are tiny wrappers around a shared non-template implementation. * So there's no penalty for using different versions in the same program. * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded * output. If your system uses a different charset, you must do your own conversion. You * may also need to change the font of the console to see non-ASCII characters properly. * This is particularly true for Windows. * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments) * into the usage. printUsage() has no protection against malicious UTF-8 sequences. * * @param prn The output method to use. See the examples above. * @param usage the Descriptor[] array whose @c help texts will be formatted. * @param width the maximum number of characters per output line. Note that this number is * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will * count multi-byte UTF-8 sequences properly. Asian wide characters are counted * as 2 characters. * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available * for the last column (which typically contains the textual explanation of an option). * If less space is available, the last column will be printed on its own line, indented * according to @c last_column_own_line_max_percent. * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to * less than @c last_column_min_percent of the width being available, then only * @c last_column_own_line_max_percent of the extra line(s) will be used for the * last column's text. This ensures an indentation. See example below. * * @code * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10) * --3456789 1234567890 * 1234567890 * * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) * // last_column_own_line_max_percent=75 * --3456789 * 123456789012345 * 67890 * * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) * // last_column_own_line_max_percent=33 (i.e. max. 5) * --3456789 * 12345 * 67890 * 12345 * 67890 * @endcode */ template void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { PrintUsageImplementation::OStreamWriter write(prn); PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); } template void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { PrintUsageImplementation::FunctionWriter write(prn); PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); } template void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { PrintUsageImplementation::TemporaryWriter write(prn); PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); } template void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { PrintUsageImplementation::SyscallWriter write(prn, fd); PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); } template void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) { PrintUsageImplementation::StreamWriter write(prn, stream); PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); } } // namespace option #endif /* OPTIONPARSER_H_ */davix-0.8.0/test/functional/test_mv.cpp0000644000000000000000000000250014121063315016627 0ustar rootroot #include #include #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); RequestParams p; DavixError* tmp_err=NULL; //std::auto_ptr c( new Context()); Context c; DavPosix pos(&c); if(argc > 2){ configure_grid_env(argv[2], p); } std::string url = argv[1]; std::string a = generate_random_uri(Davix::Uri(url), "test_move").getString(); std::string b = a+"cake"; int ret = 0; // create dir if( (ret = pos.mkdir(&p, a.c_str(), 0777, &tmp_err) <0)) { std::cerr << "mkdir error "<< tmp_err->getErrMsg() << std::endl; return -1; } // rename file if( (ret = pos.rename(&p, a.c_str(), b.c_str(), &tmp_err) <0)) { std::cerr << "mv error "<< tmp_err->getErrMsg() << std::endl; return -1; } // remove dir DavFile f(c, b); f.deletion(&p, &tmp_err); return 0; } davix-0.8.0/test/functional/test_valid_write_read_fd.cpp0000644000000000000000000000444014121063315022167 0ustar rootroot #include #include #include #include #include #include "davix_test_lib.h" using namespace Davix; int main(int argc, char** argv){ if( argc < 2){ std::cout << "Usage : " << std::endl; std::cout <<"\t" << argv[0] << " [url]" << std::endl; std::cout <<"\t" << argv[0] << " [url] [CERTIFICATE_PATH] " << std::endl; return 0; } srand(time(NULL)); davix_set_log_level(DAVIX_LOG_ALL); DavixError* tmp_err=NULL; RequestParams p; dav_ssize_t ret; int fd, fd_out, fd_out2; Context c; const ssize_t size_content = rand()/1000000+2; std::cout << " size content" << size_content << std::endl; char url[2048]; generate_random_uri(argv[1], "test_davix_",url, 2048); char buffer_mktemp[2048]; if(argc > 2){ configure_grid_env(argv[2], p); } File f(c, std::string(url)); fd = open("/dev/urandom", O_RDONLY); DAV_ASSERT_TRUE( fd > 0, "Impossible to open random generator"); TRY_DAVIX{ f.put(&p, fd, size_content); }CATCH_DAVIX(&tmp_err); DAV_ASSERT_TRUE( tmp_err == NULL, tmp_err->getErrMsg()); strcpy(buffer_mktemp, "dav-fd-test-XXXXXXXXX"); fd_out = mkstemp(buffer_mktemp); DAV_ASSERT_TRUE( fd_out > 0, "Impossible to output file"); ret = f.getToFd(&p, fd_out, &tmp_err); DAV_ASSERT_TRUE( tmp_err == NULL, tmp_err->getErrMsg()); DAV_ASSERT_TRUE( ret == size_content, "Invalid size" << ret); dav_ssize_t half_size = size_content/2; strcpy(buffer_mktemp, "dav-fd-test-partial-XXXXXXXXX"); fd_out2 = mkstemp(buffer_mktemp); DAV_ASSERT_TRUE( fd_out2 > 0, "Impossible to output file"); ret = f.getToFd(&p, fd_out2, half_size, &tmp_err); DAV_ASSERT_TRUE( tmp_err == NULL, tmp_err->getErrMsg()); DAV_ASSERT_TRUE( ret == half_size, "Invalid size" << ret); lseek(fd_out, 0, 0); lseek(fd_out2, 0, 0); char buffer1[half_size], buffer2[half_size]; DAV_ASSERT_TRUE( read(fd_out, buffer1, half_size) == half_size, "Invalid read back from local file 1"); DAV_ASSERT_TRUE( read(fd_out2, buffer2, half_size) == half_size, "Invalid read back from local file 2"); DAV_ASSERT_TRUE( memcmp(buffer1, buffer2, half_size) ==0, "Corrupted content"); close(fd); return 0; } davix-0.8.0/test/pywebdav/0000755000000000000000000000000014121063315014124 5ustar rootrootdavix-0.8.0/test/pywebdav/__init__.py0000644000000000000000000000000014121063315016223 0ustar rootrootdavix-0.8.0/test/pywebdav/lib/0000755000000000000000000000000014121063315014672 5ustar rootrootdavix-0.8.0/test/pywebdav/lib/errors.py0000644000000000000000000000272114121063315016562 0ustar rootroot""" Exceptions for the DAVserver implementation """ class DAV_Error(Exception): """ in general we can have the following arguments: 1. the error code 2. the error result element, e.g. a element """ def __init__(self,*args): if len(args)==1: self.args=(args[0],"") else: self.args=args class DAV_Secret(DAV_Error): """ the user is not allowed to know anything about it returning this for a property value means to exclude it from the response xml element. """ def __init__(self): DAV_Error.__init__(self,0) pass class DAV_NotFound(DAV_Error): """ a requested property was not found for a resource """ def __init__(self,*args): if len(args): DAV_Error.__init__(self,404,args[0]) else: DAV_Error.__init__(self,404) pass class DAV_Forbidden(DAV_Error): """ a method on a resource is not allowed """ def __init__(self,*args): if len(args): DAV_Error.__init__(self,403,args[0]) else: DAV_Error.__init__(self,403) pass class DAV_Requested_Range_Not_Satisfiable(DAV_Error): """ none of the range-specifier values overlap the current extent of the selected resource """ def __init__(self, *args): if len(args): DAV_Error.__init__(self, 416, args[0]) else: DAV_Error.__init__(self, 416) pass davix-0.8.0/test/pywebdav/lib/WebDAVServer.py0000644000000000000000000005652314121063315017516 0ustar rootroot"""DAV HTTP Server This module builds on BaseHTTPServer and implements DAV commands """ import AuthServer import urlparse import urllib import logging from propfind import PROPFIND from report import REPORT from delete import DELETE from davcopy import COPY from davmove import MOVE from utils import rfc1123_date, IfParser, tokenFinder from string import atoi from errors import DAV_Error, DAV_NotFound from constants import DAV_VERSION_1, DAV_VERSION_2 from locks import LockManager import gzip import StringIO from pywebdav.lib import VERSION from xml.parsers.expat import ExpatError log = logging.getLogger(__name__) BUFFER_SIZE = 128 * 1000 # 128 Ko class DAVRequestHandler(AuthServer.AuthRequestHandler, LockManager): """Simple DAV request handler with - GET - HEAD - PUT - OPTIONS - PROPFIND - PROPPATCH - MKCOL - REPORT experimental - LOCK - UNLOCK It uses the resource/collection classes for serving and storing content. """ server_version = "DAV/" + VERSION encode_threshold = 1400 # common MTU def send_body(self, DATA, code=None, msg=None, desc=None, ctype='application/octet-stream', headers={}): """ send a body in one part """ log.debug("Use send_body method") self.send_response(code, message=msg) self.send_header("Connection", "close") self.send_header("Accept-Ranges", "bytes") self.send_header('Date', rfc1123_date()) self._send_dav_version() for a, v in headers.items(): self.send_header(a, v) if DATA: if 'gzip' in self.headers.get('Accept-Encoding', '').split(',') \ and len(DATA) > self.encode_threshold: buffer = StringIO.StringIO() output = gzip.GzipFile(mode='wb', fileobj=buffer) if isinstance(DATA, str) or isinstance(DATA, unicode): output.write(DATA) else: for buf in DATA: output.write(buf) output.close() buffer.seek(0) DATA = buffer.getvalue() self.send_header('Content-Encoding', 'gzip') self.send_header('Content-Length', len(DATA)) self.send_header('Content-Type', ctype) else: self.send_header('Content-Length', 0) self.end_headers() if DATA: if isinstance(DATA, str) or isinstance(DATA, unicode): log.debug("Don't use iterator") self.wfile.write(DATA) else: if self._config.DAV.getboolean('http_response_use_iterator'): # Use iterator to reduce using memory log.debug("Use iterator") for buf in DATA: self.wfile.write(buf) self.wfile.flush() else: # Don't use iterator, it's a compatibility option log.debug("Don't use iterator") self.wfile.write(DATA.read()) def send_body_chunks_if_http11(self, DATA, code, msg=None, desc=None, ctype='text/xml; encoding="utf-8"', headers={}): if (self.request_version == 'HTTP/1.0' or not self._config.DAV.getboolean('chunked_http_response')): self.send_body(DATA, code, msg, desc, ctype, headers) else: self.send_body_chunks(DATA, code, msg, desc, ctype, headers) def send_body_chunks(self, DATA, code, msg=None, desc=None, ctype='text/xml"', headers={}): """ send a body in chunks """ self.responses[207] = (msg, desc) self.send_response(code, message=msg) self.send_header("Content-type", ctype) self.send_header("Transfer-Encoding", "chunked") self.send_header('Date', rfc1123_date()) self._send_dav_version() for a, v in headers.items(): self.send_header(a, v) if DATA: if ('gzip' in self.headers.get('Accept-Encoding', '').split(',') and len(DATA) > self.encode_threshold): buffer = StringIO.StringIO() output = gzip.GzipFile(mode='wb', fileobj=buffer) if isinstance(DATA, str): output.write(DATA) else: for buf in DATA: output.write(buf) output.close() buffer.seek(0) DATA = buffer.getvalue() self.send_header('Content-Encoding', 'gzip') self.send_header('Content-Length', len(DATA)) self.send_header('Content-Type', ctype) else: self.send_header('Content-Length', 0) self.end_headers() if DATA: if isinstance(DATA, str) or isinstance(DATA, unicode): self.wfile.write(hex(len(DATA))[2:] + "\r\n") self.wfile.write(DATA) self.wfile.write("\r\n") self.wfile.write("0\r\n") self.wfile.write("\r\n") else: if self._config.DAV.getboolean('http_response_use_iterator'): # Use iterator to reduce using memory for buf in DATA: self.wfile.write(hex(len(buf))[2:] + "\r\n") self.wfile.write(buf) self.wfile.write("\r\n") self.wfile.write("0\r\n") self.wfile.write("\r\n") else: # Don't use iterator, it's a compatibility option self.wfile.write(hex(len(DATA))[2:] + "\r\n") self.wfile.write(DATA.read()) self.wfile.write("\r\n") self.wfile.write("0\r\n") self.wfile.write("\r\n") def _send_dav_version(self): if self._config.DAV.getboolean('lockemulation'): self.send_header('DAV', DAV_VERSION_2['version']) else: self.send_header('DAV', DAV_VERSION_1['version']) ### HTTP METHODS called by the server def do_OPTIONS(self): """return the list of capabilities """ self.send_response(200) self.send_header("Content-Length", 0) if self._config.DAV.getboolean('lockemulation'): self.send_header('Allow', DAV_VERSION_2['options']) else: self.send_header('Allow', DAV_VERSION_1['options']) self._send_dav_version() self.send_header('MS-Author-Via', 'DAV') # this is for M$ self.end_headers() def _HEAD_GET(self, with_body=False): """ Returns headers and body for given resource """ dc = self.IFACE_CLASS uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) headers = {} # get the last modified date (RFC 1123!) try: headers['Last-Modified'] = dc.get_prop( uri, "DAV:", "getlastmodified") except DAV_NotFound: pass # get the ETag if any try: headers['Etag'] = dc.get_prop(uri, "DAV:", "getetag") except DAV_NotFound: pass # get the content type try: content_type = dc.get_prop(uri, "DAV:", "getcontenttype") except DAV_NotFound: content_type = "application/octet-stream" range = None status_code = 200 if 'Range' in self.headers: p = self.headers['Range'].find("bytes=") if p != -1: range = self.headers['Range'][p + 6:].split("-") status_code = 206 # get the data try: data = dc.get_data(uri, range) except DAV_Error, (ec, dd): self.send_status(ec) return ec # send the data if with_body is False: data = None if isinstance(data, str) or isinstance(data, unicode): self.send_body(data, status_code, None, None, content_type, headers) else: headers['Keep-Alive'] = 'timeout=15, max=86' headers['Connection'] = 'Keep-Alive' self.send_body_chunks_if_http11(data, status_code, None, None, content_type, headers) return status_code def do_HEAD(self): """ Send a HEAD response: Retrieves resource information w/o body """ return self._HEAD_GET(with_body=False) def do_GET(self): """Serve a GET request.""" log.debug(self.headers) try: status_code = self._HEAD_GET(with_body=True) self.log_request(status_code) return status_code except IOError, e: if e.errno == 32: self.log_request(206) else: raise def do_TRACE(self): """ This will always fail because we can not reproduce HTTP requests. We send back a 405=Method Not Allowed. """ self.send_body(None, 405, 'Method Not Allowed', 'Method Not Allowed') def do_POST(self): """ Replacement for GET response. Not implemented here. """ self.send_body(None, 405, 'Method Not Allowed', 'Method Not Allowed') def do_PROPPATCH(self): # currently unsupported return self.send_status(423) def do_PROPFIND(self): """ Retrieve properties on defined resource. """ dc = self.IFACE_CLASS # read the body containing the xml request # iff there is no body then this is an ALLPROP request body = None if 'Content-Length' in self.headers: l = self.headers['Content-Length'] body = self.rfile.read(atoi(l)) uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) try: pf = PROPFIND(uri, dc, self.headers.get('Depth', 'infinity'), body) except ExpatError: # parse error return self.send_status(400) try: DATA = '%s\n' % pf.createResponse() except DAV_Error, (ec, dd): return self.send_status(ec) # work around MSIE DAV bug for creation and modified date # taken from Resource.py @ Zope webdav if (self.headers.get('User-Agent') == 'Microsoft Data Access Internet Publishing Provider DAV 1.1'): DATA = DATA.replace('', '') DATA = DATA.replace('', '') self.send_body_chunks_if_http11(DATA, 207, 'Multi-Status', 'Multiple responses') def do_REPORT(self): """ Query properties on defined resource. """ dc = self.IFACE_CLASS # read the body containing the xml request # iff there is no body then this is an ALLPROP request body = None if 'Content-Length' in self.headers: l = self.headers['Content-Length'] body = self.rfile.read(atoi(l)) uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) rp = REPORT(uri, dc, self.headers.get('Depth', '0'), body) try: DATA = '%s\n' % rp.createResponse() except DAV_Error, (ec, dd): return self.send_status(ec) self.send_body_chunks_if_http11(DATA, 207, 'Multi-Status', 'Multiple responses') def do_MKCOL(self): """ create a new collection """ # according to spec body must be empty body = None if 'Content-Length' in self.headers: l = self.headers['Content-Length'] body = self.rfile.read(atoi(l)) if body: return self.send_status(415) dc = self.IFACE_CLASS uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) try: dc.mkcol(uri) self.send_status(201) self.log_request(201) except DAV_Error, (ec, dd): self.log_request(ec) return self.send_status(ec) def do_DELETE(self): """ delete an resource """ dc = self.IFACE_CLASS uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) # hastags not allowed if uri.find('#') >= 0: return self.send_status(404) # locked resources are not allowed to delete if self._l_isLocked(uri): return self.send_body(None, 423, 'Locked', 'Locked') # Handle If-Match if 'If-Match' in self.headers: test = False etag = None try: etag = dc.get_prop(uri, "DAV:", "getetag") except: pass for match in self.headers['If-Match'].split(','): if match == '*': if dc.exists(uri): test = True break else: if match == etag: test = True break if not test: self.send_status(412) self.log_request(412) return # Handle If-None-Match if 'If-None-Match' in self.headers: test = True etag = None try: etag = dc.get_prop(uri, "DAV:", "getetag") except: pass for match in self.headers['If-None-Match'].split(','): if match == '*': if dc.exists(uri): test = False break else: if match == etag: test = False break if not test: self.send_status(412) self.log_request(412) return try: dl = DELETE(uri, dc) if dc.is_collection(uri): res = dl.delcol() if res: self.send_status(207, body=res) else: self.send_status(204) else: res = dl.delone() or 204 self.send_status(res) except DAV_NotFound: self.send_body(None, 404, 'Not Found', 'Not Found') def do_PUT(self): dc = self.IFACE_CLASS uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) log.debug("do_PUT: uri = %s" % uri) log.debug('do_PUT: headers = %s' % self.headers) # Handle If-Match if 'If-Match' in self.headers: log.debug("do_PUT: If-Match %s" % self.headers['If-Match']) test = False etag = None try: etag = dc.get_prop(uri, "DAV:", "getetag") except: pass log.debug("do_PUT: etag = %s" % etag) for match in self.headers['If-Match'].split(','): if match == '*': if dc.exists(uri): test = True break else: if match == etag: test = True break if not test: self.send_status(412) self.log_request(412) return # Handle If-None-Match if 'If-None-Match' in self.headers: log.debug("do_PUT: If-None-Match %s" % self.headers['If-None-Match']) test = True etag = None try: etag = dc.get_prop(uri, "DAV:", "getetag") except: pass log.debug("do_PUT: etag = %s" % etag) for match in self.headers['If-None-Match'].split(','): if match == '*': if dc.exists(uri): test = False break else: if match == etag: test = False break if not test: self.send_status(412) self.log_request(412) return # locked resources are not allowed to be overwritten ifheader = self.headers.get('If') if ( (self._l_isLocked(uri)) and (not ifheader) ): return self.send_body(None, 423, 'Locked', 'Locked') if ((self._l_isLocked(uri)) and (ifheader)): uri_token = self._l_getLockForUri(uri) taglist = IfParser(ifheader) found = False for tag in taglist: for listitem in tag.list: token = tokenFinder(listitem) if ( token and (self._l_hasLock(token)) and (self._l_getLock(token) == uri_token) ): found = True break if found: break if not found: res = self.send_body(None, 423, 'Locked', 'Locked') self.log_request(423) return res # Handle expect expect = self.headers.get('Expect', '') if (expect.lower() == '100-continue' and self.protocol_version >= 'HTTP/1.1' and self.request_version >= 'HTTP/1.1'): self.send_status(100) content_type = None if 'Content-Type' in self.headers: content_type = self.headers['Content-Type'] headers = {} headers['Location'] = uri try: etag = dc.get_prop(uri, "DAV:", "getetag") headers['ETag'] = etag except: pass expect = self.headers.get('transfer-encoding', '') if ( expect.lower() == 'chunked' and self.protocol_version >= 'HTTP/1.1' and self.request_version >= 'HTTP/1.1' ): self.send_body(None, 201, 'Created', '', headers=headers) dc.put(uri, self._readChunkedData(), content_type) else: # read the body body = None if 'Content-Length' in self.headers: l = self.headers['Content-Length'] log.debug("do_PUT: Content-Length = %s" % l) body = self._readNoChunkedData(atoi(l)) else: log.debug("do_PUT: Content-Length = empty") try: dc.put(uri, body, content_type) except DAV_Error, (ec, dd): return self.send_status(ec) self.send_body(None, 201, 'Created', '', headers=headers) self.log_request(201) def _readChunkedData(self): l = int(self.rfile.readline(), 16) while l > 0: buf = self.rfile.read(l) yield buf self.rfile.readline() l = int(self.rfile.readline(), 16) def _readNoChunkedData(self, content_length): if self._config.DAV.getboolean('http_request_use_iterator'): # Use iterator to reduce using memory return self.__readNoChunkedDataWithIterator(content_length) else: # Don't use iterator, it's a compatibility option return self.__readNoChunkedDataWithoutIterator(content_length) def __readNoChunkedDataWithIterator(self, content_length): while True: if content_length > BUFFER_SIZE: buf = self.rfile.read(BUFFER_SIZE) content_length -= BUFFER_SIZE yield buf else: buf = self.rfile.read(content_length) yield buf break def __readNoChunkedDataWithoutIterator(self, content_length): return self.rfile.read(content_length) def do_COPY(self): """ copy one resource to another """ try: self.copymove(COPY) except DAV_Error, (ec, dd): return self.send_status(ec) def do_MOVE(self): """ move one resource to another """ try: self.copymove(MOVE) except DAV_Error, (ec, dd): return self.send_status(ec) def copymove(self, CLASS): """ common method for copying or moving objects """ dc = self.IFACE_CLASS # get the source URI source_uri = urlparse.urljoin(self.get_baseuri(dc), self.path) source_uri = urllib.unquote(source_uri) # get the destination URI dest_uri = self.headers['Destination'] dest_uri = urllib.unquote(dest_uri) # check locks on source and dest if self._l_isLocked(source_uri) or self._l_isLocked(dest_uri): return self.send_body(None, 423, 'Locked', 'Locked') # Overwrite? overwrite = 1 result_code = 204 if 'Overwrite' in self.headers: if self.headers['Overwrite'] == "F": overwrite = None result_code = 201 # instanciate ACTION class cp = CLASS(dc, source_uri, dest_uri, overwrite) # Depth? d = "infinity" if 'Depth' in self.headers: d = self.headers['Depth'] if d != "0" and d != "infinity": self.send_status(400) return if d == "0": res = cp.single_action() self.send_status(res or 201) return # now it only can be "infinity" but we nevertheless check for a # collection if dc.is_collection(source_uri): try: res = cp.tree_action() except DAV_Error, (ec, dd): self.send_status(ec) return else: try: res = cp.single_action() except DAV_Error, (ec, dd): self.send_status(ec) return if res: self.send_body_chunks_if_http11(res, 207, self.responses[207][0], self.responses[207][1], ctype='text/xml; charset="utf-8"') else: self.send_status(result_code) def get_userinfo(self, user, pw): """ Dummy method which lets all users in """ return 1 def send_status(self, code=200, mediatype='text/xml; charset="utf-8"', msg=None, body=None): if not msg: msg = self.responses.get(code, ['', ''])[1] self.send_body(body, code, self.responses.get(code, [''])[0], msg, mediatype) def get_baseuri(self, dc): baseuri = dc.baseuri if 'Host' in self.headers: uparts = list(urlparse.urlparse(dc.baseuri)) uparts[1] = self.headers['Host'] baseuri = urlparse.urlunparse(uparts) return baseuri davix-0.8.0/test/pywebdav/lib/delete.py0000644000000000000000000000123714121063315016511 0ustar rootrootimport os import string import urllib from StringIO import StringIO from utils import gen_estring, quote_uri, make_xmlresponse from davcmd import deltree class DELETE: def __init__(self,uri,dataclass): self.__dataclass=dataclass self.__uri=uri def delcol(self): """ delete a collection """ dc=self.__dataclass result=dc.deltree(self.__uri) if not len(result.items()): return None # everything ok # create the result element return make_xmlresponse(result) def delone(self): """ delete a resource """ dc=self.__dataclass return dc.delone(self.__uri) davix-0.8.0/test/pywebdav/lib/iface.py0000644000000000000000000002057014121063315016317 0ustar rootroot""" basic interface class use this for subclassing when writing your own interface class. """ from xml.dom import minidom from locks import LockManager from errors import * import time from string import lower class dav_interface: """ interface class for implementing DAV servers """ ### defined properties (modify this but let the DAV stuff there!) ### the format is namespace: [list of properties] PROPS={"DAV:" : ('creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock'), "NS2" : ("p1","p2") } # here we define which methods handle which namespace # the first item is the namespace URI and the second one # the method prefix # e.g. for DAV:getcontenttype we call dav_getcontenttype() M_NS={"DAV:" : "_get_dav", "NS2" : "ns2" } def get_propnames(self,uri): """ return the property names allowed for the given URI In this method we simply return the above defined properties assuming that they are valid for any resource. You can override this in order to return a different set of property names for each resource. """ return self.PROPS def get_prop2(self,uri,ns,pname): """ return the value of a property """ if lower(ns)=="dav:": return self.get_dav(uri,pname) raise DAV_NotFound def get_prop(self,uri,ns,propname): """ return the value of a given property uri -- uri of the object to get the property of ns -- namespace of the property pname -- name of the property """ if self.M_NS.has_key(ns): prefix=self.M_NS[ns] else: raise DAV_NotFound mname=prefix+"_"+propname.replace('-', '_') try: m=getattr(self,mname) r=m(uri) return r except AttributeError: raise DAV_NotFound ### ### DATA methods (for GET and PUT) ### def get_data(self, uri, range=None): """ return the content of an object return data or raise an exception """ raise DAV_NotFound def put(self, uri, data, content_type=None): """ write an object to the repository return the location uri or raise an exception """ raise DAV_Forbidden ### ### LOCKing information ### def _get_dav_supportedlock(self, uri): txt = ('
\n' '\n' '\n' '
\n') xml = minidom.parseString(txt) return xml.firstChild.firstChild def _get_dav_lockdiscovery(self, uri): lcm = LockManager() if lcm._l_isLocked(uri): lock = lcm._l_getLockForUri(uri) txt = lock.asXML(discover=True, namespace='D') txtwithns = '
%s
' xml = minidom.parseString(txtwithns % txt) return xml.firstChild.firstChild return '' ### ### Methods for DAV properties ### def _get_dav_creationdate(self,uri): """ return the creationdate of a resource """ d=self.get_creationdate(uri) # format it return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(d)) def _get_dav_getlastmodified(self,uri): """ return the last modified date of a resource """ d=self.get_lastmodified(uri) # format it return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(d)) ### ### OVERRIDE THESE! ### def get_creationdate(self,uri): """ return the creationdate of the resource """ return time.time() def get_lastmodified(self,uri): """ return the last modification date of the resource """ return time.time() ### ### COPY MOVE DELETE ### ### methods for deleting a resource def rmcol(self,uri): """ delete a collection This should not delete any children! This is automatically done before by the DELETE class in DAV/delete.py return a success code or raise an exception """ raise DAV_NotFound def rm(self,uri): """ delete a single resource return a success code or raise an exception """ raise DAV_NotFound """ COPY/MOVE HANDLER These handler are called when a COPY or MOVE method is invoked by a client. In the default implementation it works as follows: - the davserver receives a COPY/MOVE method - the davcopy or davmove module will be loaded and the corresponding class will be initialized - this class parses the query and decides which method of the interface class to call: copyone for a single resource to copy copytree for a tree to copy (collection) (the same goes for move of course). - the interface class has now two options: 1. to handle the action directly (e.g. cp or mv on filesystems) 2. to let it handle via the copy/move methods in davcmd. ad 1) The first approach can be used when we know that no error can happen inside a tree or when the action can exactly tell which element made which error. We have to collect these and return it in a dict of the form {uri: error_code, ...} ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion themselves and call for each resource the copy/move method of the interface class. Thus method will then only act on a single resource. (Thus a copycol on a normal unix filesystem actually only needs to do an mkdir as the content will be copied by the davcmd.py function. The davcmd.py method will also automatically collect all errors and return the dictionary described above. When you use 2) you also have to implement the copy() and copycol() methods in your interface class. See the example for details. To decide which approach is the best you have to decide if your application is able to generate errors inside a tree. E.g. a function which completely fails on a tree if one of the tree's childs fail is not what we need. Then 2) would be your way of doing it. Actually usually 2) is the better solution and should only be replaced by 1) if you really need it. The remaining question is if we should do the same for the DELETE method. """ ### MOVE handlers def moveone(self,src,dst,overwrite): """ move one resource with Depth=0 """ return moveone(self,src,dst,overwrite) def movetree(self,src,dst,overwrite): """ move a collection with Depth=infinity """ return movetree(self,src,dst,overwrite) ### COPY handlers def copyone(self,src,dst,overwrite): """ copy one resource with Depth=0 """ return copyone(self,src,dst,overwrite) def copytree(self,src,dst,overwrite): """ copy a collection with Depth=infinity """ return copytree(self,src,dst,overwrite) ### low level copy methods (you only need these for method 2) def copy(self,src,dst): """ copy a resource with depth==0 You don't need to bother about overwrite or not. This has been done already. return a success code or raise an exception if something fails """ return 201 def copycol(self,src,dst): """ copy a resource with depth==infinity You don't need to bother about overwrite or not. This has been done already. return a success code or raise an exception if something fails """ return 201 ### some utility functions you need to implement def exists(self,uri): """ return 1 or None depending on if a resource exists """ return None # no def is_collection(self,uri): """ return 1 or None depending on if a resource is a collection """ return None # no davix-0.8.0/test/pywebdav/lib/__init__.py0000644000000000000000000000030014121063315016774 0ustar rootroot import pkg_resources # get version from package package = pkg_resources.require('PyWebDAV')[0] VERSION = package.version # author hardcoded here AUTHOR = 'Simon Pamies (spamsch@gmail.com)' davix-0.8.0/test/pywebdav/lib/locks.py0000644000000000000000000002007714121063315016365 0ustar rootrootimport os import sys import time import socket import string import posixpath import base64 import urlparse import urllib import random import logging log = logging.getLogger(__name__) import xml.dom from xml.dom import minidom from utils import rfc1123_date, IfParser, tokenFinder from string import atoi,split from errors import * tokens_to_lock = {} uris_to_token = {} class LockManager: """ Implements the locking backend and serves as MixIn for DAVRequestHandler """ def _init_locks(self): return tokens_to_lock, uris_to_token def _l_isLocked(self, uri): tokens, uris = self._init_locks() return uris.has_key(uri) def _l_hasLock(self, token): tokens, uris = self._init_locks() return tokens.has_key(token) def _l_getLockForUri(self, uri): tokens, uris = self._init_locks() return uris.get(uri, None) def _l_getLock(self, token): tokens, uris = self._init_locks() return tokens.get(token, None) def _l_delLock(self, token): tokens, uris = self._init_locks() if tokens.has_key(token): del uris[tokens[token].uri] del tokens[token] def _l_setLock(self, lock): tokens, uris = self._init_locks() tokens[lock.token] = lock uris[lock.uri] = lock def _lock_unlock_parse(self, body): doc = minidom.parseString(body) data = {} info = doc.getElementsByTagNameNS('DAV:', 'lockinfo')[0] data['lockscope'] = info.getElementsByTagNameNS('DAV:', 'lockscope')[0]\ .firstChild.localName data['locktype'] = info.getElementsByTagNameNS('DAV:', 'locktype')[0]\ .firstChild.localName data['lockowner'] = info.getElementsByTagNameNS('DAV:', 'owner') return data def _lock_unlock_create(self, uri, creator, depth, data): lock = LockItem(uri, creator, **data) iscollection = uri[-1] == '/' # very dumb collection check result = '' if depth == 'infinity' and iscollection: # locking of children/collections not yet supported pass if not self._l_isLocked(uri): self._l_setLock(lock) # because we do not handle children we leave result empty return lock.token, result def do_UNLOCK(self): """ Unlocks given resource """ dc = self.IFACE_CLASS if self._config.DAV.getboolean('verbose') is True: log.info('UNLOCKing resource %s' % self.headers) uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) # check lock token - must contain a dash if not self.headers.get('Lock-Token', '').find('-')>0: return self.send_status(400) token = tokenFinder(self.headers.get('Lock-Token')) if self._l_isLocked(uri): self._l_delLock(token) self.send_body(None, '204', 'Ok', 'Ok') def do_LOCK(self): """ Locking is implemented via in-memory caches. No data is written to disk. """ dc = self.IFACE_CLASS log.info('LOCKing resource %s' % self.headers) body = None if self.headers.has_key('Content-Length'): l = self.headers['Content-Length'] body = self.rfile.read(atoi(l)) depth = self.headers.get('Depth', 'infinity') uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) log.info('do_LOCK: uri = %s' % uri) ifheader = self.headers.get('If') alreadylocked = self._l_isLocked(uri) log.info('do_LOCK: alreadylocked = %s' % alreadylocked) if body and alreadylocked: # Full LOCK request but resource already locked self.responses[423] = ('Locked', 'Already locked') return self.send_status(423) elif body and not ifheader: # LOCK with XML information data = self._lock_unlock_parse(body) token, result = self._lock_unlock_create(uri, 'unknown', depth, data) if result: self.send_body(result, '207', 'Error', 'Error', 'text/xml; charset="utf-8"') else: lock = self._l_getLock(token) self.send_body(lock.asXML(), '200', 'OK', 'OK', 'text/xml; charset="utf-8"', {'Lock-Token' : '' % token}) else: # refresh request - refresh lock timeout taglist = IfParser(ifheader) found = 0 for tag in taglist: for listitem in tag.list: token = tokenFinder(listitem) if token and self._l_hasLock(token): lock = self._l_getLock(token) timeout = self.headers.get('Timeout', 'Infinite') lock.setTimeout(timeout) # automatically refreshes found = 1 self.send_body(lock.asXML(), '200', 'OK', 'OK', 'text/xml; encoding="utf-8"') break if found: break # we didn't find any of the tokens mentioned - means # that table was cleared or another error if not found: self.send_status(412) # precondition failed class LockItem: """ Lock with support for exclusive write locks. Some code taken from webdav.LockItem from the Zope project. """ def __init__(self, uri, creator, lockowner, depth=0, timeout='Infinite', locktype='write', lockscope='exclusive', token=None, **kw): self.uri = uri self.creator = creator self.owner = lockowner self.depth = depth self.timeout = timeout self.locktype = locktype self.lockscope = lockscope self.token = token and token or self.generateToken() self.modified = time.time() def getModifiedTime(self): return self.modified def refresh(self): self.modified = time.time() def isValid(self): now = time.time() modified = self.modified timeout = self.timeout return (modified + timeout) > now def generateToken(self): _randGen = random.Random(time.time()) return '%s-%s-00105A989226:%.03f' % \ (_randGen.random(),_randGen.random(),time.time()) def getTimeoutString(self): t = str(self.timeout) if t[-1] == 'L': t = t[:-1] return 'Second-%s' % t def setTimeout(self, timeout): self.timeout = timeout self.modified = time.time() def asXML(self, namespace='d', discover=False): owner_str = '' if isinstance(self.owner, str): owner_str = self.owner elif isinstance(self.owner, xml.dom.minicompat.NodeList): owner_str = "".join([node.toxml() for node in self.owner[0].childNodes]) token = self.token base = ('<%(ns)s:activelock>\n' ' <%(ns)s:locktype><%(ns)s:%(locktype)s/>\n' ' <%(ns)s:lockscope><%(ns)s:%(lockscope)s/>\n' ' <%(ns)s:depth>%(depth)s\n' ' <%(ns)s:owner>%(owner)s\n' ' <%(ns)s:timeout>%(timeout)s\n' ' <%(ns)s:locktoken>\n' ' <%(ns)s:href>opaquelocktoken:%(locktoken)s\n' ' \n' ' \n' ) % { 'ns': namespace, 'locktype': self.locktype, 'lockscope': self.lockscope, 'depth': self.depth, 'owner': owner_str, 'timeout': self.getTimeoutString(), 'locktoken': token, } if discover is True: return base s = """ %s """ % base return s davix-0.8.0/test/pywebdav/lib/davcmd.py0000644000000000000000000001207214121063315016504 0ustar rootroot""" davcmd.py --------- containts commands like copy, move, delete for normal resources and collections """ from string import split,replace,joinfields import urlparse from utils import create_treelist, is_prefix from errors import * def deltree(dc,uri,exclude={}): """ delete a tree of resources dc -- dataclass to use uri -- root uri to delete exclude -- an optional list of uri:error_code pairs which should not be deleted. returns dict of uri:error_code tuples from which another method can create a multistatus xml element. Also note that we only know Depth=infinity thus we don't have to test for it. """ tlist=create_treelist(dc,uri) result={} for i in range(len(tlist),0,-1): problem_uris=result.keys() element=tlist[i-1] # test here, if an element is a prefix of an uri which # generated an error before. # note that we walk here from childs to parents, thus # we cannot delete a parent if a child made a problem. # (see example in 8.6.2.1) ok=1 for p in problem_uris: if is_prefix(element,p): ok=None break if not ok: continue # here we test for the exclude list which is the other way round! for p in exclude.keys(): if is_prefix(p,element): ok=None break if not ok: continue # now delete stuff try: delone(dc,element) except DAV_Error, (ec,dd): result[element]=ec return result def delone(dc,uri): """ delete a single object """ if dc.is_collection(uri): return dc.rmcol(uri) # should be empty else: return dc.rm(uri) ### ### COPY ### # helper function def copy(dc,src,dst): """ only copy the element This is just a helper method factored out from copy and copytree. It will not handle the overwrite or depth header. """ # destination should have been deleted before if dc.exists(dst): raise DAV_Error, 412 # source should exist also if not dc.exists(src): raise DAV_NotFound if dc.is_collection(src): dc.copycol(src, dst) # an exception will be passed thru else: dc.copy(src, dst) # an exception will be passed thru # the main functions def copyone(dc,src,dst,overwrite=None): """ copy one resource to a new destination """ if overwrite and dc.exists(dst): delres = deltree(dc, dst) else: delres={} # if we cannot delete everything, then do not copy! if delres: return delres try: copy(dc, src, dst) # pass thru exceptions except DAV_Error, (ec, dd): return ec def copytree(dc,src,dst,overwrite=None): """ copy a tree of resources to another location dc -- dataclass to use src -- src uri from where to copy dst -- dst uri overwrite -- if 1 then delete dst uri before returns dict of uri:error_code tuples from which another method can create a multistatus xml element. """ # first delete the destination resource if overwrite and dc.exists(dst): delres=deltree(dc,dst) else: delres={} # if we cannot delete everything, then do not copy! if delres: return delres # get the tree we have to copy tlist = create_treelist(dc,src) result = {} # prepare destination URIs (get the prefix) dpath = urlparse.urlparse(dst)[2] for element in tlist: problem_uris = result.keys() # now URIs get longer and longer thus we have # to test if we had a parent URI which we were not # able to copy in problem_uris which is the prefix # of the actual element. If it is, then we cannot # copy this as well but do not generate another error. ok=1 for p in problem_uris: if is_prefix(p,element): ok=None break if not ok: continue # now create the destination URI which corresponds to # the actual source URI. -> actual_dst # ("subtract" the base src from the URI and prepend the # dst prefix to it.) esrc=replace(element,src,"") actual_dst=dpath+esrc # now copy stuff try: copy(dc,element,actual_dst) except DAV_Error, (ec,dd): result[element]=ec return result ### ### MOVE ### def moveone(dc,src,dst,overwrite=None): """ move a single resource This is done by first copying it and then deleting the original. """ # first copy it copyone(dc, src, dst, overwrite) # then delete it dc.rm(src) def movetree(dc,src,dst,overwrite=None): """ move a collection This is done by first copying it and then deleting the original. PROBLEM: if something did not copy then we have a problem when deleting as the original might get deleted! """ # first copy it res = copytree(dc,src,dst,overwrite) # then delete it res = deltree(dc,src,exclude=res) return res davix-0.8.0/test/pywebdav/lib/INI_Parse.py0000644000000000000000000000303314121063315017014 0ustar rootrootfrom ConfigParser import SafeConfigParser class Configuration: def __init__(self, fileName): cp = SafeConfigParser() cp.read(fileName) self.__parser = cp self.fileName = fileName def __getattr__(self, name): if name in self.__parser.sections(): return Section(name, self.__parser) else: return None def __str__(self): p = self.__parser result = [] result.append('' % self.fileName) for s in p.sections(): result.append('[%s]' % s) for o in p.options(s): result.append('%s=%s' % (o, p.get(s, o))) return '\n'.join(result) class Section: def __init__(self, name, parser): self.name = name self.__parser = parser def __getattr__(self, name): return self.__parser.get(self.name, name) def __str__(self): return str(self.__repr__()) def __repr__(self): return self.__parser.items(self.name) def getboolean(self, name): return self.__parser.getboolean(self.name, name) def __contains__(self, name): return self.__parser.has_option(self.name, name) def get(self, name, default): if name in self: return self.__getattr__(name) else: return default def set(self, name, value): self.__parser.set(self.name, name, str(value)) # Test if __name__ == '__main__': c = Configuration('Importador.ini') print c.Origem.host, c.Origem.port davix-0.8.0/test/pywebdav/lib/AuthServer.py0000644000000000000000000000642514121063315017343 0ustar rootroot"""Authenticating HTTP Server This module builds on BaseHTTPServer and implements basic authentication """ import base64 import binascii import BaseHTTPServer DEFAULT_AUTH_ERROR_MESSAGE = """ %(code)s - %(message)s

Authorization Required

this server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required. """ def _quote_html(html): return html.replace("&", "&").replace("<", "<").replace(">", ">") class AuthRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ Simple handler that can check for auth headers In your subclass you have to define the method get_userinfo(user, password) which should return 1 or None depending on whether the password was ok or not. None means that the user is not authorized. """ # False means no authentiation DO_AUTH = 1 def parse_request(self): if not BaseHTTPServer.BaseHTTPRequestHandler.parse_request(self): return False if self.DO_AUTH: authorization = self.headers.get('Authorization', '') if not authorization: self.send_autherror(401, "Authorization Required") return False scheme, credentials = authorization.split() if scheme != 'Basic': self.send_error(501) return False credentials = base64.decodestring(credentials) user, password = credentials.split(':', 2) if not self.get_userinfo(user, password, self.command): self.send_autherror(401, "Authorization Required") return False return True def send_autherror(self, code, message=None): """Send and log an auth error reply. Arguments are the error code, and a detailed message. The detailed message defaults to the short entry matching the response code. This sends an error response (so it must be called before any output has been generated), logs the error, and finally sends a piece of HTML explaining the error to the user. """ try: short, long = self.responses[code] except KeyError: short, long = '???', '???' if message is None: message = short explain = long self.log_error("code %d, message %s", code, message) # using _quote_html to prevent Cross Site Scripting attacks (see bug # #1100201) content = (self.error_auth_message_format % {'code': code, 'message': _quote_html(message), 'explain': explain}) self.send_response(code, message) self.send_header('Content-Type', self.error_content_type) self.send_header('WWW-Authenticate', 'Basic realm="PyWebDAV"') self.send_header('Connection', 'close') self.end_headers() self.wfile.write(content) error_auth_message_format = DEFAULT_AUTH_ERROR_MESSAGE def get_userinfo(self, user, password, command): """Checks if the given user and the given password are allowed to access. """ # Always reject return None davix-0.8.0/test/pywebdav/lib/report.py0000644000000000000000000001044014121063315016556 0ustar rootrootfrom propfind import PROPFIND from xml.dom import minidom domimpl = minidom.getDOMImplementation() from utils import get_parenturi class REPORT(PROPFIND): def __init__(self, uri, dataclass, depth, body): PROPFIND.__init__(self, uri, dataclass, depth, body) doc = minidom.parseString(body) self.filter = doc.documentElement def create_propname(self): """ create a multistatus response for the prop names """ dc=self._dataclass # create the document generator doc = domimpl.createDocument(None, "multistatus", None) ms = doc.documentElement ms.setAttribute("xmlns:D", "DAV:") ms.tagName = 'D:multistatus' if self._depth=="0": if self._uri in self._dataclass.get_childs(get_parenturi(self._uri), self.filter): pnames=dc.get_propnames(self._uri) re=self.mk_propname_response(self._uri,pnames, doc) ms.appendChild(re) elif self._depth=="1": if self._uri in self._dataclass.get_childs(get_parenturi(self._uri), self.filter): pnames=dc.get_propnames(self._uri) re=self.mk_propname_response(self._uri,pnames, doc) ms.appendChild(re) for newuri in dc.get_childs(self._uri, self.filter): pnames=dc.get_propnames(newuri) re=self.mk_propname_response(newuri,pnames, doc) ms.appendChild(re) elif self._depth=='infinity': uri_list = [self._uri] while uri_list: uri = uri_list.pop() if uri in self._dataclass.get_childs(get_parenturi(uri), self.filter): pnames=dc.get_propnames(uri) re=self.mk_propname_response(uri,pnames, doc) ms.appendChild(re) uri_childs = self._dataclass.get_childs(uri) if uri_childs: uri_list.extend(uri_childs) return doc.toxml(encoding="utf-8") def create_prop(self): """ handle a request This will 1. set up the -Framework 2. read the property values for each URI (which is dependant on the Depth header) This is done by the get_propvalues() method. 3. For each URI call the append_result() method to append the actual -Tag to the result document. We differ between "good" properties, which have been assigned a value by the interface class and "bad" properties, which resulted in an error, either 404 (Not Found) or 403 (Forbidden). """ # create the document generator doc = domimpl.createDocument(None, "multistatus", None) ms = doc.documentElement ms.setAttribute("xmlns:D", "DAV:") ms.tagName = 'D:multistatus' if self._depth=="0": if self._uri in self._dataclass.get_childs(get_parenturi(self._uri), self.filter): gp,bp=self.get_propvalues(self._uri) res=self.mk_prop_response(self._uri,gp,bp,doc) ms.appendChild(res) elif self._depth=="1": if self._uri in self._dataclass.get_childs(get_parenturi(self._uri), self.filter): gp,bp=self.get_propvalues(self._uri) res=self.mk_prop_response(self._uri,gp,bp,doc) ms.appendChild(res) for newuri in self._dataclass.get_childs(self._uri, self.filter): gp,bp=self.get_propvalues(newuri) res=self.mk_prop_response(newuri,gp,bp,doc) ms.appendChild(res) elif self._depth=='infinity': uri_list = [self._uri] while uri_list: uri = uri_list.pop() if uri in self._dataclass.get_childs(get_parenturi(uri), self.filter): gp,bp=self.get_propvalues(uri) res=self.mk_prop_response(uri,gp,bp,doc) ms.appendChild(res) uri_childs = self._dataclass.get_childs(uri) if uri_childs: uri_list.extend(uri_childs) return doc.toxml(encoding="utf-8") davix-0.8.0/test/pywebdav/lib/davmove.py0000644000000000000000000000431114121063315016704 0ustar rootrootimport sys import string import urlparse import urllib from StringIO import StringIO import utils from constants import COLLECTION, OBJECT, DAV_PROPS from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP from errors import * from utils import create_treelist, quote_uri, gen_estring, make_xmlresponse from davcmd import moveone, movetree class MOVE: """ move resources and eventually create multistatus responses This module implements the MOVE class which is responsible for moving resources. MOVE is implemented by a COPY followed by a DELETE of the old resource. """ def __init__(self,dataclass,src_uri,dst_uri,overwrite): self.__dataclass=dataclass self.__src=src_uri self.__dst=dst_uri self.__overwrite=overwrite def single_action(self): """ move a normal resources. We try to move it and return the result code. This is for Depth==0 """ dc=self.__dataclass base=self.__src ### some basic tests # test if dest exists and overwrite is false if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 # test if src and dst are the same # (we assume that both uris are on the same server!) ps=urlparse.urlparse(self.__src)[2] pd=urlparse.urlparse(self.__dst)[2] if ps==pd: raise DAV_Error, 403 return dc.moveone(self.__src,self.__dst,self.__overwrite) def tree_action(self): """ move a tree of resources (a collection) Here we return a multistatus xml element. """ dc=self.__dataclass base=self.__src ### some basic tests # test if dest exists and overwrite is false if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 # test if src and dst are the same # (we assume that both uris are on the same server!) ps=urlparse.urlparse(self.__src)[2] pd=urlparse.urlparse(self.__dst)[2] if ps==pd: raise DAV_Error, 403 result=dc.movetree(self.__src,self.__dst,self.__overwrite) if not result: return None # create the multistatus XML element return make_xmlresponse(result) davix-0.8.0/test/pywebdav/lib/utils.py0000755000000000000000000001532514121063315016415 0ustar rootrootimport time import re from xml.dom import minidom import urlparse from string import lower, split, atoi, joinfields from StringIO import StringIO from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP from BaseHTTPServer import BaseHTTPRequestHandler def gen_estring(ecode): """ generate an error string from the given code """ ec=atoi(str(ecode)) if BaseHTTPRequestHandler.responses.has_key(ec): return "HTTP/1.1 %s %s" %(ec, BaseHTTPRequestHandler.responses[ec][0]) else: return "HTTP/1.1 %s" %(ec) def parse_propfind(xml_doc): """ Parse an propfind xml file and return a list of props """ doc = minidom.parseString(xml_doc) request_type=None props={} namespaces=[] if doc.getElementsByTagNameNS("DAV:", "allprop"): request_type = RT_ALLPROP elif doc.getElementsByTagNameNS("DAV:", "propname"): request_type = RT_PROPNAME else: request_type = RT_PROP for i in doc.getElementsByTagNameNS("DAV:", "prop"): for e in i.childNodes: if e.nodeType != minidom.Node.ELEMENT_NODE: continue ns = e.namespaceURI ename = e.localName if props.has_key(ns): props[ns].append(ename) else: props[ns]=[ename] namespaces.append(ns) return request_type,props,namespaces def create_treelist(dataclass,uri): """ create a list of resources out of a tree This function is used for the COPY, MOVE and DELETE methods uri - the root of the subtree to flatten It will return the flattened tree as list """ queue=[uri] list=[uri] while len(queue): element=queue[-1] if dataclass.is_collection(element): childs=dataclass.get_childs(element) else: childs=[] if len(childs): list=list+childs # update queue del queue[-1] if len(childs): queue=queue+childs return list def is_prefix(uri1,uri2): """ returns 1 of uri1 is a prefix of uri2 """ if uri2[:len(uri1)]==uri1: return 1 else: return None def quote_uri(uri): """ quote an URL but not the protocol part """ import urlparse import urllib up=urlparse.urlparse(uri) np=urllib.quote(up[2]) return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5])) def get_uriparentpath(uri): """ extract the uri path and remove the last element """ up=urlparse.urlparse(uri) return joinfields(split(up[2],"/")[:-1],"/") def get_urifilename(uri): """ extract the uri path and return the last element """ up=urlparse.urlparse(uri) return split(up[2],"/")[-1] def get_parenturi(uri): """ return the parent of the given resource""" up=urlparse.urlparse(uri) np=joinfields(split(up[2],"/")[:-1],"/") return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5])) ### XML utilities def make_xmlresponse(result): """ construct a response from a dict of uri:error_code elements """ doc = minidom.getDOMImplementation().createDocument(None, "multistatus", None) doc.documentElement.setAttribute("xmlns:D","DAV:") doc.documentElement.tagName = "D:multistatus" for el,ec in result.items(): re=doc.createElementNS("DAV:","response") hr=doc.createElementNS("DAV:","href") st=doc.createElementNS("DAV:","status") huri=doc.createTextNode(quote_uri(el)) t=doc.createTextNode(gen_estring(ec)) st.appendChild(t) hr.appendChild(huri) re.appendChild(hr) re.appendChild(st) doc.documentElement.appendChild(re) return doc.toxml(encoding="utf-8") # taken from App.Common weekday_abbr = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] weekday_full = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] def rfc1123_date(ts=None): # Return an RFC 1123 format date string, required for # use in HTTP Date headers per the HTTP 1.1 spec. # 'Fri, 10 Nov 2000 16:21:09 GMT' if ts is None: ts=time.time() year, month, day, hh, mm, ss, wd, y, z = time.gmtime(ts) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (weekday_abbr[wd], day, monthname[month], year, hh, mm, ss) def iso8601_date(ts=None): # Return an ISO 8601 formatted date string, required # for certain DAV properties. # '2000-11-10T16:21:09-08:00 if ts is None: ts=time.time() return time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(ts)) def rfc850_date(ts=None): # Return an HTTP-date formatted date string. # 'Friday, 10-Nov-00 16:21:09 GMT' if ts is None: ts=time.time() year, month, day, hh, mm, ss, wd, y, z = time.gmtime(ts) return "%s, %02d-%3s-%2s %02d:%02d:%02d GMT" % ( weekday_full[wd], day, monthname[month], str(year)[2:], hh, mm, ss) ### If: header handling support. IfParser returns a sequence of ### TagList objects in the order they were parsed which can then ### be used in WebDAV methods to decide whether an operation can ### proceed or to raise HTTP Error 412 (Precondition failed) IfHdr = re.compile( r"(?P<.+?>)?\s*\((?P[^)]+)\)" ) ListItem = re.compile( r"(?Pnot)?\s*(?P<[a-zA-Z]+:[^>]*>|\[.*?\])", re.I) class TagList: def __init__(self): self.resource = None self.list = [] self.NOTTED = 0 def IfParser(hdr): out = [] i = 0 while 1: m = IfHdr.search(hdr[i:]) if not m: break i = i + m.end() tag = TagList() tag.resource = m.group('resource') if tag.resource: # We need to delete < > tag.resource = tag.resource[1:-1] listitem = m.group('listitem') tag.NOTTED, tag.list = ListParser(listitem) out.append(tag) return out def tokenFinder(token): # takes a string like ' and returns the token # part. if not token: return None # An empty string was passed in if token[0] == '[': return None # An Etag was passed in if token[0] == '<': token = token[1:-1] return token[token.find(':')+1:] def ListParser(listitem): out = [] NOTTED = 0 i = 0 while 1: m = ListItem.search(listitem[i:]) if not m: break i = i + m.end() out.append(m.group('listitem')) if m.group('not'): NOTTED = 1 return NOTTED, out davix-0.8.0/test/pywebdav/lib/constants.py0000644000000000000000000000121014121063315017252 0ustar rootroot# definition for resourcetype COLLECTION=1 OBJECT=None # attributes for resources DAV_PROPS=['creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock'] # Request classes in propfind RT_ALLPROP=1 RT_PROPNAME=2 RT_PROP=3 # server mode DAV_VERSION_1 = { 'version' : '1', 'options' : 'GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE, REPORT' } DAV_VERSION_2 = { 'version' : '1,2', 'options' : DAV_VERSION_1['options'] + ', LOCK, UNLOCK' } davix-0.8.0/test/pywebdav/lib/davcopy.py0000644000000000000000000000614514121063315016717 0ustar rootrootimport xml.dom.minidom domimpl = xml.dom.minidom.getDOMImplementation() import sys import string import urlparse import urllib from StringIO import StringIO import utils from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP from errors import * from utils import create_treelist, quote_uri, gen_estring class COPY: """ copy resources and eventually create multistatus responses This module implements the COPY class which is responsible for copying resources. Usually the normal copy work is done in the interface class. This class only creates error messages if error occur. """ def __init__(self,dataclass,src_uri,dst_uri,overwrite): self.__dataclass=dataclass self.__src=src_uri self.__dst=dst_uri self.__overwrite=overwrite def single_action(self): """ copy a normal resources. We try to copy it and return the result code. This is for Depth==0 """ dc=self.__dataclass base=self.__src ### some basic tests # test if dest exists and overwrite is false if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 # test if src and dst are the same # (we assume that both uris are on the same server!) ps=urlparse.urlparse(self.__src)[2] pd=urlparse.urlparse(self.__dst)[2] if ps==pd: raise DAV_Error, 403 return dc.copyone(self.__src,self.__dst,self.__overwrite) #return copyone(dc,self.__src,self.__dst,self.__overwrite) def tree_action(self): """ copy a tree of resources (a collection) Here we return a multistatus xml element. """ dc=self.__dataclass base=self.__src ### some basic tests # test if dest exists and overwrite is false if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412 # test if src and dst are the same # (we assume that both uris are on the same server!) ps=urlparse.urlparse(self.__src)[2] pd=urlparse.urlparse(self.__dst)[2] if ps==pd: raise DAV_Error, 403 result=dc.copytree(self.__src,self.__dst,self.__overwrite) #result=copytree(dc,self.__src,self.__dst,self.__overwrite) if not result: return None ### ### create the multistatus XML element ### (this is also the same as in delete.py. ### we might make a common method out of it) ### doc = domimpl.createDocument(None, "D:multistatus", None) doc.documentElement.setAttribute("xmlns:D","DAV:") for el,ec in result.items(): re=doc.createElement("D:response") hr=doc.createElement("D:href") st=doc.createElement("D:status") huri=doc.createTextNode(quote_uri(el)) t=doc.createTextNode(gen_estring(ec)) st.appendChild(t) hr.appendChild(huri) re.appendChild(hr) re.appendChild(st) ms.appendChild(re) return doc.toxml(encoding="utf-8") davix-0.8.0/test/pywebdav/lib/propfind.py0000644000000000000000000002660214121063315017073 0ustar rootrootimport xml.dom.minidom domimpl = xml.dom.minidom.getDOMImplementation() import logging import urlparse import urllib import utils from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP from errors import DAV_Error, DAV_NotFound log = logging.getLogger(__name__) class PROPFIND: """ parse a propfind xml element and extract props It will set the following instance vars: request_class : ALLPROP | PROPNAME | PROP proplist : list of properties nsmap : map of namespaces The list of properties will contain tuples of the form (element name, ns_prefix, ns_uri) """ def __init__(self, uri, dataclass, depth, body): self.request_type = None self.nsmap = {} self.proplist = {} self.default_ns = None self._dataclass = dataclass self._depth = str(depth) self._uri = uri.rstrip('/') self._has_body = None # did we parse a body? if dataclass.verbose: log.info('PROPFIND: Depth is %s, URI is %s' % (depth, uri)) if body: self.request_type, self.proplist, self.namespaces = \ utils.parse_propfind(body) self._has_body = True def createResponse(self): """ Create the multistatus response This will be delegated to the specific method depending on which request (allprop, propname, prop) was found. If we get a PROPNAME then we simply return the list with empty values which we get from the interface class If we get an ALLPROP we first get the list of properties and then we do the same as with a PROP method. """ # check if resource exists if not self._dataclass.exists(self._uri): raise DAV_NotFound df = None if self.request_type == RT_ALLPROP: df = self.create_allprop() if self.request_type == RT_PROPNAME: df = self.create_propname() if self.request_type == RT_PROP: df = self.create_prop() if df != None: return df # no body means ALLPROP! df = self.create_allprop() return df def create_propname(self): """ create a multistatus response for the prop names """ dc = self._dataclass # create the document generator doc = domimpl.createDocument(None, "multistatus", None) ms = doc.documentElement ms.setAttribute("xmlns:D", "DAV:") ms.tagName = 'D:multistatus' if self._depth == "0": pnames = dc.get_propnames(self._uri) re = self.mk_propname_response(self._uri, pnames, doc) ms.appendChild(re) elif self._depth == "1": pnames = dc.get_propnames(self._uri) re = self.mk_propname_response(self._uri, pnames, doc) ms.appendChild(re) for newuri in dc.get_childs(self._uri): pnames = dc.get_propnames(newuri) re = self.mk_propname_response(newuri, pnames, doc) ms.appendChild(re) elif self._depth == 'infinity': uri_list = [self._uri] while uri_list: uri = uri_list.pop() pnames = dc.get_propnames(uri) re = self.mk_propname_response(uri, pnames, doc) ms.appendChild(re) uri_childs = self._dataclass.get_childs(uri) if uri_childs: uri_list.extend(uri_childs) return doc.toxml(encoding="utf-8") def create_allprop(self): """ return a list of all properties """ self.proplist = {} self.namespaces = [] for ns, plist in self._dataclass.get_propnames(self._uri).items(): self.proplist[ns] = plist self.namespaces.append(ns) return self.create_prop() def create_prop(self): """ handle a request This will 1. set up the -Framework 2. read the property values for each URI (which is dependant on the Depth header) This is done by the get_propvalues() method. 3. For each URI call the append_result() method to append the actual -Tag to the result document. We differ between "good" properties, which have been assigned a value by the interface class and "bad" properties, which resulted in an error, either 404 (Not Found) or 403 (Forbidden). """ # create the document generator doc = domimpl.createDocument(None, "multistatus", None) ms = doc.documentElement ms.setAttribute("xmlns:D", "DAV:") ms.tagName = 'D:multistatus' if self._depth == "0": gp, bp = self.get_propvalues(self._uri) res = self.mk_prop_response(self._uri, gp, bp, doc) ms.appendChild(res) elif self._depth == "1": gp, bp = self.get_propvalues(self._uri) res = self.mk_prop_response(self._uri, gp, bp, doc) ms.appendChild(res) for newuri in self._dataclass.get_childs(self._uri): gp, bp = self.get_propvalues(newuri) res = self.mk_prop_response(newuri, gp, bp, doc) ms.appendChild(res) elif self._depth == 'infinity': uri_list = [self._uri] while uri_list: uri = uri_list.pop() gp, bp = self.get_propvalues(uri) res = self.mk_prop_response(uri, gp, bp, doc) ms.appendChild(res) uri_childs = self._dataclass.get_childs(uri) if uri_childs: uri_list.extend(uri_childs) return doc.toxml(encoding="utf-8") def mk_propname_response(self, uri, propnames, doc): """ make a new result element for a PROPNAME request This will simply format the propnames list. propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...} """ re = doc.createElement("D:response") if self._dataclass.baseurl: uri = self._dataclass.baseurl + '/' + '/'.join(uri.split('/')[3:]) # write href information uparts = urlparse.urlparse(uri) fileloc = uparts[2] href = doc.createElement("D:href") huri = doc.createTextNode(uparts[0] + '://' + '/'.join(uparts[1:2]) + urllib.quote(fileloc)) href.appendChild(huri) re.appendChild(href) ps = doc.createElement("D:propstat") nsnum = 0 for ns, plist in propnames.items(): # write prop element pr = doc.createElement("D:prop") nsp = "ns" + str(nsnum) pr.setAttribute("xmlns:" + nsp, ns) nsnum += 1 # write propertynames for p in plist: pe = doc.createElement(nsp + ":" + p) pr.appendChild(pe) ps.appendChild(pr) re.appendChild(ps) return re def mk_prop_response(self, uri, good_props, bad_props, doc): """ make a new result element We differ between the good props and the bad ones for each generating an extra -Node (for each error one, that means). """ re = doc.createElement("D:response") # append namespaces to response nsnum = 0 for nsname in self.namespaces: if nsname != 'DAV:': re.setAttribute("xmlns:ns" + str(nsnum), nsname) nsnum += 1 if self._dataclass.baseurl: uri = self._dataclass.baseurl + '/' + '/'.join(uri.split('/')[3:]) # write href information uparts = urlparse.urlparse(uri) fileloc = uparts[2] href = doc.createElement("D:href") huri = doc.createTextNode(uparts[0] + '://' + '/'.join(uparts[1:2]) + urllib.quote(fileloc)) href.appendChild(huri) re.appendChild(href) # write good properties ps = doc.createElement("D:propstat") if good_props: re.appendChild(ps) gp = doc.createElement("D:prop") for ns in good_props.keys(): if ns != 'DAV:': ns_prefix = "ns" + str(self.namespaces.index(ns)) + ":" else: ns_prefix = 'D:' for p, v in good_props[ns].items(): pe = doc.createElement(ns_prefix + str(p)) if isinstance(v, xml.dom.minidom.Element): pe.appendChild(v) elif isinstance(v, list): for val in v: pe.appendChild(val) else: if p == "resourcetype": if v == 1: ve = doc.createElement("D:collection") pe.appendChild(ve) else: ve = doc.createTextNode(v) pe.appendChild(ve) gp.appendChild(pe) ps.appendChild(gp) s = doc.createElement("D:status") t = doc.createTextNode("HTTP/1.1 200 OK") s.appendChild(t) ps.appendChild(s) re.appendChild(ps) # now write the errors! if len(bad_props.items()): # write a propstat for each error code for ecode in bad_props.keys(): ps = doc.createElement("D:propstat") re.appendChild(ps) bp = doc.createElement("D:prop") ps.appendChild(bp) for ns in bad_props[ecode].keys(): if ns != 'DAV:': ns_prefix = "ns" + str(self.namespaces.index(ns)) + ":" else: ns_prefix = 'D:' for p in bad_props[ecode][ns]: pe = doc.createElement(ns_prefix + str(p)) bp.appendChild(pe) s = doc.createElement("D:status") t = doc.createTextNode(utils.gen_estring(ecode)) s.appendChild(t) ps.appendChild(s) re.appendChild(ps) # return the new response element return re def get_propvalues(self, uri): """ create lists of property values for an URI We create two lists for an URI: the properties for which we found a value and the ones for which we only got an error, either because they haven't been found or the user is not allowed to read them. """ good_props = {} bad_props = {} ddc = self._dataclass for ns, plist in self.proplist.items(): good_props[ns] = {} for prop in plist: ec = 0 try: r = ddc.get_prop(uri, ns, prop) good_props[ns][prop] = r except DAV_Error, error_code: ec = error_code[0] # ignore props with error_code if 0 (invisible) if ec == 0: continue if ec in bad_props: if ns in bad_props[ec]: bad_props[ec][ns].append(prop) else: bad_props[ec][ns] = [prop] else: bad_props[ec] = {ns: [prop]} return good_props, bad_props davix-0.8.0/test/pywebdav/lib/status.py0000644000000000000000000000126114121063315016567 0ustar rootroot STATUS_CODES={ 100: "Continue", 102: "Processing", 200: "Ok", 201: "Created", 204: "No Content", 207: "Multi-Status", 201: "Created", 400: "Bad Request", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 409: "Conflict", 412: "Precondition failed", 423: "Locked", 415: "Unsupported Media Type", 507: "Insufficient Storage", 422: "Unprocessable Entity", 423: "Locked", 424: "Failed Dependency", 502: "Bad Gateway", 507: "Insufficient Storage" } davix-0.8.0/test/pywebdav/lib/dbconn.py0000644000000000000000000000417514121063315016516 0ustar rootrootimport logging log = logging.getLogger(__name__) try: import MySQLdb except ImportError: log.info('No SQL support - MySQLdb missing...') pass import sys class Mconn: def connect(self,username,userpasswd,host,port,db): try: connection = MySQLdb.connect(host=host, port=int(port), user=username, passwd=userpasswd,db=db) except MySQLdb.OperationalError, message: log.error("%d:\n%s" % (message[ 0 ], message[ 1 ] )) return 0 else: self.db = connection.cursor() return 1 def execute(self,qry): if self.db: try: res=self.db.execute(qry) except MySQLdb.OperationalError, message: log.error("Error %d:\n%s" % (message[ 0 ], message[ 1 ] )) return 0 except MySQLdb.ProgrammingError, message: log.error("Error %d:\n%s" % (message[ 0 ], message[ 1 ] )) return 0 else: log.debug('Query Returned '+str(res)+' results') return self.db.fetchall() def create_user(self,user,passwd): qry="select * from Users where User='%s'"%(user) res=self.execute(qry) if not res or len(res) ==0: qry="insert into Users (User,Pass) values('%s','%s')"%(user,passwd) res=self.execute(qry) else: log.debug("Username already in use") def create_table(self): qry="""CREATE TABLE `Users` ( `uid` int(10) NOT NULL auto_increment, `User` varchar(60) default NULL, `Pass` varchar(60) default NULL, `Write` tinyint(1) default '0', PRIMARY KEY (`uid`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1""" self.execute(qry) def first_run(self,user,passwd): res= self.execute('select * from Users') if res or type(res)==type(()) : pass else: self.create_table() self.create_user(user,passwd) def __init__(self,user,password,host,port,db): self.db=0 self.connect(user,password,host,port,db) davix-0.8.0/test/pywebdav/server/0000755000000000000000000000000014121063315015432 5ustar rootrootdavix-0.8.0/test/pywebdav/server/daemonize.py0000644000000000000000000001245214121063315017763 0ustar rootroot#Copyright (c) 2005 Simon Pamies (s.pamies@banality.de) #Copyright (c) 2003 Clark Evans #Copyright (c) 2002 Noah Spurrier #Copyright (c) 2001 Juergen Hermann # #This library is free software; you can redistribute it and/or #modify it under the terms of the GNU Library General Public #License as published by the Free Software Foundation; either #version 2 of the License, or (at your option) any later version. # #This library is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #Library General Public License for more details. # #You should have received a copy of the GNU Library General Public #License along with this library; if not, write to the Free #Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, #MA 02111-1307, USA ''' This module is used to fork the current process into a daemon. Almost none of this is necessary (or advisable) if your daemon is being started by inetd. In that case, stdin, stdout and stderr are all set up for you to refer to the network connection, and the fork()s and session manipulation should not be done (to avoid confusing inetd). Only the chdir() and umask() steps remain as useful. References: UNIX Programming FAQ 1.7 How do I get my program to act like a daemon? http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 Advanced Programming in the Unix Environment W. Richard Stevens, 1992, Addison-Wesley, ISBN 0-201-56317-7. History: 2005/06/23 by Simon Pamies 2001/07/10 by Juergen Hermann 2002/08/28 by Noah Spurrier 2003/02/24 by Clark Evans http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012 ''' import sys, os, time from signal import SIGTERM def deamonize(stdout='/dev/null', stderr=None, stdin='/dev/null', pidfile=None, startmsg = 'started with pid %s' ): ''' This forks the current process into a daemon. The stdin, stdout, and stderr arguments are file names that will be opened and be used to replace the standard file descriptors in sys.stdin, sys.stdout, and sys.stderr. These arguments are optional and default to /dev/null. Note that stderr is opened unbuffered, so if it shares a file with stdout then interleaved output may not appear in the order that you expect. ''' # Do first fork. try: pid = os.fork() if pid > 0: sys.exit(0) # Exit first parent. except OSError, e: sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror)) sys.exit(1) # Decouple from parent environment. os.chdir("/") os.umask(0) os.setsid() # Do second fork. try: pid = os.fork() if pid > 0: sys.exit(0) # Exit second parent. except OSError, e: sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror)) sys.exit(1) # Open file descriptors and print start message if not stderr: stderr = stdout si = file(stdin, 'r') so = file(stdout, 'a+') se = file(stderr, 'a+', 0) pid = str(os.getpid()) sys.stderr.write("\n%s\n" % startmsg % pid) sys.stderr.flush() if pidfile: file(pidfile,'w+').write("%s\n" % pid) if sys.stdin.closed: sys.stdin = open('/dev/null', 'r') if sys.stdout.closed: sys.stdout = open('/dev/null', 'a+') if sys.stderr.closed: sys.stderr = open('/dev/null', 'a+') # Redirect standard file descriptors. os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) def startstop(stdout='/dev/null', stderr=None, stdin='/dev/null', pidfile='pid.txt', startmsg = 'started with pid %s', action='start' ): if action: try: pf = file(pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if 'stop' == action or 'restart' == action: if not pid: mess = "Could not stop, pid file '%s' missing.\n" sys.stderr.write(mess % pidfile) if 'stop' == action: sys.exit(1) action = 'start' pid = None else: try: while 1: os.kill(pid,SIGTERM) time.sleep(1) except OSError, err: err = str(err) if err.find("No such process") > 0: os.remove(pidfile) if 'stop' == action: sys.exit(0) action = 'start' pid = None else: print str(err) sys.exit(1) if 'start' == action: if pid: mess = "Start aborted since pid file '%s' exists.\n" sys.stderr.write(mess % pidfile) sys.exit(1) deamonize(stdout,stderr,stdin,pidfile,startmsg) return if 'status' == action: if not pid: sys.stderr.write('Status: Stopped\n') else: sys.stderr.write('Status: Running\n') sys.exit(0) davix-0.8.0/test/pywebdav/server/fileauth.py0000644000000000000000000000346214121063315017612 0ustar rootroot#Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de) # #This library is free software; you can redistribute it and/or #modify it under the terms of the GNU Library General Public #License as published by the Free Software Foundation; either #version 2 of the License, or (at your option) any later version. # #This library is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #Library General Public License for more details. # #You should have received a copy of the GNU Library General Public #License along with this library; if not, write to the Free #Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, #MA 02111-1307, USA """ Python WebDAV Server. This is an example implementation of a DAVserver using the DAV package. """ import sys import logging from pywebdav.lib.WebDAVServer import DAVRequestHandler from pywebdav.lib.dbconn import Mconn from fshandler import FilesystemHandler log = logging.getLogger() class DAVAuthHandler(DAVRequestHandler): """ Provides authentication based on parameters. The calling class has to inject password and username into this. (Variables: auth_user and auth_pass) """ # Do not forget to set IFACE_CLASS by caller # ex.: IFACE_CLASS = FilesystemHandler('/tmp', 'http://localhost/') verbose = False def _log(self, message): if self.verbose: log.info(message) def get_userinfo(self,user,pw,command): """ authenticate user """ if user == self._config.DAV.user and pw == self._config.DAV.password: log.info('Successfully authenticated user %s' % user) return 1 log.info('Authentication failed for user %s' % user) return 0 davix-0.8.0/test/pywebdav/server/__init__.py0000644000000000000000000000000114121063315017532 0ustar rootroot davix-0.8.0/test/pywebdav/server/fshandler.py0000644000000000000000000002670514121063315017764 0ustar rootrootimport sys import urlparse import os import time from string import joinfields, split, lower import logging import types import shutil from pywebdav.lib.constants import COLLECTION, OBJECT from pywebdav.lib.errors import * from pywebdav.lib.iface import * from pywebdav.lib.davcmd import copyone, copytree, moveone, movetree, delone, deltree log = logging.getLogger(__name__) BUFFER_SIZE = 128 * 1000 # include magic support to correctly determine mimetypes MAGIC_AVAILABLE = False try: import mimetypes MAGIC_AVAILABLE = True log.info('Mimetype support ENABLED') except ImportError: log.info('Mimetype support DISABLED') pass class Resource(object): # XXX this class is ugly def __init__(self, fp, file_size): self.__fp = fp self.__file_size = file_size def __len__(self): return self.__file_size def __iter__(self): while 1: data = self.__fp.read(BUFFER_SIZE) if not data: break yield data time.sleep(0.005) self.__fp.close() def read(self, length = 0): if length == 0: length = self.__file_size data = self.__fp.read(length) return data class FilesystemHandler(dav_interface): """ Model a filesystem for DAV This class models a regular filesystem for the DAV server The basic URL will be http://localhost/ And the underlying filesystem will be /tmp Thus http://localhost/gfx/pix will lead to /tmp/gfx/pix """ def __init__(self, directory, uri, verbose=False): self.setDirectory(directory) self.setBaseURI(uri) # should we be verbose? self.verbose = verbose log.info('Initialized with %s %s' % (directory, uri)) def setDirectory(self, path): """ Sets the directory """ if not os.path.isdir(path): raise Exception, '%s not must be a directory!' % path self.directory = path def setBaseURI(self, uri): """ Sets the base uri """ self.baseuri = uri def uri2local(self,uri): """ map uri in baseuri and local part """ uparts=urlparse.urlparse(uri) fileloc=uparts[2][1:] filename=os.path.join(self.directory,fileloc) filename=os.path.normpath(filename) return filename def local2uri(self,filename): """ map local filename to self.baseuri """ pnum=len(split(self.directory.replace("\\","/"),"/")) parts=split(filename.replace("\\","/"),"/")[pnum:] sparts="/"+joinfields(parts,"/") uri=urlparse.urljoin(self.baseuri,sparts) return uri def get_childs(self, uri, filter=None): """ return the child objects as self.baseuris for the given URI """ fileloc=self.uri2local(uri) filelist=[] if os.path.exists(fileloc): if os.path.isdir(fileloc): try: files=os.listdir(fileloc) except: raise DAV_NotFound for file in files: newloc=os.path.join(fileloc,file) filelist.append(self.local2uri(newloc)) log.info('get_childs: Childs %s' % filelist) return filelist def get_data(self,uri, range = None): """ return the content of an object """ path=self.uri2local(uri) if os.path.exists(path): if os.path.isfile(path): file_size = os.path.getsize(path) if range == None: fp=open(path,"r") log.info('Serving content of %s' % uri) return Resource(fp, file_size) else: if range[1] == '': range[1] = file_size else: range[1] = int(range[1]) if range[0] == '': range[0] = file_size - range[1] else: range[0] = int(range[0]) if range[0] > file_size: raise DAV_Requested_Range_Not_Satisfiable if range[1] > file_size: range[1] = file_size fp=open(path,"r") fp.seek(range[0]) log.info('Serving range %s -> %s content of %s' % (range[0], range[1], uri)) return Resource(fp, range[1] - range[0]) elif os.path.isdir(path): # GET for collections is defined as 'return s/th meaningful' :-) from StringIO import StringIO stio = StringIO('Directory at %s' % uri) return Resource(StringIO('Directory at %s' % uri), stio.len) else: # also raise an error for collections # don't know what should happen then.. log.info('get_data: %s not found' % path) raise DAV_NotFound def _get_dav_resourcetype(self,uri): """ return type of object """ path=self.uri2local(uri) if os.path.isfile(path): return OBJECT elif os.path.isdir(path): return COLLECTION raise DAV_NotFound def _get_dav_displayname(self,uri): raise DAV_Secret # do not show def _get_dav_getcontentlength(self,uri): """ return the content length of an object """ path=self.uri2local(uri) if os.path.exists(path): if os.path.isfile(path): s=os.stat(path) return str(s[6]) return '0' def get_lastmodified(self,uri): """ return the last modified date of the object """ path=self.uri2local(uri) if os.path.exists(path): s=os.stat(path) date=s[8] return date raise DAV_NotFound def get_creationdate(self,uri): """ return the last modified date of the object """ path=self.uri2local(uri) if os.path.exists(path): s=os.stat(path) date=s[9] return date raise DAV_NotFound def _get_dav_getcontenttype(self,uri): """ find out yourself! """ path=self.uri2local(uri) if os.path.exists(path): if os.path.isfile(path): if MAGIC_AVAILABLE is False \ or self.mimecheck is False: return 'application/octet-stream' else: ret, encoding = mimetypes.guess_type(path) # for non mimetype related result we # simply return an appropriate type if ret.find('/')==-1: if ret.find('text')>=0: return 'text/plain' else: return 'application/octet-stream' else: return ret elif os.path.isdir(path): return "httpd/unix-directory" raise DAV_NotFound, 'Could not find %s' % path def put(self, uri, data, content_type=None): """ put the object into the filesystem """ path=self.uri2local(uri) try: fp=open(path, "w+") if isinstance(data, types.GeneratorType): for d in data: fp.write(d) else: if data: fp.write(data) fp.close() log.info('put: Created %s' % uri) except: log.info('put: Could not create %s' % uri) raise DAV_Error, 424 return None def mkcol(self,uri): """ create a new collection """ path=self.uri2local(uri) # remove trailing slash if path[-1]=="/": path=path[:-1] # test if file already exists if os.path.exists(path): raise DAV_Error,405 # test if parent exists h,t=os.path.split(path) if not os.path.exists(h): raise DAV_Error, 409 # test, if we are allowed to create it try: os.mkdir(path) log.info('mkcol: Created new collection %s' % path) return 201 except: log.info('mkcol: Creation of %s denied' % path) raise DAV_Forbidden ### ?? should we do the handler stuff for DELETE, too ? ### (see below) def rmcol(self,uri): """ delete a collection """ path=self.uri2local(uri) if not os.path.exists(path): raise DAV_NotFound try: shutil.rmtree(path) except OSError: raise DAV_Forbidden # forbidden return 204 def rm(self,uri): """ delete a normal resource """ path=self.uri2local(uri) if not os.path.exists(path): raise DAV_NotFound try: os.unlink(path) except OSError, ex: log.info('rm: Forbidden (%s)' % ex) raise DAV_Forbidden # forbidden return 204 ### ### DELETE handlers (examples) ### (we use the predefined methods in davcmd instead of doing ### a rm directly ### def delone(self,uri): """ delete a single resource You have to return a result dict of the form uri:error_code or None if everything's ok """ return delone(self,uri) def deltree(self,uri): """ delete a collection You have to return a result dict of the form uri:error_code or None if everything's ok """ return deltree(self,uri) ### ### MOVE handlers (examples) ### def moveone(self,src,dst,overwrite): """ move one resource with Depth=0 """ return moveone(self,src,dst,overwrite) def movetree(self,src,dst,overwrite): """ move a collection with Depth=infinity """ return movetree(self,src,dst,overwrite) ### ### COPY handlers ### def copyone(self,src,dst,overwrite): """ copy one resource with Depth=0 """ return copyone(self,src,dst,overwrite) def copytree(self,src,dst,overwrite): """ copy a collection with Depth=infinity """ return copytree(self,src,dst,overwrite) ### ### copy methods. ### This methods actually copy something. low-level ### They are called by the davcmd utility functions ### copytree and copyone (not the above!) ### Look in davcmd.py for further details. ### def copy(self,src,dst): """ copy a resource from src to dst """ srcfile=self.uri2local(src) dstfile=self.uri2local(dst) try: shutil.copy(srcfile, dstfile) except (OSError, IOError): log.info('copy: forbidden') raise DAV_Error, 409 def copycol(self, src, dst): """ copy a collection. As this is not recursive (the davserver recurses itself) we will only create a new directory here. For some more advanced systems we might also have to copy properties from the source to the destination. """ return self.mkcol(dst) def exists(self,uri): """ test if a resource exists """ path=self.uri2local(uri) if os.path.exists(path): return 1 return None def is_collection(self,uri): """ test if the given uri is a collection """ path=self.uri2local(uri) if os.path.isdir(path): return 1 else: return 0 davix-0.8.0/test/pywebdav/server/server.py0000755000000000000000000003072114121063315017320 0ustar rootroot#!/usr/bin/env python """ Python WebDAV Server. This is an example implementation of a DAVserver using the DAV package. """ import getopt, sys, os import logging logging.basicConfig(level=logging.WARNING) log = logging.getLogger('pywebdav') from BaseHTTPServer import HTTPServer from SocketServer import ThreadingMixIn try: import pywebdav.lib except ImportError: print 'pywebdav.lib package not found! Please install into site-packages or set PYTHONPATH!' sys.exit(2) from fileauth import DAVAuthHandler from mysqlauth import MySQLAuthHandler from fshandler import FilesystemHandler from daemonize import startstop from pywebdav.lib.INI_Parse import Configuration from pywebdav.lib import VERSION, AUTHOR LEVELS = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'critical': logging.CRITICAL} class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" def runserver( port = 8008, host='localhost', directory='/tmp', verbose = False, noauth = False, user = '', password = '', handler = DAVAuthHandler, server = ThreadedHTTPServer): directory = directory.strip() directory = directory.rstrip('/') host = host.strip() if not os.path.isdir(directory): log.error('%s is not a valid directory!' % directory) return sys.exit(233) # basic checks against wrong hosts if host.find('/') != -1 or host.find(':') != -1: log.error('Malformed host %s' % host) return sys.exit(233) # no root directory if directory == '/': log.error('Root directory not allowed!') sys.exit(233) # dispatch directory and host to the filesystem handler # This handler is responsible from where to take the data handler.IFACE_CLASS = FilesystemHandler(directory, 'http://%s:%s/' % (host, port), verbose ) # put some extra vars handler.verbose = verbose if noauth: log.warning('Authentication disabled!') handler.DO_AUTH = False log.info('Serving data from %s' % directory) if handler._config.DAV.getboolean('lockemulation') is False: log.info('Deactivated LOCK, UNLOCK (WebDAV level 2) support') handler.IFACE_CLASS.mimecheck = True if handler._config.DAV.getboolean('mimecheck') is False: handler.IFACE_CLASS.mimecheck = False log.info('Disabled mimetype sniffing (All files will have type application/octet-stream)') if handler._config.DAV.baseurl: log.info('Using %s as base url for PROPFIND requests' % handler._config.DAV.baseurl) handler.IFACE_CLASS.baseurl = handler._config.DAV.baseurl # initialize server on specified port runner = server( (host, port), handler ) print('Listening on %s (%i)' % (host, port)) try: runner.serve_forever() except KeyboardInterrupt: log.info('Killed by user') usage = """PyWebDAV server (version %s) Standalone WebDAV server Make sure to activate LOCK, UNLOCK using parameter -J if you want to use clients like Windows Explorer or Mac OS X Finder that expect LOCK working for write support. Usage: ./server.py [OPTIONS] Parameters: -c, --config Specify a file where configuration is specified. In this file you can specify options for a running server. For an example look at the config.ini in this directory. -D, --directory Directory where to serve data from The user that runs this server must have permissions on that directory. NEVER run as root! Default directory is /tmp -B, --baseurl Behind a proxy pywebdav needs to generate other URIs for PROPFIND. If you are experiencing problems with links or such when behind a proxy then just set this to a sensible default (e.g. http://dav.domain.com). Make sure that you include the protocol. -H, --host Host where to listen on (default: localhost) -P, --port Port to bind server to (default: 8008) -u, --user Username for authentication -p, --password Password for given user -n, --noauth Pass parameter if server should not ask for authentication This means that every user has access -m, --mysql Pass this parameter if you want MySQL based authentication. If you want to use MySQL then the usage of a configuration file is mandatory. -J, --nolock Deactivate LOCK and UNLOCK mode (WebDAV Version 2). -M, --nomime Deactivate mimetype sniffing. Sniffing is based on magic numbers detection but can be slow under heavy load. If you are experiencing speed problems try to use this parameter. -T, --noiter Deactivate iterator. Use this if you encounter file corruption during download. Also disables chunked body response. -i, --icounter If you want to run multiple instances then you have to give each instance it own number so that logfiles and such can be identified. Default is 0 -d, --daemon Make server act like a daemon. That means that it is going to background mode. All messages are redirected to logfiles (default: /tmp/pydav.log and /tmp/pydav.err). You need to pass one of the following values to this parameter start - Start daemon stop - Stop daemon restart - Restart complete server status - Returns status of server -v, --verbose Be verbose. -l, --loglevel Select the log level : DEBUG, INFO, WARNING, ERROR, CRITICAL Default is WARNING -h, --help Show this screen Please send bug reports and feature requests to %s """ % (VERSION, AUTHOR) def setupDummyConfig(**kw): class DummyConfigDAV: def __init__(self, **kw): self.__dict__.update(**kw) def getboolean(self, name): return (str(getattr(self, name, 0)) in ('1', "yes", "true", "on", "True")) class DummyConfig: DAV = DummyConfigDAV(**kw) return DummyConfig() def run(): verbose = False directory = '/tmp' port = 8008 host = 'localhost' noauth = False user = '' password = '' daemonize = False daemonaction = 'start' counter = 0 mysql = False lockemulation = True http_response_use_iterator = True chunked_http_response = True configfile = '' mimecheck = True loglevel = 'warning' baseurl = '' # parse commandline try: opts, args = getopt.getopt(sys.argv[1:], 'P:D:H:d:u:p:nvhmJi:c:Ml:TB:', ['host=', 'port=', 'directory=', 'user=', 'password=', 'daemon=', 'noauth', 'help', 'verbose', 'mysql', 'icounter=', 'config=', 'nolock', 'nomime', 'loglevel', 'noiter', 'baseurl=']) except getopt.GetoptError, e: print usage print '>>>> ERROR: %s' % str(e) sys.exit(2) for o,a in opts: if o in ['-i', '--icounter']: counter = int(str(a).strip()) if o in ['-m', '--mysql']: mysql = True if o in ['-M', '--nomime']: mimecheck = False if o in ['-J', '--nolock']: lockemulation = False if o in ['-T', '--noiter']: http_response_use_iterator = False chunked_http_response = False if o in ['-c', '--config']: configfile = a if o in ['-D', '--directory']: directory = a if o in ['-H', '--host']: host = a if o in ['-P', '--port']: port = a if o in ['-v', '--verbose']: verbose = True if o in ['-l', '--loglevel']: loglevel = a.lower() if o in ['-h', '--help']: print usage sys.exit(2) if o in ['-n', '--noauth']: noauth = True if o in ['-u', '--user']: user = a if o in ['-p', '--password']: password = a if o in ['-d', '--daemon']: daemonize = True daemonaction = a if o in ['-B', '--baseurl']: baseurl = a.lower() # This feature are disabled because they are unstable http_request_use_iterator = 0 conf = None if configfile != '': log.info('Reading configuration from %s' % configfile) conf = Configuration(configfile) dv = conf.DAV verbose = bool(int(dv.verbose)) loglevel = dv.get('loglevel', loglevel).lower() directory = dv.directory port = dv.port host = dv.host noauth = bool(int(dv.noauth)) user = dv.user password = dv.password daemonize = bool(int(dv.daemonize)) if daemonaction != 'stop': daemonaction = dv.daemonaction counter = int(dv.counter) lockemulation = dv.lockemulation mimecheck = dv.mimecheck if 'chunked_http_response' not in dv: dv.set('chunked_http_response', chunked_http_response) if 'http_request_use_iterator' not in dv: dv.set('http_request_use_iterator', http_request_use_iterator) if 'http_response_use_iterator' not in dv: dv.set('http_response_use_iterator', http_response_use_iterator) else: _dc = { 'verbose' : verbose, 'directory' : directory, 'port' : port, 'host' : host, 'noauth' : noauth, 'user' : user, 'password' : password, 'daemonize' : daemonize, 'daemonaction' : daemonaction, 'counter' : counter, 'lockemulation' : lockemulation, 'mimecheck' : mimecheck, 'chunked_http_response': chunked_http_response, 'http_request_use_iterator': http_request_use_iterator, 'http_response_use_iterator': http_response_use_iterator, 'baseurl' : baseurl } conf = setupDummyConfig(**_dc) if verbose and (LEVELS[loglevel] > LEVELS['info']): loglevel = 'info' logging.getLogger().setLevel(LEVELS[loglevel]) formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') for handler in logging.getLogger().handlers: handler.setFormatter(formatter) if mysql == True and configfile == '': log.error('You can only use MySQL with configuration file!') sys.exit(3) if daemonaction != 'stop': log.info('Starting up PyWebDAV server (version %s)' % VERSION) else: log.info('Stopping PyWebDAV server (version %s)' % VERSION) if not noauth and daemonaction not in ['status', 'stop']: if not user: print usage print >>sys.stderr, '>> ERROR: No parameter specified!' print >>sys.stderr, '>> Example: davserver -D /tmp -n' sys.exit(3) if daemonaction == 'status': log.info('Checking for state...') if type(port) == type(''): port = int(port.strip()) log.info('chunked_http_response feature %s' % (conf.DAV.getboolean('chunked_http_response') and 'ON' or 'OFF' )) log.info('http_request_use_iterator feature %s' % (conf.DAV.getboolean('http_request_use_iterator') and 'ON' or 'OFF' )) log.info('http_response_use_iterator feature %s' % (conf.DAV.getboolean('http_response_use_iterator') and 'ON' or 'OFF' )) if daemonize: # check if pid file exists if os.path.exists('/tmp/pydav%s.pid' % counter) and daemonaction not in ['status', 'stop']: log.error( 'Found another instance! Either use -i to specifiy another instance number or remove /tmp/pydav%s.pid!' % counter) sys.exit(3) startstop(stdout='/tmp/pydav%s.log' % counter, stderr='/tmp/pydav%s.err' % counter, pidfile='/tmp/pydav%s.pid' % counter, startmsg='>> Started PyWebDAV (PID: %s)', action=daemonaction) # start now handler = DAVAuthHandler if mysql == True: handler = MySQLAuthHandler # injecting options handler._config = conf runserver(port, host, directory, verbose, noauth, user, password, handler=handler) if __name__ == '__main__': run() davix-0.8.0/test/pywebdav/server/config.ini0000644000000000000000000000203514121063315017400 0ustar rootroot # PyWebDAV config.ini # Read documents before editing this file # Created 11:48 10-08-2006 By Vince Spicer [MySQL] # Mysql server information host=localhost port=3306 user=root passwd=rootpw # Auth Database Table, Must exists in database prior to firstrun dbtable=webDav # Create User Database Table and Insert system user # Disable after the Table is created; for performance reasons firstrun=0 [DAV] # Verbose? # verbose enabled is like loglevel = INFO verbose = 1 #log level : DEBUG, INFO, WARNING, ERROR, CRITICAL (Default is WARNING) #loglevel = WARNING # main directory directory = /home/spamies/tmp # Server address port = 8081 host = localhost # disable auth noauth = 0 # Enable mysql auth mysql_auth=0 # admin user user = test password = test00 # daemonize? daemonize = 0 daemonaction = start # instance counter counter = 0 # mimetypes support mimecheck = 1 # webdav level (1 = webdav level 2) lockemulation = 1 # internal features #chunked_http_response = 1 #http_request_use_iterator = 0 #http_response_use_iterator = 0 davix-0.8.0/test/pywebdav/server/mysqlauth.py0000644000000000000000000000363714121063315020044 0ustar rootroot#Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de) # #This library is free software; you can redistribute it and/or #modify it under the terms of the GNU Library General Public #License as published by the Free Software Foundation; either #version 2 of the License, or (at your option) any later version. # #This library is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #Library General Public License for more details. # #You should have received a copy of the GNU Library General Public #License along with this library; if not, write to the Free #Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, #MA 02111-1307, USA from fileauth import DAVAuthHandler class MySQLAuthHandler(DAVAuthHandler): """ Provides authentication based on a mysql table """ def get_userinfo(self,user,pw,command): """ authenticate user """ # Commands that need write access nowrite=['OPTIONS','PROPFIND','GET'] Mysql=self._config.MySQL DB=Mconn(Mysql.user,Mysql.passwd,Mysql.host,Mysql.port,Mysql.dbtable) if self.verbose: print >>sys.stderr,user,command qry="select * from %s.Users where User='%s' and Pass='%s'"%(Mysql.dbtable,user,pw) Auth=DB.execute(qry) if len(Auth) == 1: can_write=Auth[0][3] if not can_write and not command in nowrite: self._log('Authentication failed for user %s using command %s' %(user,command)) return 0 else: self._log('Successfully authenticated user %s writable=%s' % (user,can_write)) return 1 else: self._log('Authentication failed for user %s' % user) return 0 self._log('Authentication failed for user %s' % user) return 0 davix-0.8.0/test/setup_test_env.sh0000755000000000000000000000061414121063315015712 0ustar rootroot#!/bin/bash MY_DIR=$(dirname $(readlink -f "$BASH_SOURCE")) ARGS="$1" export ACTION="start" if [[ "$1" == "stop" ]]; then ACTION="stop" fi OPTS_SERV_1=" -D /tmp -n -d ${ACTION} -P 8008 -i 0" OPTS_SERV_2=" -D /tmp -u test -p tester -d ${ACTION} -P 8009 -i 1" export PYTHONPATH=$MY_DIR/ $MY_DIR/pywebdav/server/server.py $OPTS_SERV_1 $MY_DIR/pywebdav/server/server.py $OPTS_SERV_2 davix-0.8.0/LICENSE0000644000000000000000000006364214121063315012344 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! davix-0.8.0/README.md0000644000000000000000000000610014121063315012600 0ustar rootroot# Davix [![build status](https://gitlab.cern.ch/dmc/davix/badges/devel/pipeline.svg)](https://gitlab.cern.ch/dmc/davix/commits/devel) [Davix](http://dmc.web.cern.ch/projects/davix/home) aims to make the task of managing files over HTTP-based protocols simple. It is being developed by IT-ST at CERN, and while the project's purpose is its use on the [CERN grid](http://wlcg.web.cern.ch/), the functionality offered is generic. ## Documentation Visit [https://davix.web.cern.ch](https://davix.web.cern.ch) to view the latest documentation. ## HTTP File Management HTTP is gaining popularity for file management tasks, beyond its traditional use for serving web pages. It is versatile enough to be fit for this purpose; `PUT`, `MOVE` and `DELETE` requests can be used for basic file manipulation, for example. (uploading, moving, and deleting a file, respectively) Some common file-management operations are not possible to do with plain HTTP, however, which is why the [WebDAV](https://en.wikipedia.org/wiki/WebDAV) extensions were developed, which davix supports. Davix also supports a plethora of authentication methods: * x509 user certificate * VOMS proxy * RFC proxy with VOMS extensions support * username / password * AWS S3 compatible services * Microsoft Azure compatible services ## Usage Davix provides a shared library as well as a few command line tools. The library offers two sets of APIs, a file-oriented and a POSIX-like interface. Here are some example invocations of the command-line tools. ``` # upload a file using a VOMS proxy davix-put myfile https://someserver/dir/myfile -E /tmp/x509up_u1000 # download a file from an Amazon S3 bucket davix-get https://mybucket.s3.amazonaws.com/somefile --s3accesskey [..] --s3secretkey [..] # do an ls on a WebDAV-enabled server davix-ls https://someserver/dir ``` ## Compiling 1. Install the necessary dependencies: * cmake * libxml2-devel * openssl-devel 2. Compile: ``` git clone https://github.com/cern-fts/davix.git cd davix git submodule update --recursive --init mkdir build && cd build cmake .. make ``` You can now try running an example command: ``` ./src/tools/davix-get https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.0.1 ``` ## Release tarballs To generate a blessed release tarball, run ``packaging/make-dist.sh`` from the root of this git repository. The tarball will appear under ``./build``, and will correspond to whichever git commit or tag you're currently on. ## Development The official repository is the one on [GitHub](https://github.com/cern-fts/davix). It's automatically mirrored on [CERN Gitlab](https://gitlab.cern.ch/dmc/davix) for CI purposes. This means: * Use GitHub for new commits, issues, or pull requests. * Please don't commit directly on GitLab. * After a commit, GitLab will mirror the changes automatically, and run CI. Treat Gitlab as if it were ie a Jenkins CI instance. ## Contact Suggestions and patches are more than welcome. You can send an email to the [davix-devel](mailto:davix-devel@cern.ch) CERN mailing list, or contact directly the [current maintainer](mailto:georgios.bitzes@cern.ch). davix-0.8.0/dist/0000755000000000000000000000000014121063315012267 5ustar rootrootdavix-0.8.0/dist/CMakeLists.txt0000644000000000000000000000052514121063315015031 0ustar rootroot # configure abi checker configure_file(${CMAKE_CURRENT_SOURCE_DIR}/abi/abi_checker_last.xml.in ${CMAKE_CURRENT_BINARY_DIR}/abi/abi_checker_last.xml) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/abi/check_abi.sh.in ${CMAKE_CURRENT_BINARY_DIR}/abi/check_abi.sh) add_custom_target(abi-check "${CMAKE_CURRENT_BINARY_DIR}/abi/check_abi.sh") davix-0.8.0/dist/abi/0000755000000000000000000000000014121063315013022 5ustar rootrootdavix-0.8.0/dist/abi/check_abi.sh.in0000755000000000000000000000127714121063315015665 0ustar rootroot#!/bin/bash set -e CHECK_ABI=abi-compliance-checker LAST_ABI_XML_FILE=@CMAKE_BINARY_DIR@/dist/abi/abi_checker_last.xml LAST_ABI_DUMP=@CMAKE_BINARY_DIR@/abi_dump_last.abi.tar.gz echo "Generate new ABI dump...." $CHECK_ABI -l davix -dump $LAST_ABI_XML_FILE -dump-path $LAST_ABI_DUMP echo "Looking for abi dumps in @CMAKE_SOURCE_DIR@/dist/abi/abi_dumps/" ls @CMAKE_SOURCE_DIR@/dist/abi/abi_dumps/ shopt -s nullglob for i in @CMAKE_SOURCE_DIR@/dist/abi/abi_dumps/*$(gcc -dumpversion | sed 's/^\([0-9]*\)\.\([0-9]*\)\.*.*/\1\2/g')*$(gcc -dumpmachine)*.abi.tar.gz do echo "Scan for $i with $LAST_ABI_DUMP" $CHECK_ABI -l davix -old $i -new $LAST_ABI_DUMP echo "Scan with success" done echo "Finish !" davix-0.8.0/dist/abi/abi_checker_last.xml.in0000644000000000000000000000162514121063315017417 0ustar rootroot @VERSION_STRING@ @CMAKE_SOURCE_DIR@/include/davix/ @CMAKE_BINARY_DIR@/src/ _ZN5Davix19httpcodeToDavixCodeEiRKSsS1_PPNS_10DavixErrorE _ZN5Davix15httpcodeIsValidEi _ZN5Davix4HookINS_17HookReceiveHeaderEE7getTypeEPS2_ _ZN5Davix4HookINS_17HookReceiveHeaderEE7getTypeEv _ZN5Davix4HookINS_19HookRequestPostExecEE7getTypeEPS2_ _ZN5Davix4HookINS_19HookRequestPostExecEE7getTypeEv _ZN5Davix4HookINS_18HookRequestPreExecEE7getTypeEPS2_ _ZN5Davix4HookINS_18HookRequestPreExecEE7getTypeEv _ZN5Davix4HookINS_14HookSendHeaderEE7getTypeEPS2_ _ZN5Davix4HookINS_14HookSendHeaderEE7getTypeEv _ZlsRSoRKN5Davix3UriE davix-0.8.0/dist/abi/abi_dumps/0000755000000000000000000000000014121063315014765 5ustar rootrootdavix-0.8.0/dist/abi/abi_dumps/davix_0.3.1-gcc43-i686-redhat-linux.abi.tar.gz0000644000000000000000000037450014121063315024506 0ustar rootroot‹_àäSÔ[oã8²Ççù|Š~X »ÀN`ɉ“<ìÁö¤½³A÷tIOï9ûBÈ%³#S’²ãYÌù쇤d[ò-Žõg¢˜é\,VñREÉ(˜²G"U4¥B²ŒŸ#öø£§?ƒ3ûïEó_Ïóúç¾×ÿÁóûž7èyý‹zÞyàÿð®‡dÛG!U Þ½û!ˆèTP)wýÞS?£úöþÎ{÷·wÿù¯wË“÷?Ýë/¿Ü~ºyÿùzH®ÿ9¼þ8¼#߆w÷7_>Ÿ¼ûÛ¿;ñN¯®N¯Nþºþw~ýå¶ù›ýSí×D8.ôx9hþè:ãÚ\IûóºP'Þ»ùòÓ§/×ÉýÍ¿‡OÿÉNÔ?©6¯(eŠlPóœÊÓqž7ä;œø-H ZÏzWƒ“çCþØ[pUûO_~&ï?}:²ê[êfIBÅ‘¯×úÏÿ÷çÞc¯÷—¿<·ê×ûúîæëÍõûc+_âÀ(¡55aüg¨áÃð§_>Zx¬Õþìùµ?¸ê_ïÞ_ßíWýÒaÕõûÓ—ûcž“¦¿¦ÿ˜–° þõþîóÍçã›þ‹¨Às¦‚_Þc&?‹„O€–ZS…7¸¸¸ð½c&Bóñ„F¾Þý/±Z9B ›u׈*¤ ¿Tª#TP¯·óçTùÝ¿ÛPÁÉšßÏ'£,=ÀSzw’²Ñ(ˤ"r.ü8Q§2;=o×h,™üûó¹EJ´wF…È E“LÌ?ô†S[Œwt3:¬ï…Êñ•s•Ð…y–…¹)ÊÊ©`¡ã²ŒöB¿7 (©™ñˆ)i?ß{d`~NÔÐEÙ5ÙL–ì/[Ã?îm^Ol¤”«áÝÇÏ÷=¢¿UU9¢Cªâ3¤`•çëšQü~Dã HÕ†áAªøzSÙÛóyÆÃ,Ÿ£”Ï«}…2þ²¬•­ÊñüÖÝ\©þVØþZõÛ×êÛaµ­QÌ8¦qiŽ*AÇsöû,µIYSÚq1){½4 ÊŸ‰pôôÛ€£ç\¯—gÒø¸lB=/ÙÄ~ªç¡\Ž‚F$Wâæó=DT,õ¥ÅI¨€ŒI‡ÃsA%UèzzjÌdÕ¾¼KÆ•Ög‘›A˜ä™þÒey~/bÒ^õr¯á å€2áíçé2ñâ€2׳Ñ~(7åGnKÔBeb£Ý·f»°žä!âøÇu»ÛZ¦Ûvç7Ú]–»myç2¥4·n<©Oç¹ù¿C£žÏMVm`‚?/ÂéùlFƒ3×á]&ÞÆ›xxs>·‘(¡!µØøW‰0®/ ¸7Y_`N²˜L2®ÆÃápz÷ñ+ÁJ1X–O*?¤¦§ÖÁ›lqpî/nÒűIžÞذûªŒq3ý¿ï4Ô§±|³µi[_PùG‰÷rÆ:J¼.÷‰nÝ-S?)l— ÿ¤°Ýl—FÖ9 º×ÑwÉØM£7e즭¯ŒŒ]ïêkBvÓÚkBvÆÜ÷Êë‹‚ÛÕ"ûóNÙy«t1ðVé^À²‡z/aǃey«,Ë+Úhÿ¤ÿš{B²W´ß’ušµÙ¼F¬ Ô ÛÕê„ÉêSr7lÖ¨FkHôZVÛœgÍ’ùÇû¾óõ¤CÅñ;%Ϋ5æ-¢¼V+Þ"Šûæë÷LF)7Á—?Þš.Uûò㽇n*Õþë²M`£¼i7Š@›Ì÷ª"•Y!Bê(“`W9h•í*®·ëo~_špˆ®¬Cò,eáüF}RÞY¯7Ôÿ˜ƒPÃ]³þ¥Ùdµ]Q)TMY–Õæk1ÁîB=)²‘×îœíº'mß>é ¿¬Ô‹ôßlÁ))mþ‡ßÀ™—‹RäZ)v/³‘bv­Ío„) x‘“¸à¡s‡ÃÛéÈ‘T¥a¦g|ÒîÖRà)»U)ý˜ñȽ!û7#Už…cN«T¹³öù¬ÍRΨ$µµá&_ÕUmÎe^šE›ÇlÍ]DT*‘Áów‡ÏGßU«¶½Q«æ=¢ˆp:k´‰g"n«uˆI¡ècÕ'ü3tAëyzÎZÏfI®šÏfI®ÚÏ…5S’f£ -­KÅ_+¨Ö#ŒO@òrzKš¥ç™¹7¢)UT˜(T]™ƒN6r£„Ãe»ˆ˜Ì3ý™#s.‰³fþ\u€çÈà¨k¬¥R†c>P|¸³¿4Wuë›BP¾Hm/ý#GÅÉÅÝî°ª)ÎÌ\¹ŒÇ™ZÍ‚V ÿ|ÛÏÊsnŒ`ÇßœŠ¥`v ›¡J.£ˆ|Ï™´ÉEÁ¾¹¿cayG•ësN)nnÛB‚®{L18‡IòD ÑÇõ¢§‚ˆ>®wD z0!6‚×Pˆ"ú¸Î·;Šðq3Òž(ÑÃwDí•ômOѾ1}ÛEù‡D€0ÿéòZDÿ!ßQDç¤ÝDtNÈ­AD¤ÜD¸ï¹Ûí#š#„9lâ•EÛ² ñÊmÛ†xy‘voC eÙDà&¹ýî=° 'œj€×´^ÒΕy|¥žïTë»éTãšàN5P{œj…l:Õ€R¶;Õò˜ûgĉ«ˆËis)$,;®ò >p)):UÖÈz‰0ýË=>ñr"CÛ.XdGo;8—´Ë:uõ†‚{Q;¦U·O8”­Ç7wÀëåäv4“½•Ã^ÎÅ} úuyð˽¼Õ°ûC`u Ó·~½…èkŸŒ/ÿÎ J ¤†Þ^ õöâ¨7F½™(êíQo'†z!Ôˆ ö‰øÚ¯v¹¯;ÚsòJTªîèÊÍóTX±^U[.>ɃÒOÌ8æ®(ÍQP(¨¹±¼²Þƒ s·¼È¼Æ5»¥pµùš‹ì"¨Jµlæ¡‡ÂØ¾$üc¿0')…?ú§ž*Ë[Ýÿóì²NÈð‘©¿ÿýçO7?]Í:õŽÕà ¹ùB|â©"ÝÐI Zm:Ÿ‘ \§2îjvbÔ ú^HEÂ,-&|ÅíµÒj­SýVÔˆÆA‘*eAšf¡î¹(yd3@É1šš‚ð!Ö.\Äi6CCeB¬%¬¨y¤fd&XÝþíF%%žm £"FU8ÖA‡„U·¢D‹²œr˜h% $Íp°¾Œ§n ‰uÍ398C´+ Ȫ%,P{f –R(s×>¬KÔ@!×F‘4¼3 ((Þ°ØuïPû:¶®ˆÀZ›X *¡ü^Lòþýãå§\V̦YBfS*šÞ@“K(PPBk.)}€³8†jrÁ„Š©"DJ‹D ©…5Μ‡Ø: PÀ‚Gz⊠Õˆ@×Ã>€Œ$¤9Íi°°Fnüz¢Ý 8¤ŒSݽu Bq#0Ô¿@º¹`\á¢7Ýfp>>t4w¦š¢"'C¹³­à–Á—D›lJl°)¡Á¦¢À±A‰9|+8¹6Qµ£éh=²Ì¨ ÆÙ 5Ô Š\œh†jíYdˆ [³ÈÙ:³]ïÕ OMlÂ) ¼fw9}T(`J 7Œî(„Á‚è”i·¸]?æ[  qÖ@Aõl§–C6 YÚÙ<Æ­`ÞȂɬûÊCØ›¬ å:È­ÍqvŽt°s ƒõ¯s‘…ë+Ê-ëº"E„Zc  Xàd¸#è$›Rð\oÔ Ék,úµÇ5bˆö¸Y³ºíÆh³Ò‡N•Ë @à¸÷ ÍGØqϬE™ÖqÀYk*2 8®Âë¹R‹í”#nƒXiR^3Cª=P”‘‰YõÉx:Ç©²›Ev†kA»¹›Ôž Ïb2Pô°­‘[ð[B Ž\s(qÀþ=cÊd™ff©€L²æ[¯È“@÷Ñ™á#WW|ë”5ú¦bÚ¡ nÃW”ž±í«à2Xºk0¦¢Î6°í49¯óOcèl7» ³})¬í49Û•Ã ÂnþAäµ,Vu=†mnh¶Ån$²¶n¦ž¶DnK¢ñ[&ÑÌv$½ DÝð) ÐFÞ‚¸ÅOA`Á tûb`Kh3zmû•ÏÈ?ìÿ> 5óúšôÛ Ò„ŒÄ ¢h#>n%™£LhïC& ÞíÝÍ·÷_‡­˜Ñws<ë2-‘ 6“LÐPÿGÆY¶áÙ+§H~//‘IjxÍÖ820ž°Ö‘`Ãch±È¸¤‘p\³Ée+¢y…Òù*Å„ `^KÄqë¢Db§W8=+LFY*aIÈ22Áažˆ¤Ðß©È0¨pLÃ"Æ™T’lË:8rìÑ=f­õOÏÚÈiNýƒª ˼'¡žXTãÍùêH`Æc³ŠÒpZé-㜆 ;Tóœö}2µ‘ §2í†Q±îݶ…y…B«MFf§³Ö;Úš¥\~‘°ÐÎDòMJòº}µ¯h¬"©E%-ÄhsãíX(ò[ÁÌ«(Í£Ù­ o¹kÀvÕÖĘñ e¿Ssž˜màò`MÁCBÍ»Uïj“ÝPFtÌS–Œ7å#Û@ꮯ`nùb©e‘ ¨‚&LÚd+LQ×Rÿàh{ã¾DĹÖfl±>…y¢"÷Aµ,r³h›‚âÊ£‰/8¨WS>e"ÛØ)?²SëŒgÄ®Q³MèqÆ£"–á·M}ã+P€ǘ’ò,1Îy.qez°ÜXΙAÍ9h¬.Y˜½œ †j~é³\Mâ ”ReHŠÅóF ]_º<’šëAñTÛmSE»0?Î ²*‘m¦uÅŽ!Š5äYGÀ䋘ƒÜ ßgjêð¢5nûPКk^SE©Rãp-Ñœ¶®œÒÕˆ«´s\…gÛú^«žg6Bö58\uM§y[Ñ ¦}„Ò®XÍŠ¶²iÅÃÐ’€É’ß ZPÜ””èá~j¯‚”’D#ì0ÇN„ždQ‘R°ØF`=Æ4P… Jg@ÿPó"š² ¦ùZfrݸ™f‘B&"+r Ã­‘fÇ.gš%Œàò¿f–1.-‹™}¬ ¡Í0²¥Ñó„aüX%‘®­YðašÅQÚì6Q²3O쥳 ·vìd ƒ™^¤fñ†›~][¾i?<.é&w­¢¯ôäËH—AÊ‹ I1>«Áå㈓!c8Ü( øê 3âÌæfÈɈ%LádKDq8Jø-QHh}ˆÉj³¥1 †Cƒ‚iL³`Ë«+²ž Þfýaœá™ˆ*¾‘®aºÔÒÓEÝ0±H»…ó‚‡@œÌMN Weƒ p3°Ï6;m3°›5ûY³5G«Ý¬UÒ€Ò=·Øu››x(˜Ç‚x0˜¡GƒGpƒó¦AÊ¢B‚î*0Ͻˆ†bž+I¥4OãääÓ—ë÷ŸÖ>r#Ç”@¹ëÊ#*¡XóV ))’°PµUí jlE‰P’%˜ö±l.º™ÖÎY‚¤m)˜VXS®Š('£"._%B \»š¤U"T#?·µÂ×Ñ®TÞ(†aîñÙŽvTƒ(-_Ô"JFptãTŒjî7jœ‡‘å|fÆ €¹*%³–PƒB ò—¸Ú 7ØKIb&$hWÙBÓŒ'ß'9X—= ãRn—HèÈn9R—ª™,­á•H™ˆpжŽL$Gtyõ^ý2Szж}Þ8ÝSW,¦Ô;èb¼ È7^ªÀ§@7‡VйT=UÍtmxÁ¡ µ4Ts×kÕ`ozšx•"¯R`âU9é 3+¢%™=ó…D zǰT6µåÉHr‹æÚh¦$šX¹P+ÓI˜ÏÉh^;>Óê½Õñ L Ñ<\ÚMEL€ÚûX±"æZFP,aàf“ãÛM…äh$Þ0DNW›·–SšOdŸ)lôiwKEvG „Ý'êLœ¨3Á©3‹PI5Ê`J#`˜8ɸ@ ÐE*»Î89có€g2¥´&:h!§3ä1ž’4à‰=ÉŒ¹Hp)í¥%,)Õ±Lö€²!G Ì‘k<˜IsÖEH Ù¦šWòúîÐ8U,ÙíV¡VMV¿»¾}ë(¯r¢:§&#iÉ´IÔ“¡1ps%X³¸[Þ -¤œEnÚ@ƒYR1e!uÐp3|áAß³°àNáàœrÔ PÉ"5·ªMêì`KBJEB³–m½uòxªY;CJ( yã=É*¥+ÏRPîKžIöh†4ö’Z]²”›êzÏj%_ Ã-iå›çÒÛáÐwTÄ4ê//{ô·‚ò´£± ßráÑ‘!Ƨ] Ôkk$WÒ"çË7TÛÁÌ,ãN"“ "ê–aØ‹´Ûé ;ô'kk.çí˜èíƒÌ5FV<œbi±È&Hbu[Y š·Ðô[9l.nmsvg›ÓÛ¶Á×.Ìp‚wV¨ð’0pœerÔ‹†6 æ# N\1\¾v£p[99¶Ú"àQ6A‹7D{HÀ|™ªQæÝêy¹¾úÔæàl-§!‰#I•#¶M»Õ±FýÊphX¸Ür푤pln™Ê‹µŒ˜6Áä’¹övA›•ô%³™þÙ^LsY‹ŽD2íïÎq/oc£r®–ì<Ðó˜i?)RÔ ‘’+q猦 aQÒÐl€h P>E!SØÍí²ñbz;’BÞš*‘׿H–!‹š“FK\DS$ŽI`}‚%|Ô¸ð»= ôKE-åiZ¨7 4MÛ´–jÛWȼÑ_ÛÝ’.9~ímëÃ8-‘v÷bóÝ–Lc^KÔ,\’VÉÂj/‡¦¹U¿ñ$ãÀžÛK$ëï¾µã¥k ŽŸ”9~ÖãèiÛ Ä2X!aÙÑ+$ìÁ‰¶¶™\ ÖiŒ8í‘›7y¡“@IDN%©BKDá®'Ü÷”4'RBôÑÀ>U!Úƒ;`pÿ î~¡½/û *ˆä©,ZÞ óë çã¨,v!b ñè[v4TYêB‡È¸YÓœ4ÅÛS7ŠÄjò·•Œ0 '/°/ܘ§Û§ÀhJ…l, ·3c»VÂ’siÿ" S c‰š•f ´¢S» ‰jÑf•ä÷-OÚ™ïª2èë Ëç¹Q8è=©æî%ºtm‰ÊVöžY¥æè|õûÖ3—GÁþŸ½?mrG²Fá¿Òv¿ô½6Vi¡5"{ïk“•©¬ŠÉ-:µÌó…F‘Ä ŠdqCõØü÷ €”DRÔBá8¨ÌVÛLw-©s àp8 ð9ãw+)^ŽO<ya*‰vž+TI».ÍÚó}•K„Kø»ÒËr™{Gi½X¼eºóº‚Ê^â_|¬½(ªØäu­ ¨Ñ¥+K‚Ú•Ç$ÔZÿÔèxh 715Paœ@‚½—Z»•:JÍ´Àe+©Å·2‹ 0‘IÄk!p³.à°_$‚‚r<ô¡e‰ý$èa-• HÇ$€Ä'osPÜ·Æ'osP¤‰èœQ 5‘äKãr£MGb{? á™Ñ5*²ÙøÌèg&2å˜Zèàd'S£²íþ÷”Ö©—*µ¶VlTÐÖ)0*îjÉ(}bøF¥()¯8y`;kRJ*x¯‹Ïm¢2¬¢X·Êx fòN|]Æñ|ÄÝKAJ½'kj5ÕÒ P1v¤;NŠÝLâ9óbÇ*Ý0W°Ív Ó¶qxs¼…¼—Ì)²ò(+˨Ü_1ë…-%ÉŠò*Ån8ïȉ£"ŸâpK$ó–N¸{ô¼¶²WPnjê&ÑÜ`LØ7ì )“î¬ý¸½á9ØùCD±kؾxí£ötgprù]¥î\X.3=Pmý¢¢6 åñncS3qcþeÂÚ¾ëœu4æ­¿‡1q<Ûñff€sÜE43dJÈC©b M¡¨&4:ȳ°pk\y‚Wу”=š‘¢Pt±ëèî ëžƒ— ‹BÆÄZ¤týH¤m`&ïwÂf ™Œ¢Ñbž [ò=˜®Ä10&b_ãz,µæ‰‡ÑŠÏ0UWóF¤Ð š×ýÔ?Ë­ ­[ÊaEÎߘ/÷Ä<øç–.æÂ3Pc ZEBþÐuŠ/ vòôoT1«Žâþ¬\‡˜?©;¸ÙØ[#žåÎêû9b÷¬¡(½’ÖúÜm „C8ï0•ŽwÀzH°¾"˜x@¯4=zkûºÃ³ÇÞtgU>{¤TóÒœôçU“—ü!°Ìa’,7'~‰ïÍÉNØ}Œe± .ÞvTÅBY¡Ú‡±È¶«ŠSJ`[2¡¨†H®˜ö7qÔ±LBAäL{izÆ,× !"q¦Ì͈OAL³øŽk4HKÃY ™7’DÉN©òYKÓ؇$%šÐZJBHªUâÍ™ÀÀäî‡ú³Ð\“d&SÂ%7§úUÖàâHI€ \ÉVE—J®Ø–Dæ õÑþ 4%%ßFAöP^€d%,ÿ˜¡I5]0´ûlæ2 …ì5MPÄ!ð/b°õàoØ‹JL¤LÐú.ð¢8t¼™3…¤*ÌÈ‚ÅDæZïúR+–gB dï€p0›­Øß}Ÿä, $žÛ,Úñg ëJŽ8cqÂQm$fð6Ôó=†ôå2ñœW:ÈõÉzbZ/©Czs&έ'¾ ¹=¸jL!ã Yß2IZN,#Þ9±å98ÊÁ`Çà>=ÎW-ŸÏfѸÐ|¯± @»K·µ‚ˆy `ÙÀ+Ò“ˆ™¡…$â†/èoBžª±*¯%¨!…Š/6tþfòxÚ@y Ë f ",Α"R\y¶E¥}±xú…zÕÒšX|M^˜îšò:QÀ0'ÌÎÂ-ÌšëÔêxÞšFØ>‹°}&žÕ€¡Ím²K³æS×Ü­k:j©`¶æ~º“Ò;aPèûhBTÐ… 'K2¬3 r,#ñøJù¤®“Ð7mËŒ@ÝÇq{) lÂòA])@9œ‡‰]Öp@ë"’6GàFGØVóå &¶E g‰'bj¨°Á(ѼØ7±hÈÎãx¢ÿ €‰cãîK2³a·ªP|ù6¡xí;ÀWfaÂW„» œp$H QÁ·Ä5.(³*„ø ]­i6 1ƒÓµ6MéDìüFnð ûÒ©Çf±,VÁ0XÍÖX´5…UmeH AQ)S²Š#¡¬*—¨Œ‰„hž21¹‰©åÅ Lx KOùÀ4£•©ÜžÚ æìrù±2¢u¨äª¦ ÃÜ·8ÐÚÄ)l‹™!ƒE"SØÝŸ ÛÎ)f ›FIqƒš±ãiPM—«™;8Ù€œ4‡ ü#X²ÃtÇš…ê-Ô9Ó ÷%1S[Á'îÜjƒVì7U<ÔAØ ÷Q‹ûÔ&AZç×!a34­sj¯|'YT¦?Ìq¦Ê>C®èŽz®!C ³³ú¸O‰*|—@âsBÀ„¼miW¢0òñ"šAü¶·0ãâ¦K©ãs0@g‰žÂsOa[AÔNPàX¾ÿâ@žé(Â!ŒÃ\£Ÿf\7Vƒ•xNƒ´‡@X'Ï1ÑÂFw£H$l 11ŠDÂW>¼Rø¨ûQAÄŽP"t¼)&~âxÎT Fh€ÃáÊŒ§Y-.V p©ËÀ@árÒ&0®[ aÂMØ;×Óˆ1Ìz)€|Ð0X $`ê(¦Ž"\ê(‚¥Ž"ä~TˆšN#Ôˆ`˜Ê¡–PÖSˆŠÙvƒª’%jRK, èÚÛ4ö1¾/o§VAdÛ šˆÅ“ÁŽk‡ uZà¡®Õ 0XÁ±`±o,/’b RÔ(ƒÈ4M³ˆ6¼1¹½‚?=¿¸:ÃÂÄà¨^$ulLæ$­æT°PêfHØ^Z xÏoçÌt6OÂ"L›jZf,6Ìe0_‰×èf êL+ åI¬í„0!AûÂBÉÇGa¦.V;ï¨zAè[`4•ðÏLc8q9v²Ž›béhTeFWQq†‚\ pèFg![=…)j€srPCÁÍ󽲄ÂbÂÑR”]6H†+‡2ÊÏáI¸³®­ñ0Ë/c®yI`9b± J• Q6î} ú\@è››Í0H £‰)˜Q0‘‰…Ú:I°(`(?Žûˆ°ÂººBÅUt2Ùi ÚÐ d÷?°†r,hC3˜…ÚD…3 ·&@«BÇ/Ëo+Âù±]k ˆ@÷[F…š,&°¨¸„IÐü5.ÎXÜ"´†C7¸ìbt›P2që…Á¦!¤öyӹê×L‘Ÿ2Åe\%´¡ÀŒkâj$´¡ .‡²Qp0\·…®³pbØ èâŠ24¨i ^ ,h`±Áà"&ÐHdHQ@„7NàØ7`ØWކz8[ %B%†Ú-FÌ YŒ q„¤>Ôlä 48Z¶€ðvç 03qþ G·èpZ93¬TŽ„+ÅÊ0 m°(-ò­¤{áp¸Ä%ÉLiV#€¤:½ää p›=‰m(p³%ܘC½¬' œ󧶉 pÏd`¸áÛ5BßÃxÀã±zxœà*3Ð.`•B´m}R@€½ÑP%e`äÎ[†Uþ Jh¨”+FGg—ú“ˆ¥«"êXpQ~&Ó0sý (Ó—!Æ*‚tÇ1ÞQ,ô Ìy+Gr<˜Øk4ˆe ”(B†òû^bØli,Ìo~i 0^7|V²%Ôñvòyj¸ÎÄ2Bæ2óD@ wÉ#.LJˆÎBÓCŠ wcÁ`IáÈá{pLXc* æâ6\ùZ@öS÷æ,8¯æ…´³n×ÍÍhá¡*æÕ—ø”¡0~en³(}̧̱@–ÁÞ5Û]`]Ú„ j¬uÓ£½Â¡øÿ¡xl ‚ J]¥P±EX “†-J)v…ö9žå‡ bÔ‹í`ƹÂä›8TÌŠsF¥yS K$TÅ‚‹ ¸ÝºUFCb•žÅî(LŸ5m§ÛT†F¥×TƸӠ}†k%*+¶É'‰9Ð[,Ì“ÿH‹|Ì!•ÀaúÚ·Å]*ׯ$=|O¤PB.ûß°‡qú†¨@9àfö‰×‡¦ kK´.‰ÖEÈP“0*Î+ ¬ bÒ HF³Ð‚}q¤s˜ºˆVfW‡ â¾E¦ „B­Y‰‡æÜM¡ºË3=?rƒ–+£u…Lb±X㉋ ¼4;~D,xÓH<ߪò¦qZŒhTMr,@M‹Ū&! ÚQ”?ßÅ{h¹†kz3ÔINSÏêá–}¹ì{±?ÇLI2{±P ùVÞ9) V—?[†+ÊÚ?ü ³ÔµoSÓq™mÌùvw‹ÙÏ:ÄY°W'–øI¸3㔀QBÍkçBÕœœŸ˜aÄrçcLýpaBf¹xµ=µ» + Ï-sõ<0LEN“ÞÍ‘&Át“9Rä{¦ zh=pV(=_­Ia Zú±ú~1œWù„|{-"$þ?pp‡z6Qâ…‹Ø%$è”Rb% ͵%…! ŠœWÊÊ’BÔv½ ª¾µ-!"öÊk@±S0cxË·°pSq­ß)$UÜ)§QE£<@yS‰f 4PÂS¾Ó4LKèøFB™°²ˆÓØIÐ¥æ(»+Ž'68Ê•‰QNd»„æ‹ôÔ5gv eG‰À#kÎl¾(nQ |×±¨ú>rf6›š‰K2n2‚…½P SöˆpHF”C2¢’ùŒ¨‡dD5$1_´~ŸŸY BÐáV2ÓÆ$% hY2J±K*aœ'”ÊwET:lW½É£€éóØÓXÆ·l)â~ùòDÍ;ìçåçv±£¹Æ@†ˆ¹ *Ÿ€{&ØE«÷Ê_ÏÅ$1êcA.l›Öv-¬ ïxs:Ù F_·ö¢Ñ+ /Þ¥‹ÀåMÁÙ쀂 hG_D<úöD~htšÑŒ>Ë÷lcú¦m™Å‚&eœ=Ø`£wü+Ìä52ØàêãS kÁ³\bV—D˜±90Ø\Q/b§&I÷n±ÁFÙK`*U8³ÁF]^³¿l@‡*JYã‘A‹$f¯ß*F¨ UË\FÅÕH¯qù³iÝàÅ–éYÌ…ÇRd”Ôs=pQUÞA¡ÞëÍ¡ HAvÄë'Ô À˜ÎMLG…6y» i2³ÁJâE4!@¨”aîuq,Le Ç™•;] ,À50‰]ÇÃ8öZFSúŽ)Ȫ¢«!jfµ"bÉë¨ca \Âd¦‚4tÊ…$ CCbá`§ë/f-!S\anpü5EÙ4ÅÙ4CÙÊþ$P±qwçC%,\ŸTý+qòë˜1šø± :2 MhŸ¸²„ÂÁ QäC6ʪ´*¤t¾ ­¦Ó9èýÏ–×È¡DÑÔÔŒbЭÞj`Æ1 !k8*{e%›C-êþT°Œ‰â³Ñ^×WÌ0 ·'غƒµWh_†l&Ô¾CÈž$ÇŒV^l¾¢%˜!nÝø곘ÏÂqÌy ìü:ff;!Fëh ðÃk,²©(ÂÁŒC}MZ 9JØ…¹êW©2R2 µ‘PânheX³&¥‹E*HÕ3 AÇZ”d*³šƒE[Ÿ|EÂY3ØM:U ‚zJ“0ƒ˜…ºÁ¾6·HÅË{¥7·pØRÌ))²àÀ£€Ytèå#p€œ¨¸7ÍbÿYIø^É¢DZÁO!p¸¿au5˜ç#¡ÖéUz²¥ÿj` zB)C‚…n°í)‚% 8tÛÂ;Œa¶U TÇ–añˆ+fuê áY¸ŸCKÔÍë jx 4}B¡læcvª…MH L‹&!¤‰‘eºr!<‡š±\$jË 59$­Ï¡?¢Ú…EÈT+H¶vÕñ`%`DùI2Ûù¨¡¼³ÁU¾YbjB3àˆæëG$_?‚­ˆäk­æB¢÷ˆ1d†„IºŠgèPþv—.b žtŽ1 ¤'Í‘|H¦ŽÉ‹E4¥yÉ0ÛT#R*%µe4H”DZ@WC„g…{u3•r¸I‚ ƒ$ÒäLùb_}ÂQ Íö¦ã¡²PÍÐðGÕ ¤fÔ8¦®³¦®8«*ÅÙŠX~‚‘Æã`Bãgš@ƒõ™NH'Xö#? -Æý\tCJ1-Ë&Ê«^cæH¢b纫‚ûŠ`3Ð6Ub•\”Ðp6x †t"η³5f×i œûÀ>C]@áX!0>pýä`¸4¡ë,œsÕ`‡Ù®Á0í ,Ü0O›Ñ`·¤ôjdD¾õzþZ¢Ä°«] u•v…JýÈG-ü©m¢üw¯p݆óDâP-š3Œ8²À† Iü ºÊÁ–¸øVtÍ ~hf`*•$l®¯Á@tz‘€¡ò©sT>u¾°QmC%fçIlû)fŸãÌLX! ³mF¼scùJ ÎÚ6A dH%Rg[ñ ÇàqòõОڙÍ}"õ)g^év50qb& À‘ãEàêD ¶˜€RKÎÌõ½*½ӓ̦…rþKêËqÝ{ÞF`‰Ç<ÌQG } 8AÿJX‚šT¡p’0¬8Á\Ÿä`¥q¡dVõŽÈ¥3JD¸ˆÙæ8³É9¥~[b „9RÙ(e(” 2ìÞÈÃÉG‹äˆÉl±vS¥(^à\¬D LP¹Hà–^‚( á:¿ªŒ­´óŽ!_€PÚ NR!Bj*D¸RP`àŘe#6ãiJ«K,”UK¤YË)äùÄ(¶QXr¨ÝCÐs‘üó†eƒV°òÕ  À 0ùä8ð`P¡eFÌm¦6h˜—Âs¼(†hÀH4ÌzÏ‘æ‡,‘¼¤xWC±‰¸O z41‡Â ÜÐ̦,íÕí°Kæk¬bÇ+\%X£¡l›.@Ià 6¼¦!jxMqKG†k£‹y$#yØåÃC¯Îå{ÈfÂ|˜‡ó<nX¨– 8‹‚Y¤rä‡À0 B…«!pgÆÁ`+d)ŠSBŠ}Ì&]"ÁA:‰õ%—,ŒJA—’a¯Ó“‘Í P½ª_Z°‡oÖ´®tå§N÷îL¼™(¡ÆŒ‹ š§-m"b¹-hù±Z$ê Ÿ UYaàtG>ÿ¼$)‡í…ÈP-LÊ¡ÄÕÔ.lÂ%¸µfÏm"Ï¿«óÔ鞇ÊÂÐÈ #œÍ,߯ìÊ2@Ï¥ h@L™J(à– mã2Zñ±³¨9†QÀL™ùüØS;×äá…fŠŒ­ ˜Ø1I¦pL8 ó̉Ë,ÓšÃP=çuÇN…˜+C¬B ˜©9´65ƒ{÷Jfþ“P˜5/­Ö(D3i¥t@jµ@©YçP‘Ìhåa Ž“I§†¦7+Œz…×Udpçî:ÅWs…åŸýEÈêqûýYF `'·ðeao xVxZØÏÏÛØp@¯´|wT¢ç5¢ú¡ŠÕbõ€X}5,qËb2 ‹oZ­•~~êÏu[TÌþ·2ÿ"ÝÁ9¦9dÙ!`Z^ç”Ú]çÎnµe‚rhÊ•Âq(ÌS©\Á«å‚¶?r“BZî¼V~~Ì[vhbÔ7bkêú×RAv_±%ä%c̱™Cé[H°Ò­w•¯(Ò2Ü3šˆPÀ; ( ÛÌe˜ `¼óf¸Bÿ3H©yÌ\$—ȽMàaô/Åö.ÓCƒ MAzõ¨Š3ÃtG’ÂH(°°f×þ;“kÄY¦Ì€„Œ°ô úÛß}ôø¬09^UÑIo‘!¡Ý…ó S™ûfd9ŠG'˜C† sxûI ì’P(»R+Íݧ2”À`¶?f ýš)ðs¦Èï¸1LDM(ÊæhËpÏ{Æñ ¥7™C|b,¶¥Óð85]Ì€ø»®«~:'áÿ :êOL×Ä«$®õ¤6$Ñ‘T„æP×Γ…Ÿxq1•3(ˆQ¨¹—xâ)RZ€:ÿø&ñP§7æð†cù|¤Có'UͱæfQèE¡‰Æ˜+9¤ä/‰˜ë@ÎdREœ÷ü˜AHÛu=VÑ]Vi&J!Õ= TAyQѪóÏ*Ø68ɶc &òᎠKØcÅK¨Ñ°´X ª$y!J”^‰×ý0Æ<ÖU Š-dŒM}̪å8*¦0‰åXÂÁ`å)˹éÍ0wê–°€y¹¸zÏ"$ œLÍ8@qã)]´DzyœˆËY!¶–ˆ-qÇ×KX8²LMŒ†›Â,ŠÈï‡û|BЬ‡hŸê£€P8˜so`„¼Qã6,S %uÑPwåS+Œýd£šZÑŽìÂHØ a²å3Ú9æ‚{†TÒ¹Qp/V’bH û°9î¢F}„R¹áP ­ ŽTÑFQ @mŽÁàH»Ú(JN«’¢ÜJEBÁF~YÐD­óåâ‰#9J…C¡$H²‰8§áH á 6 AÂ!Ð*”pˆC wØG†ì,ŒØG…´ RjCíÂ9pˆD‡äPÀÞJ€Ÿ&’¡!F8„Cñÿ•:6æ.5ÇB äP¨¯û M1n{ +Þƒ–îq°U9ÌPVáÆè‚-Pᤀí hOÀ¡þó 9V9Í¥°‰åX Ò±ÔmöŠÙsr¨iÈ GæÀDu:˜‚K ©òÁ¥Î_mf…+LÓ«¦e± f¶¾‘¨aˆyS‚å¢7VÈ ™õ"æ’…S$¦TÈÌpYêÄÇìh$Ö*Æu 0qÓvnCƒ5Ü"‚éI¸¹‰3ML¸¶2ÃY— â¾±˜"°‡% ŸL\ˆshÌK ³Àšº>&Û)ÁJ«¢–(ñ垯ôUÕÕ|UºÅ¡ò €€ãëvghÀV$×ëBá†ýœ:àÔ<Ô@áSßðäC×8Ÿ²Á:Ž zm9Gõ² Ì<ñx$Kü?rüå5Ë GOrDò Õf?0ÿJ`Þ/CƒÉ È`aBök¬²ÈŠ"ž/ßjEÁý•˜¶QR€9¿0Pà…lÊBæY°Ï²oÌ‚o?$0˜ ±Où¶fs39&ЯFóRi±"˜ó7óa[#î¬@o ´Ý'èx(A.ê t=JHV¤îgì`NÀ!jŽQxš`£ÔÄs0’“9Ø+2—³ä+æE,‰æcŠ.VšÔõ-بËCfá™gû|lù!ª'%*¦ "G‹^œj¢xäÒGö%³Ê‰^¬ Œ¡Âëð€ºyCÄÿ9lÂ?]g2³ø7û©ÿ¦ÿæö§îM§{3¼é¼‰üÜuüŸÆMØá0~óRdzŸMë%Mâ¾{gôÎ?yÛKñ^ }^Eæ=ó«’èìϱ—èÿ¯‘g¹~Ä]ЇijŠtøv}ÿõ~DØ ?´˜ý Ë/,~÷á-]?qü÷fl>1÷g3b¤íøå‰þá‘þ!“»äý7 ëÉ'qÏœ±qÀ,gêXâÓ¶ê‰{MßǦ péxžÙkL>ÆžL'ÒáÊžX”,(Û!ñ ?äÏC)öI4ýÇ´ÓrL4- s-m§KAÛv<í­}HÍ{¤Gd6ïèhîRYÍC"è‰x÷`3üúoÐ#*tËe¦8áÎ^â€wåþ]˜—gg^ê‘#"äE@äK,?X i²YoÅdÝSu·ÍÖ{5cb$SN`1@jå§RëDƒÊv–¶µO7plqº;"´;¶ˆæ˜À¦š¿û•ªOØ"‰ÝHÔlˆ V´ÌvˆQ-p óLAæÙ”I©7&õ0·€ç5–ÚN$*ö‘&fAHÄ‹™·„b!úN@[)á¦n1ƒµ9ô¢Ö?esßµ«]¨‚ ùYä7)" Œ€#9Âä?ô"øÐ‹ C/fÑÎìUÁKÛŒìãnáÆU á–êj¼*&€p}̃Ó:„iÜ„ Ð…‰‰˜-ÇyEá ö j&Ó+p@-%C§ ò<ŠÀÁÌ2„™d!hK,0m QÛ♹(úE Hã$¤qóUàC*Ç$¤q Ò8Çõg¤q Ò¸o7H³¾Ý`ÚI?}Ãäž¾aOß åß0…ß0%b× ñ÷Ò2‰„iÌágH$¶vq«G…´ Øñ.È.7,½z~Ø–!ABÉ Lr(Ôf>‡BµP`ašX®ØT •‚ME$Ì`çH*€`¹P9ú8˜aÉPcÔAÀ—ÂÂÒrù°ÆØ2€[p‹n .¸`aÆsBâTÎDàÀ€ #ÜÃT¡y "4T¦å13œ¬@“w†iâ ÔÐרœ‚žÞ€AÆè 3P9Zì§fñX[4Ð7]ÃA>j৘Ê. i¡DB51Ê×”p ã3d ÓñlÌDÜ€Aš¸AC5ô¯ÄGŒ„ 2<3(Èø,‡| ýT^0Ô€0_ïáÂ=\´Y¦ ÙI ȇ“H/—!A"µ òõr,Ü÷ƒd»3$ÜÄd½ÅÈ™¹swà,iK%žG7=È‘pÓk[âê¡*Ä©I•r¦u Ò¸ä€j…9ZaަV*Œ¦ c…©ÂXAœâ ãW5Ž£!Ê zîA<™i+ªºçxÆÃWñLŸõ2u€ïSd°q¸"BN<`¡ýa}Ïc"Ù@²0ô|ƒ·ÞŒ1ö7ÈS “ËØúá oNØx>­,Ãt%43˜HÞJÂy±CcL™÷!Hµõ– b ú5=Óã›+Æ µÝ7CeX?`Þ°_À„ "ç51_ q ÒK#ô“Øñ ®¬÷¦$á®Wc±9•¢A+Ã+ ÓÞ›>! .*¯²ØœÈšW"`tÍ3´#çoÄ+È{(oÎx´Ys ½«,>0ÃÝêE4‡ï:áŽ,™³Ûçƒ ˜>¨…7m;¤O’‚pÈ–Sixh’/éq~‘çép~½ó‹´8¿Hƒó‹t8¿ˆÖùE´Î/¢w~©ó›˜aè°š( ÕMkìYE½œé£×‡±$|¡ ¢¹ÝÎÍ™H?ÇzÜî´ÅS=K@¹ Ë÷x#Bß´-3*eßa–—H°3TÁæ¯ñIŒ/L°å$¡˜D7‹L—ÌðžÄtQcd—(Øú-IHm'3›69²aàKŠU><Æ-(E:_¿&ÁÖÎìÀG::ŠtQ¬”À¡BÄÝñÙfÿAÙ_ D·¯ ûJ1úèÓ—ä™KA †¶W*e¢óÉ“•v÷ ¨Á-ðƒDN|‡`NrxÏ\°Rçt€à”9’úà5ø7ruº‚JQ \Ķ™ËH°1¸× ¾3²=Š%«Ðå“4X%]+Ô@¯R”¦ÊQÕy—áE :¾Å×ñfT ‰”(*ÉËØ‘–Þ‘»l=%q9^d•#°´ –…~@m™üØ·ŠRO44Tû‡KèO’ˆÌ——YèÜùš§|#;R]먽ԡa¶hq¿[&úÙB¹Û.±h˜-‘¦Ù²s5[°·‡ŽÝµAY]{Ó ^½†—ñúžMú–ÊñÛBèžÚ½+f¨Æn`xZëëcCŽºà†fgy  ¡ô{£²îŠ˜‹ ÙA¥Î®’—F‰S yØMTµÁÇ^.ÂS¦o#Êü*qÕžÇÜDc“.9³…d!8ð_ KŠ(l°ŽGWÇ#ÑiÊj$4Ml%¡wVPtôíè5¸xª™ªHƳ⌢²n Ü:ïqBô•Ã\ä–~o8¨Ü$UÅ“ï±ãFèD$šµÄ¢MC¸ ÄE„xÿ)ŒØ¢*&×Q^ñ(|ïQE¶žï,–¦›³(%T¤©ØÝÉibùŠf(~n¶DD6»¦.OÕOJØpUE4~ Šl?ïýáñm7)U!ÐÀ®Ý³cˆ‡WÒàðkß«¥­¢˜×ðزy ìÅ%V‚Û{-p€ó¤^Øä,´Œ£È}ùܟݼé0Iuž~ñ?bÀF$i(À*u†ÄôXjL’é”…|«ã '¡1Îæ 9X‹"îµ 1á Ñ<‰m?õ€ÐïŸ?—•;¢|jÁâ¹´<‡gžeØflÖ ÿ4ªaSÙ±pÉÇ9~ôôd¸>ߌǟ ¾Ãp¼Y„ÿú󓈙¡5ÏF¥ˆ:?èx|}–ú^² ãÑxüðõ üÄñ )¤o'ǧkƒ@}÷ðøëèIlU­Ð ²x‰‚€ï0yKbä@­ Ch[œСs/tü×φi‹+"‹ ÌW¸3Ú0‰†ì2Á¿÷šŠâ‹<ÿ™õW¶”½{K„Ÿ¯ðè–éºÓz1¬8D†?ü9ãàAè,…˜ÿ [QpИ>u…¼]ÞõðQ)BF1 å´baläê‚4ëo¸N„ŒlkHdc¬ ‰¨³¯Aèb Þ•}%¢p¼©¿™ÇD%ÿo‚½@‘Däý„j0ñ%Ó™®¨;*g±YÏi)¾M1¹å6!§X¿îBáüø¬ @ ÙÂ_2ÂõR ˯ ý…OÚ0¿AË÷IDÞQyGE:ŠhŽqÓ;F^0DNflè=·¤Ê’DáL¤#fŠtÄLUæÍäûF4D¾ÿâ0îC·ùÐÓzÁ‡qè˜è¾&ØŽÈmÈ‹,ɎѱµÄ.$ÿ=6óc‡w zXÏD$FSÑ!bë|çI€L—d˜‘žWoÑÑGx䕃’@ ¼¬›@I°­]&dá¾Çôˆ8Ö§¶4¼Ü܇¡Oñ h6MdãÏÁͽ1~þú4’‰)Ç&p ”¹?%ðņP˜ŠænžôH\à‹Œ\^3—7Té迤 üy ŽÓgùA÷:·K O‘:&¯…–e™¡Á…‡•¯øÍ¥œ œÄÕd%Ì–Ç×"Î$8uÈxDéÁ¡2¸‘éÚ0P!™Ä"a4H8Šc†Ät¾­"¹G[ø¦í-…:¾yøJƒO4£RçžÂýïÜŒD¦Ãš‹”YΊƒ…f¸Ê•Ÿ°Ðâ&Ëv·I°tH¹Ã!¸T/ð's›âã¾^ç¨è s2 Ù’"Vd!êt)ìKs]2•ì¦ND–áÈÙ­‘ËAÃáñK%íEòK>ÙMy2EÖé6›$ø©I•±‹(²\zîPß!¾ÿ¡ç‚„žËt#È/ED”™ˆ$³‘¥,´Ü)’DÌ )î79bÇz‘þ“²![¢ÆÐ~²<Œ'Zei¯æÐ_ËÑq%GÃuª«8d×pˆ¯ààIrkIªŠÊ¹PÌ}º 6õþšôjýµ,ú+YÔ×±´\ÅÒr ‹ö –†ëWnCé¸ EsÌ‘£ WTƒüS_:5á}Ëm#1—Ý™ºqO…K¥@,ái;… –²KhÇIF;ƒ&²˜ª·3m:Õñ5>0mÇÐÍÍ5>0mÇÐv Éü$Ò¨§•¨—H÷á]ÍÂP†åŸ.6'b¿n.ù^Éœ@KS2Šp23's´²ÎÚƒ¾Ô*ifÎ5J؈ÈWE/N úbê'2–àñ,&ý¤KÓul±‹ ?öK¢'¥'J¾{|t GF&'+¶XmÀW• ètÈ|âO\Z#ÍQº=üb‹?jÊpéN…2|’´šG˜"çADAs‚˜xÉ‚@0$Ã__ÏAòNßfß‚Â7"4úX²€Jb1‹"SÅÍÀ÷ΑŸz½sk2dpiCJâ­iz–ì´ŸNàÒ®\õ£¯!Ñ\¼Ý—˜›«â"[I œ“ô18R—ØÌGI·e˜" ˆ‡¤e2Xê(‹¤ƒC'¡—±•ØëŽñgA<þìAâËá+….$ëSw|Cš­q/JÂÂjçId°ˆƒO¬ì‰¸ÃϰmgÆ"‚ª¯ A^·›óDI dÿ¡çÚ*ù¤|`ÚxgÛ+½›Nñ1ÊÅà{Ò9…8ø‘í0=›Ïˆ™(#œ#ëÀ‹JüMniaF±˜4Rp Ï’‹P.î <¼µOW‡¼¥! ³¨3p¥C?²ŒõÑb Ÿ¨0tCC® ljÛñÿhñXY¥t…@ÂyƒÎÝCæÀ¯qlH˼«,à"ï*<É<;›F±ÒÃO«z¤·¾$þ” GsJ@_‹AQŠAW‰‘#ÃDžçŒD äYÌH›ÀK…ÌefÄòÞAk!”(òÊ"Šg#ªÐYšM ïÒlç7·ÿˆö nxÈôw wh(ÃLÒ›…[ª(œô^á–òZa‘…*Z¦¿´¸CCÎR^YÜ! uqä«Ã)c2xÂP #  h *zFâÙl*+Þöªª/'K6Hj… K…×Ð$ûô×ËâzuÙxØêزGˆIÖOµ's£ºz¯ÈFÖ{EÂÞ›˜6^–Q‹YhÄ>ÑËY‚Bn$ìùÆì“á:M7À“WTÙÎRíLqÌ ]ðŽ`?™ Is.rçÓ„ËÐ`–U*vB3e3W$vÙ>Ë2pñàÒ‚[¸á‚5ES5AJ‚ ïŒôj‹Ÿ·û4å~nFs p¾!ˆáÂ" B¶YìÛV_žÿ‹7IörÂnJ‘¢kðüHC$Û¡®ñ…Üa47_ÖE…3Iô dKBøIåŒûëæ1,Ô1lE%D„œc[Îão2û9ÂNÜçGØiz~æ%†ç‡‹ÎÀø$ŠÂ<ßf†ˆkúsß=ŽoŒÿüÏ_>=ü̙ޛ>9m”šÁè‰ÓŽ;z™‡‰'›¼ÔÊz2‘b`šiïäs†SÊ/LÑÕŒÝf“dÆCº±9åã8ÙB?”&tºÆçL_!‰Ùk¥ýoîõØ0ä6˜qlZs¾l{3—¿ŒõŸÝ\èv4iÍB›-l¥§î7uri³+ë‚TÇ^jqKc¸lCo;BL×m¥îʃ4qͰ ;ºâsp‡º~{§M[n¹)›µ NßÏè3䟜¹ÜǼµQÆê8T˃§Œ8åN+1¬÷)‘øTãÈ_8–¸4züÝqнZ ÙßwÅ„ò­¦z—œ~˜ÓË iQÙ=ú¦Ù„{9¹¦÷1´ÔwÆæÊovƒþ{ßE±íøF´ò,ƒ·Ïêéƒ5Ž;!™bð`ɉ£k4ê‹IüñO¶Eü ’¹~†1ƒdêúé¥X3|Òy£G˹ƒ‚DôñR,º{ñ§ÓÑ+ÿ—]ãÁ¸Cg/¶ò¿ïÉ¿ÿ0o! ‡.ÆàÀFã¸?åÿû ÖàÅD–íñèB­¾óùöNN ùî÷žšŽ{1‰ºÌð’ÜÇ»ÎèñÎxøj|xø4º“ºgR–»K:mX’V-IÛ‹jmi+>¨3¦½ø ÎšM|¶à÷”Ç—bÑEÇ{ ¾èø Îêm|ðí2 *Ä—bQ«ñAE-ǵ&µÔ™ÔN|Pk u|н5D¥èD<³páxÂéˆËÚ. áçv[Þa–¤yø4¹:72 Å¡¿ª¶›.)ÓŠü³¸Y옮ó÷NðCÉ<”)Ë5EVýË7üßtÓË •9ý7Mìv¾vg÷k?~X>.G­ÑW>$d^'`ã¹TÝsl½ÞâHï´=Ò»íH_÷þ [Iûÿ~“hÏ?|5¢¢giòÚÅøúx¤2Xük¡ñ"Þ-⛑q|¿ùWËoà…ì¨5iMXf snŒÇ˧/ü;#ÿçb`&n<ºÛÑ+ýQ#ºÒ›@ GöŒ(AL&Æ‹ãÙ›>÷ŒñÀÈzŽO®ü-u]7dâm6#H&®cQhn§´wÜ5¨-ª”n·<ì«Ö ¶•`“ä𢵤®ðZû:ÑæŸð`öjºC” ìv܈º‹ê«§…¼6ÿ‚¸“êkŒ«þ(ï¡ÊŸeþ³£Ùî1yÇ{Õ™\õgéÏúÆxhd-ÑëÏê›rÐ¥íùÄnnO¥ôe“=6—¥¾-—8RW·íK¥VCc$Þ7¦~¸0cn’ÜçOt„Y=ã½ø“Æ"š‰Mºhä{ÍÐ\0ñ×}n[ò®ãß›¹›pÌjÓ¨îÍÆ(¾©²B'‹Vfšv»z?ý£¿køÓñf­q»..3_ —y³¸ZΊÉX³Cì=™øGøŠÉ'Ô:‹>]Íæ)ˆ k™ž|õÖ Ùè‰dVŒ'uiê±)rÕ²l'ú&¢IqXýü:ß•ë¢+–h*Ø¿éíü]þV àïk´jîГìS'lkÔЮmŒŠ Ú¿A¦Óìú–ðÌ+ÁAvdRòùJüí[5$Ðà†÷X¡³#†[Oàù-MÇzZ7¢I¹k…îq[p ­ˆ=F´oEc¢Æ ÍߣkVOƨ{Ì«ž½RSö'È@NÄý±ùÂZµ â@¿–¬FºgZß6cSwS§Y QóTÚÒ¶ÁÛ‚ûʈu÷rØ‚ÿˆv‹U¨96s<ݤ–È¢é&e‹ ®A‘“†í8‰o+Ä-¸‰œYsGg5Oæa5¬Íþ’³†m8‹a”L„·ÐA£e:Þl›Âôˆ$ájlØÿ€™ wEöï—¨»¢‘”[§:C.ä³x퇮?î·‰ÌVH3;´÷H C¤™zÄ¿1r¢Ú{¤½1r¢„=Òã»ÜþÜŒæOß Yîh<4*Iˆ#"IÕ%§:ÚÚ>½ Y[#j&h ËɃg@Ô•Ó!¥9ÚÊ-=é€É9J XÉwSm(ùH?:–HWŠBàQ)ï»~ÊÂÑ£ES:YϦƒ) íÊØh™zÆg#ulæŽç :nùúœÏ3ù¸OõÞñž”íµÿ|¹{$íÎ-)ͽ¸‚#;1o•EÛ¬ŸEH”f?²L>£Qüø1%y“°Â·qW)Mñd=›¦Ü]ijWÆFËÔYϵ Q[kùÞ’…1o¢‘.ÌèeSRxùèÏÚö¨ƒ*&ýf;X©£*yà”Ú—øR ¢¡x:Íe]Ç·2’WÖ$}Ï\ÐäÕsö—(p ð ·"V·–ñƒe‰"üÅ$ŠåUŽÌ&^4w¦ñè‰Gòߣá¢-®Í'\´Åµù„˲¸.Ÿ „ .oÆ–OH‰·æªF׿.Ëèºh?%ŽQ’¨ûH£S€}¤¡)À>Ò¸`iP °4"ØwAáè:Ÿ–ó b]¼¤%qO`Y¾zŸ‘ä®÷™xA{Ÿ‰ä´÷™xA~{Ÿ‰äº÷™xAÞ{Ÿ‰ünbÚ†eFq?›;4܃HÖM¸šŽ›„¬Ž Dµ`QdΘÈÌtîʒ…^4ÅŒ"o÷¦À; ýEÆL¢^ä•e¬Žãhhb_>f.ˆÄÛÞ¹wœ4ï³i–ëGlD–iÖ…Jz¾ŸÐÝká Í~Ý™îûž›"¶¨¯½B{×ï/öpRû‹T¿H+þ¢½/ÛŠ'I©= ܂ijbEUw™Á¥Rußa‹Ã„‘=Qbr¶SÓ4Ñõlf9 Ó5_CÑóÅs?‰LÏŽŒˆô|bRjn¢ ÔÛÊ;m“áNÛD¸×5 R­þ$ÕêOR½þ$ÕìORÍþ$ÕïORýþ$ÕæORmþ$%÷'±³`çˆ÷ÞØâu?´Í;ÜgÖÉÂYCØwÊeÇnL‘TT¶_üþ{¶Åøžô{´_Ÿ2öb›«ïÑ~ñ~Ó¥ÎM‘A0¾Ï¥Cû{·(9Ľôº |ïüí`;.ª ù ýŽù ø CÉyUQßÍ—ÈS/ßõ”èv ßb阆xå4 +Ñ¢4Ú™¹ûŽ#‡»ï8j¸»¨ˆ¡¡~›¾P¸¡a ŸiÿÅ ê3íÿ^öÅ…Â í× 7µíòÖ}õÍ‹ …›¶áCá†M8 §ßÏ—¸ÌP¸Y#”Cáô‚sY¡ð¶§QÃå„Â0}‹l›7þ™âæ ÞT‹nCмˆNo)ä.Ræ×¨¿=ÊÔ‹êÑý—È,]𮆿êáÛ¨9Óœ9Ý‹JaÓu}‹²T˜³DŽeð^«Yöj± v|/¢jå!þï„Vx™?m…7vÈFÓ!Þ¾(o‡ØqÛ!žù~+CkÚÜ©µÂœ:6óF.ñóÐãþÒOG$îø÷mhË °·–Ë6x‰ W ¬uK±ÎÅ¢Ž_ÇbQË«a±¨åÕ°XÔñjY,ê‰5,µÄ:‹:b=‹E-³–Å¢Žy½X¤-pëZ,ê¸u,u¼T‹Åf1 »}x¿ð=¶:«0o›ƒ|ø4¹ü&ÉU1T;:ßk; /‚L~L»)ŽÎ6»¬Òþ]õx#Ó‰;½iÄ¥ú¥v\ÏiÖŽ>G\÷ëd÷û44á¢fB3÷s©)žèüS’ÍÑ5x°•Õ‘…³‡Ëî˽†^TwÞoÄKëãE÷lÉæN[6Ÿw²W i~­ÞÕ¢ &»gC~7Ýº×æ‹êÙ¼Â%wò B‡ùÜÜÌbÊ”â†dX~B•XŠWã]:õùNĺflÍGÇÆãã’â¿cG2&ðâ”_„ Öë«9q–Î-ÿk׌"cóçG$o ê†e—•YhÐÜ.Ð $ÝT\»u|‚Okô®#ôMàÕ0kl"£»„Fw‰Œ~OÕïi,N ÇFJ56R±‘R”jl¤4cã€&ߌ¿•TÆÜ±YÈ?ò£Xr;øÏqº Ý–løl¸Ì|1ø¿$8Ð<Â=zl<@H¬xô­•Ö ¶â•RèläîÉÖ+©BñÿåÞ0f^"¢8x¢ÞÝÆ’¢´kðhñNo5µSD³ÒÎaËvŠ´lCÚkµAÜ/â£Ù5-f˜ÉëèÛ·oðû  ˆÌ)ãˆ+5:mèšÜŸè$ì1O³÷ìO,'/6ãÔ_´»Ï‚ N)ÀMÙT̼¶>§·ÍØlƒ¾ÅE,3@¼ ±XƬ•i0È-ˆøŸ0'.AµÎQº7ÅÏ`D|)4g¬&sóSgHlÉpó=¼Y<7LÏÞvLÙ+¾héšÃiþP·ò=(s’9+Í‚´@*#»¾—ûK­ •4à^„)!emß¾é÷Ù¡þÅ2JÍ`ôÄãR¬ƒ ›9žÞ–,WÜÔËÉ#¾øÛ¿dÛ—‹5Ló~%·í›ÖÙ?4ƒ@L>‚+Ó'Ò¶Ò\îâôÎüq;Ÿ˜ÿû¡ã9±cºÎß,4\'º˜åå¿ÓÑdÞ-èÐŒ"gæéæZÍŸ<ãma˜ˆuóŒúR†yfæaž"Ÿº¾]FO5²ù’û³Ó¾évi^½ó{M¬ß©•˜5{µ5·æ¶°S†LJ%èíà5©Öþ½•«ìPBs ¦J®·Ù2)ú¨½·E*Rïp¬ ÉZûÆErÍÎOzNßd÷íaæ½VßÞÜZÍëíYj>>ËF­^¾¹…Ú£Œæ&Žº“ÕgØ(ÿïÂm¼ˆ}Ps»5‡,kû¾éÞr”™Ûñßôo;ªÜz7víãŒïx–𷢬K+ &Öªäz›½HâìÜOo‡I47&¦õ¢7o"*;?ê/,Ìhõ­f•Ðmpêu–kN½ƒxËÚF'ï‰[vM¡^¸5-Të’”âä{8-8ž ¾k¡CÄ>Z²ÛaÏÈ-wÛñëÝ–üz·¿ÞmÁ¯w[ñëÝöüz÷¢üz·¿®ùîÏ»î¥ûõn«~½Û¢_'¹`vˆOóØ3Ǻ‹R8£v7Î9/#ËÆ ÑÚÙΫÞu,^uB¦˜¹îŒ¤Ëhd™ç‡lT@˜ì8™Ù½¤ì’%Þìˆyq¸'ŒcgBÐ-9~—ÿ–p×ñ7+¢,·AËÒì;áã#AÔ3­æ’ÜÓjîÀ!É8$¹‡$wàÐä„Òî|ÆÁGËÁ·ªãJš#­{TäíM Îþ„W.Íp Ö#kÓÀÂ¥3Ø) ,Áš#`ñ§Ö¥…¿õÁÂ%Ü3ؘö•v‡õ¥¸;>óS7‰æ‹›/·©®]ñšŽ~WìË]1…¨˜?HC'æQñG‚°Ø/n§|:ø.)I¢À§YJhÖ7Ûdû‰‚58q¢`CÓF¢@’$ú0íM7ÎŽÏT|š@ â³Ÿ$¨Gŧ*>C Pñ ŠÏT|z@ â³Ÿˆv_î¯é‰÷eȹºÄ\´/qDÕ÷6HÛB+Ií¼´`}=ÃG|Åíã+—›36¤-UÔ5¶ˆ–\â¨aâÍ¢à©yПŒêŸ­°ð«XDó8EDôETûÐߨ}P‚šŠîáˆHÇó‘žG "MO=DÚtˆ4?Ûµó8ÃI´$][|hALb’õn÷AAEà^kN òMD$Dëgð“ˆì­ƒˆìEƒèÄçdàØ.;ÉÔ¡{ Ú þDjpBÓ)žh/£Sv|í}I‹ä¾ä†“"*ßJêÓ‚“|Š8>É@Ú¢Ó ¤úúd)WѧøÖ'j»gîVg£›ÖvÇP~™o4s¼€N1M bñ³¼O2Í7‚ó}O&+щÇo¡ zd«ÅníŒGÐv¯JAÑ„LÔ¨ˆ¤Û£­F:iß)àM8U4x½iø2¾16©oñèæ‘8ùs¬ 9 8ÇÖØ šÕ«±â=NУп†Èÿ»C4F¢#Y!‹êßäø”sïQLX! ˆ ‹jà4߀Jó;*Šk[ãA«|•‚¢ „*ÝQA‹›àãJékºÒ‚ ž.÷žiÅ`¢oÉéð½wn¸ËLòšR§cŒ î4‘áxuÕi}$YwCæ'u÷×±lÎ6KClL]ߌŘØ^Ðz´HºvbÚF¼ ˜C#ë[f pÛe Î,/?ÃÀtù« ],K07ÉY,/]rÛ™9µ³Ê2 Í`NÎâú) ÉY‚Ðñè{,H<‹ž% D•š% úï2|%Ê|Y³»¤=þ?4nlË‘¥upà/Uîhhy3º¾GWÇ÷èÒ.ý÷  † DÁP(Zø[e!ëYm65763ŽYH”o9åE•ÍíÍ «EoyïÖ{ÂÊùÁú4¹º})ˆ²Þ¸Û?0zä[Ãõ-ÓeFÖ D¾cÇ(á ëÈñ{í}ìü_Ü…Î0,Óš³üh3CQ·ÕÞî^Fow5Q¹ü]""Ï¿KD¹lˆ:—è«:­úªÎ1_ÕÑ2{:º|U§U_Õ9æ«ôõ¶_ÕÑå«:º|UG‹¯J/1®J[«ÒcqUªe¥OuÅUi«qUz,®ÒÚÛô¾*ÕW¥ºâªTW\•^b\•¶W¥ÇâªTËJŸêŠ«ÒVãªôX\¥µ·µø*=qUª+®JIã*_ÃqÅ–c8 û›(_–h²L?ÿg=©&ÿ5`Þ·ñ–URâÞË溛E>ð¨&«Ož£÷©sôÈË7X£n¯Glþ]ÍÚBo΢†šÿÓÛÂ?]§ HV˜]z,C†ê6û—&N¨°ù* 全hð?éEùŸ´=ÿ“ð?)ýÈMµøŸ´=ÿ“ð?zúWƒÿIµøŸT‹ÿIÉüOY†¿Ëþ=}´ªWÙ1÷`±Ñ6,Í©R- +±áæú3Ç2Xú!ÕýРѽ®2 Õd-RÍÔ"Ñ4 MoÆÈ?z‘…î£X¨>z‘‚æ£w #{Ödê¸"hïN)Xwyúâ«•C.¥Ôpù“b‡;Š¢ÂöhåYZút`¹B:\Õð5š±Ø#ªË¬a ’Ø£ªf­ÒÝŠW&ýéTÃ;“»äwÑ*2²{g<|5><È+]䙼ývhI$îÐgŸÜÈJ˜y¢ãÃßGs?]˜ÞJÏ|Íö¥A<™i åöjPl‡wx»íðjZˆb—n~/d噋õ×£Ùãî0uu1Å1;4D¡J£c ¤ÚBªm ¥vht ²¤C×ö¦ãQogÊ4dû™ Õ÷/q}üü¥ê¯R¢¡û*Eª¯Râ ú*~þÔ;Z¯R¢¡û*Eª¯Râ ú*›séI2%«ë(±PVv”‰"óÿ¡Ú¢©„ü±hÍMÈ2ÕÞ½©–]ÚŽ)ñíiÊÿ÷Aäú“H8±žMkÑñ’)^­$9“Ù¡âÃ+ Äã74{ÓŸ¿dáÔõS‚'k+T÷ÈœšŽ«+ñì¼]ä~GDé—ßø/IÞ¾®áûh’w!Ýû]š¹ÓáŸG‘¥‹h®‰ˆþót5Ï¡®ž9D¦“°K£auuÍ¡®®9ÔÕ5‡ºôsˆj·Pâа[ Ê©D«(f‹=û]n]•¦Ú]D4ÕƒÑô„ {µX;¾G4Â*$4C¬BB3ÆzÛã>¬ÝŠžÑæ½_þ¦,$q §˜!žÎÞ]5d\ÞZ ·Ï`·l‰x% fáÂñD¯øI$q[Æt»òÑ)ïÎb#öùÈÚ4¦K”t8Å¢â‡r¼Ìœõ(n«—n×;sñÅ.ĨýE!mÚ#ò•‡ zÓé鳉¬tårÂj–SØäÈgµãaV×ÜŽ´YÌS ­ô9ÍÊâŸ,¸•±{Ù͹–2ž-×jBøTÛMŸ`%m†õˆó®§X@[ýtŠ´ùà, º›{ sk{ºýâQæÖz[ÏÎ2­2§­ì,kÍhcgYkH+;ËZKÚÚYÖ³g™¶4bÚÞYÖÚÔöβΨ6w–ûíiogYk“®e¹¾e-{ ;Ë:;6;˶ÊfgÙ¢ùβ- .fgYkÜ%í,÷xQ;Ë:+·;Kв¤ (ì,Û²@ëβÖ­;Ë: ôì,k™[ÛëèÙYÖ2·ÖÛÄ;ËìüýrN4ŽÚÓBÜyÀ& ¡ßö['¿RÙV,x!Ã#¿p9cƒØCbî^Òwé^ÚwiÍ£¯_‡˜[‹zÖ¯‹É›µ§½¹ÐRêâ»ÎõkO }9ãÕõ«…Æ!æ¶Ö¯=Æ\ØwiÍ£êY¿ZØb&ímçsçÆø,ÎiBÓŠ—£ÑÓ¸k<=W”ÚîÛ±grYæØ—e»,s¦—eηË2ǽ,s—eN|Yæ¼^–9«ÖÍéÍXL{äu {Ú"ýÿƒìÏnnñ?Ý!¹O¨nT«]Õ&yKaT?¢m‘ I´ö¦'yYÄ!ò8Ní9LmÕ$:Œ§X3×µöy¯ÅY9tfž²J¹"Jwº‘­6ŸðýþeÛÝ¿l§ùóâp%Rn´g(O0Ic†ò 5"C´öyÒЉñuªC”ÓDíÚÐmßÚýØ)nË šÛ÷ò ܈…ñÃãǼˆöÜùDk&d‹}A¶° ²Å½ [dËëÙ²jÛ––’ÀGLjÉå·”>bRKA›>ÈÜÚh/Úpõ$O0AWøSô&Yô±Å±qan‰›D˜>ÂL˜>ÂL˜>ÂL˜>ÂÜÒÖ‡3¦0f0&0æ~0¦~0f~0“$~ÃÄ‹£~·°ÂCöD^™‡*-“…žeš(³ŸK#ðqºAo[žbáéSèIïHŸb€¾KÒ'Zsaãƒ(Cqµ¶{Ò'ZsiŸ¦=ßJ´@DÝÞ€Ô´˜íW×hi:ì7¨ÅQ{¤ªo1«-´Ö¹˜íËp_Îiw1Ó˜n?‰ºµÅl5—öiÚó­š3éÿ“¨i;ü’âN´©µîÐ|w¢Mmuñtlá4î$jÒ÷/-Qr‚Aú¨ƒFÑÇ–éuÄ– Ð[³æÂÆír˜ZwlyÌšKû4íùVÚÅì0u{RÓbv)‰’ jqF´“(9H¯u1»ˆDÉ1k.l|hZÌ."QrÌšKû4íùVM‹™þÙaj¢·ø0²–±1Yyæ‚=XVù‚Væ¢(ꂎ2wÛb¦`Çh‰×1Z=+mm`í0kXUfMk‡VÏÀÚ¡%X®+Öã™v(U¹(O…‹n¸T‰ÈH•HÏH5‰TãHu ‰T×HɆ„—,Xȃ*×Yˆê½3êÜÌÍȰ™ç‡‹Q%rîHÖŸú$´|›9ñÅ[vöZšÖrZñ¸îŒ…:i;¡hªÅ+—éì宸¸Ž7u<'^élpwa¾ì5ð=æÅZ[¼p¼Vˆ{¢«ÿJ_Ì/:ûºÏÇt0Ë1]ço½Ó©_üÌýÝ/~h½Ôƒ­Ë4\?Štöø v¼•Ç"î=ÙTȘjä¾펜™Çš7Ó<Ì¡i;¯?ó Í@ç·ÚÎŒÿ¥Æ&ÞeŒZgÏ÷VìÕ´ö9gŠž½«>³ƒ{ͤ ßN\_3©˜¡—¨2j'†ŒÚ‰!£–bȨ­2j+†ŒÚŠ!£ÖbȨ½2j/†ŒÚ‹!£cȨÅ2j5†ŒtÇ‘î2ÒCF-ÄQ 1dÔF µCF-Äæ’h™ÂGÂVî é(÷‡t={ d¤kèp‘°¥ûCE:ÒCa"]ÿ  i…‡t}|04¤£=ÒõòáŽ÷X8HÆ\ ’}Öº0¬eµ! YÓö„t|õ¡Yoî ûH ëB>Rºpˆp¢?Ö›èõ&úc½I ±Þ¤XoÒF¬7i#Ö›´ëMÚ‰õ&íÄz“vb½IK±Þ¤¥XoÒZ¬7ÑëMtÆz­±ÞDs¬7ÑëMtÇzݱÞDw¬géõ,ý±ž¥?Ö³Zˆõ¬6b=«XÏj#Ö³Z‰õ¬vb=«XÏj'Ö³ZŠõ¬–b=«µXÏÒëY:c=Kk¬giŽõ,ͱž¥;Ö³tÇz–îXÏÖëÙúc=[¬g·ëÙmÄzv±žÝF¬g·ëÙíÄzv;±žÝN¬g·ëÙ-Åzvk±ž­3Ö³uÆz¶ÖXÏÖëÙšc=[w¬gëŽõlݱÓë1ý±Óë±b=ÖF¬ÇÚˆõX±k%ÖcíÄz¬Xµë±–b=ÖR¬ÇZ‹õ˜ÎXéŒõ˜ÖXiŽõ˜æXéŽõ˜îXéŽõ¦úc½©þXoª?Ö›¶ëMÛˆõ¦mÄzÓ6b½i+±Þ´XoÚN¬7m'Ö›¶ëM[Šõ¦­ÅzS±ÞTg¬7ÕëM5ÇzSͱÞTw¬7ÕëMuÇzsý±Þ\¬7×ëÍ[ˆõæmÄzó6b½y±Þ¼•XoÞN¬7o'Ö›·ëÍ[Šõæ-ÅzóÖb½¹ÎXo®3Ö›kõæšc½¹æXo®;Ö›ëŽõæºc½CÒÏD£æì3a+5ÇzåžézV¬wXæ™°¥Úc½#òÎtýÛF¬wLÖ™®ÛˆõŽÊ9Óõr+±Þ 2ÎdÌc½zùf²–éŒõöÊ6ÓñiõöË5“jŒõöË4~Óë}Óë}Óë}k!ÖûÖF¬÷­Xï[±Þ·Vb½oíÄzßÚ‰õ¾µë}k)ÖûÖR¬÷­µXï›ÎXï›ÎXï›ÖXï›æXï›æXï›îXï›îXï›îXÏÕë¹úc=W¬ç¶ë¹mÄzn±žÛF¬ç¶ë¹íÄzn;±žÛN¬ç¶ë¹-Åznk±ž«3ÖsuÆz®ÖXÏÕ빚c=Ww¬çêŽõ\ݱÞB¬·Ðë-ôÇz‹b½E±Þ¢XoÑF¬·h%Ö[´ë-Ú‰õíÄz‹–b½EK±Þ¢µXo¡3Ö[èŒõZc½…æXo¡9Ö[èŽõºc½…îXïÐ3»D£æÐ»„­Ôë|Z—®gõÇz‡ŸÔ%l©öXïÈSºtýÛF¬wì ]º>n#Ö;út.]/·ëðd.³ÆX¯þ©\²–éŒõö>‘Kǧ5ÖÛÿ4.)¡ÆXoÿ“¸D„±þX/ÖëÅúc½¸…X/n#Ö‹Ûˆõâ6b½¸•X/n'Ö‹Û‰õâvb½¸¥X/n)Ö‹[‹õb±^¬3Ö‹µÆz±æX/Öëźc½Xw¬ëŽõRý±^ª?ÖKõÇzi ±^ÚF¬—¶ë¥mÄzi+±^ÚN¬—¶ë¥íÄziK±^ÚR¬—¶ë¥:c½Tg¬—jõRͱ^ª9ÖKuÇz©îX/Õë½êõ^õÇz¯úc½×b½×6b½×6b½×6b½×Vb½×vb½×vb½×vb½×–b½×–b½×Öb½W±Þ«ÎXïUk¬÷ª9Ö{Õë½êŽõ^uÇz¯ºc½•þXo¥?Ö[éõV-Äz«6b½U±ÞªXoÕJ¬·j'Ö[µë­Ú‰õV-Åz«–b½Uk±ÞJg¬·Òë­´Æz+ͱÞJs¬·Òë­tÇz+òXÏ_²pêú©ÁÂÐßuFOÇÑ.œ¨«‰èýÍh©¥CÂ20>9Qlx¾ÍŒ‰±þÜ÷_FcCW”šÁèilŒotÐ O6NG7Þ†Œ½ˆi!»ã«‹Mù–â‘®/¹ÓµX;¾gqØé•þvý%7ç}ûóƒÑyÓ{ÓÓBÎ=ÊgÎüa¹µÃÎÝL[ _¶AÛmµ¿»íõw·•þ~ßÎg~ßNkͱ¾ïËþâ\_ÆFńѸ«…ÞczéùZÁ㾈·Û\L’éƒÅÿaÇš›¡Á»]Ä‚ÖhÔ¹ ’IÄØ‹?Ž^ùè~dŒù?±ÿ}Oþý×€yHÊ3Ñ¿?¾aÄcþlÃHÇüùVQŽùó­Ò4æÓ}VµâçÏ7Lߘof˜®1ßÐ*Mc¾¡UDc~“î§mÞa"Sm®2Q ³* ͸Æfwg™Ö\lúïŒÏÙ__¨ãæ#„•ÔRuµQ‘Z*}ã„ÈiìR¥-ÉTßLõ I²¬T-•®!I–—:ÞÒtÛ0ÃY²`^L·íR‘­d;TTcb‡‡f@܆ˆ‚ÊNªÓ5Æòÿí{¬ö1“Á„˜ÈmÔsÑøZ.¢ARÏ¥q ¹Ž®´­AI¶–Õsi”d«Y=—¶AI¶žÝ.ø¸[•Ïú>Mn(³ û)Éò{)©FË^>¢³—Oç¨éè5ý£¦£yÔt4šŽÎQ“ê÷5©~_“jö5©f_“jö5©~_“ê÷5©f_“jö5)¥¯¹3ŒcÙËaª+´ß¢Ðû!Mü½ŸhÐ ¤µµÛNëö£{Øvt[:_{€Pë°ÕëmÓÖ½mªÛÛ¦º½-i`y€Pß°% -÷¶ìmSÝÞ6ÕímI#Û„Z‡-¡·-^þÊê:ÚÑâidˆF Œ¦v]žMú„0šÚuq6Q¹‘F6y–F6ès6íÊL4²¨ÛÝM ¼<›Z¸ãÝÔÀ‹³I£Ò}Ù»™ D~Èò=Û‘/Z/ÍÐ1'.ëÜx~ìLW†éVU›ßt:ô´<èÓHÛOy7žD·'žóW ¾+yyǃE³×‘6CvhIɪ£‰’lgú’‘µì>›®Nû„f–hÜ!46ìÒ·GhlØåE´:74‚fynhÍú\kD»…f&µ±ShláÕÂ^¡±…—g”N¤{»ÐÐRä_Lt¢%úƒ Ó »@£´A§vyFÑ:S u:§¡Ñé\Dt¢I-A§[xFµnáå¥Óµj‘?:UÒ(ªÉ¨Aèé€:ݽ°×tt;òj, ùPt§2ø¸d›¹6óüpQwç¬OEëð¿ð…ž]GKÖZNëx1›±P'm'M5¢xå2½Ü×ñ¦â‚•Îwæ«Á^ßc^¬µÅ Çk…¸'ºú¯Äa±ñÅü¢³¯û|LG³ÓuþÖ;úÅÏܹÑÙßýâ‡ÖK=غLÃõ£Ú»ºT=>ˆo屈ÿ-›úa­7¡â¾펜™Çš7Ó<Ì¡i;¯?ó€/ÈÎo;´ÿkM¼ËµÎž;î­Ø«iÕ:g¢ž½«>³ƒ{ͤ|o•¸¾fR1C‰–îîáµaz+²:€½„T'æûÉêöRµ°‡¢NÙf±é¸®a¡P‰sùæ¤Z8r“š›î"éÀŠWT^¹‰e #©P8-QÏrÍHì»%!ÅžzÃÕujg¬-âzkg`ÙÝQ|•XñãÇxBP¥_"¥¦è¶Ñ®.y»h’Y[x’4Õž$•ç£Î½ñY¾‹—mW ùÏIi§gZ?=鯕`ϾnZR“NG*éŸ-<Ét:y|ûÊ?ó'¾ðó¿¶™Œûsß=ŽoÊ­¿¹§eR3=qÖqG+ñ0ñdƒ—:IoC¶da´S1LËzÇ·³^4e¡üºTýlÍCßó;ÝhÅlaX¢0¹Ó•;!Ï}ϱ꫓•·&µÌ=oçMAT=œE®c±;ãÁ³Ù+*ÆßÄÑ»¥éšah®¾Æ}ƒ`æV‰»ºˆ³õ Ób}þW‘%ïÄŠ±DðvkNÇ÷¹c9 óhÁŒÙÌW›çŒ=q‡€ ^Èáûž¸,@ˆ/ãñÆÃ"p;CÅE1ï¬üzôãÇ/cc05-W–ó7·ÈïSc@F* Á^ѲaR0#dËÉ6fpÿº±…šÿ¾À¿™¹ ºŒèvvpX”™A7Q3r2í§*Ë“hr *åª*‹ž#Ù;”(hü2MŸSd[lÂ%A:¾N¯ÔâQ!Ë¢^4ÏJ—ÆìSvbÆxËyhé±-çÓîf™ÚŠ;aEÈÄCë‡ÌàÓ|Ü¥‹scî¹16ãŒþªÍN¡Ùå—)HAFAé†3ן˜® ÚÉHnó¼;a;n-ßuùà'ti·ùÙ!ÅÝúÅ]Rîªb3¬­ýqdÙÇð"œ—ë$]$›xtÓ"Çç=Eç¤ûñ£^(x—v(uõ ¥.ñPêjJ] C‰r­#]«IWisL5|â9m˜}æ!™ÆFöÄu€›hn†Ì6‚8|àS¤s#çˆLhô$rkúß|Ç£ÊÑfCQë`͉Hx0b3k?XV§c‹ ïZ—ÇTÇŽ{ùtC2@+¦cÊC褣Ùàì§#q ûéH\ê†.Õ<9«|Ú'gZétOÎtÒOÎ:ÚɹCG59å6~_…Í÷+Pè›JZ²a¾! ØÚ¡¬¯¬LIL {(SÕ„ˆ‡2U]X‘€f({ÉBªÈ«¹'ßÙ¥ƒgC3xÎ3†h i Í <ÓÚœ6¹sM=€C;€›C<€C;€C7€ƒ$ŸMþxà3Œ¡ÀÍ!ÀgC7€Ï0†v§ûŒÑíÏ0†v73†x74†v74†dk¿y71mÃ2#¢*–-<É·ÛÂÓ| Ç_«·L]ߌ§sI²·¢Èr˜;Sš -QÇ´¿%‘Ž&õŒÏÆ,ôS#õC;9Ê5ˆVže¤N<7¢Øvü)Û­|¢K¢»îÄ´^¢‘8ægË Pb:d3îX¸á=~XnٟƆCqWacA÷†7Þv¢ÀX¡ý$Å—[RÇ#¬=3ˆ hªÇ¶6£%°’Z+Íh}_y´.¯7¯¾…&ðëUL€ -AÿÁsbš’® md 9ˆ‚›2q;\6¥ý⃩óZ/ƒ£pxàNü\æ–,tfsâ.‹ÃÄ£õ…CAOÚf 'ŽGT ¼å`þ”¼Ñ‹¤$UÓ[ŽWIù$5ìŽÛ\ƒ–dÊw±Ô_D’$a^L œ¿ËÔÕÅD´!ß¡¡]»64´Ë×íÌ÷ÉýØm4÷S¾Ý¡%IøÌœ$SR’;¡Dz&Éuó-‹è/YÈKÉ"D®}ã~âû®és“–&c„ì–& ZÔ߆8À'Ží‰=0±ç%ò¸ë»cûÕá(nxWh©êåáÈFròSd ÑEšA]d ×{ é¨??U1]‰¡qMUQWd ×T5u%šqí%‹ ñ¬X¨…vˈëU3(h ÑU©ZåÇ¡±iv¦Äÿ=35ƒ¦*Ù*gKýIãN Dî¤È@ãNŠ Äî$½w¢¯ð½ÊY;üSÚÁI&´»“t¿;¡ïObwBˆÝ Yt"$/¦æÿlkhFЙÖ¶s­¡™çZC<Š/¡ðÿlkˆGñ%”þŸm ñ(¾„âÿÌšK©þ?ÛÂQ|)õÿg[C8Š/åÀÖšK¸p¶5Ä£ø.œm ñ(¾ˆkIõµ09 ň+2tµ´ƒfæˆÆ_‘|L9¯½toÖëkçþþîä×=ò›,”Ìû_ø 'ßóÊ=ñ¾—>虼ö2@\ü‘•r4‹SŸdºðI&{þò»ãGµÁW熽Z,oÿEB„¯k<ø‘ø!»£ß¡â±X²_€9y«Çš³¦4eAñkz±ÃøTòµ÷§ŽëŽ4QñÊÒT‘ dpŠñ?Þ1ÔS4°\f†íKÕíÇLmQšxAçÖòƒÕt‹n¡Pœ?Bw9n+?‘ºïBSùwŒ´{Q]ÐÆÊN$mãc“Nuûýö§ZkÚ œjÍi-pª³&œâN/ûsyJ‡ÿYjgPgMM¥úy÷GSítDÑT­z£©ZDSí|ÑT}KÑT)û¢©v¾ y4UKº'šj© ÚXîÉ£©ZÒ6>6Q4µ‰–ˆzr‹OÓi[|šþ¯$­.¦ê|sHN]Î6‡h°mÍØ<Ûê¡| UPç›C=”/¡ê|s¨‡ò%TBåæ\J)ÔùæPåK)†:ßÊ¡|)åPs.¡ê|s¨‡ò%TDoõP¾„š¨{NŸYÐãÿCË0œ†ŒýÍ(Ä#·$"Å`9"A)3_æ-|›"ÕQ¤$í7‘2ÐÝ$âÁF4Õ·øÄŸ„h2Š‡Ý Ç›úDý³Å§éŸ->Aÿü.+¤¸ƒ\8ÖM§“ý…1uÍY§³(6LÏç62͹` ?\~h³°R+…x'r¿-…L<­ œáÆ´ý ÇB/µø?)ØlÊBJ‚Äc¯³bf£Ç‹XCcÞý±Oh7ƒ/Û Ç3cöøa¹Dçp9Iß0,ß[2ñ«o,ìÑòñ£õôl|NÂ}«3]‰÷’ÀñfBÜhG¯R„.è¬$ ™›S"Þ&Îñöç£ó¦÷¦‡a YÖs–/âëÛ¿o§wz¥¿rg—¤ˆ|;c±ëx¬n|ŒÍÃ+á-_‘'ã¾1Ïø‹ Xãø_ÑÙW3¨¹}Wp}0ޤó<_F¿u£Z ù~nŠ<•Åâqú,k±rmçO“›Ñh4¡»ºvˆ=ÕÎ.vi|s¶¶n:ÕI=°D¾UossN­í¼µøÞÈZòk‰Þ^Läé··bCÚª ®ËYõ~ñ «Þoî%‹3î­´aa³ëº-l^eÞ†…ÍŠ‡5ZX|U¨Z­³®ø8D+´z[{¦Bx+&^¬—9WÛ·/ÖÏœ}S³/v4ž}·ª/j>¤;d@§UÒ¶{ m£ª;öÙSÍìÛ}{´º[»÷ÞŽ;xÝflöðíkÿþgîäÛ1²a`£ßÈ3"›vŒlÚh5²´«o‰Y÷<,íí[bÖÞæswø-YyÉÞçì}~KV^²ÿ9·ß–™—<2Ïßó·eæ…M7z8­hÆz6FãñøÑ¼ð¥£Ím˜·nCû_¢ýï@òšÖ‘Åíì1‹?Ê Ñ…ØÔ6!³œÈñkêîZ1ªo<±èÒºj z ­¾}¦-wÂ’ {ç›#ÔÉÆ=‚ ®z›v ß*†ÝŠ5‘´²ŒÛeŸÚY7YýØP.Ô·–¿\öÊM¥±êÔâR­V±‹ì+v‘}5½È¾š^d_%Pq†ÄFM͸ÞÐ a}€t†Q¤æVÑHÍm! Î4‡4@jj“.ϳSa¯=J jošeÑ#g–vb¹,pc®Úœj‚dßµgeìú>ÂI&P~„“ ëðXÞÄ©ä¯ðÉ£Æ&às7MMxj¿žHz¡éuïGŠ@ñ ;ž.Äò€õ<›ˆÖóŒ¢XϲŠ(`=˺€õ|sèÖz›Z¿gOèmLÚ¦8ˆ3áñ|^+FKçµcÔ%öÔ±d^;F]bO5¡ IšÚA’4µCGHr†Mô!ÉFiIš[E’4·…4$9ÓÒäòÔ+žÞ;52¼?)IápЈôKçÆ0¬×Wsâ,;B\xꇳÄKÏ.« w ‡†ÁDqñæYŽe.¨ÑE2Þ††æJ/¥åšQ¤—2^@#å½<Ì™y[íFúÄYßñbêkª5ŠÚg!º­•5rt$¡•¹\è§íÉ.¶M¡(iº‰‹Ê7l1¡Zœqæ%‚N/ŠmÇ7ø‚É„Þjmkä µÅ«Ä&Üe&D+Ïjµ+êìÐÖ›Êà¬5®ãPu¤<<¢èb¸Í•Ñ)šòXu†ª°µ‘2ìG"s?RÙkÖø$eÐ ¨EjS€2 Ð)èœÔ¡ýFêR€.(@# ИtIšR€¾R€®@)|4…‹¦ðКÂ?S¸g ïLáœ)|3…k¦ðÌŽ™Â/S¸e ¯Lá” |òØ®Ùëô÷:c§´«$sÍA} иs³}Þ‹`Û'¤:ÍžGÊT·¯_$ö³Ü>QÄ»¼Ù#*%‚í뼎ì 1]'ísQŒû:ý-zžTS{RÊöøÄƒ¸¢Ê¥$¥")<­GÄPxS†¡›kVÑMønîuWž¹`d¼ÌBõÅ»Åg÷ˆ(ŠïíQÚ#¢Ø8‘I2¥¢(<âG¶öJ¿Ñ´$/ 8t¶ …¸î0–x]¢®½Å9±ö;͈QuåÊ”Fâµ ÝÒÒ+=˜Hóáúù‡Ó?V«Ìúëš¹á DŸ9³ßZoû-ôö&ËC¤Šz¨Öªf)«”¥«ÆMCs»Mn>ü¾L,]}B–†nož™ŒŽ¬uwÅpÐO¹×™ y¾ßfZë†ZÚéÿúÁo±D•{–Ï6ù~,4­,=_ʨïº÷ÑÕ4º§Ë7Ÿ•ö߃RÒŸ°V§ß¼ÌB‰NŠî}g…–MKj¢ðj ->Õ·9ï Z[.`Spæ‹&´¶\ÀàNlYfD“onrPdmŠO«xÑâ *4…‡Rhú¿ð Á™ÏžÐt癯›s!çÜ·JHŒ¹.Çt]¿F8ŸŸZé;6*pj;0º?TŽ ì\Ï~7†¦­ç>CiÍ…Ìí³{¡±†¶lð^:2ªˆâ~s£^s×F±æ¦"bÍ=EÄš[6Šˆ5wlknØ("ÖܯQD¬¹]£ˆXs·F±æf"bͽEÄš[5Šˆ5wjknÔ("ÖܧQD¬¹M£ˆXs—F qÜ\Ó§×C2ž¤éÓS«°Û¥<.‰§<®éƒ¥NPwQL¦î 9¢î¢˜ ¹ëíÆ¯çÁÚÜøõ¢»ŽèC (ŽèC (ŽèC ¾Åq}@CŽêC`8ÎЇtáyú@âfiJåXïܼ?ޏaÞ°ž—øGÓnÌœv´ê˜õõë™§ €1ÜŽvC³ÆÞn®Ý š»©a=åÖ „õíõXí4íÏ)Ú ª§ñ)Ú Ww®v`µ>W»J}†v“cÿiÚ êsåDíÑIÚ €Yyšv‚®ÝX·ðÚ 0£Ú Ç ×n@E®Ý XNÒnP§i¢ÝÈ/6Ñn ¡£ÌÒ6ÑnЩV×¶ªÕ5”«kÎS¹ºgÃùÕ5T6èí‡FÚ êQ`#í’v!½–]ð!íõsŠCÚ ê_®‰vƒzO5Ñn€°ÐnPߘÖnàôÔ×3œvÈÈ]KõÙ‰ÓnP·åvƒzL~P»AyK|D»A}2ÑnÖnPÏÑnà´Ô& vʈËLDœvƒº1µ ð µÔ]Qsí'm½R»¡«—!µ`Ö`&7ÒõÙ­nÍ¡²;õ@î ¸‚bYùÜ»3¾Œí÷7£å.¸š¸ìºC}Rµ ]ËN£××úºñ®±õµô„­?¥Zƒ²ù'ñ¶¿Qþ˜²#š¢¹Gö¦/u÷È~Cèzd».¶¶@BÐ’åáuºTKTÒv‡Ôv‡ÔvŸÔvŸÔöÒµÒv”™ˆÛäkk“¯«M-r -Ðں♆héƒCÅÜzúà Zú@w\ÛÐÚ>8¥üœ¸N2Ao/´0N2AO/´8!ÚÚëíšpðŠ€ž^8l‚Þ^ho,6¶ZßúŸm‹þ~Ñš8ÛÚ~iVdGÜ1 i¡gÚ2 ÑÒ3'$êé™Si¡gZ3§CÚ3´éÆZ|{ló‘òé#·Ûóãyè§FMå‘‹·Ù%¶Ù3¿ái-N᧤fì/D>Ç5gÆÔ Ó¶CEµ×5aD)÷8{ \Çrb<•õjf…4¢"¶Pò®¬w¦Ì±-¤@^KMÁ±ÙÌñĽ\kWH_Üâýn$ÿ¶ÌŠõV†Ì‹·ŸUöžÇf Ó›¹È̳©z2Ò/n4n;>ˆÃ"ÅÐÌ$3ן˜îîsHpcJ2ug‰Ú†9ñC:pë¯Ä †f2—Éâd4|„ÌX:aœ˜»¯Y(£‡L®x`"Ø%³ ËŠýšD/ ˆÀÉ̶ùà‹Y—¼G N„MÖßK‰:›#õ4GÆÛâ*/NñÁÜìõÕXùžé:ñÊXÞ`ñ}ÏbFú¯õ+ ØÅx]ø’,`/2Å,Š “GH;¶C8ïÛùO×™¼.Üî›ÈÓ}sûf(¹þÏY\ÿüíùÃݳÿk¼à«oÀŸŸ?u.oAïF¥ËrX'ò]3î@‘ùLð­É{657¿ýóWþ%\*bÎyP`>šaÄÞù^Ì÷Šp¾kó>üã½å/3v&Ž˜¬Š˜|ýœL§,|+¶¢ckÎL2ïÈ yìüƒ„}›ä'± ÷!!߸F1 ¿ø6Ë ~7ÝÑþïB‰ƒówsf½8Þ ‹? Ñgù6Vû…y,t¬‘P&Á¢É¹ôª:—$hü‡z"ÛŒíÈ_äÖíÁsâÏ 7õ=_-B0Q+¸|оÀAó\ìÃWþ±0žÍýæsÈØ×$ÀWÿÈXð³kz/àþ‰Ge ÑþÉñØ—D<„€¶Ñ7íÑkü>¶ñ¸,„|ðì3g Ç»™1ûà¸LhØPbƒúA®õá{6If#/vb‡E(Ь[Ž@ûæw>¦ßÀ1Ûä]l­»9œŸL'b ¹ü”‡ïLטÖK6 ~:ó¦^bŒÍ%ûâA¼z6g€Á;v‹êËq&Vœ„̦„EãdñéÏ×ÓµÀ~&±f+ãXž–«!NÏQCàj½fƼ“D$¦€Å ê{fa7·–mÆæÏ"RÂÂÎM!eÄ}$–o¾pW¦…íb¾ÍD˜bw¿]‚2ÿ.~¥"yL¢9!Éξµ–á§NçÌëÏõ$"ž‡7Eî7. ÿ{5‘%b扇³è÷Bƒ8!™d]Ì182ˆd}²Æ†Î\&º¾X0N^ƒ"èðM·£ 2Ï&w”u–{¾o_ùjé™2âbX‹§~8qldÁ?ÝŒÅï|7YxÙ&j5Ç–z…FÝ&%ÐÈ4‘ æn‚CóBÓ#ÉÄu¬;–¡qeš¦«çf4¢›‡ýÁ£Cî[¾OÇ)+õùàMW:‰ýw®1¾†ÛM$oI>³…®êionA,„¡¸$á OÌ´+QÉð úƒM†\ wØ_©³qCƒ^q(àß"öU–FhtýöO8âe- |g)Y|+?"Ÿ,‚~¸0ã,[OLEG"Щpwg=û•ÀW©Hrä{‹|¹ý•… ½äæ ãØŒ“ˆ„€. ’Á‹`õ“ï¿$ø”Ë44aGÀÿÂâÏ,6×… püÌË}]8qÌäFÎ è&,Ä£Glì"ÿÙ÷EÅ®ˆ˜ ÐÇVèñ[’ÃÁð…¥èŒÔö‹ÿ>~O]?›¸7V»å "ÅBµ†'éªà»Ë–‚2Y“Âg« zÌSéføÄ¦p³‰òôh @—§ß S$e·à2, ûš$^€h'O³‹§ÚÁÓìÞévîTCEl’Ñ&*cHyDK†M´HމcñgsF°Iqfžš—ý1wb‚l¸(†)Ö+ç” ø žÓ TXNO6©°ÔÕøƒIx”õèƒG“M¢9•ìÀÉxLèÙ¦ë{àqŸ]õyöÅÍ(²¨BE7‰‰þlÞúx ~ÎíñXÞÞ>ßq8¾ïÚËOõïsÏåƒÐ·Xñ¥ìÁ‹di¨Ô'6"dS2¼â„ŒO½%#8åæÎg½«É¯H¡áiN¤£Ø c’ý˜D¦Ø‹%^ ‚W{DS(³)_´É@Ñ.äÕu¼—_øÈË¢÷,f¶¯+ Á†¤xˆ>9à4†Ä“wΘ¶sîÛwfÌcÙ[›¦.@Ûì'¾;^b}V ]:tbø¬~‰˜$+f"&ùíéÎ`ÛoÉ®døï掋ü9î''»‰Í×T‚0#ÇŽm2ìQmoŽžg@ÞºŽ‰=Îð°çJèöîÀ™›jÁ?†lIg<:ž¡RÙ+„ŠW[É Öå˜àÛ§pó¹³Ð1]çoöüçÕ?åÌöP™%‰ý_”Þñí):M\€çA«¨Çzd‘ˆ*Ã…ãQ¬!9É–òÏÿšÞan)Þù‰Pà$Ýò÷î(‰’îe¡n ³õÐà'áuCFAä¸àôM™á ›í4bs9CñÕ³ùðÝö©ÃâøÒ~G¥žR-MßGBÕ¾íþàˆ¼?ew Wõv¿Ðò}÷Ùfà*¿­">5°þ•™Tà[-lvzÃðîø,w‹L¼sÁåÝJl¡`FŠ/öJÐJ– E,C–*!4Т†˜ù)’Kü‰y³œ_c?±ˆlòÕàm¦BÏ×µ~Kh“ákì?B'fï~}ûD ?7áaqþ_‰ÏÃûLÏOã¸ö¿ÄQ88’ÀOÌåƒg' ;T]Ýàdw^ÅB“3J¬Rê§œx×é¡»¦³%µ]„ÐÏ>øè•YèÂ~mz¾'´ÀÊx öôH†LuJµE'ëðiÿn­¯Nƒî{KÂÃ:Âó»Z”ݾ=[†oª· 4çw[|š£»ÿ!"‰stùm‰NQk(V(ÒsfÚcf§Ì:™ÉϘsYk1IàQ_^ú¢GY~FNƒwy<òy–¼Ô/£ÞâpÂHÊÜPã?(*Áo!<Âþøšà‹ÖsôïÉôfÐÛ092ß@ÙñN†ì‘@3ëe­µKþëóó£<_…w7ÿÄ¿cbξDAÂÃkÉ×À¹1›oXóbyÐU$¸U{KEâgñ|>CeÑI^ ‡÷ºU©¶,w°eùeý”Zq÷v—ƒ#ÀLÔ‚ºûrvV|AÝ‚¬ƒ ‘n†€Ïvêã_>Êã5‹ûu IØ5îg»:"3HA€¾ðº…ݬ65eMu*Hb|ö‹Ãî7Ì@6×®Œ Y°Ð¤(9ðâ~*:*ä¸4—zªà%Î’€{y*\:›³r[²‘ø‚ïpI:E¬¿_×—’¬©’‚Öl)öˆo"Yè| µPé†ãá+9ƒÜÊÞÀZű ­n8(¦9ð§½’XÊ òoóB/Ž4 ´d¬tM¬^S€Æ Ø€ñ6p°øl—vðElG®‚ïØ4¹< C±Q Øû½ÿúùÐ ÞÚ~Wã>îNPøï„ÚF ¾r}BŽ/γk¼!Ê|QµO‡þÄ,ß³¸{ÙDöÕ’z“8M%ùÎâO&–ëTøSNJQ×Þ¬‚S„ã‚÷Ïðƒ‚-6…àCEõø†„*?º! Øß–ÀIÐ×]G ŧ©À,K¿ãÑ+ÏmרÜ< ך¯ã€KÍ—H ÚüÔªP¸¤Âkß/ŸœÑpHÙð:"µ‘%LŠšðþr8þn$";.¡w®ŸBÞ-ð8™€öè•ÜJ˜ÕQ.ÈÕ» Îà›òß"s¦öxj޵+* 2òk ßûØ‘üT§G‹7Êî±*kÂDŸ»3Çvâ• Û¹ßÙçå0 ¨xv„æl¡]¼ ‚·L¶°™4-ÍM‰ ´Êî–…´ ”ÆgÝCô‰¹Û~ò}Á¼Œ`LKo‰Éd J$GHrKI§~T€§3ŸòˆmC€×\ÌÑ)¥Šø$Ý#¾-…o |Diý‰ñÑšx÷ÑŒf9¦¬Æ7$ I1F¯Èè~™¼ÛI׫ ˜lÀEHB^ XÌBgYÍ#°w·E0ØšÔ<ZƒfÅÝ4èc!¥Ký}q\·ê AàŸÍ×gÿ…yÐB+ö4ÈDƒDÈ…4¸57DPЕú]°,J À­¨‚P³<7™¿52ÉŽ,ªðçåÀŸÍØ‚+x௃×T Ü'‚s¨Žg×\/ÁÓ„Ñz×¶#„ ¸(³WBF%‰#@iwk’!×é¢À&*þÐî9,m…»$ÁW¸ XÚ ÷ÙX$ÝzgdU§þá=™åòV_E™ ¿y.à?sóJL‘‚^ãRœügØ„)Iß¹g¨TBW¼»E'ÔdÎHb!#]vçu?GÞ= Á Ü„XãR —'2oÂ7'd“2s®»;WÌš/„KEM3ººÔuCWñ p‚Òz+D«Ý ¸†ý‹õ™-~aXåj ;fqùd\x½¾‡(‚ËÀp GqžŸTï—¸ qK(ɉ4lA+,UyD…¿BEŸ ®_äólô 4ϲìX¾²óžEð½c†¾9ù$# ìšíÁ!•õÿ¢íýÑv?i•¥ÀÍÞ9ɾñ'Ÿ"Và4˜'!ÅÔÍ‘Iv!>m!ѪïœÀ/ ÈÇSˆnoæ—IÞô"¼( QQO`óÿKTÝ, Ô¯hJd›UÅ^QFSM–ݾóÍ:\¸§"[Š*Ú=4$}Ãw§ C¦1ô@1Ñ…àÅEGý‡z|µŒHë\³XfœüjF5k%âX‘#ÓÌOL;—ïÆáªK Þ£§À•Ð$¸$Œl‘E•;:Ë%Ð)žÒ¸Ù•’±—A“Œ¼Ý‹(äÕt >+@÷è  ³«Ötª€O2R øðcËôHìÀT¸×%3Z€“`¼œ#p ìLš‰h€ðIú¼€†øúáù‘¤JK"“”iIdŠ:- LQ¨õðU;u³€&êgMÓÑkä?h i>¢±8¦ø–ŸMÇË–Plç•ÙD7é¢ÇdâØ4npmÄæ¤öcvJ_³r cõŸ¿>þ„†ýÈX —±¨FŠ„€æIxÓ]:xžþÓ@AÅL§'‹ ß }]¢Oàx/¢Ž‡à*’8cð­:Ü‹ dù– 0Áá’Ä%9\Èï™Ëˆñç(–äUP L3Ö>„>~±À^Dð´®@þÌÂÉxôƒŸM ¾/Ë¡ÉzZÈa“Ùˆ#X"ó3ª·øs“-¸¼¦K/–aô% ñyñô˜/1øìxàÓ%‘t†Sœ´I\ŸÆ’ô°oÚo‰2›žgØ£WQN­f4…‚mІˆôÆIÀB²a½|r&¡‰?“øÉI)Ò›Ÿ""UîϦ¸i+¬Û)g—ÖwÇPØŸü ü=¦C~æû…—ÀwÔß‘Îð>á¥>³ÅÏù¥ª1<¿w¢À5ád‹\ KnÕk¢88E)ÞîÅJê™§üĨw®‚¢pç~J»ÿ¥r%ÿ³F¦™Ô¿E ¾ÎÎà)T&3dš7á?ûvR#F…ÐQÏ w%QÈÕòòxµ˜ø.[¨ˆÐþ ðožK½yÌH–S|yGq½¸Â1~?¦(Sü‹¦ž/ … û'ó=üÎ}ͱû  ¯ˆýÎ÷å >R‡ dh¹ó'ë%Š'ŒrhŠ{ª9t^,¢ø7‡~ ýWø¾0ÇþWBö))*‹shqµ‚²W²k¿=Á ¾¨º~›Äó_IdšÖ „AY…þ<“–üļY\}ÓUùqÑ5IÝÃ\€kbkøŒàžÁœÊË ,žû$w‹þÄl‡lävìy ŸVZÃS9ú56ißPùä »b8°ÓŸXœ„Þ;‚düšal.é°É–+–Ré*‹hIIýL’Fàà4GM™^d-g!( ”Èj;×_PÔÀrd‘ì •ÔdZîŒãChÎèZ@q8¹E™1IbL<>T:\=õáè’dÈOfJ×ßÏû3!ÈŸ"Ž——稴êò‚`§ŒpºÁ%ÔOçÙ%=¼¬7‡~øJkºDÿú ñÄ>™õ$JÓ—ȣкo’ñG£Tµ¦ëG¸jµ%»­,Ài:šFŽ]×½ç ÂÎŒ¢uD‹»€¥Ú+ÐE tõ%p±Êx4žL¿„]ÙSžy(Á×õº $o|–ÄE„]Ét_= ð©Þ%ø"Ýþª˜À̓ó±3q+™sÀíÅ/þ=êÔ":zkÛT[Œ:…å?'Óì¨z7uÁ§([[ãPîQDO9˜ÇR4áxÉ_¥%‚ËJ§q7Iã‚@Iˆ“?½%ê%Ì£r •qìÈãÌÿàxÄTdo…ÁË‘3! ï„ÌŠ©BÊ0»¸H+ä4Ä$²ºšöÄ{Õv¨žŠâìûÑøVšSð=¤ø£ð=D|‹¨‰I<³æTê»ñ\¿„x‰Ç’G‚J‚ Ù‚ qG[?žó] Í©`øÙ|}Ï‚ª *Ôxä†Ç§Ôä•pmذЅ²–߉W„±Óšâ3¤x¾.'É‚o¢È’ÌôxþìWöj|C¥,ÐÉEÂV\Z}ò}¸B@Ÿ•3sQ½ äØyôp…e]ç!p–;^ ù–“„¿òÚ+a¸$ñé¦"ίÖc`wžH‚Àþ:ð)c™…®ÖØš³…ùnά—¦Å*çE꽑Áï-”Aø®kQä9BU`ͱà{ ¶[è lEáy•–Àx‚]aHünÑx·ªL7ú•,)ªÊoPpªWßJ Õz@ úŽk[fhÓ¸ñ€WâˆWñ¨ÀØY®ü1[T? +)Ç;Óó=BwQ¢¨ñz]ÐÇyä—ù;+…rýʆi_–$d6›:Þ®/lîd%„5ãK¹~°ˆ_W…ë©ÚEX=D…I¸³ˆàfâC$;Šfnª²ª—umHèÙÜ8’/_Ÿß>?|ýB蔉âþõ¥^ 8¢²`œ¶£hã’šZW²HںɌ¦ïE.Õ èà•é¢úçÄ*]õ„Èšno‘.®E’âk ÎN«Krµq™„º8cãTY"–¾j™"¬ãvX¾øâ%HšXaãOx`Bú¥ŠDõÞþp2±¥ª+ׯ} ¬Z›lq/1Ô%F@Ñè†gGå;× Ÿ˜7‹çuá"r —‰4t\yûK ¯ ¿zuÏ"§©¨¨§ßj­©2m/* ¾õ æí#$÷ho£Ÿ}_$}©iê¾h–/;O‡ dI |“9¯õ¯ båëMú^5wŠ‹Öè{w`žÚKsd;ŒeÚ»m…3i¢Ñðv6fXøÓÂèh©Œ{b4H³˜Zs¼ØÎ÷çÕ¯!þòÓ˜åÊo…‘¬m•½…?×AÈ¢è3ÁM«¬*”˜aó’\V<û!!( a•÷J?ùBÖŠ€æ3Å”#@þ…y,t,9—‰úH>*MP_ÉbŠ ÌA)nDŠä lÅ!W?"¢˜Å¢(„æ&Aþ܇î–÷@8æÌ…?#A6#ü”ÀïL¸È‘Ä}ïÐôîû„öŽTìãUü%°Ô§¢¸œ¼EÿSh¤“ˆÓW8žXD D‘¤4Ý/êÌH€×¡( ø¡C€üâ?»¦÷"îWã—I/ãdZ~³Î¸N,åºtнrVI=ù·AÆÛ¬£Ïc?_ñÈáè¯ÿv Ç•NkŠŽzâð_;cp¯3X}ç‡H¬>ÊÌ£˜bPXÁG“ØJÒ·vBÊÌÅ£¯–Í€w®‡ ‘Å:ôjx91—è˜^½õVD Ž7«Ñ3Ù^¹SFOÂP¬,@ï¼€Îíkz 0 *$õS­£¼DVh„¶[Mùà[£‡AÊq‘™ÇMWZŽºB(4GM)?šâÏ…ûɤn'©UΕl¹Ss‹lKF±[x äØyÄëáG¯Y®EhoáÉ4 äbHÖEE’/¾šˆ’FÔ5R{}ïO^޶W#T½ü±†nŸ¨' Yµ ý¥žØÂt<»ú™€$¿šÑfÔÁ“X%šýÃÕέH!mjêÑÑ<›ÐeWๆÕ\9…ºçÚPÛW¹£ ÀË/C½YNSï\ÀLþKlÙÄÿì ÑúÕ³ÂC¸€V™èÖÐŒ©ö8Ë'Œ49™¸ AÏEëömûÀ, þTQ¼æÉvèFIì*ªWÀ]$æ\ço³ª% L»{ol+8>ô–tÛâ5Á£‹òë2òQë–ç_‰3ŠãÐ-…øoZôsÚûº ŒêÁóXøçÂ%%ùÊ›BN2ŽMBož1T“S`Šõ+XÙ…2Ç[yf‰Œ§|!´R^ì¸2OÍ•- kJ,Œµl¾kÇøãì\w¨}þ@ù¡ÅcRß´ì{¹e%Î"Ô¤§Q²2:yvm€ )6$ïÞ¿}~KJP÷ÄEn(*ùèpxþ)ÜJE@!¶ÊR+`€g©y÷LBó,E‰ƒæiŠÅãzÔ8]¼–IßE|•xð숯0Ôj"yÄk$ôî¶LóeLKDëÙ3 bßž=rCèÝ×µþ€‡|J®y(Þ6ªÒP{yÂ'ˆêI¨g$á‚"ÿ›Þƒ•iûKþ·8¬ö‰9ïWFQ’Sà õÄÉ›¯JO¼& öÄkj¿²á¡õÄš’$‡fºüVfD¶§XÓ®gÔÔÊõ[Š´DZF"ý 'ÿ;{+HÓ:T!ÓÓ6 ¾<'ÒáÑ3*r¿¾¡ÑâÝ7lZfÖ†M§sÊH5¶O«ÿ Ž“3–'3ÕACV]`¢î0ò®âŸñ:«ãCü®u¬²QÏÎßµ-¿k\×´þ®wü]ï2ø{+ëàïÂßµ®„¿ëY ×´þN¹ÎÃ÷lZ ÝÕgg,yíxF6vþ¦b ÙŒ{ˆ¬ú®¦^ÇäË¢±‰/?J¹ŠúëÆ0Ê_Xü‡zœjïÕfWvz$t¿&qÐôáGÆ2Õ1úölëÊ5pù¦=zßÇ69Uöq²Iõ.dùà âÙš±x; £Íʃ޳I2«“55/ã‘×àõ·‘Ù&o›µn+ñ—|Òä·<ã8,Œä¡—³Í©NV—€µN8ß}‡ø’ð…ŒßÞ¢·lÆÌünbUü]µÌÍ U”y{YâYMðËv_hN¸²qz§ou’ýLDÆ#Ç„Ë0å࡟Ò|ìŸÍȱ>ñÞ¡±ügæÍxIƒÍÃù:ä|3GÔí~à/ü©O .Nâ¸ûƒ_§ÈI^߇fJ «“Á‡¦ãºë -D!™WßJÅxìŸW‹ÀÊcŸ>»Lw¼ZL|—¦ïþë£|>v&Ž[Iª‘Ð->U¦›ù³Ð æºéÆIÐ\Ò^?™¶˜òñgzö#ãdçäIö›çLfÓ¸"éï„b MÒìÿ2Ý #[·ÇdÀdÃyL“fÈdÁ˜lhüo2`2çü¿á*ãd¢y2g¡ÿˆœ¿˜8âù½cZ¡‹]øg3|!jÊ>¶©Ö$†P9¨ í¯¦;ÕкM’yq軎<#â‚©ÖŠ´« tüx¼r]sb†+’ï¿ ×%:ÇYƒ×§®PMx/DÍþë=[šž93ñú^<Ÿ“èð`äYBŽÜ–ƒ^²ÇдLïþëã'&2ñ"‡ø™ÏB¢¬Þ(ž;~@4hå½éR§@aþ‚Åü“Œçf@ä¤8G8£:müÅç_脌ÑÄ’™ôÀK2˜B´$ˆ‹Âßý’|3C>0iÌOÂEò2§1FêØ1wG¶P˜MwHô«éÍ·tpó_æ‚&àϸˆá³HÀ%òœ#ñ|ŸbÈþÊ&aù½%œÕÎlþ:K3f¿ElÌÃ2fLoÈÈ)Box& øÃãÛÍQù›3/ÇâqßÈbZ¦3ü‹º’ô£éMšUŽCÏ^õ,…gÚ4ü£›/T£i þ8÷=QwV?´P>äã|\w‹L¸ÇþdÒ, ²«C\ IÖ͉y™Â¶á2ðïrÑœÆg[ ×ya”ÉOÎb’ŒVÇcføsîÈ43"ã Íl|òSâ¥ú³éš+þÿ4ÉéÏf,DAe"°¸…§TEίßÇ>Ñ’ýÙ‰,Æ¿¾Çü¤D›7ï-Å8Fú39)éÇ«!â­Ýª`’–=3k¤i›ïÍ|—*•¡¡þòóÊôxAt‰]* ÛG͉|ÜW×~ˆMªôó×@NîÍæã‰YþÌsÈRz_CgEi¦·2)&±žà}»C'éŸ-üÛ‘tÓSâÒñÜ\VÊè±ãÍy|BcöÂt]ás~7Cn>ÑÆ80-qjèÛ¢¢6ÌOˆ¨˜åPíñù&Û-Ó!bM—貿¡bË·„kiÚ³93]Fa5‡ž˜^Jâá«—€ýá|b4;&¦÷_ÜAf¯žÍ…CÔ?37™ÑT7?ÏMª¬'‡¦9{v&,&Úáü&JˆÎ#óÛ.ïx‡Û<x;ñCgæxf~\EUt ãË™Ë,ªu`—…¶˜å¿iÏþÛ¡=Cüo盨%c¯¦Èy¥§‡Qd™ø÷ä6Àã¿QzøÍcktŠë°ÏîÄN×ZT^*ºG ïêa`ãÐex—#ûøø&Cöì_)›A>~bfÈQå"¡“ Ùsï¥ú=Ù·^>9“°rð€Xü%ª¾ƒ&¸¯¶ÙW×þ©bI)°ŸǵsEo¾sgðèQ²ˆ'æÖï~²ý5ÂøÄKì¾h’#Rм…!Þs­‰äÿR)KHp=g|¨¾2NBBÚ”ºGK(ð?8gà’^ýX€&5½F©“žrœ~yW}–zð¦ÿüì¿0 ÐpM:qåkÝ´ ‹Xô½â†äÏV΂œƒàLhMñÕ«ÐÌAì‘8Ãæ¡y*ŽG?¨ià™Û AÍß½7c“Ÿ¶ÿ"ô}O¾>>x–›ØìCȘ Æw^dF1|a)-ßõX,‚Âøn嫪£¨ÎÞQÊVxªûfü·¢™à„P ƒ†O²¡©~–[õ齦³˜¤%f<kÛ2ÀÏþ³ï»Ìô„š,EÙŒäxgFqÎóìgµLô<4IØ ˜€ü«?û9!=qÇmx4tœ–ÆÐ·D¶AÃÈyˆ›“ÁÓ7gÍC<袡 ”Ÿœ9.Ǧuü‹@ÌDš•K^û áÚ(¾%+bÛ£%>‘¶CP; QiÆäYfL;øîÃt¼ˆœ„oqø"øÎ´æÕðZù)ù5Ç’…1©kÊ((}SÆ@éœüÄ#Qñk\3¿‡o0ßY>ò>Y‚côÐ|ˆ Ë×É7fá ’Ã¯‘0ŸšÊá£ØñÈlÏÀÇ~ãÕ rŠ%á 4ú+1]Jü0,~,Õ¢&€ÉfÓœE•×!õ_ø„õ†!éÒ5Ë‹*ìÀ¸>˜nÄH½ô×Ï^º¡cÉSB½'; ÅÏ÷îÔøŸ*RB9—0Ÿ½mEú!òaúÉ÷_ðÕc5åç%a$¿šÑØ\0ºÛƒM:£<‡æËGK#FhyôàÁÅwsä/&\¥z,rm+|±®„ÿd§(>™íFã3mªmRŽMÞ~ò-Ó碤}ôÙ§<âø¼~»ŽþËÛú™õÓ*ð×DÈëjƒßžH?ì–R¦:Ĺ4a¢þØ Ïã[üË.kpʨp Or ú “Ð éxªgé@‚×ø­g±(öiv/E‚¯á˜¹4ñ‰¤¡*äÚ0È¢n2t¡†Ç<ñ’® âoñÁw]ŸâM¿]†±3q)‰È*ë6 ÜKnáCf1²²Ä@ý-èÆ,_‹(í>a°¯¨omjø/D‘ð†à7Ïù _¼\$YŸ’rÈ'Ø)Þã¯Náe‹>³pFÚCOlá/IÄ„&ÃÏ×Rz¥5©[Êo’Ñný˜ú´‹SÐ6!"Ìýæp”ög)øw~¿5›Á‡6 ßû–¨â/}àÁ›!„à‘,a"7¢»·º`]“á“¡ûeF\-y¯súr|ÊT†€§«•áè„ †G?’j‡¤ná‰Íœˆß·®»æ¡ñÏk"ÁBN@誋4D‡tk ¢èn /Åq&D%U _dMEüU˜<áŒÞ —KÜ"Æ7szxÖ}GKGqO.N<Úsçql†qô‡³=¦'¢«‰(ó!\µ2 íøÄ¼u‡%Â=…ú”-y;‰Ãó ÕÏlꇴ»± 1Ë‚Ÿt÷­açÍ)¼È5cÚoý&´rú}p`į̀ÈCˆ2QñGh”'ÚŸt¯&(7kŸ°XR¤Æá[{iz–,ªCÀI.y(Arú‡4Üî“éÍatм·¨\Êd=I:¨Or^Sb :ˆ(‘œE”ˆ JTçq(«\× "fË!LFBTî"Ñ ]Eæ§ëˆ¢oICù%$¶0žª6½Ìòè;eeÒï [@!é¹CBÒ ÿìÓÅÂq(â—£+Ó ÿsà7ÿS4ùŸ¿X÷0Q,^ôtÿçÝ?_¾üfŒ¿þöôn$ðÏÎ?uÂ? ãç‡_~Ÿ·Ÿ~ùòyôåÙ0ò_Oùù»_ß>u†Æó?ŽÖ?Œæ|§õÄ‹ø.‚Ùÿà£àT ^·toϦw§üèýÏŸŒ÷£/_Ÿ>Ÿ¾¬Úsß¿†ýÁ]¿Óí}öS¯Û?ðá—M7NýÑèqüðéëÆ„î›n÷¦ßÞôﻃ›^§×a?öMدoÇëf FÃú§_><|yxþï³~ü¯ßFÏÆ—·_ÿúó[>þ 7èþË?Î1úóqýÛÞÍÉß_ü¸ðËÎÍé_Zütý³7·÷·Ã{þ¥úwÃn¯3¸eÿÑÄ>úÊ-ø¿êÝÜþ?M~_ú1oF§Ñ¯ opsÛ»ÜñÿéÞtÄØ?±£wî]u$wF?õzï?5¨ŽƒÞißcýãÒ×vú§MÁí¯ó_Þ¿¹?öŸGï7kZõ3q„îiŸi °íXþëf];þígáÞ–>ùÍ››#ÿiJÅ]ùî(¾ÿpúÏ«cà¶ÉOK#à¾áO+ŸtßÌîê¾ïŸúyó_o;ì~ЄùЧm6ì×|½ÎàýûÓ_ý|'.]ùoKß{¢f¿Ý7G½»~£6T?eïî䩚ÿ¼àïzM¸Oš§ aÜÏïù¹Ùòœÿ¼ðI»§þÐý.Ú1zþõëûÍOûíãÓèÝÛçÑû–Ž>}hԲџïFÏ_¿ŒüH†G#>Úž5¾~ù´ ”nNúñ§çš˜³ó¦ÓéÞßõ‡ì§þऩ*¶ä¤)&~SÜo:÷Ý›ûîý ûéödâs?ªøí™áéú§g…§ëŸžŠ_W}ÚiaböËðô¤€jýÛbtÚmôË5\Ý»n¯/‚Ò»“¿qmPzZLºþy9&íýx;@oýû~oÀCÑÓ­zûþáÏFcó—wïøù}d¼ÿãíÓ‡®ñîÃñvü¹Á8Ù ŒÿûË;ãÝ×ÏoŸFÆÛ/ïñoª‹ƒêã îš@}ùíÌZ<|ùôðeÔh>Êßò!òõi³g?ùgoŸßýúiôûèS£àRþöéWãiôiôv?½øð¡ä¹NôWc™â.‘îI®jüëS9ìÞOûáÃÿ}ý`¼ÿúÛÏŸ6Æžäò_~øôu»ÑÍþ„äªý3¥ïÅö2ÿûÒŸ@c¡·rJuÉ?ßK²cßfó'ÿ×ÿúÌbS<üùÄJÚõïžØ_ ‹ä+=güì1ôcßòÝ&?ÇfœDïNµ“¯$¯¯æÄYvNüãbá?9éOóuêŸû_ÿ+süÙò¿8Aiòïþëê°Øýù[ò'ŒÞúÿýe »¹3˜Çq`ñN~ˆ²7uSZD¸_#<ûòˆ/6rž>Ž£qÇx|ü2æ»\ù/F¢8|Ô¾ÿ+ŸêDþÕ˜yvÖS£ÑíŒÅB8sô8îgÃÞŠ¿zbs– ‹|—!ç€^™…‚¾/BûQ¼ûôî?®_rl=ðä§Ô¹áí)ã°ô«w®åA`Ð=~dVümöá þ7’Î#ÌzHzü&pŸ­s|Ç÷™Å_~öfîv)ØN’ 0Ç#>9nŒF¸fh.šviâFéç[Ó­C˜&M؃æm:+ž;PD,ëÄb§8B;úŸÿ9מv.¼·´«ÅŒªöõY?oò…þùÄâ$ôÖÙ§Î ÇÄÅ_Eýìvrû ÍØÿß“Û}ÄVQßxÓkì7߆±3u,Ç<)º*ÿ¶às»ãEÅß¾çž5L,ÞÍy‹þZ„ç:êoãªño|oÐl¥Ùçà<Ä ¦Žgç«òûÎh©2º*p ~w¸yŸüÁÌ—ãACñ?§ŒçûÖÆó]ïxuZñ·?ÈxîϹo<÷Þ3—‰×O²ÑÜUÍ%°F@$£²«ÞžrlXú­¸/ÒöÐ* ‘n3G¿7¦}Lâü“¾ëŒžø¾ä6¿{Ç\þw½ßBgT³¼Æ½´q¯à×À·Œ¶ín+¢àܵÖá}ÙªOBÚÙÝî]{£»qx¾‡l[†ÐÎî nœrý†}]5vÞ¬KÈ­Y¯ñBR îºÃf«î¥ ãGcÅ_î ~a› ¡{ š¡Q î­rç4ż ЮAÃAœkÐpìW AÃv]B }¥ ¡Ó¹W<Ë—Ê Xç±ð¯WùNgÆbqz)”·&•®ëú©€…Uæö{8˜y ¥Ÿ‘ø,ŸèÜ4œ.P™@лSÊ6vÝfÝÿ˜=‘Š'hx(¿7µ¼.\un#¿sæÅïXÿ9¸¹Ïv¾øëw!³E¡é^÷ÒWÜ·‘^üÀu ‹Ph÷o:ßA¤Tt²ÍÊa*vg¦Ýl¿«äf{·Íu*nVT˪øÖ!&Êâÿý[r$ñ‡Ð_|°GÒ—–}îÈY]S,õh¤¡Øðz,SFÛöv€SZ÷×KmÛßS›_ù‘²+Ö¸=hÛžŽœ¿™‘†NŒ-¹ë÷ÚK×ö/|pÿ{&´ŠašZiã&z@Ægƒ»ÆñYYw¯amØžp«ÛÉ.E–0cñb;¡ ‘öFà›«y­ÔÎý¡cÅßëž YüqåÓ×69 †JÙî}·ª¾¬_’ÐQuCHþDœªÖãqè7UÚzõn;Ç/* û¦,™xCÁn¡P³Ó‡¨ß>±Àu,SµÞ8‡ùNëŒûwíÕ÷N±-ýUØÑêðBÐ;‘¬×ÊÄ­¶îÍúïÖ×Eåe¶Ñ»¦Cûšœ8pâÞ;ƒËq+Nk=^Žçyè§ptßšÞ4<—¹: =¨Ó]ÿø“Üñ4²®ŽçTÀ­ã¹to®Žç<E ÙÍP%öôÇ•‘‹¿ý1bïˆó(û Õ¼ˆufVæÙšÒšÔk¶»ù!†Õ=xTýjFsÕ~ ¸åtmÅ;·Ã~K×ï~Üxgìüm´ž> ékÌC|ÌçÏíõ(¸„V8 n´tì+ú§šÔÿçß9Â6õô%g=hR¼¨âªëjŸƒUCG]ð·ƒ&ƒú€, §~¸¿7c³a.KÝ»‚œ+t²£]kɳëYS½ÁLß¹¬X §|ÞÞ6=h+]WŃøßše(t:ýûæ_¥üÀR~ŠåIßµ”_GQy„ï1þåø:ˆ«—à5~7ŠÞ®[’“·íðöVY¨àÛ’dÔ± _åÛ¦-jBç&0 lQÓçªaxÊÏÒ0¼Š§æhW à U˜áŽGiûyÕ0<å—§i*n=.Ið3è5ßË¢Ö³Ûûf[Âëzvt= †WMÞ-ázvßäܯþ?ÿÖë™Ú«ÏWñÔ~xšx*èêªOm}9(½œÃ—¤Ç-ÖäT©¬”Ê× Õu úõÔSÞS]P2 ü¦ ´«O ¶¶Ú‹ùˆÌ •äôû·ƒïné.ÁCÞ îô…ºÐ;Óš³gÿ…yÊ·:KhÈoÝX!³|ÖÙë4[[.áâo1Ðì¤vÿÞ­–âSãK’ïU„P‡Äˆ¾1ZµQ­ä¾¯{/ÿû7¤á§­‘{Ëp`™ÝÎMóé{aro©ËÎhÄ{6å¸pÉ·eYïM(Àé-¤ú7ˆ/Póí‚"g°þ¦PHƒv·Ô«»øðV‡ºõ5W…½3ÿÓºÂ^·Óiž¡¼°µó’/l.•zB-ãü-Šz½t§ß'B3ÏþÝôºy?‚›¾ ¡žø;B¨ âˆï\µÛ¹>,süw –¹> …?Iº>,SÇ#æ®ÚíŠAÃ:]èM/ÔUC‘†äݶâCª™ï-.ñÝíõ[+€»*üžôË~@á—åÖÔׯ ¿'ýò$…_Å‚¬s~/h·§º~ÛkX õƒŒcÌÕÈÎÍcƒÎ¹·HPHÆãmsåô‹“œÄ¤‚÷JNŽ£«Ød=ÚUlò0ؤ{q×aÏîì«Ødãÿ\Å&åâ5è¨-^MÅ&éT#{ }cID®ÛÖj~Ÿü™ã=ò–§~hË%mÜmVÈs]ÃN,¾ÌÚ¢fÿ¥¯a®’×U¬ŠCÕÝA>ù/®Çõ.eJµOõî¹ )îÆÚVH…dŒNTH½îÉêÑ®š©‡qèìEJœþ° Úu[Ömæì÷ Ê6*#¸/ÏW½æg;„:´lº7EÕVaܤB»n2ô¹S }®´™­âQñhÐv‡7Jwp½†  ?DÕcÃ#êS¤wêÅ@G#ÕÓ¯³„Z(ξ†gÜ‚¸JÍÒJÍv®R³´«Ôìaœ«Ôìá_|4ÔlwØmï½ö«4ß ? i>ÐeªKæã£ªµâäÛa¿Yðºœ]΄¦ØUiv‹Fy¢t3èÞ^׳ólž§§¶ž]EAOøái¢ «(h†v=Œs=ø+€_ÆŠ‚v‡gÜ£¼Š‚–}eUTõ"XY´õ À·¯R¢Õ1R’ µ›‚¸Ñq×ô<³TÓwsÓ$DC)Š…Àiâ3MÊÙwÇÃ8¾ü†0 á@¨Žƒ NŒÆƒàèèuûJR>w7 ‹}€å 9¯*Õ äŽÿ÷£° µ qpB¯;h^±parzCHÕÓyR´W¡Ù ÞíÆ.]hVê^ü–L‹ÐìUÁð¤ÿ´®`ØëžñžÆ…­ŒwÍD8Ïš­Ün©Y)ù?%ž£«mçßhµÔë¾;ƒaÃÁªíSâýÀî;oÝཕÔëÏ“—Œ„Õ®ìíŒÅ²úzD,ÑÏ|¸úüæc²óTÆJ7º† _u®8Ü|T"SgÜͺ †ž ª˜ß.†¶œÞî5Îl^ßתy_K-ͽ}_«Ý4wØš¼aç¦sÛ,‰‰ò5ë­œÙH” q§w«¸9Í6£Û‰iëf–麪þiðÜZ©¶½Û ÓšˆòUxö¤_ž$<«XnüÝ ÏòqÜ^òUxö”_ž"<«è•Ïž½ Q|Æý Ð(¾ë6<#ýAFñ èdø†’OÞ"µ}…¼7è)•^†|2¤zk#ŸÜÏÔ>×e× Y†váRÉšOº7 µâje Jy}E=ôî}³-îF…êQiá©+Hà²9š¼Þ¤Z£Q:þmÿ;(y %Ÿ¹Í‡zuC–-àÔª¼kw;hTòz9yÌäY»AáͲ÷fl6 ñ¼€&Ð`ïŸõ†k±ÕÃ¥wøuœÐ¸âÅÙ{”ÆgõJãW¿/Ñ(ý~§ßýÎt+;Û†ó»Çœ¤:̽[•¥ ssÛȧß8=CÀùÌAÁ§t]Æß-Žc35 £Åë{¨'áÆ`Ðû¾ÞC] \ ”ûT€–uÖï¡:ëþÂ|aï|×eÖ~¹õëBþê,ÎU\½‚f³©™¸YüüÏFi•=€¯Ö®7S ÂÊN|ñD&xs=°æÌz)7*÷W½WÍãLƒÞëU¾š±—›†=å;g÷xã’¥=8T=žD,´… 4{{ù ìÈk¯7.‰÷}5mŸv/õwo Ò7»Ô¯x õº² x½æíâoåÿ°ëÚõ†tÃZÆÃg¦ôKà@)!ôÝ^¬V\: «ÅÃ^ü_“@ÚõZ5Î[äC òÞ5?^¾^©Öx¥Zñœíû¾R͇gÓ§Á*·Õþ‡g§ŸõCu™ºˆÙf˜]oîŸø;½7÷Û”°{%?6¼½ÿînÝ^øûÕŒæ—( 1¸¹Qz?‚•f¾èÇw¸ƒÈ;”ÞuGOÇ7׳:‰F¸»ô”ÏòØŒ¦:3pþ¸óäØöxZ11¡ÞVéȧ±üN¿ÿ‰’æøêú¶h„®oxw£|Šûú¾ ÑØÞW’êgúÊÂW+]Zòš<´û¡>Si·ÜX †@䥡§ˆ¼tú¦mg¦~p˜k »W*Ñ](_ƒO/©ÿÏëB§b(bOh…0ìõ8¼ˆ¶íî¥é&Ò™{±Ý­wÍR*ó*ûPà¢Õi:SKI•F—Ý/èm¾FçÚû–¹{ùßï¸!ŠúUœ&xýªæÙ+¼¸Œ|œëÜÇš‹9Õ&!õ±—š¯mýÚ@ŸeÖýÐV>0`ïl úMï _ŸTÝÿ¤j³Ó4]Oª*Kóõ­Äƒ?<úVbÃ1quá§à]ßJÜÂóhZRªp©¢íù}¦>Ö±Ëâ(òËØX^#yùP D^'/eü¥zÓâÜL(¯DÕÑêb™å´¼bVþì^Ƥ“¨z9 iüÔÃmû¹Û½SÍš—¢ÜùáV¢áPé´÷*\½®VWX»áêÁðNI¡±¡Œæq‹Â]Îu•áÜ¢QVô¿·$ÿ¦ÛLu£ú4(VIspßm>¯r\Íùi帕ï]Žkx3TÒƒm¬Éƒº}‰“òQS÷hùÌöjù\7‰FyK³Óï~õ¦¥²«»þ}³‘X§M«V2ìôÔ¼ZV+Á”`­d}Fï‘(‘ÿî*TRv*9Œs*9ÍŒK¯Ìjî+öuWñ\G¡¯‰{p®¢0Ç~un¡&ó Ö+d pÆ?‚¦‹â{nM—NG(oä7Ö¯[† í*ìRz]¦i@[#í’0äÔ¿UºLÜXÞåb;N‘h‚Oò¯®~A¢ú…[î¾/·ÐÞ4›A»n¡±BÊåä3;·J_å{Nùe3ù¢ÊÙò=—48¯¢?'þN¯èO»’gÀv§tšsý9á‡g‰þü ªR|€)‰µÞû-•3ý°L¨“U¥Z_"ï§u¯ZT4ZT« ËíªEuçªEuüWÿŒÕ¢âÞV­µ©"O‘°ýT4¬:½‹óÊ$qSæšž“h”iû»á÷VÇ*/E¨åç¶C è º7J‘×%h,5,>IcimJñNjå_ßÚ ]õ‹>aÐo¶üÔ=Ä žj‚q1uÜ)Iˆ]Oùe3E:Ý÷/ È§ÒQRcÅ‹`âÂUÄ«¨ppQ¼t•Ÿô.ŠíŠ #ˆšëU óøÏÈüAXo{÷JáÓU ó„ž%Ù®kÛSÿæßTè­Y¼wªÐ[÷FìòÄßÚOÌv¸â²Â5rÊЮzo`½·‘L8öÂ_žìæò’ì[/bY‹Ye7«Õ ×ÙþÚÙ~ÛA«”%ÈÑ >·ýÞžÎU-ûÚNs¤[mš¨*íêýÁWºM¢ñ½ÞtðÈ©.LÏbïÍØ&̓¹Ü“Þþíg3|a×KݤwnøK î½Õí`oT«Œ¾›Ë˜ÙlÆ]¨øËÎÍm“ì$ $ö̤G±¶Ñ®`oÎCh‘ˆ¼D§7 ý…”8ÿˆ»Y©dxuª„Nu0¸JelÁ ‚n%§z¯xXòÝ8ÕÒÆùÖaÓŠ_…ûÈû³çøåBR¹‘,Ò‘{ â1·®/½Š®–òî»êµ„ÔÃZØÍòEås{ù²uˆ’н0ý!ê…¬²åζ݉:)…dsÛZäÈ#1ò[?`ží„ôȯJäµhW%ò#8×Ëp§™qé—ákÐU‰ü ÚU»pX}3ì4«ô¨„ ùІ;I¹ët›ªãVäc†·ÍÊ‹pOÂB¥²Vî;—ég±Ä«ÅQIð®+ã edºÆï|›õÅÆÝ«ŒŒD£Ð\¯Þ—Ñ ™DËoV4¼ñBÖ¿K6ÔÓ ¥;÷öž5¾ôHca_5þ>nÛï¦ +Q£¥¦ðº0Òè)•Â5~ƒðY ŒP]ñUhóªFm¬p þA( û-.\—'bã=p…ºÃ¾rHï¶Mµý¢É]ÿþNmÓÖPó%\“ (fŠ?îÑ Ö ½Þ@h¤éáþ÷V Û½¹¿oÔIhÐF¼ •nϵ­Øƒh˜4ÓF¼žÕ£]Õã\ˆN3ãâs6WµÄzœ;µÄ³{üúhmãÿ|WÖn„)[ϰ †ÿžz–˜[èk=ËG3ž_wzÚUϬg)rGw¯tzÿý*vèYV»®:–´«d×åèX"]ˆR.¹±fןRÑ¿Lwë*úWF#ô ÷ƒe1 Í»ŽCôïnxÓ8ivÕdÓ¡ÉÖ®è_“_h²Ý‰Ù¥¶®5 ˆa©º•ÎUK#ñ}³—P÷ŽCÕ‡dTu”R,— çÕÃT/•ô¼úì•YIÌò¿]ÍêÑ®j^‡q®9îc¿j'Ç]žÞÀÖ}SwZ*Hè ‰'œ¿D—ü°õújNœŸ¦~h‰Eú<ý„~“Ö®îÜFfDzÓFfŒ‘x©ãÙ #¿>†ÎRÈ 5í”Ê ©XÑÄ‚ÂqHƒ_5ÞÍ÷½¾R‰LëW¨^/;z…:äöÉ+Ô¡ü7ÿcnz¶Ë®k|=Úõòôªî#‘½ÝÖl«·/½2æRuJ1UîZqÁÔ½êÛ××»¼ïòv®wy¢]ïòÁ¹Þå=ÉŒK_ý®wy«8×»¼Ç~¥+\Ø]Þû^cÑKµ»¼¨JCXˆ¡ºÏþXsxÆbþŸ£Ùµ\ C£ &þ?öþ½¹qIÆ¿Jýµuμ³¼_}&¢Æ­Úñ[ÝÕ>¥š9±ñƒ–h›S2©%)_ö§?û u!)Rb ^d8v{\Õ­„‰Ì'Ÿä¯2é÷¹€>,¶â‹Ã€ºE•+ŒC¹ƒ9Ámo7ÿç5™ˆ¦Ñ^‡¶ ûšÑÛÏÏES†zˆÙíóln@Þ ’á¶“¼(Èâa%ïuW[Š¸ÖªêHžÛƒ°Çà’vÌ•æìø>¾öfƒŠF—ëò5Å€q(`·óñ(TwA_¡-NV­œ¾†µ•wZ'yeÏ•›O\´¨ãÊöÀ;¾¶ÉÅ'&AÈf‚ƒÈªžCöXüô’~ÚdDáû4rð%x+˜¯eÀz+Mè“÷¤^r¼:X$AæýÞps¶ºÉë†^pÔÚ_,‚4Å_tÃÕ¹½ß` /¥W“aEŒ«8ØZމ©Ç€¶œaêQµuÜÙâ‘ÂÀg«·¯sÏñ—Ïax™åÒ$Ïi9¢V;¾¿'Öy½á€Üø7ÈÒ¶H+¹ áEÎàbçuIÈS•Vò– lT‹¼²³àL¬Ô›ËW(_]¨4xuT/.ï'¥zQÕ‡ ûG$¹S!3®¹4É÷‚œqÝm0Ì£Ï÷š.aƒPΗ‚°Ar¾Ô¤IƆ ä|!&„«Q$˜²a4&D(çKA» 9_ªÒDºŠ©ÙÓ2!Ã’¾@>%€=Áu,.ªÉÉÑáƒÝ89`Izǜヌ›×C{ÍG®*þ]:[ùë4XJìœHìœfÚœ'¿Wð¬k@\¿ú¹?l*,̦(Ðü`• Ø·(Ñû®Ô’ƒ†Ú´^œú˪šÅ9± ý‹Ù7ƒÖ£É/,kš²ä ¬”GçÇ,TìªÃ™@ïÕ®æÓe7¬¥#ŒgYU( wÅ²Ú >YœØFù% ‚›µYIãïqü#©ºô·š9N³Ùk°`Œ¬J“ÙI^é,[¼dýžeX@•?žŠÏ:§)Ø­ú”dá}¸ýع©2þ€ª`‘ÙM¿?§ðñ.nŸpM Ès\߉ ñnKå"ÞÖ'o·£5t«˜¼‹$¯!Dšä5<#G¯!.þR²I“¬†hÍ·†-ÌL¶«Îus $ B)‹©p¥{Î ™¨ÛIxQYÆ€œxc¿§Þ'Sfž™ŸISá{¾y¬2´Òz‹3ü¥¹¶^{Ø•€VKë%æ/—&ô©`hó¨TK1¹,CófÃ4WÈ¡ËAP‚óåÆ]ïÕê[°^… ?ÝæômU 0û6ÏÌ%ý°¶·ÿílîßÌMo&ûµH“eʧåˆZíâ"E6Ä®$Ú¨J;¬÷s€K­Yº3Bpì%Ê2h£Û¼…I¥ Ó±°¹ò“-Sæf—Ë”M¢œ[?{ü-ÿ÷&HÞä£&K•‘K•Ë› ÑÇ ˜n­¡Ðrå¢ÖP–+פÉbÃÕ+C>…_áE-W…—¬6ìðÁnÕ†Hè'[mHö¢ÊEÚ1†jC““{§Kµáí—gP­—¼É: ”Õ†'¤•ª 7÷÷n8Á±¸# ”áòù­‚È£KŽ»Áùéü¦•7Qß©©&4vÃÓ›¿Á:_IÂÉëªæyëMxËÍÓ,"#ë:É+clNó)¼á6 Ÿ‰»õ4?Þ’-Ä⢢uX)ïb4°9íÄa7lÔ µ¯Ê«©¸‹„§ÊÄè*¦¿“‰\“‰Qú«k`e41]ä•)i퉵T©îÌ£ËõL¼NDGA‚ìëDÜxDË0Y¯[@ _æ©„z4K“å"gäH¬G·iŒë±IV£ƒ=K¨ÇIyS†zõ[ñ‚ý†*p\Î^l– ëÆáö‹¬ðá~ìüÿj¿wâÿK/£YšØá¦D”V¥½wC\3¥ÕcŠhO]… ?¦šG”Êý²åSÕ¢Rj¾ 7™,{ÜK“e§åëdI÷áè^ÓJ`íŽ3ž Õ¨GZÍ^°?¸QèEeÁ+Ôê–»€æÞVu]Lƒ8ŸÄÆ*vÁ2ÝI^¹v‰7žu¡4…üU4å0¿£qâ^úóo Z|_SÀ¹¹šYÔ€±,Ld°w²ÙüPÞ:ðyæî§ÀÛ<í»|Lâø"â·Ò4͇ ¹XÒà ]kì¶¿\^CŸŸÛFÑÙ­°–½4¡±s¸„ÅØ,k² å{…Ý~Ÿ8݈ïÝà¢n™lé$L5§J'iu”,™,I“%“È%“ȵ’šÎW.=Š*êd•Hø&‹Dri²Hä´Q«}LÉ:\p}ìõ!ñý=9ü¨«m*œüö£‚× —ãÈJœîŸì©‡øðJflÇœ—Jq•~›Çß¾|=øçÂ’K+7åIòQ¯SQ¹Y .ö÷6¸‹­9‹ƒÛƒL˜øYœüô¢¹3y ˆ¦ØXÖ…¥{cIÕ~øžøQz$²„Hv–Â(ËauÇâb±Óèú`E¥ŠÏ» ¨ÝaÆÙßfž©æŸ† o?•›ò—êâÑO¼,ñÃ,½y™Íx)îjc€D ˆ@´u÷”qe8¬*{\™ª,Vq´#ËdÊ·QšÄ”‘# S&eGrdzýܧ˜ƒ¤\™¸ƒiÅsy S‡3€Œ³!0üÜ¥!„B<Íͺ¸¨noçŠG9Vó¬ˆP]ÇËÀ ÿ˜Í /É¥û¸_ì=6Î^—|•Ñcû‚W/‰> }½Mù‹Àß1·ðá&ƒI!÷\¸À~5Û*—ÓGÿ da¹?œîÉ—2òÇxyô3™}-¤ |~>£¡š›ÿóšLDÒt턉;³®ÁKÅ8™‘³t­Ay³´ÒëLµÇÎÑu›„Ï~gâhª·¢‡Ϙº:gÓôÑ´Ñq*un£Eú䈂}K}Ÿ‚x“ÍnŒü–®A4XòYÕ] ì¢uBZ©5%Ù™^VlJÜǬªÜ!Æi…¼ŽN9bæÌåzmÊ>Àû>ÀªtZ a²p»Ù¸ýCìÎ'v`Ãu¹\ÏÉ–WqŸ§Ê«Lâ«ú+°M”žhwÈåUëŠnøßôoc¢ƒØA+ìéQÆó9MEåj=†:6›³µ©ŽM» Âhû'É+Õ"M–²–óž€p=›Q.Ükùp#ÚR8Ûü‘×èo²GŽäFgÍx²O/é–/á¿}ìø«%õ Ó¹êÁJy?Ò1ækQO˧y¥—^=|çá½$*íBŸèë"Ïâý@Í™›ÅŽb½qЭ¢ÖÛ_,‚4ár‹ŽTYÓKþ1‡E£MF ´˜à‡G†7úÌ“¬0Ú@•Sƒ@±&0Íü»Ô‹.ß‚¸F——F¬ï€tå4âYKMá KËÂþ³…ýœ\”#+ì75ðó°ºcT ø¿è³¨ï˜ÅÅQA˜6Ô­Ÿ|si¾øEksimÞßËîÒa²»4Nwéò¾Âó-\•‹4hp ›3u]£€1Ÿ~,Ãdvû…&aª¯«<"ù/™ži–&9`ÎÈF5ˆóîª.¸;ÀuìÅó›d5ºJnæÅ{å|><"wr³DÌ€Ÿñ-rd®÷ܧ†ÉõæÎb’×Õ8Ka.¥‰9R½‰<\.¸îeß¶SÒË“K¨èXîÌîéÎmI%DÛË•¢ÔAµ˜)ÊûppDÅ0ˆlòÏÏd²6f'Ldm oK· ÍG¢˜Õ²Uuy[@÷ÜžBÄX¡Î•UÛ¦ÓŽ¤Â¶¹X~RbÛ”nåù¸Ä«>l/˜x¸¹xªãÀsŽ‚uÐîlDUªÊt¶Ž¿Çñïy2™¼Be’Pd’<>§uoöÚÕm)Ð,ßÇOE3CÊ“=t^:„G‚tÔo¢ýa‡ ÎZ"Öf! º nhªÑ¥¿í‘qšÍ^ ?Z†-†·¹Th”ks™°çêô7—j„Ùzý4í) ®iGÕ$B¤!Mçw¥f8Á2y ªÛ Ø•4]Œ°+òJ‚|S)9yBZЕ3fØP,þl¿GØ^帯bi‹ÁÃr¹^ºc€Ä‚Ú‘ƒ!±ßæ™õРèÍbîS芄ȶH“ÙÓr&‘UuÛäö±F”˜” Ù“³ÉIðÏ»É:p懒ã`Yî~Ü6n|½CT³ÅÛpó^“‰HžÄ0q G×àeïcœÌÈi× D_³´’Q¥ì7|ËÌòi´ô¶hÈ 6!MéJzxÑht8aI9Î {5YÄ( ^¡¯°’Q„¡tÛ¨c¯‹iøsi a"©cyžjAI“fae4o©a¿Mª“§uð¾fÏ,\fQö né,}έ0Ù+¸]Œì|æCì–RL¯`ÇrÀªU…oñi½Ÿ_òt²ŸŸŒã7K“FgäÈ£nÓFàÃ?-oÊ1|¾£ü2C ß[.ôm5VŒ;ˆºÆÝH_üõ웬ÚJèä¤lÒ!(Kg3UMÕ&†·âƒN’cŒg2]Åä,Éœ:ƒ³#„ÁYu`ì’À9—& œ‘ œÅa©]…'ZM{SCƒÕCc!,ˆ2ÚÍy$÷qòäG‹àg?óU+‹3õ=ñ£ôžÜÁR’B %…2mÞ>’½¦©lÃåHSÕ÷ZüÕU•‰×Rè(ؼ–ÂØD²š¢Qš¬¦À«¦¨n²áë)\Uãz"Œ žBqQv«§PU @OA”I–ñvi²„â´œ •PH–ñº4Y@qVÎT‰ÓK¾ Plï/Ä€Ý7²•ò_ÛZ)»ÊAy²•ryÍ5 J—­”ÇÝJ™¿Ç(äãø¬â®a³#5¬’;òhG6´¼Wooœî”]”Ç×E¯µ÷º(ST=‡Ël"Üøn¯ òØÏš»PÏ"Ÿƒb®³™ýd߉Û&Ýa‘î°nëöÈÝá ôÐR@·õqÚœn©¾ ka¹:º"+¸€ëÈ%XÛ®£có„àÞTäáù:ŽÅ‡ÕT˜ÉÂjù/Œ™^ÜìOYšPê N¢… ².âM”áZc8$D²‚zG²Ú\á+ê, úòšÁUd$¬'¬œ%l8@Ö¡Ý}SãJ-MŸãÞÂq¯kçP’ð>—& ï9B•ûý$¥UÓæºœF”†")mzaʽ•&ðDëö¢Œmç±)ù~Ä<ëЙ*½“BÚ¢öe~5w‘ðø˜|M/vÎçïd"×d"Ä,‡þêZ“-™ aA†-[2„•*f’Äß,¯\.£Ž]³ÕÈÅ*Cí$8|96¬Ð+bEd'€i,rZÎDr'Ám@€ìÐ$GÆóÏ}êrà96O‰¥eRÈÝÿ@Ý@Û7ÿç5™ˆ?—O B˜¸'kèò´Vªa篨*ÛEJ>î÷cHªbLÉ3dŽI~?‹“ÿ…÷ÜF¥*ágÇ+GHª!lM70eÅFñZvk€ê±íVÕ¯q”í»Up bâ¶Ù8&Ó’ ì²%qøxGXìHw3B¬Hœ‹,XB7bÍ”6Sǯ{ÖhºÂ—Žãž2ÙgÎÒõ/e̳ñòèËìÕVšÈì•a(Ü‘˜~P†Ã•‡¢k¢ÈMwÀx½QáuΪˆÞ\#áW2šÛ,MBáÏÈ™H8WBá¥I(üI9 ßec‡ÂÇ÷÷i€¼Ü¶1œ)¿ZäÈTŹO Uz°Æ­=ÐtleíAçÚÎ*㋨=Ð,“³¼e,L‚àØ•IP¥L‚ÿHƒäÓCe3Épµ“&‰OËÆ'Fö¢çÓÍøÎY®xy÷‡ñ¾¶®>c€ê8|¬GÐC:Äìv!±‡-Ò$ö𴜠ÅOtí’ÂU¸Ä'ÿUâ›äÈGý¹O ˆ?ÌïG<7Á7U.¿¸tXCs¬ÎÈþó}¸ Ø‘‹F —Mþù™Lƒ³§ñV J—œpTáâÖæ1ðb×åÑê]žI‚P»ÉÃ,Úí»<Œl ´ó©+Ðk©½j[ ¸æ´±uÀk3 í:C_ŠnѾÉÅi6{ ³0vÛÔÓòqü.:8R€´#5vÙÈYß‘NyG&ÁvCˆŒF¸!5hkCêøElH’Ïj ±ÙÅ>\ásP|3„MX‘7ðŽÔùœj؃go”­è•vÖêä¿ÍƒhYLt6³)Íñï¤ß,Òo643¶Ôo“;Kíúæ*úÕ>÷Pòk¬›ÈÒß›³î`©ºmâ ÎT…á½ ƒ L38–Ü@i-¾Ç’[ë—$Ì‚2˜ü‹D“·J“hò3r$š¼Ã<Þ!šÜ±¸R^lrNâÉ›äHóKÀÜp¶³lÁÜ‹x)!7[irS¶¦ #ƒ¬Yº±&Џ1,çb=Q^ìu䌚í¡/âÕŒ¾ÂÍ}-wñ—ÎþßJËòAð›\2}Ö¥•úãÑmˆkÈmSç^ï åÝK'ÑŸ³Ugê&œRÂ*€I ¢åöw‰_j‘&ñK§åÈgñ¹O±ÚQ`ò¥fHGÓŽ\ÐðwŒ_âl\0*ü’i8ÓÎ+Ú(m-Þšªòå}Ú,M¦ ÏÈ‘éÂó{ºðns/+òkrdE~—YŒ½"_úå¼âÈâ¦áryc—¬‚…œ:'«dïƒ4™¬’ý½sscB­M•\Ôò —7ÿÕTÜEÂʯ¿“‰\“‰Qú«k•ö¨SÒáæk±3—"_;å6 »Ú,¯üÚ‘o½°Ã2ƒYùšbvà¾Ðrý ZzOAšú—²Þã.ØÇHÊ ædz-×ñËÔ\ƒ†K-`)P{X ¨.ˆç¯iløº ~Ò+‡Obƒ¦ÞÖ9öº˜gs’­<µê\ôM°¸nœ'¶S¦tRQ<Îj`çZ£„N2 .2 Î_¼q¡®aq"P—Zuy—ºç@xå4âYKÃà | u8Ùçë`ÑU?J`ÑU(¡¢ÍÒ$TôŒ í0±CE/­ÅÍØá¢÷+ÿטð†Û$ZôŒ¼)£Eó³È‘»Èݼ„…e˜\î-*ö z…ž€cUQŸª–Å%WL:gÍÒ„R èæp&uìΙ4©\¹àòáF4«–ÒoÓ$q°- Τ#…‹I|Ü_ƒÌ_…Ñ_if™ZU­ü7Õ?I+›K“D.§åˆZí'ŒŒ|Åʺ†>1Ð /Kù8cZZ¾žð` ® gr–­iàé{pÔ<üoIÍ·•&²ÚÉ™\µ'Age‡aZ|T,JÑ{ï…ÅFr±‘ÐŽ,\v`â´Sbù*ÒàÈêŠç­Ûƒ³¸W{ÞÂ(E³É??“i÷C};l¥@$àw» Û€Ï(ð‚Å2 ýµ*ö„j²™ªÜù˼™Q¸ä· ;I­pµU{¢¹èd¢â{¼M\ݪÿ# ¯æDÂxºÈ+“‚rã`Y>Í-!› Qbƒí|å|* ÷Ú}àÂÏxªÏU ÂÚ™SþÇ?¾'~˜¥œÈʃ Då‚ j>%Yx.hñ.TC•}³Ûƒï‹›h¿3 ƒ—¶“± º nh4ס¿í‰¹ƒÙk°˜Í€Ä‡M;l`·R‡r³cmHK…冬oH»Ø‹ |НHö#¿Åóu:EÀàÐH…“ú\¬â´Â£)sïÒ$0òŒ Œì0±#%Ð<·¦xávÛ?»!]q†]€#ä@ ƒ­½cÿÁ¯ÈØ57¡™`<×’8ºˆ š´B-éšÑr»ùÒUaƒïÅ~{xŽî HºÔ•îË|¨Ç$B!—&)¿*…^ŇQƒW²M‹ :â/Pb¨#ñ—³X~"©¿¤Iê/,âñÃ<Ø6£ß;†¡tC ü˜°ª<$ /[¨@R€Ú ¿ÇöŒ(o pGoUýG×ñúÍ¿[0Œ÷esU`^È×D¡ªpÝ,7D÷ûá#%g ä ݈5+RÚL¿îy[àš|ΞĠ4î bê4×â3jŠKÎe#Ùœ¬áóÌ¡Ú_øi†d¤r&º‡š]®¤P«N¶xïÎ)o„–8?Í3—ÎÀ£SPUÏ[ÆÞfMÕ?»ýòUUûÞ_>‡0ßÛÛ×¹çíeÉ—K“H¾3r$’¯Ã<ð‘| «­EšPŠCSá‹QŽ‹áw¹Wèm‘WJêÃÙ‘±ÒûlK£œñ÷iåh·ž^bÖžÏ?û™ÏPã`5¬ôrlÏö ¿y>ÚÌâMý´ÉisËûpáSZIÑØ¾éêê0@T¥©¤Ÿ\}×4~)€¸ú«ÍÎQêí8¿ó ‹³ûhXà@ëÎ,pq¾ÁúÓ*|fwò ðAðà²8Þ@À“i‡ÕþA6¢çÓèQNhÔ…· ë=á¬ÊÇñ"7ÀÝG´pìh:i<Ùö÷k‰ˆÞK“°I´Ò±êC<Ñ.gÔŒA(“à†ÆðöA¯bcŒ—G_B¥·ÒDžyÅ5ÍizÎ6ÉtcM5ÿâê|®‚ÄK¥ênÂx)—vl“)áóìFØISO »=íð)aÎ]QK «NeAù+/^Ñ2LÖk ­›{µ(ùËEÞvÞæk;/ÝžîeÚø”4ô>¡¸BG•9Æ]ïtAl®[ï ·Úcow/ßa¼D¥œ:Þ$«ËYl0ùE‹I&uîS ( Ÿý LüR %*°Ó^Í›?öûð"Š®Á×fú¼+' c ïŠöPNÕÊpc.M’®pÔ4ed ]šzí3k8žQS%ÛhîÛ÷l9téÛüÛ´û¥Eè,¹QÔžÄóÍèåq1^ôØŸãÏ9jÇ­ÛÜѦÉÝzesŠxñ¹:gþšArÝé¢)¹¾ÏÉÌzIšÈ̺¦ð–sËÌzãÇðÓX†ÂÇ"a+ îæ£gò«©¸‹„§kŽ‰Â¥lüN&rM&BAçþÊŸS7Xñ$éƒ@ÒÃæ Õ_(éCœ„ühå ÒIåe×`ù4+©Ø fšš-Ž×Aâgqò¿°ú¸4a 4‘ÈûT$#GãÿHÂÿ²[²fÄÄ}{´¡$íÞX.$íd9IÍ{3ÀòéµA]Öjg·º?°Ý3ò áåÄ úBx9ÕP_òýT’&ôý¤) š¼ã÷-sí3A)0Óˆ¬%]¹,%æäM%íGw[Š»Ú?‚ ‚@M Ÿ0ºÅî÷bäº÷¦-‰@®+› O3áì9„z£söܪ¥{ÒÙ·yf=´èãfžk?$ÿ›ÎÓÙÜ¿™ëÞL"Üsi2¯~FŽ0“,¼"·ŽühÑ Þ8Eß¶Y5¸`õ“h¤->ž¢ ¢s­gl—³ÕZÍÈVN#š—¥×Í:ý*B Ð\E¨<Ù.ð)¹4YCXÉh /S!zxM¥h…wš壺å@lòrJüEví/ƒïñ ’¶ 6ö,G¿¶À¶@=lÁÑ6C4 –Ãq7mwn8– ôÁ ¸h/oññö‘„ÛUË“¡Èä 9ÃÍ-8¦äŒj+|x Óˆtrèݲ¼¬,ê(¼9]Ün5ƲW ªJ°Ôd3)t®ö€®ªiË‘~&Óî‡úvØJ6¤:ìnPÆ€!LÆ*^ø« è¢¤yd´P&†ÛaS1ïýEMR~µ8 Y°„/ÇQ´¬C¢»NaöA«¨Ö€pµvÍ*Š+ƒ$‰b/‹½ýãdæõ*ɰ•4 «/ŽWr™é!®\T4=óJã.ˆZé§µþ~ÀuÆa$µÎQð2CàmE¥mí”ñÎêEû͇—6u¡L‹e÷SS@i´wH°N‚…Ÿñpʨ„(«½OëßãøÇ÷üʉO;öI¢©Po„#q†;B8» ÄT—F×ÚìqMwÆŸËzé.'6 ‰¿ûß…zœ 0*¶Ed   þ·Ï‰Ñ-—5æ2}NŒFÓr8ë®ÄáBs5šÛøø)É›»‡þ |µ—}L lÞǼ‰ödðrC@ ×Ô å u2lúÛ·`„ÏÁ–§š¯orVvS5hs¬ýè²r?Ö÷cþÛ<ˆ–ûͨñoF´}¥ƒŸ?hv/¿€}å€žŠ­”‡ÕíÄ™¬ ØÆ6WvpDÄS ½Ýµ”G5Ò »Mâ×·y<çôS l—œÚ] d :!­TæC÷¤‡ÝŽÿÁ7)j¤êÙÆk¦Â‡¹€Öù;œˆ«&Œ¿¾Iƒ¾¿èëkÐÿ¢ô·Ò®~kWù#•lW³¼$÷s¬÷dT+gÑ¦Ú Eª,®— JZ³5°Q—pù.QuÄ›å„ËKìkû ݆}Õ “˲LŸÈvØ•Àx¨†Ydéo.MÒT¨6mÝ„ÝpÇ<BÞû´sòï}Nbã†÷¾Ùç•ÿ0£Ï|uû—ô/*˜ÝɳþA¾øÏʵÚ÷dâ®¶¥iæ±ùƒnüi"»礜“ºÈxƒÖÔlâÝ^†¡@—æÔ"‘úלZú~ò4Ïü,.m!Mº´•6•¼îìn{ašËŒÂ™ÅÁTœÙ‡Nά<ä¤/{VÎûòeû5©@Žö&«Šë_™˜½ó/ N'“¸~ ?Šj"¬J#Yß$lÌ­€g3òB¥÷WÔØÚ¢bРҦÆàžjˆè‹j¤/þzö Æ5/ýÎî%õ„4tÒùòz›®Ê½ÞSŠê‘ƒŒèrê&XjoxP©|Wj²‰n“àÛ&¢E2$WHùk]ü)¾MÂgC‡¤ÑŽe_âÙ Œ™”ÁþÚÔŒ¯âkÁ,M›Q›| };¼ÌØ}º™¬²áANvšikà ž¸nKäõšRZóF4Þ«©¸‹$XÂN /b´¬n]q}47Ш~<åÙB+4²ˆF«Q`ÙÄèëE¡É´;—9¨ß…4ï]ä•¢ö`‰Æ¬!'À#*ŒÆÖJômZ3‘¨×¡nB» ÉKCÈ…óý3–‹­[\8r©†\8·ÅÄC.:¸ÿDe« §ÍÛ]]ã{Œoßâß‚õ*\ø×@Š~é§u‘Wz†ëº>-Ça»1ðœ.0‹ìDXîDÈßa m“ËäËN„•N„ªìDØ]˜ìDØ.Fv"ì0 Ù‰ô#;¶‹›TÑzm œU•ÇÑù­±!¿³:°›j[¨ËN„ãØÇ§ÞÓQU®Ê!xÌ/’?ܪóŸ7Ä[—G?“内4‘å†.Eêò ì™LÂp¸ éÆšfÞ„’ÑVî+ PoÆ~[5Àèf–ª°]Vå»J‡|Û#‹¤ª_ãè:^¿åÅC è;s_ú>-Í ãù<¿ÌœwâÜÞW‡WЦPLZ'yeAB½°Yd%4d9– Ȭø ïKËlé';}ß•£Ó9…%?éÁa* RµP :&‰ÍÊwç+Fßõ/ÿLäšL$ˆ2rÉÁîú£ýQ†t3USåÃò¶>LÅ˶Y[Þ¡Œ½êEÕ4NÖòyf.¨á¹yPà5j˧000Œl&œ©µ€´ R—[>ÕØ-ôBèMLÕáA„@ùÑœ¡°¶ {s±Š#XŸétw’WÊÛ*¯Ó-Ú¬tÜs Pü¿~Ð …æ hªÁEj*„²ƒ0\'×Q8MôH¡Ó'„ ©¯65ÓâJvé®lÊ=.›£).w™mž¼‡ Ë+ñÝm‹ó»Í½f#Kc‰þO˜í„ß|@pjCZb?< 0/ñ‹=B®!Ÿ:D…)tnÇÄôËý˜ýh¹ ¸!Zåx¢ËNd ÚâÄl-ó& ’¥ŸùˆËÌ×ôŠÅIï®V~Ù–Úõ £fÂÛmU¤4œf[={ë0,GÝàä©þRòÔÍeì…é,{‘0‘ba"¦âØÜ0Ö èñòò[¤•¸½'ÔÕÖUÇ包ŒªM6îæö¼îÞÖTƒ³ü¯Êuf³dnrwÿ‹ë@Sývõ*Ü?Ó/AÓä2¨fØO¥1Ö`†ä_/’YÅý-/Êb/JMwlå‚.Jäfhüø‘Ê=©Xöû±Ü\¨×Ü m¶u•«ç’•\'¸åVTÕœ›>/áOg·´¸F¥.ë‚„‰Ì=Z’¨ë ½{ey©UW–„½çrÕòåfÙÄ~s¯Âž¢%ÕÉmÅ×Î1ÕI'¸ ¡=ÁµÞl\ñD\dÂûJ6_›Z™]eή‡ÿIvU×À°rqÌÊ(0o·LFÆÙ÷A¬¼ý.x—žuH^寲*y•sa’W¹]ŒäUîð!v ‰È«lê:Tç’û#V¶ã>’‚H[ÚEžä>ÝK' àò±¶LŽcq¦"à8·_^æšw {ÅÈ\cW— ÊÁ†‰¬bÜå6lƒûxÙ¨œÇð‚–‡ÚRär?¸0(Ã1ù­Éd’éÅîš:J7L¾V˜Ãâ ,n8(+ 2òïf·/ %’Î%ê”4a(ÓÕ‡[ë±{$k w ¸@Œåû›©ŽmÃh=k÷car‡¿ Á|ÕÕ ’¼a—ÔèÂM9O n–&òž4ÉÞ’÷dEš K ð‡ÜlÉJ9ÚQá÷”%Á;ô”²‚ì;ÙÍ2"2¢¹:gÀIx*äv“‡óÆ?Ñ,…‡ºh»ñò/6”ÜP¶pm ‡‰÷!›Ñåª,” _vÐﰸˀ~ …³gó”3Ñ,}2­*ËØK~”ÓC iù¢ý ÓÑçåHŽˆ.ó{ì÷Â’ÿãÏF1ù?™€ F2z{Û î¨WÑÜÀi›»è¨[FÚNƒàG|?{%ÿRónâÔ›“¿Y† ù³žÿù·u=ÅK‰Ï¥ÉŒõ9‡åÆ ‹Ä«ªîpÖ%_°Û‚œ²&;›·Øþ‚–5ˆ‰°E\¹÷{ÂÏ©šÁÇ#¶½Gà¯ð1‰  k Îít ‰ Ë¥IdÀ9SAã/½‘²4  ÃáÙ$YÎ r :Ã0¸æð|zJ"[€ %ÊI ”/mNJ0fìeL?5›ëÞ·Rôż?ˆ½ ÝäíD5ªû7àyÈÞŽ¢Xò ®J+¯vˆ›ÇPÛ.þ‚ÀÞÜ÷áj…kM†Ë±-rÄ­6ïÑ"¯î²¹ßMSò/-Öã8g4È‹m‚Œ‹¼ðRÜU /ê. řIÌË9óÒeã÷%æ¥AŽÄ¼œÿÔ”1/äº܉qT.©A/.'òzYÇélž÷äoT•Üw”)6ð²™D¾4J“È—3r¦‚|É3æÒy)K‡|‘`Œ“Ÿnc¬‡o)n8œàÑaÁ"À£M¹! J“`3r&r…:š+鎪Ò$vô¤‰=÷©ÜÛP¬ €ŽšªÎÅ-¥Û&¨«àØJÅ]6ûg›½X Ùð)ŸÂð{Éß/#ƒY±3€X8zY Òoî,P‚¬NI“ «Ór$ȪÓ<$È þ3&:Q0D5Ø"M`'ƒ{gOÆÁ¼`€©pe1t×p'Ûè"îQ¼Ë‡`ë]†ï’|Šz—5ó۞ݓü?­3ú&{¿åÒDzœ†aK³*­|Mܸ…ª—D鉽ÞA´¼ õ;«ç…ùøã‡£ (¨Ö"±d¾m‡?´É¼Þàª9Sÿª†¦s_–ÓñósÓÉççGop?Ÿ³W©ÑŽ}/\©¸ s ØCÉHÁXÄ«­ü¿{£ÇëæePÛÊ\†ß_úû%30:)èUü"ÉÆvÒ$¸üŒI6vîSC`QÈÆrC0¼u‡>*>~J²ð>\„þ ºŠÕð"ˆa ¸ؼŽÊͰ ÖI° ×ëò/ë5d7Ñþf€ ^ JBŽðñ]bþì?‡¯ªý9\7Ñ}|eABo¸kuöíË\4æ¿Q.T‡}” œåp¾ŒX狼DÔB#\$¥e¶t‡žÊt‹tS7åG§r ¿?&ñ È¢Ÿ7è®ÂGÿ†S¼Â‘»18S7]ëW¬×”<ߣÙí ¨îK:ã^ncRì8òÓÇÕ/)ƒ½ØnÐ4¯Uz/OîʬÂèþìq9|[–%¢Ä³ Ì K<ëÒdmÖX ÉhJ\1„ŽF°¾¨P%)D.M’Bœ‘#{|ŸûÔ–§Ç÷8byŽÍÅ48Žöדªò2â³€À¢òbè,P²œ’&Y NË‘påNó,ðŸ1ÃÇÍR :ÊûÉ_ Mã8\þå”KmXšd ’DØ‘gW²$ñ”4Y’xNŽ,Iì6Y’Èð3&¯S–$žšÇ»+I´4Ý~?nþe”$:šÎ 5 EŸrI긜|·‰C|ýõ&¢…3#hó]›Ìð;ÌäÂjɢĿ¢DYôšK¤µ²(‘o{(Jn—²(‘l6®¬ë¤‹Ä¢D‡¸?/á2ˆ$ ¦&«ÏÈ™  æýd:LM5¸p’;0¼U·¹r† -— ¡À Ƕº8ЦyiCÓŒ±.n‰6GsøxdQ&sQæpÞíHŠ2]ã²|eڜԱ]‹2Í,È–&{ª—ñ(êÓáòÎ'^'̶õP'ËaÊ›¸«@Y'xJš¬<-Gbˆ;ÍCÖ Â.±\'h¨ï¨§ÉeÔ :¦ËÇC1é:ÁI´.ü—ô8?ö8eà‘4Y'xNެì6Y'ÈðsÉ^§¬l’3/Ÿ¬¶ö~BÉ—R'èš\n¾¬l©‚8ª:A׿ª;ÌV`É÷°Ãí^8ºÆ óW Ž&T¡#0µW šäŽ ÓY&ËåÒDl]õ€h%Ù[¤•=Õ'ÔÕÖ‰M.¬3þ0(-ß"¯ÌÂßÄoÔÏ‚ÛM®5æ…nóBSˆQB¼T®¶^S®ˆ6n½cEôí—Å\ónåmšK“…ÑgäL²éÈ&­Ui"›.öøöKòôÇ5%-ˆGí½TûhpÕ›Œ¦îßuù|Y÷Ï\÷?léõ€3®¢sÕý[zm+ÁÊNýp×wþâǽ®fÇ’K{ùõˆâQ3ÕßïÅeà®ußÛá ·vpGTï.‚3£ ¢(93ÊÒd­ûXjÝÇPçîªP0EåÙ¡‚¿"`Êöꨘž¥ÿ¾ú›ìñ/ë5dëcBÎÒ±í1¦SPÕy¦aÝD÷ñµ21üÉÀ ÚlóR².–eq’º3Ù€i!–%|ö³¼·k–¡´©º~áó]ƒË]55Hª‡#ºp|Γà¿6DÜš—”ýÀ« âáÖ¯+¦“ŸÞôgà™¯)º" OÕºò¾ÚmßD{5ƒÆ/sžØˆœ'’R¸&M’œ‘3dÄûáÆèÐ=ŠÜ¹,®ë`Ú¼Re$ïÆíŠÈ¥Iæ3r$óF—yŒQqQUy’yþsÉ5¸5yÎ;"w»â WWßoƒn`G¸ˆ7@ÕÒáì,Poœ’&‰7ÎÉ‘ÄÝæ1~ïE¹øãw:%ñF“œ©8ù†«™Ü—åtÜüË Þp-› £.iZh$ñF!‘ì0·çÊ£yHê¼{« -Âí—ZÎ ³$ò1ØUàå’#Œ¼œS·LÙ€£*M`=ç «=þ‡às€ ¹pLþÒðQûÊ8lù¶äs²1Ù(ˆ/Ã…º˜4…ÎïÌìÙ(\¢˜ÈO’øeö"át¹4IDqFލåF®»+ÚÖ_Žã‚Ã^Þû›.;Â{0‚-Ç×aau ШÏE ¦F|Q±9›a&Fh/¾ÜÉKøƒàðkjÃÁéÆŸKÆ]mÕqT ^¬J»ØÌæ{/"°YŽ(“Œ½Þ¸™Íœó½x˜…åœ>~Ñ6¹øÞ‘ø8ÜDFDÀLd½¦D_”ôS–^`g—K„í—à®¶Ì!I+/6¨Š±E^É$&“{µ§sMæß–ãš,¬î®É ³M ¡ lÂå—hå™K;ãÔˆîÈQÓæ„WïÅhó²{‡$б۴Bü£Û ¢¬{Ï}¸ Ø){\ Ž.›üó3™†¦«½$F6 ýÕß6÷÷AòÏ`Až2_ç^Õg÷—ä“7¿‘ÿè&¢qðÛÊßý¶¡÷v›ÿ­’4K’8™I 0q`ªÍ Òg5öH¶^ÔBäX¨K­ºœÆžy©q^C¢–:¤ÆåUZm×à0¯6ND\ØjÇ›LÀz«Šar"˜'$^ZpŸÒ,ì°à‹xá/·j8œn:órãÔV‰Úßulå(–isæÖ„sdV0› bu»ÉŸÃ#Q—¢3WÒÚûMºå¯dwƒaÕcm~°¦åsòÒE¼¼MzÄiHƒF`IÏ×þb+=— ù|Eûš1]GɣƯƒµ¬<©Ãîz—,š.g"ª™EsÛ†N¢si’LóŒœÉÔ-É6tui² ÝI9jCg¸®õ~R|—Ñ†Žø<WŠoÚL^ü-t{`ò‚xÛÒ ê.P2y’&™¼ÎÉ‘L^Ýæ1~Wè¢ðî’É‹åG2y–WqóÍËf'¸<&/ îåW *mPe)^Ó·` â/¡¡t¶Èfµ‹F^¡8ÚÕ‹nÇx¯¾“s$ÛÆ}бl›³ºOxJ¬f$šv ^Zxô³ZÞ*~xØ!üø‹=B®!ŸÚA°É¸ÏÎÁuºð#Jp™ —2DúApˆôÂø-!(¤6iå76¨ÝF‹¼¨KuÜáÒãO_›èøÃ£#duüh4ì–ÛKâ’ú4.§O3]ŠK“¿­hÅeáÀ,$Ö­&™.Ïș̭jæacéÄ”¥ ¼V‡]îñ³l’Zô‚³¼èøBŸ!qÔncÙù3)·Ñ’¹ZŠõ3ª™GbFy,ñ€r¦-DÕø{–­¯ýÅcð=þD2wøAlîÐQx«D{ÎV÷^ÖÐP¸z€„™lX0ÛÛ3ŒTD¾» ”̧¤I æÓr$$µÓ<Æÿ8”ÌMr¦IÕ-ûݼ /ƒ™¸—W$fFÑ68{tt¥_vâç ¹_Å/³IðƒXðÒØ—GÍ,©*ºÁíLÇhçß–ÃhïÌÀðf›“8‡xdÄùM%¾âü…$Î¥IRà3r¦Bœ/ILêÒ$o¾äÍ?H$·$³®Ãjϰr^Y¶æf®SA¤û­Y/•f5¶ Í×ÚìÛ×¹g“ÙìÛ—y*I˜…‰KжÉ[PÇ8›‘“0/Š-‰¹ÖªbJ惰ÃZoþmM¢E,>nþå÷ÇOÛPß^=xÙt[±xÞÍï‘ZTÕ@ûú4µh p È÷xW—Ë*Šnä§Z¯¾ÇÍùoÆN§µÆ(õÃÄüNæ5~)T[å»{§Lqé‚vÿP—oòFþ øF–—GÒ$Åå99’â²Û<Æ_Ã}QxÂñãÛ$Åe“œ©à MÅâ';™Œ›!—*ñóyÜü)ó-iüMxNð-©;*‰(Î$áRYš$\:#G.u™ÇøA-’péXÎd˜!$áRë'E.‘[qIU®:‰i—áòÓH"—á‚né÷t(ËpOI“e¸§åȰY§yÈ2\–ŸKS"—áªÜøQ»™X†«ª_.N=טÊp›’Ù‡2\YË•K“µ\gäL¤ ×2ùk¹&c³ó/Ëa²ÇR„«ê6´¾H‚‰MXŠ«+˜øöËB²7¤ILñ9“ Ñ®f w ?2€£v¹ÇXƒüüq’·¹UšämÆ‚ÌçÇøPóªÎ—xjž$Ʋù½Å`󰸉t:» ”°ùSÒ$lþœ ›ï6ñ#q.*ÿ7~ßSÂæ›äL%ÿgªÿjOÆÕ¿ؼ­óõy˜0lÞàïèw¦MqoÖë ™ÁžsÒSï*ðrñò£NbÀjFmèqÅù2ñÝ[‚(¶ ‡ËÞOPl®¯Ï«¼>¾$ øHšŸ–# æ1ö´¡7Ë9¬7È=i‘&.  ½§(¶M.²-Ã2uíãˆÒ†¦ÍÏX¹O¾´¥ [ýË®iÃ;és~ësšŠ¦wMŒßçDO*Š5\ðç¦ ]o™6dø“×)Ó†§æñÞÒ†ª¡éܛɸù…é¼€´¡ ¾öÊ~¾©è N1>þ°v¹KV““œ‚¸èÄÕ_o¢ñõg?«3ЩâÙŽµ µ›ÅÐ[JSt®-5mÄ©ƒ”š‹8¹‘òéØY Dœž’&§çäLèé(§GÒäÓñŒùtì6÷öt4UWy?ýX.qªé&¥á„§À§?âôöåö‹DæÒ$êôŒœÉ˜®~I¾úÈ9 $opë'‘yƒÑQ¾™×;e”¯ƒT¼‡ò•ýÍriå{FŽDùv™Çø/â‹ âH”/ËϘ‚f#Gùš—]Kv(_M·ùІ‡Gù²·Ôµø«†{ù‚ ¢t9; ” ßSÒ$È÷œœ ej%È÷HÚÅ:ù2SËò#3µ§å•aM¶õ~Šù.䫊ËãæKo ä«H¯¥¿_ZY[…õÊäȧãÁÙ ò=’&A¾çäLèé(A¾GÒäÓñŒùtì6÷öt45S¿lÒ%‚|]«G™é¸@ïÈžŽäíËûtTµç{÷F×°E¢å™ ¿· ¾Úc]·aÊAÞ[ :—€}sÙ ŒV´aoÙ‹xµ"½wU1‰á7”ùn9° ™*Vñ‹äÀÞI“ÕgäHì3Ÿš:…;7 ˆèx×âr F€ŽgBç-ßG†—´¹4‰?#Gâã»ÌCâã~Æn–øøSÓxoøxÕyG—wm°Y¸€¼ ‹… ‡íésv(ò§¤I€ü99B9H€ü‘´‹õò%ÊåG¢NË+?©4Ý~7nþ…äuò5¸2Ñ`€ühÜ|Õv8“Ð_ªàx•:ïË`>ù+o‡QMKK½£À’‹îèü.úd¬B.ª²A7?šÆÕËuÚź6…bŠ[iÄri²šâŒœ Åd5Å‘4YMqNŽŒ3tš‡Œ3°üÈ8Ãiy¥Õ6-GVS´zœqÃ{u²šâ\5ÅpÕøcª¦Ðégo¹–{DŽloѳ…»·²R'—hé¦"+u8÷V¹Rg@‹5ŽJ²¡øi E‡Á‹.xC k¦Æ²¡Ôw[úåò™v,ý’ÍhöÒdù×9²M—iŒã/›ÑL¶ r¹nj`ãpAåv@‡³‡r;Ið–K“åvgäÈr».óÿU|Q 2YnÇòsÉ Iär;C}?DÕRn§S†8sÒåv“èGó/és~ësÊr»ci²Ü Áàd¹Ý‘´‹õòÇïuJ\“œ©xùdµ5íݸù—RngZ\ÉÚ)—Û9À™w*·ËãMêGËÔKƒµ,·+¤Ér»ñ”ÛU6èàæÇ†ûV ÁÒ_q”¯Ù_ׯS6:ä¹lÌŸé4ìç IÃ8ùTÐ|M Y!-—ù|%Q©©ÃZßÛùw=Kguk(PcT¾XTd·Å«©¸‹$X²ï ÒZªm[¨Æïd"×d"A”…þJ5W±¿üœÄOŸÃUp«j³o_æé\óno¿Î=UÉ?4K’8™AFç¾:nÔ‹ûÞ(¿|‰·Êwk°> Â:¢úžìʵŸ=zkUóèùÁ\õÜB ³ê8ÁQ«¾&vï%N.e±q";¢#ÌP^gÓæ ê0ùŸåT®<>BíîBôl¾ªY1ÓP1#«±¶{‹Q\1ƒâà®mö–Læ¡Z&G /â§µŸ³Û//Äm-þO†9>s¸–3\ê` @tÜV$Øè%"ñ‘è´ÜãÏC®b1S‹Ä‘,÷øóáø–{2!j Çq ÞúûW‰…¬‹­ÖžûBk²¡¸X!&\kªüý±Úëbb4^ÂeÍ`EòÒUàåÄŽ»âe7©M7ÄÜxàgŠûž‹3 $ð<^qæí‰ÃÉ¥ÉòÌ3rdyf—yŒ?>uQÀmYžÉòsÉ*\à¶c½Øö…Tgªò~«3I4C|’.çÁ9QYy$MVgž“#«3»ÍcüYÑ‹ròÇïtÊêÌ&9Sqò W3¹;úLÆÍ¿êLC…ÞzÕ8²*lÊ]|¶ôqù u‚7iü×&Hyj³l”"œRY͵šWÜäÅ6ó|’×ñ20è?f0$£,ºé$ï`ƒÈ~ª"aÜE7é"^ƒð ÍGQû1îBâÄÐ“Ž¹Ö¦ÊÉY|¹e6¿¦ü/PÜ]ÍòiH¥MÍ8\;x¥2ªÎ׸hÊŒ *gÏ¢:cƒJý¼$Þ¬ÃèA’5Ò$YÒ#D×€ʆ7ÈvoÿÑù:ZiŽ ƒ…Œ¬>Ï19“eÃ3h—˜Ý,ßR–Æ·¥¦\–ì x®,O£¼.‰¥÷qò´-Ì“—ÙÁ—™,É;’&°7Œ¬È;’&{Ãà8j¦ ì…ÚÀªµ³¾#¸V{nç7¢k³Ú}Q¯v_Èj÷Š4W«¥èŽ-¯ÖŠ4‘Õî†3Žf Wëå¬öøQصîC®öøAØ¥î«=·ñb*Ý-‹|kÊ…É êWöÂäÂ{¼• {si²>ùŒœÉe¤ãX—&0&#ýƺ´òb/ƒ”Óh‰ÛŒzÔ¾ Rý½3¶ò{ËàãY™tm.9Xm„â^úAÝÊÚ¨SÒdmÔ99²6ªÛ<Æï ÉÚ¨9²6ªÛ<Þ_m”kr¯ö¨]ýK¬²,>Z÷)ã A…]qÐY² è“8èBšÄA ^SìÍáŽÍW|!qÐUôp¬ÀcÁA›ªksm©)ã MþzžÚ&–âÑO%º$M" ÏÈ™L²M" ¤I4R©¨×i“‡FíîàW©¦ôܲaDW)fIÑ⸤h!/Ô­4‰{>#g2ªD¯Ô¥½2™ëTÓØ+ÄEäRç_.jrv@:‰u‰–#?Iâ—Ù‹l\“K“ÀÐ3r¦Ò¸fHúöñƒ!–÷þf… V”­‚Z>Y*º_Ê…¹Æƒ*š”Ðê½B]PåÑPPÅ7y3PÅór$T±Û<Æ;K¨b“ Uì4 Udù‘PÅÓòÊ—¥ÅÿŒµ«PESÓùòRS†*3jg¡Š41uï¯R‰U,I“XÅñ`÷›sf‡+º+ŽÇìØÀªÔÓfg1SiÌ`,Â'å­ã0ʤé)¤‰L‡«ªþ~zÖpG'+ÛspãcA·kÅô¿ð ÐZ×¢ßKßóƒ`¤‹¢I“@ôsr$½Û<$áç’ÝO Do’3 ºªñ¯ö¨½ýK¢;œ@ô #B „¾"4{Œ7©-S/ ÖZH“ˆÐ± B+Ûshãc*_›ÁI˜. 2€Ò‚u(ƒ §¤É Ã992ÈÐm2ÈÀð#ƒ ç$Ê Ã)i"ƒ ®rÙÄVd° Í}·A•Ù] 2ÐÆ<I¼Y‡ÑƒŒ/Òd| «)¼½{w{sp£cAïÆJhAU!ÁA´rÓ%­Øô7Ù#{±©‰RkªÎƒ4 ãè&º¯U¡‘õ£ä•lŒeqV¯»MÂg? À{»fJ› ­n̲¡1ŒòAWM çè¾u|ηuåkz\Rö¯ªHbë‰×·}ùéMžùš¢+² rÀ7ÁÙýaÓŠá÷e¶ÕI´‡1ãH?¶«@e>%MF™ÏÉ‘QænóQf†e>'QF™OIeÖL]rª¶z”Qf[±ùøC¦eFmÿ¾íß›¤É(󘚡£ý»­óD™UÝkk¤ûpð„0Å6ùçg2UMÈäÈÙÏB5»¥L„µˆÒìöùíM XVm^§ñB‰ ×иd‹ÄÒR«®ä%<;,õÝæT¨Ú,¯ä›_ +!(ÑÚ,¬Ì´¹1ü6 ,=8yýæ…ÆyÜ‹Zèøþ>…½uš%–#³Ê@+ó¬—D›'?po*H ”–¬yÈ%_ -ÏjëP×qÆ“f{6)?Ÿ6ˆè³ÍuÕ´|N^ºˆ×÷ú´òˆ[ ,ñIÏ×äý^HÏ%C>Ï¿9z5~¼ `@ïÀò[Gs5PšQãm’Qƒ±Û(/;%lÿ2W „¬òÍÓI^ÉÎÛª|ó„™ \ô}Z3ä"ÚB(¦¤l u,Ïë$XøY°„Ûho!ƒ—¢M:ÈŸi‹6} Ö«páKCº&Κ:oìB iœ„üX‘ÒB;†£MË’nO!ž5µÁ­>‘ÇÍ}¸ ¨Q*çütPEý%b ,êÐ?EñÞ|{š²ûÍÅ‹xõìíÙ¬0Ò öÒHw’Wj=d©CDÇm¤×ü€µ²‰6UÞ ]Ï&zw$!‡ïû#å…$H;Xv•«ôoÚàkÏ;øúVâ;ri}}FŽD_w›‡D_³üHôõ}}JšD_Ÿ“3ôµaZŽD_·zœèk[çj0iô5°ïäYôµFtzï¯R ¿.I“ðëñÀ¯÷›sx³csäá ûÝ…qPßÍ!_ÉòAh°—ìvÎvJCE!Ë»/käðäàM݆ágÀ³¯ Pi;­Ò)3ñ;a"“<:/tõ2“<è™xò ™¦Íÿ˰: ÐÓ ±©IÖ°…IÉø{–­¯ýÅcð=þDÒ-ú Ö-rx)aû>µÕýwnU&4]‡= °Îí#Y îŠÔË¥õjf[µJŽí·¯sÏ&ß3 ^3êæ¤²|õX˜¸ƒMnÞ÷Îeú=‹bK¢Ö¯R–¼aÖzÜõ«›d…Zž  Vž€^Á*ËýŽ?Äçl¯<¾j¨œZÅA»™?þâG…kȧö×¹NUcÛ€=Ù\>÷dô;{«à9èZî7Þš\6/qr)‹ÎT$ÔÇÜǬÁ#Ç®æ0`=ÇmÝSè” ªŠŽ+@¯[(Ï2ó6‰×÷a´l Ò“?Qª•™t펅 „(èÜÖá2];ªoónn.Ó{žEÍ?¨]BxþšÙt`ð•qù04fk³ŸƒU@JÞ&½ƒîÂÄyŽfÅq*½ðôÚÅIï E˜ôö P¹‚ð|`±C…{U\®~A|€*ØÛ”•5ðØ)PÕ¯qt¯ßü»Õ¶RP¨À}ÍãÜò˜çùŽ/S‡ï†g4†8÷» %æç *-°«òÕijXÁîJal]7¥ãŠ½Ñ¡¨jR\u!µ²Çpëáñ ›1jvO U¡±í_ãåfäypùìÙ~Gª‰Æ¸Ÿ=ÐÊñfy¨9À>sS<ÿ‡ã‹æYš*lÈÔ@ÌÎ?x´þÛ¨SÑ͉§JÙWµÝÙÏ .xD±[’‘&Y8¿?lh¢{<=î4 DÙ®ÇýdßãÏËæöv¡Œ) “½íÚÅÈÞvç'1îâ=*’I“ñă°÷OÄë¶½°ð\E{D=À@nt›Óf•›f=™Ý¿èÁSº#û~uøÜ©¾_ª$É)„ɾ_íbÞMÞ³ç|bß/b e߯Ö÷KÒ­0Ù÷«]ÌTØÆÞ{ß/Û‚Gže߯ñ÷ýRe߯B˜ìûÕ.Föý:ñ!v=޾_¶¥ dÙ-E6¤eo°ìUŠ_ÙÉñ L FÞÔ$Fþ L”Ew ×–:ÅhöÒPxŠ Â∀QW‰aU.ûü—ëO‹Ç`ñCN¡†Ó̹á|ä†Q¿c£¹?½x¸]*a'k¨dþ"^¿1§òm@÷â6Ûêæÿ¤Âz¬©‘“[¦ú…¤ú]ƒ3}©þâúrÇ”X%¢$ KÂkŽIk.PÑ„(£– aX<¹aû:(¬’Ýú:¼Éäű0ÙØ¡]Œlìp~ãÎ]ÈÆe1‡E†¼£Z„9 ÿ;ðr-`®µ¡8…6Ij#³D§>ÄøþU ǰÁÁRq]4@–GJ3ÊÍ'(:ÅÛÎì"ºi”¿â&àéªíªÜ…r’ƒü¹¬Q+„ÉÎíb&B¼3Öe ©*ª É™Hb?‹“ÿ…fù:‘‹úÞHÝq:—6¹Ëòá0åöÍKÕ%Ms»¼rDÝp'VAÜt&--¸&Nò³—Ÿ]vÜØ “üìíb$?û‰ñÛé9³LTB²è¶ûÞˆEZtÊ*;n„ ¬’2é|„‰²èªbr÷ªz¯&‡¸B2ßù\7fxÙqc+L2÷‹™HD2ÃÈíªÉSÜGüÝ÷Áp@i‚³vuþ7.K>Z¡Î­>ÑΕtwàu‹§.Ͱ͉¹P%d°C5þžekZ,|‘Ì í„ Ì 9ÜDÒÒj—Wy˜k@V=ˆVÒæ°’º®‚Þ]£bAR$$2™ R^0 ~ýöuûw²b@ Å$×´ 䄚œäuæ«ûÄ^"SøŠ­]­ ζ*Q¶­0Ùª ]ŒlUpâCìF¿U«{«ü~\,•~¸]öCB û ìdÉ~N“2ž~ÃîŸä„¿Ÿ7š.ýŽƒà1UX€ÿç`è÷;wFC7Qžýæm¯ïÃhÇ?ù30«QÛR5iIÿ'ð ¢\M‘ÔØÝ>؉[6Í“ÔØíb$5v‡IŒ›^BRc×ÄHÒƒSâˆâSc»šÊS¸nëÎt“Eº†„Qn7™ì˜Á Ldûfm0–逤_Ð.Nú-¤_p4ì/ <·@ãb“vÌÈÝþ„(Ÿ <ò¾Ôm<5Ú0Y‘÷¾ª9cOו#Ö7“™˜®nóP·@@ ¬¶°É·£¾[æùë¼o„´B퀡ýG¶û…fdOƒÓ;ßÓ@•= ÎÈ’= ¥Èž­S= ?Óîi@1OÉü°= L V‘rOƒÏ›Õªùù6Ϭç€^Ÿ7‹¹³˜Épsƒ0Ùã ]Œìqp~ã6ßmîïÔ8(1ŸæPD2à ú™û>½Èð^©8P-Ž}g¦ëe²úe˜äû›· Ó,Œ<òR¾þÆo†·-LXƒn« ¸#„vHêiƒ/ó±uW¿ëU¸ð9³[)Ãf \ˆ„ßÖßñ9>c3 zÎÄ(#ïŸB¶%Ù&HÍ O¨C6K8÷AX³YÀ¼&›%´‹™ 1Žl–PÊ…ÒVðÎ&àí;ž¼¦ Ø 'ªã‚ä>Nžühüìg>Ì•’Ù˳âÊGÖâ£Íï7ïSÛXÙSá!ö4u€A¸ˆ7¼‚áU»‘p¾äË¢ 8˜ßLöFÍËü¨7‚ìv³&{#´‹‘½N}hòÑ Ĥۖ1Hã…štÊö,ÛÝ„‰,q45ÞÖZÒ¦·I+NLc¢]·é\ýnd_†ÓŸëÖ—A•é.Ù—At_×4¸Hte_†Z_™~Ú “}ÚÅL&ý$û2䃸ԑäÀ¤É¾ Õ¾ ªìËÐ Löeh#û2œúŸ½Ä& qGц ëùÏë8 _Ù-¥ÂW·EçÈ?oé<¶Íkö%ÈÒ>Š$àïp™òÑ–+ܾ ®1±DËîDâH—«ÂÁuÜ÷…ŽÀ¡·÷ybP“{…ØË[õpâ¿«ì¸ó·§»xõÏ ¡ôBÅFkúÒs{ðã*¼ËlIã¿(ÑÿÂnªˆTsí'iàÑG‰·$ûèö˺'ªíB`˜ÆŽ¥¨("ÝBdš³ç'K”yºOþÂK}õÛ—yJcC<ÒöÔ¥óÓpq›%A@óxúïO+çk¼ òZ 2Læ¯Î_yY|3×¼Ù\÷næél¦ê嵿~ôÃè[°˜}u=ï!Úx‹Wr@s$DnË9Ôð‡Ó} ­×¯ñ³‚¿añ®•’LWEÑ-K…ÿd,w°Ç†Ðû#·—J2ÑöRI&Ú^ú{ÿøžøa–^£Í³$SÀ<ñtT’)à»ãé¨Ôú¢÷sÉØvyl<—d¢é¼$Mçd]·ÍñæY’‰5Oævmèƒ÷½;˃£mÏŠP,½W„â)>ËÖ7¿åÑ)U} 7SN'“æjPí¿Ú«ã¿ ZÚ.Îh ÃÀ FU§ô’„Yð9‰Ÿ>/›§¾áJžƒÁ}-i°¹yØÕù[Ç_>‡iàe¾¹± VA| Òx“,‚æYöÉÿ\Ç«ÑrG= «ûËå -DR–lÄë å[„øƒ%äˆ6vûŒ¿OÍU?šÇ{Ãÿvæúä×ðýòÃß2à j'Ad7¿õ´ëå O7OmÆ6E ³T†ÍõøÏ`Ѷ²9k.ùÜÍoä?º‰Ö›¬@íÿî· ý;üõwèÄrêÞ¶éÈ:[°˜|{¼ßÊáØ~µÑ¿tæ»ÿ}t´jE¨‡Ñ, ñõqýÁ_ƒÌÿmöí‚ì‡í×ÙÛ·1Þ ;ÌYÜŽŽ{wBElFܳ¸*âëãžÅíƒOU‚h÷ø÷.§.Ãtá'Ë¿ÅË·~¤×à|Ø$ÅÞðú UÆ.ª !>\tr8´pÑ©Qð‚§FA •.ª ’E;:Æs¢ÍZì IGÈÞ†¹^´cñÝì(xˆ³p{5ö÷å¢ Ž¼Ç8þá­sË·˜ÝªZ´Ÿ„—’³üÅòbÜl#à  V†©~Ñ”¸ ß”~ÑmXü¬“x¤é·í&¦YlaÁ²ÒÀš•õ;b`¼E±Àd âçp$3j©ÿ…>d/ÑÇúx‚ãÕáþë… بî:\ü Û3Mû8ÿýD6Kn£n•pH[¨ pmÀÁñ~e¡h¿²Pԇߜlebê4Õßd_‰%º^…×A’ýê¯×…Ê­pZügÄ ¹ý¢ôoÒ•·¤8^Š[­Lg¦þÝê0plRTÿx7’¾5¶Þ*&¯4oí§éËÒ»èWÿ²oXeØåQÛC빑'7£ÖôP3Â=‘;¡¨'r'íDnÒ(^̬,m¦EÝ÷>¤Ø”ËhÚ8""Ô÷ ¼gµÙœÿ»Á)²Â1޶«R±ô[•Š¥`­@ªþ-÷¶Uu?=…Ù/ñÂo] t ŠžÚ$¨ –sWEm_+YRXx Lu4ñ© Êx=TÁTÇë£*¥2be)•ñЮ‹ªT!æÏ V¤ YlƒJ³ŠëTSs µ_7«,\—"éÇïŸîYJA.YuÞF>mVäºÍ§~;¥©ÛÔÆÑ‡þªÐ-ùS™ý¸rÙ•©aŸæ­TäÓ¼•Švšÿõ—ù§ßoé)NT%?Íרù²@ZäÊjžq›­‚§ë;šîÈŒµ&7ç˜ ”)mnz³;3ÕóÅH®—´…òÝ,$ ‚¬Se&³h¹]:޼:TA¡™ÌKØv+d@{±];=ãÏÆ¥¾e£™O°Wù(æƒçyU¤ ±Tx¶º"UÈ  ÙjýçmIä0¨ÖÚð}C?«Ã£m€šX¬P‹¶*A¨œó6‰³x¯r쿹û÷Û¿töÿVÄðþK¬?­Â空 aˆCôé&lÑàµQhÝÚ|þËõ§¼WÌ71 ]½¾Íƒä™Ü÷È9 Úh&m²û•"rèîÐÊSý“Iв”ëUHïÜ É~7w„7èï×I°$ÿмb„ N=[Ó{3Œ£ïáSÓ§„“‘ßÒuÀGòÝ<¤F)q‰=ŒŠ¬{?cjû5þ…æ}niÚ'Np«kCÒÓòé%ý´Éã$üï|¿o©È1ÍÊVºöW«;ñ#ßR·ŸÃÛçb_•Sų±¾ÓŽ/§|¬6cÛ_.é\iïk? ¶«•½ÝúÙ£(C¦+Í»a·^­kõ(Îô`"‚VG§Ûö{âG)y’Ù–À*óÍz“÷‰#ŒL{\îîëZ1…ÆÖz$öH´ÿ‡9‰š1&±ñ‘h‹çWÅŠQ •ÌX/jþ# —³èk¾Kú?Þ& ½ÅÓzë•h5Ñè­õepïoV™çç®3N>™‚L²ØK·6ºªj¼RÉj\çžw~çJ…À×E°¦7Žªeqiˆ~¥†¼¯ðŽD£l±4íõ!µ¾Ö óh”Ý뺡]u¹X÷C].ÖaPX yx¯©/à¹"u¹hómi1.F¶˜9£#ÙBæŒw>jr­1Þù¨ÊEõ Œ]ˆItJ­>ФZ}°Òjµ!5¥úç×eoJxÑ…Ú°G)‡ ýëS¨§úŸž¥¨ÉE³5¹h–¢KSÍUì/sztzªÚ.ì!Ê?;9üì×Ýð½Í÷j>’-Di¸Wó‘l!sÆ;5¹‚æ‹{…Òªä-üAvKŸÜÈi#ãik+¼"õ…³ æÎ<¿®WqBî+slþìSSýFOm™²ÃFÅ“îF᭥ ö‘`¬y$kgš9h,þg°ðÒ¼U"’Xúî¡e‡Â"M o4B}x{¬.mÕ£í1ÿ%Hã§?ÏUo®{áDSÖö.øŠ3ÓÜÆ‰õ™‡oþ4È=“oõ@/ÎPôzXÄËà&ý'±ãK¤¢ 3ŒÂÌ{ hGðïI€f7¨ËFUJöâ=õÓñ¿Eþ‡îôßýe÷è|ÈÛ8 Ò7iFÔÛöx(¡¯Ûãázxß ŠæÿKƲ{G’Ñî€cÉÂVí°ô%…«7«\Ÿ+ĥȄm¡òß¼ÙÜñnÉeàÐÈ¥Úô¿À™ør[Xp»'«h*Bøöúúí «„Ú*.ˆÜ%󨎥„7?Ë) hPļ‹ã´|ÃV W«0ÈO=ù®x‡{{ûßÌæ–÷i:Ìöµm‚¯mÓ3°¦gïêQs¯üÞ_àÐ6ˆÆ:á ¢±Ž¸½«%ËËgé8x r,mAŽEã-Èî½F¬jqWZÄL½>­¼ Z«'oq7»}Î/KiS ©QDA>ævè¼èâ02Žr<®¾·pvÃçõ=õï~‹öýçó_<nñnƒ'ï[^íKÃ~j~Qˆqçí’ïŸb+aíŸâXûÙ£¤ à…îíp«0¯Ò[¨3½bË!§D1± åÍ3Ê Uù i?¥í= *食Ko%7d!Åóç³å ݺ+Í>J¾ÓLçD5ÍbÏÝÅÛbEŽä EW÷Ö- È9IÊô£å*¨o_QA{¦6ÉÆrSd£9nM²® šëæWo<ÅÏ·ŽSb)ò—õoò?Ý–oËæ;’ìò;Q¶†Fj½ÇNîmé@)uÙmAT™Å^±4„8 žìÂ:*8”†¼çs‘[Ž6ù¥­4{ͨw¾D;±A£p¬SàÖªc^³ÄÏã¥Þ+u±ÃN¼U˜fÄolØŠ8k–grƒ.¼€*cëÑÌÂo%ðßp®ÚfG†ŒâCª#ŸàФf—ôX²yˆ½´CøŠÏ£F5°nãQ¾¢³¯-™Ógs‘ÉÙ±i‹ºF¶y»½çyÈ¥;Þ%Õ+}y,GÓ½W«ÂÏoY@å·ýWÛÌD•å{ëEt$KˆW“G›†Œ“èÚ)ÍÓî Ú{Ãi:©oÝfª€ê#„ðç㢂³/‘Öúa o¤ë•GJàˆÉµAÍn=à½Wt=ߤt hþ§q£6oQüg¢n4ÔÊSd{\qÆËo™4¤O‘üf£¹¨ÁòÛºyêˆ|ã_âèAÔ­Scÿmëµt3u«vDýÅéé®ýŽÝ1µÂˆ<¨U%¨]îkçå7 Ew5Zú7G…³·Û/ Aë›çZ½]züà‡Òó~tÀ„¥|©¶T­H’ϳ„.Vª<mì2ð"„[t±¾+òDyv”œŠ‡9f ÿ sz8·•…˜K8ÈÃûªH!Y* +<ËBTVØ™ÊÂ$0(.£ßT5ï\•Óu´4è QüÃíxæúd'0Ì¡ò®ÀŸ7«–®j¥«kAî«ÎmU;ïH,~I± ÆN҆݊Ã:—;q¸_ëtîü%U¡•Ô¿ÆËÍ  ¶N›bÒJþ_B¬Èà^ôG~ˆuŠåihW”W´QTeÀns±Š#¤ÂüLL—¥$wŽˆ¾FI&걌Ñ^òb›#L‡a÷¸Ë­Ð$Ùœçt‚÷(5Úk™€°Û~Õæ±úÄîGÊ“7«Õé%'ÞŒ¹¤“¿Ã·ÿmþ§Œ-‚ר¥5gØÿˆb¿uŒ«÷{l™ÉÀ½wsΣá-SÌÿØám²“s‡¼m ×rñ³É]ôÆÙJlw\ð>pöµÇ§ŠŒÏ!Çiôb.Î %ö{ºä\oŸ×ƒèÕw,ÉlޣނéQ–dŠŸ9šŸ¹“‡ågîäaù™[8´ùíäaÍoë¡éc'ëûîäa}ßç É Q¤íknU…¼iSZã¾^ÏnóœJøJ3¦Ûªn1ì0¼³ÇÏÑêÔí4šý¬Ež»´ÁGöS2èDÚ«9‡áó ê­S(â~yûü/Ñ#¶{޹« Ð{ÜÏÁÌwaùk o•ÁÒx+Ñz5óBöe­åmt¾²±V¢ÇLžN~gÑÃçùòWþ"ü0Yë¦AE/´µ‰òüþP+mßñ‘Ò×~Û†ÛÞÃ}_z–ò ô~c:»ûzˆ±s’‡BJÛ{ØøÇ~rmán·E‹+ÕÇEJ{œ}E&ø=× Çrä‘<ùƒ@$WÞÙóEÒ­ íþ”£8gyôè ‹6þäPÎí\‹–Ñ:9švO‚¥ñ“ƒˆØÍ BwCÛ"wEÛ˜BvGë`"vIë`X»eÀÊí"ÍÐ]Äë·¼|¬¡¾¬³—€~=nY-WñâGQ†‚°×Žeò+åX&¿^Ê26~²¤;Õ|ÚË圖6ÿÅ¿e$Mgf¤AFÙ°P¤«›(${Ô£_"7÷Dþb“¤á3­œÄ]©.ca­š™=&ñ‹ìš{æãÙwþÒÛ•éæÔ)³ÙìùÛn&£bLk?š· 2?\åÑÅ(ðîü#pÞe,]KK­£Ð¢ ¢2ÅSÝ¢|/// £íùÍÊĸJ…MM¸nا&N¡ ™ÔlâT›š^ˆ9¤å|bsæ6Éhkw$k5Ž—Á­l-nÖhJl-nA°Ô¨©Û ’l 1pÜ6ñH Ó&iqtï.t(źÿhù`æ•à7·Û÷J•Î1o}¦ûÉÃÍ/¡JoÝ×<ü™•™|ÙM¥ö0¢“ѼâÎïh^†€y™¼óú:w=ò«VLÑDš¢á=݇úÓ½~óÚ¨µot>MÅ&3bÏ~ëÞç×¹éÍ-ï åÉ1m4Ó «‹=MØ\ ˜š¾ä}£ÐŽSÕíåxóOÈ*9umTS~;>¬ÃOH2¡»0Z¶OFmV¬Ú¤Xµ!½F¾MÕ&ÏmXå·âj#ÆÞ¢ã{ÙÍwúßVgþÙû®xßUï»æ}×½ïFÞôgÏ¥uØžÿì™7ßMï»å}·½ïŽ÷ÝõfF^ê<#‹tã}&ŸŸÿ¿Þü‹7ÿÅ›ÿêÍæ·Þü{óoÞ|îÍq" +÷Ü´ æ¹ÕÐo櫬Fq³í—¸!˳_Ò:ÌÈ:üÍ£KñÞüïdvË1ÿ:Ü ´,Áùñ·¦ávÛµ• ;d¶_‰ùoÙìGذáùíðéh;8¶ÃÏd>yd-Šu˜•Æ×/‚¬X®øV’çmmúÚ¶“Ô"ÞDåT'„#ÏÜL×…`2 ÷ÙË Í’øMì(Xï¶VùÈ*8’¬»$Ÿö¼õM©`~6˫ն”9UæÒó—G–úœ‡½ Ó5E/öúí±wËÙñwÏÙñpw“f‘ñ‚È¿[ÞÖtäÜ-Ùc˜Îþq = ªjæ¿åÌ{ybçAÎòMóm—‰Ý³@•ní†xo_Ém}tµ™ÇWùOéŤ{&½˜ô›ü×í[ž\CõØFl¥%ŽI-ï%É™oˆ£;+~¬bÆy¹IÍ}ôê®hÅø\âôßèJí+Rw’SP–ˆoû^×ö5n a=…Éšì—Ë,/WÎZû•ÜÛyã?Ž‚ß9º­ÓׯÓkÅÑiu¥ìæˆÆaê~söYOÚaºøí­óêýv‘«ïgï&Üþo÷¥›ÊÆ;ñ8oÚx_ò¿>~Û Ž–#Þ¼È7d‡þìí~û¼û­û‚¿Ì~.dý¨“gÏN»õè§^ð´ÎÞ¼Œ|› ãhêþkÇwÿ"žêsü#HÔÉx4¢tíͬbâÛ‡ö‘*É2àâ |­½Òe=·@Ÿ¦¹@ü7×´Vg—ÓE¯)Öý3ºEÒ{¶„42Ùi5Ä^™~ÍÜþR€½-®“¢!±¢ ]†B ,쇲‡ÚDB¾×ÉÁ¾Y¥gÝi®ãŇØÇÿ毻Ñûù®'‡Cúv.y1ñìnn???çÐ_b)\ú7Þýʘñfë¬OËày½6ó]7ó´Ñ›gÆ*HS áFXÀÎ#q¯õ7? ,CÕïòÿõ–ANlÎÏYL\n*øöË#g{ž%ÿÈ(*6£]ÒæëU˜á¿ï%ë‹øií'-ÈäÅ _ýëöËG¼¦óµ¿f!š¼tå§¼òöµü‘ýƒ(îsvÅ}¾l \©¸'Oáßæô ß-Äÿš>¾í(…$¼\2•÷„ÿ¥/A’׊ÂÜñ÷mc°‚¼^ÀPVm¨´©­1"E_9»Á@ã$ì-ÿ¡ƒ$Ú²~ýöU°æÊCÖ\y¨Á4WšDÑål¿¤”sm7¬ÕÝòS73Wà7"Ÿf þŠ5D•@¥MŸ‘¿Dmj\wÕ¨‚†ÐÈ_‚`ýi>£íô†1ȯOÔÖŠãi|z"nþí–1讚ϹþtM b:}›É3gÓ–Q¨ùùuÛTæWê´ŠÆÎKÑC¢’ë É~7WÐ@ô*ÿm—fø>ñFÐ.È{½“§]T°ÛŠKÛ÷†Ü·†ü¼ 27ùh…¶~‰ÂèÖOÓ—8ánOÛ2šYÙ×äe{ç/~ˆÛ#šC£nt¬ð>¤ á¶7³·¼•1u¥yIwßVШT‘ß?Jé#,"7aÑ@ìžùf½Ž´íjÎô®¼ÍX š’ºì—G_Ô¼ÍóùbT{œçׯ¶å nˆ¥0KôË’ºÑÛÝEŸ.jÖ1=cƒžúë$X’Íú+ûÑOé9EŸ÷®àJíåR¿#n"Ê5sŸ){ü-ÿ÷&H¸‘«%Ù&Ù‹þ ƒ¾·$ÔÎÛŸð·>©‰D4Í{‘xöФl;ØBL„æ]áð„ÿ…¸m`ŽÚÀàLyDZLŸÄ(¶øˆôéš:&NÙç\é«z»8³Ùm,|Jœf;âæg'AN±‚4Örhœ qè ²»2kÝhièFõf3#E¸—çä=íÍi[Ì4K6‹ìæ«ëyÑÆ[¼¾ª¶çEqò䯼0£.²Æ·_4U3›Ý.¾Ór;bhˆy¦)÷qòâ'ËýëeþCÏ“ÛÎm®ydrFÏ“»]‘:²*|d×û5oë/hËdâüÓ8çW§ÞÙƒþ|›§4S{C®ÞÜ¡ßÀõæùzÞ½¿¢”°oë€sÊ™ªz?Óm—ŸœÝÛdþ¿’ƒR‘ìrïÉ_Ï83mÐ)ðçcÀ#r§mZF¬4"êwy†¶¬Ç#a,§á}ÞcmÈ`ªîÑLð¼KŒµ÷7ZÝøùöóóPg³Í‹—+{ù_mà%dÁ31ZĨn!Bš·kÄ@Ž%=Ž·ô¼?Æ«%9‡ Í?oÁBÅ/:ùåo9ꓨX!*ÞN“f\ïSôæ-ýÌ'¶éWz¼ï×:j{¹P”]—‰¡V“H ´·<ñ8ï6÷Ä ’]µxô‰yNü0K©ñÎM$†6ÆŠ†ÃXLû  ‚=9¹9y”ãà‡aV9OôF*ÎCéŒP”4ýïÏÙîhÌvGã“—£ gnnü <Ý—òÉØÈ¿$èšÅbì´G•l#Æ,Ëâf×ÑÉV-²YÖ›ôÑ£A\Ïß¼ÞÜMCÿÕìùçõo¼(¬î±s—è&¦íâÊæì˜Úypw¯i &¾­ó[¦ëPèÛéØáÒs›“’‘é¢6ËÜú0{ÿœ>ÈÿßÒü+ßc¢'eI݇«Õvf#™UýhPê' ^¼`<Q–z~–Ÿx~·øÜÈFÃÈÅQãz÷ÚÛåoÔ/¸Í’ ÈÃ(úïO+çk¼ rþkbZ3'{Yœ£CÈe˜3óÉÚÇÛ87…vn Ͻ= ~rÖ0L&ú÷²)OqòŒpÉ1ì þ¤,&ú¤Š.Ë.úîRw±ïþƒjWÓcä¯òñµ–áu;¹ß)èpt¾°3°‹Ä·]†77[wêì2©^ŽY±LG“pîŽÇ@wŸ8Ò¯_óvŽy13Ǻ}ç¼-OŒß”ªç3¾‘iј]¨Ý›¾˜žã‘‹azõeÆ¥-ñšæ÷hE'3¢ ‡Þh:ïø–G¼éhINH®òÍ4úß¾¯IÏJüh?yþbAn<¸½›~.8­aŠ˜=çÆ2PtDþ­½ð¾ú’¢16‘Ÿ¼yQðàgä¾Ë4s‡4àCÎ’Wü»½‰ ïȉ*6‰ã‰^ÈÒw!Ó´’à9HÒòRv‚—2~Ü¢Iô7\¯Ú±>ó;r( ‚|êüéôPpnï7ªú5Ž®‰µ¥õ×¹¬w˜…í ,xíüb†&ó?hÁyqg2U_(íðû=×ÞDo7øUi¼©%v¹BªfàH¥ ¯ßÖ)ò\«+€1×]bw®%^Ĺ–ëR°vkµs;Ú hÅÎú[Á“‡-–’DbêKûý×_æŸ~/’³x ÓÎ/ ÛÚ£k+ÔJvñæ[+¤Å›p5«Ž7as[&—§Ë"…6c“Âà¨/„¾',ò?T8ÙÉØ«Ñ=ÄZ{g"~‰þ*OÒc‰vJÖò³OŸÅoh²Ý²%~Í‚h,ÑÖ[Sv뽫¦þ¾çôƯV¬ö×´êaÇ–ŸGjdYÅm‚¶´»êZ¬ùí+XòvoU$yôÝp§äÎÀº2½©¡E¥Ußd†¦§Ê(-Ç e´£Úe<¡­Åº4—€ `Q%ÁÛ©é"V6¼‰Ô{ãi¹aâX²[Š©ÑäCš5Þ¡TïtëÑyÑgQ94k8´dÞ6rèÒ¬Aß6k@:'@Žòm)Õž£|ÿh8Ÿü«¿å?q”ÏÊåæÞ±íÑÚB9ô=(éÅlÐ ùŽÛrË¿íYúGõBàú´mä𩯯s¢K@“‚¾ä}ÜyÁhî¼Ð´=›¿øgïfÛ&…þv½ûm”‹°m•ÐýËÕ·)í[‹÷­ÚÚDbË?×HÍè»õ;ý+ä®ÿ'ðÐ j³Êr6„›ÓåÞí¹ÝZ¹÷®àtV«iå_ˆÆ²N©šv´…ÖÏŠðè±[©>÷L[ê‘ÞÕ#ÿ¼«Gv ´<¯Ræ 9•ù4¯%aT…YR{FcN8„¥a0„¥a0„åa„6äa4öt*ƒ$µš‡Á’Š¿Çy © y$©Õ< ‚Ô¦DŒ¦ó‹mHÄà‰­$b0Ä6%bøÅ6&bØ£Uó–[ Mns&F3ù7fb07¦b·¤b4‹_rs.Ar[.F³¹E·æb4fí »-ƒ »=£¹ÜÂO¤ctn7êd:Fçö(N§cØ£“{ù§ó1:·q-%dTnaµŒ ÷Q¬edTîXKÉ ¬ædøÖ“2*÷áí’”ÑqG9“”1x6F[R†ëuÐ=)£óØ;ÁY—ÇÜ`felKr:+Ãu ŸÉÊp]”²2\×ÁÔ²2*ÿ&0/£rù¾ãĮ̀÷ÙWnF5xÞj“Q]n»5ÊüŒjr_ég24\î3KŠÆàöŽR4*»ÈAs4œónIÒpDòOÒ¨¡§±§iLæ¯öÏzf…ùñðÏöÌ †Ðã¡Ç™æˆÈAèq… ÿL›*\0¤eVöt"³‚%Ž3+s=ά`Ìõ8³‚ µ1³Â¿M™„•mʬ`ˆmȬ°{¿ÿ<¼£šJ\øuÖ˜YAÛ’Yaö‚3+3n̬ ¨®%³‚0å¶*~Ém™„åhϬ Ènˬ ,I{fAø©Bné'3+ü«~:³‚0ýÓ™þÊ™naÕÌ ÿ…RϬpO°žYáXˬp <ʬðKìYá?Ì ×h­™ž'G÷Ì ÂÜ…eV,µÞ…gӞɬð«¹=³Â-ûtf…_þ™H!—‹É)äð8RȾwNEܘ—þ1ÒOÜÑån$|‚¼¬iÛ Ž¼A©ðY"µ)%óûvûn<5?ÐtD/l2¼+³J¿Íão_ŽÞŒòÈÓ<äù<¥ªãøü2Ç?™·Š¼U𬸥IAÂ-& ˆÒ~oÛ¨‡¤tûõ¶ù¸g–"-×: îÃ×í÷ ø¿mŸø¿åÉ|üî'D½ù Wa´yýØð¯i¼?HÒü¿úÿ› ]…{òpùËãzÝñÛ þ¥îòƒÍøQšõKáŸ}Œã¬óî_–¬¥öþÙâ¼Á?Ǹ8›$Èßdà-ЍÃçÖoà%E|jǧÀŸN3?Û¤[àO¿šŠ»Hè¶YÓøè3±8´¡h¤Ç,[}³ÓŸªY D gø¬uùøïj7 Tü×_ý§¢Ôïã_þò—Ý,p>™âC7í ›†‹>ùO‰ÿ¨*Šb¦N?óiõPôî~³}¤}—_@UÃêø½é§ #_|öxßu—sX÷ܺºúȹ&r‚ˆ²æ~ÈÛÁÿ)ÿ'@* ´R À§«q×íƒgµ©ZChÓ„|ó#mÛ •@…:ÿI““&¿÷Xz„©ñ EÀ¬(‚^©Ô]éþé_Âh·XÝÏòÇ_ƒ§;Ø-ZaþèA†Ï°TÍ’¢ýÞóž×YÂ)-Ûo#G·;n£¦Ÿ“[«utÈýÕ&£`D.¾Ã:‰3òž –œ«"D[^þ;–º ÇáQüùÔù°Œcš-¯® $!èS óµ¿8ˆéþYkZ¾W>ÙL?øÏï{¶]¼5.ÿGeþÇŸþçÿ ¾ÙÿüŸ ã6ù¨jM+uõ\ uÉV³dÏ SoGe¸C«Ò5å„ô}HŠ]¼Ñ&~{ÄÃ_<2KvNHÞ¬>Ä©«Š6švÆÿø·3‰»ì²Ð2õÒ^aÛͲœóDTØÍÀæ‰ÔJCeóbêágÆ«ƒ}-En–Aºðºo5¦çCÉLÒß–]ýγÊ6€VIÝÝUVÕÙΦø+€€ƒ¾TÝÕ˜Þ i–lÙ‡âÌ%*1ÿˆÈBÁKoº{š®É\&Ó#bžÏ é¡Ú:³B!o:z€Ùï^râ5 9!lo}P…Ã-Ëà¾Àû&ïþu,QxÜ£cÜ›#o’ž™ãl|Ÿ‡†;ò<æÜ>&²“Y÷25BÜ-ÕÇ+ûžû|æÕÕË£Ïê]v¯¾Î3|¯¦Œ(«·Us·º/ËhMÈY;î°zaOªê…iZ÷m‰ã„ L‰ï,[² €oÎŒ=«3—ùîeŽÅj®fò„b÷92Žì?’pšAWM5zs–ó·LËfTY=ÁÅ¡´RÝÜŸz¼o‹p–5frd?4‹5—…¨¿C1å¤óWšÃœd~€ÞÑ^¢^Jsª„ŸÊž´ÙåyŸV«xqu•”õ€Ýw.ä0iþ–OInŽ VâÊè98x´Ó¤>ÓÐA1ðø#ì©,Þ $vpN“º|‘#S›Õy)µÌd<º ±µ·piøŸ^Š?üõêŠ\mùŽà|7 ïѼƒŒgw•aö:|CQùÜâ&#Þx€)8z€oœ²N4Qw¶aö ÒM‹õº¬Ðœ_iº.´Ñ÷ý]EY²\â€´É å…¯4â°+¿e¾¿sIC_݆; ÌÔ˜dÞÉñ j*K2ÌT´!BŠÆ ÏDWåOµ?Óÿð¯S~ãš ÌÆ"éÔvÇs<ë:ý»Ÿ>þuº—¦Ù?F²x¢óûB†›³~evW/Ô¤´ó:÷nêã5¬ù!ä¸+ÙN"â]©1,¸îJ}Óô‚ ªeCâÍ!…ݦ”ù\ -¶h+SDµ<еúAc•÷BacÔ¼AÊs½9PˆF»Ê_ñÂ\&¿w0ÛäµÊ!ŠéBDyy”Wp–šEÕV÷oy ×q¹þY@j ‹î=ÝQ&&b›¯®ü(Žþ}…äŸÛóúï ³w„jÞËî1þ:K©B¬¥)$l\ îXö8à»nSN@ålsý'  S/ÉÝTsQ9×ܺdGÄ §¸ë1…y*Á”ŒšäçYغ39­¤Ö%;­üyxy½9UUž„þߘ’£ÊSñƒ.ê¢û¦À˜—z¨àp^4/‹`z Uƒ…!0À €û¼Êò3@ô¢)þäܯ1af隉Ïkó,v©*¾Ðätæ-ƒg´à¾iõŸêÃMOÀ­’Ê!¢µ¿ä 9•óÓ ,ÛÒŽ×S$÷nõƒ[Qq¹ ¬kŒäÄ^ãxñàå5‹,…‘u€%FÀYˆ[b À[`ÕцXa¼…¸~º„FÀ]ˆ[áÅ%¬0þBX.omÒ`É-²äN¨\ħŒK Œ°7KºÄf‘/ñX!…ÄH„+›ýNÜam5K—˜ÂÒ ‡ Ø4ìþ_cE’µÅ… Ožÿ²€…dq7!oï—2†¢ÿàÂ…&ji0—Vã¹ÊØ–XâÛ(CÐÒ&S™+5e‹™ñŠ6f¬bn”!hÛ¢V"é*—þ([C«}2…©¶“©¸‘£+g îÇbë+nW YñdqHš= PI©ï?‚KàšV5g rÉXÊâÛëâ§ßñVÕ\ö–U\]këÏY a 6¨Ë…†Ãä%›È#ö 1Fgº<åh#)lÀ^æ4ˆ–È묗¢ÿuoâ¯ØÎÁ"À]gÍÑørØðÏ2AwÌ9Ä:þ‚®®ËÊ­Änî^dyöZÒfp³Ãê\h€¶™øôù¬][éóãûûQÑç³m*Tú|Ø“©+ d¹Øö™_o¯šN@iÀn-$võ!â¶)nè°‹ÁNÊAeçr”ñ…¯ÛgûÚOü'övÛ{yûr¿Í…]ÀûÏp˜Ò™/ZƒÅ—ñ<ÖzMçñ^§oÈðå_ÃÐõ¶ÁÜ ¦‡.SÕ¥>D0{ü”öS6¬”y€…èç2 ódS&°¹NÀÛ0 ¢ÐéRÞçÉCÜ¡æðv·‰™y¢·§ƒÈ D[ô¥ü÷û8YPí1å —Y”‡PVßP£Ú&µØ=Þ&zô»Åh’ÊË *‰ç¯ˆÇ-ˆß×ÃŸÐÆÕÕ¬ú©fó½õ& ¼ç0É6€¶z5‰§Ê㿪Êá[©fí;ÌX+æwó°cªÛ1ŒÛ›ÙEÿÏéØé½…ƒ®w§ÚÄh ÀÄñy¢7Y¥§Àµ¿ZÝù‹î€ÿÆ„dIú4w°7(?‰{;RÀÖ!=Ç6ihž#Ë4pØ‹€øaùwX'á3yIr®‰]åQfŠ¡­¼2Ï>W½a¯ÌÚ[d!Ÿ‘e‚t¿c·¾ºöÄ/…j¡&÷¤¿mæ£ÙÛ!¸ìÖ¹æK»ýûY&Ä‚=?Ü-=`Ð+ùOq,²€³–”Š%Û·ÉE‹ ÖS©÷£x&ß=†4"(7â±¢Èy+ÆÝe¢JïÓ_ýäGtÇ&ò·[ç–`jüñ{~›ð{Mœ»¿ä ·->×îeX¶¯ˆ^0´ãcßQC›ËÕÐer¢Þ 0ˆáÝ8 ³ƒÞŽ`ª MÆßp¨´JޱÈ\ëÖZ¸¸²¦jÌí˜Õ7Òæ“샭Ùö0÷VwÄ©è¯ps&ÛYYSax'”úÝfO|p5X†$=!o Âb¦·r†F͉s(k›‰CÌ0YÿH„EWÙ¡äÂh&«CÃf®Ét詽+U Ò »úrú;U¿’çÒª_E]‡)þ±YKÈR’ïκ9òæx!G²×~‰¸*¦¸ÿT<úú‘ ×iÌ4÷Û`Å Që‚{|—l'àQ Ó}/¹ð€ˆ^¬ÞݨVÔ’ÔÜ1¡ú4W’ª2¹\ü­q;Á« äF¯ïÝ4~*7†7Y½3üŸŸãpYûć¢],ãÍäc|Øîû&Ê’0JÊooh*sy/($šå@¦ÑÐ×·%4nØSËšó›½»;“n³Ò¶ó¥ÉïâxÅhøÊÓXc)Ì•¥þX…F‡O$}t>©€t,¦Ìeôj¨©LQE‚ÐìÓÔ–Ñ?W Å~õ e?:i?°é“UÜ8/P=ÌURÖܲä&¿ýÕdË:éa`<v/ì^˜yò챜"ľ…9µÿC”÷f>E}`_û„¾"‚H c(³ihÕ{Rç<ˆ–S‡2FÿÝT‹µÿ†Ueb&)Nƒ4h•aP$ Ÿé07Ü ^ÁšâîØÃÊ{SFíå0ÈT§¨6+1Œ@øåd]P›ý-ÁqmÒâZþk“=oÒGÑÕ¡øÑX}¾€&MÇýiº'ÎeO¥‚"²\ Ù>:–mÞ.L Kö<žl±•3(¹i6²ì“9í¾’?c¬ž§ 0•’_Ìä—©0·«â :ù›ì‘õqdp‡œ®®æÄþo’íâ†}᱄įL`!R×1ŽÂ—Rs ^YâVÛ¤IÜjƒÄñãV]“§F¹WÜj¥2M¢W›%E¯V4puõ›Fjct@²ªze$,@ëé¯Ã0 ¸Õ… ¹¡•jw Wõþ “ ÊØÊ#W¨Ðùå̉–„¼šÏiÈ„±! l³Ïšž#Ó;ÏüìfÊD‰¦ÕQ"»w¨ÚP6ISh×ÅB5ˆAçZÆx+€—Üezþ4ræL’õœL[hßÝ÷qšÍ^ƒEÿ.%ý²|ÊEWŒG=õñ¬£ñ~jû¯WWAöDÌ^¯‹?ë6ŒŒåÕv_ÐÁ<\Ëî*‡#ç ª°.æ„°)¦¸»K•îZ’båºl‘ˆÜD$‰ðîðò%Φ*_áy+2aCrÖMGa1¼ªßeiêXiúZ[Ì1—˜ý. €(ÈóBp½}¯¦rô’&ŠÊn&ÕÔ‡±Nóòè°-5ÙšrRvºˆ™}·¼Áû)á‹xÉ.»‹chTGdö j÷O*š)wŒ“¦˜åÐBªÃÑ붨ôD‘ï¦å á³\•õY\!Ã&š:ð=&÷8‹‡×ÑSEõ™íbøô6º>Ô“Õ¡¥hì:äáˆXû!+D½?ŠG>ËŠ5‹:<ïîÃr}7‹ËJÀf…‡[lØ7¹ˆõMr¥r¿ì¸§çs~9ÑÓùSþ[Jiþ\úý]#hKëp)½¦ð¾Óûnhl0¥?é'i_†ÃhŒ¸bdΕþ jh ¢/fV+ö§Ÿ­¨¨¸½ˆ=?ý¼á,ØÐG+ºÉÚŒ¹x l’÷ ð$ÜòM¸šÎÒàű´‘ðâÅeÁëD ¨,fư! U˜”ÓJ¸$ŲYKR˜QšŽËxl¯¯þ]øï÷q² p6 x^!ä™ödò IÞ&z £ådQ›D…CÐd&ÿt·¹ßS2C@}™JŠüžøa–^]Å÷÷ùQfÔmE1]aô·|R8·Ïå1]–°ÒMòØ ìùŽTî÷j*î"aüNäð¾ï°M£iYvY½Bˆ'»ñšìÆ ÊÂþÊwy/g´ÞB´»iïS‹èæB¥Vµ,êÓ-ßÂgµ»ÙÞ&uíAJç‘ß5S£â]21ŸË?û«Ãof«}\ÛGJçâ±cÌ·2/\S8[ë˜" ¶ Ôäeá28|çÁãy¶*¾3éÑ ä‰æm£9œ÷æöØM6a«.;L‘õÌÜùi¸ðŠ\+9“ ©»(E!>­Vñâê* îˆöêȃäêj½5bì!‰&¹#PäY¤>ô{ÔâAcåì'{5¸½ÔYó0{ÉþÖWÝ÷T·Úõp/ ÏŠ6Ê©ô¼N3?áÄŠ•é|hÃ_Žð Ë9Ř0úlìÓL_ p`ËTÁí¶¡0»Ûì $J"̪;6¶™åÑι”K‰êƒ«6Ò¹E®Œ¨°\™a3wJÀÓàß³l}í/ƒïñ bÓd Qko<Ö(”n1fn6ĉË@ ˜ë$ö|Ðs޼è-H…áb=ùõ yÃÕûBzÏ–Ÿ€ ÔA©OñЛydZª°j™rpš  Ccš¢ CyÔ‘º8û_&ži³ú ?VÔÈØBçàmÕ6ÝL 0;Õ§¦¨ÀFcm’¦2Õ'¤KWs-ù)ÎÀþ±_J/ÞZMœRÍRôð'Ï,EŽÝ7ñ%óožæÃ̹#™Gû¦A¾ù:÷ši8g˜Dœ]V–eÛ¢\”Ì2}^”ÀªVIò¢Z–ñ0˜•¢Ò´ËŒdÏ^Êü&Û‰+Ç ì‰#¹q×6Â\\ŠE{L¦F ØÛ› ‘ÉyL®Zê¼{M=FyyI[_ãè:^¿Ñ°Òš:† tÊꨖDÓÀõj$ŒfÚP«8ši¼ÕÅ&™æ¹Í`˜&¶…kŸãpù§?ï yAš†qDQy[àúîßT©pö(šÌ$IœüéOÿóϹ¬wMQ¿¨—Ât/É{ä¸ÎKR¯^&Ëf'ÆX Óg! bºcAá|ÕL®à4ê§fútË”´‰ÂuÅ¦× Eþ20dUè!©´>ýóæwïóÏÌ,Ë$Î*ÏfoWÅq]²peÕ…qšWóòPxìd0V]FèØvÿ:ÓEemTEÖûþâ‰Öôµ'õ)X†zY<ú‰—ýu²µ¼Ží ÑÁ‘èPc­æe:wC©ƒš ¶œ×ü· DêÚÈ °“×ãöÁ5ڎʼ}Á'Þ^ð¸¥^»°)ö‚§;õsCq§µÃ¦`F#c©Ó‘›/VU\ÊS Ô^x‘ÒùÄeGŒ0jº­M&È·YØ{Bï9D¸]ƒw sh÷¦Bx¡{lÙ2ÉbiW¤áw[{[Õ{5X?{Í¿¯â !¹{¢ÊþCššbi\Q0úžÚ¤Iìç m‰–}/ð 5]Èb€¤L™«I2iÖlú1jèK㢴!}ázk¼ÁrK²õÝÀã§ M0Ä_’|e·Ž¥XÀ´d«¬ê{,΂EÆýêù€D™ [²ÊÆ{•?·Šq:ÏùýÌòø!+E‡îê¦Íþ›5i÷XøºõÕ×Ô´37êr<¡Gÿô’~Êý/Á[ÿäƒEºÌôŸ<{FåéêÆ±gÚ,÷®²?9múA—™G’™~PSyúµ¡¨³I“å#„v‡â½§iÐFÛm’¦@³TÞ´>mGlòÍ}YåŠýÈ­xžb%0Ø”ßom«8‰W^SŒÜw¬WUM ‚íè‹äwµwCVã‹»Çë}Ffu·@òBË“Xù!L@=wCùÚ|fÿ ÉË^ܰl/D¥° ‘*}Óö·šøýèÊO’å*¬þ‹œø´UFä.ön)ð!m·Æð*3þÓ&ÛhP©Ù%þ^Șéô…音Õt%Ú«êœ9}F{CIË_3ÙÐ-"uNdÖŸ‰9'²?Ï$úóùéPìEÊþ<-avšúóäI¬÷ìÐx—.°½1 %%X9ûg‚“\7Æ.útpáëhèu¦Ûã²°®Ks]5Íá¡II’yÌ®Ç?¾'~˜u¯pB#VîΊÅ\Å_Œ…[‹µ/Å:Zþ««?tQ—nmí„·xõ½õ& ¼ç0É6€HMâ© ¯¯fþ-Tå0ñk©×®Òë̺0ÈîvœÎÝ•ÀþñìÉö+ |¡·JšÝïu¼‰z`»#6€"½ÑòþTú}Ç‹³×`ÁÎÜ‹9+OðñBNˆ(ø’.µ;{kÑy︮ƒ=Y¾Ðâ.@ƒŽ{óuî©Îñ f3Ì;±Ã²vEêt6ÑUU;²õw™ +»&6[Úœ­sKջ곉¦XPjG Zóœÿ™-ÏÉÃÜ@¨<]ø¸¥1ë4ÿ:þßq!T‚!ÏJMeë.phSV4;g=»¢UÓ²Y =„· ž®.õ!­ª*€gï]ƒ'«M` —KT_Uô¸½/™\-£{ »¤nÏËÂ'rQOÓ5r] ò  QÐV©Œ@k²]ðÌ÷aé?Þ,®DÉgiCaâ ðW7 ˆ½Æ,¸ŸLâ>ï`LnxŽÃåŸþ¼½ËæAšæ.æ}\\fÿVnn\ûðç£;ðOúŸÎE¾k€°µåŒ 3îu”#\Y |eÞ#LBU`kÉ߬Óam½J-[Hv+[)ÙÌT€î÷ûT»sÌäŒìq%GcíÐFýT×uˆ Òu°˜ì[&oŽÆú2¾3Ä÷m錷 ïÑ–VQ6O¶·•ä¦0!²ÁZóø’Ú”MdéÉ8È‹Q2›²ˆZk’Ø”EäÐZ“¼¦L2‡V›¤5e’9´Ú$«)“Ì¡Õ6RSTµIJÓFrÆþ™Ÿ&Ïg:¥r8D2ӜСï|k½“1ójBàl¥üø®Â"Œ²<þÅ~Z,Žª^àbž Õ€µ­ã,Šü0-Íø-s‰=DoñJÞ•9ìyoƒä>Nžühüê'?Ž˜Ý~(¦-1åÈ]ÛZ¾·hži 6{‰¦;.O]cnð8€ÜºéPWGYnǾºŠ×Aô/ùº½öH¤ ëÝ=ÌðV¾"ÍtYY¸ó4ë& 9C?ÿHÂ-C‹ÍdêCó + ë°Þ !KamëÎH›Þ„Í™óôÈcŠüèJÿ ¬%MH{ í₽~²\a´…€x–éQPån)³l½]Ê뎧üÈé»áÔ3•K…ÍÑ’iSm’lë9wèçM´¸ÍÌ þ4Lû)KÇ`ú ÛO”QB˜9ï>ŽÿÈÞGh'¬lÃlž ×{ÛÆoÁ"Ÿƒí¦êÀ â(—Ü骢†m&6ÕÔÇ:×èª4F/}®Tûh\ÌÞVç’%’ƒrý}xùåÛá§ü‰À(bñáûU (þáõsÈó- £4ìX²sn©Mà{%öe¸:W«vË\4ªÁ‹ê×8«Iæò¦¸ŽÌ]°_lávQ'Æ1úáê­ýTæöLLñâ–¸/0î€PŽÚ=òp^uö4å¶ÍZئh>ÃÑõB±Ú^ö×i+Ñrâpeód\T€ó>êœf`îù ¶YÞ³¿Úìm8OàŠi8t2Õ5áç’)­É;(Ò•5¹ e¨ÍòJkÂG…ȶ&( Í•5A]$Ó ôÇ•%‰7Ü-»ÊæÄš*¹peQ²dqS7•–…«ønPòÞêñ!ïh€Á“[Z!Ë4u¾½#0‰Rvå‚hóô!÷ç¼²¿aà.zôýfdúh®ßÁ S3ê äáÐ ÔIƒàÇ2ÄE/§¹ÇÀÛ†+2RÒùd×Á—5$rnaAÎõaiŽ[‚/êTZÜU=| ÿèüYÌsÜéÜ*Û¬¸%f˜™0?øIÜ*“E½+¢€­ƒ«Ó[“áä¼®ã§ås˜Ÿ6Y÷æŒÍ"K#W¶še(gõ5™ÓÜI~˜ðV†'¤3\­X}e¾ùÑ2~Â[•ñ—Æä/‹­¡õó5€to”š¡û«âœe¦¹Èò9UÚ tš¹¢ËˆÅ+ŒH•Ÿròªig³MÆÑ¤¡BJc0Suq‘¥cS–j@²ŠP— DŒ )gM­‰m5×Ç+µ~ôef®¶2Ë3Ž>Hó ìBO²*écü²Ž»Ç—ÚÅ–7Œ¢qe阅2¿i8kãk{G1¸2vÌ˃RP[žáúuu ÅåJ¿0¯F’·¶:›(ÌøûîTs½ªËe{˜—#á[_Jé±%ZÄV¿º3ŒõÁÈþÖá$ËmÒì> V¼)ÎêÙÃ1ŒDpÝá!Û}}øúm2/J+ºêòä tôõÑ,¾š0Ö¾â[Ä! û•ÿ" p¡ãÁp݇¯ü=w/Åõtl¶È»8WåpmzyX®Up‰p»(W Ýj‘W6¹C”.ç•EI‡GT4¤6„qÁ¸®kÏÍEH“”÷!j,Ǿ¸ø‹ó¿À XÍBKKcrvy… ùyëϽ?(d^ ÖÖRu]RÊ"¬ ­G¥ø‹Îë½Þ–'ÛlYJ÷Þ ¸ V2íVkðLîoá¯Vwþ@Bq‘XVSƒ†x1²£y+ða²£õBƼKÏ”«sPùĦœ1fLƒÎÀß6yH`ÀñäJN¦íÁóÇø0Ü*£!Þîª‰åØ–‘È*¬üé1G(ª™æËÆfwp,ªª1vç¤}ë¹ZºQl<ìà W|E\Ý Aú· ëˆ‡1`MõÁØ]וÖÝÛÛã€IaÃ: ´ß£Æz¦º/E—L&z÷¶þ}•± iód1·9`µ. =PQ<­.£ûîe¶õ÷UÞõJ˜jG ×ǸÈtÖVà˜)~jïNÍçe ÐÚ]5­1véM{˜b,æy<Ίٽ–L¼þ’`Ò b,PøšE5õéjgí]}i÷gAÙ×éN]é‰Fq÷}2&¬Ïj”•šºÇv* Ná‹l§rRFé Ø³ƒÿQîÎÐ?‡ÄkP”ûŸ~û€vþà:œœê:’wé`klNŒü½þuî5µ:™a6;9¿¦,ÛÇÝaçŸaÇrÙ¶¡?¨CWÞs°€5„>zö~ÊOièÿá¯`¶D´÷ ®ð‚èŸBfšIo x°q;] ¥šXº'e”AŒÝÏh(»ø}‚ïÑ0¢¥láwR‚p÷ ƒ­óÅ ”ú(§]ÛÃýtî3ªƒbz²§o8ÖV¹!ø°ºæ2Óî±]# &å[°^… ÿŸÁbhÇ•R×õï¸j¶£p°ãÊBÊTˆ»ÜLµ×?t—•¦µvÈ2` ­]¯•ƒ‡ÍB3 Ì›åPvQl:ýÚ3ËR€u(ÃW.¤uâ¸*—‚„|o//”åKå… Ÿî6ø s5LyMŒúÒLŒ! V;<=³W³“W÷a³zxŽÃ%}µêãÏ•¿ü·?“çà•ôq$I´R $¿¹2f¬o_äo¢:¶9Ì7Áá--é„“ÞOd “¾ý²MAóÇüvåó&ZÜfH„yYÞÏ ÕT' )ìQc¨$¶9y„〿e}¯‹`…1 “j]k{LU€£Êjå™[Öi9RU e0ª}&Œ× €õsœ8¥tšDd¹°Rª‘ïu‘K{“l㯊¬ §8±¯ ¤à¥ ˜Ž!áÃ÷k³ §Äó:ã¦98zŽnOáqZâ2Ú¡ &£Ñ‡¢y_[HÏ­J”ƒ,\ßH‡ ½×S¸X×M_©6³Sðâ_7ïáz0¦«ös°X1ùugÄQã§qçüêe!7iêáÒÑUKá»vŒ£‹UZgtW‹ §M¶G±ðʪl€ûpÅMX~؆9ÕlÁ;V¿F!wZ¤cÔíÉr¼MÈrï¹?5—šö¯:”V RÝ"cGÛí%–®]ÓVÝ©ö‰˜Ú¢Í“·Þ ZJݲÌ!ü%”VSÜC€©8›jM+¾B`ƒÅVì2¶RþÐÀ±ˆlCáþ°VîŠ@~5w‘pÓGüNÄ\1´çŠ¿š&ó‡£õÅ2P¦Ž°»GkhÊh)NêÝ¿0—3™ÛL2ÂB‚ô­@‡é³ ‹Ùzà1«ºÀÎM(pØÆþC+KƒEÂRÄÉe>k÷!u7¹NùŸÏDÊT#R´c…h…!4º(ÅŽ®ùEÆXø1èht¦Ô6°–ØŸýŒ«!@SKSS:-{<ìÐ…¦ÿœ ÛÍwQ4edݯ®þ€¬~M^–0ˆÇb;Ì—A ˜ ¬ÆðW\Ö·fÛ…ï‰fédÛ-½õÃçÃBþ‰Êd*鎢²‹ý³žZz‰nðÚáBS!h}CÜõÕ­éT7X^¼ÿCaP¶4A„@íÓÕ{ÀŶÆp+žl6Íè§nõCœ8øEiØò¢ÜB©ƒWLµêèCT.Œú®¼dƚŕ*zLÕáyÚ[’'ʉ–A÷0@‹D,N­A«Ý-pÜ/â ?Õb‰ÂŠ'èñ]û«Õ¿øá­B1ºçÇT@uýlfo€;)ßú[¸Î‚~ HcÂÊÝoAHšGqõcǯE•e…OkÄÒsݵ]>_¢OQlÍþK±ÙÚÍ€ÁN×òrëŽËJËŸ—ëŸ5¤\]=ùéŽFReBñæ½Wˆè k*^ô#¾è.<Ýß´ÓZÿ1@ïƒÞDO3 c²¦™8pغ ølY}Y¶fAñ6èHÚêo‚Ð`“;Ùšþ\z'>ÔÐ¥_ãLŒ„¸¾±û3_+±ýlýÜIÚ™ÖÏ•žu"û>÷ÜïÐô¹Þ%OXÇ熥dÙ¢(W¡Ý¿û©ëºÛ¯ûYî·ÊT¸+R߇êØÉäî"’…d}$kÓ[ QÀÖkX-” +´Yÿú,¨J™“É0*Ûó|×î¿ +–ÍÜ>ƒKƒŽÅÑ=Aƒ{ÆŸ^¨½ì¯Sï¥AuÉÜ‹½8Xu/´OcDž§˜M{XµÀ:¬‘%ª^YùŸòVt~]–|¥áC,?¤qÒù¨°DÀK }Q¢ rp;-÷ÙÅFMyŒGFQU5¥ÚÄ8Žè\?^ŒæjÂè>fÊ«.G/fÚN+z=1'o·9bàráä»’;X­8„+jz#j%Ö…[-Â_}f`ÍÉhÄo)ŒÕ˜25³A´¦”?ªÿ°JA}ÆVáæhc˜™nxÌanâ5áV¥€^V'Z•æµ\ï³UiQ0@XUuü}ÖL× RD¢) s#+¡ŠdÒ£>41LQÉ1È} bè_A2чã ÑNN×ÜÑ”r]H®Š²]1*RcV£á—F`Ø*ô²ï€:1$£,Žië°™pOÕaó0 $üU:üÛ¦û£÷ĶÃÃQqƒ³E€=dqçüš²áÄ[}åeº.¤ptÑc ˜`‘½ű‚ sÎ|¸iŒ-.0²WíðH[±ç!–€‚ H¬Y³C‰°<‡Ec«<¼”ênãô 4EïïuÈ®.Y4ÍæŽñMƒ( Ц>'ú,™n!ºdšjm[ S`]p½\º,°XÚÙ‚W)]_ ±8UÒscsV¬«¦pæ˜N“ ¶fvŠ‘ûñ•FDÁ½€Ð–Æ„ö7Ù#k’ÎfÂAm_‹tà]‚ö—ø!Œn‰§­ðþF£Žý'ìF°uXó¼ì[Gg¤ªf²+‚<Ϥ1,ð¼¦õ}ÐUR°tзôŠkúÖK9#=»{.kªåšÞ?¹ªæ˜Œ'îµÈ ±ž·d³È>xÞ6¡·ô3’ŒþTiÀø—|&—~ÆþLv¼­LïdÞg2Ëèò­ÜI„è·ò^uÛ7"ƒ*ëCÔ_Í¥!DòŒé•±ðÐí+4àSóD6ZW-cY;­ç "m\W0´”¡Ö^u,­{§ ’zÇgKgÆÊ0þéŸ7¿{Ÿž,’0¯xïË{ªTÚš=TÚOWúÞ‚Þj<úcÃ…èƒóùk6kg+æÈ1ãks…dõÙ‚Æ42ÂòFM‰ªº3?Ž+tçôßgN…Àzë÷!½ ùé/(;ádÑ>ȉa »­ª«;þ%—ÌÎW'“*äš;«æÃ„a•<[í¹…j)»ÏYë´^… ÿŸAo)A&Ô¦ZIsmb´'xýdT :%¦®°6\Eí—û=ñÃ,蓞‚ÞªàBèëð1½áËË ‘4†+“ÕáòfjÎ È×dÀ²(æœV”þ_š• Ó~’VRghôؘZÃÁb `™ÃJcöUpÀÜŽýàÚ;½_(Ó?9ù€?“ ð[z˜º2l“‡}¼ ÝEŽúöŠêxÈ»¬næ‡õ§-·´Q“ß¡³¸ª–ÆAë%ÞúE¤c´×u`Æ%Ånë€M-Ìý,‚ð9(ä xýN¼8µdñbSàaŸãpIÌñŽþ·?ãvËõoÝÑGÎ’CœÎ+‡ËJsMsª-N²R0“¼Púÿ@r¢f!‡oaê¶5Ö¶%¿Ù&‰À7§5¡d†·Ò+Ö6é¶`Øk#k$ Á¥4•×Ý1Ð")“#U‚Iìøâd µ,Ib(@¢ ¤h*.+1Cùrkïæ)=ÀöùCÀ>ꦡ²Â¯¢à…Og9ùŇɓ~å·Ïg.ï_9ž[o²&Ó6!ß3mmX.Ó=ðqÒ‡ÏÖB S´E&j©Û…!m±=ËÈæuq¸¢>à5šJYÈ}Ûvp û£® Ä`ÂÔ ³›åvíÞaCK¸%¢ïµn:–ƒÉ™i¦ÒdßëS“}¯ÛÅɾ׭Beßë¶ ½Òt Aµt*ÚYpuæ€0ÀY@ê p¸²tPIž¼³ÚÅ]à…9ÄÓ×Ó&Û#hº3u4˪Ü~Ip}ÿÑÞMS¹þ ;ruuO.0>ŠÒ,¦Ût÷]*JEWWuR}‚5Ϭb43„~U¥9iþL7:ʽœ'܈Z+ ¤P`¢oªÙSU†(‡Ò-Åfå8ÁÑeÖr¢!O”‘&24Ö‡š ì3`vúÔuXYs± ª”=á†ÙºŽôªšfUT¾÷@#©6sK-Ì37UC©1§¸n8Ýa½áXÉkªÛ‹™ö=ÇJAÏÖñžo߇‘JÀ]|P›ç=DoñJÌeeœxöbY,®ì¬þ Ã…×YÇ4Ü0{– ¨ñ¦™ŸmR–úÓf®¦ðu¶³|ÓGó™V-öÐ8$ËfÐVý2+‚—aüìÝmîï¼ZSžÚ«‚E­.eÒC[[ÝÖF_Æ»å·?X»›ßþ,~Û¬7ÔóªOç`çùWÀ¹ð¬>*«÷eHÌú®ßøéÃ×k"g²„„&ƒ‰?b(€°¦‹Òæ¡$Iœüi¢a›=ôÈáeZ&ë{z›ÁÏs$°~S³çK ¯ËÁþD²ÆÃ®=ÍB&¥¼<Åhz5Gåò ä}l2)ÅE›'h‘YRn»CxNñ›é©î½þl'³¤:Ã6FK,{"37dpRÕ2Æ`Ë;N»Ê e##‰ýOçÿcÚú[RûS’øoX „Ù|â~Z:Î}Œã©wÿÂÜ Cjj…¹k2õmÑ`ÿºg•õÑÌkHû?÷º¦è¬ôÞˆµ«SůX°nÄÜMÈÔiM>íõð§?oÏœø†aђĦæÕ?n€îM·Äd᥯ é|þí€=ÄöF¤ÿ(¡™Rtpˆv"(QŠR®Ãä ’ |õUÚ‰hK>¢~"èä°4kçj![¾õ6Q>DÁòCžƒïúy†ÊÏÒRßDôÆ$oùN‹}v­ûæI0T…çEào²GÖ· 5ôñ[€|í¯VwþâÇõ* ¢ì:H²ßMÒíQÀtDQßz_k+Æp…‹™?"Y6ÀQ²ÞT†W ”Ó$ ñˆÓ™95Ðé&û”3€ä X¤_ À¤à|²5aŒ[Wcd'»Geåm£åPu© Ï2™£¦€²Ý#¾½”µwfÓÇ8ÉØ¯:¦jeÄ«Îd¥²a÷M U|k4Q&Ì)-Zk:ÀÅf›6ky¤°W¦«Ì„Õúˆ N!:ÖN`T)Û¦Ãêš ip‹¹„:e ¤B¸Ñâ-«8z`³t^baaŽæ;  ‚ΨoX“+kHúŽŒH!Uû€y§ )®¸=PË't¾3fÚ&§7:«Ê™3†ÀL ¼Zu ñ\À‘€uµÞèÕ¦®6Ìí®„wó´TZa7#qÉ Ú@¾–¬n~p“„ÌÈÁîºeúÔüyN3Êf«¬¹Zödƒ3”ê:²'UK ©Å›J.ZƒŽ¥Ø8¥bjˆ¨\4²‘Œ³U˜ÂÊ[Òl)¾¥‘(%ß"ö§=ê}½ >;>¤:h„ŒöÕe˜·=æ]¯Ââùlwýu¼É)§ck ÁÚ4çp^TíÝ3§#Ðõ¡±õ]k:qaÐÖUsµþéè"ƒB–xkÎpB¹‚W媽¾võŽ6…ÀÈY[™òw2ÅmdºïcZ]ü««? j¨É=ÙÄÔÌG³·C0÷0ݵ0m;‹W‚â[€¬ÊÁ³pº¦ok¥Ã[E@ñ we)ùng×¢tÎɰ^JS^çg+K¯FHø9Õê¬n#s”AS»×‡Ši¸HK‚*ýþ-XásPŒõ×éF ôþÃ}šÎÜ9S› N4ÞgÕ‡È2UW㑱݂Ä×4ë„UÖcmž>ÔK÷ã,^Ä«««ÝoSn²iñ’(ÐV òNv0çA´ÜžÊÉšU ;íç`²ûÑuÕÀ†=··áB­a»°)Òï²Ã]Ëu“–@ãÃbó’!öËøÕ[x;œ&.% îØ–{PÀ±Ñ±Vô· )t"O….ê™ËâÍzÍÛ-´G4•!Àd`½EVÜ*~¹ÅM€ñWqytOmŠáa('Àw;Z®ñ—pD€C¯EhiHÞÜŠÐilDýkCÔº`<Žßëˆü$‰_¦¾0 ï{ŒéŠi¯úæªè¡Z|¾@õ’°{zÝѺ’4Œš8À&ê»ýêê®øåAn¼Œyßó´>F pã¤p®íGÍ(\oU&ÎåË}ÔO©“Oô)„Í<3óÁnÌàúø<1w>ç£qj³pÊnÝ*Û£Édæòš0 ‚Cã˜*$³ÑÓåjb*&7íôÕŽ³ªÁÁ©|¶}e.ƶÜA™ˀЌpõ=Ý…x׈2LĶ€Y8$-ÚkÇ$-^–‡¹mµÝáPKÝ|nœ'Nö逞´ äZUªNç3ˆz>hîk]Çë7ú$…fÙ‰_÷ïDÔ3¹=o¶¹_ß—íäÀ:It:MÓ@¾ã©çWÿ1YгMFW÷b®b曂Ç9s w‹êswš ÇÒ‡yëÚÌA'œWÒ%=uóÀÁJ4•£)©€ÅdßG–ÄŸ"ÙRÚ…a*Ì-é¤O!”³åádÚ.koA†t²GÐÖ†9‚6s‡´#¸×Þô_½4ü:È]h¼¿œs¨¸ÏÃ#ŒùNôaA‰…Ðbž1¡ÿ4áóhõÖ4æ,ÚâÿùŠõg ¥™\zMñÞ¾’±ÿ(ÛV5Ä<¿UzêðqäBŠs{8ôSv¡\CïÿÀ[k(AwƯAæ¯Âèǯñ2¨þiÊäyžm˜­Íª_¡ù½©^Êùz G]eõ®Dªqš.²k ÒŽØPè¸çOJÐÛi_•=BeŽýà9vÕ´¹?1”9önbÞ}ŽÝ…vÉFºçM‡¹e½¼Ðdý4[ÀêÚ:¤ÝQI…éªPZ3¬#ê:Úƒ ™4¨Œ}·½4’–šî!dG%ó¨ÐbOëá«0o 7]:0 ²c £Š XQC>¢«±¶S”£5ÅçpÜD÷ñ =2ÔÚvßXM*dŠc-\]ýÁ®™úXÛ‚}Ï[¼úÞz“Þs˜dŸ•ýrOº€'±Co Õ>Z¬6Ý–Ÿa$ŒÖ†¢Â‚æýL•§ ä«©¸‹„›;üw"暈 ¢,ô·äïÿÖ›ùÖ5½|V{}¿—Þ“ý ¯ ¬tÑ4%‘O€Ø±jÆÏÞÝæþž—·´äôßl¬ÖòÕïïÓðFo”YZ]…'¼YýÖòõ¥M‰ÐV×Ðyú·÷ã×V;@“ÿ¹ùíŸÁâ&Zo'Ðú¯ãˆh JnŸ¾{;Yk3 ºÈ‹xýÆé6äÿC«Ù™|…î¡/¾‚» 1<=ÇÓK3?Û¤,‰½Í’$žfó&C1X•™ûaÙžãpIŸJ›(Œ£yÈ-KÔ«+ïSôæ-ýÌßzÌ>ÆŸüÛŸóÿœ˜Ê0z¨ÿg¹Ž‰ÉÜý=Y¡îϬœIXœ"%€Ñ9„ ÙI£ÜFÖâ[ ô–(µ5ÑTcªJ±=Mâ[ t(í(¾ïÿlwWî[m’|sÞŸ7Ñâ6ú È]ÊF‘›hΧèPÁ¨?öÚ×µ*Å#tѽ;"[u¹”««'?ý1m°±¡ÐX@ÿ§ÐPÇÆL:a¨ª¡ô ‚àp[UUFéO›"T5ŒS¸*1A©ÌÉøú†Ï~ÆÝ$ -XkÜð”>ðÊ+{ñŠ3VßñÈîv%…«MÂWàx×géÆe58ÒÈÕÕ`ÝÔ°Nðòè3gNg¦ç™³ÏÞÇÁNït\'ñ(lïÔCl,–«¸æMu¯­ÜFÛ¼gçÏ–Ê%º?KÆÆó"ZgéõÅ› ©>«RXh¡¤Ôü·Ñ›ø!È1.{TëÑËè08°†§¦ G|Üü‡¿r§p³n†¥l¦{ˆŠ©hæì94û'â2T×µ«ÔƆÑ}ÌØ_æ•p9yÞbCUX­lÙâŽPo„&þ´KÝÌɃ$Œ#ŠZ«%uªPªýJ)·?M8Ç3ý©q!+F’àÑE~‚G7m¾oÑWr@À7¦ìˆªö‘'çŠç}Ô€@Œ69øA"´è H4ÖNÄßd­q1Ð@?óñ0—šÁº¸@F%iR….(†Wc-eƒÞÒòÏî²Ýø)OFð­]|x[ äÙáVU÷çÄ9Ué0× CUwMQ4ª:Y%™ 3Ë;u¶e²Vg3¢J71„Üò¸Àó²ØƒµnÌÆdö3À¤ž,° …F×=u²(•¨@™h¦ÎYâÜNfÒÁ;G‚DßÐUcT">YÊ´ÈœÄbö—L•§Ð…£râp!ëv÷àýñ[¨¨-&Ò=s9ðstýžÝ50Óâe»Z÷›·¡¬w“„œu6ÿHÂiب@ÖJ”÷«­ÂO¸œ,*äEv¤æÛ$^I– ¬“ ¸ÕDmš×àF'ã²>ÏäS'ëTÓUàY¤8&+ÿ ¾ö¦é‰Á'“DˆuxUbárŠø0MQ˜9ÛÙq)ÚÐvtá_@7mCSaJ×Ò×?†ËtLµÇ?~*ýþ-XásPŒˆ5ÉûÕ4…9ÐÄ~uÕaP¯‹`…qÄw÷b.à4C…ô¶ÅúÚuçA´ÜÄ©f~4­°ß‘Y{„©ò ¾‰šQ7ài1ºöï“}ÂÎÞA{]ñðG 9Lï pV¼¤,ªŸÿÔLëÿƒ¿ȧ௅OIâ¿¡¼ ¶ÇG±]Îæ™X´Ñ: ÈJ `"GÕ:`ºÚ&vFÇe¥¯@±OXwƒô еo-¶î¦ù²ËŸÉ:2.«â=ϧzôò•âèéÌ-«Ähp¢Ð"@0J ‹tè°½¯µîxfŒTJä¹,y<2lΩ͔ÊëþM…¤òò‡ò^ DÓßéxªš5ü µÙû÷²‡Y »{(L´¥½Œ@‹î Òf“hÒb=L4oçH¹¦|[ÒÅìßë±Mg\èÿÉ{=£×ÓU‡ìàqDìxI…Qß®IÆ<—w/É‘¤ÿ„=9¡JÝuxNƒÔËèç$†©OÓx×D¡(=íUPÓñÑ…ÆY°È@¢E(NÌ]èÂÛ5…Õh6‹.«8Ôïà6$WXýuæjkTÑ_ä'IüâÅ?ðT§é¶6U~¢ÉiOm†£ØóÌÌG¼yá`ÿ7Îlž,^Å/<_àÌâ–fq9ÉÍ3Û‡Sú™ÍÃ÷0ûhQ-§øS ¿5–LwN`ï",««”0 ]Ø>,ËÅ#LXß߆«AÀíÂÞm”î®9ê^<õü»4KüE–'<tÜA½‡¤^þôÀÏìfrÉ4þÜ:‘úê{ëMxÏa’mü·gŽ)ÒÀ頋ܹݘ"ñÕsÚ¹ÖÔÆý…âmc~ ü aàoC˜øÂÂWÃoÐõ¢‡ Š5LËb-0 úï AÙ0œ ZŒ*qyŠ» ä¦a[ý“"éÌZ„S´—õ·Š£Hm ¯¦Ð*RrœëF3oZ=&|íTäÊ=p[C×OÁ;:––ö&Ê’0JÃE—Å=·²ÀZ- ÕVx“_MÅ]$Ü$6ÕVx“m>¥gS ÚjÒf-4`òž×sªe+íbpt”SU9•fY¦®,Cq¦Ò-ëÐfp18¤&‚5îÊvźGËuõƒ.jÒOv²7sùªr†9¸¶‹´œù ²»mþs7§>Um*:’ØË¨×ÊS}½íxË2ËŸŠÕ4Rïs&~(³¯ÝÄL<ûŠefé#a™úàœ†!ÛiÆÝM‹Ý‰ùÎgòEkŸãpù§I†k-MëŸÖÂtYó[Y¶f „´Ua+d}^ù•?L™–ËÒtfóÉîk3³rñ¼M”†Q°ü>ÆIÆv!dû"Ž  ë”.»®í¦¨"W{xÁ}ù‚K6‹lwô¾Î~ûºí ÞW ã ¼y>” °ejC¶® NGR>Oùi›û~òiËú3­§­ê*¸Ð]>m»‰‘O[bf,ØáeéFÃç\•vûNM}%jA¹öóKmØ,P:—:€ šž¨š¶LÐÿ©êX”õe25íÞÃ✲ˆ3Ó¬Àp”á1z§Q±“Oä^êÞñøèO' ³u¨Ç‰£BGßb91í£f²_ˆÌþ"™¤ämŠ`WA|2‰„””OBš­¼gòÝãp ÊO%cªžbÜ]ÂÏá*¸‰îãj™èÉüÐÙa|8±¶Hç}7á<›J¯¦ÖuäÚ‰,Ϩî[‘éuÎŽMïŠ÷Ùî…/õ§5sÙV^ Χ(<¬_ýÀù ïþŸùÆ)œzi9~¤!¬‹—'áЙ:´†²MÒ<¯ëx/“N³3ûJÛà2M3àl_æuCÝýxãÝ7º6øøÎ*Þná;„¶3¿z»-'€í ??£¾««?¸´ZÑj±îž”‡úëÕÕCñ ºãz½Š#æQ; ï5¥il,>D,þŠÁŽ?a­jã¾åôwÉÉb¶GQ¾wRÌf»Œ:©Ò¥°Í¨…u©žûFÃ]¤°6K`²¤Ö-F(+ú$œs  îžéäEŒ€òœgµÇšãÐÀAÖ^é,íÔ6UZÛê+Vê ëZ 4†ó{¬º8þñSé÷y-‹XƒQ@Ì€E‹5%vg ªhpÛÿ¸ógKÁ¹î ”’¾=ï)^²5?fiˆØüØv4`;)X3R% ‘2ÉR0Û±ú¯ÑWÛG_\ò[F¬ò$U—UÇÑb>l½(§ ½Ë×w½æýƯWñÅ"pxy@F¥z:ÕùH¹©¶þSÕœî ô’ªÈçXT@¥ŸW•3zyŒ À6¢Ð.#H—££ŽNbÊøeÇd÷Oû·›uŠ–ÍQ¦X"ž"ÈÕÊß6@Í*B™6Ä«`{‘vØFöTdªã²3nïCç åêŠvóœ®9gŒuÕ]]s/b>·©¹ž¯§DAgÕ£0ó³G4Sc}°ÓAl ãÑz!ëæeÿ©™›‡«h€ï,ÆÅu´þˆFN¶5Y›è‚¢¬ÓŒœw±9ß„Ë)Î]Íì¿g‰®0""ç“mzájVÿyÃuÍÁË×›_@ïetæÔT™Ã®Úå<þSeójtÀñi\Sëß5tÛ<ÒØ¶kÊA×4û­›Šf²:§Bš }˜¾-Ø»½â¥²?íVÞ’‚›ãoºqˆJnç§9Ñl¡®ài½ò³ (ºÄYz‡™÷.d›âò ý§ÁÄÄ„}£?"ž\ÿVNcÎñò·¶ãpõÙò·x®>uºû0dõlÍ~ŒØÙï1€y-¹ì-8xÇF«Ë©>ÙÏ5¨kÊëh~xìeX¾ã§Àú`ÒÅ=( z¹ƒ.º"=êw˜Ùù:8fÀö¶áÈî(ì’oØý­WR'Ö‹ïï™"’Ý¿¨ˆˆ$y©C<Äkp¸*¦½ÐèH¾{XC$ÖÀi¢NvR?ö‹/oÅ=‚ÉqSìé>­‹`Eÿ<:î¨:.O;è\,ç‰Ø±5ÎæxN í5æÿpXUØ0•Ë=,’|ã"¡À¡PB‰zàKè¾›Uè—~æóÎìÀ˜`jšÆCà$xk;(ëM´²Á€CLv˜¨}ˆé 1N PN sNH'šwðÕÕ»¿cÁ:=Â2ö–Á"|òWÞšúeÌí¨ªN ”=ƛԖ©—€&tõŒ³=$ñfFìc8ç¿L² ò“Ã:†~F÷dŒ{•ò rŠodž9»ao^˜YFö4#ç÷0“aÀñ0­e¢l¨™¢ 0l²)#S±aX>~fÕV¤ÓGÑWSq 7AÅïDÌ5DY诺«Ž7/ÛYqçôFƒý¿ÈÙa˜(ïÕdå±R”Ò#Ÿ˜7ʃY}DöÔÕG†æ °§NnÉG]UÆDWç2¤#«Lé)6)íSét›Ý«™x"ºÒcî·/\¡€Ïþjp©XH.8.Kë@ÞÙô"ý™w+²´ jß ‚Á§ZÚë ñ³0޾ÆÑ|³^Ç wH«²:ý&yŠ7Ä•áØ8Œ+¬°hRZ™ˆ|›pI™˜ÿN^ò+^ÞØòÚh½¯ ðMØ(ä°6ŸV ¹|Þ¾m¢ˆ#ö°[^½÷…:[BJ ³Éékf‘ÛœY’ļ´¾åÕ1z_„Ö¥Õù%~£[?M_âd‰½8\ ˜øökrXœÃC˜XäÏñ&¼¦¬ÞˆmRòl‚ä)LSr¦ÈÛ}“¢^á}›Tr«¥µ¡7”€-ÃÕЄiY€%YBÊž·†‹YeYø½šÒ¢üŸàîgÿù6‰‰[œ…AJ^ )¹Áùmqy8¼¶Â}2ÌßÒ,xB¾ž´Þ îCZ™Ùk‰Æ4J,¯IïO(Ùl££'§äaó°'·rË+Óûš4jr´2ó y’oAºŽ£ñ¥õþN€r 4 )Ù˜ù/ئ÷džû8 þïÏÁ"y[ x:i½¿ ]í…”VÇÁ ÓïÕû·1¸o‚ŸÉz<ˆxgëý[ÜÁ·à)ÎìUéßÀà>Ð|Ýê²ônYøoêÒ¢ü# …¼8ŽÛ¢à¾¶þ 횸UzÂè¸o€D?¢øýjî}Yø}¹²+äq)â¾ ÝEåÅá°¹L+ÃïÒ•V†æ÷‰ï¯6ta>ÕhKÃaw™–†ßŸ+»sq º,·I|· žÐ–…ã01- ¿OWq\–yÈŽækƒ`Ééî–—…#ÈË´,ü]ãnù>ñ†/ÒP^Ž /Ó²ð{tM¹}ìUáˆñ‚Kº.c -D›§]W½yŽù¹Ž—ÁÕý'¨æ¼Þ@³,Ž¡…sF¾ Fõ¹ª ЛHÓêšq¿ŠýIö2U ðAªEÖ€gq…åÕŠ^Pý•x#èâÇ€7nkZLÆJÊ1Ixã§MK€#;X¯J‘Ø8B–øQz'ÌÈ·*;bã~ 0C5ñ§ùU£ª 4ZÁÎÊg:]8W2}ß³^ÉÐGW²¤±ÆÏ™ £ ±fñÿšEU8§y¹VwB¼Ó†ÃÇ:Í4HÆQ´Þ»%öRêL¡­3y~ ±Î(~Yi;lg‹¬ÊbûYü”zaÄ-u¿ÐŽ¥¸0Ö•ÆØÒ¥•Vq×™6ûôù©ôË;ZÓmžúMæ•F( Ç[çê2oÒ@€‰æ]hÆuÆ%»y ÁwB«¬[&OÑ-ë*c`pÝ„»5¾ˆ›)@Ô:sÏ菉™„/òEìfL¯®Ö£ÅÅNrV‰ô¿ÔÏwAîJ‹äÁjAÜž.*¼~˜•^û=µbYúÊlÈEåC,)ŠyžLGJ‰RDÎH QÖÐMÏå˜ÌQtÙ rZ1tÙ ²:…V†ÃÅÓ3P+Hj %Ò¡«˜Ãþ¡ë6âÂ`Õ½+®äV¼àö‡QDö~<Œ"¨ñcékˆéúx ¿– ì–G;v80†D³ò÷´¥ûó¾ IÖIgÂ8Áäß‚õ*\øÀ*^2 à¬Ò XQéûï&iµ@eÒ÷?'¨âû/¼Ž pbDZ-ž^ý¾êðGùè(f²Å { ãwÿà<ÒåÜEüiÚÞˆnnRó.´Ä Tbd(:Fž.öný1Ì#uƒˆ‘Q·Ž"z,.ÚE2DVB>B.ÜrÈJÈm{ Ï‚"¬ U7…xû0tà tm®ƒsñN‚®í:^‡äÁBL¡ÄùJA“î1“ãè mUGy ~ªýyÇgHm{÷[›“÷í6 Ÿ©{ [M¶H%ïMsÑ—[4µ+€¯xáÃÝ÷ÿ¥²îu:äjØý=ó°˰AöÄÛUt瀽^Åó¨øÝÐ7_瞦4Md6Ãâ «˜å ¡d@€¬CÜú–‚ÑÄõOË(ᤔî[¾L ÆM‡W^Uº1ù+QÊ9 Máêâ-p·µ:m_! 0°o&™|+j+Ý+ -ÖGèæ>Ð!zsƒ‰vT­<&¶_Ф¦á\Ø›š‰D›{ÜêÞh •Jïëì·¯[:½Ïþ"‹“·¾ [=Â9=Z°ìÉ8ôð4Né±gyA „UõóCÈòöýªþÈá ½d¶Ú›&‘¥n³òÈ2«Mce‘%'Œî_–€¤]=÷VȘm¬n;ƒ´<3 •×=ŒS¢+ö4韆 /$ ü§"åC5§LÛl(ÐnÊ¡ò2=‰à«Ør,éyKUŽd"eû‘¨¼î?½”è4°QÖþrÍNà&²l§ŠÖX¹SHPñN z(¤~§2†èÕ¬m34 "`g3,—ƒ¹Ð_–‰ôípÈ2Y&ÿ¤LDâV!b$nµ£ˆ> DjøE‰Tí©º/ AF¨©v@ÇKí±éL¥× µ­h†¥CØ®c/$bl˜‡P¯²vë¢EÁÜg¥0bkƒtž7ÙL)™nMe'd²%×°‰6MÈm/$¶µ ñR®·ø…ü4<2¶Çå,î_£¦18üQo„Ü|NX‘°Ã’©5î… ½ž§l`MEao ™}5zH½€Oòñ[m’í¨‹–w¥?-ßfH'Æ4ÔAb–ª°Æ­Ð“‹ðĴȚmrÞb½Ì©Þc¦a ’@µT3НÌé_g†1‰ÕwJ}“9^ˆ½5q55uxWóÌ;p¢ 59l.„Sâ…w0ýcZ‹nxa!Ð^üŽß†3DNŒö‚—ø"š÷ª8wX=e;†ç*×:º<ÂX×cC‹[ç5Âüõ åý¬é¶ÆÇjȶÒ@/®Yˆ˜É›4` yšq{š…ˆ±Ð¼éÕС/A`š±YˆØ%¾ˆK˜þk"f¹ù;©Cïe „›è5¾ˆÍ ‡·sÿ¡`„v’KÚ`™1žì‚–$µ“<ð2cðÌ Zæâqoðv2ïã¤×âÙf¨A_ Y‰~=|ˆ%Ð áËëienßyYåÓMPšÃä´òί#IPî S.ò$7HE/åä¤í@;„žÅK§æ¸y0'Žÿ°Tu-ZΈPY“~ähšAÎ"¨Gc(žéžG}Õ0lƒS“Â!<“U)(ïSRgg¨oM™šÙý“uj €Ë ‡îåý%¥{Þ2xö:›\–~%Òß–™¢ÏjtÐdN38s;}Ö™üa0Œ7µ­’ÉY»ï%ü]´pöÖÖ´9Â5 r~ѧœé1N`rGÖ储rgÖ6NëŠ.§ÿ2q†‰Œïªœ®iuzo_b€®?F¹µËÝ ]Gz®‡—õ pϪÏ$€n›k—/ª<Ÿ²-µÖþ]l}B£àe‡¿ŒH? ’‹ÃÔ½Ëó¢ %I$byðþuÿf/™å ÅñuøÆèÏÑo7o ã—ûtC¸6ˆ%¾G_rª^H~ r¹¬l("¯±éªÑ¢˜Q7{„Þ[äÌ€p@ˆñDlX䌽)|‰²Ù„4/+ðžZÁ0Žü‹3²‰ÈG?äšÌÊØü)zó–~æ%¨Lm™úQcµ9t4‹ùAÀÎA4êjâÉšSG‡VèbèÒUŒñÀÛ.æyçè}Uæ§EÑáa‚W“t‘ ·²Ö!Q­£ˆÔÏÁ*È‚žÛXs^Y0&[~"[\Û=m“®®þ`ÓHmŒSl¦_Í|dU¯ŒÄLgºc3íôuXžú(Þ‰kL¢{¯aØÐžíÂÞ-9†áB‰&wn ­{-Ⱦ›¯ƒ,(;ΚÙð÷œ¡]Öšö>mÉUú{ö‘¬úHÕn²!`!k¢«íÖpE§E§ ?â’ïtÅìóú‘‚k‚ãÍztwÉ?£V^ùgˆÙµòÞäêlœÙDY¼Š_x¾È™Ä-ÿÌNz —3³ÌGóÌ6â”~fE~’Ä/Ìâ­3ªå´ðçL(Óý„pœvQöçÒ, £‡û—¥øL/Ɇ'Sk‰>s·Æ"€øø´ÉöŽ_QxáÀÏüõjÃ|ýmeŠîÝá)»·iLÀû›By&0¢€$x`÷™AÁy˜{€”³j©ƒ·kh ¯O5Oâ*°4 FÂÒPj¬¢i€Îßdœ Æ9¹ãÂ8ºÙ·• |Ñò"ô¶,Æ’€4[yÏÁˆ–«¼BÀOùïÅõW@Ž?]ì „QÀ ÿup&‹þuM7øµ§šö¶9¶5uRN5ns¹;•N¨á‚€,WF†³ô´;ÛM®' ‚{[òmç›õ:N2rä²0ڪ¡-$?û«Í0Ì,ˆ…” šº´.7ËàigA”ñe8·‚KËÂÁ ~Dt]Ç’ñˆïû¡jA>¯ü‡Ê:ïó¦ô;›$†+¥d“fäKa”>»:ìðñß'†e¬pÙ ý”? ¢øÖ¯PwqÓx ô)‘2^rö|×ÇYTê¼Ô\›3ÁÚŒÂà·4JxqºÁ‰YÜ Zzñ=Ù¿qâ?ðÂâðY å«óÐþ3·|ýl+Ô_ÿaø´––Wƒf‡ì>ÈíÔŠ“±ÑsŠÀ^Y ÐzbXèk¡UÒ܃ëxKà†Â%Ì´^E+£[ýxÑÿ ¬§å=–“F‘6,ü„¥?8ò*æ“çàêêÝŸ™‡³ Ã=Y¾ÐŒƒí"â»^Åóhjµý­ýuî©Zy³Våvg²”Û[ï+Ãñ¸·]”Î×òö>)ãp{xÔÆ€¥%.ÀGñѪk O·ÜDW6grÍòöò\­Ùÿ¿Cö×Àž,ÏóÒ\1ª·Òµ Rc}„nÞ¢7ïë0˜hïëàpÑ1±Ý­&5 çaÙƒt6ÍÛqŽ3í<ÑÚ4¢J‡¹E;~@UUNýõš0x€,iÔUeUZîàKɦ­Læ4 z°V:¥°bAèꇠÍqC!Òâûw᳚w⣇;÷¨½¡|TÆ#·X\yy··ZÊ©Þwªª3—ÕsÜw¶;FþK¹ïè½3ÀÌ)"GyßMöHÚê¬ü–¦ë¬ÍÄhrêýÖ 37À™4T@7ÃÍëTOd~2Ðc^98¾9U5RÌÛ+â¢zçM ¬³w9¬§¬¨•îÖS6×"¸wʸzÊZº³¦üçÐ&ÞñØÎ!GǦÈD„b½ÄbލhÒÌÏ6)gÓ@isëÌÿg–$qr‡Ñ€Œ-ßCƒl…îJæ-i; 0‚(±Š.”8ÙÒ9Ãb-yìžö¯êOÓmF•‹Ñå.ŽWì4ˆæ¯"´2™L\`5ÿ¥{dæøˆå‰{[åÝùp—”[ [°ÆyÌIªD[vôqÎê—ÕA…ØÞ®ˆeÒ¥{ùù…Âù¼_½M´IéM£Ä§¶êð`HÇ€éDæ%U–w/sâr´vUÝ=ª¯µã(_‘Årñ1Q`þƒ~”‹v}íÿ±àŒ±ÕloÚÃs[L‹•·‹…êaµ ß­;í¯ ÕAMtßÊÝÁêXÕ{„7Î.¸ÓV?wÉØØùoIÕxG”0e×Á_Qü3aœ R¬¹û‘Qˆ“xºýq×ÄÜͱ³»B/(.»ÁÚ·¢n>îWŸ®ðM'^}C5ä„ÃÁFx>ßeOrû*ãcwLÈ^Ü*ijNgÏiƒ‰®æ4LÀþHc²ÿ̰ÆX€:„1q,ÅÆIgÕÃ9q,2^°C.­SÓTè°ÕîÑ.ý`û1Uã³:¥5˜„åAÄLÓ–¸}à ò®Ùì8[!}x' ‘¶˜QÌÕ'&äu&Xu“…FÓÖ,}:]s^­è~0“ÄqùôÕKB$G*ÞãñÓ¾åßÓ]¾½•¿r¼“€…àásSÃv9Œq: п ñâsÙiÊÒü%±ðHU¢L$…ˆa¹¼Iß¹”Û8Œv¬ÊSÅ$غÃÚ¬Jòу>1 CWËñ6ßd’Žþ¤¡ÏÃò_]ýÁ ‹šô.˜Hå0 "²í[°D†0l{÷LÖoyJ„É pѳq7pÑ :,½ßßP™;3?&!dmh=ÿèj3õ»ej÷‡ÔïÔvì_r-n¥YQ>DÁòÑõÓp?°´º7e~JÃE—5>·ÂJ$­ˆT‡&SìÚûž&s<­W~ ”]­ôI6T•§U,2Ò!ø¶)>N„Ù‚Äèœ9Ž+ ¹Å]ðF|ÂJÍ- Ž"¿ÁZà/*5ƒÌ¯­´!W",`UŸüäGt¿›Å–UÕ°1ô“ì­Xnƒä>Nžühü èé‰Õ¥{ët& Ý3—‰Åüð`Žžš c_4ô\r½ô³Ì•ô×ɆT)÷TïnÍúšKx5IÏÒ{Ïh˜ÚÐ5–;õÑ1Ý£$‘ñO_ÔÃê[]üW“QWêÝmI5†ÐB%ÇD´µô0ï-Õ0 §WŠqò?·Ôéé¿h¤;šãrcõ»Õ¿ºú¬ˆšä.±ëÝXqê¦é’vTÆÒÒÎwÕ…«°US3²/G%âäó^o*;š`¢(fü:#г¢ÿÿßÞõ5·iñ>÷SøÉM<~ ¸Ïx’¶ñCÒLÚ¦ƒ$d«•…!×~h?{9,„t»·œtû±#s‚]n÷·n×ê(5€£Büû0ñ_ßAGÓ5·A¿l“1ÙkŶŸ¦‡nƒ>P‘5–A]1‡Ž1® zEÆ ÃyG/ô¬h®[XÌúëZˆ¬Z’D³0˜j;d˜.Z[Z„»¥îA;*&ȉxüÕÀÄ]0lLj$ÿZv IÅäˆéÔÌÔ±\dm)áC¦—·÷íôÅI€:~Šj@tüÔ5]ìüô†Àe×Ô<6.¥ÄÊ>úQÿ¯p@ÛT³_·$Þf~"5‡]§~¯ÈÝûp&¡â½HÝŽSGO÷"m®)z{ÇKþS¨{‘î_AjUÉšýWWÿ!d±±:W/Òõ×P—T=bm’“އµWµÏš!hE €ä‡[‘F£Q³­HÛ3”ÆívЉ%äÛÐæãŸ7qDŽÝ3P©ýÛÉ$\]Åa?«ék<Œ/¯†cvw$rµ¯7ã+R@ª²ß\¤*›îjkÊĺn=í¶ðÓq,Xô±r%Õ¦¸FéØEÜ¢´'÷»µ{R*ƒ˜ï^¬±ôºí/8Ïlxñ͹þ'·è7,HÎt»ÿ0 ˆê/¨ÏÃæn6xHýYHóÒPëÚ.7@8ÆÖµ) ±…ûËÅh†uQçÚA´ànÎ^±Xƒú<žŽç€7b÷’Ís†äø]‰3átèG£ô͉âà^´›6)‡Z *nÖWÀ ØÎj è—C0 ¦èç°ùìU Þ²Òz¤ZïÚž·C¯—{ÒFIúŠ&™¥:ì¥0•ÙíïÙ«”ï·rv褅2+NÓ1豇v rRÁ11 –©š)7¤ ë¸7T}眂”)Ùl7BÐk‰tVmS@ìG²7F¬ÍŽ1¢$û‘âœi nzýÂ"g²\ànC¤©¶:n’ŸÂìUÕN]ð§„qé)tR˜Cn@eÐ¸Ë h¹ÙBÀ1X¶½+jÉlâcÁ"ü6ð…o¤ Z}¶Ð£i4¤§Â°½¤1NX·Á(Þ€—å_Ï7~¿ÐQª(òå#Q{žê¼¡Ç¢Ð|{ëâDcnÀÃ]ºz¼ˆÜÀ¿­ŒYÙÊ´­ª`NØ`øp¢úM×1ÿœTˆùëb ²Ø¶.*-ÙäÕáåQÓuvž{ÊŸC-ˆç)óÆÖÜGÐÛ3$Ö25%±,¡.RB@è^îÿ½F/ûýÉ߬‹Ï‡”*dFö©zèFó~ÝEñdF7ÉÐL Mƒl'^•@²/>«‘jX#•R8A’XûL‚éb6Äð‘¦8uM ÎüdßìÏ“ è0á‘ t~H‹ß´vðL>Ä75®Ï lzB¡@ƒnIlYÑõ.¿…žg“(è 'GŠžr½ †iü³”7!Æx:Šh!‹H±ë}¶ÀhZfÇ¡feh·Êã¨nïÒU,0l{k·å ‹äÁW¼3þá$Æ­Iø¾Ö¶G$,ß*íÛM¤FCú´¦aòëÚ}ò)š¾‹f/AÝTØ$ü/|pÓAIÁrN8‰… ¶BD.ŒHå"D‡Ddây"2{à© ¶Ô޶…ùª_à ,H™’å™À(8ÉDA·‹Ü)I2‹Y®9¤o á}8 “ðK¾–’3½ŽQ÷LAÓè˜È(äØª+¹):›Îëbá&ž™¾qo.Þ¾yË}é—0YÄÓ×€R=àøÇÅtð9!Ç0ÓOâwZüðv˨0`+æÍ¬OƒŸj»ËðD0Qб±êFض€G4Hy”ܦÈ`ªLP^d &.dÙØñ¨‚'¡ŒÛÚtw?§`îŽ%“­‚–ö˜ÐH°Û3¹s‚’fÝ.›\B±øZpüR–°@‡„5&:‹;~ô/çâ鮅˾MÁô­g¹°ó‚4Þ± òÓ×¿Ž£$Dv³7ª‚}˃¥H)dêîmS³LÙÞ(j"=¬‰ÄÃÛàñÔ€ a±aaiòF‡IÒ†å&‰ô¬ÍßrB®(ÙxăŠÓéSÛÀÆEv!·ƒ_ó.üÌn” „Ù°Œ‘mìb‹D¨…É„§¦)´Í6a§Mr¦EKyQ€I—`ûº°jHѵE2)¨«.‘¾>¾ìcÍÇÏÈš@P|Otí3»ƒUD´ ¶NJ鈃MJð‹®¼ép•#4Ç!䯤+ÿ¨$‚ï~âaqç¾~öï÷ß~£I“&Mš4iÒ¤I“&Mš4iÒ¤I“&Mš4iÒ¤I“&Mš4iÒ¤I“&ý‘Œ\$à$davix-0.8.0/dist/abi/abi_dumps/davix_0.3.1-gcc43-x86_64-redhat-linux.abi.tar.gz0000644000000000000000000037231714121063315024754 0ustar rootroot‹ÜÑäSÔ]ßsÛ8’žçû+òpUÞ­º¸Dɒ퇽ڌG7ëJ&qÙÙÜݾ  ”“ Ek¶öþö@J%Ê–É6㪙øç×îÐÝh4ºŒˆTÁ’ ¥ü”΢ŸÀý19;3ÿzçãýú|R~m>&ƒñOÞptîyãÁùH߯ãŸÞ ÐŒ4}äRQñîÝO4`KÁ¤<ô{Ïýüýø÷on½wy÷Ï{·ù8ùðó5¹úòÛͧ럯¦äêoÓ«Ó[òmz{wýåóÉ»¿üç»ïôòòôòä?vÿî—¿ÿvSÿÍÑépçׄ¿(ôp1!“³úO¯R®U•´¿²Í×ÞÇÉ/¾]ÿùùÓ—«äîúÓçÿä Ôߘְ(Ù ì¤P«ŒÉÓE–Õø;ñsVž .''/ùד„«Ñúò+ùðéSË¡7Œ;Nçs&Z|{Ôú¿? ƒ?ÿù¥C?zÜW·×_¯¯>´| –@ º%#ƒÊ~™þü÷_[Ë/€ÑŸ½|ôGýë퇫öÓÞùÐ/]/²?¹ë°æ91ý ÛXþÑ"øï·Ÿ¯?·7ýWçL¿}Àl~¾ZÔ-Qx“óóó¡×f#4ÏHäëíÿ+•bØ»ö@T.û=gRµÁö¸•X½dÈÿ:ü»5œü²»U2Kã#<¥w'q4›¥©TD®¤bÉûDÊôtÜÍh,2ùÇç±…ž”ÐÞ"ħŠÍS±úe0]Z2^k3:ŽŽ÷Jt†Žè\ÎÙZ=bnH †Ôœq&"ß1-#=8Hè=#• SDJ›ÓÏw™˜Ÿ5uA{¢"-d‰ýÞ›tFÿø¤ex½`DK3®¦·?ß ˆþV5æ€M#Ð_ÀET±1Þý«°2,¤y¬ö4Å×ëJáÞ§ÜO³ÅŒxÞÖW0íoˆmEhxÖ™ÐÝÑ£uÕÝQ£ ;úv¡ó®„ˆc¬K㨨=ÎÓ^ËÖ¶¬W*털ؖ½Aœú÷å „ïÅ5pô\GïºÞ K¥ñr£„y^(ÒÄ~ªw¢LG.¨`É”¸þ|G&S4нI©qPEÉŒJ6Ž“L¡Çé©E$+ûò."®´<ó̬Â$Kõ—.é A$íâµM÷ n(GЄÛÏó4ñ⚎ÇY³Æ ýÀ-E=)T*ö,èÖø5Í2Àú’ǰ3ì;®í®‘¦[»Öì® ÌÝZÞXÆŒeÖ'Û›Å83ÿw¨Ôñ*b±Ó¡MLøÁI gz?+½7{ÞÕ¨ÃÃm¼7ç±E {ð™5bã \Î…q}#ʽÉÌú+’†$I¹ZL§ÓåíǯËÅdCŸT~ÈÀSά‚WÙÓäà*|š\¥ÉEI_Û¸û²Œq"¦úß™¯N£ùºµi]O_Qø­Ø{=eµb¯OÊ}fZ÷KÕÏ2Û'Å?Ël?ÍàÂðºb´ýýTzÇ~êúÒðØ÷©¾Ãd?µ½ÃdoÔ}§¼‘ȹÍÙŸ÷JÏÜõFÁܽ‚fõ$^CGóò Z;š—7ÔÑÓ›þ[jìÎÞPÏpÖ mníæýPâ6C½ÐÝ6C½PÙö–ÜÕ8ê…Òj½•Öö÷Y“2ÿx7ržO:–a¯Øy3cn`å­¬¸÷æ;˜ŠR‚o~8½1SjëËwÚTªó× &°G¯Ú=h• ½Š„`2Í…ÏU¢ƒÙ!:p¹]}ޤ ‡Ø£vH–Æ‘¿ºVŸ”w6Lõ?æ6ÔôЮaYíTTÊUgË(iuøš'ØS¨gY6ü§w»þq;ò¦Ï:ïËõºüchŽà””¶þC¯oàÚË5¹CÅžeÖ RÌ©µù ?f”ç sîÛ5w:½YÎqU2à§z·Á—í6RíVTFaÄ÷ХܬTYê/ˆ¿¬JåÎ.ÀTΘ ’ÙÑpS°êj4c™•jÑê1Gsç“J¤ð ääð釹²í=B®Ì{Bƒ€pVÔlâ…‹ˆƶ&D’+ö°ž4¡Ý:=gÖ³OÉ•ùìSre?çVMó8ѸÔV¥'ôÒu¾5#ŒO@²2 ÝPféyfï XÌ& U—檓†ÜáxÞ΃Hf©þÌ‘:ŽçÄ™™¿„Wà%<8š;¥”þ‚ù÷ îÓ3ÐAwÓ5¦î(¨ÏÔrî‘zAá^Ç—»Ó(Ë'×düH–Y‡D¶VN•Ý †|÷DÑ=D¹{2ˆáð "F—¯@¯CqqÞ þŽ "¼Ð<œE—Ý;Ac™lŒ"._c&´".p}»»G“ÎÅøm˜9*Џpjlm¢ˆs§†Õ*Š8îY]£ˆ rÅ=EiŽ"†¸½íé(ÐZÿELÆ0Nž‰"F¸Yô\1ÂÍŽöQĤ{(sw0ŠÀêQÄ7ùžˆ"p;ÒSQ@pÍQ„×]HßG€¸øÛSQÿ˜(¢û=æ#èuˆ"<À++ #zÇnSÑ?.ãˆ^°ùD ᘿFïiÅÌQ‘Ä[³ÖI¼1GM‘Äë³t0’€òr ’îtOûø@BÏxÖ€cœ]Jóó»¤^îYÇ»çY=;³Šó°gí„Èžg ÒìYZäÜ1\­Ûë± «¡sÀ²£.úÎ9í³L]u«wÏjϤê¶)¼C_MŽoÝÞÛ=’Ÿ“†ÚX¶z$-7½¬Á|½­¼\öIF1„”ÐÙbËrù¶—K&Ñ’ü®§ºä}™Jó:þñâ–Wbi»h–ÝÅ-n9í³LÆ-ŽYí™TÇ-®xDËñ‡kðz|;ÚÉ~”vÎÙýäë²5€{~{*a÷m2ê@¦?Bøõ#D_Oñøú/!¢BI(Œ8¦‹”ÆQ _0Ó)±lfo.Èß³·lq¾…kNOÀÕal&Ò£*Ö¼™' r£ü±=࿞fæ$Žfþûá©7<•e¿÷¾˜Ö ™>Dê¯ýõÓõÏWdx:<·•à ¹þB†Ä#Rz&}Ð÷Ã6—’¶q#îÖœÎBqið=—Šøiœ''Ý ¶@ã,¤y¬HÒ8N}=‡ñØf±’ 4ò{žd †úÞksÏñÖÁàÓ%ØÍÒÂç )»w™†ÈE¾DUØ}Ò‚*Š6R¹â>2çs{3ít…æ’”AFBê-žèõÙ$‰#δj¿„!§*xÊDÄr2i¥#]ðBg: š°(ÏÕÐ`ä ´Ä{Ží9*EJ¬L÷œ;¯ÚîͬCp@›Ë…¢ëp4’Pqπѥ-ਊ 2có¸CXLÆ‹°EÄNB ÉÙPí1£ÒŠôä¹'HýÄ‘f³Ñ…ióë#¤Y)Á\ ¦·¸å²Ž-unžUÀm|Y—û@óÏh´¨LGm¾Õ?ÒqͰŽ+ÚoÍDê£ÓJ<ìé`}uÁ’tÉà[¥I"L,"4-a¡î´,ЃV3,šm¡Kh^|˜$ÑKŽÉ˜€8¡×Sú”#‡­DéþšÐ>åñÊ´ÉæEHh`|&× :8¤5°ø%Nƒ:È>ÊœcÞjÿE¤LqMj¢T’¤ÐCxÄNhÄIa(`“GÜ$§¶ðñâɹ—€Xk˹¤—¸ÿW¸x Oø.Cðþ°„o´…Ë*žÂUOá°Ž§pTÈS¸ªä)\•òøZžÂE1OáèÜ»ptJ]¸9.œ¬®ŽV 'ç …›ôT  ¥B;r¾¼¹½þöáëºãs;Ì໹œðã14Iã$Ì×ÿ‘Eš68myÚ'Ê„¯Pk¶FœÿQ¶Í‚"sæ% Ž">BTTG(ÖØà±¥ï‹Nˆæ%>ö]?à~¿†ÌÊ[Hdã™(Aa¹ìG@½Æ'³4F¹¾ûÀ$D%·ÉL&6Ìæ"ƒAþÁê|U[:óï‰X¤RÉoï[Õó›9´cO£Ó³.œšËU°a³ùÄ×›áj Ržz5ç¡I«Ô¢NÒK9g>l%òÕ*c£!™¡vÅ5 Jµ›Å6Ï20,xðdfÎÕ¶fKWõ”9©ñsíÊP˜oTb»ÐÓ-'ʯ@¼æbÖt¨Ó–ËJ¨"¿ç‘i_»®æ º°iqîþ›E #NãèÜ’¼š›#Ö²n=ç>aæwè@qtGóE^Ë8ðõB €Îü:ß²Ž`¸h>ÑÞ|gCsyfÒ°J'S‡•h#ÇŒ/#‘6d'Z®H:Äà)±9Ö¨ ¶—á,%på}Ž‹ÌäØûW8°„+«£X€Å-À|N5‡Á8«±h°DD ‡3Ãx†c-…Už,…«Z˜¸ l‰šé¥0âs—MÛH·X6Ìr‘)‘6Õf¶h;_bŠ9Πm‹‡ÚÏ;Ã5ÏâθæÉ3踑Æcî~@óÇë9„Ué-rØEÓ¤é4eÌITÓ9äSY»‰SáaÑêüuRG…‡A›ÓˆÈhþ{Îr†Ûæz‰]Ú,ˆŽ-©$Á̶Oý…¦“4ÈcfÛ0¬7ŸQ• &¡È~ôÏ4^Àâ(AMƒ—šJ*Nes.Ò<º¼Ò¤ãá|Æé<â˜SÖ˜eÄI`™sTBç ÐÙÓ—v cà héXš J”°4 (ì”ÕD`ȉØ>‚0“Y8J,Ø'9Mb…›Y¾•Zé¾\nÐM-T…þ( ¾|Ä¢Kóÿžd`‰&zI6,|¯ó2ÃJ4a5šc×ìzf»Ó"HWÙ/׬vÃĨœQ©ƒhX»° 2š»™TRQsÇ—‚·Z¹’Š¡WþÊ\wB8Ø`KeÕÏb=¯ "°³;‰ÁP1´ª\“±µx¦Yê"{ ?À)¯ÑT ë~¤á$·€ÀÒéXíš`]³ÄÏVÈZh›.b!3Í%Ì„J8™àZ÷Pi ç€l¦Üî‘9ìVøáËX- ’SžÊ˜±‡“rV`ë–yLbÊçöéH˜®¹”ööu4ÏÓ;nzÓ¯aœQé:’¦@ZîSÙ–8VÝA#…±)¡´ie-œÖÏvƒ/݈dÉrÃk‰ioÁnßaÀM°l‘Mm ^F¥,7vPÃF2-™XF>s`¾©ö¶¨OÐ7o׸K8pÆ8.b)ÑÈÖ%á.% Àöà ÉñMÂ4mlâÕÕDH.©‚¡a»à‘,•d)ÎÕÍR=˜¢äZ®±SLjÌäWps¬‚ÃÅsÙþUÇnpèÛ¢bÛ6½+û=g܇txnœ.X²Ôî’)iAwaÊ42ÎÊ-LF`+^~˜D© [ÊøÁNBƒfŸÓ#Ò<@Ç1ãs’4£jº¿Ä¢…"MˆóHš†TÕ»ŒN‡`%‰À'ã÷™ÅKèjÆÀÇm—C›äYDôÐåAšà®ãLsæ€u¶9`*«sô ì[.}’á„[Ƕ¥9ÚËÄõÅÜ!€—ÔZbù Ó°"ËwNòº̦½]²«Ìz‰Hw6Í•qí¦Ú¿Y!û6¡ã΋7èv‰|ƒj?Éc\mi‰,!¯"ãæóMr\Ëñ%46(•¸g)V°Õ$öJºŒæÔG^}6€r;Ñ€‹±€‘ÔÒ 8O¢9ŸáÜ“ v3²Âƒ%z4^Fsœ§ñ´~·J‰€¹Ìó˜ãs3ã;BÚL÷~û쎘 ׋P*d@‰†• ¾@crì ùÞ¨»YøToÌÀ ¸AÄ®W˜I¨ˆÐÚ ƒ¨Ãì Ñ.¸ðeƉïÁaMs7ˆ# b€;\Õhå% ¤y‡IÊ¡ÆÚ<Û3tÃã.– ŽŸÕû nwH¬ñd3q.%"rºH–VEZÑ€#4 ì¶¡ÁC/³ðU¾Èª4Øô¤ÃbñB7l†`6ï¡[ŒÅÃÎj•Æn$‰uÌ4ž#Ìі»(Z¢¹#Fs<£Î8ŲºdBb#»‡PÛ¼Hx»g¹’¦ Æ †æÎV2NçÐÁ.m‚g†ÆÅÿ£ñÁ´–e*7TÜ<ö„·91÷†” –7ÛBy„‹Ý.F©ºÜJýq ÌÌ›´ÂC¾u .˜är¯ã—}‰çt kiÈÔ<Óè߯›7U·´\Ì–ÈWL–Ùk‰Ø•EøÝX‰ßqÐëذ]œø,ùìuì:n¼ºÑ>ÏÎbAq§· Øæ½ð÷¸: ÕŸ¾ŽZÌ[¡8@ Ï [L…åý@¬V$4W¯ñð¹ú«´qÛNÉ Ø@c:€t‘%­`±xø,i‹Åçw*X0ž#­#S% +¢%ŠŸ˜’šk\4 3N±¬bS…v`À™t 碩cL§76ŒéŠv|›Z±tD_ìŇ5øNmMtðL×CrÏSXØU¢¡)|ÈæÄtniÎ<¶ÇDWâZ̆B¤n) po7dk7š«ã*òq·‚˜Ð À½Ç¥ñ{ÙGOgj²ë8>ë¸zÝa>*µ©Ñm¯‡íû©Ý³¯Ù¿WÃ-‘xàgïÙ,+ƹ\àžòŽTJIyxTöHjTñ¨ÕJÕXÅäñÑ͉Ž[a×[–v”BâÇŒrX_²s¥¯×âc!Íc¥5$xµ2K¾Ö ™Eöµô†CÎv¯‘9'6%Ä› œµ‚•’˜¦¦-’Œ`_4ÜEÏ —èrî=ƒ¢›°Ïì° Š¶ÒdÕË dnÿÏÞ¿6¹c]¢ð_é8_úœ˜(Gê–—‰÷œ—-Wåø–rU÷ÌEBÉâ%•ÙÏ’(‰Êŵ@Ù­Žç鮋µÖllll,,•¡–ï7¸j*/‘Çb »—ºi¡J@—¨@uø%¤Üo…ñ³:FEåKä@,œY b¥Ý¼»¾\5¦” À¬ºüè—«îQˆ‘c¹úùzàÓÆr#,ƒ|imä£î%A¯ð%ωRœñ½òCn±l]\_4Ý] /.` ½äQc¨ ²¿„T)È`C@bÙ™GùáfÞë!Áú Á”ÔýÆ8ì-ít2KÐ]¿Ó9ÊK%q éWÔÃaÐìË>(sià ÛcPiží8"JKÉ‚w9ή×F”U®‹ÔCÐRB)€ ¿—ëÅ ` ÙÛ}´ešoÇ iýHg"'&*÷ÁÅÎÌŠbX ·O#µ<ëôŒ¾ŸUm€Yn–Ð!Êó*<¥U‰»8>(ÎÓpzë‰Ä‹ÃilÏ­q6Õ™ØJ7xÔŽq^]¬¨NA#Åý4¾Ö'C¾,±§¸Ï÷oõɰhrg‚k¯DŒpÂ"˜öËñ6Þr„‚»Ñ¾€Z)žÒ؆Å) Ñ […$ NA^éݻ ‹b’Æ^0õ&¨h*q€ÑT†º¼º¼ÈBKC’CB…<)L&\¥ƒÕëÁP'U`NEšI\”o.P£¸±A8hxOLÐåy|l;Ê_ƒl]Á©óáqèƒ6¾;°Ji[ 2†Ýð;!J©jìêSg˜‡Š¹’•Ê•¸8ÄtB9ËQò‚ \n8#ØöU!®­a¢n°zùxœµ]áž,ÿ[Ä g~‘ï¸+¬8‚ÉeÉsò·(õ8ÿäØÑ5Å$lº:v T*—hJ߆{ÄÇQÍÇϨܲ3‘íô’H b- BçöƒˆmPu©ƒ;w& ºïtß)-i ÞÌõ@›6g6ñíªz£ãÀæ¨zag.PSu‡!jžúr9…élçh¨G–hV¨›ú°Áæ©5ŽCÛuìÖ¹³Ò€ÑêUTº?‡•€*VYB-LH-OàMOÐm— | ¥NÇÌÜÈg,öÐÂ!0¨*¥#¡`aª‚Â-É ­ôšcC´0˜Àž%X{BåEÔV‹J/á@Ûp=PÇù %,¶e¨§ÀTİW €§г'KDŒj¤k‹9ê½×~ö½é¬bxU?á:Jï vÈæ:OyB‡¯: HôKE°(Ûfo2ÁÍ ¹j¡ð{oÅÚc¹¾åI¤¼\4sAÓßcäÁ©«Þáë_CÁPnÓ-½oÞ©¤ˆ}ÓfNÐ}ÆÝLÛu«Ç_<ΙôÎ# 5FEàÚ¾§QÆîжqÛ®1Ú,LpåÃY,á†Ãv_‡i\ ÑâÈAÂɨ÷Š7Ý@kPé¯À"¤iiúŒ„S†d&PU? :1²ô ‡¼µ/Ñ€5¬M¶4÷v«Ñæ"FÕÿj¼X(%!  *j…MB=6\d;ˆ€® X Å<>^ –o;4‡‹6Rl8‡ÛDkdrû °ÛØQð"Wö±SË÷P™ér.ƒv{*ö³•ÎÉ‘U­¤Ö”¯´¸°ÞÆê;{ä1Žrÿq ºï%Ò™PŸ •k[ãÁ¸FT9ØHààÔxAÚh ô*(Ô8VX¨ FbÒ• ØÄGd£’aN,” ×$Ÿ”QÁÉRµ¦|N×`GºÂ¡¥©*ä+È&в °†,Ç `AZŽ…² WÆcÁ^1ž8ê†ø–)ž3Å9¶ìä9•‹O\œá.®Ö9ÇÚp ¬@ÝëSHàZÇ pc˜cÁ Æàm¢ ÝÚ jU™$(O$‘PPS‘¢\‡‚BwþzT²‚ƒy_ … ª¨ª€‚áÎqVpȾ65! =ÜÉÐ ­Ü{MñpGM+8äÇE]Ó˱Ÿw~ Æø{’û­²^ûñ`ž/P5ô9ºµ^{Ô ÇBx µÚ*q@ÜGÅ•´k(õaApJ$úÏÓyªDŸs;…íoTak?°Ã”†ê{ÂGDvºGH÷88`Ñâ$Ê`±°‚B»H‰‰Z°Á<ØŠ¯±;¿âoŸ4†Â›‡r'IIøyÁ“HDo¢0ÈÊ*áp…´“¼ö·îǺðäp0°'Ði†B¹v…… â€/3O!P+«‚ aƒB£Á° I’™$I»,¥Ä96TÃÁÁÆ=â¬Ã`¤°úV …›R …»|5I«ÔhCг`ûìƒ{ïsSõ¨¬ç»1lýTˆÀÓT \Ü%0FMõ%GØ7ê@òB“<þ·LMû äs/Ùͱ0Ñrª%Xx.ª»ÐìðÙÕ ½?[Ó©í­ž !ÂÊ'¦"µìÇhö¬Þ7› P¢P,Ö§ƒ®eòòƒˆ¡Ÿ¹š;Þ+„,dÅ¡dzp?JøôØt„T×7ÇÏÐQTÂDÓ-Qa'‰%@  ½¡BAAÎl`K%ÁÄ0À)(¼Î6à`V壮”,qß×¾z¢G¡yj½Š=Û×o€â _xó÷XHðã‰RLQj: %Ш°2 a@†Ûßh¸$8oü À:4tšÆÃ¶U¢A­“s‹µ.Ì¢ÍÇ ˆ8÷©.‘u°O€vdªÜT¢¹ÍŽl`Æ:¨ø©‘û¨hƒª¡Ò0ä*A-‹½'{«Ã4»û&ÐY-Q³ù n ¢­Eºÿ% ÒF uÙØ÷œ˜ :ì=?ô5?‡Ìþh4¨uÈìªFZ‹¹ I8dkcß›{°7V€8¸È{þ"òkL¬×/ab-E:škîN…—)ù;.ìM„‹¹)U]ð\YC?q ýÊkH°È¹Rà!-„Ýn_n×p! hpMBç;ç$ 2IAIv• ¦`ᇠW5ÒºlŒü¾Ð² u†N\·*!Ðs8ä·E†Ò`mv…Mgàìq†<5T`PÛ çg9Ô¾9.­¨À@âÆ 'áŸÃA‡ÉôÃâ8¨›óS‚TŽÆDÖ¸.8E® ìJèÔǰôˆÄÂ!Y‘l£ˆ åI$¦º7l-Nr`:Çݘ̱`î<È,WaÈÔ‹`CÚö=¶·1­Ce›ijå '~ŽÒD$¸’Ø]\+… Z“7q¡&OEà¢Ô“s¼ÔÂÕ¾)ÄÕýq˾’#+Ñ-(^n,ÒCݰSHHDéÁ§°sÿ²Úmø°Š9ß™ÍÃR—n¬pr¾ó-\PêÄ—stŠrþÊùû.ìaF …ê2÷0£+Éô7ë²A!o“ùj¯®06©[¨¢gèóè>Ð{‡¸¸DýÐéì"ýr}T…ø±P¶/pÁÆÃÝ\ÁÁü´z1u‡RƒÁ *&Ó‘Ÿ4˜~G]`÷‘.»áòÁ?ûÈ HÚsÀÐ !_äõq¯Îm÷ÑCÝRå›Ð7™æ¶\X`BÞó­BúæXz ,Å+P7›Ü@Ö©ÀK(V*DP$R ¦1ê©0KÔkJNçYã¢nÔ*°­ê¾F+Ð\¶²ÎÇ1+ QJ óq²YcÙ,ж¡†ñ8ÃAÑ€_Á™‰ªûwÇcYùÛ¨4V ×RÖì0CWÍ…œþÞ5ÇÄÜq"P¡›‚E…… а“%<#Áäÿá°dt ‹]#Ç,??÷'ŒQ]öàz¨6*(L:JB¥6&,¦ÖX¨Fªg¼æQyûvÕ ‰µñi§Ó„¶ÓmÍ>i‚kàŽƒö²¸ìÛ\%¸€P¸ jnãF™Ä!…¨“.…„Bõz誫`¾‹Z.Ã@%iâf_¤vœf°ï‰ ²#ã¡f¥zÈE *ÂæÈï›àÇ79\€ÄšÂbÆd; Ã‰• VçÉs€Ú­¦1¬HpžËšBÁpËRàÆ«ô=¸n ì L|!@ƺo]%‡ET×SQˆ‹üpq:Lõ@̃“tQ`šˆ²X(³pFaL‚ŠèlFù–oSÜ¡P S+ Wö»²i8CM% ÊL©Ò?ùŽÛ@)ÀâÝ8`I(®s|±_8–!sžïkb{¾p­™üÖ~•>ê4hI!ž¼T3dU)²£”e—Ð8!ë%¢¾ÁÚ‚-1¡ îPX$Ô~§Ñ©”z3Rß@c.*@Ï*H{㑾¦X($XYù!¨;Œä&½ë8ç¥8¡j%˜Wµ:¬ò€þ(°ÈŽQ8%kÆs4óÕcÑ · »NÙéÌ Q—å#;C•E@1â(-±’0°}ؓ̑‰RuèñRR eÒc˜Zq¢­Üe«0Hþj؈¸w5býŰ³¢(¶ êq£žêø "9 —e-2.¸{%@ wvÅ¡ŒS`XSéȤuj× ¦¨|Ìè¨|]z2“›n(G"|X}L$=ìT„|>0JgjÒX„ø±Œ,£ W¤¶3^ÜÚ&ð‚™ˆ½|ã0ÀWèJ|äò¼CÂÒqeh`PW†MØ£&¡F\W‰Ï5 eÔ8aàZã8´]Ç.Wÿ4‘œÙƒ 7{ÇKÂŒ^"ÃMÞ~k d¯†…»½¼ÁÌ-€á«B waSºx 7›d1ÅX^x²Bǯa⯠¦áª5–ˆÄ°fž¥â‰óÕrhü'ËqqÅÁ›¸È²ã%²Ü¦ ¶©+ÄÔ±Gø„¨k…Sf.Aã2®x:JÜs¾ª2ÊRP•¾B*†9,œ–3ØR †7Q ´¯$Ö4¨+Cmž€J®$V[ ›‰JûK¤é†]M25,B62K}/@ù÷Å[àpþhApH ¨GZ0\Ò#P*Zİ D£!±`ç9ë/á<‚&¾†B­õMpvMvMqv%°< UnâõñP™ˆŸ¡/±þ•yÅ̈ÍÂÔ†8Æ6¬²KÝÂ!¡¬Â A gÙ)z;sT÷K$Ø£¡±°œ%xQ€©2­‰¤° ¸%ÜÈNSƒJØ$®x å]‚Í«…ûš Y š@÷´¼óU¥o{Ì]‰Šj]Á[­t.c1UÒÝ1hwS &ÏAj?á 5œ¥.¾„J€Wb¢ìÙÜñ÷a˜ëŨXxóý9  iN‰†¹é¶U9ÔÐ0ÜÖK©ëP ±›ca îâÄ%^¢&1,,“hó”WƒKÒ •>“ë2ø™ï¢)´Ð¤×hZæ` ÃpW¼— óê:¥zöôÕ6ºÍòÊ—éìó¶Á“H8<ô̓pÁ\«º½6Écóé†}#'‹<?M áþÊ`¦áN³r,Ô:þ>ÀìZÀžʱ€‘p÷'¡€»r‰¶'pÔVMvœ@íVæ¸O9–#CªTTkôºG"wâr»üˆ»Œ¼‚à œ¦M¬4¿BÔÖ"õSá)‘ \2ŽA MÛû  EƒA±@ÝŸƒòÚ,& 8¬ÏfB‡©8.Œ½ôYeáxØlàØöd¢ÊÃ6Êt+va±â Õ‰²µ—Íñ€5P+LýY¥¢×ñ¸±¾–`É‚ˆQÅ’9t e $„o–¾Ù³'|PTœ̱P¹JõVÎ/¯’%b;£•X0 b‰‚òQJ—½—ñM1ÚÅ)$•0ØP]mŒ†³ –_T`)è^©ò˜¾g'°B8 8ÎPqŽÆšÀ<¤\Ë‘OªpáÜö\¶EBŠ©›¸ÊW…• ›@GÜ$AvÚ$A¶i°øX£…J^MÂ)©p¤y Øw :Q½è±Ÿ„Yì¹N¤e'Õ(•ÀjÅù<ØKÁKU$#Ýû¶~{c¸)l¯ªÑpJ&o@çG ÐpX÷!=_4q£x™Ù†ií;Üõ ‰CcŠX@W[ ‡\nch˜ûÞÜKaùÄ% .rE½€ŃÝÖÑÂR¸ïš„ÎìqeGˆ€×“îÂè —ÏÑï„ׯùä4}FvÒ«¨§d&Prº  déî1 .’)Ô?-Ñ,L¥ŽÆÎÿ%lÊÎ`õ —4ÍQoJ(\þu–¥nˆRN¼© ¬gSp® “ Wp~ªßCÁPûÆ8¥-¨é#ó(}Fʨj –å‡m‹½é,„XySoÀÞçÖº€ª¨1ƒEŠ1`/™‹ù–1ò¦~LqY#  bŽ5) —ãÚ–XaŒü À§LšzÜ'@I¼8t Óö¯L êU%Z¬œ(-ÍP·ù$r”$`ï‰]h“LE‰8w\¡¾ÖñUZ+± †)0œÞ/ð)×$@ê%«Ì‰-‡0¬ÊQéj ¾‚ÆŠlXiHäo¼&Ú ù bÐ ò Ñû†h‚HŠ V A–†Bí$EÍòÔN' ,®ÑpXXÓq¶¹Õ×޹³-ÁªÎFÅ ³ª—ƒ­t¸+ I9*F,vìD8°íÙ ó&u—¤(ç¨ðPñÄB ¯äXA†rµùIaoõ`¸ÁœI„Ú䥱‹z=H½;Œ»±½D+€—–h8ë&sX":ƒ µIŒjäÒ’£ÁÚé£ÞÞ“Xzq ЫK€\lS¾-@ú£9D"Ü G WÑμj œ/ñ áB‚ scè.OÂ×Qdä—†¨í¿Æ‚ù 4Dm×5Ð.wTÁá&ºÄiˆü ø`g™9Ò2h—möYSÛþšÜ’)0àÈ Ÿ ƒ ë:2Ü7}q‚ Ôž&1*œƒ¡Æ¬$ýѾF£Ð&Õ8¿tºG¥ü$âTÕj£ÆÈ O)ºâ6¤kØç>W ¸ce ©dX•‘“Šõç(eºðØ¾Ô Ãµ;΀[ݬEä§aÀÛlgé̉¥ÎªtœºG~nǖ†ª]á„.j‡—C¡*fÁC¢ŠmrHø.@“g9’敇B PÂ~€~ø‰[¨oÁc{†L ™¹‘5Î&T¤ì±/Û™qï n«ÄD¨…=†!EXQ NPé†ZЖ²èáyŽ“®.À0Š—És€Z¨$R®‡ÛÁ´4='–tÿ¾W~ä·Qþ¥sq}Ñsw³pqÂì­ E+ûKÄÁ呈Áƺ¼ìÈ£‚±%&’ßFë±úͰÔåŽñ8.¿ë´Ldü2è;ZÖ¨;8è#ýY€nNŒ¡ÕSåh3¶Q•`!ÎE'¸K^Ï °Ðö9ña‘¿ŽÎaX;¯m7L7¶Qê©3ñCЋ‚ +K@›ÔQ:)ê JÃá´'4ì{ê¨|…ts6(ôQ€Ð΃ w¤®ðjB_¾N¤J<¾Ó5”ž( P¢•j“kð&0ñv\Bš¢:Lbiq#\\± >þÅÃ%â4×^@B&XHPMAý;¬zP÷¨lv:¶Å&Y—ÃÁÀp3_c¡ŽîÓÐNÏCÉ•W/À0'yi˜EÎ2 †²lᤱ]õþC#8˜uÐOº€~Óô£._5¶a`œ©"Kœo+ð@hȧ!Óô§ Y€Á|eª¶¦ ´rº°}Ôðøwu—ýÒ9&q–þv žÙ¾*ìÈ|ç!Z¸ ìGT}Ëp×dzy˜)èQÔ „…›”Y žpb-``¸3‹ sd!±B9öa_©B-ÑfvYÞ¥A3#w‘¢jÊ 0Pù\–ßO*¬-Ýãà ¥[× PF9êdª…K*h¨ )[vü‰]ÜgùÎÖL9üqpÀWzm¨ú£ EƒÕò($ReKêÀ0†Iß– A€“u éqý¢`eÃãZu!áÆÍì`Šº¥ö ‘ç8å–Ghÿ#{«ëóˆu’HM“GléÑ#´öèy€ü\ß6JMC¡Öì·D~J¥àÕÃAVNœH™V(º)¬†©Àºpp 0 w9|áÄi8íN½ñ¿ÆÃd¶5jüK,Ô}î &ÿ¢àŸv[©Ã}LÜ,Hpò/ &· ±€b!K4Ø€)AH,¬XH ÖZœXˆƒ68pú L// (TâáôB$N‘CaŠtG0 ‰SÑȱ`“¦¢‘cí©hh8Üð‡é^äXÀ.Cé^`HË ]†ì3¤óihh,`\‹ÓÐ(À°¦Amú ”‚†“ÿ‡Ãò\ÔUa‰†Óâ(ÀPß3 a[lävX¼-Ý“`ÏlÓ£°Pv!Çë\Ìq¨ƒí(lG!Áæá#êkJ4`*M¢Á*ÆaìŠ'Ô'`“X z ™&_ĪüRCÊyÉû'W8ñ3ªléÉ-ÛqD” ×*ÂhÜ8F=s©á 5' ¼Œú(bØÊQµDDdÇsÐ*¦pÇ!j_¤ÑžSÔ!œ‚S7rg.hÑXÎБ£œÙHóÔ4|Ïv<•–n¡âAcä÷VÓøÂ † ³1êrÂA ºÚÄQYV [Cšªþ•žú…gϰ{ N®óK ؃°×^öÁ€×`<˜tV Ÿ¸Fúš*t(JTØëÊž*£Í€&ª×$±hêÿ‘£§(i†åÜ Ìpü‡Fö_¨÷×x@½?ÍmÐfj‰¶©¸Ò1ÔºâÿÊl×Ú„9þF‚‹ÅDÄ"p€:ß…CØÆh8hÏSÚÊ Òè~ T¨×Mf°:f çý[ ÎÂ4^ÞŽUxx‡¡#¨ dà5+£¬ZÜûdèÁCÛ Ûfðà6CG·Yà¡T ¸'l¶èQ®0¨¯4^ˆ*-Uh‹ØŽÀ.q.æPAR  ‡)7”;j'Œq=ªq –ÂK¼l¦zñ2Äö© Í€Iæ(NÁŠèòEÉñš˜ÿõ²÷½ñÔ‘_ï—þ›þ›«_ºîÅåEçM¾éhÂÿS»;ÖÁ \ëWÛyHc[ÇïÞY ¼ØKñ^KŒ ŸTæ?÷¹šèNôAþ×0pü0‘néC8e:|»>èÿz?$6(ŒáæÃcùM¤ï>¼åõ“Äo§ö½ðµAmÇo÷TøÛ;2üm.Á))úÒ»PH>©û…öTŒ"áxÏQŸ†Úª{é7Ã`”Ú:æñ|O)}ŒÝÛ^b•݋$›3Û¡ñ­0–•Îb-;Jšþ#î´‘¦¥e“G×ë² tº†î¿{­wÝtÒ[:(°á®+»»Gé ð Ó54¸»“™Ÿ’ìNf1 z¬HXMô0Ñè Ýñ…­jòç;à]ãøÿ.yäP‘È) y¥W头ÞHY½áŠå6КÄ6e…Þá°¼UTh€ÈË*¡Ðy®³Z=.ÐØ ;uH«^Í2›µX+lÎê!‘ŸXR̳ÔOTõŠZ·c‘$œÞ)xV“kõ|"ƒK?8e‰'ád©PÏ×é©"9ú¡î*¦¿Ò iÙ•;7¸î„L° žx“IBÚŒHdÒ?ñžä7õHÐ :¸é3*ð„ žòÀ³ qW=ÃA§}R‰žPm'G‰N‘Ÿ8(5>w\>Q¿íïÛÒ Uý°ëéË.Œ^Wð >õÜ ­kR/a‚“;æ‰g{GœOl‚õÈ£¬ 6½‹žH-PGבˆ“0°}/}¶/Vg Åñ5ˆGЂíiJ†ÆÏ]Ÿ×>/Wìó:Ú'uô ´§Êx{ú,c·jIn~À’ù/Ý7î›$Ô„õ¯ŒüÝútû«õçð~tûõËÿعôòK¿~éBµpڹ؅;¢»Wh KSK8ê‘:Þ `aK4X[s8\[#Ç·“Ä›€n×qm^AÂÚxÓ`ŒzLdkqj®í„  ÿ ÔH’ÛÐPH³€ýŽ‚J<Эg…„ê+ …ú„ i°ßQP©€Dà4ª·°‰8$`Q£TA!Íö;ʱQBì ÔW Ö>ØbèWC¸:ÈõÐA.ˆpEt`Št Ö[ñÖ>Ø’ï×|¸è;ÈUßA.ûpÝwp«¢\àºè F¹2:È¥qŒÒƒRH¨Þ’P¨öáVFàÂ\‘Ë"rU.ŠÂ"¡úJBÁ¬B½P `í{ŠPíóæ6*ªQP¨*,T™dhšEv`ï`+$` Qí  ¯BBµOBÁÚ=«$, ÖÎÖVÔ²[õq‹>pÍ.ù¸?Ò"@ $TOI(Xûâåi¬… ÕÄXØH(TÊ.\.˜Êf2‰ d˜ÆHþ‚m¬·þÂm€q‰`ž˜¦AfiI\ŽÆè5…ê+jì 2 äà€Fá: gʦ§µóÕP¨*,\AgÜ ×@Ô 7,ÿ„K?á²OiÞBá88oOpÇÛÜñöÄõ@ëŸBBµOB¡Ú'´Ö£ÐR¾(H×KÔ5,h®ð…ÅœŠT gs4¸yp⣲Ø4³ôÂDÌBßÅ6;VâÒXÈú¡ÆwIÀß% x8f‘k§×À²phQ8´$|⇨×k4ª ÕĹ B5oŽÊJ¤'®yO°ö¡2‰ Ö>Xšm2Q.U"ÁÚº¨öŰ-”†Bµ0Æm£¦öåa4¨‰ ÔÄÙs‚Öi j¢Æ5ÑóÃéj¢Æ5ñ;(õ•‰úŽJC}¥1¾£rßQ Œï Õï;jíûŽZùÔ¶ ´2h(Pû4ª‰À¥!Dz@±º\i 0¬mÐOàÃlócØs»9êh0T§ùÀ­~†k§BC5W›ˆ,MDV&*,”›UPÀ&ÂÜl8B)$\Q‡P°ÚR\ˆ Œp.®tW9‹\0ër¹@®ÐŹVÌít&bPËÕ($ ¨³TeU+¬ `EG°ãñ3lZ¯àP ]âÁšû”ÚØ;Ý+8Xs <`sÓpa£^c_㜂Z… T¬¡@íÔX¸&€pÍ5.sÛ \Ô]ÁºÂÃ5÷¯,Dbá*ÁP­„­/À¨4cFdȈŒÇöAû- j¢ÆB6ÑÅz´™¨˜O£!Û m&¬•Þ4˜Ú…GÉH*4oâ96j¢—Q½·F„u!j”xì¦fŽë³wŸw½ w» x¹ x· wµ w³ x± x¯ v­ w« w© x§ x¥ w£+ž™¦ÈSÎy,©õÃP¨6*,PŸA)…gT>á•LxU›<£ªMžQÕ&Ï ÇùŒò›Ï•n¥&Î*ìQ:‹…í6Ôb/ð¬Û¯êýFçaâù˜ò2p?Ó°³€­Û4dÂÁÄ1+PÇAhÉ>°S/ÄÌ…öÄAåNÖaü€EœQ»@N4Dz} .¬8•»/“űR%ª§¨òø—(@;¾5E"ø»v ·lBlT‚\6† #\ö±¦*L,b¤\;ÚÌbŰÔýÄ ‹¬8ÌR/(9¹Þ›Dºeõ”nêÍWw÷·¾ý6“$\Ù†$ŽÊ¹p¾‡ºåÙ¾÷oaɉé•"vtSij¥Ds@—ÄvðçY*ž,W$ibžëØC¡ºŒ‰¯Æ¿ˆˆ˜y`Dd°Ó46ð­5 ù{kåFž#Ò̇„¼znα%‡Ïñæ[$ò³OÊg·Pª…vêÔUpðFUA»¼9XPHOb†eÓY˜.« `¶"a Y`d²ïÐÈ韤aLг`á­ÛÐ!OŽn© $°ù‹ØK:FW6£+Iá!_"@G¤kDoj;øü#>å°°Ñë†KPÈíÍ^b®T¼€¿ë&<Hw÷%‚íø¦9íÀtC Dx‚’ž„')9j´ƒ˜$Ï “²% )NJžûa0ý>‡º_Ä®µð”åýÙ+3 MAñùOtö3²3¬c#$S#tœ¶\…ìT{#0'[³?©=ÑbOÏVP¶½¦/±¿Hƒ‹ê·Y\IäÌàÑó6Í4³c7ñþM%ñ‚™QfâÌiäæ<š ²ãªšL4Kè{u4'NˆÍîÈ]…* l×…F³•$ÔŒNÕm€'fÜVbÄm%fÜVbÂm%†ÜVbÄm%fÜVÂv[ Ûm%&ÜVBv[c;Ž=A¹–,ç¸ÄGç»¶ðÙ¡i™F.VQ2³ã²3Á9à2ù£,ÇðNkpLÛg @ä0 ‰CÛuìd#/ßå0š°3hÁ Xâ“Ìߢ`Û58ÉpuÊöi¦ð$ãU­’»éRÁö¯HM ZO4œ½Ò¬8ä2ãl4ã™2 Óû/iX ÙŠ 1ÑYä¥^T·DÎ÷r dñWº´ üÄ0üì"=±¨Ôh  9ýºïy¥7gƒ©¢LÏV2‘$A`ÏÅFuPË =;I*^±uûܲà2º+|ABG½Ü^k…J?ÍÊÿIRö8ž¼XWNÛDU\•T`Ã~›bcr¡\'­ô{“@Å<±:Âó½`Êj+äá—o¢'FzHo1¸ !Ôȳ+äÔÇï’ÈIñ ‹)QÅh­™Â4tÊÚTÞ¦`ƒ'ÇYBóî›,<¿äA_”àßø¨¼ïadÖqÈk&þ¬án¥7x ÌšÄЬ!\/b].â_Å!_Ä¡_ÃÙ¾£¢!3,ø ,&.™¸ND¿LD¿J´IÀŽK,Ür“ˆ¸t”ˆ¸Å@ü°IDì´Døå›\v¶–^O¥&ô8­”jÅÀ zJ8aflé…Y+¡“Æ(3#œxÓ¹P! ýW&²Ò¨ìtPБ0W6ÏZ48kå×àÄÄ—ÆçEFê…l^ÕŽÕÈÖz‚r÷²ß‰èÏžð± 8ár¿ˆªŸž‡ ìÍ›X8˜ç×Kx“8„®V sž@•Ç1ÇkÜ)P‚_W°rçðhûÜ\ô2¡0Ñ7âf&p;+*Ñ@ÀrO€• —@.…Š·«Œ ðà“?pSÌ{$KD†xƒ%Ü%–¨ðOþœ¤êñSÇ•+'´7áBè^Tx¶¬h_8sÞ¢¼Iâ¿IÂ77o:BS'Éû÷_•¶­•¨7 J°MºCcba³ÉDÄ |-I 'á˜Î³9GŽžåŽ=I¤³Ô@„3$³,uÃE„~ÿíÓè±#c9O•öÌE: ‘–ð"p,×Ní ä_:n3p–щˆå@‡Ãïï-?”{ºÑè“%£]/˜&@ø¯¿þOkœ;vfù°ô"U†wÃÏZkJ7a4n¿~aÀ½H¡Ý;Ÿ×…úîöî÷á½Ú69±å!ƒ@n dKRä@ÝB‡Ð-l•bæ¡K/‘:þëç;ËvÕ%„yË Ü­˜TCv™àß{IÅø"ßþ•÷W¾–½{KÂ/–xºcûþØv,'‘ñÏ &$x{JŽþA<388¦O|%¬Vt=|T*‚X0¤žV"N­BÛŽC°ñ–ï%Èж‚D7Æ“HTxuœBWÛõ6ë‰Â &áj“8þÊ<ùß„Í@™De÷ÂŒ5˜ä’éMžÙU°¸"Jg\Šyè2&·Þ&ËJÎOÎ j,æá£ ®— YíŸ>iÅ ü—¡è-IB宅ÞQ‰Ž"Í1izÇ**QàÜ0cEÀ÷Üš*OZ™ÄDÌ”˜ˆ™¶ID0ÕoòpˆÂðÁÒ‡J@†6WDˡƢqÅÄÎüTNÊ$Y¸y¬,1)Î-ÙéŒäш{¾\C’V/3±ãvÅ1O¦l õP¥oñ¨Ê\áÝΚ*±lWµÔKqEÉÃÊÕq;Q1É6SGºˆ†‚Nß'*’õÌTGk©~(ƒC”ø¬LkÁÀÛòjt?Q3Fº~+‰ÓˆÅ2,wÆ·ŠE8fxâĦÓÄ-Ì×`*8-Á¡Æê]ž-þHIoXoG_:|–üÁ Ëýè-½¿68˜]¶IDì5µsQWô-6³ÇÊ4ÎÌöC½Æ¤QÁçʨKÝ“šyÚOÇâŒó—%ôT¤V$Ô“<,üÕÑ)~‡Rfáì¶¶XG$ej/åÏùRáñaâ’ŸŠ_"G1oöjlk‚Žj—ð:wJÛa”XÈ3,áŽNÞ&fù”X¬¡°]/.’âÙø»pÒÄRi‘¿Pdj 6Äæ+UñUT²ñ-UFO!Q÷–™(á3áØÎLÈ =1˜u@ì õ":ÐÂ×l稬zmŽÿtnhÍìÀMfözq3ôÒ-I‡kâ) åÜ–CWMë¹Ʊg£ûš°ÑÛ]’¢ck]Jþb¦žìô°žªHŒSÑ¡bëbçI@æ%¦Ôóê5:ú^9¨ ´vȲ L‚uí2‘Eú; q,Om9¼ÞÜÇqÈøœMS Ùú×àâÆ}ûz?Ô‰)Ï%8PfîCÁO¾ØRFÉŒáæ©Gâ _eäŠÒ˜™¾¬Êcà9~MAüE ŽÓ§ÅA÷2·K†g¤ŽéµÐº,s¬¤ð°ú%¹™V#ÁƒS\M^P"\}|­âL©CΣJ/„6Á­\4ÀÀ Br?b4HœFå1C1]n«(—ãø·È7¸·Jè2ú–á+Ÿ4£ç¾€ûß™¨L‡3S)ZÎJ‚Åvü\¨a¡ÕM–õn“°th½Ã!\ªWø“9<¢I$ŸMñqŠÜN/sT™¢uº+Æ~j²2v #Ëeæûùþ‡™ f.Gð.FÐ/E$ÌÌNBÉì$´”…‘Û!e’D81ã~s™#õœí?™ Y“Ãý´<Œ'­²Ü«9ük9&®ä¸ŽÃºŠC»†C¾‚S‚§äÖJªŠå\sŸ·ÁfﯩW³ø×²øW²Ø×±Œ\Å2r ‹{ËÀõ+·¡LÜ„âs¨ÊU ÿrÝzaÃû PÜFb>v{4yãž…ËR ÖðÜNaÁ2»„;Nz$ì›d2«»s…mžîøŸÌíÞä\âÓ€¹ÃíÎ%©ÔsEêuM#\Sàv=’ªºZnê'x,’£ÂoRæ°Å«s‘$öou~k¬¨L·‚ y2Z0€ï•P­X8aì}DàÐ>i&|yBZ€Ã¯¾¸Øëi9(ïCï%‘*‚ÊowâáCÒœwÃlì Z·Èe Ž ¾ÿ–ƒê›4Nb©Ã1ÂD\_•¢@³|k ›Ù3ú9^uŸ Œ±åþkŠÜÏR YsG]¨%NMù=ãt,l<²—h£cu%Í‹¡åm9ª˜ÈlT;÷kžfp\lufŽ)GD”¥œ;J9C‡ŽR â“ü¥çZu_‚žØžO}±ÈÄÿRÁæ{ÝaÉÆv̽´ …»tÃT2Ö2¢^åÜHƒÇBº|èaj™H:N¹^å{ê‘zÏZÜ>±Ëó ž¥CÍG%‚ŸG—(×KèzŸÃ\Ò—o–Âph–elì±Uð¸!T™}—€³-3§=&Ô&À©çA*Áè4ŒHЯö¯¡çïÚQ”ßáç!Å#‹`l¯ËzÛRßYgžïjÑ<¹€Ú¾ÕE8zÏô€tœ9®ÎÚY:гßåMtÞa…«rеW÷;ƒ»YÁJLj½ÿ_F¦u†Ä†WV­Ág!¼«E+£Ñ°òÓ¥öXí×íG¹W²ÇÐ├"ôÌÉ­®´ oµjš¹s6!ùªäÁ‹T_LÂ,@ÆÂ<¦ÔOúhûž«vqjáÇ~Iô¤ TÑwOŽäÈÈeõÀV« ø²R ‡,'þØ¡UÒ¥ÛÃ!æ°ø£¦—w*”ãSÒþÛÐ2ÂT9ç1'²9A2$Ç_`/@3z§ƒï³¯Aá‘},YB¥XÌqQ4]Ü|ïùå²sÙ\ÚƒR¼5§geÀÎýtŠ€€Ë]¹õ£/!Ñ\¼Ýט«Ëâ*[I.HHA?æGê›ùÈ!iq‹ÒöH1#"ˆËä°ì(‹ÒÁ±H³8€ ÙjìåÇø³ ö q_Ëá7 ](ëSw¾!gkÜ+“p°êy™Ið±“?rwø9¶ëMEB¨úZu»O’EJøz®]¢ÒÊG¶‹w¶½—Óc³|Sº P?ºvàÊ1Ue„3dx™‡–Y2j$ ô0L%4ì½´Eít¯./aËMjE:h&¤-{Œ]p;PÂy¤Æ ~Œ0¶î=ÎÂݺ÷H[wrÒ¹·\’ôPn±N·)=Þu‡=äñ­HЇ9ÐY@'„¾=|j¦§<”íë#¸ "Ó?½â<Ÿ`ÍG¿J.Íí$U“FkŽáYŠªsËeðѽ‚‡W¡nÀó ‘×4”8‹‚Û8õ£¥Øg‹ø¤ÊÐ +^WØlÛñÿ+hõ^­TºÄBPq^¡K÷{#ðƒ+j÷6 ¸Ê{ž2ÕÉÎj†1Vzøñ±¬¡G½ö¥ ðÇ=Î1¿ƒQ‹Á+Å(á¢Ht&*P ae‘KðR±ð…ˆ¢wÐbEi ‰ƒñrÄ6tž'DèË4”íüêúiÏ`àza‰‡ž˜à_.Ü¡a†™Ô«…kVN½X¸f`Þ+,³°¢eþ­ÅF8˼³¸CÀui«Áá¦Ì㘞 äÌ@€SQѳ²À]ò¶WV­œ¦ mPª…‰ÅÂKhÊƲÝ庸\^Öö‡*¶üa2ÉòÙR{r?jª÷Êl´Þ+“{ol»xaF ¬f¡•†¤×³…ÞI¸ò-Œ,þÜ'ÇõN7À³W¬tçFõLyYÂŽ}ð–`?™I .ºs(hâÇØ޳Qî„fÊg®ÊìŠGø,ËÁÕ£Ks¶r9Ê‚%E”²š EA•wÆ?|µÆ/Z}žr ?³“\îRA\XTEÈ:í‚}ßJáëõ®3eÓ¡'ìªø)Û±/Î4T¶úÈá_ &3ûaY%A (JУX<á‹´Á*ÝI¦ˆ°Ê+ o0°õI!ov寄3Nõ¬œAQ—ˆT¡¯±½å.%Ú¥!îr2s;Ì]>bÚeJ(ùLŒŒ‚ˆÞ}’Ç·¡C0´Z7h›Ð58~Ǹ¼œ¦êоQ¿¸+ŠCƾTgT½@èW`åÆa’NŠ_¿×4t‚ÇÐã±èÓÿ¼¸ ]ÜA²};ž3>tO)QrÝ"†…:†5°*E“¡“Šð‘slM ÁeüM³_ÂC7 ù‹%ŒÛù#Ì‹w9íâ]ñ, óâå]òCùƒŽåd2H;Øn€^¢v—pxèòIÝ\U‡¹ê9X‚&Eþfï&ãMâmò} Ú3 ùkø^ÆÆŽôW6Ôò†_:Wðð¢¥î4©Ðâ åcú%¸œëQ²¼í$÷aq¥’áðÿõ²MW$©ëü·ÿ¦x.ß\¼éô4×ÿ9ª) Ñúß_:–å<=Ùcï±Ó¹´¤ÎòÕò‚Iøþbøø?þÇ»ýëí¯·VçM¯É‡9Œ°cš°Ë%¼²,;Žígs}ZÁHîÔ F~¯:¾­œ“Á^Ýfä÷ê6#¿W£±*$7Ù«ÛŒü^Ýf$÷êd ½@ÅYÆúµ’“ܳ•œÜ¾íÊ¿^¦ƒŒuîRnïî!åwoâö´{HùÝ[AJîÞŽe=Î÷ïVrïa%÷pOÏמ‹ •»tc}¼——ÜË{yÉý\öý¡5êñ8s½ý ;¹Ï_açôü4Ȭ ŒçõI…¡+,×ôgaø0¼]XÿãüöéöWÉlõÞôé´ÉÂŽ†÷’vÔ1Ë|™ºÉFY¯b¡R Â0íµ~Ðp"bý…]ÝÉÙ]1Φ2¤Ù9ŽS•- cmB§k}βTÖe;V:¨²z|? ƒJñÁ©XÔj|PeQËñA¥IíÆU&µTZÂŽºW–ª«ÇcRϽ@9uYÛ1üÜnÍ{™'in?/†ÃÎ…ÎÂ&i>o·›.Ù¤Uùgu³Ø³}ïß;Á“ùRg¤ßöæyõ¯ÜðÏMÓë •ýÜ{§¯ÝÙýÚwÑo5ü’ȼLÀ¦3-»ç¹&{½Å‘Þi{¤w;둾ìýñ<¼£öÿÍ*Ñ^|øí¤7‹N¥ékcŒñõñ•Ê`õ¯•Æ‹z¸HnFFéÍê_ÝÝ=~/d¯ZÓÑÖd‘c'©2çºûøxÿEþog`ÿ\ ÌÌO‡'`Ûz¥Õˆ®6•²Â×=£J³±õàîªÏF=k4°òž““«øAK]×Í™zœÍв±ï9V;C_Ú©íu-¶E[¥Û-ûmkëJ°•Izxq-©*¼VǾ^²úç<˜=À„ŠîP%(»7dwQuõ´2PöÑê_;©ºÆxÛ=´õ§†¹ÿìöŸ{LÞñ^U&oû³Žög}ktiå-1ëϪ›ò¢KÛó)ÈnnO¥ôi“=6ÿ¥º-§8R^®¸x£k¨ÌêYïÕŸ´æÉTmÒÐE#ØsgÇö\¨¿îKÛ¢XvüÞÂ_…cN›Fu/VFÉM•{‘Z´rÓŒÛÕ[Ù²cÕ?æ»f°2Aî0½`ÚŠWËâ2ûÉòE0M·ËY1Ë×ìP{O¡þ¾bòãµÎj£Ï«Ù<Ä5a;ÐÏÞÚ±ÞSfÅh\•¦Ù*W­;Áõ’ï*šTç›Ã``žßdã»z]ôÕNûÜlçïò·j€~]«U L€žfŸxq[# Â€v-hc l™`üä:Í~è(ÏLX ^dWA.%_¬ÄóùvH`À ï±ÂdG\®=A¶4«mh݈6&宦?ÆUÉ-´6"öѾmŒ‰ 3 ®½}2Æfì‰`ûì•MÙ·îE¤oy‰ôÇöƒhÕ‚Dþó8aô<¼3=Óú®Ú¦›:ÉSˆ†§Òš¶ ÞÜWNlº—ãüG²[¬ÂæŒÅÔ L“:*‹fšTÌ£t»ŠN·ã$J¼­·à& fÃב¤QB.y£*ûמyˆçHeÙoBª*ÓâÚ©qœQ˜˜æì8Y[Éó|^fØGê†Ö4³HÝf4F:‰mG½f륉1R95onûùýdƒ´¡ÕÂV´-Œážlªzê=)e¹¨¦•MõZ Mga–Ø›X g;TIÛWò3-ø ÅÛÆÌ½Tz­LÞË|ò¶0¢/óùÛ VÌ­Œëk£ëP§…È¢ÓBdÑi#²è´YtÚˆ,:íDv"‹N;‘E§È¢ÓNdÑi'²è´YtZŠ,:­EÖ"‹Nk‘E§µÈ¢c4²X´³X´³X´‘³X´‘³X´‘³X´“³X´“³X´“³X´“³X´“³X´“³X´”³X´”³X´–³X´–³X´–³X´–³X˜ÎY,ZÈY,ZÈY,ÚÈY,ÚÈY,ÚÈY,ÚÉY,ÚÉY,ÚÉY,ÚÉY,ÚÉY,ÚÉY,ZÊY,ZÊY,ZËY,ZËY,ZËY,ZËY,Œä,B3u#kšËˆvƒ5Uj½©7EÒ'WD´çV4_º|JÑX5¯«ÞsËi“áAbõŒßè?'–=ÇâÑ“wM‘kyrÝÝm4]¿5%çm:k¥ñª;ÊRuÝEÞ}즔*º-Ö«âs›jåõr"›"¼Y}T3Œ‹JgE"©æÝvVƈ·g¬â}ÎÊù~ge„}¿³2A¿rV %ucÆY-6œ•‰Vn8+„›ÎŠÃè‡SÏÙ_ú ¢éZêQ/›W­3^b…‘ úÝUT*#_j`ÚSEèâÉúåjzoÝêqcg[¡Æ’{uˀʇ×ÚÊ`nv ßÓ~|D]è]P5 ~#õ^1ÖÞ üD-©Ãø©‚P+Â6Mˆe«0½nö‹înËçÂÏžr5màw‚i·w¿é`Üñ„-Ï„ù }„CmàwBK3áE~ÓÁüL(.ŸÊ þ4ŒŸ;â¯Ì{´}¹ä©{ò7V=Ò=Ηlð´ƒ­+²f ÙC—Õk½ÿ³¢4îô6þ¶«WµKF]YVcóÝêiTÌ㨯Ûâ<~]X‡íðç1)ƒ7Ÿ’«-¥cìO#ŽΡüQ»ü1¶‡V hù DÛŸ@?’Ü¢—S‘ú¡cÈ‚ª•Ñä,¬ä78*£#“³°Ú€–¿€ÑYXi€ÉYX 12 ½`ºÇŒlå z$I¸ ö?àF³áºlÃþý»+j™ÁÜ:Ur"Ÿå…×~xýq³Nd¶:@êÙa¼GZ"õì0Ð#ቌ‘í0Þ#í‘í öHOîrû3;™ÝÞ¿ønÈÐñ‡£Kk+ qA0"ÑT]:Õ«­íóMÈÛš°y„¢–ƒÏ€Ô[§C¥yµ•=.=uÀ XÍw±Ý(Pò‘?:ŽJWªBà U)úáBÄÃ;‡S:YÍf‚)‹"ƒíÊÙ¸L=ë³µð\X^àÑ×|}ÉØrÜ/Ì^ËžÔíSµÿr¹»£vçšJs£®àèN,Zåp›UâsˆD‹|à'Ž-Gc2Lï>.(onñ­ÜÕ‚S+ '1)w¬07)w¨MNÊrÓr›¿zR. Ì„mK6'åÂä¤Ü6Åä¤ô}É©³:†^=Ä Ù7•ÈaþdZõ´aÛA¢nuæY"v×vÕÎkMi su2ÑÓ•ùOx%»ÓXûnL~¸Åö4$íœ77¦áÂÈ7\ìLC•ý NÃÅî4äwîrò™®ÌÂÒ4ä·ïÆÄ‡ ²¹5©>¿ñVu_–—ŠX=Y^Y†™gËÅ“ü'N*c™ôöûP}åÿw?J¯½0Q¦Å½¾;}+ÿNþ¿Zêï¿r3üŸ£óŸ£éÏÑŒ§Ÿ£Ï?f3.K͘ø¡iã!Êc›Ð“?9Èè;Ê6–lôø´Ùým? Í“Ðæï? Íþh3eçD¶™qfʶùé´ùùtlV)Öqý®c÷ -áuÌ>¡U¼ŽÙ'´×1û„Öò:fŸÐr^ÇìZÑë˜}B‹z³Oh]¯cö -íu̦®î‹}fW]„=Ýá¤-®Ì'œ´Å•ù„Ó²¸*Ÿ „ NoÆ–OX·æM®Ì'œ–ÑUÑþ‚£,¤¨û¨Ñ)À>jh °—죥û¨)À¾ G—ù„Åf>A­‹§´$î ìOËWï3ò„Üõ>OÈcï3ñ„œö>OÈoï3ñ„\÷>OÈ{ï3‘áÀ¯Ç¶k9v’ö3{瑆ɲ WÛó³XT‘¨æ"Iì©P™™Îõ¦¤»êg¥͸‚Qæí^”x'q8Ï™)ºáe^]Æêyž&öõcæŠH½í]¨q·ÁÉyŸ¥L;pü0CFXR¦Y*™ù~Jw¯…O¨4ûMtçbïÜá¹)²Eíx…EÙ+´×xóþb'Û_,Ìø‹Å–¿hï˶âIlO"·( œTEJÕ]gpYªî;liœ ÚÓlJÎvbû‰!ºž+onûVªc(>_: ³ÄÜÄJDÄçS“Òp¥ÙV^› ׯ&©I°0êOFýɬ?Yö' ÃþdaÞŸ,Ìû“…1²0æOt’zsqŒxï…«^ cWpÞá>Ú°NÎZʾC.ëÜuSFR±±ýê÷?²ýÏBîIDû•ñ !\ûùG´_½ßtªsSe¬y¤3íÐ~ÀÞ-KI/½l‚Ü;Ï_lÇIµ¡˜¡?ð ”?Ci(ywª*ê‡ùEê凞ÝNé[¹P¸¦ýFCẶ޺ß@}ódBáºm8ÁP¸f^ …?Η8ÍP¸^#‡Â‹jÌi…ÂGØþƒF § Ãô-òmÞèWÆÍ¼©oCмˆÎ·r)÷kìo2õ¤ztÿ¥š¥¶oDZý|;öïßœ3§U)lû~è0K…%Kâ9–ìµÊ™Õ¹OŽˆR/ V+_âïÉNh…W„“VxS6š^âí«Bñvˆ=¿âi¶2´±+Z+Ì ÏÁá_a¾ ¤¿ CŠ;~…û*vuØF;wmð’ WJ¬UK±ÉÅ¢ŠßÄbQÉk`±¨ä5°XTñY,ª‰ ,•Ä&‹*b3‹E%³‘Å¢Šy¹X,Zà6µXTq›X,ªxY‹Åj1àÝ>¼™‡x>ª0oƒ¼ý4¾ü&媪µ¥AÆ?§ÝŒc„£ÍÞTiÿ¡z¼–éäN¯[qª>§Q;NÈçÔkG Ÿ£®ûu-Úý>M8©™PÏýœj矊':þTgÃf‡t låIudéìá´ûr¯¡'Õ7+qÁõñ¤{vÃæN[6w²·1ŵv¾«EL»GCþ0Ýº×æ“êÙ¼Â)wò„ùÒÜÜbfJqEr9aÆJ,¥Ï‘]: åNÄRºvê̆wGÖÝÝ#ã¿cG3f‘’ð’”_” ÎÓ“=ö;+ù×¾$ÖêÏï(o– ê[–—ä—•Elqn—èšn¢®ÝzaÀà“SÀ¾ë(}x5Ì›dt—ht—dô{Vo¼çX¼ Žkl,ˆccÁ ÖØXpÆÆ šLr3þVURY3ϱüÈwjÉíà?Çá6t[²á³å ûÁ’ÿ’p ù ÷Hé±É!sÒἕÖ,1Òg+fèl¼ÈÝÓ­žµ ]"?þ—Ëš™ŠTà¨"xKªrЮ%£Åk³}T×NÍj;/[¶SuØ eòÐÞ¨ ê~‘;íËΞ†óù~?âE%{"¤êJIº¶ô'& {"0ì=ûÖ½ˆôÉ‹+¤ Ÿ‡ÆÝgÉ/‰”`‹&Äb¢f^[AÒ»vj·Aßâ"– ÞJDªãÑÊ4$òOØcŸP­óª Ý‹òg°¹ÚSQ‘¹ù¥×%[r¹úÁ4Yvà®;fÓ+¾éš— 2ü¡®ô{Pö8wV†#mVFöàð—F*mÀ Sb¡ÊÚæsó>;6¿X& ;Þ˸Ô$ë`,¦^`¶¥ÇWw ÍrÊÈ_.þ¯í_òíËÉfx¿RØ67:û/í(R“peú@ÚVš+]œÙ™¿AÜÎ'–ÿþÒ ¼Ô³}ïß"¶|/Qº˜›Ë§cȳ[ÐK;I¼i`~˜¯h òœ·…a^"6=ÌsêSæ¹5†‡y~Š|èúv=UËæSîÏVLcˆÊkv~/‰Í;µ fÃ^mÉmxàÇ-ìT.c¡¥Ìvð’Ôhÿ^采¢çüPÂp f›Ül³uRôÎxo«T¤Ùá¬Xçá£hí—É 6»8é9|“ýeÔ·Ö‡™7F}{}k ¯·GhøDø(zùú2ê›8˜NVa£þ¿·ñ$öAõí6²,í››Þrl2·ã7ææ·ÛÜf7%vããLîx oT þ2Y·Øj0=XÛ&7Ûìy–æç~f;<Ê’™5¶³yUÙùÑ|aaNkþh5¯„nƒÓ¬³\ršÄkÖ6:yOܲk ?x‘Ö´P­K)Å‘ïö°àl8üfÉ=X ¢öÑšý²öœ|Ðy·¿Þmɯw[ðëÝüz·¿ÞmϯwOʯw[ñë†ïþ¼ëžº_ï¶ê×»-úuʳ—ø ={dº(E2wã’ó4²lÒ£í=™ÍcDŸL'Éh|8IÎÓNÒ|g»*Y ¹(çJE¢R]†ÂŽ÷€® ”[lë»ï/(¨”þ§¬kÞ†ÐßÝãpx?òî¿mE©ˆw(¶¨ÆÆ˜\cLÂÓÄÓwcL¾1¦¹1¦ÔÓ“1¦g&“»¼s|¼£["ÃÇ èûÖÖÆšü´`V½~$£˜ÌëËžw9¸Ÿ<ÃæA";c*ãñþ$ “[%5kES+%ŒÖ‚Î-åSGêÅQ/&0¥Â÷§”.ËÒȼô¦A‹áæÂ`—Àif{¼.ydvÉ#ÞìDiü¬NGÞ˜Ð-~—„%G¸ï‚ãÍÊè„…ã*ÊR]š@À¾V>> 礞i5wàQr^«¹’;ð(¹’;ð8¹%‡ôA:Ÿ‘EøhøZ@utÁ¤yå±µQEÞÞ´ì÷xåÒ—°)X— —BÎa'XBˆ¥`ᢺ9,a…T°ø3 —pÏaSìöjqw|,&~–Ì‹[¨·©‘©]ñ’Ž¿+õ®˜!*±—ʨø#!,ËÛ©ߥÂS¢»8#È •²ó»–¤óï>êó§’Z.Íиfh„ß ÍÜ Í“šg"M«‰‚’([M„”DAHI„œ¥„³†øù&;d$ –àäDÁЦD&ÿHú0íM7ÉŽÏ(T|š@¡â³ Ÿ$P¨øBŧ*!¨”¨øBÅç*>= PñÙ…ŠO$»/w¨×ôÔû2t®.™‹ûG²ýÞµ-\Iòdç¥çÕ×3œQ"WÜ>¾r¹¾1#KÛB¨¢®°Eµœp‰£‚I6‹ÁSñ >9˜T?[áàW†„ó8EBz‚"©|h‚ã7*”`SñŽHL<‘˜y"1ôÔCbìA‡Äð³ I;3DKéÚòC jSÖ»ÝÁ½V>œ@òM¤’å3øIB{ë ¡½hø<€Ûe§LÞ ÉZ🩕À‰¦3žhßDgv|å}I‡r_rÅɈÊ×’ú\pʧX‰ãSÒ3^Ð×§ ¤BEŸñ­ÔvÏÝ­ÉF×1¬íŽa~™9gŽ—ÐÓ¤$ϘåexÊ4_ Î3úž&+ŸðÄã×ЄYk±;;ã´ÝÛ¦`4!u'õIº=Yk¤Sû¾Lo¡¢ÁËM×хµJ}Ä£ë[DqòÇXA9 8Æ‚ «mgõªm†z“qTQßý§`ˆÁH´¶q”²¬þMÇgν9)&Ü"`D…e5pÎ7`i~'eqmgËxÐ*¿MÁhQ¥;)iq>®–¾æ•äð¼Ü{®ñÌÄ&¸„˜1XVÐÌ^Ù³ÊUQ¢;%aM¥„Ì‚ÔziÖâ}‹Ø:µ§Ð,].KNÒ!’t¹ÞªKöV]¢·ê²¼U—ç­ºtoµG°™ì­ºToŨãOY6ã­ºF¼U×€·¢\ãH(×8­tLˆ/s=c‚[Ú'ZLšÒ’ŽÐ;âDË ¬ÍÅ„ ßrŸb0é[J:|ï¤ é2³¹¾¦ÔéX#K:ÍybyAUuÚ5’¬»" ³ªûëX¶d›¨¥!µ&~h§jL¬/hÝ9”®Û®•>GÂãÈún20Üö&Ã…KGÁëÏ0°}ùÁªÆBòÈm–hfÓYœ }:‹ëM½ÊÙe™Æv4£³øáBÄt–(ö~EYàðY’H%PÙ,Yñ¿Ëåq(Ëe9Îï’öäÿpÜØš#OšàÀ_TÜ!1Ðz3º¾G×Ä÷èò¿G—ÿ=XÁP‰ •HÁÐ< Äs²^ËÕ;óS+²ÓTÄ•AyÈ©/ª¬no®XNx¼æ½^î8ûM¤Wä[çÓøb8ìöµ Êrãf­ÿÀðNn,?tl_Xy7|ÇŽQÊV‘ã÷ÚûØå¿¸¶Ja9¶3Å0f†!¢n«½Ý=Þî"b¹ü]"’çß%b.+¢Î)úªN«¾ªóš¯ê™=S¾ªÓª¯ê¼æ«Ìõ¶_Õ1å«:¦|ULj¯Zœb\µh5®Z¼W-Œ¬ô SqÕ¢Õ¸jñZ\e´·ù¾ja*®Z˜Š«¦âªÅ)ÆU‹VãªÅkqÕÂÈJ¿0W-Z«¯ÅUF{Ûˆ¯2W-LÅU j\8®Xs\Nb!þ-Ê—4:ÓïÉÖÓjò_#ÌC/a¹MJî=07Þ,úÀcMÖž£Ù9úŽe¥Þ\¬a··G¬þ]ÅÚ·ÆdQA-ÿéUéŸ.Ó”f—Þ‹Á¡‚ºÍþåÄ [,$¿³ÍÂñ=Û,üÏâ¤üÏ¢=ÿ³xÁÿ,ø#waÄÿ,Úó?‹ü™þ5àFüψÿYÐüϦ Wü5¼ÿèl_eÇ܃}‰Û°EAµ0Ò° 6|Ãüpê9–ˆã0fÝÝb!ÝëÚdaMÖ2i¦–)HÓ4¶ƒ© ô2 XX½LÁùè]ËÊŸ5™x¾ Ú»†ë.O_ýïöcåK)\a$´ØáNFÿH{ò8FútàøJ:ÜÕåS2i@ªË¬`‹²4`U³nÓ]©W&ÃÉÄÀ;“»ä×ÉsbåöÚºýj}¸ÕWºè™¼ývI$îÐçŸÜÊK˜ebâÃß$³p1·ƒg3ó5ß—Fé,¶«”OēŨïðvÛá5´„‘b—nq/ä9°ç˯ÇÙãî0uM1‘â˜Ò@ئ11ÆÂÂØ@ ¥vhL ZÒ¡ë†sÛ ØÛ™MÚ~fƒ†õý78H¿xéƒýU6hx_¥LÃú*¤¯f©N,½£%~• ÞW)Ó°¾Ê髬ΥÇÙ„V×±Á¬ìØ$JD*ÿ‡µE-S)ùcÕ,ÎMÈMª½{S#»´S¢0‘ÛÓþDþï­ÊõÏljp´R3›Ö²=ê1$[½ZI9“Ù¡’Ã+‹Ô㜽é_ø(â‰.OÖnQÝDJ sb{¾®,p‹vÑýŽŠÒ?Ü=Îå?RÞ¾®àûhÓGïÎý.ÍÌíËÏc‚È1E43DÄÿ<]Ãs¨kfÑtvi Ì¡®©9Ô55‡º¦æP—?‡X»… »VN%yNR1ß³ßéÖmÓlw‰f»Ç`4=%ˆ&ž¥^FØ gˆm‘pÆXo}\ ò­³[Ñ3\½÷+ÿÀDÄ·pˆê9àüÝUKÇå­õÇåúì–-Q¯¤"ž{ê•0K£,m˘nW?:ÈÝYj¥¡¹J›ÆöII‡C,*(/ÈÍYŽâ¶zéj¹3W_ìDŒÚ_Ò¦=*_ù²Ao:=s6ÑJW 'V³ÂîÉ G?«^æuÍíØÁÍbbµÒç0˜Å?Xp¥cñ°›sÝÈx¶d\« áC l7M|€•Ü ëó®‡XÀ­~:Än>ø Hwsanm¯ÃÛ/¾ÊÜZo›ÙY.¶™­ì,+ÍhcgYiH+;ËJKÚÚYV³g¹hiÄ´½³¬´©íe•Qmî,÷ÛÓÞβÒ&S;Ë*rs;ËJöv–Uv¬v–m9”ÕβEŠe[œÌβҸSÚYî5ð¤v–UV®w–ßÛ1 ´³lË£;ËJ Œî,«,0³³¬dnm¯cfgYÉÜZo“w–ùùûéœh¼jO qç 6ý^`¿òŠ+•-ñçÅ‚'2<ŠK§36Èú%æî)}—î©}—Ö<*yýz‰¹µ±hfý:™¼É«ö´7ZJ]¼ÀnrýÚCŸÎðhuýja‡ñs[ë×cNì»´æQͬ_-ì¿^b¦ö¶÷sçÂú¬ÎibÛIoï‡ÃûQ׺ÿ¶¥ÔvÓŽ=ãÓ2Ç=-sÄi™39-s¾Ÿ–9þi™3?-sÒÓ2çé´ÌynÝœÞT¤Ü#¯CØ-ÒßË1Èÿìê6‘üÓÊ}ÂæFµÚUm’·Fõ#u Ú¹’DkozÒË"^"¨ãÔéžÃÔVM2¡Ãxˆ5©ðýikŸ' Zœ•—Þ4c±U®ˆÒ®e@«Í'ž ÂÿØv÷?¶ÓüDiü¬Rn2zcHÕ0¢Û¦WÒø^ Ú[£Ê´ž\EYª+…[â¿VQBÎ[ü ÅÃ"§GsóÏ/2wO¯3ZKCr“¾/2·6ÚKúÆÉðîƒZF½¶†ZaBzíÉYþq1ê·mÊMñGå6BÏÁÑ M‹NÌ5H“îïÚ®÷-E.ŠÚmšxùõ¤=jâUÒר[Ú))ê–b2EÍž<š!t{ 5ñ†ÂkÔOíQ?ó¨Ã—’³êZ"qçó÷`âgÉŒl½È®/|ÏP`’Á å‹Ö¨ eÔÚçYÄ^*Èש^2`3MÔ® ÝömàîÇ1€º-{É%ÐÜöh¼Ñoà&"Noï>å@Üsç­Ÿ-î Ù"NÈÿ„l™Ÿ-O'dËsÛ¶´”~Ť–\~KIàWLj©3¸Ià™[íE¾™$ð&˜JbŠÙ$ðk}lqlœ˜[’&sÀ¯0SÀ¯03À¯0À¯0ó¿¯0Ó¿¯0·´Ý“ÌÄäï+ÌÄÜï+ÌÄÔï+ÌÄÌï+Ì”Äoœ©7ìw ·xhOämò°âÑMRè¹I‰2ûE°t2‡dð¶å!F¯HBO½#}ˆæ.Ih͉R†â jc÷¤´æÔ>M{¾•´@DÝÞ€4´˜íW×hi:ì7¨ÅQy¤jn1«,´6¹˜íËpŸÎiw13˜n?ˆºµÅl5§öiÚó­†3ƒéÿƒ¨¹~JqÚÔZw>Š;Ц¶ºƒ<[8;ˆšÚáá©%J0Èüõ¢QüØòEz±å‹-_³æÄÆwy™Útlùš5§öiÚó­ÜÅìeêö¤¡ÅìT%ÔâŒh'Qò"½ÑÅì$%¯YsbãÃÐbv‰’׬9µOÓžo5´˜™ß™½LMêpG#ç1µÆÏ=·Ž³yA+wQŒ™W™»m1³Øk´¤Áõ­™µhm`í0XÛ̆Ö­™µCKX¾¯–ã™;”¶¹˜ƒg‹‹7\¶‰hd›ÈÌX ƒCbajH,L ‰mHÙ\Ä2¨ò½¹Š Þ{ÃÎÅÌN,Wa<nEÎÍúKŸB+·™ãP½eçî¡å´VÒªÇu§"6IÛ‰US­$}ö…É^îªë/ðÒg“ îÎí'KH½à9‰ôžb¢dL r_©v'Þ4-˜æƒØv½'ƒŸyÆvdòÛ^ºÞTþ¥Á&^çŒFgϵôVâÉvö9gFÏÞ¨U_8ƒÁaÒyèf~h˜TÍPƒË@ÒN ™´C&íÄIK1dÒV ™´C&mÅIk1dÒ^ ™´C&íÅI‹1dÒb ™´C&¦cÈÄt ™!“bȤ…2i#†LÚˆ!“bHû…’4ŠìÂGb+÷…Ž<Êýa#¯g_y }!\$¶t¨È#})Läõï‹!"‘ö¥ð×Ç/††<Ú—ÃB^/¿òx_ iÌU¡ í³V…´–U†€´¦í ÿx|Õ¡­7÷…}TªJXî‘Çæc½±ùXol>Ö·ëÛˆõÆmÄzã6b½q+±Þ¸XoÜN¬7n'Ö·ë[ŠõÆ­Åzc“±ÞØd¬76ë ÇzcÃ±ÞØt¬76ëMÇzŽùXÏ1ë9æc=§…XÏi#ÖsÚˆõœ6b=§•XÏi'ÖsÚ‰õœvb=§¥XÏi)ÖsZ‹õ“±žc2ÖsŒÆzŽáXÏ1ë9¦c=Çt¬ç˜Žõ\ó±žk>ÖsÍÇzn ±žÛF¬ç¶ë¹mÄzn+±žÛN¬ç¶ë¹íÄznK±žÛR¬ç¶ë¹&c=×d¬çõ\ñžk8ÖsMÇz®éXÏ5ë ó±ž0ë ó±žh!ÖmÄz¢XO´ë‰Vb=ÑN¬'Ú‰õD;±žh)Ö-Åz¢µXO˜Œõ„ÉXOõ„áXOŽõ„éXO˜Žõ„éXob>Ö›˜õ&æc½I ±Þ¤XoÒF¬7i#Ö›´ëMÚ‰õ&íÄz“vb½IK±Þ¤¥XoÒZ¬71ëMLÆz£±ÞÄp¬71ëMLÇzÓ±ÞÄt¬73ëÍÌÇz3ó±Þ¬…XoÖF¬7k#Ö›µëÍZ‰õfíÄz³vb½Y;±Þ¬¥XoÖR¬7k-Ö›™Œõf&c½™ÑXof8Ö›Žõf¦c½™éXof:Ö{Iú™4j^’}&¶Òp¬÷¢Ü3¯gÍÇz/Ë<[j<Ö{Eޙ׿mÄz¯É:óú¸XïU9g^/·ë ãLc6ëUË7ÓZf2ÖÛ+ÛÌã3ëí—k¦ŒõöË4“¿›õ¾›õ¾›õ¾·ë}o#ÖûÞF¬÷½Xï{+±Þ÷vb½ïíÄzßÛ‰õ¾·ë}o)ÖûÞZ¬÷Ýd¬÷Ýd¬÷Ýh¬÷Ýp¬÷Ýp¬÷Ýt¬÷Ýt¬÷Ýt¬ç›õ|ó±žo>Öó[ˆõü6b=¿XÏo#Öó[‰õüvb=¿XÏo'Öó[Šõü–b=¿µXÏ7ëù&c=ßh¬çŽõ|ñžo:ÖóMÇz¾éXon>Ö››õææc½y ±Þ¼XoÞF¬7o#Ö›·ëÍÛ‰õæíÄzóvb½yK±Þ¼¥XoÞZ¬77ëÍMÆzs£±ÞÜp¬77ëÍMÇzsÓ±ÞÜt¬÷Ò3»¤QóÒ»ÄVŽõ^|Z—׳æc½—ŸÔ%¶Ôx¬÷ÊSº¼þm#Ö{í ]^·ë½út.¯—[‰õx2—Æl0Ö«~*—Ö2“±ÞÞ'ry|Fc½ýOãR ÆzûŸÄ%¦æc½Ô|¬—šõÒb½´X/m#ÖKÛˆõÒVb½´X/m'ÖKÛ‰õÒ–b½´¥X/m-ÖKMÆz©ÉX/5륆c½Ôp¬—šŽõRÓ±^j:Ö[˜õæc½…ùXoÑB¬·h#Ö[´ë-Úˆõ­Äz‹vb½E;±Þ¢XoÑR¬·h)Ö[´ë-LÆz “±ÞÂh¬·0ë- Çz Ó±ÞÂt¬·0ë=™õžÌÇzOæc½§b½§6b½§6b½§6b½§Vb½§vb½§vb½§vb½§–b½§–b½§Öb½'“±Þ“ÉXïÉh¬÷d8Ö{2ë=™ŽõžLÇzO¦c½gó±Þ³ùXïÙ|¬÷ÜB¬÷ÜF¬÷ÜF¬÷ÜF¬÷ÜJ¬÷ÜN¬÷ÜN¬÷ÜN¬÷ÜR¬÷ÜR¬÷ÜZ¬÷l2Ö{6ë=õž Çzφc½gÓ±Þ³éXï™ë…"žøáÂqÆï:Ãû£d— NÔ5Dôþbøh€¥CaXŸ¼$µ‚ÐÖØND†û‘e‚+YØÑð~d.LÐ]fnœ‰n¼Š…üz‰0Bv-W— ™È-ů/¥ÓuD”za`EiÜémüíòK*nÉûö×[«ó¦÷¦g„\z”Ï’ùÃãã°véfÚjøc´ÝVû»Û^w[éï÷í|æ÷í´Ö™û¾â/Éõedm™0uÐÂ,½\+dÜ—ÈvÛóq6¹uä?ì83;¶d·«XÐ;Q6N„x'“¡/ÿ@׺ k$ÿ‰ëÅòï{úï¿F"Aª`,5µÌŒÂd8Jûù¿·ŽeÍÇIj§ÂJ‡'ck?étxçŒz–ü¿6­ˆr+Ú3á9p8Ñ!ôƒé8›GC¯5~Oþ+5åGé¥:¶ßÚˆD-÷D2i›#Añr2øíYe²œVùe|l± 2µ¹mo\&j´8 /¥G–ÿ®Íax™â©Í™x™¤a’lð¦saÒ†§ÖÝ4¡õùx¥"ªVè«Ó;¯~˜ó*É‚vרk/°ìGÛó[4a™Am/Ò¹–“êd¾›hl;õMZë½ok{Ý»IfábnÏ-NåòÕi1 ¼QÅ/q»qXž@í¶¶+}G:X9ˆ»ÛrÛ»íµtlvw‹ßü}‹}ž'WÍŒ·Å6ÿâ$³‹/šyb‘^•­Evqa.»¸ÏŠ(·¢=Œm^ªèMf+ù[ 3+-1˜]¬ä7˜]ÜË/÷ò #ámµ:»¸h•_e3ZìƒÙÅ*~£ÙÅjŠ]V{ßÀhv±Ú³ÙÅJžZwëìb{6˜Í.VZpúqç)f«í4™]¬²Àpv±Ò„Uvñ{k&´•]¬2¦”]l­CÊÙÅö|éìbµ «ìbka éìb• &³‹{øÛk»ÁìâþÖÚn*»XÉÝâ77•]¬â6’]ô‚éžìæÈÖ•볕E® ™ÄT•SrûãU{®¤=«?g©±†¹×,ìÉ?ú*s¸¦ªa^³C.µQ¹sæóv-9‘ ËAvžÊ®å5cMÕ¼f‡±³øW Ù¬¾¹4nŠ©xñ5CŠ;Ч5r¥Q'fP÷{©{b½DD_5€TD„Ò€EkÙ~{N%"Ûká2"Ë?Ò±dD]q1Û 9¦Ž^³cš-Ì„fû-9­Ðìe;O,4Ûk¬©„êkvKd¾jˆñÐl¿)†C³½†ä¡ÙÚ1žÖn+FÛoP÷¤»«¥`m¯A¦‚µý‚µ¹H{*küØs!ãB9Tï>:”e´‚¬kŒõ+˜Œ}-VZw›iar\,LŽ‹…±q±06.´qdó( œÔˆ¿¨ ã‹]2Ö¸¨`"‹ &Cã‚ê/*ÈÌ ž¿¨`24.xþ"õæÂšŠõ”ÿðÆ[Z^*b; ãÊ[ Ì1ÔÐ0Þxkfkl6´Š4ŽZehÌ/öYUuVnrÌ×4Ìܘ¯g˜©1_Ó*Cc¾¦UÌ1e›31<?¼aä1´aÔ1¼UÌ1¼U†ÆübŸU­øùã 37æëfjÌ×´ÊИ¯ii̯ÒýlÑæ&šjó6k˜mÓpÆÍ¥e­vwŽíÌÔ¦ÿÚúœÿ5ù:@·! WRIÕ5FE#•TæÆ ÉiìR-Z’ sCranHÒ²R•T¦†$-/ué¶ï¹–O³¹RÞB¶KE[Év¨Xcb‡‡3 ®,KEA›NªÓµFúÿ; DõÓ).…™ä7ª¹8Ž£’‹4Jª¹ Ž’ï¨àZ´6*i«Y5—±QI[Ϫ¹ŒJÚŠv5—ïyó´ïÓø‚™gØOIË ì¥d–½|¤³—Ïä¨é˜5ó£¦cxÔt šŽÉQ³0ïkæ}Ͱ¯Yö5 þfaÞ×,Ìûš…a_³0ìkL_smY%Æ"´×ÃÔT i¿¤ÐûBNü½Ÿ4h_ äŒÚÛNëöczØvL[ž¯}Ðè°5ëm­{Û…io»0ím©å „æ†-5´ÜCز·]˜ö¶ ÓÞ–Ù¾@htؽmùúW^ÙÑŽO-C Š`Ôµëôl2'…Q×®“³‰åFjÙ@ò,µl0çlÚš¨eQ÷»ëxz6µpË»®'g“A?dúºw=H~È ×ÓoZ?Ú±g}ѹÂÔ›<[¶¿­Ûü¦ÓáÓÊ Ï m!»yx¯º= ¼¿2aÉ]ÉÃí(̳T< ²#AK%ÛML²éC%£µì&Ÿ®^û„z–Ü!Ô6ì2·G¨mØéEZkÁYžkÁYŸ+hw£PϤ6v µ-:ܰ4Êxt¸a§g×éjÕéj„A§sAÐ&µná Õ^t¸…§g”IÔRt¨$t¨¨Qm'£mX`¦ª”ÌvÀ^ ÐÐíè˱"–CÑ÷æ’Ê’ãRt.fvb¹"ãyÕ¥³>‹Ö“*E·ò®‘Ö R1±IÚN¬šj%é³/LörW}\/˜¨—žM6¸;·Ÿ,ñ…R£-ž{A+Ä=ÕÕežH­/ö“}Ý—c:‰„ãÙ¾÷o³Ó©_þÌ “ýÝ/h³ÔƒµË´ü0©¾¬ËâN½à9‰ü[1 ãJoÂâ¾RíN¼i Z05<̱ízO?ó@.È‘Éo{ézSù×›x3=×Ò[‰'Û©tΤž½Q«¾pƒäro•ù¡aR5CIË@w÷ðÚ²ƒgZÀ^BÖ‰ù>BZ=À^BV {i¬ê”]‘ÚžßéZV+8_nN¶ G.òQÓí÷/’œô9ÒÚ+©na"#•ªz #ê9¾¨}·&dì©W\]¯r¶ÁÚ¢®·v–•ß=PÅW™“Þ}LÇ„*ý R6E·vuéíâ$³Öð”4Õž’€*àÃÎõY¿Œ—oW,ýÏ©ŒÜ鹨žž¼ñÅìYÃWMK2!ž:YÒ?kxÊtTJyrû*?ó'¹ðË¿v…Žû³0|Þ.6ŸZsÃeMv4¼—¬£ŽQâË,Ð ~4Iz‹G';Ã\Ök¹ ’‰ˆõ×eõ³3‹Ã ìt“ç$sËQ…É®Þ ažS]ÜxkRÉÜ v^D…Ñ—ÓÄ÷qmÝ®xJÇx®.ˆ^?Ú¾Çöóí|8ê[„™»MÜ5Eœ¯ŽºÊ¿J}'V%ÂCãÜçŽô€.¢;Ó0~f¤€ïê²_ ÆñÖí<ò;—:ŠKRÙYÅõè»_FÖ`b;"ÝZÎß\!¿O…9©6@{eKhädF,"_’­Ìþue ›ÿ¦Ä¿š… ¦ŒèvvðD’›Á›¨99Mûi›å^µÆ‚¥\µÍb¦Ã({‡ N€¿IÁ ò Š|‹M\´ãëôäJ­žr,%êÅyXz“q°bÌÿ1³sÆ+É(CË@¬9ïw7Ël+®•±PO­¿d†œæ£./,Œ¹‘ƸB2†Ïmv g—¿IAu9Ó\Nýplû:h§‘\ywb;®œÐ÷åà'º´«âlHq½|s—Ê!]UjÇ•µ? Ž<£}l¯Ây½Nò"Ù<ÀãM‹_ö/ .8¨ûñ£^(x—;”ºf†R—<”º†R×ÀPb®uÔµšºJÛ#ÖðIg2fte`öY†dvœZù?P×.’™ ×ŠÒøVN‘Î…ž#:q<äèIÖô¿‡^ÀÊÑæ—ªÖÁ™‘Hd0â ç1½uœNDzæcÙµ2.OYÇŽ{ùLC¾d€Q:CÇ”/`’޳ÁÙOGq ûé(.uE·0<9·ùŒOÎ ŒÒ™žœ˜¤#OÎ:îäÜ¡cMN½ßWáÆù~%J2¹)P¢äІùŠ€5°WÜ¡l®l“’L`z(³jÂJä¡Ìª +p†rÍաоš{ð]Ö<ÒÎà9ÎÒ@;ÒΠ<Òî^Ô¹sÍÀ5áàzÆpMc¸¸¦1¼eÅl OÀa o×7†8€0†7€0†;€ûŒ1í0†;€ëCÀ5áàšÆP°ñû‘×cÛµ;!U±¬á)ßn Ïù^¸To™ø¡N<áWfo›4”ˆÇAêM8 k¢Ží~ÏMêYŸ­i.¬E»ÉÐ3?Ô yká¥3+I]/RÙ®ô]ºÝ÷Ƕó Õ1¿xÜ‘€U!–¨c1•žAÄ+îá݇Ç5ûýÈòwVt/dã]/‰ÂD”ÚO)¾\“zu°öì("pªÇÖc1å8Y¥‚ŽÀ\ß××åõfÛoa  Âj AÆ%èß^Ê)éÚâàFšƒÜlrÛá‹ ÷‹&ÞSµ8 ŽÂ“;ù¹Ì5YìMgä.Kã,àúÂKA=n3.Ç^@ª^sˆpBoGòàE JÕôšãIFR!¥†}ÅqUè`pI&rËþ"š$‹‹úc‚pþ.S×iC¾CÃ]»V4Üåëj†t?v•ÌÂ…ÜîpI293ÇÙ„Jr­”hãÀ¦\7_³¨þÒ…¼L%r-øiŒ›qú¶Íl.M>Æ<Ž„ìš&‹";ìoCðɱ=Ù“=/Éã.ïŽíW‡cÜðÞ¢e3TËÃÑF9ù)3Ft™3¨Ë äq½§ŽýùYÅt mŒkVE]™=®Y5u œqdó( œT©…v7—ÿªbPp 1U©ºÍ9J;—ÖªÙ¹züW|f6ƒ¡*ÙmΖú“ãNJ $wRfณ2Ù,NŘ+|ßæ¬þ îअ eãîd±ßðû“ìNhÑI™ìNhщ’ <™šÿ£­áŒ #­!¶c­áŒÌc­!âS(ü?Úò(>…Òÿ£­!âS(þÏ­9•êÿ£­!ŽâS©ÿ?Úâ(>•kkNá ÀÑÖGñ)\8Úò(>‰k%Iõ¥0…1âÊ ]#íàÌœiü•ècÊ{bôÒe9OO››ëƒ_÷(n²0™÷¿ðÁ'ßóÊŸxßK|æW^û@ .þèJ9ÎâT§L÷>e²/¿{aR|u.Ä“#"õö_¢DøºÖm˜¨ÿW²;æ­Q*þ‰H5û ˜3зzœ™XiJ3 Š_±¦—zBN¥Ð8qâùþ ‰ú¯.MUÉàAþW¡˜üã‹ žúŠAÇvÜþ¸4QÝþ𠱫JOèã\9aô<™§ª[Šó¯Ð_ŸŽÛ*N¤Nä»p*ÿ^#ížT´±²Ó¡IÛøØôÀ©j¿ß^àTiM{S¥9­NUÖSÚéå®HéÈ?ËvUÖäÑÔÂ<ïþhªŽh#šª´Ãl4Ui ÑT;Ç`4UEßR4UeʾhªïB¦*I÷DS-uAË==šª$mãc“¢©U´DêÉ5>§ÓÖøœþQ¯$=ŸLÔñæPN]Ž6‡4ØŽ6‡366‡=”O¡ êxsØCùê Ž7‡=”O¡ª0çTJ¡Ž7‡9”O¥êxs˜CùTÊ¡JæœB=Ôñæ°‡ò)TDo{(ŸBMÔ¤Ï-èÉÿá2\Nb!þ-â‘k•bp<• Ô™Ž¯‘æ¡ËHu”)©ý¦R¦›Dl¤©¾Æ'ÒdT»[^0 Iý³ÆçôÏŸÐ?ê )é çžsÑéäaM|{Úé¦"I-;pÕ¹NsÎÅ<ŒŸ­0vE¼U+…x'r¿-¥L<×Épa»a”ªc¡‡Jü_¸b"b&Aˆ§H8©pÑãE­¡©ìþ4$Úß“ãÍ’ËöÜ ìTÜ}x|Dçp%Iß²œ0xê…×Ðz¼u‡wûoÖývBÿþ#ý–p…=âÄì™´mëMň…5“~Ï1æ9IÅÜrd÷M¥;#¼º;Ò7”‹@X.‰ü’•Û¹ûÝsçoÖ· k8º´î>Žz–¿iÜ É¶ªø¼5ÛÒ™R_Jö¼èåT"–íâ+5‹£çõ‘XuŠ_yz¶êêMÓ®Y–U€v,[~]øLøþ’DúVoò¬ÞÈ"/˜*q£½NHº¢s²8Aj­N‰d›$ÇÛ_o­Î›Þ›†%yÏ­X¾¨¯g­ÿ^½Þémüí`ȵu?–ƒHËN,æ²åÒ]”ÿùêþÓV‘›çö‚¾&7Ç]š´jÇä1bßë,pìl:ÛœGh–›e[”>b!J+½‘ȧҿŠ8c.QlSÁ#ê^¬ÆÚØ·¹ÄdûgÀö°q¨_†Vjõ{¦Á=þŽ¡¶ èl7œÛ^@ííåøÁ4™` ³Ô 'ù8â2!ºn“ÇÎºí¡¢eúŽ•ÎNf‰prLŒx?&„âûì;"R¤Ù·^vˆkš(–MÝÿæÍµîj®Éuâ«pŽÆÕ[reK'ë¯ÖÕàÑö=ÜÇÓ,‘lë9‹±íÛ#¬IËöÉÙ¼w’æøM),S;mÒ]Ù4ÞcŠt7kÕ;ÐÒNßÛÞéSŒx%ÝÀ7¢çxÁ.è/ÝëFï$ŽÒ¾#gPðU·)° 9ÀrU§‹Àõk'½à_:7£n~‹bÆ«“Ï”í÷Æ‚4ÿ?Kfí÷saGë=X°’D&y$‰LrIWS‘ú^ ªÆÇÈ~y%¼’+òøvÔ·FëþbÖ8ùW<û*µ´ïÅÜ\猣t^êè·bT7D¾™Ù*OåˆôV>ëZ¬BÛùÓøb8ŽyW×^b_gW»4¹9[ [·F½0I=pT¾Õls N£í¼räÞÈy”ÖQ½=ëÓo+mņE«6ø¾d5ûÅW¬f¿y͸·Ò†…õ®#˜¶°~•yÖ+6haùU¡Vhκòã­Ðšmí‘ á­˜x²^æXmßVLf-É8 2eA§—¤®ZrÑJsµ²ÈµJL‹gBe+Ù„ëÜ„ä9pZíŠ*;ŒõǪ:x ë«8{R£)etµR\ò茶ÜUÇD½F p ¶2(j û‘dîG–½ö®Sj:f€: P—* èŒê1@¿3@}蜚0@Sè#tÁ}b€>@>šá¢šá þ™ážÞ™áœ¾™ášž™á˜~™á–^™á” >yäVìu ÷T#¯´ßH ]‚† дs±~ã‹°íSZ¢fÏKe÷¯Š@¥÷ó ?©êuÞü)• ‚Õ½Žü"1±—vô¹#¿J†‹Ï³0Ôž³=!yo‰s Y°HJ/ì‘JOëqº…tqÆw ÇûØsAûâ›,¬OÞ-?¿G¢(¿»G¢(?¸G¢Xy‘q6aQ”ó£-ˆ½Gà8-)Ê^:_0B\u À%^–ªoqAl¼Å^=b@`½uuÊ ñRŽŒ¸¶ô6^Nä|¹~ñåÌÖmfs£uÉ\sÔâÏ‚9l­·Ãz{„1Ò–Œ¨ÖmñR«Ö eǃÛ<¬ˆ°¯=åHªi?WÇ!O×ß|¸•Ó˜—vœ}€öíP8ý Ô^0ÝÓêüz »× þ½µ¤$þõBÍ“;D¬I9Xª‚Ò[´MDkÑRÇsÕ¢QmGCFÕSrde›=u°n£!£ê©4’ŒÚzŸ›Ãr¹ý07‡æj]}ø}éX]uV–C·7ÙL££µîº¼îû™kp• †—á›u† µn¨´¡~O ÂûAU»ç9m[nÉbÛÉsôÕ¡Ló÷>ºÊ€@דtÅþs«}¯oC™ôì‚›Ó¯^ia¢“Bѽo®pÙŒd'J/¨pñYßæ¸÷P¸¶œÀ¦àÈ×M¸¶œÀàZn9v‰ÉW:(i›ò;+7Z~N…CPz5…óJ£pŽ|…ÓG>uB4æD\α—PŒ¹Q>Çöý°BE_œ\™;:*q;4ºy©&¡¹w=úNc},†i͉L~áXí¼ÑžŒSܬ.Wà+®Ý4…¬¸uÓ²âÒMSÈŠ;7M!+®Ü4…¬¸qÓ²âÂMSÈŠû6M!+®Û4…¬¸mÓ²â²MSÈŠ»6M!+®Ú4…¬¸iÓ²â¢MSÈŠ{6M!+®Ù4„ÕWüéõŒ)þôš­’»”¯ë¥À)_WüÁR(½ÓCŽŸƒ¥wzW`Öƒ¤w°¬Kïô®‘´5¤wV¬ŽJïô›­æÒ;ýš ‡n &4‘Þ4õ. éÆv"½ÓtÆ*½ÓìŽë¨R¦aÿTjÃ4ƬØ5ƬØ5ƬØ5ƬØ5ƬØ5ƬØ5Æ¬Ø 5Æ¬Ø 5Æ¬Ø 5Æ¬Ø 5Æ¬Ø 5ƬØ5ƬØ5ƬØ5ƬØ5Ŭ҂iY%Ó²J ¦!d•LCÈ*˜†U20 !«T`BV‰À4„¬Ò€iY%Ó²J¦!d•LCÈ*ý—†Uò/ !«Ô_BV‰¿4„¬Ò~iY)ýÒ³Jù¥)fÕ™HSÌ×t_:ƒæ/ë¾^Ô}A¼¦û‚àxY÷EðŠîKÓ-桺/`žý¥øp^{^Ô} €×u_: “Gé¾ H^Ö}izHñºî €áUÝ—†Ùãu_ælÔ}°¼¢û‚è®Wt_¯è¾ (^Ñ}P¼ªû`yU÷¥iÚõhÝ—^svœî ¸ž¸žØx‹kê¾àˆk*x ˆ_Õ}Ìœ×t_Gê¾4=‡<^÷ÈlV-¨Ä\W÷…Àl°Íõu_šV0§û‚a=@÷¥ù>æ0ÝÏAº/ͽéëº/’cu_úͨ«¤>tú!©Ð}iZïÑT÷Á˜îKóߺ/¢Ãt_D´Áu_.›ïðº/0£º/ £_Ñ@u€îKóàæ Ý—æN¼–îKó•²–î …n²™EGk]SÝ—¦Õ†Ý€ u_Í'kcÝœ Çë¾°l0Ûµt_šOÂZº/º&º/ýƧPt_šÓ¿¤ûÒi¼'}I÷¥9z-Ý—ÆÙ·Zº/¶t_: ‹ì^Ó}àÃt_Íû¦û²rOhKã-@s[^Ò}iî)^Ô}iŽþ²îKóJ…Wt_/ë¾ X-ê¾4)º/ c0.hLsŸÓؘu_:3eõu_šÞ@=F÷ÀùbMBónê¾\6Þ !u_`Ö@&7ÔšæIÅæÖ¼X=Ø|X¾¨û€I÷¥!|Å›†APÅ ›†ˆl"VܯiˆXq½¦!bÅ횆ˆ—k"VÜ­iˆXqµ¦!bÅÍš†ˆk"VÜ«iˆXq­¦!bÅ­š†ˆ—j"VÜ©iˆXq¥¦â7ÆkÊß*ïÔ4¬ÄþVy©¦1èkwR¾VýíÕë‚ã*E¯›2Äö8âš•¢€Ár\¥(€øÈ KÀè:²ÂÈlöe½sÝ K\›ëVX˜›ž0¦uÓf€ O˜_¢ñ 3ΆãO˜Y6˜í‡÷ê ‡ÛŸõ%ö.›åÄþÙ›Ï4Þ'û-!öÉz•b¶·ÄBhËã…tû¬õª„δݣÚîQm©¶‡TÛ7îçPÛ±ÉDnSh¬M¡©6µÓÕ´Àh˜ kjZ`¤^ªõ6Ó/Z`¤L‡·5-àöÁ!ÕéäN8ȳ½ÐÂP8È3½Ðâ„hkÇ·k‹ÌôÂË&˜í…öÆÂË&p{¡õýÿѶ˜ï£9€£máöK½Â;rÇÔ4¦…žikÈÔ4ÆHÏX¤h¦g5¦…žiyÌj µg¸ùÆJ|{\ûŽyÿQÚ„é,VE!R3o³O¶9¨:;mŠÈµx·xAµØ²Óp®ò9¾=µ&alÙ®‹$©¼Ì #ZHc‰§È÷/ÅS9Ov^W£JdKÕ!ï6µÑs¬kÈKM*8¶˜zºµëì ï7wd¿[Y ¿­pRA°ÞÉâXéú³ê~Âó¸bnSŸ€,—Õû“XP¼ºë¸îø(Ëo@3W‘Lýplû»Ï Á­ eêN3;v-{ÆÊba=zqšÙ»¯_4F…^!ñÀ$ØGáXŽ“†1 Z~Ä ‹Hà4³]9øRÑe‚÷˜à$lZbAêl‰Lêi‰ŒvÕ _œâƒ¹éÓ“‰8 Û÷Ògëñ‹ް¢8|ª–_i€]Ž×•/‰i{™)IjÙ2BJÄk;„ãøþëe;ÿî{ã§¹ß}“„oºo®Þ\j®ÿs×ßÿøöáú[ø{:—«lÀ¿>êZ]Ù‚ÞE“.+`½$ôí´E–3!tÆïÅÄÎütôö_¿Ë/ዸ!æLvóÎŽñ. R¹hú®ìþwÂyd§ÞØS“µ!¦F¿f“‰ˆßª­èÈ™‰¹hYtdŽ<òþƒ„}› ÈOjB c¹qMR ]Qüiû¢Â?•F‡üæïfÂyð‚)ÇÃÀ ] Üì7ˆØs†J³‹¦çÒSÓ¹¤AÓÚq ²ÍØŽüMoÝn/ýœISßËÕ"u WÚ8è½ý*?&p¥ßü ñ5K£ ðÕ? ýêÛÁø£’Qh´òñ%S& m mwø”¾O]<®ˆ!<ÿÌùÂñ.v*>x¾PÒ6LlP?èµ>~/ÆÙt¤^ê‰zкåhßü)Ç´8áÚ²‹e—#‡ó½í%4—ï‹pàíûcÛyÈÄ/GÞ|ÛÄć#ûQ| ‡ó(}þfOƒwäÍ#Õ—£4Μ4‹…Ë„E£lœÈé/×Ó¥À~&µæ+ãHŸ–7Cœx× A4ë5;•íg*1Ü(®Pß »¹u\;µU‘vf+q#é#Á°r»ðEºò$²lË­h.ÄT»ûõ”;øwé‹ä.KfD’}k%Ã/Ýî±KB%‰ŠçáMѻÕKƒÃ^ø!òDÌ, °svý^)d€3Ê$ÓèjŽÁ‘å@¤õÉn¸ð…êføb!T85|ŠÊ —oº…ôø‘Kw˜wVzg|ß>ÉÕ2°uÄ%°OÂxì¹2È‚º©Hß…~6òM>Ôj‰­ô3u”@#s" ,Ý„„–„Ó#wÙØ÷œ[;Òï¡qušÓÕ3;òæ¡D¿ xèéÜ+÷ êøc!6ú|ð¦Û:KÃw~˜¹†ÛM’×$ŸÅ<ŒŸ«io®@,ÄP\“HÐ{a»[QÉåô—†¼î ±o¿²óqÃAßr(à?ñU—&htý”öO8òβ’¾³Ô,¡S‘¿ÏæÑ‡0žÛiž­'SñH: wwVáÑó°ø6ªÒÅÞ¢Xn±@/¹Ã(µÓ,¡ðÒ 9¼ V?…áC†@9¸NC“ˆYÿ›H?‹Ô^*Àñs/÷uÐa8ƒr «°ž¬°±ˆü×0T»*b& œØ‹Ò·”ÃÅðE,Щ5ì—ð}úž]=›¤7nvëDÆBµ†'é¶Áw—),3Y’áóU½©t;¾¸Ù¤<ý šáxyú:#)»×aíkR¼i'ÏÙųvðœÝ;oçÎ:*cSF›ªŒ¡ˈ–†MZ$GäXü›=%lR¼iÆöØÿœy)!®ŠaÊõÊEåCþÀŠçðƒ&,‡'›š°TÕøƒId”u‚G“Í’•vàá%2& \Ûð¸Ï¯ú| ÕÍ(²ªBE7‰þlÁòx ~ÎÈXÞ Þ¡ÜqxaïÊËOÕïcóÝQ:"IäRv$º4T닉ˆE^qb!§Þ£ œrKç³ÜÕW¤Ððœé$µã”²ÓÈŒ½XD*xu‡œB™G•òE{íBž|/xøM޼<x/Rá`ûz‹lhŠÛä“NchܽsFÜΙûoßÙ©ŒA¦o]lšº Ol–°ïåîøë³6еC'ÃçõKd’¼˜‰LòÇý-œÁußÒ®äøïfžüî'/»-×TB˜Q`§. {Hªí-Ћ È[ß³±Â9þ-ö\)ý"žÒ‘']8sS ³ö9ü],yÆ£á9*Ë^%ÜP¾ÚJ'X–cB€wnŸÂÍ—n|$bÏö½‹oOiQý³™Ù¾lÌ’¥á\.Jïäö&.ÁË UÕ¨c=Çm¢¢ÊxîŒ5¤ ù"òó‹íï0×ïÂL©H’îæ÷î4%ÝËÂnŠpÍÐà'á»!Ã(ñ|púf“ዘî4bu9Cñ5p}ø®Hˆ}EuX_Ûï©€c£§š–¦ï#aµDn»?x*ïÏì.Eâ7½Ý¯t£ÂÐÿ~à*¿µ">5°þ]Ø,ðµŽ6;½bx÷|–»F¦ïÆ\@p}w„‰­̨øj¯­dY0’`9²V á@«bòoZ$—üIÓœ_bß‹„6åjð6W¡—ëÚ ~«9Ñ,†'רÿŒ½T¼ûýí=~fÃÃâü?²P†÷¹ž žÆóݨ£6pp¤ï…/ÏNö²¡èê ŸÝýõ9UšœI6[¥~ï:ý/¼k:kUÛE„þ2À‡OÂAö+h;¥¶é€ÍžÉ‘Y§Tkdu²Ï‘ðï–úêô0x1<¬#žßÐ*À`vûúl¾©^3pÎïÖøœ£»ÿ6¡Äºþ¶¤SÔ Â E=gæ3›8e6qÈL?c.t­Å8ƒG}exí‹îtùïòdä= }©^F½Æÿàʼn–¹aãß6T‚_CÞÄþøšá‹Ö ôÛàÞ¦ÐÛ0²Ü@¹„x'G(ÐÂyXjíRÀÿöíNŸ¯Â»[‚’ß1³§_¢ ááµäKàBˆ-7¬E±‰>è*\5{KEãçñ|1CuÑIQ ‡÷º9ÕFm Xî`ÍòÛò)µòîí®ÿJ€™Ô‚ªûrv^|ÁnA^‰Á…+&rñs)Âk¢o³XØ.] nß“p$þ¢à“t3|¾SýöùS¯á¢çUÅä7u¿ŽÁÀHÂ.q?ËØÕS™AúÂëvµÚT”5uš»PE’â³_v¿á`Úh\º2"A6±Í(9Ððê~*:*”¸œK=ÛàŒgM ½< —gs^nK‰w1øîP —Ò)ú`ýý²¾”²¦j ®XSìßD²ð| [¨tÅqû•Τ„[Ù+ø—„Vq,D¡Õ#aZÚ+‰Õ˜ABþ&ÒÕc^èÅ‘£@[BÆJ×”Áê5%h¬€M ¯a³‹Ï–q¹ƒ/;rrŸ€Àæç*ð,ŽÕF°÷{ÿõó?c;zë†Qº÷Iw‚§Ô6*ð×'øê<»Â¢ÌWUû<ô{á„#ÝË*²ß.©Ç1©ÓTÊwVx:±\¥: 'XãT fP%píÍmpF8¾"xÿ ~P°Æf>T0ªÇW$¬ü芀±¿Ý§ ¯»ŽŠÏ©ÀÜ”~Ç£o=·]IÐäæ]k¾Š.5¿Aò’ Í/½n Ÿz!¼òñÍ“3‡– ¯":ú%$ͤLÊšðþò$þn$";®¡w®ŸBÞ5ð(ƒöðI~Ü­0«Ó¸\!oßÝu†Ü”ÿ‘ØÓf§X»¢’ #¿.à{ûšÁ÷Uzd ì‘z3lÞðaØ%ÖÖš†01”îÌs½ôY‡íÒïìór˜T=;Â9[(AoG^á-“5l.M˹)QAVÙ]³P›À4>ïÒ'–nû> )‚y9ÁˆKPl‰i2P”#$½¥ä©•àyæ3ØVxÍÅ)…TƧtú¶ ß@|Diý^ÈÑÛx÷ÓŒ"áx¶®Æ7$Ž)‡çHet¿Œßí¤ë› ˜¬ÀUHÂ@ß X…,bïq;;ŒÀÞÝÁ`+Róh} šwsÐGJJ—}›|ñ|Û‚À?ÛOß •$VÎ9ȤA¢äƒbnÅ ôVý.X%p·ÔA¨yž›æïTL6‡#«*üÃyðg;uà  øk$à5U ÷žpõÁ ÜŠë%xš8YîÚv„peöJÈ4ÉU+PînM3:] lRñ¿‚&T¸°Ü wM‚¯pW°Ü ÷m,R·Þ9­êTÁß¾§Y®o•ÉUTØð›ç þ³t1O `F z‰Ë8ùϱ‰)M߹稬áï®Ñ‰šÌ9Iªd¤7Ý9dÝ/wC0è„›K\Öp¹§y¹9¡MÊܹîî\1k¾.U4gt+t­ë†®âUà„Òz«D·»p û7糘ÿ&¶`WhØ‘H7OÆÀ¥×á{ˆ2¸ ÷¸pGéùÉæý’–4n‰‚‘’ÈÀt‹e[EΣX$ÉgBØõ›~žÏÀy–Ea§ú•÷"ïsôÕÉ'€Ø5ëƒC–õÿàöþ?¸ÝO­²TøOù;'ù7þ2bIóAØi3¦nLÙ…Hø\´…¢U¯Þ9_Чno—)oz/$*hOUÔlþ~I¶7KƒæW45²+¶Å^QF³&Ën_€€åf]F.ÒSÑ–¢-í¥oäî”±0äC·Œ‰®Ï%ô?í8«eB­sÍcuÎ8ùÝN*ÖJı¢DæÌO L‚éwÓø¹Ëï1Áتš‚Kydd¬ªÜÑY.…ÎxJCáæW(c/‡¦Œ¼Ý‹(äTt >+A÷xÐäüª5ÏA•ð)#¥„Ï€9v@±[³p?d¾O3ZS° /ç(Ü?"7—f" ð>¥ÏKøhøÛ¯¾ÝQª´42¥LK#3ê´40£Pëö«v&u³‚&õ³‚ætôùŸhÎGÔgíUŒÛÀU…A2üËÕƒá;=u;ß„µâáÈC+dε=…L Vðµæ52£¶D¡“ô™tþÄ7©ÄqM@L{¯IøzٷɯvByÕnü[Vï.~i""ñ}ÿ”`˨»M8ýÌìãwá|ì=Ž4Ëö÷Þ/SÀ²lV§á„q̲R'1]Nc;šáߎÚgõÉ'‘¦ŒoùÙö‚| %`{OÂ%ݤ¿Mî²±çrÜà ÚJíqõÇ\6!غ‚…±ú_¿ûü ûQˆH/cI…0…€sޤ¼y׃^NÏæc¹"}]Ò'ð‚UÇC¸Š¤ÎØßFr«÷b Y¿¥B&.i\Êá’B~/|ABÆŸ£(XÊ« ˜3Ö>Ä!~±TÀ·ABxZW!ñ”2$îÂèWÛïË hZO+9lšÝ™:‚%žŸQ½ÅŸ›¬Áõ5]¼Z†9è"ÆçÅKÐ#¹Äà³ã%‚Ú>eDò gœ´iÜã)=Úî[RRaó¡áyF…=|RåàÜh5§)l3¢Ðe‘ˆiÂyøäc&ñ)Ñ’2Ò›Ÿ’*÷g[Ý4ª+ öh9¬ÛÙÌ.-°?…[ð7˜ùUî¢ÐkþŽtŽ÷ /ÝðYÌ•ÈÛ×à÷^ù6|‚¬‘·Ã’«æ5QœQŠ·{±„úÂÌk|/XÈ;WAQ¸³pÁ€ÝÿRy#ÿ³DæLê?ßGçgð •É™ó&üçÐÍ*Ĩ:ê9ô®d y»ü‡E'Ô╱߅A †VÒ’%'ࢃ_6\â/àKS¬Ò蛑|cYý¹JÀh8!8\#Ó‡£¾ÁGuJ†V:Z/1ž0* ÷T è ½X :£ø·€¾‹Ã'ø¾°ÀþGFû”ŒÊâZ]­`öJ~à{x!ƒÂWU×o³tö;E¦iÉ@ hú+ð\Zò“¦éö›®]’T≠&¶„ÿ ÷ –à,¬/HˆtR&îý^¸mäöæâÛs„~Zi ÏrôKljß°|r޽e8°ÓïEšÅÁ;B2~É0²yØ´åJ,XºÊ*ZRER¿RÒœsÔ¤ù"k ¡€R#Ôvn8gÔÀJd‚HvŽJ5™+Às|ˆí)¯ŒÃÉ5òÐN)‰1Mpw»ÕáÍS9.A—$G¾·¼þþ¶O0‚ü‰±Hp¼¼¼DåªË+‚2 ÀAè —¨Ÿ.9òKzxYo }û•kºFÿ‡sõÄ Ÿf=EiZâ’< ×}SÆG©jÌë;¸jµ¥ÝVVàœŽæÈ±+àª÷œAØùƒQ\çAZÜ,k¯À‹xõàj• 8ž&‚¿½µ§<ó°_Õ?è&PÞøÜ`Pv%#Ð}õm§dÏz—à‹v ø«b ·ÎGÞØßÊœn/~ ¿˜Q§VÑÑ[×em16ÐNTüšMò£êÝÔŸQ¶¶Ä}A¹§!ºzÊÁ&KåÐÄñR¼JK‚éJ§XH7IÈq+A „âOo©z »Ôˆ<‚oXލÃrNrc#Þ¸—Д _MžRñ\Ë%ýqË„_áÿÓ Üp‘P8’ü:õÒÝ7ÅËQò‡z(µúæúî#q—oº£œ]žð \!éVÍÂØtígª£¸|Ói¬œ¾ŸpçšßŠ®Éõ†]¾Û¯ÌNüàË“@oœèÃı·ë<:xNd ÷­oÓ.ŽÀóG¹è¹"‡¿¯¿É²]ÑcøÕöíÀî»Y{ø‡€ó»ï¬ujuÿƒ>OÃüA޽z=š4N–4Gy7¤Õ3åøðz´ö›OInKK]Rµ6ç«þ# åKLäq¿éè=m¼R;NY1åè9IÅœùaÕÁ3­oþ¸çÌ%‰{o/6WÑæÏ½® ©CñO'Ò=ª7€˜ø_2x%¦†—x´á¿uÝåûH‚÷bœM_|:§‰Ødα# 3ÿƒ;¨Ì Þ ƒ—#ç4J@Þ‹…“²BÊ8¿¸ÈŽ 2‰®®æžxï#bm‡ª©g߯БÀ_a圂ï!Å…ï!’[DCLê™5o«¾Ïõ[Œ—xÜ!¹#Tì0d J$äŽ"[?šÉ] çT0þl?½Ѷ *Ô¸“†§Ê§Tä•pmX±ðÂ]Ëï¥ÏÄØiIñO;f<_WäÁwudÙØ³ÓLOgß­½šÜP5è”À*a«.­Þ‡!\! €ÏK…=ß¾ äØyôp…e]å!p–{A€R•W$ Yœ^þx‚ß|—¨J Œgº´ùÝîF®Lç ß&ï…Ü'Ͻ€ üžSèíZ,bb£Kªb¾CK ËïÂÑÙ”Hî]˜ð‰ÌtžVºØMÊ ÊÃNFfð¸ä<ôïïÛO_~+´êUÉ]²Ù’Æ¥¥öž y[ hð¦±J}¾ýZÎn…\­2‡åØ#s„¢øM¤¥²•­ÑÓøaÊ5‰n“CIúïLÄÓ’~!»ç‹â¿%‹Œ¿Ùãj¯@"”‚ ÉDic%ðÑÛuWÂÛåÐ üêÇCPàr×m;r’0Àw¥@È{®Q£Ð·êÚ<½ÂÂÁ¿0¾hõýcøÞ[ -=égsu'b ?ú(voÕâ°?y`Ú.—Q{®²ˆÌFÜecßsnÑLjz~QŠ‚þ»Ð‡¨ä¸ È·Ó ŒU¥Ö?g^º{{Å"·áEbMþmEFÉ:cS\¿§sß {$£TZoûaÀøþûîƒàeÜìˆ$ÑO$z“¹Un ⩼ÑÃNBÿ±B/„/÷CË8æSèØ)%üÕ×^‰á’ÆçLexJÈôG-Õ³§xE…/Ã1•+äh-<ðo!GÆ=ÇÞ®*†Œw [ù8|»¦»óDö؃OǺZ#g&æö»™p>ØŽØ:/jÞ9üÞBAèûv”THž#T–s¹·»…®ÀV”þ9K“h«%0žhW¿[´Þ­*óFÿK%K@Šmå7(8ëÕ· †íz@ ú?=ßuìØå¸õ€Wæ©Wõ¨ÀÈ›G¾þ·©˜o+•ã„Ñ]lPTx½.h“ÐÎÆ XÝ-ÕŠqOŒi–°cg†ÛYâþúü{Œ¿ü4…†ò[¥D¤k[uoá@Õ5…y‹$ùL¸i•W…’V/Éåų2BIˆØz¯ôS¨d­4„­¦ù7ˆØsô\&õ‘~TšP_)RÆ– Œ‘*yÃÝrÈÛQÌ'RUÂù†YT<÷Æ»å=Ž™ðáÄhÐ_í?%ð;.r¤qß{œÞ}ŸQ`?t¤rà¯â¯µ>ãròý_J#"N¿Åq/‚uN²àt¿ª3£/CQ ø?c€üàE¿úvð îWã—É Rãd²ùf5œ%ò½TÊuyнͬRóäß o³‰>OÃbAÆ#Çÿ2üÛW;­ :êIãìŒÁý³Êàæ;ç4vdDâÌñQfŽœ¤ŒAႉ:£ØJé[7c  {~â«esàë!HduG‡¾žANÌ5ú?í MÞÏ$/˜Vè™@Ä­ ô,ŽÕÊ"#Âx”ï…#»æÅG/s¨Ã IBÙ;h‚O"ØßÌú³Ð[òmß;]¿ Ð_B±'ŸôK碑\¢¼Õ3à,r ö‹Øz}¸±Ü˜ætg¥ãÄ%I6& –SuUŽ£¡/ÃW¼ÄwU¨Ù6bÉÆ‰t|Yºr€¤G«öq®-¼Ô™-ÀáÑèZ³ºŠ±nh†o!«Ê¥Ë!Eðd ù³ˆ§ð³ΟYIä½ 3ü¦yÍ£R„›Ž%‚gÕ† ÉæbûâNãyͲsu w^B—ö§=˜[$ÕS­Óx‰Ü¢QÚ6þvÊß3 ZŽ‹þeîb1ñž¸U…PhŽŠR~4Å¿æþ'›ÝIR©+ùþr§æÙ–œb·ðȱóˆ)Öß"{³ Q¼†ÿ-׀Ћ!­‹Ê$_B34 “FÔR{}ï ž¢m¯FhóòÇ º}¢ž²í*ô—ºsÛ ÜíÏ$ùÝNV£žÄÚ Ù¿Ñ0ܲvne ­hSQŽæY….»wÈ5¬âÊ)Ô=W†’ؾ*”u¾ù1Ô›4ÕÎÌ>dÑjÐ&þçP‰îðWÏ-âºÍÄ[Cs¦Êà,¼81äädê&Ÿ‹ëömûÀ,þTÑ&xÅ“íÐ’ÚUl_uw‘˜ó½ÛÛZÂÐÁ´»÷ƶBâË@ï‘·-^ÜÙ©*¿Þäi|ÔºæùG¦‚qº¦PÿÍE_9§½¯ ¨nƒ@ÄÿšûT’¯²)t’Qj½yΰœS,_ÁÊ/ÔÐïÖ3K4žÍ ¡[åÀŽÛ䩸²ô/#C‰…‘‘ÍwåXœë•Ï4~hqƒ1Ûß´ì{¹e%g*ÒÓ(]·2À…+’wïß~{K%¨z â"W[ùèHxù)ü­Š$€Bì6K¥€ž¥âÝ 0 çYŠ ÎÓw·4ô ©q$ºz-“ßEr•¸ ܈ßb¨:ÔDò¨×Høîv“æËˆKÄõì9Ù·çܽû’ Ò¿xèSrÉÃxÛh›†íå‰OU“°g$qAÑÿÍ÷`›4ÄþÒÿ­k.ûd/ø]0JrJ\OœSPÞ|Ý"azâ%Û/yØ~eÅÃõÄ+š IÃtÅ­Ì„¶§XÒ.g4ÔÊå[Š\"##‘¿ÂéÿÎß 2´m‘™i›_^™ðè9ݯ¯hŒx÷›‘™µb3éœrRƒí3ê?ØqrÎro/LÐÐê±KLì£w•$ø$È묉ñ§Ñp›=;ÿ4¶þip üÓÐ"ø§ÙUðO³ËàŸ­¬ƒ\ÿ4ºþif)üÓÐZø's1œÅïŤ$º« ÎÎYŠÚñœläý›Å‹©ôyõ]E½:Ž)ÔEj¯^~ÔrÕ×a”¿‰ôŸvHª½W›a\ùé‘Òqüš¥QÆéÃBäªcüö¬ëÊ p…¶;|Jß§.*ÿ8ù¤z‹âáõ‚lÅØG¼ÓæåAïÅ8›VÉšÀš—óèkðæÛ(\[¶ÍY¶•ü%ï ù­ŽÆq¼,ŒäáËÙT«KÀZ§œï¾C|É ð•¨?Þn“·b*ìânâ¶ø{Óä~4³ÇBMTUæä‰g4Á/Ûå|±=öàÊÆ%èf¼5Iö+‰LFþž —a*ÀãpÁùؿډç|’½Ã±üWLeÉÁ–áü¹ØÌ‘º=ŒÂy8 ©àê$Nº?øuŠ‚äé}l/º:9|l{¾¿¼ÐBúÙlû­TŒÇþõùß*° ÄçLÎ.Û=ÏÇ¡ÏiÄ»ÿùQ? ŸzcÏßJªÐHx‹Ï6Ó­+ÂilG3Ót£,Š8—´—Ä÷¶«‡¦büÙ{'£Ç4Û9¹F’ýxO¸ü·C¤ýRláÄ/Rr¢ »KÜw4`Nè¨á­9 ±B& ;ýD†+’¯ç4dÚüD›Ÿà„,‘?Ó€isû3üBÖ ™´ÒÙé0'dWÈ´¹ý…6ïhÀ´Ñ|Gû€w´yrG[]ï8û…Ìt´u{D¦ ç'Í¢iÁˆ64þ7 ˜æœÿ7\e|…Lš'3‡‚äìÂùØS‡Ìï=Û‰½TíÂ?Ûñ©)ûØ&a\‘Bå V´¿ÛþÄ@ë^h,Hãпóôy‰C ¦:ÏÔv ²¹:†æ2½ûŸ? •‰W9ÄÏr’²zÃtæ…iÐê{Ûg§@á\¤ò“ŒfvDrR’#ž²N åW }‚XN,©‘©^šÁV¢%Qê9 ÷[öÝŽåÀ䘟ÅóìaÆW1ÆÂsSéŽ\¥0¡ÿšwHô»L3ãàæÚsNÀŸs‘áóHÀ'y É‘aȲ¿‹q¼ùÞÎjo:»‹½G;$b$òpj¦WdtŠXÆM¿½{»:Šâ˜¿:óò—ÉL¤VP¥i;©À¿¨«I?ÚÁ8ã¬rzúä-Ï`Yír>øG;µX£i ~7 UwV=´P>äãlŽ\wLÜc²9‹‚®Çêë4É2b✘oR¸®§\þÁã].Îi|¾ò½ÁL|òæãŒ2Z½@Øñ¯…#ŸsfDÎAÍl| ä¥ú³íÛÏòÿ9ÉéÏvªDAu"°¼…gª2ç×HnƒÓ´döGȯˆ0Û -š÷–1$^#ý•NJýxDr£µ[LiÙ7áÌÕ—œ¶…Á4ôY© õ—ŸŸí`ŽDרù¥Þ>úëtFòq_}÷6µYé篑žÜ«ÍǽpÂiàÑRz_cï™iMævðl3&±™à}½C§ôÏþm,(ÝtŸ¤Q:šÙ[Ž eôÈ f2>á˜=·}_ùœ?íXšO:ÃE¶£N CWUÔÆÅé‰J8k/7iÒnQk²ºD—ÿ ‹­ØÊÐQ/ÿ”pj—†@•i^ P ¤ñó¦{a÷å6§SŸå¬å8´oöÔöÃ)Ãj =¶ƒÅÃo_ö‡÷Ip,öþ•ÙÁÿ”’˜½úfÏ=NPÿMøÙ”SÝümf³²žšs:öÍ‹”´ÃùC•0Î#‹Û.ïd‡»2x;coêvq\Å*:Ðq‡ŠåGÂkØeá³ü/îYÃÿò¸gˆÿËû®jÉÄ“­r‡$¯t;LÿžÜ x”â7ê÷·b‰Î¸ûíõÚé:ó­—ŠnÈ»:EØ4öÞãÈ!>¾É‘7ÃWÊæÐQˆŸ˜9r²õ ‘ÐÙŽø^ð°ý=9t>yãxëàžˆôK²ý^ šI_튯¾û%iŠ¥¥À~Í<ß-½åÎ]À£GÍ¢ž˜[¾û)ö?ÖãS/±‡ªIžJ)ÊÆxϵ$ÒÿËR–Ðà&{Î.=ø°ýÊ8…„Ú”ªGKø<ÂøŠ$…W?– ©¦W(uà™ãôË»íg©oú0ðÏß°Љ†KhêÄÕ¯usæ©ê{ä†ÏVPgAÁA8ZR| ª4s=’dX=4Ï⸠£ŠVž¹]dÉìÝ{;µ‰øÜüƒèûîÃ>|þu8~抱:ßy‘ÅðE,¸r×ãˆoÁð·N¹ª*ŠíY ;ªñƒ‡[<Ûûfü·P¢™à„PƒO²¢Ùþ,Wͧ÷’j$RJKîìtöÖuu(€Ÿ ý×0ô…(5YFÙŒæxg'iÁó-Ìk™ø<œ$ìŠGM@ùÕ¿…!ŸˆÜq+g¤1ü–è6¹99<¿9Kòà7Ä@˜Ÿ\x¾Äæ:þy¤f"gåÒ×>cA\ƒç÷delwøˆO¤íTÎHTš3Žr’Ü}Ø^ÐIäG.‚ïlg¶^7~J~Éñ(â”êšr ¦oʘÎ)ÌòˆJŸÒŠù}ùóõƒ!ï³y¤8†OçC¬X¾Ž¿ Ÿ`ОzDøÔTŸ¤^@³=…qŠWƒ((‰+Ðð¯Ìö™øq¼9úA°¬EMÓfÓ\$ Ëë(Š»X¨ú/|ÂzÅ©té’å^$[ìÀ¸>Ø~"¨^úƒæ/Ýðtò”è£÷dg¡øÅÞÿiëAJ(q SðùÛVÔQ ÓOaø€¯« Ø|^Fò»Œì¹àmÜn]ꌾ <ÎÖ–&‚hyrÀÅw ä/6\¥z‰¬rmÏøb] ÿÉ&§(>Ù w£ñIØ.k›T`ÃÛO¡cûê\”ÚGŸCæÇçåÛuø/o«gV“åràÛ/HÈËjƒ?îo©ö‹X0Sê\š˜…¨>öFÂËøÿ²Ëœ®áiA¡¤àm’„;€´ãÙ>K<¥oG$iÈÙ½” ¾Æ#ásâMÃ*äZ1è¢nºRÃzI×ù[|}?d¼é·Ë0òÆ>“ˆVY·b^ŠP¸†…#h!äû[ðƬ\‹˜v Ÿl+ê[— ÿ… ¯þ¼¿ðÅËe’å‰ •C?ÁÎdx¿:U†×¹;j}ñ”ÚC÷b>RÔ„¦áSÏ×2½Ò’€ê–Š›dÜ­b˜²O»$· 1÷[hÀ1íÏSðïÂ~k6‡]¿UÅ¿ño.!w´„‰ÞˆîÞê‚uMŽOC#fF]-yR¯s“}%>3•¡àyµ2˜`¸ ­vHu ÷bê%òû¾õý%Ç?/‰ €èªË4¤Cº%)º[Âkqœ1©r›ÄÀYR‘¿ŠÐ'œÉ;årÉ-r3g†gÙw\:Æ=¹8 ¸çΣԎÓäŸÞú˜žD£VUæC\µríø$‚)»Ã²1qO¡„>uKÞNRrx¾¢úUL˜»‘YæT|êîÛÀÎ[R‰o§Üoý-θzú}ð½häMY ôb“‚@ü3¶#扶§îÕs³¦ð‰ý#â˜qšÆoÝG;ptQN péC Êé{s*¸sÜ{;˜ bt«¼·ª\Êe=)T‚§œ×l0°"6H(g ¤Ã‚ ÖyAëj ß·£D¸zÓHHå.½ÔU4?]EDˆ¾5 óKhle<«6}“å.ôe›$Ôï [ÀôÜ!¡4Cà y±p«øåÕ•é†ÿzá7ÿU6ùï¿9Žô0Iª^ôÐtÿ线[¿}ùÃ}ýãþÝPÿàï¿¿Ö ·>Ý]öÿÓÖ¯·¿ý6}³Þ~ºýíËçá—o–UüúòŸ¿ûýí}çÒúö¿î†Ë&3¹/û[$rÏ!Ü¿É1s(P¯»t „lϪׇüèý¯Ÿ¬÷Ã/_ï?[Ÿo¿,ÚsÓ¿¸\ö×ýN·9è‹_zÝþÁ€·¿­ºqpè†w£ÛO_W&tßt»ýþåEÿ¦;¸èuzñËaßDýþv´l–Uc4,zûåÃí—Ûoÿë¨ÿãÛá7ëËÛ/µýù­¥Îôÿ忬΅5ü×Ýò·½‹ƒ¿¿úq闋ÿ´úéògo®n®.oä—ê__v{Á•øouŒ£o³ÿ÷/½‹«ÿ§Îï7~,›Ñ©õëÒÀ\\õ®×òº5ölÇð]§{½=’;Ã_z½÷ŸjlƒÞaßcùã¯yÙé6׿.~yóææµÿ %z¿^Ó¶?“Dèö™Ö뎕¿®×µ£?~U^áíÆ'¿xsñÊêRIW¾; .ß8üçÛcàªÎO7FÀMÍŸn}þáM=»·?ðMÿÐÏ[üzÝa7ƒ:Ì/}Úz`—ýН×¼øï·?ßKWñÛï'=Q½ßÃÞu¿V¶?eïúà©Zü¼ä¯{u¸š§5aoܯ·ï­ ù[½å¹øyé“vý¡5üSµcøí÷¯ïW?>ì·w÷Ãwo¿ ß×°tøéC­– ÿõnx÷íöë—Qéðh(GÛ·ß­¯_>­¥‹ƒ~üé[EÌÙyÓ¿èto®û—â—þà ©ªÖä )¦~³=¹ßtnº7Ý› ñËÕÁÄõàÖž.zTxºüñqá©úõ¶O;,L̹žP-[ŽN»µ~¹¤“ƒ«{ÝíõUPz}ð7® J‹I—?ߌI»ƒZ?^ЫAÿ¦ßÈPôpëïß¾¿ýW-‡óÛ»wrŒü9´Þÿóíý‡®õîíõvô¹Æ8Y!Œþ×—wÖ»¯ŸïÞÞ­·_Þ[£¾½³:8¨.ªNÂà¨ë:P_þx§s·_>Ý~Öšú·rˆ|½_íÙþÙÝÛoï~ÿ4üsø©Vp©{ÿ»u?ü4|;Öç­ùƒßêýà_ÿ²Þþzký9¼ÉÅl¹•½8lÜËßûv[çÈŸüsøöc­¯vûå›rJå ­Ûíõä.³wy=è_] ®/®ÚcHå|‘ÓCsEòçe+ºþUÿºwÙ?h |ªNõÞ\ö››A¯s}Ý•€—ÝAO.æ7ƒÎAmú´;:ÈÓªHuÞ\\÷»ÝÎU·=\ôû=\ˆ_:7‡räý©QéS³$Ò§ª,ÒåAóçSu©Ó;h}ªJ$]Ê G­¯×»ë›«^GŽœÞàªÛë\].ºâ¿)cÿ€U‹·D8,)ô©:§$[Tó÷«ÉÑ»ìv.d›zŽ 6{ƒ‹Ë®ŠtnÒ×/¿åÿõŠ÷8 à†T¶½Öýüù_µþü—¯Ç¬Žwßîßß~øp´{é\zyDvòŒ£ßï7ÃÎîÕåa?¼ýßï¬÷_ÿøõÓÊâƒÜ_ñËŸ¾®w´Mºâ‡·_Žú™@›æ–â(ÿ^ÿ×=öww_ek‡÷Gýt9¢Žùñè÷¯÷«äN—?”ÿså?õ>êÓþS ‰ú¿Ülu°F£a7O)Ô™ëúW5pK½?ÿí½Ü'|}¾¯ÿ»:?øc_$X·÷‹Ày‰ñõßôß\ý­{!W«^§÷·ÿû^Býn§Óÿü—þÿóúÏmGZ/Ò,Fq©i6&à Sí¹[ëYÿùZΉü,Qÿ_ã7Ó ³|/Èžj1=ÔÙ”>\×ÂÖÖÔýóµ²À«C þx-ü§ëK«Ö§ÎPƒ£^•ÛûâŸÝ)¯øSÄJ@¶ðÛjšn°ýýwa»òèÿBñÅß]ûÑ{z3‹"ý'/^°8ÿ£ÖÄó…å“põ£î?JŸ#‘¬~õRKñ«Y>¬Ð;ðÖdá®~Ô?ôGÞ<òW¿¼þ+?œNE¼úÅå¾l~8¥4˜ÙÓ¼<÷ïïþÛÛühÅsÂêŽnþ'4WåŸÙøþIê>¿ñgÐHÉÒR„ó÷÷šìµo³ú“ÿý¿©­ÞWþ|`Áñòw÷â¯L$ú1£#~v‡iè„~ŸŽR;Í’w‡Ú)öÓ“=ö;þqå«åOúÓòcúçþûOã„þìæ=xÑÆäßý×ÛÃb÷OŒžçãÐ?¨tëïÖÿþ2ÐÝÜÌÒ4rd'ß&ùÓÃÞ! -#Ü,¾…ú¨/6ôî?Ž’QǺ»û2’›|ý/†ª†~X¾ÿ»œê· DÿÕHnÞSÃáÕT¤J_tx7êZGÃ^©¿ºŽðù:G.&€> }S†“t/öKлCHý¸z|é±u+WCœRçâ¢Ó;dnüêo'E¬Õt_¯¬*ÿ6ÿp%ÿ›hçç=¤=~¸O^ –)Î×7uå_~¦þz)XO’Ò °GC99.¬Z¸wvlÏëvé&ÄE£Ÿ¯qlºß}-XuV:ó ŠX–yÕÎÕËÚ«ÿù¯cíù{çÄ{[@»ZÍøÆ}}ÔÏë|¡¿ß‹4‹ƒeưs@Ù^ù×#U8¼žÜa$b; ãÿ÷àv¿b«*ì¼è×ö›oãÔ›xŽg]mþ¶äsëz>÷½ô¬qæÈ¨Ï[ö×*|8ÖQß+W]‹íà{ƒ×³¢å_îsðâF/p‹Uù}gøØdtmÁÕ‚úÓ‹Óú}òOa?¼4”ÿsÀxîÔ^u`ãùº÷zY^ù·?Éx¿.ÿrßxî½¾PÄ䣹Ûl4o€Õ¢ŒÊn£èôªwóz!ÙÆoÕµš¶‡ViˆÔ ®÷Æ´wYZ|Òwá½Ü—\We€+ÿ®÷Gì +6€ç¸—÷ª>8¾hëîvò! îñÁ+¹àWÿs|‡wO¼Ã³Øƒvv·{uÙZg×^8öàжuq íl÷O_·;¯Ö%äÖ¬WÛ³•ƒ†ëîÕëgK¿=± ¡SÏü½AÃob4tÏAC=4fÐÐé^_œƒ† ´sÐð*Î9h8ÀŒsÐPû?惆õº„ ú‚†NÝã§s°Âq59ëÜ þå*ßéLEªN/•@YͤÒy]?°´Ê\]\Ÿþ\¼‹½G;="ñ¹u¢sQ/™¿åJ#èzײA§áYxüGjö$MÁR«XiÚº¿'.6¿ÒxÃÿÓfWïßÂZÄ^Š-¹ë·Øåµ‹ÔöàœZ¯ýêØ0íéŸòO·â´Uô€ŒÏ7µã3ZYw¯fmØžp«ÛÉ/%N kþàz±•(-ûZà««E­ÔÎý¡×ʾ׹i¢W69 .eCº7z#UÕ—÷K{ FÝ%$¢NH›ÖãIè7m´õê]uêÕÓÁ¾©ˆb¡žšp[(Ôìô!êW÷"ò=ÇnZo\Àü uÆý›öêŒ{è÷nüUØÑêð­™-Ù3z¯U²B]+S·ÚºË¿[^Õ—Ù†ïêísrâPÀuˆ{uÙm\`üÌv9^jŽo³8\ Ðà¢5tyQó\æì€ö8 NwùwêOJÇS7Ê:;žC׎çzÐý¨OØñ\5‰½½Ábì}q›þ¢i^Æ:2 «NýlÍÆšÔ«·»ù)†Õ xTýn'³¦;ý2pË?1GKñŽÒ=Ç;¯ý°^¼3òþo´î?*ésÌC> ¾=?ïQp­¥c\ùx0è#ÌãlTCµnrwó®t±ÑÄUWÕ>GÏ5uÉßêœ3¼ !âIÏÕÏïíÔ®™Ëjî]AÎ:ÙÑ®uó^6¬ù8jª×˜é;—7ȡƿ>oeÀpü¼­'žqJó¶V6~ï¼½*}–Ïvü âšÉ óÌ=¯4s» «ãZœ¹ùÍÝÎE§Ñ‰êõÅBlü¶E²£0)ÔiÜè@÷®åß)KäŠ{W¾e|ÞÜü¼¹Q2fçÍÍÚº»gvàú`ñ½›^ãºbãû›åôÄå¤:½ú¥E»%>[ÒÒ†3ˆõ2[ûjBT~éí—QÚKãÎõ¤x¸þöãR\èt~OÓ¨¸ R>‰üÿôòQ(ÿ;Jû‘íÉÿMFÉpdߎn¬áЪÿÜüf)€ëÕN³…nÿîØÁº}%òä}ÃÆ-Î^÷ªÞ]˜-ÏR þÿß¶¹P"Ïjàþõr*ÍlÔ•ÊÞæ5üÜG~ïÃvˆ#oVOxsÀƒÌåßþ‡O Ó«Õ —ã‰tÖ¨sÍàYcØéê‡gmÞ&Cš¦Í{qÖæUã¹þÿY›·Ñxæhó6ôÏÇkóžÐX®ìÆ•_®Ú© jy,ðÌ{ù—ûÆrG5 ¤2]‚ªC‘WÍ2¸g¹È¹È³ÆtM´³\ä+8g¹ÈÍ8ËEÖþÏÏ+hðŸy»Þ€\¤ô©Í4ŒNA.ó¸ÄJ.²çÄÂ^mO΋þ«h'®%ùÓ®ù?ÕtêëýæT>&ô.ë%“¶Ö¯ · \ÂúÍÞVª­vª÷½k–"© …ü>îQIžï¦j4ê.·ßü%%³~A+Š6ð ;à éšåÄږ輆dï—׮ʻ{aP­ÐyžÛc³g5Î-4WLìÌÏWÓ¿×:ÔØxòòžf}s3a¶Â] ýñõIIòÕvÛ'É×-+ØÉ¿þ%?“&ߺEÈpså;ð‡/‰ò5<ˆÿ£^¡û GB#9‘³”ß!¿|MʯayÒ-å×tk'ŸÊ#°Õ?"ðãÁÄUKð©‡?ŽjEoç-ÉÁ€ëˆöòJn1Ï[’2ZIF›ðí^ü ß=•Ôå¹ ŒÝÖ Bφ‡üð( óxjvÖ0‹ðÃ"Ơ¦\ĸÛi&­ÝÔ”÷ÞôB]5ìÜ`tXKâCM3ßk$\â»ÛkQ±ú¬ð{È/Tømè¼~…_9–Û»œpVø=ä—)ü6,È:Vá÷„Æq{JÕW½šÏ ý$ãs5²sq—¥ sî5R-Êx¼®õ==ÉIL:i¯ää(9‹MV£Å&_Æá‰Mú'wöèÎ>‹MÖþÏYlR/^ƒn³Å«®Ø$O5²æ{½{÷"rÝn²TóûN½àN¶|Æ®^ÒFÝzÅç5ìPÀòˬýÆÇË?íæ«!y^ŶqXÝ“ÿäzÜìRÖ¨~¢Ú"´†»±¶R!£RÏ{²j´³fêË8<{’§?í‚vÞ–uëÝ?Ú'([«„p_^®z'¥C yÀ¦{QVmUÆýL*´Ëö CŸ›F¡ÏYƒ6× mxT|´ÝËN£{™ƒ^­+R?IåÔ%ä6ç†ôNµèpØôôë(¡ÆÙ×å•Ôg©Y®Ôlç,5»B;K;Œóc¨kü92£R³ÝË^ý`ï,Í×(>0 Íw–š-ÐÎÒ|'*Í'Oýò»³4Cšt!ã¤ùä¨j­8ù겦øñy9{u9Sšbg¥Ù5óDéâ,~´Êóô›­ggQÐ~x˜(hç, š£EA_Æù1ÒgQЂC:Ù#îQžEA7}å¶(hÓ‹`›¢ ­oޏx–Ý#R¢€Òì¦ nt\Õ}‡¤<6njÚ£HÕ:àÕ‹pË ƒ:Õì»Ãa”Þ(~KPslƒNŒÚcàÕ!Ðë^6ZB®/j^V7Daâ=5)n€, ×ò¿ï”%¥ƒ‹zÝ«ú›°S亄=§fyÖªÜÂù’åúi7cx­J-)vò;2#Z•g´ƒþÓºZ¯{ýïŒ×õŽWŽÕªÜºÜR±RÊ¢*<‡gËMœÿ ÕÒ¬ûî ®:õŽÙ±¼Ï‚ŸØ}­û¼wýT›HXÂs—Œ‚Õ®œäÕT¤ºú|B¬ÑˆG>ƒË!ì½ËbqœÈØÆ…®ÁM#ÕàbT"S7g½PŠ^hÃôvI/´åìv¯vEÝùy­Šçµš¥¹×Ïkµ›æî×~k V×¹èÔú&8_³ÜÊÙµ4¹7qz5…I+NZÔf´s5¶]k٠˱}¿©Ú<¶TªmïVûèSq³³;€w@™”^{o§vÃ7·Ð`¯‘Éo\ÿ5²³¶pÏEÑnXQþÃk Ëq\?X?k 7Çmá†+ï‘ÚÂ'4Šû­Å×Ý«v®÷´<Š/@§ÿ¿ ”Bö©m•€Þ`P?:89…lHÞJ!»Ÿ º.KiÎYÐíÄÕ° Ÿu/šé mŽ1`NspÙHö£Óé¶vƒ¼éqxéqHà²:~>_–[¢1@ÿêòG8 ‰½G9sëõí Y1¶€S¿vîf†±Ö›ßM¦=@˜õȸ°ä"ºµ.Ùîu£ÔNÕáiMÑÜC€Ô? ÝCÙ;¨S#¸£|C ×°=Á—#—É»ºht¶öƒzŠÖtÜ; ïÅÜóÀ´ú!óš¯Ñ˜k~§ßm|åÕpäyqSoí–1PeÖ{W—Þæm[f½æ¾ê™õNn?ˆw¡ï g¿Úúy¢ÿ½Ã?k«o¡¹bbg~¾¾þ½ÖñÂÀ“k7먥g6Ò9_ÕwÎ<5ðæ ràÌ„óPz«¢áëçþ}hç@|kÄBgx#ïÚRï¨]ZC•÷¦ÅZ×2ï72D¥±LÏ[°™]v®¯~¬‰¯5‡›íÀòá…œõÍJÉϲþü°‘¬Ó£DñN§ìäú¢Ñð¼¼èÖ;Q;Ï×d8ÕŸ¾6*öêìÎr¯üð(¹×³zyv–{=U¹×Þu·Ñܳa…aÓ²ñ“R"ì]ñ²ÆY‰p{Œl(ȉ(ö{Mê_þÓ•ëƒU"ì÷¯9ˆ³áZ‰°ùî¼´µm¯Ð¿®_á~b*M ¥Cô k*5… ×8ÿARM?ÙQà‡nT7³Q椶VAï§æ‰Õ!z?¾íº¹©<á»Ê&£îÙ…j4¢ í_ ý´.t¢†"ö´^ÕµÕݧ^ñhûY­ÔöDlw›]³•ümúPà¢Õ©ë<Æ‹|ÂïØw|Ëy´:aÔkøžŸãû~9ƒ¾Økú9¾b`À^ãôêÞOÛ¼îÛ†Ú ààd€x5³3¸ñ$Œçvàˆ÷vj×xwúغÓ‰$ñÂ@ÕïGÉh`y»‰Óá¨s.Û×hÜ(¼ñsŽ?mîÔ)Æ.:¡×ø.þO›=Í»ê‘dÿ%%/8aàÆ³W÷Žnƒ¦Ð¯DÕYÿ~%ê2‹äÈyeVçªôo?Ûñƒ8—dQ£Ô‹Ë†GR?iM–‡­\6¬gÿa*)òÙ Ü>Ü4Ê×·­:Û…ì–ª³×ÎL8I6ßSN1JÎ×S–hg¡Ù—qÎ…‡™qê¡îæØÈ¿×´žõ'.žpf–Ä®¥–±ôG¾¥ÇHƒ×r)î­úôi~TáÙëzÕ¢/ Ï*mÉßÃ$=ŸãçhgÍY°æ¬\Èßm¤©÷ãêÍ^AC:HoöZ?.r~˜m…vœ-û¥_ÔÌ'èÁU ãdD=¥j¤›qVœ=ä—õgArž?¾â¬[ŽÞk+ΞÌ#¨±o«ÆžUØ7ш‹âõ Û°î?K…é@m¨ÏŠÂüð(EáŸD²Z°FáÓYQø€¥(Ü®duëÓ ÑîW³Þªu¨2f÷BíòÔߺ÷Âõ¤J€ã9åhgL°@æÎHC&ÞX8 LÈæhS'³—ˆ¼A¤"NŠZ®­ê„ólÿw¶ŸU3wжÊôèŸÛv~°„mÓ2Ùõ4GºÕ&U±‹Ë&e±G”xÄ— îë¬{cxu/VÅÙÞ$çZnGý#逵ªÎ¹t–X:;èŸå ×`Pq‘ÒÙë¦roÇüºÒÙ)Œ« Ô="oP?‹¼?{Œ_.%Iê$†^«»U¯áȈvy齤"{ö°Ì»ïMËlRë`¯€´¦§yÚZ±YìC²æ±ì…lk=*œl%ºî\Þ4Iž´­‹Ù¹€¼0²Ƽ #¸^ü‚6æY³í¬Šù ÎùrÇafœúåÄtVÅ|í¬ÔX:|¹¸¼j”,V4\fðºsÕ¨B 3¸êÔ poÂBeoꨶí?µéç±Ä“#"u2ö®«ã eä{ïBWôÕ GݳŒŒFãÊÈt‹9þ´ÑFâ„õŠàö žÈú‡6š¿ÕM+lœFÞœ¯n¢•žðK°Ïÿ·GwÓ ¥•¨ÖRSz^ iV†&JÛ¶ÍY—m í,As:ºl@Ò,—\[ƒæd\UÄ*ב9‹Xm¢=ÈÍ ó£í:~+é@‰X5†øáQCíŠXÕùAcHËf¡ñÕM½õá§–M·ÒűêÆH|_ï%Ô½ãPaÕ¡Œª«F)–SЧéaª—6ôiúâI8Y*Š¿žÍªÑÎê4/ãœsܯýª÷æô&°nêÎÓ‚„ΠÎzÕ`‰ÞðÃÎÓ“=ö~™„±£éãôjé’ï:áÎ…eåv<Ê^°¬Ü+ ^àÖŒüþ~{êQ¹º²5H¶¬¨cAé8¤Æ¯jïf^7½ºÒ1c-}Gôó¡×uª4÷-ë7ú¿ßICº]%Fµ~-´ô`vñ\ööK£Ã»Çá¨_çRÓY²ã ¼R–£iéìϪØz{£.溭·[O\¸ò6î!ìF€ªÚ¡Âô?núµÎIét wp×ú±´Oët.õ¿±äßX3;p}qÞ V£•?^Áau·ºÕìí\j ­Þ>õ²Îs> 3ht|]¸V\&à¦ßi”Y= Ql¦g·…(:g!ŠWÑÎB¯àœ…(2ã,DQï??ïm†³ÅÿwrB7ýfeòµ…(Peò°£é>ûc…€ÅT¤ò/>'Ós­[ŽÆ &ºƒ ³Û @é|>¼;ŽºB 4ÂíÍt6wëì˜ön56oN¿«÷´Ýùè ¼Ésâùò­¹»1§Òhg‰'ð9Õr€§¾šº ¦þ«ÑB•yÊ5ZÎ2O[hg‘–ŸPæIºFrµUZNÆ…Pežr¥•³ÌÓ&3¤¸øá”âÚÕyªó+‚`ÊÍM³b»³ Ï?ëúóBö7îBv–ëÙA[÷öXÃÿÀºydBiB#uS×G”—µ šŸP¹o\Ç«ãp÷îÔ•;µxv:i¨ï¦«0¼ï«’þsU±XvÐ? ¦¬ÁJ‡jÍ07Š?®.fF‹?´¹ÇW”¦0ªü£{qQ74Ýð¬Wõê§ rXz…ð’ýßÃðAçWnÔ_-«™Ã$> çÈ4ËÙe„WšË— k ÏåZÙ•æÉ¼ê\÷¢öM†¿¿Soâ9ží×n6î@ jÝ (ïršÇsÍt‹ýs•ƒª©s¼=+q«Ëeí‚âS†Â$ñ—ÊP׎&â, U í, õ Mê, µƒs†zíWGW5{ ±p¬°œS÷âê¢Ñ=ÏÚr DÝHü†ìB²’]8gí—hÄ…ê²ß9gí7ÑþÓÅnI{°ÄE·sqÙèijöyTÍ0ìjýeÃÂÕwë»ÓåÐÍ«õç FÝ*ô» /—Ú¼¼¸©7 w“Tƒ è&:½FW Ú¾{X+‰õúÝþêoß¿‘ï9v2¼Ó¯lz€áý(¸êŸ¨„õUñg‡#ûv4°†ç÷ö ï,¾ŒÃêí|!;â›öR6§žFxXÍîe¿é ëIÝW<'mªuô5…šqnE€±^ðE¿Qîæ‡½³Ø°J³|gq ?ÎÎÞî?2?Ÿ÷9ÚùÞ"øÞby!]ÀU£»‹?îÅ#êÝÅüâÑùîâÚùæÑ ]^l÷º‡ò<çÀüùêè%úöê‘‹Í pNáêQÍuø¨«Gwçç•ìoÜ•ì|õh­tõ(›L6p=8'Ê6ÑÖÝí‹ÀR]Žà͵½~¬scÆe¯n§Ùû5ßfÇ?°ÞìJ‹¬wº–õÿgïO›ÜF’tQø¯èSkºnMö%­¦ÍT)j:_U©òˆê:ewì I"3ÑbÌ”æµS¿ý".ðp,ÌH›©ÖF`,¾<þøjÞ|óô‹ÈÈz„VòŠÁl0Vx=Âm>§æ:ÔÒ|{›!•¬!qñ“ÍU0‘mIoX.¨$´¯Ê7Sqg1¦Ê„´VjnÞøG:‘ët"Á2 ýÅ5°²@ª˜6òŠü”ÖÈZª”ÏÝÕuMTȤ÷:àðçêDÜh,ça¼Z5€@>N×êQ/M–‹œ‘#±í¦1tv/{–P“òÆ õÈë·ñ‚ý›F*p¡øÑr¨À7¬¡2ùgÑ2 ¾AãE~IP˜£ {zO#µôS›Bôf“Ö~+yE ¨‚Ìã^(' ²Xô©»ÊûTÛ+HèLY(gJ5mæÎ £È²G,n)÷OU¥t½ê¥‰íi©¢[O_¬ëõ:­ÓŠ-_SJ#ÓAQ ©œ„Τ¨ùT5/ÎRó^Ö‚ï¥ÉZðÓr„5íbçppa‘qeõw×™N…jª…R¡ª å° ÂDû÷„OåbëÀ§‰»Ÿ–Iï»|yŒ£ø"Ò÷Ñ4ÝÀ• CYÒР]+ì¶?Ÿ_9CŸŸÛFÑÉwVa!ßæ½4±n 2£{Áoó*=†òiæ×ß'n7áSm¤/-BÉŽ¶t¶5§J'Yu”,™,H“%“Ä%“ĵ’ša8˜;?ˆ*‹êd•H¸E"™4Y$rZލÙ÷Ä”¬ýá=†®‰îïÓËO{²þx‚†¯Y  Dƒ,nŸogO“§© ÁzÊ«Ý^àÅVÂs‰ÄÑs8'n˜f9ª¤›/Kt‰æÅ&ü6s?ñIW{dî Ëau×D±ØiŠbÃp:TQ©¼ÀónjwX„!ûÛLÕ¼ó×áÌÛOåæ%ýCuöèÇ^ûa²¾y™L°w•1@¢D  KE˜Þqe4¬*{\™ªÌÑ:hF–É”o­4‰);#G¦L"ÊŽäÈôú¹OqIQ™¸ƒj¥3y KC¥PÄ}®“@¤KÙu%µ47«ü¡º½*ãXÍ^°K®½@ÙØø”4âg¹žÜQAÎþ[C$Ø=(u/ªÝ€¸—Ai¹–Ü˳EàÇîe©CßHKŠ®”ìp¼`RD¢ZŠÙSüÕ4A ‹ñÇ_5P#ÌFMUvBàê‚®‰i`HÓùS©‚y¤¨² $þœJ ý@Ó©tŠg(²C d>q(s=ŸICG5\Ëo ¹mËo塎@A2+fÒd«ï ÏP± ~ñ[†ƒŠh·,•F1°²Ôà¿eØê M–¤ž‘#,Š,7ˆ{Í%©Ñ*ˆýÔ,þÿ Ô¯¦Ο­.Õ¡á *Ö¥ºq:ÍŸÑìëävö$!õÒdYêi9¢VûnsOÜK]ï±½÷ÐOþ7oþq0ÙO½"MÆÂ – j¼#Kaÿz 6޳R–О/¡½¬¢kËst΋ ‹¡âKh™º—÷g©¨_m}6MA5u9YGÁ0e[äÕ¦m8Œkâ€&Þ`m¸Ù¯Ó‰Èþ;aâ@®ŽåÉæœÌÀÛ¬ð}3‹JUµ†-½Ãg?³]Ô¥+Ùå%#švT0‹N1έ: üxF\&Á7¨VPŠ6Eïû:Ÿ†?•*1&²¥ 6†z¡:”4©VDc¨ØU­KìЉéQµ/Ù¦S‹:J-ÂÒ´F&&sXŒn)¸R›Ú¼¡´9wÂ*XtjðB,о”DPÕkÙŠ¦,ÝF:mi»ã®0ÂÖžV»•ÄO'»•È8~½4Y`tFŽ,0j7¡ÇñeQÃ?÷©~ Œ²ÇŒ0|ïàZ› ãêçÛ ãn¬_üÕ䳬ÚJhX†*3ûeiât¦ÊˆiÆ¥4qÐÉôªL²õŽ9^r°ï|ÍæmßGñ“¿œïýÄW­$JüÅ®Ÿ}Ì%é‹PÒÓBò4w†¶A=Yª—¾z¶Èâ+®j[Ô]»#„À]ujÊX${&Mò·ó·‹«¥pY¡ú¯¥ÆOÕR›¥¬¦¨•&«)èª)ʇ¬ÿz WƒÆ´ë5Y[QÓ…ØÂÐVÔ¦hvk0“ñ†™.u]o'‚£Ó³Š»:´~ŸèDj ('Oäщ¬éx›H  ÉΖfÈ&ʃk¢L×Ù{M”]ÜØ»¨´,h‰>HfƒÎõYbçÛ3 Âç Ÿëdb?É—Ôî“Á3‘Á3ÝÖ‘¸Únû¨˜ –œš´;R=_}Üb‰ÈÔÑALê—ð9 o£é9:VOæMI­ã:¨ÚMµýq¨:¾-ƒÎÀ17;MÜ;îù‹E4:R5íܶ‚@B äßÑ÷Óúþ¹ÿ¨¹á¹þofÖ¥ë~³œ1T†l÷FlÖïõ5€;­^ ˜TGàZºô]ŸI”hÜ×gÑ*X6—g†2çX/MÖgž‘#ë3ÛMcèYGYŸY#ç°Ø àIƒ´Ãbß/üÚ³ÝczŒéi#Ó»ç>ÅÞÕL æ³ -É2»Ì6CaÃÛíQùÿÄÝö ŸÖÝö€aŸ÷K‹‰ ¨v”ÓlU;­iû6B·qp~ æå>a²`'Mö ;'ç•õ »XK~•i‚ÁóÝš<4½ÙJJµ÷Š]1,¤á4˜m.M¯Ìr(K×ÖA’U#§ –Éç`ÆAœnV«t'wò5|#8¬uY}Úð´ÝÅÕŽ'’Öý×Çæ“bÛ´¼æ„¾*S™˜\uïuÆ üáé:cë>Žž>‹ôi{nýä1§¶•NÆNZ1œÒ^pÍîÏ⺇ v_¹É V5¥Z½Ü°wMEò0„‚Q ‡F›‚Q‡ÕÛ|‰>Ì'2mÛ M–Šž–#,±5¿”¬ÖУ<2«EP´È”(¯ j&®¿ókǵÂÊg.תêö¸1k*Ì©?‹YcWtrëdêÝÏoŸ%5Fƒ4 S;#GÔr<9RCÚÎvåyqÚ¿7ooã( fI0‡ÄŠö)¦–_·….“] ÔͶùê7Sqg1†©ÃÄu¾Ø=1¤¹N',“Ð_¤×\ö]Í„ ¬o5,Ùwõ ¬yCAv½¼"ÞUA机¦._F*ê]µ0¥ÿ–"f!nðjèѤæÜì¿Ùó3• .&NÁ¹Ø^ªßVxTdÑlT­¡Ó$ÜÆá³ŸÀi~ŠC¡¯kjðb?µØþƒP™¾öK®Kºöp†..eÒdÃ%ÿJ-s\7¨hÕ{÷%k>Š6½pʽ•&ðFë6Ö êâBsZ „ÅÙy¤¼ëšƒ¹ëCáj$·½ „+Q) Ò$ ÷´‰Â=7‰¡#R˜ÍZêäH Ä¹O] îY3p|>pÜ3A yF–®,bž—G_:[i"ôДÝÞsÃFµ_fk¤ÈÍÔP ¥w ¼Ž¬Š¨áÍÕ1~!Žzi FŽ„Â·˜ÇÐ …¯‘#¡ðmf1t(|t¿ˆ—Û6úS%æÀ×[zÔØÒƒmífêà3#kZ× «Œ/¢ö@³Áí&‹Lݲ&]þó}¸øx°Y7œ';ýï‡tÈöZ[)d`ÍvQäÃá†ÔƲ (GeÜÿ\ñ»‡`™L$gÙNš¤‚<-GC\z=ŸFb·yl¼eX&Èý¥&´ÀÀ è&Úr`u)CEÁªì$2½ù7#8„%y=ŸH {3A±7š³QÔ: áÏjìWÓ`9Ï':™Ø¬Ê35exMdxÍÐ4$@Gxx­T9lº ×½¦p˜}õžï=óKõYä,^ÄKD¡¤ªº ™/ # 릋ÓôŽ%7Hºï±äÖê%“ &ÿ(ÑäÒ$šüŒ‰&o1¡‹Ä泿³=ôP±Ä“×É‘xòvÓxrðÏØð䙉F—Ñ-E×”S1½QaÉu6ÿF¦· ˜Ü\Ï"`,FËí–”€…V¹Ýjdývv²FZ^ £ð“® ŠÇpéš’ªaÇ,\ÞGœ!_4ÝZ>6MAU\üxج›ÐVé?¤Óž‡êqØJH ï-i+˜c ¹ -DËÛÄaÏìTú?ãfïK$V;yE£l$Ié¡ Ù*«) vz25¤†ûÌO0ìq*Èzj ®*ÿˆ¢¯_b?LÖHpìAáæº¨X¸®¸Ì»¡²ÅØõ —÷ çâæì±DUîüy, çxÃl'i¤%ô¶.®{'á}8c,nЫ^R0*¿Þ»‚áŠ–Ž®M¡— ¦MnXfÇa¿Ú“ô“oÁl2’ Ö©ªžÍJ Ú±œê@Zhä¬H;?³ |ò¯˜žGüÓI÷h‚[uR-„繄£å@ˆIm°ãE ßJòzVvÀ™zþ‰N”!Àa¥’x€ßleO³É°šÀ_4õÝ&yd±é•óN «­‚¿º:ŒUâFÐ!ßµræj¿@Üïþb³'¤JëØ†ÕÛ3ÛKÉeŸºéj„P2Ý5 –ó­"Ä…ËÂzÖ‚¦¢ñê½|É%és(_š-¢u‰ÃYâck¥Éâ¥3rdñR‹y ½xI‚‘q]z2mJ—·YVñZŸtRµip1UøòC¾,±1™4Il¦½¸ù&(eqläM—ÍÀcSPUÏ›GÞf5óYÜŸTÅófß¾ùwᳪÚé¯Ù:yû?¹½•È(‘}úYü{¡Už—øñUHa±MCïk±‡Í`êyÑÝ¿¼UBÊ«™®¶5pÐ_)´¡[ ì@å},¨Õ~cøŽªƒo¶¤ÕÒÐÓÈiéA‚f&ËIS!‰é$ÙËeš8l÷™. €5uʠάYÔ ¶Tg(Ø1äp"üRu¶ùûyPœ$¾/5¤ã„ë+Ów~ZWHšÊìóÓö½?KêÅÓ§©çäì%2=I“éé3rdzºÅ<†žžÀ­i8HnPÔš´Ë½@Ïhƒ¼ÂZ_³&-C{Ïf´Ešd"WZfk)ÐåbË+Ä’ÀiHz‘z…–*ãA°z·ŸƒÉ´ÄÞ¶Ä.‹â ”ñkvXí¯éAô|v=F Mºð–ak¯H“¯5¥:µQêt˜‹F–0+ÆCl}-¡h{i¯B†J-0ºíª*îFƒ1øTtÛ½œ„1^}‰QÛJyçUÕÙ%™¬‘FÁSÅ%|’‰¹£ÄAzwĉ9W·‘É]™˜Û%æNÒØs®¡ºp4µµHsª.“ ^ú /ZËy¯V m9õ*Q¢ôgY×y×u^š=íÊäÝ)iämBiû„^pþn=Ku±+/Ówei‡Õ¾‹æß‰“ÓÊ%%ðhW{/.g±ÁÞWƒY§~îS (ŸýÌS %*–ÊÛ}„EKë6å:¸‚w1`û‚wí¡˜ª•áÆLš¬vG”‡Ôed ]Ëè¶Ò}8=a,"î‹R¶ÑÜwìØÒf2ßüótú¥Fh-¸7ÌÅzâÙaô²?¸+zèîøsÆöH¹Ü¦Ž÷ÇG÷êÕ)ÙÃg((ÕrA5õGí7Sqg1¦7‚IBËkü‘Nä:£5õþ”=XŠ'+öVìfx¡ûQâq…Åà¥2ø¦1EUi* @BUSF« ö“(þ*’uCQUdí%&0ü‘K#Öáö >*H >ÒTwd¥¯|”j¨ÝNÝõM%2XâŸqøŸAr›nNj8}šz¬$í^Ks/­¯bÞ'$5¾4¬Õ-§Œ ©â¨j‰ò¥³ t³cN»‹ú"° *°/i¤ µtבÖÁ©ÏÈ:°päSC* %AV2®?Ÿ2 S ª‘ú£½À‹- ¥]í¯Áa FPÜbwû0¢5{ÕI˜EÓIe²‹Ðs‹Ä5ÙdfÑ<¸Yÿî/Âùâw]¢‹' )\ݨc]“¼baL^,޵r0éüXË|­Ø`\¾öŪ$kדÏÓÄzXÉÖÍ41V~˜þïzºžLý›©îMd}J&M¢bÎÈfO3/GÆGtË™a¥°øÖi˜ÆšÒ‚ÆKáÕé¥E)SŽ3ּ䰃¥ƒì:û:Ÿ²ÉèV D93¹¡8&®{‹á‚ú¤¥{‹í"{9MÕØö_‰ò™Ü¼¤¦ÎýØKb?LÖ7/“ ž!¸8H’ˆP¢‹ëE«›Šó7‡qZð½~²LE¡[ÈÃ2Œ³¢ªP[tÎýªg¯.ž”il­¾V'·Nø†ÞÆ' O_(œ¨úœ´ø\xØ¥¢dK·‘,p¢Zf·IºÁ•ÉFÚ–*©µ‹H`@&M–òšŠõÓÉ=tÕ²Q]´ÇF…ùí¨vêgÇþ,¹ögÁ—èk°”º —6ô@i·ºÀfé „.8:f„*¬JænAâ„A»ûpð»P°Y7ÅëÒÿ~H§$…«nîVJ¿ñ:Õ{ÕG&Û:ñ“ÍŸ$7 ÕÞM›£Y9ü<ˆãeä%‘·ÿmO ¥âhØd"½VX‰šfp¹ôËôŸiØÄHáFÚ=÷iMZ÷Øã:Óp¶‰Zçeð2!`¶"%¶êˆÊ…V,Šæ—.®ä =IÓµ`ÀyªŒ OÊë`œ¸d ñÙ½$÷TÇÁQ˜ËTðéT0š“zH©`ÕqÁ/SE±+r.å´Ì/  ºP­Q<š¢ô˜Vq0ó [Œj2ÔMé]åQôõK¦%€¢ƒ žc®‹´9$JDü;2 í¡)¸âDÝTXC&ª³²ˆfþ"ðfl.Áúoœ‡F·‘yÏibåS1ïýY%2ŠÞ( f©&„/ÇQ;Ó¬Õ±˜í¡‚Hœ‘ÁŽHª–`üim:ý]k“ÏŸ¦ÞðZàãÀEdQ4 ßþïBª30†ºAd ˜H⣠©R´  ¥¹Ì*E§€qÅS«~Ìá"‹ƒj*tÓß¾‹“ð>œ…þü´\ Äß¿ƒ{³Ü[Á‹)übƒy³7ÌȰٯ>³ |¶<ÐÀk§Ü¯ÌúÛ÷s]dáÊóX=Ù¯¦Ár¾?Œþ0Ò+°ûC¦çz) ìñ\9 ‹ÔÈyX>NHRYXÏ:βP ¥OéÈÆõØtc$·qôíû4ˆŸ3ú)ºK Nm/P2PV(óagÒ£n‡wøFET¾Ût@`Í'Üpµ@þ2QR‡ñ×7ë €ïÏûì_þTêÕ7bõ*>RyÁz5ÉJhŸ1 µ•R-ÝqBê*È,¤DɉNX*îù}Ÿ§‹À¥fªñ«D.T‘ ÐãqaÈÝ2Qä:ã§0ÏQ€ñP³ÈÒßLš¤(±õÙº c—?æâïë¸äsxþ>’µÆß·×Aòaá?L˜›¯nÿýAé7“;y×ßHÿ¬ÊÊÚâjß§gvµ-Cïo¹éÙüA/~ƒ4‘í3žíQ=dØ 5S›t¯—a)(Bð 0j‰xÁ+F­Æì ?~š&~H“6—&MÚR÷[¬9»;^”ê@ï¶?€c– P2fZ³ò’¿‘¶ìY9¯Ë–íV¥Û®ÔiUZûÊ„ãHÉ[ÿ’Ààôt×Áìk^MDUitÜOÞ ˜s6/Tz}E„ݪJª *mš:ŠÁb@ðT`ïçvðTcýâ¯&Ÿa\óÒîl/P¢QOH#'/®·éª#k_‹ê¥™Ðä4q°þ!øð Rù¶Ôx³¼ƒÏ›%+Â!¹\ÚÀ½uñ·ø6ŸY ’&»þ¥sI§,\R+ÛÈÕµ‘ÃU| ¢œeàléA¼ 0k¾Õ›`¥wïs𮓠f·Oö ÙJ“Ïž…ÒÑ$| % ¡* õÊ•ñ=~üMòÈÿ"˜¸Voû®%Ó`½£åÍò>Rõ‡ ùœNÓ¿[ï?Á‰K[R3,¥!–a©Ë€Z:]Ð;NCY@Í2p¼ší‚n>"~_YÀ †×ð`xw?‹›YµŠfFØI¶oœ;¼Ó¦1¨¸æž$ì¯å«?|–Í=ßÕô²¹gIØa¡=çT/­Ø1CÅÒèuü b:9D« öÓgè?èSÛB!¥±6,+DVg­½ô± ¸ßRÛA¿¥ÎnØWs'§÷GÓ¶QAwCqAtå:ˆXêôq°ïýp±‰ÑÇb+$âËc½À×RÀa²5”ì%HâŸ#ÛB4a£w¾ë#h¥îC&I‡\¨Cî`Í´.í‡ ø„rÈÓEf<Øš½àâºDR°’kJŽTÌèyßLÅÅÁv±PÀâv몋oüUþ2„›5Ëü j/ øHT“¢)Ü2ÚûSP©ÞÛÈ+¸‡¶"íÂJ€\/½Párhý+E¿¦Iú¦êZ¦Û}’#0MEëÓ·m똴¥n«:º‡³Gd çWmݪÏÁjÎük ¶|rÛÈ+xTº®ë Ø ºwÀÀô†’­ ‹­ ñ4åChUh›(•/»…•º…©²[X{a²[X³Ù-¬Å$d·0ÐìÖ,nT…¥t K( Î.“ïyòJò==(,†L¾—“ïÈc1òä»N¾ËN„ÃèüVÛ‰ï÷ì[PжìD8óx܉pìm1]Cejà/-_$þ‘Õ±Äç5¯¬ñòè'²Ü0—&²Üеmd k2 ؤ¢&ØÁ©ñågé½Ò·”ÿµªAŰÃ,Uá{¬Šo•Èfk$Uý-¯£Õ÷¬Æ ”ÙãîëQ=§…´¼ŸçΩ˜=µ×]º·µDÃ+h3Ä.+§½Y&A̽äè.Yd%4×l9’ð ¬@f…'¼/,³¥;HNꮣµG·r v‘Ãa*˜?µX aÁ²¨”$6;Ü0¢*ÇY°ë_þG:‘ët"Á2I9Ø[t>ʨú¬ff÷a‹èá!ˆVØ/þò!r ùÔá 8³èGŠæ¢ÔœEöéG9_€ZÚ׋,hOGÈùDѼP‚–y³⹟ø„ËŒ{¡x¨öÃ˦ÓPÐ$LMx»£Jät¨¶-ç)Å ×€õ‚ î4™µWä‡0«š†l¹0MÌ;7/p º.“ÙzÎe¦‡Éµ-µ½Ÿ\æÐ°ðµ­Ž/„¤Åd쌻Hî(€¡‘™¾E2š³E´„5Y’ƒVò @:[AR2wZ﫺:¦Þ7;PdÞ¦ã¸B¤P4úkC=AÓ]½·4NR,gj¶ƒ"ûÓ]ˆQþKçh ˆ ö¬ØËÍ“÷$YY¥¦_/ðŸî6÷^˜ätRµõ–}º0Û ÷~ø\h"ûàÀD¨Þ:ÉSý±ðØ™óÈ ×“äEÂDÞˆ…‰˜ªâjÔãôP6H+pzO¤«­kÊEµÉ¦íäèy3Ú³­1J0äjs}H¹Îý Rö€ÌTnß/¨G²T+\l˜ÏU| ÷–ç#hšh;]5sSz?•ZsÝ Ó¿ ^$±ò÷[>”oÄ>”ÌÿDò ê¡$n††Ç”ÞIÅQЋ=Íj—‘i‚ÞÕ¶Ša°€2w’rpÒDä·œªšµ0ÈèAÖ“[F4P¡R—œ5ÂD†ïM ø;#ï^Y\jÕU$åÀ^Øk.…/>n– »×¶„Éõ)Y^J'hNOFCKvt‹Ì­aä¥~ÃýE°Ðn¿ áÖcˆ•$ m26%IB+Ôh‘$´%a’„V ­©ë˜¦ ’]ôÜϱ‹Kã¥.m#O²‹î¥§ àà€3ŽåBîøà0§Þ„ˆXm¶ˆˆh$ˆˆt½ …ˆp~8N€ÁÀqtxU<‚W™ž4| rd;Ý“/éË(-‘‡æjCw'n7qp¸oœQÍt‘­¥ØY¤3s,p÷¸ËÁÞYHÜA öîöãËTónaJ\ Ú ¼\ír{Þ"¢]nõûÃqÐCð¨—û1¼ å¦áȹÜÏ-æÑpl,Å͈3ùé=èÑrP…ô=ƒ-t‘[;Уµ’ôï&·/ i”´(ÑŽ§¤ C;š®ŽDÎ\°E²¢¨è( ”4E}=ÈRÕq |™Çïc®rð@âeªº[†ÁWÔ…|eU@½4‘朗+Òy/K“U²*àM¦¶m¨[#[8 ¶…ÃÈû‰˜††~J ¢ßLô`†æ¢ØíFœr`׿drJUæ‘·žùËŒ"ÏQI#÷ÌP—#9"ÚÌcèá  Ë?A5Ä|àh|8ŠüÔöµëÝ„Ñ \ ®ß$•†a¶KRÙë øÝßOé_jÞM´ö¦éŸÌÃ8ý½žýþ·U°|Šæ28—I“I¬3rËMMœSUtÓ—A™-´ÔVÄY¬ôd;èæ~2Zˆôä6ˆ+,¶f™h÷g4&‹ªÀVëG)Ãììß^1QD°=ç E€jê‚s{PÍL‚j2i2YxFÎX’…Ø*ŒAY#SSÿ©HæÈB*ÀŠ©1,pv™#OI$3vº˜”P€a™º¤g6ÌšGìS“©î}.ôGŸÝÉ÷÷Ø÷×ÐmÐûKðw}1¦bŒ¹ 0@‡½¬¢õdš÷éÿÞ¨júBÜ1ŽìÀK&ùR+M"_ÎÈ ò%˘_Žñ2lä‹cœüt cÕWÞôs·ðh]nH‚GÒ$X㌜‘<¡‹˜É´(MbGOÊ‘ØÑsŸêÁ\± õ £¦n¡¨duÛ6Aúq`¥â®Ã7ÕØ;ÛìŬO ül ýŸ%G€ß?ÌŠŸqÄ`Þ ÈJ‚œ3iduFŽYµ™ÇðgdU#G‚¬ÚL‚dEÎM«JŒ×ã¨\ÆÊ´TÛ˜1VºŠ7.Ë´BI´Y­‚xò"mÄ7\u^ް1»´¦[èWt4š=ÿ¶8;U½kw n/%Ì4À!â?Õt©fo ã¿ä£¿,=€ÉñK ªŸ¢åu´úîß-XÀŠûØV]a-ïj‹óî7 ð’¥ +ôÚ‚—Œõ÷å ¤”~KĘ¤Ñ¼C¬ki5’ÉþŸs̘ ØÇF̆Ä>¥IàÆ9#ndßË ?¸!±§>“c’»£Ù¿.1­ñ&ã…`yêbµËS6ôûhÔÈø±<–­¡¼{xr8Þ½¢ ÌÊÞ=l[¥ži+°²5]ÉcV–& Ëc8¶ÎÿŒF©çßö2M[½öà8¾ÉgáÄœ—#qmæ1üx¯ÄÔÈ‘¸€6“xm¸GC3ÏÆÀ¼`€­£²ºË öj\ò÷ 4So´.‚­uB¬ËôS̺¬˜Ÿ÷ä°éÿ³2£Ï²u`&M¤ÅiXNòð-λàÖæT |KÙÙœÔë,ç´ÞÃïsQ6þð­Î Õ$C› ’ʽÞà¢9c±òUC³^Qv0S8;?5ôz·ó¨Zxû.NÂûpú è –ÂÍݾÇ2]M°ŠƒYj>Ïal5œt5%·âU;æ{Æ´£ÚÂEp³¼n–©'Á|kuòùãTt‡Ä{DΩv£vŠpLËACy"7@ÔBd# ËléòÁæzA{SUãG·r ¿<ÆÑ H£ŸUè¶b‚ý˜¢^65ý ®<Ÿ±¹ü¹A‡uf̢ł1¹Ü}g'ýæ¥WBûÒ\ú6lŠH,ž.Õr!E7ˆ³uÌQ÷ÍTÜY ÷ €Fˆ®k|À?Ò‰\§ –IjDOVõt”…µÕ-¶Ùû‹SfPöñΡc‹èErÌî¤É¢°3r$Çì¹OõàñÓpÌfŠ ÷G\5pu45JˆÌе-S²¾­‚d9¹}‘=d2iC¯Rî¦×¿”®Þ_.bøð®%ml<+I{-/%º/Wºý¿’¸PJÏÕw"*yë0+²’·*M–à E‘ ¦’×V¡pºR4%õ=zI–±€›mÖqðß›`ðÏTÇÐ=S²ÿ™Äq_k,ïµþ4õTešMò:šûÏdªÉt˜Àt˜e¨¶L‡í…z=‹`Œ±õ+­kŠÑÓJÓé¤Á¬ÂJq| $Ö¯YÀ ¹}åxi p¢uºÔ¿®ñHOÚSÝqž÷ðìÐåX µc’ðáäXŒ|¯Rž;»ý(Kô3i²DÿŒœñï)ªíÊh]Iš@ò=Ã5^'Böm±‰­Ap"Ø ”‹yRÇ̉à {_Ñs"|—ïðÁï°äD8’&9NË‘õR­æ!9à?—\F[-eúhÆÂ¼RÛÐP°©"p[—ªÛÀž8$J+“&9ÎÈ‘œíæ!9x~†dtJÿÄ<†ouJN„:9ã±òS“ïõ˜ù—Á‰`ÛŠûL–ÐÖ—ÐöØÇyX%´6®¶ÒÔ-V}ó Î×L–ho%¦çË»IÕÚÝ^Ï2V¡›h仦z^†.ñü»ô«ù³$‹7ôKP;¥6Ôc9êBq`=hûBqÙAt/M‹Ÿ‘3“ì z$MvTÑaTç;*ªîаl ƒÉ°ì7Mq‘,…TÓKSª©®Ú¿Oën;áþŸ‰rN{n_k h9YÛ¾v³L'}Ÿê YôšK:1Äh^2UÑ XqDE“ìæt ªÿ$QýÀhfê0{š™™0dÒ†^BÁ^íjë²Ðï¢]>É2óêYfUEEëG]ª“1mÎÊTYšI“ gäÈ&Íç>Õƒf§iÒ<ˆX^ªÝÁ˜§$ò{OªŠå £/IEåÃÐZ ,I<%M–$ž–#áÊ­æ!Ká?— 'nàf»¯«|%‰Žª9(ûrÌ%‰6,îÑSI"ìŒH‹³­@Y’xJš,I<'G–$¶›‡,Iäø¹d«S–$ÖÉ‹•oX†¦™%‰cèC˜ù¦¡™îˆ!¡ªŒ‚×"qR[µY²Â™´õ¬L¦÷f*¨4´,J¬/J”E¯™Dv¾P‰0Y”xª(±¿S6È¢Äô°½Þ¢D‡°(ÑIÍŸ—p,% &—&«ÏÈ  Fö­mþô± ”é€þµº†«‹3~yYÐ ßÀG©©.Ž¡i^šÐ4C¬‹B¢ÍÔQÌò²(“¿(³?ëv E™Žiã:‘ö[” srešYy& 2S9„bÌT‡ BÈ=w3QØ]ÛÍXvW¤ ½s4zÄ2]`i¨uÝŽƒsÄF]²†ã6–¬ÉÆ…{i²l팜ñp~ÉÆ…GÒdãÂA5.F ƒl-3î:ANé N–Ô/q[²Nð”4Y'xZŽÄ·š‡¬„ÿ ±­‚¬šq Wµ¹”BAGGA¢Æ](8ŠÞ…ÿ’&çÁ&§,<’& ÏÉ‘…‚íæ! 9~†dvÊBÁSóxu…‚Ž¢¿Ç¥ ü’¹=÷ŸÃoÞ"zxâ¿=®Ví¿ÌÛ_üåC.äò).¢m´éKcø.2È1ª•u¸Æéò{Oþú+ZdÁ,ÀQ0sªL{—R]Vùi¶t‹ª™tã]a ·ð=þ]Å} Ž·ÿê%u 8 GŠº åZ~ݳj׳|–°áª Pä‘>hø±¾÷7É#LÙõ¶ Q}Çó=›‚ªNƒõ:Œ–7ËûèZïðq¢0©]G)Üq˲‘> —QPq©I>ûI>Û•‹^8Tm¿ðù‹®)¨2IÄÐ@ÄÐkLjÒ†bô3 W‡92¯á„õÚzp' j7Ï—j‚üdÄé:¶Uâà¿7©¸{ò×üF ãd'°ZôÏùt2 dýh·TÎHIás…ƒ•ÁY7“õÓ ØA›7Ìyä…ëI"›4gÒDæìlSGÓ(gª$kV ú>‘®¶žÚ·ý­öð3v ˆkƒ¼"ŸuÙ<·›88X0ܱyÝ‚AOŽCóaë7µÍ£ªãx(FÌ.dIÞZ² Ý~œM5ïV¾¦™4I2tFÎhÊŸªqô˜½ø©ÇÅ>öežz—´ªÄ1ÕׯWš ‚CËÕ É¡…Œ.òrhõKc4 º«9¸~ð½ÒÙ A\º ‘»ºóg_ïýp1‘ðLÚЩŒdšu3gRz-&š7j¯úWÜ.оgî(üsuÕ>’®(MòF …7jœQ®iàêÇÆu³Ük ÐøE®)›kJR¹W¤I’©3rF“E»ìZ) 娇2MpýÚñDét|G·¥ÙšI“ŒGgäHÆ£6ó~öí¢Š¡%ãüç’KÏiK¡}²Gcb^ß‘kZ8BÍ1ó9xès|G äª48[ ”|G§¤I¾£sr$ßQ»y óuQ&þðNÉwT'g,F>+u{Efþeð¹`DY©–ÖµZšºôªKAa§ÿýNCSRû|žÚÈIè/~ÞÜßñïÁlrûñÓÔ«ªîþ0ýäÍoé?ºY²xðméÏ~Û°?{ºÍþTÉFšÄqO$3‡8fÕ6‘ñJ^eOdª‹Zè¼Þ›t©UK‚»Ô4Vº¨¥™2ðž|†¶°Ú®a8=­6.lµ£M"`½UÅèM“ÐXé¢|m–ôË­N_ËMc¤‹Zn ‡¨XœnZ8&CñÔUE[õ,­Ú×uö/Ï{LÆÂ‚¸›õ–’…ß †!ƒ›ì`MËiýÖ³hx›8ôR£aÄ0N&xºòg[é™dÈçK»¯‚¦×³V¿áÐÀªC²Lµ`™’eÇ—œ e|b¦Ò–-㓎7föŒOnº1K?Ž£—É‹,CʤI²§3rÛl¼XÛnj:žÌo@† 5ög~ïo´ D¯©ð ö|?‡¹Öí?(`âøˆÁôCC*ûRlXÈìdÙŒ|¨¡ìëåN>Âo‡\»Gkø\ÚÕVÔú WX"BOÌã5}0FK½Þ´ˆÐŒwúµX˜¹æ{Ý—¥( ŽªŠ†ca&w›fÐú¶N÷‹qo¿ÀƤØVàåÒ RÛ%´«-sHGÒŠ‹ biW°YÅðëy&³o‹x&s­;€gÅ¿Ó/££*Þºzæ/(ï*ßÈÖ‰YôFšŠ7#•|-JË 9"^KÑ 1RôÜ6@ˆd²>ÓÁ*f~ºP˜0‰f™j]¬°;ÖH˜Èh-¾¤Ivª~Cÿ U”í ŸápÿŠž¨;%Tíôî[¨ÈÆ«dÐað[3ènÛ•IK&Méž‘3ì­lWV•&Û•”3¦veŠj»¯Æã¹Œve©Ícãh¢GÍâ‡oµÚ‹¤@RAíJ¿SÒ$‹ß99’ůÝ<†o ]fK²øñüH¿ÓòÊf¾dñkþôYü,Å€u•´†;®´F*Ä?ØžP$ÉêÚŸ=_¢¯ÁR&&ÞˆML8 –ϬãÄDù|Ð¥$Àe±%ç\W@É9ª{û˜.š¶HAPo®ÊvfKÏ™^ÛÏŸ¦ž~Ï$ø–L>œ®%ç±0qÛ°M$ÓÇ…2pÎò#IÊš§˜HÊ…Rpnb|ÉH «)XÒ<Þu6ùæë#'¬1 ¶OEÀ׈€ýˆY¿ â…@Y¿T%uÕÖ3ɸ¿’œüKFÞß޼_õ—FºupjWz©z\íáã.‰hmøQ÷­ :,9â¯í#IÆþ•Ú4¸^Õ£fÿ2ñªëØ¿rf&!”¹4IvFÎh^UÓpíK üYíw¹‡O@2HÖµ ÃVuíõPä—gý ‚玙Œ.ÊdìŸçŽ·j€zêuÂr'ùM2i’åîŒÉr×fÃ72/ 19|#S²ÜÕÉ bR3ÐáÑX˜—BrÇpæ%É/{ˆ…ÁpçDÏA|¿ˆ^&ÿ’à±à¥Ü š¼GUôפ´³o‹PÚ;50µjºHDº60nÒº Ô7éLúî™4É»vFÎX¸I%ÇFUš¤&•Ô¤‰–âJž«VŸ+²Üi°lÁIž«Lh(È×·­ÀË¥¸¢.’7༨÷—ØM¥Ëþlç?:ؼµkãÞÞ1ó-¹° CO|Kßå‹üFð‹,ù–ޤI¾¥sr$ßR»y ¿òã¢ÐÃÏfK¾¥:9cA˜ŠcH¾¥æO’oIÕu~`ÌUÚžþD•¶º+@[F‰,Ó.J“eÚgäÈ2í6ó~ K–iËM=™,Ónü¤ˆ2íô•¤«ÓVuW§=ê¢<ù qÑ èÕ‘vOk²èæ”4YtsZŽ ›µš‡,ºáù¹ä0%mØ ¡´•y57ªîŒ¹c¶ˆš›º\ö¡æF6ÌΤIàö9#©¹‘ ³O}x 7ª¥£èh_%–Ø„=Sm±ÄyÓ\Iù¶•&!ÅgäŒ&BÏ’¡—„)xˆ¾ßåz``²óÄI²·Fi’ì 1ïâ{4¯Z¸¼Ó@óüá–·;@ÍÃâ&Òèl+P¢æOI“¨ùsr$j¾Ý<†ŨôßðmO‰š¯“3–ôŸ©Îë!pºÔ¼ë:(|ÙˆQó@¸Go³$Ú¬VA<¹sÒRo+ðráòƒNR j­èiÅÙ2á^ˆ­¡ÃkŠ vs.OlŽÄÿ›|Þ~$žøHšÄŸ–# ­æ1ô´¡Ä×ËK@ÁÑ^8íBÅš¢áŠð-Û€-À҆&Ð2>™6|iJ6Ú—mÓ†wÒæ|#Öæ4ÃìÍIž6TT½?3è¦ {]o™6äø¹d«S¦ ëäŒÅÊW ÍzEiÃLuŽ>m¨)&ªÅTL–6|¤¶ðf–ZÀCˆ%«Ž‰ä¦HMôÔÔ_m–³ÔÖŸ¼W' […9Ž•µ›EïGJsqeM£Fœ:D© ±ˆS)]ÇÖ%âô”4‰8='gD®£DœI“®ã9Òul7׿:ššª]6é§©·Vׂ8µ„5í§·/·%ê4“&Q§g䌆”Àt/*Í3pNIÜøIbÚ`z”¯¥ãÞØ1£|¢âm:”¯lo–I“(ß3r$Ê·Í<†ÿ_TG¢|y~.9hFÄ1ŒWÔkëR`¾–«"ëæËßR×— w€òiDis¶(Q¾§¤I”ï99#JÕJ”ï‘´‹µò‡ouÊTmœñXù®…ΔŒÆÌ¿”¯eÛ3_¢|+(_E¢|]åõòÊÚÀÛÐÊ7®ãÁé ‰ò=’&Q¾çäŒÈu”(ß#iÒu<#GºŽíæñÚ\GS³ñqÖñ¸Ž—òÕU×E¹Ž®êÀ|¯¹Ž¦‚oN©å@ß»ïìrõ[%ZœIïg+½#¨³¥›n¯gkÆæð.[%OkΖ=‹‹ÔÙëùTå“èÿ@i¨Òã1—$ØÈW›’„Eô"I°wÒd9Â9’û̧F'!ÁÎ<^×t”1x<Ze5“ÈK^‰LšÈŸ‘#òmæ!ò?C 7K€ü©i ?ÞLLg»¯9s!y]3Àaú‹ÈÛ ýÕ@vF¤ÍÙV ÈŸ’&òçäŒå òGÒ.ÖʾÕ)QurÆbå–a¸¯ÆÌ¿€¼®Ù¨î¹p€ü`Ì|ÕvIèep¼ÊŒ÷y0 Ÿü…·ŠÂeMKK½¥À‚‰î˜¯¨g7A.ªt@{W?¦‚ê¶5îb ]C1Å­Tb™4YMqFΈ⠲šâHš¬¦8'GÆZÍCÆx~dœá´¼Âj›Žk¼‹ÿRª)l ×nKVSÔTSôW?¨j Û›°å³åª0F´-ÃE­™¬ÔÉ$²³…‹ÊJR¥Nk •:¶ƒÂÕ˜†fõÊH3¤Õ¯šÊ‚–©–vuî?‡ßfÑ2 ¾%{\­_§øéôxOÍ÷lös¯Ãh ÚÒ·LÐt•>¡¹´Läó¥Vš 'WÄvþm“6{‹ ¹¬ÏœԶ,듆öÒdiß9²ÓP›i ¿~Cvm§!êRJVœ€ycÇ]J©ã«ç‰K)%y_&M–Rž‘#K)ÛÌcøOñE%?e)%ÏϒͰT@ƒ8µ”†òzàŽ—RKé((*¹q×RŽ¢Ùп¤ÑùF¬Ñ)k)¥ÉZÊsrF„q”µ”GÒ.ÖÌ—Gž‰q<-¯´Ú:0=3ÿRj)•­s-¥£à{ÖÕR&Ñfí/çko¬d-e.MÖR§–²t@ûV?†5‹ÊGµ\H5â1†è›©¸³8˜óƒˆ@¸¶& ‘jü‘Nä:H°LB¡š‹ÈŸˆ£§á"¸UµÉçÓõTóno?M=UÉ>4‰ã(ž@FG«"íBª\¨uKÑ;2,$7¯ñHäú‹ZèûôT®üäÑ[©šÇîåªgp¶~V& jÕW©Þ{‰âKYlï_ÔbS¸¢Åu6-ì:ó|°9eç(­¼]dÀRC…zÔeÈ‹)fÊÝ>ú±Áâõ›uü÷&XcË6‰µQ°®Õ̴ȬŠi6Éëhì?“ÔÞÖ…8ë"=ÏHhé…ZëY´á©êâ‘#·(@¨½za¥GŽÝtʵfxiOì„•–ú×5>YF{ªE›ÃàðìÐÙº)ËhQ1̺2ZY¢½=[¸ªGp-]h]ðò0‡Ú¬ti=­ü8˜Ü~|IMËüÿdxüàð¸ëêèðø€,ôL´ýÉ(Šj`¡/aº å>~eØ$d¹‡_y ‡·Ü£Im-ŽãÄæÖ¾èßl´pˆ I–Q"Ëxõì+éÂõÍ/¡‚©â›f6*8©Òx çÁr+E•~H[—ˤ0ì&ɲErý'‰¡T™ò «ê7tÇœ3îª~ ÍBUý·%~3“&ëúÏÈ‘uýmæ1üøÔEüȺ~žŸKPÑü8&úlÚμÀª~CwÀJøbªúQtH~’&çÁ9QYÕ$MVõŸ“#«úÛÍcøYÑ‹2ò‡otʪþ:9c1òYòèõ˜ùRÕo8ò®QWõ[O­êWÙžÆÑf.dA.Mô)]u±a…ÝÙì_é¨(œ‚©+L÷ ‹ï˜ÈCQñôÚ&f7‹Þ”« xÎG Á7ðì4E¾Æ¸?b¹¾â§-_>fo?f~$M`‰¾?’&ˆÐj¦ l†Zü´Ó¾ý?«*®j QгJYÙ6«V¶Íde[IšÀ§ÕR,C>­ei"+Û [>­ei" Ûú\íágp¨ëÚú\íá'p¨ËÚV{4fãÅTµ¹¸àÞ˜‹@}‚ù‹rëñVvuͤÉZ¤3rF”‘†cUšÀ˜Œ´«ÒŠ‹=Ö œFƒHڎѶeˆjí€ µÄ—Ú¹®î¨qÐ0C¬'ô7i½œœ’8è#i}NŽÄA·›Çð­!‰ƒ®‘#qÐíæñÚpЦ¢Jô‰Oí¦V:&Ñ=f´†[á “x°;&qй4‰ƒ¼&?›ý+Uc-qÐt €CÁA›†ƒlmâëy 8h;ÕþúQ"  Ò$úŒœÑ$Û$úHšD@SAY@0  éÝ<¥¸®cÆ>S–ÍŽKŠfòAÝJ“¸ç3rFó JôJUÚ°Ñ+ãyNñ•߃)(JUTœuÌèPÙíà$:ÔMwyéÇqô2y‘$õ™4 =#g,$õ}Rµ 1¿÷7 Z°¢l ÐðÉTÛ W×tPEÓpqo똡Š.,äÐTñ»|™ßH¨ây9ªØnÃ%T±NŽ„*¶š‡„*òüH¨âiyÅÇÒ1$T±ùÓƒ„*š¬×ák…*ê0pÊY¨"KLÝû‹µÄ*¤I¬âp°ŠûÃ9µƒCHƒÁŠÃQ;¶ƒÝŠ*‹̃Yøä/¼U.©zri"Óáªî^v\“4:Y:ž½+ êy–TOj7¾A®xø`Ò%íó˜$«8øïM°Nþö¸ZA¦pP>¬§7àƒGªÇ|ï?‡ßT3=W«ûp9ÿœOèZ›|þ4õìô»&Á·dòùcú;ýŸq8¹½M¥*ÙÇ&qÅÈøhÍD¤˜HõµZ*h%[·‘‰D^w—(X)j¡gùÁ¤\k5õ|zZkš@¥¨µÞÄxtN1F©aÑ9ÜëL µÎѲ"¨ØLßÜ:ó|°9U»¢òµüYûÀRp°¢Qcu)Ë^fŲ‰ÒÝI“(Ý3r$J·Å,$Jü3‡û2Š^,Åŵ}1>×ÁCˆZásózÒÙ­„éfÒ$L÷ŒœÑ¼­²¤ôHÚÀKJz°è F‘3æê2¸1pã‘…žiaáÐSÕSx8ôd3ÎV¤eTN‹¢ßKÛó`¤‹¢I“@ôsr$½Ý<$ãç’ÍO D¯“3 ºj¼"Xè…Ñ-UEö\/"ÔQðfþ"4yŒ6k9_{ë`%¡¹4‰ "´t<{W>ðQ 1¨ $jB†3P¥¿Iùñ & Tëu-o–÷ѵ Ò5âÙJ^AÍXØ~ÂaZ·qøì'ølW”DáPÑA»l—‘u4Ñ)힢‰ È‚4UZ ”ÑÄSÒd4ñœMl7Mäø‘ÑÄse4ñ”4ÑDMÕ^_)ÑD[E¡FMTñ%¥h"ëÀõG›U¸|Ä\š $)ÏG½;›ý+¨-RT9ª º·ˆî[ÇAÄm]ùŠÝÖ54QU!†Æp¢¾-èË”Çú=0 X9%Y9àrö|غ‰j§5êà“ ¤‰ê)øcÆ‘Ï[[2øtJš >“#ƒOíæ!ƒO?2øtN¢ >’&2ødãËÑø‚|²u Ç©:æàiû÷™lÿ^'MŸ†Ô míßmaS™Êâ ݇‹6¢@¡Ùé?¤óPÕ8\z÷“Ð_Lna%¢4¹}~ZHbÂcaâPkªmöEâ6lbÂ4.Ù ±°Ôª‹ò.õ°y ï6÷ BÕzyÛ\²î…™670†ßz‡[¹Ï½Ð4ν¨…Žîï×0_§^bѵïKGÓ¸õ’hó䇿M™”–¬XÈ[Œ ÄmЇæ8ãɲ=›5žOÔB¤ÉtÕ´lNÞz­ïÛÓÂKÍ‚ußLðt•úï¹ôL2äóˆ¬ü‘_Tûu€…ðu4æo–ëx›8D”ëPœ6ÆËÎÛ?N!«ôyZÉ+èy[‘dìaC&ýžVÔczét!ÐvªQI‹èá!ˆaZéí/þò!r ùÔ^•AN+Ô¨€Ö¾KA¾³·žƒ¶VI‹}€^ºâ›¤Û*$âO÷&«8˜ùI0‡>J7Ëý^B/DýtCjcÔïs°Z„3_>h;aâ4S×uù í…\ñ8Äcv íè^Ç/ÚöÒ½j6¸EÓ»ÔɼgÌÑ„*¥RîÄlp Š–ùiÐÃK½°Rí›OSOSv¿cyºh-¾¤g{2É•4¨ „TÒ­äZ@YZ_m‰†­¤Wxà`QE³–£RÑ»+ ¹|_—+$Q}^³;ÐûX‚ÀÛF/Í÷ú´“I²ãõ*Y’µ¼ªŒÓÓŽ$¢ëKKO Uçb|dS7_¬ð3i»]e)=å0‘F¶SÈ…aäž²©,ö[¼ŠdŠÕQT0Xár* AÄÞ* o%x9“&K ÏÈ‘¥…íæ!K y~diá²´ð”4YZxNÎXJ Óq/»'Ö–:ІkM>æÒBÖ²Ei¡–î齿XËÚ‚4Y[8œÚÂýáì_í`·†m€p«ýn oF+ãI²ºögÁ—èk°”i—7bÓ.Ž2²älù|ÐÅÁaÁ(Q‡¥¨îícºèÊ ÔS§¹µÛ™mõpzm?šzvú=“à[ÂÒ(kYF|,LÜÅ6lSæUŠU—Ù‘$­#V̾€Dî#ÞÄ Ò2Mé«Àuؕį¯ì²Æ(Ø>=T­ÚàÚI`­î‚ºÏ À @£7hškÙ{dmªâcD¹Ö¤û ´ÎÁBÂ÷*Ø‘~Až¶êBÙ÷KdD– * :ªhûf*î,Ƹý6E¡­jü‘Nä:H°d𪹈üù‡8zbûu;ù5ó ¦š—þŸô#Ž…‰»áša¹ÒØ ;,4#òZùÉ£·ŠÃgïkðýB,Ýa{ûUgJëBV|ؾÅ*}l^¢øR{ØLE¯Ï‘ã­W?2ì*™¨OL‰?Eà¤~\ S;Àþ$¼çÇFª~Š–×Ñê»·Ø¢è z´Fc¢QÞqb­D‚ =r*RãLÐãë ì*ÈæøpûMáì ]Už…ëJÄòaëPº•2úFuz©^$I¨éI8˼£Õ}¸œ7&ÕÒß1Šª‰t‰… ,YÒm™Z;“©µ“b^ 3Øeº¿¯Ï#«˜•GˆÌ¯Ò0oMÑ>p`p³aÙ°êìÆæïƒEÀñåÖ&­ƒöÂÄYŽfbuÒ:8)RZ ¤uÐ(FZ§>Äo”ž :ÛÀÅÄTÕ1rO·š ƒ¨¥ÀÂïžrUa±í_£ùfdypù|‹l¿ƒÄ_æó -®©—Gšì27…áø?\_2 iª(Ø©‚¢«ï:Zÿ­÷”wsÂtB#)7*·;{¯Àà‚GÔ®Y9à:´óçÅØo;Q¶ëqg?É—èü¾½](}ãca²·]³ÙÛîü$È]cH6­AXAFŠdê­ãšô‹A?#ê¶}°èLEìL‹ë2£›Œ6«Ø4ë)Hü‹èþžá¦cüÙ÷+ÚB’¿¾jʾ_%aCŽßwW&ìûe›.ŠÚAö›:óÁsý¦¤"Ý “ý¦šÅŒ…Eûµ÷›²-à†¥‹"„oxèHáN°†ŽOþú+!HŒ‘çÌã48kZb¦— ì®É&nÃoâ¦Ê&n¹0ÙÄ­YŒlâvâCüvÏ0š¸¥Ç³'Ín)š%5û‰ÏµÑìå~P²-çA˜@µ©IÖA˜(îšÊHîõ­ÑuTa«lÍwæƒíZóÉ âV˜lÍ×,f,AEÙš/S¬†P¬–¢CÞÇKP¬.­^ý‡¿~”-OwÂD¸†4pÂÄéU×DÃózÒ«ì*RéUGÑÁzUÈXöA›@—Dƨ™¦ZèKž¼*Ož*yò$O^½É“WÿÀ](Ož£@5(x®•"hãa–áqƒÊzÞxûÑ__q"%¡e|Š¢ ÝZ*ñ  +—~{¦èü1 ç2L­fLÊ: Õ¡ËveÜj'L`¯HC•ù€ƒ°Bµ#±rE/sÇ®èá’éHÍÄ´Ñ•ì€G쀒; L²6‹‘ì€-&!ÙA?’¡YܨXº`t4 SÏi™v/,Û@az›[u§“¼ÁÂÄY®¦Ê΃0iœ#-ƒ3“–è§ó†Ý‡ˆÎ.°L&e¬ÁìH{Ö`{$Ó`½£åµ?{ —“;ù€Kæàf1‡…&¨4)<àùé#}XôÁ+<*òà£[L§/ê²äEG„±3‹Vß¹ñ:6 uÖ¤`Ýì¿ Puj)f%žGžÇÕ‘”ˆç™®/ÚEâ]`I`Š„¦—’¥W0jª.ÑÇ4øÉPº¤±ÇEOA:Yy8T½üÓ_®ß̓ÙWi» µÝ]Õ¶û^XáIyDÓD½b»}{ÉlvÃÆä>úíë`°J¶ëëð$“ÇÂdc‡f1²±ÃùIÈÆí.4q±ÿ'ðâôY \k£·Å†>¦ bd–èÔ‡8¯AuÑH /°§*®‹†M`HiF±ùC§xÛ™]D7â¢;ô ÄtÕ îŒAÂŽÇ€AþTÖZäÂdgŒf1#áAkŒ¢†TÆúSQ‘©jŒý$ŠÿƒL'š¦~Õ°~ªÙz¤Ã#é\ZÏ9-Ëàv–ÁÙ–8SªæfyŤáެ®îNjZpMœ¤’.•´l°&©¤›ÅH*éÂëéž9³L½¯æ6Ì‹ý¤Fgt²9ÀA˜À*)Sí+Wðš4:Cÿ =,2P•n`ˆ+$‰õ™Ïµ#±–ͶÂ$‰u³˜‘DA$‰õ›L¯š˜â¾ÔÞAt/@¯: ¸úY½: ÿ‡E—%¯¢PãV7ÇyÕÙé »ê¦(À°‘]õ²ƒØ¡ÿH’+ ¾D_ƒ¥Ì í„ Ì 9—Sû;hk(uLÑ•ëÈòm¤Ó’6¦ ®Ãš² ŠIUˆXÒÉX²‚õÓä·OÛ?“5¦a›àtvXèôv¯3–ê¨}IM ã"¨`ÍIè;Œ ( JFrà¦ì0"†‘@vÙÉ’F'Et'û†í?‰„vžSš®¢È>ä} djb+Lö)h#ûœø¿eIß§ÀU¡–%‚ÇTaþ÷Aßþ;:£¡›$n¿yG«ûp¹ãŸ|ÌjTUEDÒÿü¯¤èWS1Å’»B-›f„Ijìf1’»Å$$56èçB&^éxjìTbRê¶îŽØ.€…!}øÛM";fpÙ†TÓ°xiœ)í‚aÒ.h#í‚SBöY £z;fõÇ÷ÙPA5M½Ç6ŽmH˜¬Èw_ÕЈ¢ï.aûñ£ÓEvýuàË*@T@¨²ÄY²D­Ù¢q ²ägÜ \׳ ؂ȥj¡áÐ%úFx©?qý2j¿á±Ààt[ሰî}rĸåÖ\ý¬áÌG"Ü·RúE¶¸¨ÐB7@®Cÿ|2¤J­ïVQ¦Êø¤@Wȶ´‘UÿƒÆÓ5\L¨Cv59÷AXWY4»&»š4‹ ƒ•ìjRÊ5 •©›¯Í5P(m¹ ÒA(Š¢;*¸×¢ì0ƒÿ¨7‚ìv³&{#4‹‘½N}hôN•©õñ-˜• UúI•ÎØže»›ƒ0‘%޲ƒYQ˜0®š&–bâ•êt(“}Î|®]_UFÑe_Ñ}\Ó@ñAʾ •¾ 2ª½&û24‹MT[öeÈqMÓÀ@]d_†r_Uöe¨&û24‹‘}N}§/© H\£,EUPRŒ¯¢uø_SZ ØfSt.ýï-›Ç¶yÍž†@êG‘ŸŠÖWÉð䣿œ/h)Æ]}d‰–ݤS.ªË—ë€ÒãGGÐP„Ûû¼GªPã{F…ØË ¦>ñïJ'îíôûÓ]´ø=ˆ½P~ÐêþÁúÜ|»ï²j‚¿­£¿)ÓÿƯªÒmPÍ•¯9%Þ<=G·gÐ3QhçÃuäXŠJ"ÒÍE®“Tíùñœdžîã“?óÖ¾úùãtÍbCi{êÒŸýu8»Mâ `y<ý§…ó)š;&qR«Î_xIt3Õ¼ÉT÷n¦ëÉDÕ=Ækýè‡ËÏÁlòÉõ¼‡åÆ›}K/ˆç-Yñ “¼ëÌÍíÇ©å*_Ùo|ößIú3xŸ§?{7·Û?ýþiŸ_m‡Fa«œþݤoŸûŸ Õëþïò»Ã]$­ÿEzÏR/}ޝQ(NW•Ù"ðã¼Pýö–L GXÉfU²¬F~šÿ]§ßÜ`ÿ™L úÑÕtôôWSVøÆŽÐš|cG+ÿ!} ßqª’MÛt÷á·`^PÄ·3Ö/þjòYÀ¹0g‹hПh7ßð_×B¶›‰ÏÏí¤ö S·Ï ‘Ûp5úá4A_Cëôk¼Wè,ݳR)à©È;ŠRmá Oçê±!ôþÄcÓ¥‚L²³TIv–þE_¿Ä~˜¬¯ÉæY)`žt{T)à»ÓíQ¡õEç÷’³íñØt{^I¶ç™d{ž®ë¶¡-Ý< 2©æÉÝ®|ð®Ogqp²ãYJµï%¡tŸ$«›ß²è”ª>°—)c©XgÛ Û¿ÚoÇ!~ÁviËã6a ƒ*UžÒK&Á‡8zú0¯ŸRøD?jê÷A2{dÁæúaOéŸ:þü9\^"à›ó`$Áç`mâYP? Ã>ù_ƒëh±Hw9Œ– «ûóù„,DR”lD« á[„ôƒÅé­ìö™þœš‹u|m8ŸôßÎ\üzàÒ¢óf—¿aÀÔŽƒuÜüÖÑ©wfŒx½yjR¶k²0KiØlfM+›‘q¦Ÿ»ù-ýG7ËÕ&ÉÑcû?ûmÃþŒ~ý6±Œ´iAº²JB*f_¢ß7‡QÃ5?mìéîŸNæ –„Š0ˆíÁ‚P_ŸÖü5HüßVë®Mý°Ýš Ûa»VÆ»aû¹‹ÛÑiïâN¨ˆÃH{wBE|}Ú»¸uøT%Xîœ?q®pa]w1¬ÖÉÊvŸ1;5x'+Kë Ò'ê BÉœAæ].ÂåW!H¢®0¥.2…áºIEX̼8³nÂÇÅ»YF§ Y…Џ¦tZª(TÄ×§ÓR…§NUféÑL/þ[Ø[T¯ƒYq¼®"VÅ1»‰X•F¼ƒl³-U'qÒåWÒgÑò>|ØÄùÙ𺠕Æ.* !>\tr8²pÑ©Qè‚§F! .* y—+Ås–›•ØA⯽W S=ïò(â»ÙËà!JÂíÓØÝ—[ÑÒ{Œ¢¯Þ*Ó|³É­ª-÷“ðÖé]þè.³bÜd#à –†)ÑujÔ|SöE·í%ég°Š£Y°^Þb–Å,+ ¬YÙW¿KŒ7Ë8]‚è9œñ$ÓÔäCv}¬Ž'8Xî¿?3P˜€ƒê®ÂÙ×ôx®×]Üÿn"›…·Q·R8¤)TE?¸ÖãàtŽ_Q(™ãWJêøMÓ£œª:Mõ7Éã§T]/Âë N~õW«\eZxÿ³T ¼ý¨ìOÖ oÎ(p¼5lµ4y¸öï‡ã`³&µw#é[eë-¢ÔKóVþzý2÷î—쫜…·3ª2ìâ¨Í¡õÚܿț¿›QcHº¯ÑÞÈPÒ¹Jv#·YŽ.fVJ6Ó‡¼î{R¬ËeÔ‘FfûÞ³¿Øl ÎÿÝ@Š,qŒ“IJTªý-K¥Ú`-GªþœYÛª:‹žžÂä—hæ7€® ÚSEOeÌ˸«–M_*YRXx Ly4ñ© ÒxTÁ”Çë¢*¥4be)¥ñÈž‹²T!ê„N¡–¤ Yj…Ê²Š«µ¦fj¿nI¸*DÒýŸöYJA&YyÞÆ:|Ú,Òç6›ú혦n3Çfú‹|oÓ¿Ë쇕Ë.Mú6o¥ßæ­T²Ûüǯ¿LßýqËnq¬*Ùm¾~ܰ@ÍG¢ˆ]y5˸MÁÓõKw$ÆÊã›sÌ„3Æ”65½I€™êÙbÄ×s?ñÓ¹†‚$'ÊŒ'ËùvQØ@T8òòP9…f<-ìÀv°[!Ú³íÚqì3ýl\fûËd0ó ö[>ˆùÐY^%©B4®.I²dºZ¿-‰ìÕZ¾kègyx²PKu*bÉŽ@)•±`î:ºgØs÷÷Û?tö+bx-þc¬Þ-Â瀨º fˆ¦—èÝKØ’Á#*£°ºµéô—ëwY®˜obä{õíû4ˆŸÓ÷ž8TÍLGÛì~eˆv:´âŸ”'d¬,åz²77ˆ“?LÅÝá öëë8˜§•z1BgŒž¿­Ø»FË/áS1WÂIÒ_­WŽä»~HQâ¦úp™gÝ»SÛ¯ñ/,ïsËÒ>QL[X’Ý–w/ëw›ä1ŠÃÿÉøcð}-rL³t”®ýÅâΟ}ÍŽÔí‡ðö9?WÅAî6VOÚñã4¡‚Uflûó9›+ë}í'Ávµ’ï·~ò(J‘éJýiØ­WãZ}N7Îôj`"‚VGgÇöKì/שK’ζV™nV«(õOD(abÚã²pw_,ð"°Š)2¶Ö#ÑtD°G¢EØ?¬ÈIÔŒ)‰D‹X :‹¸,VÌÖ ²ˆIÉŒõ¼†à?ãp>Y>SÍwÎþÇÛÄ¡7{Zmí¡­&½µ>îýÍ"ñüÌtÎóÉVèŠùÞz«£s¡6K­§«qYÞÙ›#Ü•4rßfÁн8ª–D…!º”)ò®¢»µ²ÅÒ´W‡ÔºZ7Ê Vv§ëFöSÕßÙ­-RvؤxÒÝè;´3™Â>Lu0SL3E¿3oµJ$ËüÖY¶/,ÂѺF#T'@wƪ‚ÉÎXU0Ùó_‚uô”ÅI3bÙÏ å2Ç‘ÙMç~³Ìr?7ž§ª7Õ=†pb)k{|¥™i¦ãćúÌCŒ7s 2Ëäs5ÐK3{fÑ<¸Yÿžêñ9QQ….ÃÄ{ XGð/q@¦7˜Éƶ4=‹÷ÌN§WþVú?ì¤ÿñë/;§ó!^lã4DߤfQ¾íñPB½Ûãá:ðo%³%Sé½#ÉdoÀ±da«Aö Xú’ÜÔ›T ®Ïâ2d¶Pùgo2u¼Ûô1pXäÚRmö/h&>ßÜîÉ*êŠ>/ì]ÒéM_ˆÌ&ó˜ Nµ ;s~’q@±¨ˆyEëâ[®\­-ÃH²ðÉÅ;<ÜÛ3™ZÞ¢Uh1ÛEÓMÓ3¨¦gï R3³üÞŸÑUÐÖˆ¦ºâ5¢©î¸½+&ËêgÙ8t r,šlAŽEÓ-ÈÎaKÕjþXZ©žúö´ð‚åUhÊ.¶«þò}E¬jN¤ñ¤©|Ma;ˈ½§ìÕõؽ-Gl}øžœù0›Ô^3f“['D1–²lö¬¥ŽÌœLv°J¢Ô/š{þ]èÍüÅ‚(è)Á’U/ŸýåC®'OŸÕEøy1ÕRåE´ì)yf¹äôëÌ/KÔÞÞ:ÞÍoÞ‡›_Ý}MaÄP©í™µ49Ó«žç§…¨)¤¾üfåE÷÷é/NMáãâöãI\USK×ld¥„6 Aˆl‚Lá6ˆ§Ò¸ â©T®ê/×;Oîî;‹¡°MS‘§©¥Lâ×yêN•Y¢f®• ÈM“|ªSÓ$ŸêØhÕ—:7Ëú~«µüÀeÇ;º‰ ÖíÏD¸‘ÝdòÓŸþú·Õšðø—¤ïÑ\B¤ÒhDÒõ‚ÒÙµãHRC’èò²Ü_žü%7O«EÀžm2ÃJ¯3~>3ÖÈûß–2íiºÎê=˜ Ôd9d摾<Ï· OëhÏÐùd¿æöä ®£Åb—\ÀܲÓ]ŒQÏ-èï'Ph´×0a1¶ý$ÊÍcô‰Ý”%o‹ÓKžZ3æœýIæ‡oÿmæ‡3ÆÁkaTÒšµ3ì~D±ß:ÆUû=6̤ç^»9gÑð†)f'vx;=É™AÞt„+¹øÙd&zíl%¶[.ø8ûÒãS5Æ‚çá4:Qg†û=Ýô^oÝë^öšÔv,Ȭ“ŽBiQdŠŸ9™¹“GegîäQÙ™[8²ùíäQÍok‘íÇNÕ÷ÝÉ£ú¾ÏAœ$’HۗܪJêÓ®Y‰ûj5¹Ír*á7–1Ýu‹Q`‡á=~ŽU§n§QogͲܥ->²Ÿ’Á&Ò\|,Èx8 ŸQo|#îç©¿#zÄfË13Zû9˜Ù),~mÁã-ÖAðµ0ÞBô¾šY¡@ó2ÿKôø«ãƒ%È‘>Œ?ü΢‡ÏòůüQøe²VuƒŠ^hk³Ìòû}­´}ŸÇGŠŠ>lrnûVô÷}Ù]Ê&Ðù‹éìÞë>ÆÎtH )ï~ãûɹg ˆŽ…»= ¦T)ëqö‰˜à÷ \(œÊ?$²ä‰LygOÉŽ‚¶û]†âœdÑ£ïT´ñ'‡rXçZ²ŒÖɱÈv÷ä T;~r§ ž@èihRä©hSÈéhLÄ)iŒê´ìÀT¹Ýƒ@¢º³hõ=+«©/km%?[RËE4ûš—¡œµc™øM9–‰ß—¢Ì‡ÏÙI5Ÿ6éãMr NË'›†âß’®'f¬ƒ„±a‘HW7Ë0=£û™ºOåÏ6ñ:|f•“´+Õf,ªU3“Ç8zñ‚]sÏl<ûΟ{»2ÝŒ:e2™<þˆf2ÊÇ´ö£yó ñÃE]\Þ¿¦œ·…j¯NBµK£°¢ŠtËOuóò½¬¼$\þkȯßLЧTØÔ„ï ÿÔÄm(h&w6q[›Ù¾¤ê•ó„Í™›$“­Ý‘dªÕ8^j³²Q´¸Y“mbhq Bµšº= ñ–ƒÖÀmO´0Mâ‰G÷îB‡1¬û–½ fV ~s»õWÊtŽYë3Ýn~ Uö"è¾æÑÏÄ(Íäãn*LjMFónRý7u¼£yæebçõiêzé/µ|Š&Ñ ïé>ÔŸîõ›Eí®}fó©+6™¤úìשî}XLMojyO$n$b:Ú`¦–'ì{.š°¹°mú˜ýñqŒB;Ne”—ãMßo©È©kƒšúóÓâè²¢©¥ÑÒ„Lè.\Λ'£Öo¬Z·±jMz-ý6e<µ½T+?åO[ªì-6¾—Ü|aÿî°:ÓÞÅû¢z_4ï‹î}1²> ï=—Õa{þ³gÞ|1½/–÷Åö¾8Þ×›Y©ó$]¤ïCúùéÿÏ›~ô¦¿xÓ_½ÉôÖ›þ/oúÙ›N½)MdcåžëÄ<·úÍôçÒjä/Û~)Œ›työ«QX‡Iº?{l)þÓ›þ#]„ÝrL?õ·‹ú%Xœ=?׷݉¨¬DzB&û•˜þ楧£ŸõkDxþ8¼;:N‹ãð>]„w^ºù:LŠ„âëçAV*S|+Èò¶¶Ž¾¶m$5‹6KŠrª‰gn®W¹àtî³çÁ:‰£ïbG¡òÛåoÁ‘|â]° òY`Ï[Ý æ'“¬ZmK ™ñP%.»Yd©ËyØóp½bèÅN¿=õi9;ñé9;íiÒ¬t¼`éß-o«:2î–ä1\Oþ‡p = ªjf¿Ê˜÷–©‹9‹/Íç]&vÏUxy´›Ôzû”¾ÖGO›yü´¥ÿ”=Lºg²‡I¿É~¹õåÓg¨ÛÈ‚­¬Ä1–³À{‰3fÀ›ÔÐä?V>㬂"}IÍ}ôê.ïÄø9}ÄÙßèJå+2wœQPˆo»^×õ5n a°žÂ.3‹ëe×+£­eÖoåøpåøÏ}”£ÝBý:à…Z”,F[Ê®iÐ(8§æÀMf|ìÛ5‘ކ+^¿È7é }ïí~õa÷«ö þå2ü9wÛ/dõªgÿ»ÅËb=úk/xZ%ß½$ýJA"Æ2ÐÔý׎îþ•Ú«ÏÑ× VGc°¸Òµ7±ò‰oÝí£­LÿI‹×óÛ¶`ËznÞsðÏ׸Vg/ÔE¯)é#4¸•Òúó`­¨sË‘ý+бWyÖ_3·¿ÈÞãÉ‘T‘†6CöCÙµCm–B¾×ÉÁˆ¾Y©§gÕ©´ÓÅŠø§ÿæ‹ÝèÝ|דÃ};—‘¼(µïnn?ØÏçéšejoÒEc«7uØ7p½i’~=ïÞ_0zØï«9åDU½÷ìXg¥(gÏv:ÿ_Ó‹21=åÞ“¿š ÷A§€ÏÇ€GD§mF,5%êvy†¶¬Ç#Q,§á}ØcmÒÁTÝc™à=Ž7UÖÞϬÒñÃí‡ç=, Êl›2—øö²?Ú&À È‚çTi¥Ju Ò¼]S†ôZ²ëxËîûc´˜§#gp¡é‡-X(ÿ…žþâç û™n±’nñvš, àzï–ß½¹Ÿø©nú•]oÇûµŠÝ¥^.’ͮʤØV3•ÎXŸùÔâ¼Ûܧ 1=U³G?Uϱ&k¦¼3‰Ïð†£X1Àp‹i6(gRŽoN^åø2(ùe˜”î{‘òûP¸# +ÍþýÙ«1Ù]Éîj¼ó2ÌáÄÍ”_ާûX¼ûñK"€ ©^,ÅyATÊ6R̲(Ž`v-lÕJËj³~ôX×ó7ßnnÒCÃþjòü~õ…Õ~"vfò¥{±ˆvþd#»§¶Ü]E+V‰Ï·µ’âÈ´Šü8\z¦sÖéÈì 1enm˜½}Î܆ôÿoÙž²3&zRF:©ûp±ØÎl ³êà  ª±ýY/^°ž‚e²öü$»ñx³øÜÈFÍÈùUC½óöv@ù™Ù·IYEÿãiá|ŠæAÆ…ªÖÄÉÆ^eèô1Ì€™Ùdíãcœ©B;S…ç|Ïœë&½k*“ü{ÙŒ³8~¸äz~R“|RyÇelÄñÄÔ]Fì‹ÿ ÚåôXúGÙøZÃåÐÚ]ŽÌît9ÚN_ØØEâ›Û›­9uv™T/ì‰X¦£I ¸wÇc^£[’{ä4œc§ÝetuÄD÷ÅèOø~nö¾×k—xÏ ëj¡O¥ÐfÂý,S®½ ²ošž?Ûþºã¼nµëü’R®ó¬0'J•wJ¨ãŽ̃{MjgHº®µXã§¡.ñ6uUs­gmæ4£¿@M3ê{>U÷¾ÝTR'Y½u4ºÅñ>ßy™ÀÞûü¤~d…;ENV@Qäqå,J¬xÓÔÉž%ê:É<†BíáÞÁU{8¹ý˜eI¶#¦ë5Ï3NÓÿô2¿wè_ÆL7–ÕäÄlDOÕI—=Ÿímú½´æÙ¿ônUmxëcã­fkÍÖh}JÞ{$ éÌO¯³A¹Î‹ýdwTîd<åÈNMwÑál ©W¾„ãÆÎü£!LEÌT(LŠi` £i¢iž·Y°ŒÒvõÝóÏ¥êýVí´ßj¦÷ÀÚù­£ÌõØp3‚§Û-'È— ktÃHœ?§ûEEÞ‡ߕݾ§è¹hðÊÕÓߎÝrsûí2Òg÷5®YnVØ×Èæî§iÉzÖ¼›ÏÁÌ0c_¯å‰ñëò+Õ¼ÀçtZÌ÷g µóóé9^úLÏ`6áѸ¬Í\Ýü¾¤»¢§3b‡½h:v|ËK­Òå<½!Ù6¤ßLcÿ÷ùcú5Óųb9ž<6K_:Ø{›Þç<Ѱ˜<AcÊ ûÖ^xßÅÈP ›¥÷–ÁƒŸ¤ï]¢™«(d“ô.yùßíUdx—Þ¨ü8žè…,|—tšV<ñº¸”­`šœßð—s¾ ý†«E3ffz—^Šœtž:»ÈãñåFU?EËëTÛ²:æLÖ¿«·´=ZÒ^͸&tBÿ“ÕnçÏv.T3ðBYãÜ/Ù–ÎôvC?S••” ZàkË¥ T–<úmµ&žky(æºKrÑεÀq@8×bÙq-·D'[-?Z?ç¤sÔbï"å†iüúËôÝy¦“nÇô÷YGò{[ñlÈÎB¥–n•²T—“Ôt36·UgYöié/è¦l2X³‰È…•þžfêå¨ÉÆ‘-ˆ½S¿D3‘e½Éd;ùÁgòw:ánQ!K‚å<˜“-¹¦ì–|W üeO–M!^-éòc®iå+O>@¶¡fåÏ ÙêîjVÉ&¸Çƒ Üù®T™q­Óçƒêùtö:‡Uk–í” ÙV•Fi¸t$£Ó =Ùàžb‡EÛnçfŠ˜l*t©vú¦Û暉SÉn(S&“i†`x‡"¸Ó >§y7CåÐ áÐøxÛ(¡M3}Û ê¢€ø¿-0<|‰R÷fâOÿê]Îÿ}}Äÿý¾Èÿ-bö-; ­”CkÂÖ˜5[ó³·£;ÿyO„?¬¯¿Ñ»m³„w}ŸTüu[ô1ûããöF}{ƒºZÿÍ?x7Û^$ìW×»_ s¶ Ú»êIÍþwAûÝš3’p®wÙ àVDÄwÈ IÿwàeÏÕf‘d¬7§Ëª›s¿•²ê]aç¤R;Š_‰ÚòI©šv´¹IÖÍŠ 6²]MËB0waYUÇØ¤iÌ©=f!ØçÆ4 ^öé4 ^þ™€!ÊÈä â< "4Þ‰ÀÿÒ?.UËwwÑ {„O˱vn‚ ù_.ØlÖÆúé;A¢xÓYá³$j=»XžFŸ?yœòR=Ä|ž‘Û!>?Ï"óAâ-¢o< ´´TÒC£Å,ƒtó¾ß·±„¤õöëm{â¡g¶&Z®U܇߶ß,àÿ6}âÿ'óö‹§Û› òv.7ßÞÖü5 ýñ:ûWÿÿs3a«pŸz/{\­Z~û|áÀ`¤ÙAvÁ9?Ê€køg£è+ïǼû—9ïG™nƒ6¿oðÏq.Î&Áò7É#øC³<´Áñ¹Õwð‡âæªÆÚǦžÏ?ãp¤ÎŽ3¥øìßâš3ó•gy<£½ ulBy¬¡‰>3#*·¶µ ÙTÞƒƒT£bEßI m‚0¢ßÀ2A¯sñ$Tc„ˆûW¨Bø¡Ã—ù6owCu5î D´!ìß¡4eÔ!@Íáèr;¦w¬›·fa釿=òYØ ä:lž÷n±ˆfWWqÀ Iùmê\×î±_e¢Ù@ÝÐx7°}¥[Õ~1y·¾ÐÞŠsçu2vŵ* ÿÓKþ›¿_]¥1{V‘.Vp.­± 9cŒgðTá¬rþ”ÇÒj¿lÇ–V1À¢;x=·‘•IêÛ¾2`® EZÀ2Ú+æãýß§´9v²º…í­*ltdSÝ3³»Àâá+ H­{¤ "n|ØÇM0ð_ÜQO›RÚX†Ù}Ò\7M\ˆA؆f#ãuy ·œ¹™:Zœ»Yà <žºJžQgÍM`Úœ(ü h/.v/ªüžýÿٟ5yƒƒ­/çÑÝtFCÅsÿñ=ÛêÈö÷ïòÜÂóƒ3]BÛå~…_ÂøëÇ¿÷…4Õ>0‚¦ÁìfC/%ß®>”wŒ õPêÜ> ù–²-·bjN/×ÒÌV¯%Ûž¿:zoê==žî`6•mLjßJÃíãRÚí¡»¢ö¯Lg2j?ÒâäòûnÏQÖÛ ¾â'9 Þû‰T¢Ø€+!0ׂ=Š|!r@buÛö•ˆ©ÍäF~ žî`:©øià{T+Ãçy£j%-±HvâpÂ’C´<5çøEµG²GâÇkeˆXØ%c‹#[YÝÒ;_Y oS+ã°²C¿VÒaeŸ¢9Ý‘Um£û3 ¯ÖÊqfý$|¢[ZW·;_Y`ްV†ˆ•}ýÊTKYÙÙVüÑÖ{qljîZ‡tÅ(àpøŒÓ¬öÄ8utî\#78o,¼0upý$Š3B±]˜ ­eCõ%d!¦”ø(œŸ‹ÙÁ™kñŸÞTG†bãÜy÷Cù$N¡ WÔÚž—®!VÜAm3à%B׋Hâz—p™êEU–÷Žn} ×±P ÿ, ®±cöžîBªœ¯®üe´ü÷Í2Lÿ»½°ÿº|Gå!{Ù¢WÿÉæO£*UE㎊óU5ÅEÐZ8n!Õað˜S×K÷) ÃT¹CâÂ)fÆšÝȘ^úØK µ—B fºÌpP^K`¥EŽCåÄU±ý­un‡¸tCB³5ŸÎÀ,v¡^£½r©9‰Ä›Ïd1ÓpdVâ°´á²}Ȩ^\Áï²0~çÒ{µÈÅ­¬îk» ø¨yXaÛÂ$y—˜Ø³¥]b–¥ [`ÕQ1©5Þ&H®‰[á§KXa‚$›¸ž] $Û­°çm–›uj×K,*&O<ˆ<©A‹o0 wÚ²ðtø¦€)!†…‰Ý!Oº¶›©ŠKëtliñ¤Kû@¹´j÷®°>§V†ˆ¥õ¼•?çæìÛŠ+xmÝ#ž€9ÚZ‚²xì±`,¹V† µ%E—êJ÷k ¬B¨•!hmï_I—×±Poø£<ЧB š«¤Â…#„zN;Ì™úÁsýîÉO¹`.¤êtX0J?ôy•ÄtN¨ƒz¹;Ca”¹s»G¥Inæ2wñŸ{Q]¢a¦Ý9ãò´ÐQµOŠåŒ¯³{€­»Ã¢ -ŒCsúÀSÁ8ômß—Àòªjn?;ÈMtÄKÓÌ3þv]é.vC xLWiÛÈc(ë³p¹†rª˜¼x³ôRýDg/ë¦ãŽN½Ìë`9'^gÖõ§ûun=?ÎÁ, ]gÍAÅ;swT©vü%=+¨µâ« ‚à,R;û,é½4D¸ˆÒmƒsÕn‚ë‘BFun’è®{bû?6m\ß±RÝ龋†hLCOáÏÛX°‘Â?º¿…?Ÿ³@J᯽4gáº4´'G¼Ë[Ïý6vþŸÁß«…{C s!…š¯tìÍr«†¾ÿ3ùo"¦Ê6ú§yk& k%#ší~3‡OX<ê jð“+ 2–9\Îâœu´9 ÓäæöGD¼-n«º£ / µ l¢ÒScÞZóßï£xƶ’«0Ð2ô2 # à$dh’n_åN¯ùéñ6ËH“BŠ>¯XbV¶-¡E–ì%'vãêêOÞý© ¶ƒšt2Ø|Âó½Õ&¼ç0N6÷e‰'{}«Êá[©få;ðõûnwÏ>"v-RO¬Âô:Âí±ú` ¯ÌE…v0å‹vûIôμ—(æ4t®â޻ø<êŸ @ Š_žÛc 舀qD×Û¿¬ê\4‰':^–hÙ¯ýÅâΟµ/]¬ÍI¤wfDО¢® Qø»zÒ[vé4I#óx¦AÃŒ2›©=}‡U>§frM„ìU·áFoå©Êmð[\ˆS²\%>\]û.Ä?+/~ê%A·¡"wçŠQË=é#™Ùhövˆ>" 8˜ÂÒd¦(“ÄírÄãÄñÁÁü0,~k#Ýw‚é7G/c”³Í‚’Š]E[™˜Ñ7bß *YûsúÝ#KwÁÐTm@l°ÄÉÇÝe žÇ¯~ü5ˆÛãf0åpoo·f,bÏÕ˜ñí—LKàŸCäé/˜^M‹:½èYÀñÑ(µCëF÷ËËp"y ¶Q¾Zšå/ëû˜¾˜n †ðŠº]'qš( &„~ IÑŒšÂ{ÅùTHFð ÏÕúhÛ,fäø]_sG„Î3òG£©À{G"ÖøÁn¸zÅÆÚ>Ì guhF2Ü’Ôæè–É­7Q]N!úº65–0e†Dƒ‘ Ê‡Ù¢aœý§3¦„îA ŽtAÐ0Ú7–ñ$t¿ºêðîŸ8z†Ñî¡á«´{à-«„ Xé-ßRñAÆnUÄ—šÜ(âåÀš:0%ÌÙÀ±ë0ùÎÓ/Ï{:L¾Ï—ôNvÚwŽvþ¿{M>ü:’×i67Öß…2x‘hL}†àfÉåÉxLÂxcMÀ—˜hÃø}^4 ‘V©´68`n@á Û§¹À’ >› Ï0KÛR[UÚµ£ë½›ÆOÅÛÑ&©¶Øþñ9 ç•ÿ@Œ¨>únc³³DéÙ2}õÉUF‚ 8á$¼]¥¯ÉNGOß…‚k(ß…¢“ÓP¾ EÏ$êïÂói/˜v-j’$` Ã<2M ˜û´[±ÃçÅÁç`°lÌD 3(!( T«k÷nbêÏ,@J¦äŽçá¾ÅæsÈéÖZç…µBLÛO%Å@¾õðœí©Í ©þ À·áŒ*Ô6ßrû`À$a-t¯*¹dzú“M ?…H¯ìÃf9»Mh] Úݹûm‚ÑãÉ;,ï ¢è†Á­õoÉL¥­c«‡¯¢z‹¾V³bú.çÁ}ê7Ͻåê*ÕÎíU/ïe$H ÿ$Ѽõ<¿™0Ô=vŽ• þ¿ÔòÇ_3ðaI†ê þ(_Ó«ôæz¿g' “õ][ «NüŒ¯J@Gðg"œ/Õ°l^ê}j˜±ö=š–£Œ{ ïü¹·æÍüÅbÌD¨z'T`´*Á# >Ê‚¿w„¨RáRÉÅðf,\ sr¯TÛ~¯ÔŠwLîËbbØ.þÕÕŸÐm¨È­01ÉmÃİ¢G&Ý›Ñ${\»=‚„ÀÓoª$g¹†¿CR ’†Â R-ݵˆ–oæÑ梸°ªçf™ÄárÎH :Cí¼0Ótˆ§:.| !©£Ö1LÀzÌÆLƒ¨Â·« Nmí7¡ÐÇÅ:0µu¹¸ÃY›‰ÖäØPNÜÙí4ø»BòcÃ)m :”£;Ù®6Z«“ÔùÃ`qÐùét ’ê?là]-8Kîz¶:”WÙGˆ‚„ó½Ó»ˆ8áÁ1Ü$ý ßÞcÝ8î0o @„S[Ƴø„= ½ ÞÜÊ¥± þ õ¾qq䯃õz¤5†aõ‘s D?r3KñªZn2 [1Úä ±ÛýFfš¹w²  p—8a§ÑG³GÕ´U âÒíœËùØqß†Õ E‡j:VÜÏàÛ,X1¸\w/bÌ`ƒ ½ÑÃÖ)ªÍ{¢FFû<ÚüvBºÜÈQë‡ñÞ—4Œò¾ýMòÈëÃAH囂iêË¥ÚŽ1Wì|‚® by–Üí"=€b†OO|FfÄýù²01ìðoèøáÅV‘äèùHâOæö»ÊÈ ‘ €-ÀXÊ—)3R&ß›¨¢¤«@× €Hèg“4 ý¬‘8|è§›ZSˆÍý,Õ\Jhƒ¡ÐÒ\]ýÉ·%•1*`P!c´†ªzi¤ñ¡&êC€µ³ þœ¼ìâèjO?¹3 ÊÊ ÑvªÓ:àTÞ­0– nwä?çZ‡;:H¨ãìuÅÈoª¶ †7IC‡3Æ= VÓ"†TÄ’.Óög±g2sRS4u,æ$ •ï^ühL¾³îJPÅù…•5‘š}˜í©ŒW10…§kGãýÔ<ö߯®‚ä ˆ½<^ãÖ­¹O×V»K·"âÕªª©@ÀM³°1†•Ñ}X ­©?C½¶D„h" txñGFªŠoxÖ´!¬Oî·ñlA¯lxYŽ3Tº»ÆfLœØ#nËû2½l/bã«®¦»°y 6×ÖT†9.ñ2LÅÖªóòèP0Ù†rRözqÛl©pç¤ðY4ç—ÝÆ 4Ê#òÙ‚mÕÆyk¿¸Ó‹{× v¤¨æt?¹Qêü0<Ëmíj;?o–c5gàâî/gîy ÔM½z*ÎIdœ6w‘L—O%°‚±Q’|*OÈ(<•.`o”0—ÔØ»Oà ÒY2cŸÐ3v¾¢jàæTF;Á‹-`´–or>H7¤ØÎñÀ}>ÃÜ„]íc ‡«>6ìèwåØß,YÎx¶4íÏ,•Óy»9(?Yá!Õ‰¢Ë|H“goÍ­8vâJdÇ#GžÑ®í’tq mðfJ…òOxäD±¬ŽGá:?ñ ­?„Q_Ú‹ì‚•*•Ãe„V¸\ÂàÑ[jKÌ¢F÷÷T‹ª+"8®EÅe ‹ €÷Õ *.jêò/n.õ\^q]¯,׺â;ƒ“q–ÖFÀQ'­°ªf×§XmV'BȪf¿&ZUCŬ*ô“m·¡©}bë÷´qZøì•sæ èq™+H_{·‰¢J¼°UŸ¢åu´úÎ"C#ìsé˜ü(½Ö±fÉ? \¯zAÂØ‡ Uo'úÕ¥æ6ÇE<œê}ŽÂù?îpuÁzFK­ÛZwS&(Ú oÇQüÃý1“õª™‹éõR³%yÔÇTóéE0;X6?Y¨@„|—kÂz²t»‡È«® Èwvƒ‘?ù«cÙÜܽ˜šM×ÕÛà ë¼ßå º*‘VBªF 'áÝï7xÞs“q´.6:»yŽÊ­Lùë:ÅäÕ¥a´Îª¥1å¶;|õ)Zß*Ž£÷²g6„Þ¦²g÷/K´²_{nžœ,ø§—Ù£{ÉßG[’ë8_¦ 2!/ØÑŠVîÝAQê:dÙîkö«Dµ[˺°“Çu| Ë/Li÷P¡¦šÃ$\e¡“ãØÜ >D¦ÆdFÚ©†\ýÅC„P|†±tw¥¦6'£+ªm¥¶]´17«ÆÍ¸gtbFàå§NaŒXÓ-c4aâè¸ßÅÞ–}ÍAÞí¼Æ`¦ËÍ…‰j;…nÖàÇo*]/ë'ß’ØïªþAÔµ?èÚ*·nUw-xLr¾Ž t…ìŒ/_üEÄUç9¶ªYØe•-†( f ú]~Ciæ…ñVåc¨Ê ‚|ÜŸÎs¾á¯z‡˜¬^oÑØ3VWUì”ïŒCQuªäíQ¢ÛUõ”·Å wNw£5E·–eäÎåfÓä·ò4P•øÑ®Åyé助vîž>€&éhÇß½¬ßeöÆÇà{÷5ν3u¦g¦ûfÝšb¹Ü”Žl©Y¦e³Þ,è!‡`íº“ŒîàZ?›‰¢B°™ O7~ôŠ ì5C¢Ï5Ó§ ¡Ï›¬ª]u~&rÜ‚®ÁËHÇMwÞξ·³nGK*í¾ÓG,FKw&>¦¤â¡õYW)`¯n´!™9üû‘)Ze`Â$$í˜c+M«8Šˆ ]Ó‘ ܵE§ª&€%³S,òXQu ˜s¹û’A‰uN¤ÞŽóîA™`1 Mhx’ ®©ªåŠAƒCæ_Eƒ¿¿ùÜ?²‘šw[†Óh–ÜäjúÒŽC©Ú‹ë;ÈÌÍw†‹êV?äøVõ1:°`¶r–˜ÄÔ'÷]óÄçUè¬[+í€is4 ¤m¼kdë:÷(×Uc숅è_×rÃ~‰ý0ЬöBwÁœ°ùúoÙY›Q‘^ÃK(}ÇùÊÊ$|oµ‰ï9Œ“ À„©HlCëª&Þk^J(Þy',…Ò”Ñ2±Â÷ñ/&Ý“9 è> OPÁ³CF½AXu¡)j/:4±T!(J²Ý«lßKãçV Ø3\í÷Þ‘p©ŒkïØ›Ã’€pB“Ü‚Aì..éĹƒxfÏq)ΗpžŒ…z‰ý+M•Ž˜&ÎN>·oËó~6`Áä-íë€3Ú A%!°]½d¢NˆØ“tÏ~õÂ¥w<Ðí›éöBýôÚ é¶Í6„×­§mA”zÛÒ¾ýlÛ ¤Ûm’‹Ð’#ˆ’ïÛ%¨É×údûv zrqObs’åH’딹õNÃ0M ë݇e,¿¶$³,~ˆ?œEéŠY-üÒÔbû°mS‚¼9o‹·­K«š,Ccž©÷Eó»Ý‘ðÙ_l¶BGË`]Z—;ŸxYýÀûî”–%ˆîi—Ekô¤´,ŒSœv]úˆâ’„'JëÂtë¶a …cRXË4uD×òîŒÛ`¹yz“½ÕÞMº7íc¸žw¾¦1“töDo»Êß2ª»~#Ž­êÞg&ìÕö¤µ‡` ¹ßÈÓ&ÙgïIû`ÈÞ%{!Cî]"lÿg„‘¦TiŽâ1Îa!²JAÌhÃF„”AÌ8áî,›¡Ë8‘ÍÐFÑ -åJƒb/R6Ckø·!P× -  ¿f+€-Àë4ºêh˽cpb®FIc`ü½ŽVaª›@:šV @ZÏ ôSá×;jì8˜| füDÁÝÐ* •+øx%GDÜúƒ# §:q´·œR„\UâÛQWµì!H²]宯•Áƽù4õTçx“IŸTWZ­‡t€ËF­ÿ].r×]—©m%òv3UÕ¹Îï»õ¦X]V…3cú¼Ì–}™ë¬€cz8+ž—„O×]“ Ú½µ…μõÁ7_ I´]Ø=^°•åpïhþGä,î®t}¤Žø· ½Áª¿ÏÙ¸G¼Ñ.wæ±Ñªi«h\§ÝßF¼—}\ZUUÌ7ínº¼ßx…Ù.§-Í^Ëpyßž™¥le<&«aß`:ƒi*£œŸ*¬¦½XÿiΔ—5Z²_ºTÇ}CÚCÖ‹+2Óh}WirSô«»ÒÛLYv6šRÖ>}X$ç9 ç?ü¸}£¦Áz™Ž;…÷—bÇøÊoR?½m?üð×3‘¯:%lm‘yγNr…K ”­ÌkLØ¥6i±Gåu^Y˜ô‚9«LÂzÌFkïfÒx½—þÛãAV°¡=Þ<Œ½G9‡ÔùŠº?¬j± WòÕÓEÉž¥ñ%YŸÈ‚ûÑ˾I®(‘}ŠâÙ÷®I¦(.™}o›$Šâ’Ù÷¶Iž(.™}oÛh¢H·M’DÕÒÝH†¨–bÆ ò'¤‡ÊÊT»ÎÝUKL8³x&òT€—íš¼†Ë$‹ñßÚ"¶:Ë&E³† tkúâ’ h’ {µåš’KâÕqIÈÒÏŠHÉ%øéKB–ŽÈº$ͨ­K’JÕ”(åE¿™Š;‹¡2M0ê?Riש´`™„þ"‡Mû‹öéj,Ê”¬>»™ð=@ mF‹ªj*MQðˆ¬LžÒàòé_/]ºaÛèÅ<µ‡àµÄ=·[û¸NXÌÈ…õ'ÛoÛÕÕŸ[X]êPF+zWÉZýòèsc_Ï4>s÷ÃôÙùŒ½œo{TÕãYq ¶yr»*3å³£Îí&+ë%†©R9l«æàbíJÒøß‘ÚAú‡¤‹›xêa*ÁÙpùpÿ2ç«ø0¿ãBS.}`‚*.E–(G%æ~â¯d#ðblÂÑ04î"Éršeéù$0&'§78ªt£[VŠWWS¸m(DðÂ|öè¹Þ>Ô+vz`°î‚‡„OŽ*Qß½¬§Aj&ƒï¯ÚCÒ‘ÙÝ$ûnß;fžl"a{kJ÷!LÕÔÔž†£û\ÚÐqÆ-a M<7²¦º\XSäÍÑìÖŸ:lاhy­¾gvcÛOˆðZ†ç©=»CÜZ“ÿ¥Õ ÜÅ þ–#Î Ò‘ºô¶°5/ÿýX/Vª¹ô…(à}€sJUySô·§ŽÒÿ3lŒÿÇ3 T‚ åeœwdË«kšÞùòT5 ]Þ$ZD/b_¢®0Q1 ®E&(B¼È›Õjì‹LP3$h‘ٯ鴰aYtXWQ¸:ˇÇðÑt@˜YŒS¨Ážx°m57ŸçpiÎÐ|‘‹óa¹ñfßRO°4‡ðmßGñ“¿œ¿úñ×UÝÅs$Á“áÅV›ÖòµÅ[-hz®•C¹”]@Ü‹´O²nA®Â,·c_]E«`ùÍq 4¹ÊøZi‚¯gO7Ô—9P3iíšÑ&‘Á¹Æá–î‰KgBzì¿õgªH¹Ãû„"b>¦Û¬FBœÞ'Ïøì$ºƒ ý¸°RS’ݳNsüîÕ´?ˆrþúÑÒv²&â·ð°„Œ–ÁåvK™$«íRþå¯íå!7šŠ¦R±ð`»{¥ª:ÙÄð-CžÐ›åì6¡Q3º ³{iAeiŒ2od ª“2 é1çÕòù»ûì„u˜9üèQéžás°=TcL4@œKnvUÚ†mÇ)¾­©ŒUÓëJØXg[]Æè¤Ó•jÛcw+]ç6ó¹ÚDÝ/"@aW¢p'S,—ë°e»¼skdÁç‰ Vê.Џ*¾@©°…ö¿¢ )ÖLÖ©/·UAIB#8øj´Ö!œ³;éê}ôÑÑLÍj¢ˆÙ6Ä^®?Aa{çÿüÖ™Ü%E®pG‡p£x’Ïe½0D»—ü}Ü›hÃb8|4iÖCµÀM!o?õ|ˆâ¯—÷ì/6û×;âš §KyMð„.…5é£ ‘siMîB@ñ`½¼ÂšŒ–&¹´&¤K⌕ƒ¸´$Ñ݃©¨Np4A|‹BÂð[Z”$Þ,ÑüI…eÑûP)$ ºåë“>¼»d?Yma…,ÓÔGA1,7Oo2{λI—ã7 ìC‡ˆ‡I:}*ÓŸŒ‡,cê:„}Ðl4ˆ÷Þ–YÁ×y^$VòŽMañÃeÛ×c}xãSçÖd ÂâÂò,¢ek~·“;‚wn‰,^ä7ÔÊvÛÇ è9Ýj™eF ü0lØËÁñpеãëÚ:€´ïÁt{7×Á»MÒ¾Up½È‚Á†AôWtU]“)‹©g—‰neº¯2¡¨—ª®Ìg9žèVãu“àÏ,û­¢õ³5ðÊ•*¹Ï•GloÕŸÑÌYŽª‡| c:njlœ±ùt/¹«ø³œ–¡óÆõ…l廌bkÜYN““?¢­µTX¸Mj¢?,ƒù›öž—ö嘪ÂFzSA¤ƒQYÅ(O(òk͆¤ÂDœlÍâÖQ}å­±5½-§…¢há/V¾L"VVfP†üûˆø«Ôu¡éª¬£—Ux ÅŒ‚kNǽ@§¦v¥ô•³£¨ä"÷òPd¡«Ëó5\½®Ž¡¸¨L÷êY”Wg³ |ŸžrZZuQº‡{y(rÓÕåa 3Pž£Al)G­;ýh’žäËü_›ur l6¶¼F¸~?Ü+D‘³®<éñ!_»ŸDÑ]µ²<à|}4 WAÆ»@$½ýŽA÷OÉýÂX€hQÛ݇ßð=z/pö´7È»8ÄY%åmzy°³EpO Æ»ÔYàèjWT¹£íŠ^Z”8|x$nj}(ŠçºânÎB–ϽIc9fúXXQ/ä(TCÕ -,©â” ü³¨Í[{îõ¡6³Âµ¼ŠbvJrÖT0×aúÄvt~ßl ²¤Ù7Ër;-t,àm È]iÄÛÏé{àÍüÅâΟ(+èa·|§ˆvkêJ€¬ux?ÙÑjÍeÖviÌ—þ}d S]Î3¦AkŒt“<"Üäpr¥³ ’˜»÷ü1}Œ¶ ªß]@Áeª9¶/²`,s=¦õ?ãô<,Þ;Ü5Ž‹ii6‹Vß‘õBí÷~âçÄÑ–m˜@בdÛ{¢w0§DGÐ\ûGEwlÚ]ªœôÔ¬é3ª»ÀGI ð:El’löGäæÛ 7ÕQgŒ¶mU?jŸ XM ]…“Fœäfa(ßû¾_¼Ý̬ᮠøÎBYú¹vŒ‹¤ŸÐêp;oh‹'6¹È'›ú»ªBÒ©Èt»n‹Ámö³âàpyß¾J¶úœe˘„Ñ6Ű”îß2­·–¤»¥ Ѐñp<6 î§i iôÕY“ŒÎv²É‰ÅÛ8º=CGyóìÖWñHq®Û›•Å—Rçé4í¥J6j_¤.¤àÎnh-Oª V´+~!ã`ÔMk ½6zi¢($¥²!ÈI-f·§/hc~9ÿ»§ Y CíeyÜ 3B·½,[pM:N5³ÈºhðŽUÓ¤CØXƒkÒadÁOS¯®[ǤÇ~–ÖU€ ñ<º&I­¢|OÊ(€á°þ‰Ód¿¬£OàŒ›i°œËfY'%‡{°} 96¥2JÍ ,`”3oïa€nºcåAû|j ­‡.F¶£ñÂ×ÉÂ{fIc ü¹„Ÿ²_¯sÔÃßÁÌ^˜Œ2Þ³î3÷ªk ª©T…nmœ }Ëbe(n–®9íó $ZÍ~V‹pæÿÌú¾NŒQ­ ŒËÍD ®U(FÁ!œbõ pÝ#JyÙãHKZ, QÁÄw€ƒ|{Âr Í‚œÐÆÂ¨{ŠÈñw"°, ¾d5ÈVAM§ßÛ˪òdUMqa§» ýÂ\@i Cq§ÊŠ|iFV¸^)iŸÚ¦+%ÉŠ’»0ûð…shÜKø—ÃeòWÀHI£bŒÙÈʙñ¯ˆ¿‰ê8jld4а´'HÖ9‘ILæû%›˜ã’aÿ›åì6!âYÈ !zð;UÛáã`t¸c¤Ì¶¥pïÔqMÞý ¾Í‚UF€^¤Õ]Û‹àª(T¬-‹'ó^8È”7в,^çMl»÷ýpa– dØry!Ãâš«0œ…/»Q†ˆ›& Óï›2çfÒžÃ8Ùø‹.'ÖG$ =›vªC%ùðóZ/¨@Tñ¼JÐ|&3ÝÁÙé]… IÛBN4øDÖW&r–K1ªtẆ€½í{ÛBe,tAÀ<7ù ýsóžcl™? ä“_ÅQ’šÙx^roί^¢™XŽ®ÚF/=‡†¿i­a¯ ‚ž6ÉÞ‡•U:÷áÍ‚~8*\Ûg®ço¿.CtR«!Ö{á7'!Ž‘æÞŠî\Æ’ÚýÖ‘ôwÑÖÍ~€ð^báÙ5§;Ió‰mÛróä­6„šR·MkŒ‘mÜC@¹q¶mâzUt_I°Þb+ <‡Œ­>ÔslÅ6+¥HĤ¯ ý˜ªŒU¹­½ûîJASG`˜`õ° z_²r3ÈâD´ž=7¼¸¼ Nº À.Ô±´.“à[‚ÌÞ]çRFK¼åhÝoqkg¶Í$pÇQ6]<¦û.áòBžYÀì›<  hœ)X¶…IµÂ & *ÁÖMùs¹ýHzprðêÊ{ÇàVÞcˆ)‡nÞŸR{;çœÞ3¸ù”8oéòû HíEá"ë€Aˆ==/Ú›û‰Ï³ì„´œŽÁKŽ0/5­=H»g§Wÿ‡ÿRõÿÃe%(\„ïâØÿN³qN=œtE5x Â3#ÑFoÖÛjcl•jö?“2R¯Êe® )seTµ]ßBÕÕ8iùŶÅ%à.ÃsÞFLÙ¿ ¡˜Ž?+vÜÖQ\?Gç¥;ÛÒ„çúñu4¡#ãt<—$ê³ß®&"¾Ö „»¥ò²QsG¦´ö„ÆG—í>d'ꪥÿó!•2Ú ë\!zÇ^âÇ€ðëE†YðHf2 3W‚”OVI†Ï~‚Ìø Ø©¹G¹Sº­`P2þ3»ÏËpv±¹(Àtᯮþ„,E^…ð-¯ßžžŠï‘cÏÕÄ?€G4`¼-)Ùú¿Ä~˜¬GËÒÏzÊtîØæú,œld3Ê‹«wžÑÖÜ¡ö$ÊÛgŒ·%kFÒýÍ€ :ë€2λhð>ˆˆ´‘ɹ·ï1IV<9‡šýK%m÷oŒ~¼lÝÌ¥æ!›'¥Æ3Ge kTlóU¸ÅK£1Á³â"šÚ2AëÒ®¯†¬Þƒ–Ô| >óþwº½Rˆ«  ®k8@E0VåjØR¹æ—|£,iP]g´ ¦¢–øŸ®WP®¦fãjFø˜¦:–‡n¸^Tù[΃ö±Ô‰T䄽ž Zà8¸ŸEUØžÎò§¦Å¼äïco+Ãö²«F¥Ty«rAúÚ˜*¦*žo÷¨ŠâuÅíPä•WUM¥‰­F×Dðñ ö…Ëûˆ+ ¥ºˆNÙ¬ÙY6:Tcrgn·‰'àrÑ$*ÚA"!bH•}»ºú“g+Âwq#!Âw±¢#á/>7àdXhš¨Êa ®P[¥qFs«Üà~¾hý2xÉ»ú°nlœÃE÷a¹ñfßR¾4‡]TU}ߤ:î†ïïSåñø~?Wÿ"øÇ‹9¢(>E¬Lµx9Ò¸  LÞCKIö?©±ñ}¬ä :Ãj‰ˆ£3ž÷›åŒEýö ”RˆÀ”«ˆr‹V­€UÙ"Ftõü–á` .z¤^³¾OþÒäIêEÖ×Ö{ð| ™™ÄêÕ•÷a{IaÈÇZüd*G—“bÞ@[—M1Ò^_gÓö8œ V/¾³)×DÆÐbŽü@]5 )*®ÕÐë^ß1¥çŽ´$Ì(»¦>Ô/®šÁ:pº†Ö5Àª}¢kJ${]SrI×ùBf-BŒÑà•“…”4¾éæ™Ý% ËT]í})Û·ï+6ú|=CSv­·UÕÁ¡“÷-ê.ÈIFèî Ä×ÀÙºÈ4(œÂ4}W­‹òî0™mÁcY´Š†:äÄ€­i&<_¾ýRÒeh“„™1·kj@ ÙÇU4z¾ró‘»¹*1P»Ä‘NHFÄm¢+l›xFkÞÃKX©p¹j¿ÞY.w¼ÙMËÂZÇào’GÞ Œ ¨L;ò ØÀ»ËûKô.oÓ“ÎýÌÆ+,Ëîbº\Ql^¾¡:€KÀZ‹pó3€|/O27,˜?Î(¦»½ÄºÊ]WA} /#Ü–ÑÀpn¤Æ½ „«“€z¦È\ɪŒ5¨ldQ_f’ë耞â‡æuóà¼)*MðÇÞo<6ݧ¯!Ó’†Õ”Îû¦Xgß®¸Lm„Uæ2°©ÊšÚµ_¦ê&e¾¥_X±ì™€Ùå¿3Y£›kPàƒ¬™,þ\vÍ$€‘¬¶fræ#Y[eÅdÑ“l×¶%° ¬>ª–¤|T)™ X'éìFé³HRÓ`Y ¨ƒæð¾·ßò¨ªo±çmƒ(s?ñGÙ÷(Ý4n”?®Ð2¸bÈenh‹öA­:Ȧ›¥•ov(¬6 µ^]$Ù dmÏ.m‡ükÒ`|Ó±ÁìHå¸,F¬ÁÈ3º´[‰m5î·nkáqleeˆ#û‘~ˆ#K²0„HÚ ½4V¯F¥ÉŸ™áƯ«ŽÅÍKîÃÔ*ÜÔñRi¾ûýæïÃûñ¢",Þ^ÅÜ6efiÓ6Ë0½b|ø5MãâË]¯Ó½jÏ&8,ЂÝCjÝâm]ì?³ëˆçí`|-ãųk÷¦ñìOÏVx+ð<ÖÈê±Õ"œù¿’]U–' Ê@x?ŵ¥þûa²i€€U`uåÅ–+¿ Ÿ^ù5ZÛ‡­c÷û—Ót gÿø €ó¹Ý8š±„iÍbÿC õä[0ÔÑI•BâÛ6o¨µiÙ•ˆž{rna¹±0v ƒFäÐ7]$ ÚvUqù˜$+žö “Üpm](¥ž·ˆŒ¶¨G2=êÛ$d¯æå^¶©ž™o÷ö§W}ûöw_’Ã'¹¬Ör‡ `Þ8¶£"¿ÚQŽZ~‹înªZ§¿~nyÍE®µ®ÅÕzŒÕÁÎV³[Õ D ´ ]äÚÄþ½l]í>6©Û: š-ÌËþÌ‚ð9Èå ®°Î5]Ju©¿‡|ŽÂ9{]Ž_±¿üx\®Pü£¿üµýxHþÎԃᨹÆhÉI“BdYéã[¹ïê…¾…©ÛÖP Gß~’M ¿^Hm¼o¢PãI¦iL3ÃÁ›PDÍ/¥×¦¡X=ÕÁÚ5¥¦ùßQ<$fVZ?Œ“¦fòÂs”5¶OõÕ3-nåÉßÒ4íš\áö,câ{3z΂ìõéáÎe'†óêVeöd´˜ "4Õ?êËçÚÝñ/!œJÝ“S4 #,ásËtÓ…>VÍÂöß“_É~ÆÑþ¥}í\óÅÍïŽy««j–b ÐÍ`ŠíÚ½ÂVpMÔGÇ*ÝR µš…ÉŽU²c— Ù±êXˆìXÅ/«ÇŽU} coZõŠUánŒ"bÓÓ¥ë½|³šÅ]à›Eÿ=ì—ô´Iö`¶öõ²J¯_ÜS¿¬wøXž¿\\]ݧŽ&l'‹ëõà!/˜Â¡´WW7¥"ºDÝ@+ú$ršXùhf6 ’ˆY!K¹õ·V\îd;iªo¬ùS³úè [vûÆøíÆœj0õ®ù0t×é»›q&ܤ[Ã.Szã,"„öÙã ¯æÆ½}£9ξZ.”öyÞÃrã;¥[Wš²ÙÝ^,WE`÷eóºì3<°`²æu&аàƒ“‘.ï €jý2 çaôìÝmîïºÒ7sœEŠ¢V—?‘­­naâÉÝTnÙrDJ7¿ýÌ~Û¬6£)/œf_H;[BSá…L‡×~'EêÖïbë×ý¾iª=„åH}.Ó郇G·L€ùg¸=EU;j—Ù‚]9Š AËà¥áaOÒ,Z}Ç3 †ß®S9ãå4U øP‡ÁϞĖ{øÉfÍEoR¿“8ŽâFì°¬î9wõtÐöÁ*Ò-lÜà  zy¨?ëú4d±¶Ÿçˆ÷ÖêfÉê|Yá6=»Z]5Åà è,•JSÀmEÊæóÿÓæ¶š$QAå»béºß,gLeù žø—jX€v:ˆ€‚HÊûÕ —ÏÑWšaÚ(ꯎâ>©/’ÄêÕÕîTþô·¿ý?‰°“ÇcTé€lˆ˜8P!ñ³oóßHC1hŠrF¡5yzѪZSáêu¸SÞ¯þ÷»ÀÛ,ýø»ÅÞ]˜ýª¯«ÆÕ©†3É'ä~òGe>ÃÍ ¶E¹f8"ȵ®Ÿó%P‚e±=h‡Ã¹=â­ë‚HꨀÓªÙ{Œ¢¯k/k¯Í—l6ÉæÆîÎqðy³dŒbÝgÒøL*Êæð*bY‰X’öú*eUÇЪ:„›Ú÷råï6$;(+ÚJâ ¥V´¹vw|/õÃìRúgϱÁ¥x¶lEôè«xôèC`(`IB§²„›¾}Xè¬aM2íõ)€;‹Z(ý6mTÉ%!ºÎ¸€vÇ>Á÷v€5ä-€J¯^”°*ìûpÑ>ÁÐ °8´, ¿Wn±G»iB€.CÂ:|M·ú b 0àÇ¥¿÷Ý:9GG™œ›G¨׿e™1BÕ«³¾ÈÝo¬ê¸AȨ6n¹yò ÅE 2‹[çºv[GÇßÖ=ðÓoìd¶ÎpMmdj–Ðí18 ë 5À`Ëë N[Šë©u™ý7þËù?\G_ÕøÀïâØÿN´ƒZ%O‡õ — £)b­µ~øq .˜¦ïE-oG]/­òoR?ÖT¾Œ·áV6q·-3uðÆêåvÛêÑKíý[¸k…ˆAñÏ¥ÿ4‘Q–`©{›è“> ömCX÷Ƈ®©v¿Í£2f²±b/-­kZ2CU0ÈK“<òb.Vê1æ’ |í/wþìëõ" –Éu'€‘üàK®ËN‰½´´š÷ª.'ATn¬f`]bsÙζŒ®&Æ ¿åU—°=[d ¸ÌâU,bTxŠ–Óq½5£fòZo.ÏÞrÞÆs{ ,Ü¢Ðá€ZòS54å=‚ep+óUÖ\»EM%þú1Š~ÕÅWïæi(€¢n¿h€z‹ÀtÚ o¦•?¹hA뻜 Ýòp­¶óWú ztlYl”%¢¾€É%+¤îŠ{w,¼9‹bó5l³t~FÈlØŸöÜ`«E8óQì€+4¸–kåeEó5Ê`è^£qªÓÚ¯'Áyþ§hɺd°¢[Ø[Äm´)Îîìäó…%Ñ<·¼½@ ˆíÕ÷Õ# ]#ã\»¬žz©±I¶®š«v¿°$! ›Úr+¤÷Y¬ÃT]LÈ ÆúŠåÐQΫàlò¹.™¯Ùúƒ¿ÙóT  ¶J{^BRÖ¬ªfñ¯®þ„nCE®fˆ‘ëÔ}ûûËïÿýróÉÌF³·CLþÊsäÛõsÆ…Îk\pG 4^H·qF„üSáןƒY>ùXoDAï>­é*o ˆr7K;8Ò60M‚^Õ4ÞÊÝ›ËùvëF{÷ ^Zaÿ ^ø– (ªq«·PÊ ÌÀz¡÷1XnžÞ¼¯ÐÍGI4‹WW»_!šÃ‚X&D ó2”#çÖvH¯):Ó,¬_SUhø>(#ÄRmò£+‹UŒN™ÃQsrãÿêͼø‹–þKw\£©°o’Ò%ÎBºÌžˆG@—Izç’h³ZaÛ#–£M–{!È¢oÜ"z¹„»%íÆe1@ºmS,»ÇmÜ–ƒå~ çÁÒtkZìJ+92‹BÇq(•·ÓÃÖ y¥`éÇqô2ö@yÝ'`HÏ€ÐPLs‘1 bÜAqòtÌ€Û?HrÞñuBjÿItj8·~H®WOûÕÕŸ¨øÖ>»N.XךÏ#l €¡ù wN Gyʬs©8áVãf¦ÂQFâ[ûÔvâDŸbL3ìf6iÏD|4À©Ó‚3Þ:§ËV6—ž£Ju×ä²P4ïX.¤Þ¦#Ú ®×]íy$ÝDîÊy~æ‘t yÙXI·ð!¸æ;]Ï^n¢`!Fv<Ýst× !Áï#åUtõ^¨¹·=¦˜]¼¬M솉äxyùÕ<& 帙r9­šcÙÀ|ÅÃèZ¯F}L’?Þ?RQ[4×vG|#3s±«‰ÁpIÔõ¤iĤ>eÕwëƒy2l·ÿØŽJÃp?˜7ßµ¸{Zô¢Fê;ŽÊMÁ‰ó¡\^7õ}I.Tæö°‰†k÷»‰ÇŽðhínÇèÎ\+*SGH,#S¥ã¾…nlƦ ¢Òì@‘Žö ºPG„è º ¤fAÈÜïÞøý^ÈhL´‹&+ET8qÄ÷°—°~ˆ`,q¬ž#Âìa³Pô·ñ‡_Hƒ»s6·a£i*ï«8ûþŸ|ý9£i&$¥PÙxo_$×} 切:ž?*f?1!ÛÓƒúÒÙ†r-•;›Ç]ØovRØÿkø‹pùõ×h”7æÊþ,ÕÖKÔÖäµ®„¦øÆú(gëÙÃ>êÊ3µ#µ‘]Ëêã2²’ÄÞ±„`ç¸ßJ~À„̳,Ï®ÂàF§’†2ÏÞR̫ϳg)š>âa.¨Kxjh´–š÷òÐM€ÉÚlo‰ÈG1TkðG”ÀÂEp³¼nØ•aÏkûs@E,¹wáêêOþ©ŒUá :Ö®ÈÑófß|oµ‰ï9Œ“ÏË]µ¯l¤“Ø‚çXµV¤GÊã,ÇÜK\Ví¹Èâ(·=Z3¢§|š¥è½ƒ¼Ê[ȵƒšÕèÕí§rtx‰í_B§—¨kÖéy([˜µë°(ÏöU6¯=#miß¶ýŸZ¶¥jߘ±°Åž·dù-¯«^Q¼óÙ-í¼ ¤©ò’È3ã𛩸³Í#ÿG*æ:,“Ðßòÿ¥3ÿés[ÐÀ¹ÝÚ5|MŽ¬Ý§ö9¼ËZ©‹= ©Ç€B„æaôìÝmîï±D§…І"ë²úwe«Ý߯€Í[+³À@æX²Wq}ñ]Û‹«;‚°Ý:k¨¹C¹¤ÿsóÛïÁìf¹ÚšPEîLBz‚¦¯¬ho;X€ZÝãgk­¾#͆ìXP.[Fb,À\h S»_[çuâ'›5î¥aã&q³Ý“¡¼›iÿÎ…±fÕ÷›å, £%_¿jâTƒ^áÒ¿ï'ðÓ1äé/?fÿ0Õãáòakõÿø…óŽÚZtàD µvqaq ±y9Äßëøpôòµ(u¿;à£hX€~œÓ— ¦×G´‘uÿŒÖpC  ‡TÈf ¯gøì'è&`d1ëJc’§õV^¡ù¦êâÓ=’•'jw*Ž$\lb\•õA^§õc—Õ9ãhK®®þoNe€R ”:iÔ ðòès§ÜN£C§‰³ÏÞLJ ¥ig`¨ oþO>\ãtQØš°hÎ?nCpÓTñ†Ñ’ewáÌZ„Ãþ…@øí{X¼E€4ï M¢»×–Ç…¯ é˜tr¯M€ ­Œme™õÙ·ð›È†Ìò·Ÿƒd/á9_döêÃf9»Mh²WªÂ½Ìå·0Ö•Þ&ó‚D‚$޲·þ&y|%è0êƒØñŸh¦˜£Øi‘]ÁDUy‰âé´‚ÚmýÎTS(íÓ_Tm½µ/Y‚l?„s.Àvû•ØVU~"îĘ¡©/ÅÛÙr÷jj™æØ8œ¾·ˆ¡j¼íþ«êîYVû¬fañ·•c@š .Æ.¾Å>»Ö0*6е†è%Ï~¼«l¹@Ÿ’‚»Ûâ†Yp&ê Æ)¤¦óD~ßó’ȃ5µ­ Ädv¨)©/ót}`Áõ-ÐCµ¡)? ‡fëƒØÁ=7Õ¨mÐsyØÀ¶8‚#t8‡ÝÎù¿4Óú?pË=ýÜrÇþw»XýLbø¹˜r üþðXêv{¿áØuÏ« ó‰´wÖè¼w.Ó ô4ž=50ÛŠ?pZDAª€ï}\º‰Cd±Æ?ãpœUªcñ÷ríŒí¥`Êòµ>ô¾dH7>Ã1xZ-ü$ÈŠ4ï–ÛEtEµÚ:@±ÑÒÅ©|NæörÝÆÑ*ˆ“0xõ[²HªP]~oc¨êŒh¡£û}– hÌFªìpCò"ZÜuŒœ—ý˜¶;оþTøõç`„ÏA>ÀoÒk™•ûpU‡—H@0{¬.¶Š=mÆ#5”Ý©…ZL$9$]uy‹rh6næ_@wzCÓx]Bî2~ÛÚó7 –óÝÛÇ8áËÍ“%N4­ øè‘%ÃKüD¹•‡í©å¢»ÜoBêoŒ ø6 VŒ§A÷b.@‚2Nðí£a2Ì#j`¦µb° =iaÇÓq3v§1Rf9¡ Ӭ͠rQcu-t…Ÿr¡^]@ºD(uÃE°nç!¯îá X·Ç»{Ì[ë#Pªº¼ä^âˆ÷®—–šÊýRïÝ8ÒÌÂïãÒéŽ6,Ïb´WOfì©®ž¨™ébGz9½Â¶­›ù:„øœ†¦ÍÓLÞuÖ²ùܪY!Ñ~Ïí åt_¡ÚÜmB8=üÚÈZ&ö÷`Öžœ–‹göìØ@¦YD¸HÒvæ}ˆ,sˆ{°F ·=4´CGœkUÝè»yÛÇî¹Ó]ìŸ sw/# b(ZO÷±}ôú8 ‚æÄ<☳N5 ^xûìíaý6Ëuø° æoÑò!ûOgé¶›%£Q^‡3’„›añ7ã7)lÛD¶#ŽèޤȞönö6ÌÑ4/f³°12òŸÞ"‘?¨úðx £$˜% Ð ”¦]v…ÇpæíšÂ*HëE˜vôÒú$×»­ér•öoéÇqôâE_é¶NÓ‘$V|;GB(6º£Û6ÃÑ\u¬jb÷­mTµIPiß^Âyq×K,l›« –ñn0¸Y/Dì¶i”Ûv"ø•7ÍÖµ6‚{LÖÉ ë]A·m¦bè8)Ôr>:z~œ!Gx;‚~D ŠÇn»à8'‹§+ä¨\•µb4žú««y„{qYÓâq†Ø[USÄÊ·Nˆÿå¶•I¾‰eëg–=œÚŠhãÌŠcD;§E¯gþ#ß<µ›;ùˈŸùÜ:s™’h³Zñ·Š~kŸÙV¬üSÌíÓÄÌF¼y™´§?àÌáI¢Eô‚ùgNV¾{æåÚ’ëý¡ Ív•%DÄùtMÑ¥7ÍÂö¡Y”qÉ~x}p“•gÈ@3.Ð B TŒu/ zþÝ:‰ýY’eû4ÞAQ¤^üÐ+7ÃÓ£üÍ÷V›8ðžÃ8Ùø ¼íM)sgoSÊ´Z_åÔ.®ý46xÇcëôÛcÐïÎÎ&'¹3à EZô×Ç¦ßžÓæµ¦Öž/{›òKзù@ôiJ›½”q˜Î0*P w˜BbÐ*f÷ÔÖlƒ:ºà¤kõÐLÜ€”TÖŸ¡ô ~ìJ“Áþ3˜hZ/ë‹;$xêX¯ d÷ÀìÏç–ß–£Ã5/õÜâ¨Ý³õd­Zö¨ªè›©¸³MØSn$Éß§¢gº%³º%1,Úª˜Â¢ h_æ=¯îàûVÚQà °;\Ñ^ ˆãXZÍy”{e±.fˆÍÑkîÐ]¦p)È•þwÿ¤ î#€Gëuõ'ÇfT¤ïb|b¤ŸlvmfòUå0 _¯ëvÇÿÜÛiº@¸(EùépóÝ×^FñiÃÀ£Ø~å¬Q9;×›%c…È–3‰Õ«+ïÝò»ÇÚ‘V:–ÿ#IVŸsCé/?fÿ|Íì÷‡í?q·rÛ¾€†åškŒ¶¾ Pà¢)ãhõ ¸rêô… » ap$yG^hg™ÚL[´3r°-Ã’$=›-Ûfrf¤)6Óá§™äö,øðbÌœýa”™Ëйó_íkðª‹lóÒ=¦~OÀ´‰ØlëS|Xø¥ß ˆêzçô±ß_ç¹Â÷ÜïiHÖQœð]!H2UÈâî%Þ>†qœ=ð7É#oÒ‹-½0ñf–ì®Î§ÉoŸ¦Áz a‡D4›7ͦBâ–X â$žÞ«Õì{ò«#\€qPÌé­õm±•£÷Íùhþyh iþ- †6àxÒ ë´³´9|r®ž‡´ôI–Õ}Ó<@ÿRl9€ÿKÕ[·y.Yµ ×’·oõ|v¹m~{ ãœØ¦Ñ{7ôreÓ˜Ã噫'CY¼?ã e©®qWÎxä2”ÕRŒ e夻yœùQAé$iª.…°˜ê-‘h‘¢ÎZ' ï9ýîQ PXE}eÜÊŠ¶ÊÇݵSü.‚›å}tÀ¤L‡þÐ^}a´o[p¬î¢Q]ÍՏލ“È£ÊÚE.EvVñ†HÚSÛR^!»½­|©˜Ê_½ðiÅ]|µ•W@ê±¾mü²ºAêåõš¿g'/Ó”Šñ#aU¤a]• ð«$S‡17Iƒåu­ÂÔÊdÓlÍrFÒý¸H‡ (å¸Ì熙ûÑ,¢{otÕuÿÞT´âív¾@8º)•Ûm¥ìüKdù¹ý»ºúµ­•+hóFÜñHTF¬ZDÅ¡þ~uõ$˜AwLàA¯Ñ’{Ô`{M©»Gؽ Ìñ”¬¡ß9ýÕ?s²RíÍQœï•Tª9 †]ºS{„[\û³ÇàKôÀÒ*«ÕmŠò¤o;ç¦TF©Ø‚FiS½f”‡êó)2òð'+øGÝâD~ñâO¢¸¶¸Çöäت5ÅÙÝãTðñ8Zÿõ‡§‰åF_’˜!Vz@Ê ¯ÅèhYcl“Ÿ$ ³…ŽÎÝsYÙÙ¸¯"/ ñBrÒÛ¼Ç5ÇÀÍ³Í nn»oÕ*€Öl[õ°N¨qëæTrg¸{î'Í5É@ŠÎñ݈¢¯?~= –ó| Àk5$3ÖCv¤U­íšRÀ&œ±ÀQôî‰I»ú¦¶ *=Ñ|EP|egdEPŽÂÏðȽڪãp—ÜÒò;¦¿JRµ:έc¾lVºæð–vêCÕûÊÖ·ÚÁ¾v€¥á‹e-a9wÐÆ¯J<͵l¹ÿKÕœö¥Z…µN?dzԀR­³K­C‹g.—«}¼ZPW{yÝ\¥ÿ‚»jíјcPN·‘ Eûqi¾·uÒÚ»Ø7Íå©ÕN‡õ¢û{.?'‚Bé§Ù° U÷uA¡¢?ifL“Ýk઎^ÊgqiÈ!jqŒ`‚Äe-ymÝÜ@ź )WW¬³öhßiWѸٞ¸‰ˆTÍÔyó¸éò§‡—sï^Ò•ó’ÿÒL‹Ï6N«gã8³oz°«†È²6ÞKgØÜ›È­4m>gr"m˜Ž#YmSQmÞ8"¨² F 0é7¸ËÃé‘´ÕÜ„ C ƧÙ>E‹Á`@° XÜß>¢€¸oŸýÅf+ QŠÆƒ˜&LÖáÖY£÷üÅ[‘…A4Ðà[ p~áh¬‚ØOÂhù)ZN7«U£I#J«ƒ)]ä[ ˆýa}nÖŸ¢äÝû0Ϊš¿® ªó ×Êð½Wf™~›pÎ {þá/ç lBqmPX®µæºk…ÖæÝ"NŸïŸ7Ëe¸| \½ó…z•µB ³IY·³Y¦s0=^v²‹«Óu=Ï[• Ò»°:¿DáòÖ_¯_¢xN½8(þ®ÅZëµB‹sh”—jäÑfIùLY/u_+¤`ÙñS˜‘ɦîÖfMú„Û¯ !VamØ %àÈ êã¹–G¨R´l„˜5n×Ë‚·j ‹ò¿ƒ»÷þóm¥fqëÔcX§/8^×aÝð­­Ë0ý¾N‚'âçIëÜQÐh¦e&ßBH~¸VbqM:w4!.»øaó”>Ý„+Ó¹ƒlq[/ähe¦AüÄŸƒõ*Z® (­s?š}ªRÐ1Ó_¨LçÎFë0û÷}0‹¿¯¸NZçÞFìøËY° ´{õîu ­Oð>]~¶Þ½v¡õ>OQP¯J÷ †Ö! ³uËËÒ¹fÁ¿Ô…Eùg ñWˆoQh}€­ýÂj×JçQÖøçòë2z!š;_¼-W4åò&G©ùBô¡s¹VoÒV†eùSÛ?ZlØÂ|ðÃÅ&¦KL"ô.×Òàí¹¢9-—ÁŒ-ËmÝ-‚'²eA\&®eÁÛt%Ãež…ìX¾6æHs·¸,ˆ /×²à ºÚÓò%| ¢ .ÒP\D—kYð]]nŸzU1^0[ÛelèP9Í0?×Ñ<¸ºbÿTÙØŠâ:ªèž¤ß…¢LÀµun.írðÝÿ¥ò!†uÀˆÁ ÛF÷àGCwÝÞkQ«¥t£gærm›»¤c5}mDÖúßçvî›ñï#°b†¯q-wáUµØàêøØo¿G€»½#•…myšªMË[~ |j¹@×gÖRQ{¨Vp4>FV¥0ÚR…¼h€s©AÕ€UNж‡b…«#é=ÛÍî;Âx/ÇZrb* KIQr²-6Y±†R¼í£,9y·I"YtÂ&Ïx0G[mB ®K/Åhat¤yÅw/ë) ®°NQ6±ã€Ü–v׿êêØ»ª!2W‘;®ð\êCS‘1UqzgJ*su3ê±¨Ë Þh]ïÜWé~šÝó9†k¶§}ìažØÕóüDÿ زûÎoCÀ”"ŒM…²¨PôE´AU/…62Ñ&ÕB£ôä4»˜»¯é*€Ï>üMòˆ zlkÓo–÷Qž_Ü#Ý8îÂÝøÃ°¬ž]p¾°K­ NÛåóé[Rÿ[†Ñ(j.­"X'ñf–¼9Ö7 z²ô£ìÇ'd»~7M]±{oÚçy;È›ù³Ç`ô]fØ^r—þbŒÙt7{ï|rdÌŽ9"¦Ù=€BUCÀ+x‹–.FgÒºvwÉ þÐCzÑL—€É-6b¸ØŒ…|^›ÐFee¢ÅÂOïî;ËpK`TŒµþ j8ÇWW–ÿ†$$|´`h+³ŒJ™EO+ŸŸ4­Œª!‰ýåú>йÈÊ ¡Ú1ý5@éUÄŸ†Õ¨Fy/zF×dï› -ŒG¼ÉÂM¦1-ˆ 87X/ª„·Æ¢wB˜kÖ !‹§ö EeôQöÝ{kfM‘­³j`xÀ¹×™DùŽ3@w6È*-¶ŸDOk/\¢¥îÚ±UÃÅã]iŠ#]Xi•vLãËHŠ'ZÓ- U9÷Jô¡[çò2oÖ]hÎu&èT"î!ÄBÕwB«œ.r/!žIÐK¸[ã‹x š¨ˆZgtIÄNj ‹ðE¾ˆÓLÐá…Òª«…R_í$'e°@÷KMÐ2F”¹AR|¶“ÜûBSä.„éÜQÁ’ŸS:*Ö:7fûJmÈEéC<9ŠiQ¡É‰f9ý°ƒÆŽ¢+NWèC#iP`B^/ Š© >]š{u˜ÑûJ¨CK1‡óÃÖm,6Ä…áÊgWû ™øzê“­xÁ¼'‡QD’žFÄxRøbèNtÇu2ë¡ó–órXŠè}RBú«8ÈRaÈšŸÏÁjÎ|  îÀˆÏmš ‰÷Rïí:q{B»_d½÷u´ S &$9Û7PŽu|#>„‹€•¼üTùýŽK›âö"²pü6ŸÓ•®&ßíÄ•46e±e{óà2önþ/µj¿Õ½H­ÃÝŸñw5ìÎ&… û$_@µ’åAw&*xÐëE´äµ}³úæÓÔÓ”º‰L&=RèÀ‚¾>ž}KÑ(2ÉòÙ?-£ÔvábƒO¨¨ðdâñEø…ê":> =mVÛ'ÈôlœI. ò¾^qÐ6VFh0 Ghi+°!:³ƒ‰¶ T­8f¯F lÁ×r–˜¿ Ðÿ¢‘˜áÓä·O[r†þ,‰âï]©<¾<üù}쪣¤Là¾é·0Ù1‹Êî9A¥îÌÛíQ^åHˆÄu\ÃM2·ZV*Ó¹-ÅŒvaÝãºè?‘Wº¶VR¾¬No!þt"ÔÞØwUº¥p·ë”)ÆÐ,Š ‚LØ«5È(™b$v "Fb§ZŠè#fqê€ †x¨Ú÷÷âòøAHB^ÞÃ]’Âô C²`5øÃˆj2/§¢Zóò‹ gY°Ú~<Ž,k(ÑíÖ%`þ‘JÚîÞ8IbõÎ[eù5®mK/N¸|¸™Œ¾ªí–ËÅ·¡(½À– ±3+­«Ó½â7³ïüu8óÂtÇÿ)GßÉPaœÌÚšÁõL1î×ÿÒÿÏM¸&…e~ÇþwšË¢sd}ùòð^æÍÂFìËãªãËÅ„JÚW¾¬—<œÅ{…„åá:LÁ‘R'fkÙýꪭó6Óµ‡|*¤ÍÅè@äÙ¾ÊæÙ­m…#{ðlÓZz뇦¨,½yðìµÞVž{ÉÙtú܆º@+¾·F`ÞÕfa# (e+d12@ÖRD—ÉÚ*ǤÐL-õ`’×0ÀÅóZçe{Žº&°éÃfZ&äÓD9Êv=­G tù»óì¥ÝtÚƒ(E°fÌ™(€,ò_¤ úÌÏÓ»ßQÛî=&yÔ™%SÓ#ÞHDcgŒªµA¡ÅÂËcV°¦¦wá,§T˜%ñWÀ§?É&æ»ÒÒ]¾M¨nŒ…å#nŒ¥HåGgœ\„U’Y{=l¤æÚ¼å9â­ÌѾcV?ï˜Å¨Ý¶™ãά~rÞ–nµ'ºf_f>ƒçß­“Øgy:Ç Ñ·¿WјU}«Xöûñ¹6´wPCæŽujúÝGzÌÿ˜ Ý8½¬;6œ¼Zèÿk÷Ñ;ÆÝÑ Dì_Dëp•¦ÙUGëÚ>Ëá¹Êå>˦‚Æ»ÎZÜ:3@œ/à)žçÔ°Aµ­ä]i W/DL‡öÍ:  ± ͹ÎÀœI½1›òÜ íûFMë…ˆ]â‹x)ºÊ Zgtr}'µï³LÑÂGô_Äa¦ ôþ‘àvv’ Úìa™!Àz!b–™¸´“Üó2Y—ê…ˆYæÜ9‰6t'ëœtZM^5è 5+ᯇñZ!<-"­Ý!í]8Þ¥ÝS'kY4å>2æRNK×zÙH[Ñz‡36ˆ9-™ájäÅ9þÂöÙ%»•Æ`À<ã~XÐF‰Tw‘5’È.–Q<ã½VÜ׆Áè† áí–ý8!Kã@.çø™H,»ëV´øvéf{'´±gëúpÍ¢(_¢¯Áò]Æ­Å0¹kßa9÷H­ÖnAcûô¦Ø˜®Ú;Xn'ÀU<³}¶ÂÛ>§} ÷â,ƒ— DT¼ˆ\] <ïa¹a h©Yœœ¸½z ÷’y¶ ÎбPšP(1q;O,´u(ôˆ€æÊh½gÍ)†{«=i+ÒÇ]vÛÜfŽÞsÏâ Ò9³Ën«*¦Ct·ê†–b­”õed®Ëèr“å Ö¬£½“6ìJRô³L@«„Ò&Þ³…£¥¿àq6Ëô£o²MLbF”ünùÝ›û‰Ÿ×HqõÿSÛk 3ÍÖ‹FÕyS…"5êh/¡£÷áu覢óÒ ÜF¾¸gÿô£°¸'Oé)E¿Úb¿ûÖ TµAh¢—˜nV«(NÒ}KÂå&`…—ìÞÛg±ÙÇk¸ñ@# ä ër3žVQ,hãèZÁ…eA  Á ¶ëXP'AjíbðÛ¯þaá?”~Óúœ×áù$q”QÔÒ$ýR ºŽÞ•yÇ}–ó–ÝÁKºÒixܲ}Ô’¸Û¼Î×Çw{°ß‹ :î45ža´¯xÖWZÒ×=çkÝ\]ýÉ·%•1vT¯"Ç8ÅøùÉÌFVõÒH|”Ÿí.ã9=hªÜ6?à ‰AFë-9&?Í ÿ^ºš‹Äá"Õ/&è*âÛt•;ÖÄáò!õ\ŧ§Q%éÜJÏðÝ7“ªxóíÓ&Ù?ʸ‚®Ju¢Ÿø«Å@ _+óP0ç讎°%E’µ•ü|ãqJ.NÀ‹D<ì>Ó+âÁU`Å& CU– åÅÌJ“<"A^ÓT1†Ñòfßq„ð.HHCÐâÒ²ÚÛ@GâÀâª*.ðSöë\Ñý³¡Ï¾¸*¬PŸdxá‘¢.ÎhÑ‘®Ê«øxwO5ÕöÙëãÝÛFŠVìÝ\#·që‘goðz„‰Ïtóº ðÛY¹5M&ìÕ2C.¿S©bâ:ƒ©:¨Žoº f@÷h„ Fµl)§*Fõð¢óÈ{ ç7ã[UÕN‹_úq½ðË×±ò­sªáêêÏâŸs¤탨‘ô3[rÇCÊ ÖˆE;§E¯gþ#ß<Úéùˈ¿ùœuæ¢%Ñfµ ÚW€UåÛg¶+ÿLË6­x6o^&€>,Õ΢$ZD/˜/ræ$aå»gNR®Q¹Þ(š :KMte R"ª£‡¼ç2€®³ÀðN© )|ªvíWëùƒÖùÜ2½G‚È @ÌV}ÿûp þôXaëØc6®ÚÞáöë¶m’°…¿yÕn¿)ö8åö÷Ô Ü´!q‹KqùÇÄ¡xþ~£C»ké-Ø›%¦Æ•-´ÁF:<5Î,¡ðc'¤(çÔø²tÂkü؃p\´¨Æ…¥ ò^g´Þëá; £Q5žë‘ìýJ—¿,‰hg)–6˜é´³n.~˜‡n«^%!d>ŸƒÕ"œù£ôRÓ=ã-Þ€y©ÜæÌ[Ë‚R›6I[é ¥P{º IJ„û,5׉#‰÷ HMK·l R“g-îĬí}¸ ×€÷¯VbÏ‹KÐLÌâ˹ݧç7Šý,¤šn‘j¾*ÿèï™æËiGióþ~ø‡áÓ ÈØP޾´²ý ·[@<(àÂG´)·k)@æ‡^*;]‡ü4 óà:Z…Áx hyLùR9•ëT½^ìòW‹C±×rÔ5 ?¢j„ÖxEîÉ{puõçî÷DŹ¢‡Û…TÛ ÷$Ù¾r¶ ±¶ìz-¹GkQ‚ìì„OSOÕŠ˜Lú+H¶½«x »·¡¸’&Iòù>!ãð|»ã*/åɬ×J:¼€>¡×ª«®3îñÊfuÿƒYÞNüÕÊÃóÈùêÙ”Åx˜—f‹±}+ØB m¬ŒÐ`~ŽÐÒâbCtfqmqŒ,6fŸ&–ÕO½¬ã0˜#…Ŧ[iô‰Vu ‰oÒhÌih•ŸmÐM£Rv«hœ…˜­B\ïãæ@kâß…ÏjÖ¶‹‡Ì óBêÚô+}ô5´T×êÊ»¶*kÔ×K×ziR™un ¦ë{§ê.w§þ÷NS†Ó„æRÞ;¦åz¸? µëh¯¤k÷Aµoi„ẃ{'¡\Íõp' ëŠQ¯c½‘ÙÍèC·ºî›înäX·Qå˜x¶°²¶Úþ“G$L™ób_*Â3ZkòÂ~çÃæ¬O^k•˳Džf¿š·äj:·¿V×,iƒl";N:{²ÄÇkh³¨€ò‘–Íœ³]7V3gKbñð÷ÐV!(÷nî!¢Õ×e$"¼³ ¥ó®êl׉ŸlÖÈâ³Æ ™ýÏ$Ž£ø".£ÁÍÝŠh»ÇÎP/G¡ý¦Žó•4:'‚5ÿ¦˜½<ÚıҊX(²Ãå‚mÁ,Z}¿ü¾mTH¦bÎó*á.vÏ…øý5c|Mߨû:ˆØ¥¹G¸K®†šuу®¨ ¯Ó‹ róyM.2f^¤(FŠ;j¢µ[xÖÜ º ÑÕÞY„¢[ §Üý\È©V‡ýÜkhð6‡÷°=ʱlÍh:¤¯ÀáÚÝEÑ‚¿}À/btpûãs Û=»HÇ¥Øë/žîýêm–›u «•X0@Tgìõö÷¨^RiyWÑ<ëâD¶À®j Øv„RoìLÏäØÉâRŒ\­þɾ‰f4¹yO0Á‡3VÉ£U[ì<â]ãëªJö°™6/‡­ì9 ú×q¥è9Ì—aÙ¥VÒÉȎç%­©)l@êÓðlGE~Åc"—ߦèD-ŒÓc͉éòÆõ ^߉³#[ŽÇ‹ýD)¦Y ¹[¾r|Gx˜n.¬<±Öâ9Ì£$¸êî ˆ‰s§ʪÆ_%xAUˆ¢k’4¶Ô_07ó›cs_›ýÈ$ H˜–¯ØÚVHìeè4-‡ÅY šâ¦ ì?š—ýÒé¼ù‰—®¯®Ì ˜ƒ~€÷óU6rNoc!œÑ`Ú@âFIc3ò~Å÷/s>dp»UŒ†è©LöŸéW™X°ðXÊıU¨·nR%Á,Á&y2¹d½{ÆÂk­¶'µéïÞªžÖ)¬Á(4!4–õ£ë:ûcº gN=Ãòù›ä‰¢œ¦ê'Œ–7{Vˆq"aaµ>…­ks;^ým6#¯â­Ìj êRyPï6 /+èVÖ³¿Øèª/d!"®³” Õb¨/žê¾°üpñÛ3C¨\^a5ø ®Õ2&Ô‰8¬ÆéÓ¤;ÕbèÃF¢ËÍÓ®¼â× ñáòë¯Ñ<(ÿ…OåÅ‘_)·©sÅOþr¼PóSõøiO·ËÅuî1q%©;ügL¤î<ÓñÝØ$’Óý´¡@¬Ãú_]ýɱé±ô6(%å0L%ÛP»n…•eعt¡;Ñu ¡{ªCû%tãZ÷{ùØ?Ùrq5ºæjŒFÔè”ÇJwÖáÃ2˜¿YDˇ–_˜Ã·/¬ÐÍ’ñù­ÃY›u:·Jj÷™*CU0=‡‰‰lƈ”´-nåÁP3UÎü3yz±Šy.Ö!ÿ}´Q6V×ÝùM´!YîŠÉÇy'õ΃ܦh#tûØ_Œ÷êëó$û¹ð"B!YyÎX Ó.‰ ûVá’ •´–Û2µ®8¨†{Ý Yù_Y W·†Wj7:9uQ66N‹Ùê¢ró°tsÿÙ[³Òx/90ì±èÖ?f•ýMkŠ=,ÇÍ›GIJÇWýBRþRü :Šj€÷KpíÑñ%ðXí "ßžnœ¤Ú€pîU¼½!xÁÙ€Ò‹’²–]”P‰íALýæyw‹¯3Öÿ¶#à6$rfSa<> «•ЉËøf[,È#Ähúy/„7g Â`jA“˜Üv_“3/ræKº ¨ÇåS1ø“GÓäòLÌu£tÖ€?Þ§3Ý^¥vE|ÕK°ZWGq‡smûù8¶ËK§ ÚÐísVºÞ.|£­Ñl×Ú»Ûr–ô±[Øæ‘ìÖÜ£|·Tð†ÙF¡¾çÓ-3zº‡Q·¯/¸Ü¼×nõ¯®þoDEr%ÅE(¹MÊg7FéG5¸²ýT3dÂãæ=‰·Q!'MOØíýêÂdÇ"Š Þš±=ÚÖÅ¥™±´ónqèfœVlqaæÁ:‰£ïôK3|Ö´¬{lÂ`G‰­‚ØgªÍ‹Àe™ð&­Æž}Çìî¾–ÁK Åó‹"ÒÀ»åwoî'>_ WaQ!‰£:¼ðȾÚº ØóþíQÌ¢wÿ fta•q¶0´¶Yî’z…³{3‘$Î(fwJÀ[ms·d'ÙÔzàÉ% ŠYé§T¦¶ õ:«ºa ¬ûN,µ£—úSĸwò”r/VßkÿOö=hÞûN:Bvà.Š,üÒl3ýØøW9Šä/?žµ·Ç‹jÌìf„°aMÛîžIŒlÌbq˜oÿ,´QÓ-€³7l£C} ³zuHÑ:À*[?¿N]7^vUÈ‘"ÀhÕþ3©¿³­ÞïÓ-Ö@¯$°éj­Í‚º¥Ý¿ý¾­­Ÿ¿áà,e×á"Su8ëÁűfޱ²ÅÑ:/Ir5¥÷­{,‚$9Ý©£Ù]óðÇÝ$C†¡rSŽù’¡îŒ¡ÐŠÃú_]ýɱéx±ôV u‡azDYhn×/wC‚:ÀÈç ê¢ûû~ ê†Ãôîè÷õ»óS—Ò[3ßò³·„ެPm÷n±ˆfWWqp—š«é1H­ËÒx·1›É>‚Èfzç|×Û;‡Ãá|oN¨´,x¹ó€¸VD$™òlMgÑfIÆøÞùš“ð}ä½ ð)LÙ›àxl¼+bUSCl¹¾â8hÿ׊,äƒmLò„kmñŒq"×öÝsëÔC½È^×ÖôÚÞ,׉O÷€!×úI’Þ¿fíE@IŠî3ÅjóqÐÁ!6 OÚ­Åó ¼¡$öþœUMpªu·†^/SîFIzDà4¡N;Úhnû{v”òûVN«¾jg¡¼¯Ô1¾°Ò1ÈÆà`CÛR&½ò‘HªŠª×/Á)H%ëIhô¢øý‡ãû‘ìÄôÑé‘BKŠõ#ñ+3»iÿ—þ‰y&Êõ*Žäã­¯¢´¯–¥xöš@‡?´Ïôó%¹sý-ö XyÔ»Ë  õ Á1Û ©5‹Z2»—`q܇1²xoëBoo¤ züËBom,£9qŠ6Û{°4„šFqÅ ø±üÛ¿T~ÿƒŒâPEq8‰ê<ñ­þÒÓ×¢Ð|'¾Ö¯4æ,\–è!°±k4ÏÊQ¦m‡‚yÅFa^©þ÷˘þ3†˜¿‘Ŷ%¨$²ÿ•‘` ÿ¯½ëûMÂ{Þ_ѧUU%$ÜM•¦nÓx骮ê¤MS”RX#e$‚PµÛß>~$@¹³4p÷0µkí±ï»óÙßÖ&òY‚âª8Q•ㆯ!BïD-!g•œj±æ1?ìtМ|u(”–q¨ˆhyÔ„hyFs¢åO@´<ë ˆ–om¢„+¨cæxR¢ˆœC‘sp'JɹaVrÂÁD ö’ó8L"nQ:EDAñì•Ä×Ï–% cü2LECûäxÁ­¦äN“Æ,ÍçÂt£ɶÿÜC'¨"‹]@"Ÿ]«X÷`ÜGŠÿ˜r£°ÿÂôF7ÝVÐ ÄæÕr—³GøôxþH@®$Ë«E¦!Ù5R°P×ôÜår’9Û•?¼ôƒçÞƒj%6‚8äÚ¿}Oý|C­ëѦnå7…µ—áæ®Q¶`©1£¬·5¬ànV¤Ü6ëõ®ßƒŸJ„”XSCd¼ê\Ç@j|>†a0âúŒ^i„}¯öof}URwŽ5õbDÛ“.¥©—Žïu[EåËì¢Tþ&·éW?iÔ¹›ÞôÃÉh¸Œ ŠÉµ|ž {סŒ\ ƒ:–Ó5¤:\äTxžD,9-qŸ9ñêò5fèxÕË“1X‰¸’œ?JI ‚$rëÁ–2A¼d塬šQ-´£ûpyj².=–?†–ÿµ ª/2³p5Ôéìk!Ó¬3:>p½¾'ßXA»_§Ì¼ËËUfô¼šÜдÐ,šÖíü EÚ¶óë¡U œY21„MAÛD?vŸ‘{D¦ÀQ<ã®ù,( ¨Cl‚OÅV3Yúí´‘R9é÷kß_üÐïùØ‹ªÆi&ÃJ»ã1µ´& 1W(¦ü/ªé[Ö!âÉMKË]4Q°Ì¼0šysó»‘ÄÒT‘u¶U6µIB‡ç7¸œ¿¼µ¥csþÓ°tZš5 ¿8ãÇ‹Ê&1[zñÑÒ ìŽ¶l09xõ…@ )“°™_öN=nÀ]é$zùâJœŸ»â^ tÆkY?9 Õ].A5<¨Ð~­fœ?ùî°&ZAZ™©ßÀª&3 ü b‘ŠM ›‰¢BÀ9ƒ´Ž5…OA(¦Î•T0)ÖÄÔjJ(ÕT ®­';úZPfÛ Ú2/²™G<°EÀ\ás!Ñ #yÛÝÝòÂ:ü»;_Ljõ)£<â•gggàj½•Ît+mÐÏÏÿXëxNRåwl4Ó;¶mwl3žm#UŽk¦¶¥óÁdØ ]ˆï½“ÕûƒoO™VyÙR­•bÔñ$è¡eõj´—­~|dÿ¸í~ Ùòo5kJ®Å$û—V––Úwô$‹ËŸý}÷ö Îþ‚q;¸$davix-0.8.0/dist/abi/abi_dumps/davix_0.5.0-gcc44-x86_64-redhat-linux.abi.tar.gz0000644000000000000000000052600214121063315024746 0ustar rootroot‹D!VÔ]moã8’žÏ÷+òá€ì×%;Nì6öÎÝÓ âÞ¾Ùýp-Q¶:2¥)+îÅÜo?’’+–Gz˜¨Ìt^Ÿ*Vɪb±H§!ñ³EB"*ä †?á?zêc8üÔs§ƒ~O}Úwúú_gÐ wø“úÏé¹Nÿ´§~Ïé»ÎÙOG= ¼ì|dBÒôèè§Ù4”ß™Øû{¡| n^ýã?¿^Þ:G=ú÷m>Ž/ßÉÕõ¯7ŸÆ—Ÿ¯Fäê—ÑÕÇÑ-ù:ºŒ¯?ýõ¿Ž“‹‹“‹ãÿzüwþñëMõ7û'î£_K½yñ£ûó!ª?½Š¹R —ÂüÊ6_;Ç.¿Ž#ï?]_}$“ñ¿FÏÿÉ^¨_õYZ°åÓexOä*aâdž$þGüJ£Œ€ƒÞÅðøå xàW¿\Ž?7¶røÐwÆ>|ùØ_0øëÛÆ3ܺÖÏljývüe|uÙtŽppÝU…à4Xà^ ƒ£÷ÿø¹£–?°hôê®Ñ÷,ýÏ·ãø¹Åÿ2ºü0º…º2mgúãá,ó/À—/7Õ¼ãXT½vd']äÌàLøÃGs=ÿÖåÑÛüäêúfÔ‘/mìòUAüߟz>úߣª3Þd=8z±t>®›;¿¤ùìXŠ{ÑP /ˆZ*F_:½K4Âá˜t1æÕãî¿xÜúËíåUó,‡Ý%òÔâêøutûþzÒ"¿ceæo¾ßdÂ<þÿ¹¼ý<þÜ<þ±?~×êøûµ«“ݵ3Ù½Ää5 $<·iP·cÿáÙÙ™ë4Éqêg$òåöŸÄH¥vÇ.$•™HÙï²¶Ç-ÓÕK†üÇþß­ˆàøK&«Å4ŽH‚GátÇB±’-Þ-䉈ONÛA&ÿú|j ‡´3`i§Ä£’Íâtõ¡7Z2Nc3:ŒŽóJt\Kt.fl­ž 1;¤Üž&5cœ¥¡g™––žçöôŽ‘R1÷CÆ|ôyâ¡þ9‘#´‡ržÆ¹(°ß9ÃÖ蟴 §§ŒpI#ÆåèöãçI¨o•cöÙ(ñ\„%§Eÿ*¬¸}Ÿ4‹äŽæA¢ø2.î¸<æ^œ¬è4bÄq¶¾‚iClÏhKBî 5¡ÉÁ£ê·Õä QõÝÖ„¾Dè¬-¡ äëR8²jŽó´×²µ-«•J9!6¶e§ÅÞ]1á{q½WÀÑ»®ÓKb¡½ÜpÁ'Hã…ùTíD˜Ž˜Ó”ù$‘éøó„ }&i9ÃBãħ’’)l4:M™`=NGÎCQÚ—sr©ä™%z&I¬¾´IÏíù¡0‹×6Ý+¸¡@n?ÏÓÄOˆhZgÅ~×ô}»Õ¤qºcA·Ú¯©—Ö—<„·SìØ¶»ZšvíέØ]˜Ûµ¼S1–?žlo§‰þ¿E¥ž®BYÚP‡!œ„;UûYÎèÞëð®FnãUx¸9ŸšX”°{#Ö¾ÀÅ,Õ®oH¹3œ_`Eâ€,b.ç£Ñhyûñ Ár1ÜÐ'¥Òó¢˜3ãàUö49¸ Ÿ&Wé^rá"‰Æ&î¾(bœ±úß7æ©…Sk¾jmJ×£W~#ö^OYØë’rŸ™ÖÝRõ³ÌvIñÏ2ÛM38×¼®íÞDßÇc7•^å±›º¾Ðd5SQJT –aÑòð5[`O¡žeYóëŽöîvÝã¶ïŒžu†_—ëuù‡«à¤¦þC­oàÚË5ñˆŠ9ˬ¤èSký^Ä(ÏdÜ3kîht³œZâª`À‹Õnƒ/Û­¥/Ú-©ôƒûöÙ¹^©’Ø›oY–Ê ÎÁT,¥‚™Ñp]°jk4§")Ô¢Ô£æÎ|&dÃ+÷ÃW¤ï#d˶wÙ2ï!õ}ÂY^±‰."vÛš‹L²ûõœè¡ =®Ó³f=»”l™Ï.%[ösfÔ4‹â) m•zB/]g[3Bû$)²Ð5e–Ž£÷^ŸEL²TG¡òB_u2Ñ!ÎÛ™Š$VŸYRÇáœX3ó—ð`k¼„KSãQ)¥7gÞÇ;OS³5¶¾ža^–¦Œ¯KÛ ÿÈ9±‡ÜÍ­Záb ÷ÊM<ʇ]аážÖýÌ"?§Z fýMXºa̬Á`5”Åå=:òÉ·8ä¯S6¹&ìêþŒkÍ[\Ÿ«pÉÈœr?‚¯ÏëÒZåTù¹r¬ôU©Â =¸W\Ð5Y6hËÊ.6 ™|øå„5.|­-pñ;F‰‹æ÷£QdÖ£ñÍß—KSߪ“3f… ":‹]/ÔzÏÌÚ3ôŠf ³Ý|Œn\¹°DìbjbhõÙ¸~ ,ª#Öî‡I·7âJ¤ò“”i×Ä%ýþ"Œ¢P0<nn Ç<g#óaÎy*I¯fÍ|Ó%NßüŸ¥´¼Û#¾F»:wG$ngD¢·ä{3äWÙ ŸÊ|Âü'‰¡W©'‰Á—®ªá\9…‘èï‰ú⪷ùºÈ*ëoœ›¯c¶tZ0ãvƒ™Í©…E»z aÏœhس¢‡C‹ÂÚ"bOZ[Dàâ2ë$Q+¦9 >-–Mp…í+ƃ|NqNåš@¥Î èMŠSó§Ýæñ,eæ6U—¸|îjB÷äúÇÝ–rå.@—…[a´Û2­VÜwY¨UN;'Õº2÷މ³ŽE[rÜSsce7\çëLö³$«Gn‰Žõ›éUrè›ÛUôs4Ý…PøÊÊÜ8“z_I)Ÿ!Ow q^î4ηÈsr;%2el|óq9‘ƒ„†éX×7>.ùX•çî#ÅTLX¤¦¯#äxrFÔ·b¬þx4¡æ[#õK¿*ƒ,•D×MJgCЙ‡ÉÏäö£úõePçjL¦6et£×­Ê€Ìo`òÐNl+,ÀµõzhVVqhñøOÞƒÇ÷CÃ:÷%§Ýàï9'¹«ÜV¼Î®2Yõâ:Äesô*ìE ñ‰"Úßc>€^‹(¼²‚`ðÐ0¢sìÖ…Ýã²6Žè›O–ù{a$ÑúñžFÌI¼5k5‘ÄsTI¼>K{# (/{" àN÷´$ôŒg 8ÆyLÉb~þ1©—{ÖÀñîxÖÀGÏð¬âÜïY[!²ãY#¨Ô{Öä¹Ryw Wëöz,Ãjè,°l©‹¾uN»,S[Ýêí³Ú1©Úm o‘ÇW“ã[·÷¶Ä_‡äg¥¡6–­IËN/k0_o+/›}’Q !%48GlY6ßö²É$Z’?ÀõT›œ¢/S)^O¼¸å•XFÚ.še{q‹]N»,S‹q‹eV;&Uëq‹-ÑrüáZ¼ß–v²¥€uvùÚl `ŸßŽJØ~›‹ŒZé~ýÑ×S<¾þKˆ(†P BŽé"¥p$ÈK™î”X4³×äïØ [´8ßÂÕ§§àò06Iã{£2R¼é' 2­ü±9àO3s…Sï{â¸'¢è÷þïÓ:&£ûPþío?¿¿"î‰{rÚTÇd|M\â!}5È.è;·É¥¤mÜ[Õ§³P\êË„$^e Ž“n ›£q}Ð,’ÄiÅžšÃxl½X‰97™Rï.Pë/: ¢8ÇÃÞ‹“´w/’ Š“< ¡¶PØ×4 p˜rUÇÀ”bÀbähÄ ¢ 9+eÚI,†8$ FŒP©ŃAÑ–½Á$È-ßÀÚØ9 0zÛ(@ÁS\cj ù-[$5†úÎirÏñÖÂàã%K±›¥ÕÎ9R0vg2‹|*±û¤•m¤bÅ=0dÆ}+æöf &Úé ô%)Œ„T[^<7ñkmtãò÷ÿ7‡/á ßeÞ–ð6·YÅ“Û*ãÉ-Öñä– yr[•<¹­Rž_Ë“Û(æÉ-{ç–N©s;À¹…“ÕÜÖÑjnå4·“žÊ"¡Ó8U΀˜­onÇ_/¿¬;>7Ãô¿éË ÷04^Ä)óÔdÇ5ŽFS^Så%©'Qk¶Bœ}/ÚfA9óPÅ !Ÿ…*ª#ëlðˆ7ßÒ÷y+DýŽ?ó®p¿_C&Å- $²öLdJa¹ì@µÆ/¦q„r}wI€Jn“©ðul˜ÌÒù¥¨óUeéÌ»#é<Rì9x{רž_Ï¡GöÔ?´áT_®‚ ˜Í'žÚÌ¿—s•òT«9tZ¥²µ’^Ì9ó`+‘'W ë»dŠÚ×€2VnKñ°Y’€aÁƒ'S}®¶5[Úª§ÈIM‰—)W†Â|£Û†žÖ h9XQ~ ä5K§u‡:M¹¼§„Jò{êöñ•ëjN¯ ›—áî¿Ä ä4 ¿ã–äÕL±uë÷Ó|ØCŠÃ§«(œÍkðnľ§ tæ×ù–u|ÃEó‰öæý,qaÌe‰N7Â*tÖB9.d|¦qMv¢áФB “c ë`›qL³@WŽÀã¸È<`Aй…ó ¸¢:ŠùXÜÌgn…Q}Œ³ƒKDp83Œ¦8ÖbX副’a°ª„‰ÛÙÀ†¨‰Z C>ƒqY·´‹eƒ$Ó™LãºÚÌmç Ìt†3hÓâ¡2ä³Öpõ³¸5®~ò :n¤ñè»Ðü±FÄzAYz‹v^7iZM}Õ´Dù^WÁnâ”xX´*­ÔQâaÐf4$"œýž±Œá6‚™Zb—& ¢bK*ˆ?µíQon…éEìg³­V›OÀ¨ÌR& È^ôϞϢpš/Ö•Tœ.”ÍYg ÐåU:ç3Šg!'Àœ²Â,"Nˬè£:cȀΜ¾„° EHÇRgP‹ŸÂNYu†œØ ÓGf2sK‰ó$0§‘N¬p=Ë·R+í—Ë º®…*ÑdÄø@tA#ž-,BՀɜB…†HÀiDùÐS`Ô'˜ÓˆPøá,”Hîf)MæHÀVZZ€aÑ€-OÅp€œâ–I ”œB4ö..Èã*ä6 ‡5dŽÇ´€hÒÂÀwÊÄ!˜6µiÓÆØ-`b!MÆ ¹J&÷ €"ÑEf@À²˜ÃýºîØåpG,‡{bù#W ƒåîßåp/‡;>9|‘Èá«D_&rü:q78â’F¡Ÿ \ÙÏ[Ÿyé*‘‚ ¡›Ø'wäÓõÕå'ØéަÁ¸}3Æ}&ÀÀºµ:)®Ñ/“[·{Ú§¶°%#©!ìä¦Z÷YnÝñï*P¾½ˆËÌOÈ4 ЇÐ,g©ÉM)¡¤XFZ nKì2°Kõà–ÆàGÅÓ+D ])‡‡¡êö6•[ß0d±Z€1*)°¥ÀÜ*•AA¦ æUn·Î!˜¦ÍF¦vzm`£˜Ï¾-°DjI6,|¯ó2ÁJtÁj8î‡Iù<Ìv§E®’%^®Iå†7ˆQ%8£BѰva%d8³3©„¤úŽ/oµb%$C¯ü¥¹>ZAà`ƒ-”U=‹uœ6ˆÀÎî$W@EÐ ¨bMÆÖ╘z© Íý0ü4Ny…&cX÷#'¸–¾(L hÄr×ëš-¼d…¬Qˆ¦é"2Q\ÂL¨€³À! \ë~ *tá͘›=2ƒÝ ß«¡ArÊc1VápØ‚CÎrlÝ2HDùÌ< Ó5ÂܾgYÊÔŽßátÄËG§TX….VŸ{ÀF6%Ž%Ç®=h¤06%”&­¬„ÃúÙnð…‘lC#Y®"bx-0Í-Øíâ; ¸î@–-²©ÆK¨¹oÇ*ØH¦K—¡Ç,˜o¬¼-êÝôÍÛ5îœ0Ž‹X 4²uI¸MI°=¸ÁBòE<0k›x5GÕÑ#’K*ahØ.x$ qåIŒsu“X„÷º(¹’klÕ1"ÑùÜ+ápñ\²{Õ±ú¶h‰Àö€Mýž1îÁ:<ÓN,Y*÷Œ I¤0 À»0Egå)ÍuF`+^H½…¯O…¬l(Gàl; 5šyNŽHåZŽŸ“Ô  •säн%-Hãq ݰ“Êjw‚þ‰Û V|2n0qO¼]Mø¸Mãrh“<ƒˆzJ¹/p×ñ4¦>sÀ:Ù0Õ9j¶€-– |Áp­b›Òåeâúb>"€µÔbysݰ"Éäµ &6˜šö¶É®n0«%"íÙÔWÆ•+ÿf…ì#X‡Ž;/Þ '4¥°KäTóIájK da y²7¿˜§“ãJŒ/q °A©À=K©µ‚í¬&°WÒE8£òê³ô‘Û‰ôY„ … ¦ÀyÎøçž”p°›‘%,Ñ£ðšáü;…§ô»UJ„ÌD‚œÇŸ›©íßÒdºwÛg·Ä”¸^„B"« 4¬ñ5 “cÍwFÝnÌ©GÕÆ œ€DÜéz‰Y›„j­ÍЈ*Ámà©O=‘pâ9pDXÓÜ bˆèãWZqIiÞÁ"æPc Lží‡ÚáqËÇÏêÝ·=$Öx’iz‡."rº–VEZºhÀ>vÛPã¡—Yø* _deìozRa±x60›wÐ-ÆàagµŒ#;’Ä:f Ï’aFhËŒl -ÑÌ£žQkœbY]²T`#»û ¶yðvÏb%t6ŒAÌ­DÏ ƒ]šÎ µ‹ÿ½öÁ´†e27TÜ<ö„·9Ñ÷†dJ9,o¶„ò#º]Œ”+t¹•ü¾§ÌÌ6ÂC¾u .˜db§ã›}‰çt kié‹X?ÓèÝ­›×U·4\Ì–ÈWL–Ùi‰Ø–Eø][‰ßrÐëذmœø,-ùìtl;n¼ºÑ>ÏÎbNq§· Øæ=÷v¸Z ÕŸ垊Zô[¡8@Ï L‰åýj@¬V4W¯ðð¹ú«´q›N‹)° €Â´i#KZÂbñðYÒ‹‡Oï”°`9»¸ÚîH—+´©ÑM­‡öûÔ·G_5*gý^ ·âÄcn{/Ù¢Ró WK¾VÞ~;¢¼<*k$íâÓW]¨Tu€³@lšnîÑóWawK–¾qB7NÄ–Ån=é{X¤‡OÎ<Èô ¥‡n¼^¥–Q=3bæ›né{.9_§ð9T aBBÑÞbg¯‚UJPÑ *‹”*)x;n£']- è +:ûh‡Ý3‘ÃWÍdUˉIÝêÊPuÿOp-åy&lïR;˜‚+´Fe¬_CêóVœ®éšË+¯‘#Y¸Ë<âòU¨vóîþrñ*¢2ËýéG¿½¾ 1q…gÚ×3¶6Öaíäki“€ë]ë>µVTq&ðÛÃjÛ:yòVÐݽðä„ ô´|•íƒ<«!Ï_åTdÔ) Qæ«ìpdzAïÀr‚½ŒJÝwôð´–ï|øj•©AwíÎàUV¢J‰cZ~U>šsqƹtfqÊä ;3¦Ô<Çue’µ‚o(xWbñÉ¥ø¾‘K*Ï㬇`J ¬$UáüÑÎcc*{âx+'r¹D œ”©´‰iÒ©ôÂäŠð5€Lp©»IÊ–Ãí¤‹„¶gž1¯ãó}à×l75tÌey *äûŠ»¿q)&?ÏÀ™£''^/R'³|a"±{Íà«NŒxzX±·p 4gq?ƒoê“qO_®œßôýCSÆ‹¦O&|ß«¾Â"1ìWâuz9²2£'É*¥|ÌR‡ÍO!D?R’oÒ€|ä Þ6€U–úÑŸsySÊeô¦J0®Ç«õC&´,æCòÙ¸\žŒ­L8…ƒ©{0«‘ª02Ë5.—m®P“va£8’ì yä?"Aëû$ð™ã>½f’µ£ûáY0|w`W¥QÞlÛ ß™sUªšyæÖ™ Ìçò¹Idz'®.1ÝX¯r®ò‚®«„íøJˆi™0¹^°Í”Çúøx¦$×™ÀøZÎþ‘)S›_Î>î„•&l`z[òݲ¥éñÀgŸ\'Yp-1Ŷ\]'c¬T®Ñ¨¾/_—šÍ§k®Ø²;×ßé«DrùZ0f ™:LÙ¥.ßõ¸;WÜc§¸ÇŽjI3â-=ŸéÐæ.ç³/ßèu`!W¾°»Œ ®¥ºLã˜kz;e«³]¢q5!¨ÑDÑK}6e ¢LÌÒØñ\G± £ÆäÒsdÈÕ/ÄsÖ¿XîQWåOx.Õ{b»dó܈Ï\y²ª/]P(Ó©ˆ-Êãýf>ç[z×â À|ó:0¦3–_[$²rÉÒcZþ³s^œzÔ‡ïì=+—ÙôZýÍߌԪˆýá-8lñ•ôÖ|/ävÞêëKwÆô”KGeä9O—‰\ÂEÞœ­óÚîÍhËXñ¥k<Îld In8ÞáKÒ8‹Y N´4q9á´×»bÅ[tÐÞéO` §hY¶æ„£ƒZJ®¬Bd]yöÈÇùj_£1æ°4ý¥)“soðØ®b Z(S®ü_ƒ—Jª$ÄHILn“¤fÃU´qÀáе[®ØšWˆí×o‡KºR_ßl¸„뢽I<Îãƒä=>°]•1^B”•}œL>Wdº„ µÓî,ä¡döW…sJdÊ•45å÷Jü`sŒ5o.”Çx•ùOS¦÷^2[Jš*®XÛMÁ "yäÌB2*§Á‹²ØáÆãDHãÈ™ûçóOINt;îöúÎð”ÞäV¼­Jwo|”.—ÓKP\zLX\NŒÆb W(ÆO\q~bÒl0xW®y¹(yŠ Îëª5í{º7œH<&´,s¸yçŒdsÖ²9cY‰Å¤Œ i%—\|i %[ã¹q½Ÿ³EŠçŒ‘â¹Ö-G­#¦tñ¹'W¸Ç—ë\bu ÆVr½ë#$æ\Ç9ãÁ°ÄbÑ?˜3¾&*±¸¿vε«Ì—%ÒH\P ™q™‚âüëUIÇf}5`+®¤ª ŽŒï§ã;ÆOUÕã»jÐÚ£÷V<¾«¦Žsr¹žé•X€é-Õ¯@èߣ>oµëµ¿Ì$W}‰Åýµ~ÄÖÔ Äârð ×nKÅù&•/¥Ý@ÑÄ2ÁQ‘X>×?ÌBÅ”‰>B'c;ßÐ7²íýŒFPn?ø\óÉÖuž8ÙBº¯ƒcLZœ'9›/LPÜ&RcrmXmÇ7XÇï^Ÿ¼Š_<.s¢‘¨„Ÿ͹|èÏ S±ì¬Ž/‘v^æ¾ðíû©dÝxJ86°G¦ÛÅeÚ ‹Ë‰cìÌéøn02¶üVÅ·¤ Ûã«y¶¯íëÒ<Ú¾»fdƒ[3Ÿs3j*ë^ʶ"ãmª†cÜÜ5£š™GŽ\`ŸÖ1•š—þ7£ºå´ì£–Í}}Ên‰Åã-—PL¹…ïq WÁ`l»ZbqŸÏ FÇtáøMËP&D¶ô‰…Ì„³J–kêo¶L.¡ºyjn=?e,“GÈ2¤isÉ(n¸>XÿµQ’Æ.;žà‹ø(`êyÃHÏ7gkV-jarÝÓÕ¨l7‰-@F™Î€ ‚\:Œ_ªÁ"Æ_¥Â+ødóØü Lì}¢óª'%5"ßüz2ð™ZôšOûUêK¶s}”ò‰ž¿¯…dnž¨!å‚«šqh$¬œQ0Æ:ï|càT"ù¬=ç„2æ¡q§¡<ÞoÕh¬ÒéµÏ‹Æ*]œ'Ýfˆ|æ“‘ÍŒ³€dÈ”ÌΙ£Ç9ç­!±ÊÆzV±Êò… Œ©¸±Aã+á_±ªÉ#ëÄòp¸^Î/¥r &gŽkIr-ø Øž„.‚xÆÑX|H"Ñß(ÓHpYIïæ9¿–¯äÀ"ä{1Yb±™ó(ž\‰Ðùw<ì7(]©——\1ƒú§œz±‰ÀŸ¹"•t¸Þ=vWÚ±ò¹JÙ/R'â»V 4AJÆÈõ‹u¸|ÈŒënI9ùû3,;;y`Ä—å¿tTñ]í/9ûVW`\ÖféI•¥1×´VhlÒ1¾7¤DÂ!kúÇRI'åªV±ïcÍesu&(¦¸·ïÆ\* çKûï­½?äý” zžd: iTƒ¦ç„mYhL~) 1‹91CçÑ™q)¢ckìG&½Ñ‰öXåßo€ â8™9ûŠD¾—o>´i¾”±æ$TØ}ƒÊ9÷ˆ~»N9&y¨«¶³ÆJõJy£Nˆ˜Q>\{øÂ4;á9›tq·T” ¸«§l°]`ƒí*¬JWrâ¦Ù²Û«ó­êE€‹²H/(ïb%ÄTÒqWò‚*¹eÔN_`AíÎûÛ ߣƒŽ­ù "‡«åˆÁ£Ðóëÿ±Š¨ÿW°Õ .•“pϳÁäë$Xb²Ã1Åh \¨پÖÄØË¹€ çÓY£:…Œâ8®S»™'/\`qæÏ×´@DÑ-rþúd”>¥5rSÀ4äühõ3çÒ™Øåj@æÇ‰L™’4—T)e.pլфõ)'ˆr®Q+ÁD» ÷›À’%×FQ‚±I¦\ßg“Œb“\Y7ŽíVÂW³À‰¸4·ãš7ÊR®Z‚±I–­Û=Xßåù ®dÿ Œë#ç^÷+ß&Ú"u¦{ƒ Œë;}®º|Š‹Mùƒ¸àº]­À¸?r¸q‚b|Å6ø¦++×à'yäòIF`\’mÅEÞ&™ã’,O¾¥dÀ¸$+X½¼‚ÕÍ+Xý¼‚ÕÑ+X= ‚Õ*X} ‚Õ *\Nÿ Dc“Õ­*Xýª‚Õ*X}¡‚ÕS(X]…‚u#-XwÒ‚u+-X÷Ò‚u3-XwÓ‚u;-x÷ÓG^#òÈjEx…ã”íGêDÞÙ{Ñ*0®hóƒ\ Oºé:É”T|)±»¸"ar)ZF‘»¸¬"/däqUO.ñ2Á—ûFˆÍûqá3va)‘©è+^),¤ÏõÂŽ¦"JA¼`»'.ΘN[Æ\à.ø“ê2| V\0‚À}H )tè5ºà2þ—ñ<¶ÆŒŠkÈ<¾ÆŒ[JfÐÍËzçk²Àç:«OÃ&zÕÁ•ôÌÚ=`´^ŒªÅü| DƒØì"ýöþuP{ €¿Ê $ŸócðøÞ6plvš:Æq½¡4`lP{Ó+§4ZüàzÀp¸ÞWÀÜø9à|€d,›¢1š!ÎŽ¼_—ÃÐñV>×k!JßdíÉ:zca+än%Ò¿ËaSñ*Ôî'¿¡¬S…§ R"“'R!f)W© 0WÔMIðÕy6¸\/j l+»ïM;P¨¿•Ée g)'VsU gª›cùF°ÈÈÆ¥Æ3Å ÇŠÆ8 îRî{÷z,QþÛá cU¨‰ôœ(óÙ>;ι®«B©—¿¿àZc2tÝ„)À–LÎ"aq9ńŸó”«ðŒÓÿðaiïš ,á²”S/Øâó¡¹qÊ5džÏõÅŽÒP™d[GsŸÍ§6X\Im¼Â¤}|{÷f4N¬N?ÒÁàíxLh;Ãö¶)UœºÆ}Õ¶‡oØ"'ŠU %“pUÝ·!ãE¤ç©\ˆEy¹Éq;Í5ˆ`³ Ñ<+ÚÌ[вTX\bñ Å#kýÈg[QœhÁw)ÔäÉ•8wöˆwg²xɵ”4Sd:ʨþɾV}Ø[…â¯Oö‹gÚe.ãݱ+æŽHO,õ\ûìð«nƒj ùèg†!ß"{UeÙš¯uh^p0ÁjÌ+hd” ,‘×yš¯F'!QõfÎú³Øúúh!A:&}oÅâBb X3%clj>¤ïÁzqI2¾BÕT0oßùéµ`{/è_–8©’•Qó8 ¦•OÍ¢ oÈöœ"q²¥s=–Oœœ+%(a,Fœ0–‚ÖX*Žœ€­%sâ'²•úúRRÄ%Ò*ÎDÇ\J«OÙäéÿp©m…È×÷Ð ¦aæ²E "Û]¥AË#>¼˜í;ù<ˆ$Vþ£ö9Mj!—ƒÓå…$'ÜÉØ%­`9AYÓ5+HÖD”“T‰+K®DT‰Ãõ8ª(æúà%— ö**1ȹ[=AãåÉž—Ü,Ü z k߃,|- JƆÉoÀõÆ6œ×^¹‹ž˜ª¢0xå.¥§]`®CàAŠ8ð]Ü(áɹ“ *)BG1]lãã´_ATaTáTYPP…WP…SP®¹íº±¯¿$)Û]Q’JÇcs ŒjÕɧzý‘Œ Š/ÊZE\øÞm´ßÝQ’ÆÚOaÃZhC¦¥[Ñ©Á4¦ØÛÌèUñº=èj©ݬJlù1‰¶XlÏ ÎöI¶¤E#þcY{žÌwÉøpk›À–2õË=ÃÀ¾CïÅçÜžwb¶p\šÑ©kÃ*´Ö(¸Ö üº½ø(­Q­qãȳ4v<×igÿ¼¥äÌlv±w¬$›Ð52»ÈÛ½¦˜ä5°ìÂnoolâVÀìS"…W8!Þ`³‹ ’",Î=iÐù÷0ù3çvÓø²5jD [æ™|ÄÌZ Í?e%._rp—3í¸FÖÇ®cjƒ˜¹NäÊàu5Ø|•™[ÐüŠÌ—!UjÎæNkÈ¥Ãø¥Œ_DÉUûJc-RÉõdH£…Š)åJc%¬`çgr…ý5Ò¢#×["5,áüÈ< üˆË†Ü#+^Á‡Äg €A*X-R0I+ÆòPI‘úŒ %‹íþ DcÁú)ÝÓÂ7P\{ýÏ9Ÿ\sN¹|r)¶<ÕþÄ÷¯‡ÊeºfíÄú3÷«<›Ç™Ãvá˜:l™]ôjˆ‰Ka +f:h”X|’œER7ä~ÄÖ44•¹ ^T`”¦5wTÆö·…›8Y&S¦6+%Óö®ÁÂý…ûÞ‚&˜r Þcýæk_}Û×¼…Шœ…Z8Ư¦:—©\Péî”étS¡ªu”9|NÐ×8â*@Ì—bBHβ÷ú÷°æù)—/ÜÀ±ÙþŒS6¾êø5ÏK·­Ì¡7 Æwô"0zŤ»%`3¶§8©ä*^BHó”Í-Óha'äõ†GÒŒ+|¦÷NçgÁøÐ:®Éé›–e Æ$ßïzcnžSRC<¶ÖWÛè¦h–ß~Lÿ†sÞ6¸J¤‹Cï^ô0§ ›i¥×kóÒ7_t пÉÈò›ÇÖ)XcQF2§yß®ßþf¸ÛYÕ ñU2Ñxaĺ>"É Çk^NË—,R>-®#Œ€q³Žßó –²ú©dÝm5çv›²º)ià‡~ÆO¬ùà—SQ¨+ÛkSXŠo^Uì>°5W6x?€ñy¡ñ=­Ñøâ9¦ßA<÷>›œekÎáã´*t㤖’«œ.!²ºyöÈ ·âôÙ.Ô‚Õ>Õh‚'SÇà1®ÿŽmÉ.Ù Ôk(¾ é2äê]¨¡øâ¯Ë<ób®ªÂÊ_8Œùlçyle .ÈL?>ÀˆU¾_¥SP3àN†I¶æÔ^ «€¦,?Û±Ø_,c¶+á/"¶þܦ. %5ælž¢FTìì«P†3¶ˆ‘¿âhÁ5b,ˆXbÍ[êòúFÛ+N9§±• ¡QsŸˆëÆH㥱˺læ’+_U£¥dDѲœë5Ÿ†ãÔÅl=y7Z•“—ÈgŽ÷T_{#âŠ+µVc± F`|õ~[¹ªˆ³^2EN­ÂlYŽTWƒk Vâ°¥†$A§›è[8§€³´âì!ªx{ˆ*¾âг"€â-  8SCYÝ-•q­òÌÉæŠ-ŽnÐø°V¼¢­ødóö?_xÍ›m ¶ïnôµXq¾¯óáëÀØv:¾' *KÜ„+%#Xê:Jºldz§'u…§2.ãHx\þÆâ*¼RbE9—©ÕpœSÊÖ«¯ãSÎ… ®C^–z\݃¨ï0ß‹í­=ox„P£ñI7ÙÑ%›ªÍS>U›sn-%Ûw\½÷4VĽ¹DÜ»KĹD¼ŸÊhÛ"N{qªHÂ÷ÂQƒ±®«dg]½¡p¾ÆcuŸ››²žò4ã>Êéùe1×ñß`±Ù ,æ:®,F¹|¾‡ Ç·Ð5£Ó‘Å|ʯ±'€í.³㔌uȺcöVÙ~2ŠÆx$#0ÆÈY§ gžƒœ×tä|sº’©âtÔç)W$¸ãÒ¶”ô•ËØ†Ðæûp~ _òÓˆ ÊÕæÒ‘*ºòH7° Ÿùl@ù®•5$•a%!ç{öŸWUö!Ѓ€¯ôºNßw§9ãdÓËÚT&ã2Ì#öovòléI%è®a_§á+§[¦© l6A ГnìqðJÈ(¦d~H®d›’WlÅ+PµÖšî½zj!Ö‰Ÿ{Uõ-6ÄÔ)¸!37á†Ì½DÌò9)#gH×q—Œ¸‘ÿÈ.«ÆäV¨Â™±!%¼E4`<ç /×þX°æ°œIë¯tuÆSñR­#®J#•õPS'Z´ÖÁ.ƒÖJhóøí&¿Uåß'ïOÞˆ¹{X89áÂÛVá1¡q¶†Ì²5_MÈ ŒÍVft4e +g…p©Ç?û‡ì·ÁkgÙ?l×à¹8\‰yà>$…ÇýÈ«¾å|ÏÇó0ΣŒ©)j Ƅŷ(óˆZ80bl`|w%Ï•…ÆŠµî³Í$gj¶tÚå]Þð™‰Wd\9eSú\®dà3ÝOÖVÝ×»T·nIÆ2Ê9cƒœòa˜ ø‚ *RmÉ^c—3ž‡óòdÇö™ZýùàVŒ]zWkõ…•ÇŠÆ–ËCHLˆÒ–¨G`œ²•¾mA2Îc®gH«9ëŒÎ3VsÖ¬ Ç)ÜÒ‰\¯ÔVŒ.ò*ä«Ü²bÎÑç­ë³â5’œ5MV¼©G+ÖÜ£çòŠq_W 4ŵ·ðÎ%çTR¯S>(¦“¯H™©PÆtëFX —¦2*jáòU€ÑX|à 7Íâé|X¸ŠõÅÿ'²mð¸ô_cq½ç.±ØÊ¿ç°½VªÀø&“o(¾ò/Œ­Ü‚Æb,R£±M[%Å[,¤Èöµ|ÅB ë§2®¾úf¶&/TãñÕ Ñ`|9Œ÷C9Í[ ÅVE£Äb[œlU4J,F¹øªh8>õg«{Qb1WÝ‹ ŒS2Ö!ã3NãÃVCÃ`1úµ|54*0^ÑXeã5\44˜þ‡Ë÷¸ž k4¾Z×|f1Û›ó¸Î˜¼Çšº§ÁÖ Û¡‡°¸äâÔ×P†|(±(ŒíD¡ÁÂxÅ5›1”¦ÑØ2ÆŠ8õä#×h°y*¹F3L^¤>Wú¥bJçá Þ?zÒM×\iK^*וI&=ÁXÆà¦)W›KWUƒqSÉä‚·QW2e› Õ”ˆHœ4dÚÅws‹ Ú:㺄#8z‘»ô˜60TLWŽpépŠGËðA®tÁ”Zº…ÊšrÎ7-ƃ2Îg\ƒOF9“ÓMhó æŠ²8¶=”Ð(ûW[FÖ^®ÙÞœÞç‚q5àéðâŒð=3˜6"2-®9mMƒÊªŠ•­»r…Gi´9£ˆÔM’þÇ©=UJ3[̽Œg?øðâÄùÉÕoqƒÇXï@“Ða:LÕhÝŠ+oFŒMCW>ÀŸ¹ã‰NI˜×¿H ¼TÎe*#—q¢SùCº€cŒcuCÓ0#×VŒæ§BeµºjÉ–Çlàü$×]˜ÁËR¶Ö±„—3Ÿrn*çuræ=+‡ìZ9»õɹ;gwmsvß6gwnsnï6|®*ŽÜ#o´h¥w®†W/æJ-%´"uf“ʵ ©†L¥‹€”‘ëµ§|#jp7,ÂS~Â,&u¼ŒyÇT»fŒAæ$͘+¢È'KŽ¿óÿ{Zˆÿü™‘øwÿ>øýä÷4<ÿ÷Ų׈—WW£éT\¦W“ñÝýøö¦Šu©N^;FOðP¢ý>–ß^Sô žHüŸ3šŠ™/ü…’(Ü™‹ÅŸÏÃ÷p 4ø ²=HÍm[º3¨ìHlôúŠñú'½Ä…`+™ÕªC¡DG5>0Ž<"§_½†>°Ûœ~x:Nô騻M'T´'·0›q‹² k|eþÜ—éÕ2ö]à@mñÀÆk‹=l ?b ?X 4N7qyó7J~þq|/¦÷“ñÍgá.%]b#¾¡Åší.ÉBï³CƒÆÈce^L‘9“ÿ˜·9òP8Ê…ó˜¬A<‡­oêó·;üÚl8€K¦áÀ©ñíí×Ñ%*r@ £›ïßF“ËûÑ5p6Z$ Ô*iqX-Øœ·8`&¥Å‘Åâã †å^}?nôw|ÿïèú~üm$ïæ[¶‰€ÎË6n]n3Ù›'ØêÙ&ú1ÛT°Õº‡¨¹ƒòÁ7é.\ùЛõøò>dÜpm8pCus?ú<šó> I`Ên €S]1À<¦š¨I\`¦·&zI7ß¿~ª‘ÇM±‡ÍïíÇÿ]Ý7wì@ ÜT¸)¨p“pu?j"7×£OÈoisÁv‡ l‹è°õ«Mcifìè̪ß]ÝÿœO!aW¦™˜ÎpÚ!²Á…Vhb߳£PpØ21èÊ–†) ¦ìh˜²¤aÊ‚†iyùñë¾Ãl3á6™m&ܪ‰l ›³1TeÇtôßßG7W#ðåsCƒ¤¸GD¹4Ê)q<4#m7N„r“;L°`úHQãÇ "/jCà9™ƒ%Ï3ÎÞ¶r1<9wò e/3 Y £½p…SàCè­¶Â^Ä´„|´B"æØe¢§ûM€Æ³µ¸_Ãi¬­öm2\.NE˜Åâûý§÷XœW·!À™—û‹|gÙpàܺ n¨ðùØ$ tæ8ÝœcM¬@gS`S(¬äMm²2’©øÿH¯ìÔ!ûûn„;ÎtàJ xØY¯F§ª "v3S 7ë5›&Ü't½DXx,ºÅ)W6¦üûÍøÏÑdj!k› ·Om3Á4z›H›fè\Ý_aÝŸšè5a"L_ Ðz­y€ú\1õ¸bÀéoEôºj ˜an€ß§÷x¹!AªUCÓ¬?ÇÓ±›Ã.n̺<°as<Ï܇±— !›EÈõn¶í$ÍýÈϨÔèúÈ#•Yc󆾘ù1ìõü…T ©†]ä”Ç[=Ÿ‘žå9˜cuŠ"ÐÞûŒJWbðý¡‡SIG©¤^¨!é<865v€€ ·$@­^ƒ.ÁSLd0¯¢fÐËKs$ x€°£ƒµo5t GžœƒG «@‰ƒ ”ð87Ôà+q D¼p3P:€¡È#ð¬dêÏA Eá¬<s–ŠÇQ:q¦Æ5†€¦ºHœTÁd×ÐÚ—@]iú™¿‚•¡êpÀ¬i’gBÆ TGž4”ü Ü iæp›@æ,†°6núy@Àe˜tø…ùè nÙ60«a€Ù…Rñ¡Æ¹Ã?]òìMAWh•Fh…F`uÆï÷ÜNÆ÷‹ñͧ[QUfÆŒÑ^*̈í¥ÂŽß—ÑßcTAª-ð˜•$ˆÑúx9_‰«Û›éýär|sÒ´]ȈíÒ@Æì´Â8ÁÏggHTål ,œMð8è=ꨢÖšnÆÕ”5ô/€7Ôþ8þ|óýÈŒoÉÜÀÊr´ VFã—Ý1Ð**﯒TÎ}þøV‡Cås(‡²ð ûÔþmFç7K C Ô[rƒ'Ô<ô‘ÚÅd)Àlp4°QÕT:Ô…ðgޏ™ë0™&õb‘;©e eÈyˆ£gCJemä ä×xr–/š¥ˆ¡X¤N(¢8s's!Ó4æ&DÀ¶Ö0pa×`û•¿GãC‡§¢€RB4}þ€*¡ÏÍf ‚ž9J^œ¡ÀõÞ/1+u.\?YÂÀCþÐi ÍüXd(s¯ñó³ÛÏõ>øÎ ~YÂÿ£Q1О•½CÓ¨eœЗ›k;†y7lÐQg>H1É/,}BÅî Ÿ¾f:9mê” #¡4D-“¾>Û›sì#’e¬2ácvssÂ7í’AàÆ>ý;0ƒ>]¨CA¨·“ÐÌÖԳŀ9s½Yz ;n‡4䞀 x…Û]P?26Wߦ0l*¼ ¿ûr5}CÆB ž\ÙÄñ1î¸q!Òwj|X€¡Ï1gíƒÜpŽÙV šÚ«ëC! èR”LA@þ’S 49g2h|Š÷fãÂD&˜ xƒ NbÌò4I瘕™d)Î-JrÅ_°9 °E£¾‚¼:)‘‘û¼2§]ØF¯PÛ¼ÂmòJ1&¾ h‡!Ã"› é6 ê;T¸Øx”²2$¸8¾‡»põùkôÌMè¹\à`âÉ*nû´ª`¬\@ßÀSº{ C¿™(M¨ðc7Yé’ By!t'\Ì+ØåÊ ¸„WP:$݈_Ç7×eUøh%‘ü]DýëiÅF žl‹£¨-\ߤm–li¬|€‡Þbòñ:æ[Q1H„¾…t—¶XìL¼–<ñ=5õKB”†ª Q†¤j$†‚Æx|%6h…™ÆW™ƒ1BŸG7WÍQþíöæÞÈ)TÐ&@©cC€Rœ†¤= >$VÑŹñ“3]ÝA'º!@MtCšè4Ñ}8O¦T2‚ŠGHÃbxšBu%?ñ$ÈÏA´+aE§låg€k¹1ó#²FdhdOò1)‘—¥ÓÈaÂ_ä ›PJê`ÄÄ„±‡:¨WÐâgî#ryJí³ $B£E7øeó HçÀm&ÔnU“ N+5¾òÑX2˜ëN@iÞ hÝZðØõ 4£ :ö Âr¡TAƒ|5‹^g~’Æ®ûõ²ÃWÐ0 R9à1ÕL˜qN|ÐQµ–´†£tÇe޲4‰  CƒŠ.lð1a…OhðA„(Òàà<„jlØb‚Uɼ5#©!M5¶’¹Ãî Zðô¯ÄSE –ê¥8Ï=…9Ô”öºV$èH.êÒÂÇ…m0l r›An-¹´°‘(ˆÍbašŒn¾M.ïG×H–ñÍýèóh‚ ÈAq½t-Ÿƒ”på¹q±$OWÄ> ø÷OâÛèèú¸_¤1à¸Ò/ÊÁ( §-Ê’d ¡S jl•¥(±5tà:€Ý¾ÆFä䔨bL®.¿¾~_þª&þÙ[(¦÷b*2*Ny žÇoƒ“!Ãï“‘á@à‚‘á@ogF†ÁF†s8à #ÃÒ_ Èv+%´õ‡¡@µ\1àȦ+%ÛxÅP ú£ð_ìço€G¶H¹MîÇŸÆWú¸swûu|5º?í#²öEoñêÛåUùÐ TbC€H[nÐ1³]£›t¼²" ¤…rC›âO~ˆýè1"aÎ Ǽ±5Ø©T9 £äêÛT\fYêÏòL*1¥¦ÛÑ%úÓôÍRåÙRF™¯ÏPÒ»v2Gu%ÓÌŸ¦«eì»úëp\q˜hMPðoŠ£Lß8šÇ(SÕ%±ò%kÕå(ï£0Fw*®ý…TpE®“¨œšózV&iT: ¶ÙÌ(ÂN;L07{‡ÉÒÐi×~€ñí ÕJqRQ•uk,Á†n¬T.ÓËÈ›ê­Ï nÊÒ´0º/£/cªP¯w&0Í„îj}øªý"×— ½mèl|Þ)úïS'R–ènS¡ýì,N7cy›j!¬PZú´»|ø.ö£´¯™¶ÜÀOq:˜T³ö§ÁT¶Ô±äZÅz ý8"2ôHÞ9Jѹ¥/Ô4ÒO²IÙª±ÚÔøk‡ï¡‚9ñ[<&ò`®€ùs=öÐÙš)ÔÉ¡¢‡úD¯—‘,åòiüC¨½í®V¤oÏ.´häCê—+ PîŸïA @ì¡Ó›–p©¡E>3šN(ø¡ò¹§6fQ!ê0¶‡*©¶Nk|v¾ Ò¸ªC£M££Kב*#“86 ×'hL|½ËýŽÔÆüTL¤sPcØâÁÁm"¬ñk±Ù˜"ꪾÈEÔéÝæÓ¿Ds¬ÌŒz!&›ãy'{®ap\ûl+Ž ¦o%: £RžÖ›Ì3Ù¢z%šk°u2Äñ g}€œõAk:°QÚc~U@¨Ð¥ xýÐðÀ 2'òœÌäVwÓpHó•lR¢ƒòMJpäÅ2°Rac¯;$СËûsûò’è"/Áç°ul4@ÆÌžó $Aúã†@V¹÷¨€Jë 'X&T› Èjöà4(÷fôöæ“6çó_=GþðVŠDCK6ªÃ8C\;ÕøJºÙA-b!ÈR?Z`ðý0öò@Û3ïД¿ÄóDâî6K®RÐm×6“IÓÆÒàz5ïÐ`Ç-ˆ@L­FÆuƒŽ2êÕè# ßµññ«Âš•DŠnª|µsÀ¶Üš·(Ú Àݼ¦É#ܧ$Nª¤|Äõá—QÿÒý e¶Ôµnx"ò¯0ðÀJ>“¯âz<½w·ã›{T¡-LNê ä˜:ùûîþVÜÿ1]^¯1iÉÛˆJ;ÛyšBî»·xh³¢.÷3qúÞ"[:ˆMd‹DÙü"Už¯dêówBÞÇ•Ä~”!s%eßaâ0%¾;sÃ÷¸L­ ,u§bqCbqq‡=ZúíŒ.—™©X¬|æQ‡B/@Ÿç.GæÂ,Ã|F øä—ù¸¨^A-šP/ÒæC*áÊÂXI•¥ñZxëˆ4 ñà²"Ò†l4+x:Új[í ’fJ"ä!lô@šnD®gI±€;ä +ùbË!Gn‘ +ùbË!·ðE¨ˆu‡éõWÀ˜YÅJíc:ŽtY §—üôb²œªà<ºDdÕæX=ž²JYïÏ69­+è2yCÞO[¼û e”9˜<Œ#y:~äI@Áà w²  F0i]éQÏ(¾y¹Pïz‹ÒŸ-¬Ì}”'gùÂΧmèÀ§¢šÌ–ŽXS2ð£^M„eñ•6w)µÝÀYZd¼¤(ÑÁç<3¢ È_»Ä°UÑ>¼ÍȦj8€×í´œÁNµm·$Þe†U[|à³ý.øËòÐØØêŒ­\ì$q¢Ýè9 ²ÂÏÕÒ8]Áƒ:Ä6$ØýPãÇ+inï“­lF'”ýè„ê!:¡lG'>h ¬ ”ü²ÎV–ÏÙÊâ9[Ù=g+›çleñœ­l³A½+ôl©Í¼©Œ[<‚=U'”Aà;âºt½?büÓ},b瑘÷šlô × °ß AdcÌÚ,ð1ƒ6‰nHÀLj6ßNA«y`‡ýšÚe»!A OÂ5ªåöõh*¦wu(;ðºexröþmødKÜ•óã©ÑQÃoð¡ýÔ+,¾‰Åkí¡‡k~†Q"œø•%:…€k+t |¤™3øž<…¯š$´À_n5 ž$ÆKäRÿÔQƒÚ`ð_ýWè„8@‚ógеÀ1iŽS_‰B:0?‚v©TJèÚÈáWk 6:¨°a'èáÿ™;ÐMÔ®‡0Ý7ÑŸa]3†Vóž§Œ »ôFA6¢æÈ#4KìyHoº,ç$²X õ÷`ÔiÚòG¨ÍøCÜ&2šN¿" þÀ€E’Ï0£þ‡©GHý£ñðzxbýyÊ£q2’©ƒ_Û'”¢Á~È66LðR4 ê^wKËÖˆG(%,pÜ-ªX€³[Þ Â„÷ÿX¢<Ñþá%ütÙ¥ó7”]ºþÃØ%© 8¤ÎRƒžh§ጴáù¤×ãÉèêþvò÷ô~2¾ù Ú!·H0S±E±œãéÝ×Ë¿ïGÝ£FjC¥ h„ª¢câæòÛ6JÔHuHÀ£…(ô‡Ç¸ äÁØõôò.õWÚïý¢˜qÒù,ð]$îܪ±§cÔÞPÃF…À!Ê©±=Pûí Ô}Á kGñú4LM°§ì6ò˜½ŸrÎ6Tø£XE;‹mðGmM‚²Èö†=jdÈ©CƒÛT4HÍD† µ½˜FŠZxÄ‘ÛÀ#âàÐÐÀíö5«ÏÞ„ŽŒž4è(ÿ ?éâcLÙ­ø6ºÿãöZÌ$  s ßãwÝAŸ»SÓDyý€X”‚R¬Bè~¨ÎE3í5™·08ô•Ã_›ÀÝ8ÒÖ33½@çÿ[LQÆ´´1ȘcÖ­#CIÓ²<ŽãIσ§ ž9þ’ø²Áßbš³p(ÓfÌ1Gµ[ìQíVŸ÷³ålíxÆTZ9R•4Ð=S•ð${½µš: è¤2ºj§(ÝÞnô/Äà÷“ßbtÅ‚ÞÉõ0ìÛc`DÍñÉÐ MAhö­mvÄÚËBМ¶÷¢¿©E”Æoß´Äï\¶àðé<¿xÞr ßà›#~së… ¥Ü½ÚÁX2¯Û(ÖÀHã˜Àƒ¶±Md‡ \íØ7Šá˜õÆšŽ_íoÚî.'—ßF÷£É¶¿µ(P[\‹´ËÝ}±1R_lŒÕ+£µ¹G¯.l°˜ë‘±ó)bô—¸¾¼¿4¥Ó² UäCí|ûøà\ö¾ÊÎ÷çM¢$Ÿ?%"Œ#¤d8¨+šC™jP–Éí÷»úe_x¾rS?ô#c×j²fù#IBŒÍ¬ÐãâãUðÆ÷­ÐÁ#¯-ÔID§h"%%rá™þ6*˜«B0ÏÌQ¾Ù:ÏŽÖÞ¹ãÂç†Zu¯$™I+<å}”È“ øÒqêIô̘nÙÕ 'Å÷#J®ŒSÏô7⦪N±ÀWO2Ê,ux¸¨YYàÀñ0}‰>‹†æ˜¤ÇÜ+P̽BGJxo ÑA«]žOËì¿’4þ!ÝÌ_uŒ,$±aÞµX`Ò¥|„¯Gßä¶# ”p2j®çG¦^)’(ŽJ§È:²Ò$ 4¢[qäH;ƒ:Ÿ”è±›ÁW†ÁÎ0÷mŠ%&…±Ã¡ È¡z³Ëª»\”B}xUJz–‰³Ø‚1UvìœÂ¡ÉøÏËû4PÚâ@åE¶9PÕÜøç~ùÕî‰8ˆ]ï.'÷ãŠýu U(: ˆ—¥£›Ïã›QyăAS„g.ÂØËÀ$”4³5¢enÚMž8×ð¡Gž¤|”nž93Ü Aj ´°éKÐøU írj C‡˜¡›l* n^}z‰„§’`|ìL.o®¡øXñ§÷·“’Àõ“%àEûƒÑÂøh"þò)m më<9t7j“U­;Q#‰êç‹Ø%Þ°`WJMƒ¶X-;„¶` ús´“¯í(¶¿Ðlx F­$‚ÚT½Ë.®k‹§ô­èØÜO±*†©Ö"ÀÍ zägV&"p°ó@õ®Ìý;ÝV[ù C˜ÏlñA 3µñå#t‚“F@i1t]bÉ‚õß"Ô;¨=6¨íIêü8+$¶f ?l©\!ñ• „ø’2ÔMM æGeNæ»æ?Ð2Q<ì®J{ Ûì ŽT‘e¨oÊ)ÃUâz8•6,ÞZop>)Û6ª˜p›£“ˆäi¥iRš!c)”;m‚-s‰â^2m¶ü9Ue:©\ø*“)0Ú´¡À…2dœ©MbáS¦ ‰…FË*Þbaî …A#+Ê\Yú$+Jmˆ,}=å_¤t¹b*Xƒóü;dà`j‡ËÒaz—Ó-±¦¶tö^ØÐ‰0^Á&HAS(6…BS(:…BS(6…B¡S(>ï@ÙÈ;P¶òZe“-P€-‡…Ô†6 Ú’XImh¡-‹…Ô†6CPS½•6•%‡e‡Ò6yUYÌ}Qø„dƒÔ…¥DŽVy.ÏBÙʳP¶ó 6„vò >Û7 uw)$¾E nÇr[¸ÊÍ# mœ‹ÒbAz]+ŸƒôÛ4V>zNmñ€½ÔØi1Y²pÛŒX2PCÀÉļÿ“i§ ?®C±‚q”5d ¿”u<Ø"CS˜&%@S‰@;Hø‘2IäiZf‰ ÐƒÌ H¡t@Òw(pëÛ¤xÓÕL¨]eã!W4”?Ü|Ó,uR@bREJBlÐÍBÇi¯†Ä/EsLºœÞ  fŰ|ßZ ¹±ÀñýžäêÛÔÉí·;,76lò÷ݽ £&¶pj#ˆ'±0ZeÓ_ ,6Flte£ ŒÀyô/ð$Z0/ŸÆwLåíÇÿ²@r5µ0`w£oH¾\MC;<ïð4œ²ÀbÊÝ[X-ßÇxŽ¿ÎO>üyj‡ÏR‚ây‰”À÷wâÞâÀ¹ ½vF؆’Ê@3I+É2»™ª²¥=È£šÈ$l™+;AI¢™’<ÂnºÓ©¸MîÅøº¬ÄÇTÖk`ê{¶ //5þx:ý>šˆéh2¾ü ›‡. l6º4°9éÒ ff:þ|3¾ù\jjb:$°yé°À¦¥Ã™•?ïÄÇu&Õ}üñ&]Ã_ïþЪuuÿ—˜±û ”ÿ`NºL¨Ê‹[,¨2¹»4)*#k‹Ê´]s@Šòv9¬ Ƹt9LO”$¹u].L…•-޵…^ ju‰(…ÈÊ.·)iÎ] *‚©KÒåQ˜¾KdOáL.°ãyx—*£Bœð!4É…Y¬?*uB$‘Ä‹éÁ8žA¨8Í$Ô2À§~QwÝô…ª64V¶;¼˜5H‹‘fI¤ìÌ|Ù+nJ|ððUI`÷Î6ÊnTÈY@ïp¦¿]Ão:ZÈ[ŽšuÃÑÂGMwM‘JðtW5U°Ë† јqƒŽ,W$àà«fÇC50Ú #ã š:æ©;,F¥ “ “û6‘@gžÐa»þÝÇ:øEN°À41îâ㦘H^áSÙ} ø—«éûáÝ—Ñß øÑßCƳ4~€DΊ›ïÑaÀ´Wh³@ÖÚ°|’†a!³z¢.ú·˜lÐ`³ :Lˆ·Ûv¾DOÌBFÚ ŸÇx²8‘)(a¼M…ÊÃi@ê ¶9­k³OÆé0¡—‚/í „“!wš†BÌÖâf (Á¶—éöãYbÊ +&J(Ðt'x í"ûæ\¸áE«6@'¹MõÏJ¨ÿd(È­±@6ý5V¯|: ‰±†”9jˆdVߊ<^5 T}±:Ö]4ž",M»¦@j´w 5À; £+ Ö—$Ræ-°‘­à‡64îÐÏ9‹æA°W†‰]ÆÑøà­ƒjǃÃ@†ž1ØðLIÝ …… †á ƒ 6 ï­»LxÃGOø¹ªÅ„=04Dp_»a²`1Us3hÈäíPaCC7ä~v™V&½Þ‘H¥¯GÖ-Bì(úJQ«‘$è~D÷Ñ¡ãª6ü2­À®¬ÀhÈ€^± ãê 8¨®œ•´²L:Ì àae#Ì àaÓ–óÙfÀ^c·|B›+XÞ¶AÇN1Ú=©¼ìØr}º<¸šJ'ÀåÔ:,áû¶ý"¶ÌZˆ0örDãŠXòà=Ü#zG*1¾î ãË´ðÅ’fµt0w& “‹ÉÞhðç3ý8šþX|ÿRãKP¾l¿+i ÿGPÂŒÁÿ0Äš#ÂGŽ?áƒDE&€i$4>ÔHh|¨‘ÐøH#1<¿€.â ß‚Oa˜€3að±æ¢¦@À¿‹4„4„4„6(Ÿb6‡Y"‚žÏ.΀à(h”6jh”¢¸N(ƒÀw Ö. Î.ïðXa±ð-(ÅêàU xé’ØP1äqa›Å·àU è7$H¹KbAÅ .æ6‹…o«Ò£r•uË ÃüžˆŽ›^B‡Í+0÷Ñ“ ¦1e*p2Vè‹SðQZn°=y ‡jcI€TÉš¨—5N9k,ZMaö¸"@b£W^EÑúƒV¨ö±qª£Èn*LPºžÂT&’‘+¢TdÕT 1™%³u¤Ï 0’2¿L’"Iãô^Ã÷¤Søf(kx8ÊDp” ½!3¡wÂÅ™˜ÔгØÂ!ø‹3(<¶ä+t6jÁ6j½§.j¬Ï´ŽÃ Mjí§ÒñhçTYŠê8Ú¥¡ÉÝOýD†Þà3JJf Jp\Ýà£V¬G-Y÷ë`©=x8Ä‚>¿@AŸ¾‡I}>Àx\‚»’©:XÚø·³³·¡K? ’8x^Ýn®G×ô`M|Ÿ^~ê@ìòz%òÛù+âñí§ñÝT¸qšæIFYCXNˆIl J txR€gÒ%@Tji¤ »™aðÒÙcD6ðzx¨˜<–X½Kcú/Z†w™´g¦YJ' šHK èʸ¡PXŤš7VfAtÜ ÏÖê|[î8OÔàÓ:C:r†N(™{1|2ÈI@ª*Î!­à3L‹†.…‡¢ R+®ËWXm¼³:г²¡0­q;DA}e%ƒy†¨ÓAÇ…WÛ wÕ»,ˆ‡±»,ˆç«]àžºáãÚPÀëùØÀ) Hûö-Th½a.|:0ù]޹ãÃN- É¿ú`—5ø\à®QÚüwá]ŠÇ§ ¯ dä¡Âà#}MC<µ|Ü©¥‚Ç)Ø‘¢dzûÌO6ø8Wÿóèf4¹ü*n.¿¦˜‹×.$q£K¸·j3@:!v<ÀãØ|¢Ën-q¶”é â5Æ.×Ê r0\wñªkоc)T3ów8»\Ø™Ÿ~ÿx?—LMÕ°š¡d|»¼‚€Š«û¿`6ˆI :$ݤA7=¥gÁïà LQk )öÝ É߯€O<ÄÕþøztù«Tàó7Àß]z^ú‘²ÅÆÎ” R©«eì»c1·I¬| Âb6ŸœÐÖàѪH°£U‘@Gë68Ñ­\5 v¼jè€Ù.ƒªéôûøæ³¸OïÅÝíøæ4\»<˜!ÛåA Û—ÉÇsqy7ý÷ÇÛkPì-Èpmq`‡ =Lè!Ï÷û?®/ï/‘#TS©¦€ŽÓèæ½æZ,ØÑªYІ,ü@áéêÑÕ—é÷oÀQj(pÃÔPÀÆits6R5n”jä Ñ Jè™öÈ!Bµ^5øw“ñÍ.¿Å§ l¨îÇz*Ö»"À RE€¡/ho fŽÑœðõV† ¢»æO®Ð˜ ˜+!CB® Štœd~ñ‡· WzáÛ5} Ó3”nœ‰ûÔ‰ÔŸ!žet‰à:6¶ b˜¤ê.‡²5#Ê_<È…>8ûsàwüu~ò¼J Vy DyoïÇÚ=¡ŽT mŠÔK Ý"×I„¶*8Hý†¸ÐØ©“¼éšD)™®|ı°ÅåB CYY1÷ƒÌ¨Euºµ×d¡ !±“ >ŠÑ*õ2…[js'CÜDÕ ™'S€ûÜÀ§®£$rŽ5E„æÐNÀÐÎsá'’6 ~ãsަÀÒÖ†B£zRýŠåÝXîÿM`½Ú7è˜ì€sÛÀCNF‰Œô_û€q)¡ÏÞõ“¥Ö 8ç/¤Ÿ¹û8Þ]N.AM·6ð5ÚÀ#ÔH£c‡;2Èùrý «6Ððl #4ú&.§7Lः õ5 Eê"¼]xØL¥`š‘Ôè†$58¨mˆ÷pd4:nd48pdLÅS“r [º] ˜öoh°«l¶Î´ ýOÎ…«Ý ™è@S<`². xŒz»Fè”9úóN\ï´Om&“¤±+²u‚Yv°ÅfôòêÛ~ýGâ¤Nð͆éå]꯴Éû(½Ý¦wß?~ý å@ÖèêîËqÈ q2kóX˜”Ñ|Nö÷+ÁñÝ}¹š¾Ã¿ÃSÓÙ?õÙ€ÙÛ’ <õ64xbÇzM> |ÍŸrܰèâòû_`cKî.Ç4Ïä+˜a2úoÊc®Á±®àÝÃbLjTTð%^ñØ9[îPÅei’,¸EDcÛ5"N°{TS]¤†Â–›d-¨ƒ­udkYrÍj*¼{V1YQ¬›V3`]µ†Å‚»¶áBºl ÊmÃ¥%:î¾¥ £ÜÁê Vp“Õð ­HC0 þ_Cdcb°ž_ÉaÑí+ q>ßãðµð­Lÿ¤oÏ›/¶bC뵕Â;•¨GÙÐà'æKnàaŽd‹ëE¶‰@.d‹å?v)ôVó?@Tx±A/ÓxT¦}ïÌ„u]+;ŸbÁO¶4ípáÍ$>lºá±æ7[ œ¶©ìÌ“u;Ýâ°c'Ðn{ÃaMûìºï6Ñ-FËËši²¦¶Î V¢Ñ*;>CÀÒ[46Îðô öLѦÁœ+´) µÜÿ1½ü„jP±|¼ü êbÐ&€äuI‰ÿíòJà:l“ Gª!ŽÖ—yzV Ó?°$wGò-ø¹öW É_&¬â ã_} tqÔ6¾¸4è‘éÕôîÆ¡Â"€7ã-H¡Ãþ<õeäëÈ·t¸EwZ\?uO•—Zö0»B,ʙÖb8•¤¹3g1|„¸Ù». ºiMƒ©ÛW¡{Ò€ ÔY¤Qן˜å ÷ZN–¥¸ÁGÛ:¡x åjlàžªOKa£§ˆ~mè t(Oâ¸Æj ‚"ÒKÚ¬àÎZS7T +¥¡GÁ6!3ÇNž-¡[aIÞyNæ€)ôºÀ²¤€B‚5øŒ*àWµÒV¸QU¶IGvÔµâÁ*lCVÙ²x6rZȹVž&’C;°Xñíó§úe9ÇYˆ‚*܈?¾]^áÄôKÔLh3kl^ø+œ”U€±$0ôoŽœ…•…ÀcÅb”JôN\ÞßOLEÜ)¦"ùs4úIs=þL]¾a'î†ÿ (¿ÿÝ\Mþ¾ƒŽRM¦š:Nâêöæ~tƒ«†;^ rÌþ}½½úÜ‎VŪñtú}4—7×Ô x|ùµª›i8E»dÀ¹Ú%ÃMÚdt5¾¸ŽÝ;,‹ÊÃ3g¨ÅbejP¾ß;ã'®‘s_1g£bÀÍ„!˜ÀWI›¦^&˜¸M— =5ôJi³€—JÍ‚èã¶¡±âvt‰ÀJ`Ã1#évÏŸ™ ò£…€´ƒiè5ÔÓ1eÈK7Ž2e RÛl*Ô£ç:üõó·™rÐ…ø»&íÅŸû.êÚ½b¥ ”è©týÄ—€Î‹{8@ÕX"ZœN–§Èé(û ZÑ/C…‰-¾+[gÏÓ8¬hsS[œ‰v3Ø*¡{¡kéÆjª‰T¶»ÁÇînàÿÄ4‡­$îBö]µÃ–+¡YÔ(ïØËQ{2å5·…©'Ð-›ó†šÑ:ñ ¹GÕàÝ¡&Ãz±Áfƒ¸,mq tï1,XxÄÁí˜IêëÙÍAøær”Ž"Ζ0/Fµ—jIÙ IPúH@èYRí±ÈùT1‚Æ»öÍ1ê–)?L‰¶­¨ù<‹ÅýTÿsz@nHV¸IØzs¥¶‰`;Þ6jÿ{_¿¿É•³@òàòêñ¿I™± ñŸöˆY?@²´v~Ÿ^~‰»Ñd| »åÚ¦­ºmÈš»ý:¾úh¤6ø˜QÚàã†ç¿¿_~EQæ†7T”¡3½Ÿ\ŽoîQõvy€CÖáÛ·Ë»»ñ ì‘v‡:/5‡ï€ÌÇäö¯¿Ër(f©ŒþºÝLÇ·7 Q;H‡Àƒt¸±¬& 8|pÄ*Ä MLÚ×ô«tøÏ"ñ°Â›V”h7NˆÉp¹ ˆFÊÜ×ÇzÈcOÙ”âØ¡Ì–1hˆè ³þ4DAìxfœ0ðIðÇ÷Kd%s/FjÏÏ\¦k´Š*)AŠCçFÒᥳ&ÊØð˜U £…¡IKMeN–ƒæùm9Îß_VXì㫡pg.,Jcð糋3(*‚EØÒAeGbÇð‘§¥‹(µBظf7“«3€Äg"N2-0ÀÈhlØHïFß®üÎY`Ò†6ø´¡ ü½ÞœÔœ´_¢W ÉŸ¼ÒP,d$S½6Lé"$ÑÒQK(ÑGzeD=Wˆçs0ÿ=á»Ké>`¶g>ÀC(ƒŒZÅmµ„ ôžB@žœ;yÁަ|Â>-|mé„^À±ŽQ(Ã8]S©Ð>j AK”?q4Þ@—ØÀ±/ pƒ_âƒF¿J8»½Ýè_‹Áï'¿˜@!¢n,@äœ[ôûË«/¿²aoÈ‹›þu3ºƒŠÔàŒ¾‘Ãa°Í¥°ï‰ñÍýèóh‚%At7ìäA ¸Ž()pÊSV—CÏAE‚›ƒŠ9¸5Ya÷Sqyuõ}ryõ7$õºQÏ6É‚óÝ4æO×Ü¥ O£¤G–¢±m´Þ*;Ó®ìL»O;]mVf¼Ê™ùüe55ÓÕíÍ'£Ä™r苲ƒžykMÕªñ iÙP î§jSÓuóÔq±$Øq2 ”Œ¬Xº>¹äT·ÒGS\áÉ•ïB6²†É“szÞïƒg©Î"½.ïP™²¢Øù‘J•뵋ç.gmˆ-Né}Àl“%ðÚ$ RÑв‚3Ô@·xÐ6”v4HíMòmúYŒ¿ÝMôòÈÛ(§¼ÍaÊŸ ˆ—±Í*ÈŠlÓ æ6ÈgnS@¿6‘²4ý 7ý·ÿ ;^“Ñ›"ˆ^Á{2”` dÀ˜+‚ÖRÃLá#±•C,Rùɜ٠^ÌÖâf|mE/8 ,nêg¾‹ñ}ÚTnœÞ}l‘xCLqCk|m¹…b^È´h¢8ÂÞj‚ò܆x«ß"yò"êí(‡°Až AÃwheÁ’+;kA¡×‚²±~-”íþMÆŸþW÷ax¦w„m\À¹ãy*1íŽvÈ Å-¶YB´(pᲆç#V¦è©ü™#ðlód Ôh³M³õ>:žÝ!‚Å´»,ÖâÚZlĹC¥I™osgp²2¶i… âÜÇ sv©LáV¼©Øâ¢NgØMÃÄqýP"uÃM%½iO¥JâHá6XàEcCw½…% 3;¤ÏO‡½§âÎe¹YƒOfšÁ–­R6æ¹z´ ·®#úl Nï/ï¿OË6" cئ@ÙÄ6j­·9@K¾M]ùuSFäÕIý?ÙÐ`Ô·ÁGÞ¤4$p‚øä×!BO9þveèŠeòže‡vٲúqÙæœþ;$àxs‡ tî° ³³:DÐw‡ —¦Õ¡¡31žDñÛæÞ 4<('­!yh ¾÷ §íÙ2fд‹c¿¯ë0Y0fʆ1SŒø’ssµ ëtØeAZ>¢üB—d™ÿ:?ù .¿~¾¿Î!ÿHð×½¸þXÇ¿1uï+Œ6•ØäFèã T~?R+£Ê> °ñþÝ› LÙvé¿Åm"£éô+úûýøkYl#á·[øBe·@Ó˜€ZšÆ)˜ÃÜõ¡)’\/ã8¦Í K‚ý\ L=抠¾€}…GMnnïÇW#бiƒ¹9náCÖý§÷´õð—g4ÈÚ—åGþŸ?Æ“¯w··üÁÞY|ô3Páì ¦TùR°|º-ûóTŒþºW“¯&ˆ©·^þ¶c{x"4Q]Äüƒ4 ^8ïðïË[$ÆI>à è‡ /I„âïÞâA¥-´)ÀCeF)$Þ´8éª-xí€áÑä¡ððõÙÐ"LbÝ6¢•q‹c嚇ÿ⨢¸¹üF'ˆ8„Õ½­ˆ´… Õ–,¸ÊœÈsRoóp¶ÃšKh'ÈaŽbC`®í°Ü¢ß×ä†$w—¨¢1¶ rê®6ꋵaæ ·ÕVeá‘Ves›dÀ¯Ã pº'Uê¯W³ ]&ÖO+0X:j eÉø¯C[ðP'«ºâƒMD™ø;Å[™Ånˆñ®*xÄÖعv‹V|k‡ ëhÓ .WÊ]kˆë0„Næb‚øºƒ#5<*»À0XHáîpùJå2Åô#ìŽBå¹vx,,?sS¤m‰ÏA•îÙø 0:ìÒ®dˆ‘.JùÀƒ?úë~t3ßÞ ¯ìø}d0GeCs´78w{ÃagBÝ­.ÎHvy‘× “%s]6Ê¢(KJ ÀJŽÓah_oo¿|¿#K‰{~Ð"™ûÑB¦@7yCU¹–ÈÓý†Lå@«h µ{Ús?épM[$å ÏÇäyÖ$úŒmôbWË<óâäw›üñÑÍýd îÍg›˜¤Ó¡QVxÌ xò+K„Ü[46-KsTü¡¦™ªH¾n(pûHCÛIªÊ}ádè¾®C ì0ÁÂ;L°xf]Z\9i¬ ˜ár—Ò} gxEka#ª*^‹Õpd´Öà£Üo&;çX[¼ ¾2t|PzFÅÖ£šn(ÛDP;Ù]£š§£È@KÙáó$ù j±î ÔsÆRxX¸vÀ Õƒ²¸*”m5ŸËà)ð(\3A^ØÃ‹÷ð‚²Ø´Æ ß^LFÞ~][x‹ÝbÂ=B­IÐϦk¤;W2@ßìn‘€®. ÏµÃ…}K°MõóºT°w¼5Ò9*€RIP6»YÅ®C%@¯aÛ|eºÿMÎ=Ÿ Ûtüh€7õ„›öéýíd$®îÿÂÞzlh€³Ðp˜+ 7OSÑË(!;ÀW>a±B ¼ÌÛe2c‰r·éâÀw×"³£+á.äXo1YÓkß´Yh°Â/]>ÓPÜ‘ö“ ”³Eê·Ÿ ×*x/_¢´ŸU M‰{ìµá°°#'yšÄŠjÉ/µƒÿ"“¢wKPÈg‹ÈÊÞe^F[0KÊ–½m•z±CeÁö)[6Ù„t¦Kú¢ÊNØ Ê|T u‹—LÒ%*†Â¡ÉÌIÓÜÈÅô¦«ÈLÃ@°Í3Øs•éIÇØ)ú4Zž.ôl@ AÉÞ¹ëÄ8d*zÉÄÍ}‚~؉3EÄáŽN»ü[âdKèˆYñ ¬ìž–vN+»™…ì~ò}Šë¨[ÁCc%.ïzƒ¼jnH¹Ðàå̆¸Ô7$À5X’À’“xìÉïÏKd…è?¡µ¶—ÿ9šŒ?ý-î.'—ßÊrïÈ(Ö.[æÌP%ž:dd|Säbì°U­M³Àú+;\¶†ì0!a"; ˜|rK4@7`—ËØ$_ÚÐ=ð`‡ËÖš‚ŸvØpá´]*œÿÓá2»Ö‘Ç'à†Tš´Qd-*ÃcfMƒKŒ3%HǪg¶):çÏ}—á:ñ•˜œÔ‘­ÄwA%ºÉ]€ÊàUÑ |I4·°re¸IæÀíLÄ‚CGg3#îÁí™gnÀ×ܼVõfGÿYÁ¹¦ƒ^EàF«Ìp3_ÄÌÏê} ú…£Á]RÚEëZƒöhᤴ½íPÁªQïc2ZYbà ßKeçËj§:iм;)yÐç16žÅØxc팅ç/ðg/ ÍÀК7øåU½vSP´iaå­ËÂÊ›×EHN¼p¼ü_wî٥•nm-ø;Ÿ‚-F‹»8Ô«Þ÷€Á«¼2©RÆßrÓèÞmxÐÐÏ€]1Ñ1HO4°ÂDõ$ÊD—  \É Jc‰=ÐDt¸ˆéUd†¦õšÍ0Y`‡ìgîþ܇y0­‡yÀI›Å|–ÑK\؋Ժ\»9ˇ\l@-°/…Ž­ÞSañéêBÔä aà/t¬´¯6½žãìrž¡ŽxÃG9SàG Ývê>Ø©ÿ¯ý„«û„­ùDèN–§Rx9ê°»án=mÂÛ;,¸ƒû îä®ò$‰Sz÷ÖT•ÃaƒQ5:Ìù¨ £Q 3I2nÝÈÊkõÓØ«ÆAUõAeÚ˜,`l‡ÂogoŒi9¸Dw›y߳̓ºóÙæAçv2xmiMa•ä@ƒ‡ ZÛ¸…Ö0uÛ4¸“÷êšç©áÁ¹UšyE½GªT—¥Q]èEu‹ ¤»ÄÅP\ýq9¹¼ºMÆÓûñ•¸ÿT/ŽCl˜;¦Cl‹ˆ’ìûäOTçFCði<úz=FÕº4w£›ûË›ÛocØ“ÄK_ƒ˜÷ÿýz{ª?)®no>™mä—¦#$èWâ—yn†8}î0ˆ•ä€P~‹9”„œ ‚‡M…'•0€üÐs?âO¢Âª±R8ùpaÆ#u"/õ˜^n”Lqà¡F½Á73;s…û rþb*»<2²òEóÙÅ™=.[L8êñ»Ã;<„=´C_ÂVT`nƒÄW¢Îäud—‰2 ”»„º ÄÙ3C6 Blm¯L¼.Kboš~æ”jÁË«übüZ²ã€&½‰aâ(UÄ) s×¶šÌ èd/ ì|Ý!£œ¼òKìÑù‘Hh5ØŸe6•?s=Bü±1C`k -J ¼«ðt„¼Xeð›ì(œ‚ž€r× §Reˆ7 rV(ôGá*GÔØþàºvÙü.ö]©í Ý µlM½__ê3bȃ4ÊÖ·d2Lª¢S¾RC¼™i·ûîÏ/bæÇì²ÐÀ>ß…Ç}A> |ö5:FþH|þ4 E˜bøÈy¤ñ2• Lx³b€SáC¬øÄ÷üÀƒ«H±ÝÂFë?v Œ5†Ïœf ”ëdhvÕÏh|tˆñ!tœf:Tgˆ§3ù ìå\9àüÏŠÁFº¤BÆ&7 ¨ár뛲ã{Ôm™‹¾îk@w¢å±'ç€"nè¸Â(:| 4<º¹‰Ë›¿‘,ÀI×àXéï/èiÀÚ¿û¿ï€èßáFéûÍøÏÑdŠ·àßﯰ3ñýþÓ{ôGü9žŽ-XŽÙ:’ià©Û-”è1¿ÿãv2¾ÿ[oןn«s˜éËèo@Ñ8Ñg10{(>jçÿŠJðh½ÔÖ3XW£ÉýøÓøJ;µw·_ÇWãˆçÛTT±:ŠÁ8ªãþ„’ËUõkDÐÂ`O¾Šëñô^ÜݦüúÓ5 cB®ÇíÌÞNþZZ=@w_/ÿ¾ý…q 6†Ç¼õ3ÓK°yê0ÀÖC—Љ£&åñVâîûG½á‘óPSà&ALÇ ƒ1½š¼ÑRöÑÕÝ—»Ë‰6÷ÚÛÇQàiVp¬½kÀ–Y‡´ÐFWHùS;|({D 8k× glëF×c½¤ïÿ†mÿtÅBž½<~MÄt4_b¢£Ä¢Íêö#Í×`HþºÝ\®é°(¾O/?cfZÝa›³Mhõކ&Ú‹BG‚¹þ„þËÕtÀ_b­7åÏ;WỼ0KWqL/?ôw )Pa× s%ôw8dq=þŒÚ‰K‚ꈃe |“{T£fùSï1 Ü»’¢ M_Þ\#ÃÓ%×dt5¾°¹$¡m”tÞ"˜Øø ó´Pïê½…;Æmä瘛Fs³Õ¬-ìÐmqA‡û!0Ñë›4q§­ï-ÈnQ¶âß8µ2ðÿýýò+Žbrû×ßÕ5-i’¹‰œ¢^Ä•lågapWþàû~ìe?8/ÅÆŽß, éwx2äÄJ2äÄF2ä Ù&€UC‚)ºí€aßM§Â„S0A‰ 6)u‚OJÀ“R§¡&Ø ƒ‚Ò÷Sz^ó}r Úé5þ·ég1þfdZ €iÐ H‹4 êš©„FŽÁ#Ǧ¯°±#£ñqCSÞ­âΚâ~zo9 h&¾OG“2ãË’ `qùõó-æ òã”ø÷÷“ñÇï÷¸¡—ßÿ›³=žáîr œä+½º€èLp¾ÇÙ·†eÜe3øØ S—h)`ò ºÝÜO0þ´á€e–踃žÁGù·58x#}膹Œ«!êy£ÿtCkÀ¡óŠ˜S9wò ÉÁ²½¿¼~‰­­ñ¡µ¡=ål>àPëÃÁÉ›†HSÌr?ÈüH˜wà ñO³&T’Ï„e2œ@*ÅûÛùÅëY¤+>JÊÎ"eg5OºU¿a¼v‰ÊŸˆÂœ¿–ì. 5ŽËbG6>Iýä/ïÙfY¤qž7NJÅx]2÷ÐÅ ÿ•Å.µïTÏÞ¥1 óй¤âÒÃea)µX€ÚmXðêÖ¢OòÃ$Ñ]½Ë€¨^Ýeðf0õªàjÜá*rÅCQÿ+IãÒÍü•ž£8N=?r2©èÇÐìåB*Û¡øÊMýPs í¥µ°;u £Cdñ›–¬Ó†Í“ Dwé}tÈ ¸CdËÆûÑJ¦èOò•p¨!ia†VxMGVÆ.tô&9×_…fŠÝl˜Ä>Ü Ž¡f³ÁcÓÜV„xs[Yü&2€¥¶wj+ÔŒaI¤úûÆê nÉvNeѰ¨^=³É5½ÖÐs ­iüâæò“X:zõÑg噤sd2СÃ`ã¿Á[–~>Z90lÒ"h¼\F céôîiOÚ‡ÏýPºxQààxæÚIyæt¶$H:S£ !” Ocv¾ QÀ†-sfA£X/vÐߑʅ¯2@¯ª‹’DxÉmŽè1Ú0@c>þбѽÖЀ›6¨&u ¨·eƒê2ägâîÏ/ÜQƒ},n( o¬ý¡ oÜpà´Ô³³¢=h?êÜz›†?j_2 •ªæ€õ£ÞP€úQ7Ð-³Óz›=)¸~Ô ¤½‚õ£nÐa{vìGݰàúQïR ¿ÚºÅœtT?ê†×zCµ~Ô :º[ô†Ô-ºEëÝp`»E74Ú3§·tB ¤[t ôg­t‹î2aºE¾•3±ØhålxÀ­œkp+çšsrýɉØŸœàay9Àþä]xŒwîO¾¡toÀaýÉ» þä Dò : ?ygß ýÉ; ËîO¾K´°tò†–ÇŠìOÞà£ü[lòt½hhò†õ ÖŸ¼‡Î+dNczy ŒÁ) Õív8ªX˜B…SVʪeàâp+ ¥W臕+ôÃJO:¹Ôûœ`AóÙÅ–Bº30<ÆPœd~ª¸2mT ¬x@˜ðš¤" I”Qó±’©?ç‡äJ¦KV{üOrKø¹¡ð—z† è‹CÈÆN5°pRþ ôÒ¹+ ®1 ÑTW#G²€Àj…*s2~óÒA‡¸¶5C®œú+Z°oÉCágPlHƒ§2K} 茬±a#n•¥Ô™­÷!¥·ìýп]¼<ôÎÄŒšª ÏÉ´kz€&q¡w^‘8*„Åž‰8<ωœP 7ä?ôÆCzèg?šÎœžœößÎ^O‘Ȱj9§òùÜdÿ†„ìf—-¡Ûaë] ×ÑCSºc¤ú`ȵ´ï '¡“$ˆfA‘1AÈ¡2@2.„6Fpä ‚ÐÉ\þ=3ù™Ë¼\t0lÈÈ”Ø ·¿FÏdêd1ÿö[áCt²†~„ K"%—ï;æ÷jèÔ`c¢üJ^&òŠËÑ.ÚæBFj®Ÿ ’âêrz'ÑoøœèÛõPŒ½k7gh‚s,Á„žÓ Çp5„Oôäê Ï1¾}»\œ`'d:]ÿeúÇ%ö+þçñäëÝííW,• }êè–Rú¤ûd£Î³7ôéLÝ3AÁ ýüâûúí‘ÞÂã1tµÑtL=hûílð†°1@;¦ª¡½ûn wßjé ðó­Y†çVxΩ, œÇ_'9àQÿö­ò äÔYƒ,’ 0Ô=ç?»hXÈټ’?IЈ#¿Æ÷ Y §™„Œ4âœ_Š(\vÎ_ËDÃ"Ž÷%,Lç’pU¥qááÖÄ;ç9Àõ"ü¥?ÇcVvÁD^9AѹdÊóª²Ô"‹Å`õ3½üÊ-Eñ½Wµ ÌL$hfâ6fâ6bw_R>Ö¡«ÑÁÉ.G+h“ïåGK™ÚmŽ$•ˆ+Ø6E i%Q3¸NGˆÀsM°Ð›‰3÷¡øØ!ªôˆ?I¦!PÕ4¸¿#V“¨|†pjx½ù…ŸçP‚“%•*ÎSsCNlOñxòo7QÁ¡; ߆¬pBkèÒ®z"Nk®áÚo‚>"€C€6D47´á˜¹³ýß¼Ý$`Øi –q€2ïG+š ÃÁˆ z*u0/”5öž 2‡@øò19|®ìRª (¿ïŠA¿ù`[uè¥?óµk­QÒ“ d2çAøe’¯6—YêøÑ¡mòí4JøÎ¹üC½ç{ú6§+RîÁò›Å]•Çuõ:@MtE‘gñ|ޤÐKæ‚(6‰ÑXŠèPL%Ó•ïÊ >z}3Kâ8Œ¿¹±"ÑŽoŒšë:ƒn:*¢*AÅ¢€Û„‚žcÕctÈ‹~#vâH} ]2TÙ t¬ìèlÎ 2‘¨XúiÄqPf2°ã?Rõ ÏOELJ.×{òF†¹H0…q—nÐç¯Cÿÿž–ê?4ÙÂu…úíì÷³ßßý6< O.N†Ú0ÿß×~Õ†C| ºõùè¸Ú ÓþúùêJœþ~úÆÙߥ¸6Ù£GWšwù5Ñ[Õl—è“þ×(rƒX[÷ŧO ðã;0üØx%DqöûCòÕ‰¹v§‰tý¹ï^›'{À¯šÈ…^†ÓÌ¡ãç^>fp›8¾²aÊ&Rå!ò; >Ý)Ld¶Lã·ü§Øe9-KáÌÔÊó‡(h…ƒÎ6ÐÚƒà÷¼l~Z(fÁ=O÷)dL4´ÂAghæáVË É­–)z¦ 'i·št…B§2iùL14nðOË¢pªŠFÎ@Èa’aL•›ÁF#C†'SíΨL¦bž:z‡£ºÒ°D$fÚR:å¹Íîq­€Ø™ Úõ*l”ب͚°1»‡F~DM¤ ó,Pevœç¥R)ÌèT<Íârã0¬ ì\‘3 ¤ÒÍ3So‹zµ72ädú™ÍAÛ®>¹ÉÈóæ`…&xÄÌç tÑÈ  ~î?ê9õAÐ Í=4®à<”׌ 6¥]Aeª£F‡j¤Á*¥ÁÇêå#tnqs ƒb'óülu‚WXøÌ÷æ°¡É|…Ì#Nö<k^Oh‚æ0_£lš>D / «ëD¦*ŽœÀÏÖbuÒÜ-T××L<æl/204ÿÚ p£àbÅn Ð@‡±Œ0`ñ1 ‹ilX|¬ÂF‰Š6LIP×d º&#hØ5™‡… #¹€Y(ÂÆ^42êêš AW× »ºŽpûc Í?‰“jÿ tEV‚ƒnÉ’8qcíc¢d¯àaÒúü0ÄWHp˜š×à(ÁQ£‚¿±µt_kõ¶vYFwMVɬ}ìÓT>ƒ¹™å 4È$h˜3˜¥”÷=÷PV°ÂW`üG~ŽËçÉ=eNÇg(tЙ*Çéó(N½}[òÁŸó„DÅN¢Tðþ=9i6Õ·<ùñ¿7g„{5M¾LÅÛGªè3Ã1ã­8á†ìã7ä¿!óø YÇïú„Žwv¯¹>ö~lð Öoo¨W]¡M[hoû³ö†ÇümîG,ʦa2ú0ñõöæóÅÙPqáý÷ö3ùà¾sËç¸ôª… -Idä‰À™±!¦©³3í¶G"Îù5°IìGt(Ÿ“òb§Ô“NF®dƒÍ2Ç]†2â„,K˲¨œˆþ,ÏØé È©îF‘XÁ„ JñB¦ÒåØIZˆJ/K6DŸËÕ§~Llˆ±WÛ Æ™Þ€2!ƒJö’YP‚äs1î`eCÍÐeË¢1£§RåÛ÷W]Fùàb%•V{>ÀÔ^N²u̹6jЯ¬“]£Ny'½`×ñ‚Y{:Ûk ùlµv¤ÙŽìd"ø¯“P¢‰ˆY<‘9cÆXš­¶ Y¯NCG\Ë F^H—/*\²_k—°™ÃfÂxÅ&\$ÙbQŠÍ©ÑXl>Æâ0FÔ.‘ÑTyH¾.Nd¤-Â:Û°aæïG2Ÿš4"ç±IÃqŸ›’õà¤YONñè¤Ñ˜=.Bdô45빂ðXB ˆ8 ´`O-TÎã@ –õ< q¹É«‰”Ü)5õ#Ö°æåKóe|$q»y »Ó˜ÄÔ0šÒžhÍÄÜaLRiAj pÎ{‚„®Ny'Žùg.g¾óÓ€œ—tã5“Fd¼¤#´,Kxåã¼§«àx,ïéØùŒEÎzKWÁq‹§ø¿šóò/e|xJWú+*8ÃiÀ»¨T[…óQ ga &½ˆUI)V1Ù‡uU寰B2f±?+n*"•‘Ná¤lÞ°žð8à‹ñëO–²E9S©—#›"ª!o¬E M>8æXòúbñü­†Ü‘%ÈXRCÖ¸’2:ŠjÈ£RC΀’²Æ“4k4A Ѥ *c0iÊKÚ ²†’Ô°àÌÎTÎJòžx9Óö ‹íކÀzoÀ@®¡fu "£Gxܧ‚6&÷™@Qû<Æ"„Ç.©ñÙáÍça0#Ï„a91™õ© ›èÛ‘]UÙüÜx ùÇ @sŒ—i³.­ÊðâÒÌ—ÿç",æ-vW*`®·FˆnàÓƒSæ‚„Ì«=39·ÆÛ<ØÿíŒUÉteú·òh§’³2ž>kx|Wweíf}7§!Æ·’ ã+I¨¤“ºl=2gAÍÓÙà$ßj¦·Ç[y™<âL-mtù¶˜ÖA—ô+k6lç ËËZÝÑœšùd+x-XÁnn ~{ó'Ý÷V¯F|F-ðð·áïƒáï*6T/¯þâëø£øs4™Žooþó??ëß]‰áïÃßÏ_½ßþ‡ úw‹ÁÉ.Ü+F·A›óÂ\pTá8“¼hlßZÂñ}kâŽRþ|ÍÈ÷Í $Ûw“Ýžù3ÛWxLŸë¸±âCbúH‚Z2BqŠÅ8î\PÊø¸ÆJCqM!AqŠÅ8î\P™ ¡¸F‹°?‘‰ñ¹´” 8Åbw&(×™1í„Ä4VÅö}l›¡Ë¸ºŒÛ¡Ë¹ºœ¢Ë¸#ºNºàCb­tÁö}l[¾Ë¸ç»Œ›¾Ë¹ë»œÛ¾Ë¸ï»|»¢Ë¸-ºŒû¢Ë¹1ºœ;£Ë¹5ÎR¦#!q–†âú>¾‘qcdÜ9·EÎ]‘qS”>#×Xi(6©>$¶ï{L¸¾Ï.¯† ¸¾°¸>‘1’ÌGf"ãr}_ýàCâú> Åö}Éš‚°¼hlßY±}+×¶Ï·ëómúŒ{>ã–Ï·ã'qÁ‡Ä5RŠíûÒ˜ËÒÛj,®OL¥Ã Åõ‰„Å%_,ƒ1”ÁÉà dpÆ1Ãê'Ûñ— ØFë'ߘ/Pça ÓpFi8ƒ4|1/•!ÓXÓ÷É”I& äò!1 Å7P|BqÉô˜p| ×ß'2ÝqßrÝp³ÅŸøÂO|Ñ'¡ø>00}âœíz{Îw½=ç»Þž{>ÓþGH\ß§¡¸¾ORcçT>Òƒ.HÏWÎ,¼ 2âÇ\ÈLF+N4vñ à<àŠbÐ4Î# oïg§Ž¯˜'Z±N´BÌ‹bž—L*fu̪Â7ŽŒiá¬Iá¬)áó ŽSF(®o$,®O 6 ®Ï ¹"€é‘‰ïóÙ¾+’HHlßÇf›‡1—IÕHlß{\ß—²¡ צ|Ǩ…rYÅô‰‹é—ë$fÚ§ Ó',¦Oôƒx1c„búDƒÅô‰?˜‚Q?¸"Q?¸ÂP?˜Â?¸b?¸?˜v¿\{ß®ŽeL;ƒbú>ƒÅõ‰Œ[C‰%˜|õ€s§©Àxec‚€M¶€*ÎpbqÍã´€ñ¨_ñ}'¡q}(_n"gj"gf"aq™Y‚büD63/˜.¡‰ï¹.¡ØrKù\\F—ÑÁåKåËœåÜ08÷ Îí‚s·`Ý,8÷ŠÐÉ–2eò#øb5„ÄÅ4XWfUÄ–X±%EÒIgk¶eÝÀq}hÇö¹™3Ï$“ê7plŸ[á1~nSñ'n<Æ.™¾8‰ ./Ø@1}§ÁâûD6 ¾Ïcú¸T†ŽO¥d™á˜>´ÁãûÜŸỷÅ÷¡Œë+ÙöF¯‘Ñidô9]FNQ¹NÀtÞ2PLŸh°8?1`òõ*0ÖÏäòù çw²~&ÛWú‹háìÉ(|UIBóç¾ëp-ô ×èmÙ†KKüˆí¥f‰Å6fß{F¾ç]|¯»w1¾íâ{ÚÅ÷²‹ñaã».¶g]|¯ºøu1¾éb|ÒÅ÷¢+c¼3Í8o93ÎkÉ,Í#¦÷XŠë ‹é×L!…5WêÔfEWø›ë6n—§D”Ä,~‘ú™äöÑIfnD%TÆîòQ'hfDá¸ü'øÈ¡p¸÷ £K¬Û‡½$æyRñþ®™@ðäLuwŸ"ØöoÞNSöçæDdP“ìDHŒšÛ@Ì՚馬ÐAÁó Ž?BVsc⋼{-{È2äžö½з‚òÇ?¹£Ÿ‰“ó6@05áöÓê]ÈÉŒ5Bc¢5ü…Ìœ¹)ö´QKmO?ÒðyõÛ,ž&r—ìÞó6Í"wROùÿ@Iüh)µ—©Ü¥inÉc'Ý—“É; Õf导Á­`¬»Ð^ÇóX½Ù½$PæÕuÀ•³¥¬˜-eÇl)fKY2[ÊŠÙRvÌ–B›-…6[ʆÙR`³5sÒÔ—PŸ«¦@ÇŸ;Þµ…vMÛ4z³JÔÒIÛÆ„Ï·™À“RëðÎ×ð1mß10"Ç‘þ4v<×Q¸üÃú„¥eþ€$~WE™e7à Áé ”ÀD¯àAÂS®’×5©Ìòo@Ÿ•(8z§i8ô6ãv/šù6™6 Òú×4¨¬!P6 ¼U²'ÕÕÈåY,æLoƒ¶1 ƒ.‹D@Ú±Æô[èZßËLoÌ“’ܬV²4A䄲3@®í¥ ×ð?bÞ¼}lZpÝ“¡sun߃+bªŸ&Ê?Qm‹ÀÇS&ëêe«(ãª]@…Mí·):‹‹ËtÂR¿»äó¤~ìJ?ð£ê3P.&¹¼‹®¬Œ9b`?#η’¿K¢ŃIr„x¼jm˜â,vÛµ©04¸CA‡'g¹‚Y÷. ÎÀ×<Ü%ð/>ö¾÷°²j¬ä ~Õ`Ò «FYZ5€çE¨ÇEø§8à‡8ðg8ÛÏcȲÃÂÿ€Åƃ"ωà‰àO‰ºhÿ±Å‚u »DÀ­£E„µ(ü‡.pД x*ßìࢣµð|*º˜0wà°Tª†å(xHX!#¶ðĬ†@{è EF„•¿Ù„4ôÏ\æ-­ ¸ ?BîlµpÔÎoÀ/ƒóŒ¨C6.kÈø¿t²µŸp™{=î@ôµ/Þ ð9aˆjZϳJÞ—7©tyÚ¯·ðæi̺[f¨X+)ò׸#P€]'X}rX9AÎ..÷6A˜Ü/â3‰»œ{2ј€õù«7.?bݸ•_RÞÊ„Ǿø#/ãéGR#"Š7hPÀ[bÊ>åk•IV‹Ÿ¹žÞ9YG“½÷(^›VtÈyÞ3Šò¦Ù[ëñþ‡áO³ƒˆV‡Ðw¯‡ÿpü¸Êäçr[Œ€2Mã”UDƒÈˆgê:°JÈX)Âàñ93Ž\mÖïåóÝ+¸,OÙª´ U®ôZæÆ “‘õ(¹AdÂkjÉrçžnSÉÓ·¦Ù®IË‚É\ä?öVÏ}#f §>ð•öÛÚôúhjYDfyÄÓ»ÿÖ¹ü-Ñh‚«’Îù£8óçk>¼îyù­h©t¥¿b¿îîíh̳Q&p´Aåýòíãû›ðÔ’3Îbà8à ÿAã—îdÕ¿%œÜ…dr;9ŸAÈ ’QHmÄâ•öèóˆUÐ,¯°Ý=•GRƒÉ(æÎÖÏ ¦:$æKŸqÚV*Ð'íß¿Ÿü>¯=pÖGê$#ulÁž¼%ø`0#YˆY>ŸÓ¸¨`Ó†#:Næ9YkuQÊ#A=;ƒZæ™#ôõý×éj =4ŸÒ„2[Æœ’Wð2r…çdÎä߃áÛÀQB+™jKÊ?šLD;ž˜N¿ •¥~´PŒð·ÿKÌ”tRwYª¥ŸÐ£/V…¼}3±ó ÓÑt:¾½AÀÏôYGaŽôp|Ü7êÕøîÑ„.)ÝÔOÊ Þ­õ—dœŠº…Ϊ [ؔЅC×VBþöÛpd—‰}¾k*ÄŒÜÿUŽW¹—]]‚ð«-€î:A0sÜáf)§ÿÓà/¥OREÍßäÁ}PójèÙµ’R‰PH³¬dš‰ª’<† Öx¸Ã’˜qg zr½ßOdB§c€yòDáGó¸YÇ ŽŸ¹¯ÿ 8 ´IèÐç(eÒ[¦?_£ªbñd’-±aì!·9&Tu?P„ñÓ«€šÊ0^Ià~IÈfŒ}Bؤ†ì–¡-‰‚”‚”²0P 5¦EˆêÝëf4xËm¨Ê ÈQ6|&eÃgÚ&‘ÑÂtÀÅÅñƒ/µ ‰¨\+l6Dµª¡h<9wò Ó‹R©Â³È#r%SŸÛ&¬0q²%È¢ör»ªT Vo3¡ývâÕMAm…©™Aï`¥ 4;*%O«Zæ+ \E‰zhLv‰© þ£™ò41©1tø9‘H6+“®Ö2Ó–C¤T¤µbÀy z hÅhÓ/Tš%(–0Þ­·Ä"];<©rà4isË=  p®Þ•Ñâ/`q—@\Nox–²= „e2½„W‡9d]"à¨ÑÉ… ˜Ì24rÄÚ4îÒñ#K£†¤!gÈ÷´×EUI–~Äm'«kqÄýK ½Ù‰H$5ÀEá7W§ü'”6 洵ŀº"iÓ@G©Ì„Âó»‰5(¾FNRÜê5ØbÎíÕÖð&v ;a´XÀ+Laµwˆ©Û}ó‚“5ÛóÓ*(žÏ~H7S‚Â"ÿ9‚Èh ¶Ä e|UÙƒh|AÖ!$T% ù-|ÄG¸Ž»”Ú)â^È< tH‡ÛÑâÏÙ.QQùÚê¼X,ÈSKç{ñrî­[#‚.×äcëµ­U—–u¨Õ8õî±GÌ1äÁ¤dgܾµÁnÿ#¹ˆ3_ ·Z/ÈÃdto]<ȸ Ãz_½Aç¾ÂƒgS©³þ$Á&wÈ¢m8ê[[Œo÷e~\È¡©…,þ:?ù ¦÷·“‘ LùÀ€"c?ØbAå‚Õaæ¡Wâ„O¹*5fiJCáp†ßP'¡rÔùýôEuÑ]ÇvÁðˆÐ1<Ú¤eΨ®?¬éÛ¾4õƒøÁ!¦¦L(‘ž¹¾&?pëPòPêàP\”%Ê ('¤¬™ô˨­3Ñõ± ò8ÿZüRûJ¡…®½oí¾bðA+ªÀ÷‚Ýþ.E‘wI!XÌJƒ¥Nº®ÊîñBÓK–Íi°usÂ<ª'þ›9íÞ„$ÙñqÁTØK‹pryG+ªÞ>ìðü[%ö¡ü‘OùRÅÜLÁÝ“³œi¢"v å²óýüþÃÎ ;#p#à"2²£ ‘ YXyÒ&QÒMï›Û™ï>û‰ü ècpÚ‹ÃpÐ.‹}šƒ–cãIŽ…ç8¨§8°g8à'8-xHlMABU(ã‚Xû¸6ú| }š…–…’…~Žeå)–•gXØ'Xž_Yx eã%暣B%S´ù·÷o€.ö1¨º¬pb®†§°òÆ< UØÀc‹¬žœ‚ª`—Ø ‘QÃ]VØÆÕ¯ñaÀØÁ-ÎŒì°`(¨J=¶H½ÉiäÄcÎ)ð†>¨ªº / Ô€Ý)QÙ_R–°UWŽP*å,ø¥._U™é"Ê9oF+æwc-Tê §^5Fc“–28oH+pö§o.ïó´÷‚¡Â÷UBIPåëN~ø´æ½8Ÿ6,’z®2c2¿+AÍKW º,ÄÍS)4ʶ¶°‘#ó3—¹¤÷qʛ(í,µvèA-piêùL³™tø‘}%Êeò1ñSÖô¶’€2f$g4ª„ ýH„YÎŽË›YbjHò óF©dHÒØ¥ªA8=)û(­3Ö¬ûôÜñ€ö¥²¼ÿIÎæŒ÷¹CÍ¥N¤B?«CéÕfJ†ÚF¨·i' žJmòY/SÛDÚpêýªJßS‰äwAJžMqkþû‰]ž¹Öµü8(û}t‹ð±…nÎ9XåÒ¶¼› ƒ¡©ÓØÐºUñx1keö]Ì ´Í^p?›PgNZ:©¡³8AÿârðìÝ›ÐËþ‡N’”oø1NHÕd‘Û¢z[š7 ³ÜäFaZ;¯NQ`.'K‚(ÕHJlæ·ñhtæ§òPö3N Í}ãÙB…HŒ1Q°’»%øÁ5òÛÅàâMÈÌY%(ÄZcFVŸ°SG\ìÎ…He0¸¼î Éfp™# ³y‡NP@åáŠätà}æC€ä ª”0¿…ʆdáêÖ”°h/ 2À©Ìò4b¯‘k°ëîÉü×L%<ÿµ†ÁýÕõÀ›\ÈþTú€9ÄO«>.oa>ƒ t‹4øÌ-û'°üÛóRÊ‚*%¸âQyB=X¯Ì[T¦_}âxüÆö´Ó”1Ý<æGØÝ)™ïp"O¯ˆe(.9SÌÛ<°€HÍH¿¨ÐãXIˆkxúÔu0|wqò&l}HòÄ8ÍÜц€DЇ é ¿Ž Žî§˜-{t?ÝÁAçÓzK2½¥¼jŸb>¦œâ^R”è16?°!©z~ óp}OùC3§d¡œ ÚÏΙ=øsZ]°—«“¹œ¤Áo‚K¡£2Z4¦œ?K•ÐN¾\Î®Ý <{‚k—㼡øYè\çÖr@ß-vðAI§ Ê_'l´ìü hj…ËÂn± D7èÚ<”Öˆ¹×GCM!ßfaN ߆‡¬cºÙiVb§g¿¦5œB_”þk‚SÌ5>‘‹KŨÙ¢ t*r”"WŠ<ñV*•t”¬F‡»ÎB‡¢J-q šRlC—qBnóNrœo^‚Î ^.¶xà ü»Å¤› }µ¸a@yáÐ7‹ä“Å6 Ê[Æ?ˆÜ¡A¸³Èç;ØU—åIµË n†¼Ž)á®@I€t0§"<97)o+¶½¡Òœ¡&m@²…ÉÂ54ä#¯Þëíeãáñö‡ØÇVö,“Ô@ßSÚQ[£×fƒ^›8z3Çã¯ùh€iŠ,5æ" s’ðrÎ6 ,ÿ½O‰ëG˜a`^¡Âì™öÒIæ#Áa²€Ý'­¸àÆ¡¢IW©®ÛIwâf*W.EvåŠ}••àÔÏ)a“É! pjŠ$C}‚©7JÖ™¿§Ö¿ú ÞΗø¥£–p}"È$pc¡ŒMØ…·uá›j 9t˜Û$?rV©Á«; ж³öO¬ñ©–¢Z:u–€¢u) @OR¹ÂWaƒ&Ü ¦Hx‹†4þ"B`››BÜê*#nõDÌA¡GD”èkíl¹Ëqvi€'¤’ÌÞ s—8†–N™Új>šQÁ‡OóŽ+‹Ã Mûìºç?1Ö÷üGòúÙe4>p[]Ó&XV׈¯‰Õú‘4­kõ‘džGnÆïlhà«ØÇ±˜¼‚2mºzÝäN"&ºÂ‡$åP¥ža峚œ 0%¹i§ŒÎœklC Áµg“_óGÊ6+ˆw•eç 䓾’ö¤¯êå‚|Òiæî.RvÑp…›k÷CŸ‡¿Bjx:¬)ØáY_”ô&–®‰©‡- ÚEÙh÷ÆÑȤjH~©ëQ¶`àe^¯Þ¡C@ÛÿÖÙÀ³§ÕŲA)Ï* ýÚ$ ®×z¢êwTú„—î-¿ø øÿïi™þƒH2Ïý?ÿ‡x.~?ù}pj¸þï«>…ÅÿÞ N„p™¿ .„¶Ãyé£ ?šÇ×'£ÕþçÕ_]~‹Áï§o™˜çl±„ï„pÒÔYÛÓ=ŒàAÝÈU7pÈ8YÕmFü¨n3âG5™QŠºÍQÝfÄê6#xT?hÆØÈϲ6®{9Á#»—;¶Cýë:dmpbG÷)~x•oÙÒ ÅïRðð„X…ÖÇ÷+x€°‚GøÔ¬Ï e”éSºµ1>È 僼àqnÛþX„’:ÞÙí_°ƒÇü옑_D¹ˆâ4œ‹¯”nÅžäל-ãøat7=ÿùŸŸ¿Ž?jfqúûœVN2šhÚéÀ.óE™O^Ye}—J 1HË´ïMƹLÍ #†zP²{r–/´K7uæZ3ŠÆ©a0ßÊÒ y&·¾ÿ÷vd¸Ð28Yæ¸K½mG‹@Žîn¦¢þÙæ­0ýìhÖ›„žlKØËH}hêÙ#dM®rx+h{ç‹{Òá® § q‚ —axßUÒäÒthƒZ· êS–wZ”f/c§?+é'ÕS.-€Ì2ýµêTkã¶¾-þkJ¥)w¾’‡õCIª}$½Ô´ŠCߥçE£»?}Ÿ{T[d݉ã€Tì>c©áô½É½¦œñQhY„fqÍ}mc°ÔïEóš¸|‚Ÿï÷*óüX¨uä ý…zUÏÇî4 ¨‹ÐÎ’Ÿ©±;Ñ_‚'ÿÙ²ÐO@Öú+„9ÏçA\‹4ÔK/ݹÁÑ”ä$Зc‘è’ò!žÏGþË¡ÇJtùàù©þý©ùým"£Ð$ÀI¬FÓìl®ÿ;¦=8œ™´‘ŽTê÷±>Þ™¥á‡@ª3‰zööŠÔ¯°O¤~üƒ½’ ýƒá;A™¢3jK“É4ô#2:ô <)û½Ý†÷¢ ÒŒ¿ÎNF£Á‰‰Âª,×ÛßË.éÒRü™Þ,ûNàÿ³ãü ™/LDÊ ?,³õ?´MožjVô¡%öA?³=Øí»O«»Õ¨7ú­¿2רli úùžÍQïQÓ}kúp°ÑôzôäztÿM ½šøí 7ŠŽîÒ̳1„~}ùEf0ý5U¡–Hú02Í>4uw·úÁ¼‘ýRš‘&O\Ge$Ή¸û²šÜèÿÎEõ礘yŽ@¶;îþ—B žv€HŠÀŒ ¥ æ3ñàG^3fÓS1=åÈéÅUýzºa©dÔöM$ù,ð]¡Rwh9¼Ó¡@K´•ºÝ³ÚoKs¾ÉkD2ê…•d_â5]ûúªùó„Ý™}†{†ƒRPvn„¢ýÙÓ$ £æ/Àƒ´?ÇxÛU#´õS£Ò~,ÛÏ"ïX¯}"oÛ³±ggbz!Ê/±kÏöÊ“&íÀT€ÍÜLéãÖ“2ÿ+eÿ·£¦÷Ó¾4`ýJЇl‰`}Ê ÐAì’eìO²“CP©¯vâ0Üv ,˜áR؈‹%ˆâž–ã~z¢E¹+…íÉx×2 ½iÄ!ú—¢Ø#†åù:Û7chÆSmß½¢)ÏÄD&毴=vd¯(ýö%pãd=º³½ÒÎ<'slê¼ !Z^JÚ>x{0_%±íQN{°j7YÍy>“ ?²MêRÍ6© “l; Nšöc$Z¼½÷`&*fË]æ<%–ÕêboôΚöa,.T>#kaY‘)ÖÞƒSA´¾ý­ç]ÊÞ%[#6£jŠ™ôôÕ†Ú²bo¸{ór‹°ûíïëpÙh'Xgƒ:ðC?³mÈÞ»N⸾u×ç=ÝRöàÑR ¿ÊD„8ü‹…çÑv¹&l%£,]»«>ÆÂ«íKHHô} ÿ‡l_(ºEÚÇbF›ye3b;×|ÖhlðÀ¦f‹4hðë?eñ’ï ÿGí»,ÃLÑ~&KT0íޥŒÞÞ+,«T¶¸`Sµ‡ 2€ ë-…ºÄR–®ª”¥ )U];aTv¹¤ê»ˆRnÀq訕[¢c†u³£`÷7 wK£pw1 w㢚û ˆŠ´Ðð¨µSÁCFxÝ¡€— xu¡ y ¡— ªu¥ˆ´ªöÅBâïùÝéÛÁƒd¬â+Ð1{…Ì+hü]A£ì KW˜ˆy68™9žyoè{gÅÒÙ)uÎQrßð˜WP¦möð´î·\ÿYäùæÉÜö ­¹¯7ýtÂóÔ›åsÄi*äR~ÔÞ±äûž0Žä:¡(ûØ­JUErQ=;}ÜÎ$V¶9nž¦B­ÃY èÌpˆÔ‹Å"ó„^3Z#§ŽKÝlýLY#ÕKÓõC'(ß'[¤E L´=èð©þT'óWÔOcÙ.öÓêOõ{ Í–q®œÈSBaŽC{iϨüL¶‚xûX¹TÏ¡—Å{Q.Þ4ú¢\¿=(51÷¢×ï­îCƒ<‹AžÅ ÏbЇg1èóôãY úñ,ýxƒ~<‹A?žÅ ÏbГg1èɳôæY zó,½yƒÞ<‹UÏ¢è!fQô³(úˆY}Ä,Š>bE?1‹¢Ÿ˜EÑOÌ¢è'fQô³(ú‰Y=Å,ŠžbEo1‹¢·˜EÑ[Ì¢è-fQØŽY=Ä,ŠbE1‹¢˜EÑGÌ¢è'fQô³(ú‰YýÄ,Š~bE?1‹¢§˜EÑSÌ¢è-fQô³(z‹Y½Å, +1‹ØNÞȆæ"½`ͨZo懲 ú”P$amò!Icûy=êçVÒªÑEbúëÄ̯•pf³T®|ýñž-rSžÜ wŸnzMéu›-{ùxJÂNòŒž»h»/à ’E·Åú®šn[_ù¾^ȶ?4“j‡±Øk¬…Höón+kÄÛ+Ö ñ!ceƒü°±²Â~ØXÙ oŒUA¥nì«¢c¬l|eÇXÙ ì+ c/|÷pê/ÍPPS¿ìÍKûŒ¯DœH£?l¼RíùBÓSJB—®4S yè§›¤æÆîv…wÕ-ö6^·"@9µ{GyØyýïg*ñRàC°O,ÎÀ 45¿6þüÀZRÏ㇄jDˆû!ÕLnzß<«†»/›÷~ô’{¡ øA°möžÃo{¬¾J€¸ç•ð$¿¥Ix® øAèi%<Éo{쯄êñ©>à/ât=8‘?såzË£wò«>èçS2øFˆó­'²v9üB5çbsþI–N;¿šæªNëgèÉ2éæUÓ•§9ê¯eqWߦ'âÓj5ꇿôI¼å’lŽü{ ãÙ"Á”Ày.Ò/ÿ¹œ9îC¯ô<ç²ï)0M’{àb!³ v-I°og´¹ ÷ò[T½Þ‘ÍU¸_€žgÀê*Ü+€ÍU¸?@ceúÑ‘:d NA%áöÈp¸L†÷mŸ—ÐCñ"1G§}‚É´<Ñí76Ì^äerX‘TäerX‘øHtä™rX‘þtä™rGäTŸrÏ–ŽZŽ'Oö ¹Áhz!¶‚'!”¡©~ùµgxÊoUhI4Ãòlå9 ç–â  4¿üÊS,=Ta*ŽNÖðlSð¯ç.…+)ø„2åã .d:ºs1©“ûÙl0åIbñ»J6,Ó©ø& ß“‘ð#VÐqÃw¦ù"Gë}a‡ð½Ió}”û¯·»;èpnØ 4è ŽÄê«\ìgµø\ QQ*¾r­j”Ý}) = ·øsU`’'÷³Ù`ªÌ•¥ï*Ù°LƒZ?¢8³¢ ”[ëÆÑJ¦™þDQ„ŽzeHÊsý‰ZûËo»³A•AçlÇ[bƒªŽ.иÃW ˆ.¨uZ ‡¾G¯2|H€šä,rBL\½"?)ÁaÞ‘¯î®²±ëR~8S™yÊQšÀ#üã3²ÿ7>ãñÿÏXÿ;?ã¢õó v²Ñs>шòµŸpªÿ/ÏúrŒ =ûÊìý e–ÿB™çÿB™ü eþ…2CNN`™w¦h™ÿ…2¯Gf ±þ÷ï—È}D[øKÄ>¢]ü%bÑFþ±h/‰ØG´¿Dì#ÚÑ_"ömê/ûˆöõ—ˆ}D[ûKĆîîÅ!±÷=„=Þ8è?ãXâ oüŒc‰ƒ¾ñ3Ž%úÆÏ8–8è?ãXâ /üŒcŒƒ¾ìŽ$ zˆÉ =Ad†Ÿ@2CÏN ™¡'ÌÐSHfè‘ $3ô¼’zXÉ|D'¥ã‰ƒâä>¢-ühâ 8±h#?š8(Nì#ÚÎ&Šûˆ6õ£‰ƒâÄ>¢­ý(â I^…oãggYQj³éI!Êݶðwîôƒ˜øG$0•—ð#E¯§;϶Ô..€óv‰ÃÄÿ:‰×Ç/ñY³ðÊ žYzÓ zÄõî¸VÜùfl¨coïè×ðî-_èSêd·-áÝØ¡ŠIBØé‰I>Ø1‰I>ØyˆI>˜+Î$Ìçf’æ¥2ÉwDî¨içéx#7è:¡zs<¦-Ñ´?v[}HÈ#2ׇD<"‹}HÄ#2Ú‡D<"»}HÄ#2݇D<"ë}HD¨/‰¸?[a7žPtLy'¼PàçÄ ì)ámï'µÄ{ã G-ñÞxÂqI¼/ž@… ŽoÅ=/žP€æozo<ḄÞçí`•AB¨ƒÊ Ô;eêš2ÈõKäƒ:¥ òA=RùŽÈ­ã E7ž@ûâ1m‰ûã²Õ‡„<"s}HÄ#²Ø‡D<"£}HÄ#²Û‡D<"Ó}HÄ#²Þ‡DDð÷3Ç®£²³béì4iøÀDR»¹ãy*÷‘1Q…R)g!)23xß-éNãLõ¢O0ڼÓï<Ã’R7¼ÍkÒX}ß·ð‰g¦™9Qoïªwœ˜þ,mÚs7ˆ•!Ü’6M¨dgþ¨î^SH5ûm gqpí?Ñn ,Q?V¡h[…þ>Þ¾½8À‰¶…{QlÙ‹þf¶KR -‰vÜ’ØZ…U{RXµ'…]{RX¶'…e{RØ·'…}{RX³'…5{RÀíIæ‡ò5Å{O<ê§žÄôá~µ`ƒÒ$ßsëÜ 3DPñÍòÓÿÿß,ÿZê3é¿Q~¾òÁsÖÿFù©Ó±®MŠ ˆ0޲¥1hÿÂÑm—ÒVºþ}vŸüŽ£ú†j…þ‹•ü¼= -Uòï(+ê_3Uèå_½$†ƒÖ\¬|GP[”çÕ°¢/…Ñ^ù1ïÿÅžÃû±×ðþ¨<†Öo³ç ¿P°£s…_)ÿÑ(õ+åÿ·*öѹÂ/”ߪ+üRÙŽoßCõÍ£q…_ú Gè ¿ðžr…‹ÏL§+ü²x³+\ÑÇ—+ü Ùÿ¥^Ãñ¸Âlõ-ÊcÞô#âå ¿¨.î@Êù/)Ë[¤Ò®¡çžKÔ£ÑÃ`’®œÀISg=GgÊÿsçô2… ˆ]dª°fQ¾+ô¨í]YƒùèÊ$óãH¡¾ò)þS=½ðÊxÞ oæÃ´é)Þ3Jï‡Øú!^Äq/ªužzÚ¨õÂ\øžŒF“ø æ‹HÛ˸AÌñ/¸ß¥žqûqwu·êƒ”¸ÒbÝ·ÛÜ,öñÛØ,öòZØ,öòZØ,öñZÙ,ö[Ø,öÛØ,öÛÙ,ö2[Ù,ö1×›EÑ·­Íb·Íb/j³h6ÜëÃaÉõ«ó61Èñ×ÙÉèÙ=± OŸ¾cðoýŽVGÙÿ›r#®^-v·Jû¿jÄ_$:xÐ_šq¬6çMßqD6çeßñ›CÏý†ö¾ÏÂ'ÕJx™ù9ÖÁ?Kôú[ŽÌ.è<³”G5­»‡ã˃‚Õp~hŠ vöÇ£َ̃¾d~ÝÍ^GŠêY;ÞÔr ÖÝW_Cþk†õ ÌG5²Ï° Ç<ÈÏ06Ä×â–#CŠ ÉEâÆ9*°”­©‡t듈 ºNæ.Gw_¦âîn…èó×bÆ<¡^šò†Dp™¿ Þé_ŽR¢ùùѤhK 3!|U>V–©À¼nѺ9=»õãÁ§—€;ºP}öl˜$ô(ô$ô5j4®1@Ý(PºQu£@éFÒ£OÔdÒ‡ñKʤKß“©žä;ÚrüÓñ|†=ÉðMÒyú/š¿àžR=6í än6 {ùú©a’­EЍ³ñ$÷©ùúdmªÐ)=ù7„XD9yä8D”l|IJ í-¾·;F/•“¼Y#çEÏrÒ€÷,CéÚ[•ÞimW '…aÈþ>âIÎ[(g.µô¤Æ¦ CGÛ›„§2²l=ÏÄD&ææÅ“Ú‚Æë‘uóÙÁW •ìQ„TÎiåõ5 šÞs2§ú7±Rê ¤dfüÙË28¯$Pú'œYÈÖù¥ Óö4¥·Bg!÷Dn~;‚%¹hæ#ZdKáDÞf`ºVñ÷s+Có´@–'êéåÌJceÙC0˜ÊÈAUöÒêFeø@nJ*)­- íÛìÔþf© 'M´_j“õ|&~d÷KÏÝ€Þ@ÚåÔž¿Þüu~)/G+˜åóJ%[huõ_8IB‹ðdú™´½|®6qvW~‡¸Ÿ)ÖáG~æ;ÿLEà+ª‹ÙÝþKÒØ=‚^8Jù‹È¾š7´–§¼äíAÍ[Ķռ¤>5/¥±¬æå-òs÷·ã©É|ÌãÙ‹hˆb'Ïåµ»¾kbûF­ÃlÙªÕÜ–?íá¤r‘JS*ÁîפVÇ÷i<”¬ËK Ë!˜mr»Ÿm‚¢wÖG›B‘vÕ™XÃx%{›ã6¹ÅÏ®nzžȾ™ž‰Íeæ«¶ýåÒZÞo_% åáWÉhÕÊ¿\Bë^ÆËEœžÛV¿BFóÏ‘Ëxç —ËmÙe©å m9ºÌýØÐþ±c›ÛîÁ£Ån]Ïô‰geù@)øu°®Øú`¸³¶Mn÷³Ã<+ïýìx’«¥˜9îƒÝ¸ ev~±ŸXXÒÚ¿Z-3¡ûà´k,kN»J¼aícø-»¢à-MÙºTü'ùÆÏsÎF£{¡Ï`= £ ûE?ì%ùyäÃ~ìú°'»>ìÁ®{°ëÃ^ìú°?»><*»>ìÅ®[~ûs5ìÕ®{´ëfOñYÖ=gj;)E3Z7ãšó8¢lZ«ƒí?Úc$_m«“f´®Nšó8ÔI Â?Ø 4ãyY”³©"±·º „ßzä(÷øM«î]Ÿ@P!ãÙ×üN¡¿»Õh4™ú“û-/•£ÅÕÌ“gIZcš[cúa)°ÆZcʬ1=ZcZ#™L±Ë;7à7t52{Áñ zÒÛÞøB~Ø €»ÞY"%"™Ì?Ó#ïaøL­#!ó¹Òƒ±ÐþøÙ<‰Õ˜Ê_…3SÑTdm­è‚i]>uJGýÀ”É X@†,@šyá/¢8•£®ñ\`·Àabû¸!Y!‡dÅ/¶’Q–®é†qêÏÃRáAøï´†~$1Ö¬Ø8Þ%yfRØïÉÆ«8L¯±;ð{øØ‰øØ‰P9¤OÚøL`Ò*ðMÕé ’æÍÖ¦§(òþ–…fŸðW.-qûÁzXöRÈ%ì p±–½¨n Ø! –ÿNÆÀ²—p/a3 ì#vÍ›âîü¾X|>rµln±9¦&¶NÅ5þT›S1¢¨X|^¤~¦½â/·8n§bü ñîp„“Se+ä¼¶Jçß}1÷O1$´Ü&šÙ¡ñìÐH;4šÐÍ£š5¦×@A Ľ bH  † bÌV‚ÙC‚ò#588PÐÐô(0ä_@ÓßrÓìüqBå*”€Pùƒ„Ê# Tþ¡œJÊ Tþø¡ò‡•?:@¨üÁµÛ¹ƒºéQ8×Ì…íÄ¡¶ûm@¿[’\ítZpÙ=Ã*½ãžñg.¿\˜©0²²¨÷ÈB_xı‡I‚gOC þà Úß¶Âåߦ9…µ P{M`ìÆÞ†h*\ãe£=„²ÓBYjõ ¬5tP–Û6¨~š3<‹2´íF ´ˆ!ûÝnC¢˜×½@¶ Ô AÕmø& Öë@Á:¨g¶0Žc¿ì¥ƒë@ 6ÿžZ (:¢E{9ð{ßKº÷’ 'Â+ß”ÔÇ‚C¦¢)ŽQ¤ :F‘ž¨¯S¤ªŠ>b®ŸYÛ½4·6?ú%‚õ=0È™ 1k¼…ŽX&­bñˆUÞ†‡,ó¦à2÷¶)ŸPu¨t»ÚÔH‡Ž}›‚ýž[4¸>4ÜLODú~¹D#ÿ) 7¯`Â^,f÷z±ÔqUñrAÌ?Ç ˆEOôÅÂAvÈvõo8>rí… Ÿp‹á¶«cæUó[µ‹k»[Â3íòÛˆOVéV­ZÜ€É5¥¯q©%<.ö^ÖxFbLBŒP–9*v¹}”\›•°†j)àóŒ‚Ôfk6Å;ÏðëèLaX†X–’d$b­Õl­†@k5DY«!ÎZ áÖê@Áf°µB­"_=£Ì²k5´b­†¬ä‡‚<ãP¦Ò1À¿,ëÌÒ¡¢Å %­é£)@¬L™a€´e1aÀ\ª šKMÇ?:ÙàD›Ì<4Ï”1Úh†JøÑ¾ì´÷œdÆ,Î÷½_çe;×lsÚ21b'#Ø<кs!C;s<‘­écÊúvf»Ë€0ášÁ%x3 çN 'lŸ.¼1-r›%Y:p7ÊÒÎâù ïêaeY¤N²„³q!S8K’ú~Ä’†øù@9C-3Ôb9CaÉué²¾×.«'çNd"q²L¦{ò3FNóP¥y½Ù°º÷xÃû¾> `ΆÈìÈc÷ëìd4ž™‚(õÁMl~`t§ "ˆ]'¢íØŠLá>rþ³ö!výïEk0„ë¸KYý€51, {íáqŒöÐÊäï,ÿ.rhˆÇh«½ÚªÁ¯lÕÀÊêزUƒ^mÕàW¶ÊÞh[±U[¶j`ËV ¬Øªâýª¢W¿ªø•_UXÙé [~UÑ«_Uüʯ²:Úx[UØò« [~Ua˯*ŽÑ¯*zõ«Š_ùU…•¾°åW½úUůü*«£mÅVÙñ« [~Uõ«b ׎‹y*å?Pù²Cc"ý¾þ³SSMþ6‘Q{ü%,·IÁ£gæÖ? ®x¨ÅÃcô1:F?"óCY°FÃÓ®ÑüÝž½/MbµþÓw­?­Ãf—Þ‹E—auŸã‹ñ¶X@vg›c{¶Y,ØŸâ¨ìOÑŸý)ž°?^s +ö§èÏþOØ;ãkÁþVìOaÅþ0ûÓ-Ã?”?G“/îöSvžw°O±a?¬¨¨ +Öaãÿ° ^ø®i§¨÷¡[, w]]ÔbmS€Vj›´LS'ZHø¤·Yp“ÞbAMz›3éC!ʶ&s? §}8G`Ýå9£ÿn7+gy”²‡+N¤)v¸áo²‡]­#×ʘž»•·Auñ¨2‹@y™{Ø’<‹PÙ¬Ûtï¨Ëd<Ÿ[è3¹Kþ^­•(ö½ߊOcó¤ É;,‡•@â}9å¢LaÖˆ‰ÿ –q:ÑÚÎz-Ï¥I¶L¥ãQåù(ÇáÞa?¼–¶0ï2¬Þ…¬#'¬gsÆÝaÚbù1;4 Eئ±¡…5E(¬),ä°CcC`A‡¡‡Ž¡3]Øy¦Cƒšÿhò«NèYéÐàf¥Mƒš•hVâ<ñ\˜-pV:4¸YiÓ f¥Ãš•æ^z–ÏaydfG—HÉLÿuDmSQùcú,ÌKÈ.ÕÁ³©•SÚŽ(I¬ôñôl®ÿ;¦X8STÀQdv­my¨’C]+!w2;TZ½ò„šÿ`Φ¾x%Óy€–µ[T*9wüÀWyÕwÁíyéŸîV¡þ÷ Òûzß®¸7÷»4K+4N §Ç‘k‹hi‰?=CËkhhg Áê$ìÒXXCC[khhk m­¡!~ ¡N  §TLE­U&Ãç]¦ºuÛ4ÛâÙ16šS*ˆ&]™d~4l‹£b[$;Ý\hE»»=£¦ß¯þ¹L!fá9bP;à²ïª0~yoãq±iƒÝ³$Ô% “ièG4*qž%yÖ—0ái:éÓY&²Xk.Õ¦qPÐá9µ'ÊJqj-îk”ÞÕ'sš±#êpRHŸòP¼òi~œÚ“ –ºò r`6ËsØ}í䘶ÚÙE™×ÜØ(æs€fúGlöÓs$ÀƃŸ!èmîs˜{;ëà΋¿dîm´íœ,‹m梗“å^1ú8Y“å^Iú:YîæðɲèIcú>Yî•©ï“å>¡ú%ýuO'%¢îÉ'#jDéÉgR# Ý>“øBáWÔýQ¯qÔñSÁYz–<ù<Å}>rµD:[O²›Ö#”ÏÉb„òIi(B™ô6=Eêgüœê)ºa¢~eö/ö<ö Ç²§ Í}kãÓWÉ4ß}©Ò°÷ÎÏ”fvD²xG$‹<"Y‚#’%<"YH–uß²ôþ…H=™üž‚À¿©§ÁÀŸdîMúó6;Aàgˆ`+üQì%Ñ—uãÈÌ’ þ30ü f`øÌÀð/˜ñß_0ÿ¿`î鸧™Áß_0c¿¿`†~Á Œüþ‚øMó(óC‰î[¸Åk‘×åAù£]ëÙ%Áx™g•³t4>ž/Å×–Ï øDú9ôÐ7ÒÏÀÞ#égJsdúŠP<‹ÚÚ;égJslSÓŸmmPÏ¢îO!-mf‡«kô´ ÔãŠØ{¥jo3Û›hms3;á>éw3³nuo›ÙiŽmjú³­–63‹áÿgQcü˜.âž)SoÃaù*î™2õ5àåØÃmܳ¨¡[ äÙß ž ï[>Io÷|Rë¾å¯¤92ýÀn OSÛö-%ͱMM¶»™=MÝŸBZÚÌŽ%Pò z\ýJž¤·º™E äWÒ™~XÚÌŽ"Pò+iŽmjú³­–63û'³§©Aîj5rW™˜­#'”c×í>Ð*M"Gæ—Ìþ˜Q ö+ZrýŠÖŽb½)Ö³5ÅÚf¶¤X;´vk‡¦XA@ µ>cUi› ©<[\8uÙ&‚)È6‘•(,ªDaQ% [*QØR‰¦QÊT;U’uí'KG OFq޶<çaýí B«™³˜zÙyh1_«i©¹îB¦6i)}ªPÙ:6GyH“ëGs?ò³µÍ†Î£IÉ(³úÅ¡õB|JCý3÷e&nœ›c}¦uZ%ÒõÀÿÇîr:kOóàÄæxŸµ'Ú.õùÆdŠ VÊæˆŸg~´Ž¤ÒÖSΩŒ©EîwôÝÊ_DZÑ¢…e5?OÏ´8ÍçYê$6çöÂóú—?ñ}Éhuõ¼×ÖJ>:î!ãŒÙ´ëK÷üüƒeÒ0öò ¶LJ+Ôâ6 úñ!U?>¤êLJT=ùª/RõåCª¾|HÕ›©úó!U>¤êχT=úªGRõêC*Û>¤²íC*ë>¤êÁ‡T=øªRõáCª|Hç ¤EÎî#ð+¹Ž8ÊÃn#ndŸpqú„»üÒî"Žô)77¾Oºˆ@Ú§ÜCÜ?éâhŸv q£ü´Kˆãý•;cÞç ¦uŸû²½. ìÓ¸8¾ý®l4¹}PÂ}.”pŸ»"œÙ÷õfö}½™}_oÖƒ¯7ëÃ×›õáëÍúðõf½øz³~|½Y?¾Þ¬_oÖ“¯7ëÉ×›õæëÍlúz3›¾Þ̪¯7³ìëÍ,ûz3Û¾Þ̶¯7³íë¹ö}=×¾¯çÚ÷õÜ|=·_ÏíÃ×sûðõÜ^|=·_ÏíÇ×sûñõÜž|=·'_ÏíÍ×smúz®M_ϵêë¹–}=ײ¯çÚöõ\Û¾žkÛ×óìûzž}_ϳïëy=øz^¾ž×‡¯çõáëy½øz^?¾ž×¯çõãëy=ùz^O¾ž×›¯çÙôõ<›¾žgÕ×ó,ûzže_ϳíëy¶}=϶¯'íûzÒ¾¯'íûz²_OöáëÉ>|=Ù‡¯'{ñõd?¾žìÇדýøz²'_OöäëÉÞ|=iÓד6}=iÕד–}=iÙד¶}=iÛד¶}½¹}_onß×›Û÷õæ=øzó>|½y¾Þ¼_oÞ‹¯7ïÇ×›÷ãëÍûñõæ=ùzóž|½yo¾Þܦ¯7·éëÍ­úzs˾Þܲ¯7·íëÍmûzsÛ¾ÞÒ¾¯·´ïë-íûzË|½e¾Þ²_oÙ‡¯·ìÅ×[öãë-ûñõ–ýøzËž|½eO¾Þ²7_oiÓ×[Úôõ–V}½¥e_oiÙ×[Úöõ–¶}½¥m_ï©ÒÏ ­yªì3ð+-ûzO–{Ƭ}_ïé2ÏÀ/µîëý¢¼3n|ûðõ~UÖ7Æ}øz¿,çŒå^|½g”q†1[ôõö—o†}™M_ï`ÙfŸU_ïp¹f(¡E_ïp™fáû¾Þû¾Þû¾Þ|½}øz?úðõ~ôáëýèÅ×ûѯ÷£_ïG?¾Þž|½=ùz?zóõ~Øôõ~Øôõ~Xõõ~Xöõ~Xöõ~Øöõ~Øöõ~Øöõû¾^`ß× ìûzA¾^Ї¯ôáë}øzA/¾^ЯôãëýøzAO¾^Г¯ôæë6}½À¦¯Xõõ˾^`Ù× lûzm_/°íë…ö}½Ð¾¯Ú÷õÂ|½°_/ìÃ× ûðõÂ^|½°_/ìÇ× ûñõž|½°'_/ìÍ× múz¡M_/´êë…–}½Ð²¯ÚöõBÛ¾^hÛ×{ªÍ.Hkžj± üJ˾ޓ­uq#kß×{º¥.ðK­ûz¿h¥‹ß>|½_µÐÅq¾Þ/[çâF¹_ï-saÌ}½ý­ra_fÓ×;Ø"ÇgÕ×;ÜJhÑ×;ÜD˜Ù÷õ2û¾^fß×Ëzðõ²>|½¬_/ëÃ×Ëzñõ²~|½¬_/ëÇ×Ëzòõ²ž|½¬7_/³éëe6}½Ìª¯—Yöõ2˾^fÛ×Ëlûz™m_¯°ïëö}½Â¾¯Wôàë}øzE¾^ч¯WôâëýøzE?¾^ѯWôäë=ùzEo¾^aÓ×+lúz…U_¯°ìë–}½Â¶¯WØöõ Û¾Þ£}_ïѾ¯÷hß×{ìÁ×{ìÃ×{ìÃ×{ìÃ×{ìÅ×{ìÇ×{ìÇ×{ìÇ×{ìÉ×{ìÉ×{ìÍ×{´éë=Úôõ­úz–}½G˾ޣm_ïѶ¯÷hÛ×[Û÷õÖö}½µ}_o݃¯·îÃ×[÷áë­ûðõÖ½øzë~|½u?¾Þº_oÝ“¯·îÉ×[÷æë­múzk›¾ÞÚª¯·¶ìë­-ûzkÛ¾ÞÚ¶¯·†ûzñJ¦ó .„LÓ8½Œ&_¦j—‰hh‰èúd´²À2€°œ‹¯¾ÊD{RÌ%Ï–qü0º› \ªp’Ñd*¦'6è.òÈ|œa|—J={JZ!{¯w—HÍõ‘â7–Úèº2Éü8I–N;¿­g’¸5ïåDZü~úû©rmQ¾iæO«Õ¨vmfúúðU´Ã^Ç{Øßx{ïë~¦ùºŸ¯u¦öæWþÔ\7S±%Âh:´BI»ôz¯Ð~ŸÒß턳|>võÜ¥“ =ìä º£Ñà$ÉgJʇx>ú†b+1Õâù©þý©ùým"#í¤JÄVó"1“X¦ÙÙ\ÿw<ÎTædRd££‘õLÉl1ºs§§BÿÓ§I)E"¬#ã=‡þ|1ËÃdä÷Æïë¿¢%?Í.‚Øu‚Þ4ò<éy$ÔBf}jñGz1ýIäzÜ^ùõ|éqr:Üö§ŠAZx¡-²þ»>ÕðBEò±Ï•x¡²X©m~œØ”á±ws Eè}=¾#ª× úÝñûïþ%>ç;•Gýî±ïýH8+Çz¡Ž öçé¼×‹êhܾÉÌqæ4'½ Èsnë{ßû –q:ѺÇòL>MHnàJ~IûõÃÊê°·SéèbåYÜÞ¿}Øß·ƒ®ÍžÇÝãœ_÷8æepÕŽ¾ÛüÅQFŸóÈ<½}²VÑÅÂ^tñI)E"X;¼ì£·]ÜËß‹›¹W‹ÑŽü£‹ùõY¾°âÞî—ÀD‹^ù)šÑãXŒ.îã·]Ü/@uÊêo¬F÷ `7º¸W†ÇÞÍÁ&ºØŸ v£‹{%8~¿ó£‹ûå´]Ü'åèâ^šèâÞDè+º¸O˜Vt±·iGû³u¶£‹ûeh¢‹½¹¶£‹ûd°]<Àßß·[Œ.àïíÛmE÷r÷8ç¶¢‹û¸­Dýhq º9uLfà¹ø&òÄ#—I.(;¿”ç–§ù9A/b-;r¿’ðTÿ ê©Ìó¥°• ó+9ÌtÑAåÎ Ã~%9’˳ä<–S˯„µ•ð+9¬ÝÅÿRCÎêïÖE±å/þJêâqi®êÈã( l”àŽè/@{£•{AhOm¡®åž­maÛÚ¶­-Ô³}‚ЪÚ­mûùW™ÙÑO5ž b±ÆKå:>™ì•Âx©\G'ÊŒ¼Hey‘ öŒM¿…&^$Qï»_*àñÉÔÃ+ï— xt2Y´C¶Ÿ{¿LrãÈóMOë•“úÎ,ƒ“(ÎüùZ8ÁvÝæß<­vú,Òžz˜Gö<òæRèSÉÃxš‡y&GÖÙ)A %ÛÖ&$ÙÎò’Á¾ìC¹\ýþ/“Äâ áÅ‚¡PöÎ/ìø„íÎ/³=¿PÌþ¼Wˆ~ /©“‹%°;%à€áÀ<Ž•©VÅÀ5•Ðz)'KG OFqî{tv†¢õõ/bªhàí}ë¤õ£L.dj“vÒ§ •­is”‡4¹~4§Nk›< G!“8’Qfõ‹C?ê…ø”†úgîËLÜ876ÇúLë´J¤ë;ÿÝåtÖžæÁ‰Íñ>kO´]êóÉA¬ö?ÖEqg~´Ž¤Ò¿•ó8ÝkMPÜï軕¿ˆ´¢E Ëj~ž:žÿhqšÏõ†œØœÛ Ï_è_[üÄ÷%£ÕÕó^[+ùè¸{3hd?Ю/Ýóó–IõÙ*bˤ´BAÛÀp÷òZ8Ñ–puc~ˆ–põ…§YJyÊžÌ? …HRªèÃÉvâÈI©5ó³“7’ž»Ù:1µWN2ó…J{*û4ô=Ñ©8ŠÎ݆q¦n¸†þÞÕÆö-ô¼up.Dùö€’¯r7»û’ÍYúR4Űï¿ ÌÚÀCÂTxHª‚/Fƒâ›éŒWW„ùs(#vyû—'N¿P{6ðû–%˜ ]ލÒ?xÈr¤Jyúøª§ù«Þøõ¯=iüdze?Œî¦'ÝVë¿À²ªÂIFÍ:X%¾È#óÁ+›¤ïR¹’©ÚÉƲ¾×ÇÙHÍejf5Îî2£x0Tk•ÉP¸”˜<š“Pgqä»û³“ß|4ÙË|ítär£/*ð]ù^Œ#O>JªcÒÑ÷+'pÒÔYÃÑôLVî6ñÐq¹ ô 6Ö¿R®yKºh4^ÑésîÔ(tå-8™\ÄéÑÚ¼b<¥7€xHÑc >Œ⟋q˜ƒ ãÅ©LVõ<úîËÍTœÏWf[Ûùïï8çg%©€œ½¶$05i‰‘Ê$ÐdÚ¾6² ù?´ø›ÅQ‰`Kˆá`W_ªR ÜB-ÉaµŸ¶Y&ô5xà¨ÊUÛ,v rvèP`ü.ÆÉ¯(Ê#6pK0†opªwjj+ä *ê…i,Ýe'vtq'Öž·Dwk[¶9¢ú²ö–(,SJòìØï~ª^$QÌL¤Ê1ãö _ UYYyùÒÉ[tå‰èÓéƒ|O"ÌÏ^¶(`²K¢6áš%+ك᧗µô»‘RÔ*¬F ÷øËÃt§¬ôþ$É—k¡aDºX 6#@“=¶ðÀ&´‚y-ƒž€1£Õ}‹hUžñ´Ù [@\Ïb‚(`N+À¼‰ÂŒ&¥kC­eË 2nª2ˆßcÊi¿¸õ¾Õ“Ãà‰¹áNÜ.s-, 'OÄS–%óˆVÚÜ‚~i_Ã~#¢Lൠ?’¿Gú=œ½’dM¯e¼qK*&Éa_Ép<´Bù-–ú‹äBæÉ"ÿ˜€8[’~*IDò-1´g×J íñåLâ˜\9éSüʯ;´Bæ|g>ÌI…¸‚‰6‰|’róµ1_y"/¥ArÍèÝý‡8žúÓÙ“O+¦Xc! …ìZÌ|6cI@ýmˆ |bÛžXk^"»¬ÛÍGQá½!–ZB==ù‹‘D~ʈVtYÍ¢.K ^×;é¨??U2]EBëš*£®,z]SåÔU$Ьëhþ<›GA&ØBõ*âò¯jí@N•©º)s”i¶·zí‚=ˆÿ½dj 'Ê’Ý”ÙÒ|Ò¨“’"uR–@£NʈÕÉkWÔÉéß7eÖ.ÿWÚÅIf&”%œ\¼îV'ôóI¬NȬ“²buBfÊÀÎäü=štähˆVÛ±£¡Y™Çކxw!ñÿèѯâ.¤þ=âUÜ…äÿb4]Éþ?z4„«¸+ùÿG†pw¥`=š.”=âUÜ…"€£GC¼Š;QP¢T_“K¡Xqe úIÞƒfç”$­¿²ò5¾QÌRßó‚·7­ßww÷XT²PJÞÝáƒ^øŽ.ô‚wuú —| ÛÖDáOž)Gs8•ðI¶{ Ÿd³/:¿‡qZk|i=ö°™èý— >Ý»‰SñA»súÑÿ”e¹ô ÇÊ«z‚'¶â”¦L(>0# ßJñÉ›át: àD=$7OMÎ`«ø‡+SŒÿsÍ#`O=0 +˜2?i]ž"»ýÐ’±HMìÐÇq‚xöãñ9ÓBÁ8@¼ÛµµˆHuä»Ðdþªwj Ú8ÙÉÌ¡½BÛøØä†SÝ}¿=év4íNµÃiÍpªÍÂpÊ4£øw —ÿ·ÔÊ n4…5õzz¹»­©v&¢ kªv§µ¦j‡°ÇšjçãœÐšªß’5U7”]ÖT;ß…ÜšªºÃšji Ú8îÉ­©Z¡m|l"kje-ÍäŸfÒÖø4ó#º$ýèLÔñÃ!‰º=¢ÅvôphÖæÑá^Ê]È‚:~8ÔK¹ yPLJz)w!j1œ®¤B?ʥܕd¨ã‡C¹”»’UNò¡ŽõRîBFÔñá^Ê]ȉêsñÅ þZ öcÂØ¿yäZˆp1¡pP枎o3=Çc WGY$é¼ —Á©_‰x±mõ5>ñ'!ÚŒ¢±»F1Ñü¬ñiægO0?æR\A>‡AOÓŠ_xS¢éK3ÏÆ"n“»9ŸÙsœüðâdÌ’\)Œ>‘»ÇRòÄÓŽKèùãx–‰°Ð÷ZüŸÁÆì‘%”æ{›± ccìõ"ÎÐŒOŽßàëÍãÇösù~zyÁöár!¦çqôÂD‡×Ø{¹^†Ÿƒ»{ïnÓ¡÷™¼J¸f<¬cãyl{AeZ=[Muuh.ÕÈêV@;#[þ<ñ™àûs!\·†?D¿ù,Œ&‚Üh‹¯% ]ˆ æI¢Ì[E‰ø;q½ñ´_Œ_ ) +fn%嫸zÞú÷¢wºfT~; ˆëÝ=ðEĘ7fAžù›suQþóUþ§­~zÙaÔ⋯…ŸNviÓŠSHaûºó(ðç“§ê>–Ò_¾‹àG\Òrí@(hO¸~eI'´‚?š0:AzoµÖ¦~ð1óÝ;`³âyIœw†lõ;¶Á~a>‚Ådãg?ŒHg{¹~X4ÉžN!)žg^üX¬#ZI =§Â8ӵͥ’ÓôŸt­h[V˜ÇâÇclÄ»S|׸ްÉÆ·>vÏ„µ „+4QÿM·×ôÕ^ãêãT˜sd²Œ¥¬y4&f®ÎÕèÅŸ†Ü¸O&óÂD"¶Þà {ð§~0ï1Nøûñݼs“ìñ~É,7íÜ¥»ÓÃŽ¡puC2š×úhé¦nÞôIqÀÝ@?#£mПuÔ'q”™ßAuÀŽæf" 0?ÕI€Y4žJ;½Ð¿t1 YÿÉ0n¾S £ýÙx%ÚÖãtž>µ?Ï‹q´>ÑÖ+•BâÈD‰#©$g²i±ºõ1ò÷Ÿ„?‘nF¦7²¼{üÂÜÁñ_ѯfQóñí=ÁO7yƒ#™¼(έߚU Dî?ùÂO°ìFDŸó\¬·óíCo0<Е®í“þzréâ–Æ/gKbëÖD¿žR´ëi_w!ó¤ïéün¼ðˆÙ~~È£ß^ÖÊ^[ÃtÊ¥žö‹¯¤žö›Góç#êVÚ¡\9©G(ŸeÞÆå’‡O8ÂrW¡VÄžtו›C´"ö´o{$Cx+C쬖9–Û·•!vVÏ]©ÙÎ;»®­jgŒZ«Ì_ü0Zž²½7Õ»Ï÷éËí€Öê^Ûž×6f`óÆÞ¢ô×K_ßÛÛ{ê·Ý}{og[øScu‡oGðÉ¿ÿ‘7ùv)iØœ~GX6í RÒ´9é +·ú–$ŸzVîö-I>ù;{Ãoi”]Ö>Gßó[e—õÏñ·ý¶†Ùå•yü¿­avlmNÓ›fI3Á½7YÞð³ß1à§ŽÊá©õ1´ÿ%Úÿ$_A6l$ª³G, ãT0'¤“!Æ4KX¦a\“w×Ê L]›*KÌ6ûö‘cqÅXH öŽŽ`'¿\õcÚJ|Û˜#ÎDÒÌ2>®qÓÉêùcv~P;Aü<›²7>TšQ5M.=é¨X'çŠur®;9Wœ«£*º1ÛHv™SHGŒ‰Þ@:bP'0äGEg É…Ô@:r8¤’ì˜N¥y¶2ìOn¥Íj+Í ë‘KÎÇ!çÇ A©MÓ!äÒGn{ œ‹ãt¡Ñ(?B£Í@rÈonø¯ðGÒCÀ÷ÝÈá®ýY¸#™Ùrï!…¡xÄ8î:2rƒõ¸1¬Ç ŠÚ`=jTDëQc¡3XÁZ?¦Öël“ýÕÖ.bGrØŸ×Ê ¹óÚTgê3¯Auq¦dÉ_¨LÙqP™$²ã8…IrĘèM’#u“D~Tt&‰üXHM’#‡Cj’t½âþæ:¬¡áýY³¨)êW­çyÁÛ›ÿ¾h‚^ø1N6öæÑk«|Â:…HÛó˜È/^uæ¨È\0Ř˜Ïó“ÄÿqZ‘ÁÔOÓÓŠœ EpB‘ý|õ°p­éO°‚¸ØYFKN÷®‚ÚôQä? âí“JMÃS/%Á—ùò|z±F>Åc_°JúÓ ./¨Ø{fÏÔK‹KœDs1ÍH³q{üÐd‚sµ6ɵŽL‹nµ ¬ÄCp‹!¤?¢ Õ©¨ÇÉæc•låùÆu2Àš”Ûh‚]œ΂â]†õ6‘b€°µFö3Ñp?S×ßVJpÐ ЀtLÊ(@)@Ÿ(@C Ðÿ¢R€>S€¦ è è+èèP M¡¢)44…‚¦ÐÏê™B;S(g ÝL¡š)43…b¦ÐËj™B+S(e<×Üu,àjÖ€š &tS€fZoÝã‹àÚ'ä5;:•ï¯B€pï~¢7Ýy‹V*«½2ŠBbÂYÚâç¢Xùu4\ôr^Oô>¯”ï¯â r®y¥Rê°G$¡ÔZF‚¾ ®"ÜñúBñþˆügFöÅ«R¨>¹^n¿G$¢ÜwHD¹á‘ˆ•y˜?R‰(5ó#;J8š7Y¤ì‹/œDp]@Vð2Uýäo¼|ò7å#Ö¥S'¼¤##<[ŒJçDš/g.¾Üéë¦äÓ­Ö¥dÉUƒ`.$Ç­ÍvÜÂl¯Œ°…´A#z©›ä¥dRs®Pj{pS•EhæšÇ ¸¨Iœü¨·C4YmÜJó2[vî>„÷ÛÝpû¡Š£ÉŽ·.ÊK¨g}!g.)‘üõAM»'·QmJkÉ JþF›‚ÈÞhÉã¹z£‘ ·ã‰%ÇäH9¨Ù¼:SyO4(9–F¢Amô禑bo6æ¦ã¬ý£«¿ËK&®Þ+K#n§³™LÙÛ¹åp·ÝOy× áÄÇpí!hmjÇÐÎ<ʇ¸ÅyÙî…OÛçW²Ä }½)¿xïWkÐ ˆ3¸¸Åýsãý_C)Å7¸Ãůº´P¢™¢;{®ÐJ;‰w¢ÔA…ŸêÛ×…v,¸ÙÝ„v,¸¸"¸ø)M¾*è qÛ”û¬¨Ñr;¥®)4 Ô…FÀ‘=Ph¦óÈV'„ƒéˆÊ9¶q É`úBçøÓi\Ã"‰¿ˆ\.tT’y² Q_N\»ÝE†æemC9šŽlî£[¿ÐŒ†6{°Ÿk22›¢¿*®&€¯)»BÖTÝ@!kŠn 557PÈš’(dMÅ ²¦à YSo…¬)·BÖTÛ@!kŠm 5µ6PÈšR(dM¥ ²¦Ð YSg…¬)³BŽä Sb#ÆvJn‹<Ì—‚.ò0ã®È†Ô;æúiL½c8ÈRQïàJmL½c¸˜b%¨w€«# õŽ ]Zpê³O6„¦Ì!@¨w,¨vA¢Þ£ õtÇ5¥ÞÕ¸ŽjÉa€óSË Ƭ¹1k.A`Ìš[³æƬ¹1k.B`Ìš›³æ*Ƭ¹ 1k.C`ÌšÛ³æ:Ƭ¹1k.D`Ìš³Ž YG„¬c‚BÖÁ!ëx`€u40@È: d ²ŽYG„¬c€BÖÀ!ëø_€uô/@È:ö dù ²ŽûYKýŬc~bÖÅD ˜‡x_4 .`?ï ‚€½¼/ñ¾`ÈØÏû‚%àï ôŠÙ”÷YÎîT|t9tï³—÷aæ}рΣF¼/Böó¾@ƒ‡y_$ä}zò¾}¶ y_¤à}Á˜®¼/"ð¾`ˆ8Àû‚"â ï ‚”ƒ¼/P·ëѼ/\ƒÇû‚(XŽÜ_ðÉßX’÷O°$ƒ†àƒ¼/;çï ‚Œ#y_ qÈãy_%Ÿ–-¨$Y–÷…@ò ßYž÷šÁpï ŽÔ¼/ð{L3Þ9x_àÚô0ï ‚cy_LXƒºZÑM·¦è#x_ ùPÞ ùÍx_à>¾†¼/‚šñ¾"{#tÞ~7Âç}A&ï Å À%ƒjÀû7nñ¾À•¸ï ü¤”â}!·ÛÙL%Žìí ¼/ÐlCÞ„!€y_,øfó¾àáxÞª1œv¤x_à›PŠ÷A„÷ÅG¡@¼/pñûx_4ðtï ]Š÷ì}“â}Á¶‡÷E&Ùâ}AÀGã}±às‰Æû‚4”:mı€¯ð±ìã}kн¼/pôý¼/ðL…¼/öó¾`  zDÞ°IÉû‚4•ƒ8¸Îf/ï‹ö”Éó¾@+Pá}A¹7'>ˆ¼/6ø.„Éû‚6”Í:¸S>š½Ùƒðe¹—÷~ï ¾¦ÄhÕTØk l€ˆ5õ5@Äšò bMu ±¦¸ˆXS[D¬)­"ÖTÖk k€ˆ5u5@Äš² bMU ±¦¨ˆXSSD¬)©!ÞStS¾¯­©fbß×Õ€AÕ¤»Uß,@p\¦¨ 3dj74ìñKfŠ",–ã2E™a‰°ºŽÌ°D”|ÚÎz%ɲ–xï,›a‰ aFØÖÐ3ÂÀf„/Ž0ãáø3ÕN;{ïêÀåö§<Åž ó‰ýyźÈüh.,h³-ò0Åž[)E±‡*´1ÅêmL±‡úM›Sìን ØÃeiŠ=ðÒB"—Ó€ ÒÔm Hz9àyógSz9`=ÍŸµ—~ ˜Èúgí­zFÖÞúÁ ‡¸4À|È­€ñ‡¨.0^¢ …ÖêºmAõi´Ø‚v¦"|£½î%„…v˜ª÷6…Ô¦b`ÙÏF°a°Q Hh@ч9@¶¥ìH“ž¨£Ã\óu€+CÄ® ‡¸"0>Æa²„79H#㲌9<Ž-S²œÇnô@”,@8 `>D怰{Ž 5 ¼Ý‘¡Dɲ„E|d¬ï¥ec ’åÙ žœ© ê%p¤fsƬêäPtâÌå4as€úŸFMØtݱl'ö±t¸²às €L\eöK3F Avf3F AèŒg>£Ú 00”+:£Æ 3: HiÂè€ F†ÑÃ×(Cé@$Ôi+Cê€!šsƒqÿ€&Ý`Œœuƒ BÁY7xc8>ë†j §)^cPŠØC„Ù~%1;ÀÅïcv€‡.ö3;€/CíŸ*ji{¨à7”ýÔøhÔg·Ö`PŠ1áÜ>–}äpó|¹<š}€Ü¾; ØOîw  w@€Gɰƒ¢r6"¹|0{ÉPàeÉÀÛàr¸LÚLrl™a’; gsc޾»á£ÙKî·äöÒ/“Ο"Íö¾ŽÆ×½ÁË6:Œv…­‘a7Ê!|·fòOøþu«þ”ï_+Ÿòý›dqN@£P΀”C™t*äFrê9ÙéÏ<ùœì ᜬO)Ê÷-I!x——žé&ÕyUB§{H:ötì1éØcÒ±WêsHߣ*‰øâ“½S|ªwjɦ“ÁIçàTfäN2ûr½O3{Gp’98µy+9Ú9h’N< †pÚYha)4Âif¡Å ÑÖo{{ N3 û‡pÚYho-ìí,´~ÿ?z,§Ÿ—“úŽ í¼È%ÞOŒä`Z˜™¶–Œä`N23 “O33MÓÂÌ´¼fš†tfhýµrðßgì) ï>óqGqö”į^M"LÀÌSâ1Gu±S("íˆ_ÑGüJ:bÏÏâgáÏ™úï1N<0ì ¼ ÈℚÄh>#'ö˜/¾Œé”à%86Ù|Gì•h²92ÑLsd\౨ðåÆ)¾17y{óf,IãÈŸ†Ù磊‹GófIüVO¿À.ÛëB—$d{YRÆÒÌó¹…”²C7„ãäýßýãüi>¼=Oõ_Òøýç;—õŽ’õÓ÷ŸÜûø÷왟vüþþr«{:£™²l˜ÆS?ÓP‘ùNˆƒ‡köèϧÙèãß¿ó/1e ó‰OæÐORvG¿áâé˜Ïá_×Aü<ó³ð!›ˆÉ—ѯóÇG–|WÑQðÄžr1‘ò(ü7$Ú·©@ÞŠ[xŒ™ð‹kš±äkÔk~Z$1ÂFÝÀå‹ö;:èÑöæÿX0јëÍû„±oól6GøêŸ›ý:õ£ïÈý–[eH«ý6ŒØ×¹hš€=ÆØÞ²ëlŒË”^|æâà¸J˜Ÿ±Oá” jJl¤yÈÏúäš=Ì'ƒ( ³¥X 7Ù´€:7ò5Æû|Šƒå”c.ç;?LÒ^¾[˜Wþtúàß‹ñó‘•oUL|cä¿°¯ñày–ý¸÷'‹w>ϦXs9Ê’yÍ6¦D³,Fó‡”o~ž.Õîgçaq2Žòh9 ñ1ŒB€ÍšŸñ÷x˜ ÇâEq…zÍÜËm0ö3ÿWa)áÂ>ù‚܈ëHdX~]øÊUy:óÜ)æWÑ‚.SÜî×GP¡à¯²7*!ÃyúD(dëÞZ+ág]?öH¨"ìyôWÉo‡+•†ÿ‰k5ÂQ8bžæîž]A_ † "à9É&ËÑÅCGæ ‘lN–ØègS&¦ý°`œ¼ÍÊ ö/ú‚züH ‡ŸX4&YwPL2,×?ðçöŸ–‘Ÿ[\ wÄqò޹‘…þé&,»Š§ó稸䣎šcç ú6êÚ)Lc™p`®&84_ 432œ?LÃàfŒ;Êûaãæn>š©~òÓÝ>äè7zö<ýÈï "üñÊ*sný¢Ã¡çY|5SƯÓèã&7’×B¾°ç8ùQ/ÆúÅA’BhŠçB8èóÇV‰ý ô§1ò†¹ƒ‰}ó ¹X74èª ø”}ËSSltný”îOpÄ7ËZ!è7Ë\J,Bä×óçÙ§8yö³Â[O,ŠNˆ@§ÂÝÞUøèÅGØ0|A¹@¹ŒÅÝbqÜþΆ}ä.$Œ2?›§$èÜ ¼0Voãøû๚H¡GÀÿƲ/,ó—‰ èø…–ûöfË/Âè„]™…øèé ÷Q€ÿÇ"cWXÌè£ gÙG’`€ð•½b{¤Ö°_ãëìš»~7qm 7»ó"ÅAµFwÒm‚oS¸"(M‘¥BøâÄ>®t?¹cèÃ&òÓ¯ )4Ÿ~…Ná”]ƒçfÙ×$ÑD7yš[<Õ žæöNws§ •±IV›ÈŒ!æ-6Ñ!9"¶Åïý Á%%œDqâ?LÙ_OaFà É0å|å…åÓù 9Í Rš;› Rêrü‘…p+k#¯¦tž>!£’<Â”Û„ÑØŸÆòº/J}îcQùƒŠ,²P±¿[މýÙ¢ex =Îq[} &úÄüÆÆú Ô?Õ{¼õwÏ’8`iʲ›(ÍSCs~Ä—HØ#KX„|â$Œo½FåæÊgy«Y”HaÃÓD¤ÓÌO2’ûXŽLq›G3a¼Ž4‰2/Âå‹­A Plò6 £ï¿ñ•WX×,cî\oH 06r7émˆìÆÈqGä“3¢œçéÇ+?ã6Èäã×M]‚Fwl–°ïøíøWgUÐs…N _ä/ )’™ˆ…üqwƒ.a<þHV>Pà_=…SüÅ¿À½ Sdµcó3•ÀÌX`gc2ìQnï}áù8 }Ü€pƒW*@¿²·lr€ì¹Y SÝ øaÂ^èí/P©Æ+ˆÊ¥­ä–é˜(À[Õ§èÃçj|ĒП†ÿf÷oÙ"û§êÙ¶ÁRæYüÌ¥+~=Åv—à¹Ñ*òDXLÆM*¬Êä9Œ(Î…¯ì•þûÄðæZÄU<ì\ˆ^ýÞˆ”t§êWaãÓˆÁß„[¨_d0KÃ)²û¦*á+›l½Äª8GÄ·(`äËw%„p®HÇÏÇ ƒ£2SÐÔô]B¨Þ„_»?…ÂïO9]BÈZÝ/x£âxzß3ä,¿5#¾k`ü;ó©À×|1átü/jC6Žrà;6å‹gË kIWWøÞÝ_d‚“3?³T?°#àJ3¿Ò•鬈Ü.Bèû˜|ðÆìÄ~íGq$¸Àª Ø‚µ)©¢TkdYG÷‘.௖üê4èqôÂt³Ž0~·€å´¯cËè—굚øÝŸ&t·À¿IIìÇzþm‰¢¨5"N(Ò83m˜ùQæS™ÉcÌ y®ÅÃÝê+Ãçºh˜§Ÿ‘‹ÁWyÜòDA^ÔˆžF½Æÿ&iNsCd‚_CÞD„óñmŽŸ´¾@¿‰îüh‚Z ³@æ¨1½S G$Ð,ø¾äÚ%ÿýþ~˜ÇWѧ›ƒßòï8÷' ?E!‡GÏ%_/ˆˆñ±ù…u‘l’ºÊX/•¿°ç;4O:Y$èákÝBT%·™î`-å·e+µòíÍEÏÿŠ€™è êêå,$ì"ù‚ú ŠL *ð„Ù#?üÆ$ÄkA÷O óÇ$è9áöMôØ“àñføâ¦>úíËíÂ^×0û±Ê˜¼õu(œ°KÜ/Üv …gBvÁëvuÚÔ¤5ip*„døÞ/»{àÈÈVãR• ˜?³Ä§H9ÈáE}*¶UÈqiŠz6Á)Rœs\ËSáÒ¹H·%[‰Ã¹v¨„K2)y`ýz™_Jr¦æ"huÀZÄòML)tº†š¨t%ãæ¹„(#¨Ê^Áï#ZÅ“BH´º’Aá0]ßî¤ÄK࿱lÕÌ ûp¤a -!ãR×”‘ÙkJи6%`|›82ùl—vñ¥l‹®‚ß0°iˆsøö_d¾«ã#C‰žaÏÀưK¬3 cˆ1Wgá8Ì~äf;×;»´Î*ÚŽÐÄJЛ–ÊŃ —ɶ ¦¥©”¨Ͳ»–Bú ”ƒ/¦‡èsµ}Ç$„y…€­€Å•˜Œª"€$„”_)éØJðtç ±­às..Ð)©Êø$Ó#¾-…n l¢´…~ÇøêL||õPˆÍXúyŽ0þ‹$ Icð6ݯW[îz8É \˜$è›  V ³$|Ùôc`o_‹Ð`k\óÐy´Hî¦A *]è›ôk8n*C$ð/þÛ}üEЂ+‹Ÿi‰‰ Jhpk*D° 7òw‘€ó¤Ü 6B$ÔÂÏM¦ïDŽÌüYd!à7Î[ñ³ÁC›1ôœ*{G‡úFãšò|1Iº¼µmá"Êì¤øª(ím-—°àé¢À&JþÐî XÚ ÷\~†»€¥Íp/I [‹¤WïBYÖ©€¿¹&y^UÆOQæ£Wž ø/\żQS¸ —¸‘ÿ›ÐÅ‘ @¿¹¨TB—¼»F'äd.„d‚FºªÎQÎýòv0 b‰Kµ\îÈ´ ¿œmÊB¹nß\qÎ|A\* hšÕ-Ðs^7ì,^NZ/`ó€èæt#”aÿ|aÏ¿± Xp¶A;bY52Ž\êÞˆ~‡(ƒç†áŽ%£Ô~>/Y‰ã–0’ :ÁtCÊ&="–ˆøy–°4ýB`vý–·g£—@Ó–E`gy—k–¢ß ôUä“LáÔ¬‡T£ÿíìÿ‹vúI³,þ[Ñç¤øÆ·1…­ÀÅ|b~6O(¶î™äÂá Ò®zÑç½P ožBT½¹($ééEX( C‘QO0æ¯ñ×tó²dÁK4sä1Û${Å4ÕfÙž $`~Yç– ×TdGÑw’¹á·SŠƒ¡àº¡Øè‚ðŒ¢Ð‘Cÿå'?-SÒ<×ÂV§Y'¿ûiÍY‰VäÈ4û“Á>å}³ä‡N nP‚S`‹Lh\’&#kd‘åŽíåè­4nQ’@²ö h’•·]H…ü¯š A°ÏJÐ4rQjM§ Jø$+¥„O? üˆdܘ ÷Ó|:%´'Á&èœ#pÿ˜ j&¢^Â'™ó>6üÍ·O÷C’,­™$M+G¦ÈÓÊ)µn¾ bg¢iÐDó, i&z‰ü 4ÍGÌcí¬7ÑX$qó¯`F¿é‰êüSðP 94ôЙ¦lO ’ x¶æ52En‰@'âgÐE‹o¢ǵB·÷Z=_öMú«Ÿ’tµ[#ÿ–Äõ·‹Ÿ!D!êã·\ÀRäÇݤ4óL9ÇWñóCðq” ©Æ~Nð©c°TcÑÆˆ ¸F¦9~¤ŽcŽY%1þa)€o¢” µ®@þÂ’ É’Ƴ_ýý^¶€&›iA‡M6î¹Á ¼ˆQ}Ä›¬Áó2]:xq Ó ¿°ß/^‚ñ#ß;^ð—?%Y‘t§ˆ´å¸1$™áØ$ò@ lzht?£À¼‰tpZkµSJئxÑ@o4Ÿ±„ìCßoÇÄÇIܦyCR ÷æmJÄÊýÅ•FõkpG+`ÙNÕ»´¬þ7àû8ò+¿/|ŸÅ!¼tw‹OÝð…=ÿÊ‘¿or ÛÀ×a:›úèd¼i–8ðœ(N‘Š·]X‰„ºgçÁ€ïòV)(îSüJ»»S9Hÿ,‘i6õ)C¿G1x –É™¦'ü—x<¯!£ÂàQ/ ·)±7ÓoðG?žâ):¶`/¦ú7ÀDSèU3£<âëEyñ†ŒÑ5~˜¢*â_4oÅ"aPаßqaq„s_ÊØnŠN‹WÆ¾Š£ˆ\IK)…Zô{ôbÃ%þ+úÑ´@nôª%¦Õ_ ׸"œÀ8\#“/Ǽ‚T!Z®üÉf‰¢…Ñš¢Nu]ˈN‘ü»€&ñú½pý¯9Ù§¤È,^@‹Ò ÊY)Êþ¸COdø"ëúã<{ú„¦i)Ð( ËÐ_Ô’·,šd›=]ÁÍE—Bês!”‰-á?1‚:ƒ%8•Î $Xö“lÜ5ú‡d+ÿKøÌḭ̂[+-á©ý›tn¨tr½1pÄI¿cÙ<‰®œñK #ÿ…›ì¸b¯T¼ÊÂZIR¿’¸88M¨I Ó“¬-¤$PæÈl;7~¦ÈåÈ$Ù*éi ¸ ŸB÷ÁÉ5òÀÏHc¹€áÍÆ„Ã]./I|ç¿ÒÍ÷ý.ÂLä[‹…ƒãÓËsTZvy!`+!ºÂ%äOç2Š"=|Zo}óvè9ú§$~->¨ðÉFOÂ4Íq‰4 ­ú&Y4LU+`ºÙ¢³V P²jeN3Ñ4t츮Ÿ3vÑ0ŠVyî–ê®@g5ÐÔWÀÅ)Ñlx2ü öÆ ¡ÍC¾n~°_¤ÇgE‚(DئŒÀž«û­” |ª¾_sµ€_*&pÆù(|˜nxΪ¿Æ_OÃN-¬£ã1Õ£‚N¡D¹€_çE¨zÛu‚O‘¶¶ÄÝÃÜD­|‚°TM¸^]i‰ Gy¦S¸š$ðq B ”ÄÄY´ÞùþÂP#”A'`D·,G¤ËrN¤ÆFtëžC“\ø hâ-•<çtIÜÝP¯ðÿ £qüš’ÈH‹rꥺ‡â(E£’ÜƒŠ€¼r}»Iœý‹¶r¶å|B¿ÀÕÈ pºÕK¡¸tí–TCFaÿ¢™Ów Ü*ó[‰ƒ”7lË»ùF9‰Ÿ¦üâD) ¿8‘ ¤¿™ç¡á‹¡± ò{ëÇlOá(xÑÔ™½`äÐëõ«R63zÐ$üêOý(`ã«§yô†8s—œ;Ä/ø÷Û\ÜÕõˆ ç½€.R7(ΔÿÉO(øyVàu©¨CØs|†È™&ÓbMrC)°³·Œ¶@žŠÊ¸À-ì2õI™³Ä ™rÜs²õHDXÆÎã2 ‹KŸlžªÙÔb¨ñsªFòw‰ ÇÀ;?X?¾÷iÎ-BíY@NŠ€§:s t:+}qM—ð+ߘÌÄ]ŠãˆNÆ[A±.˜½©PŸòKøÔ¿xš^¹2›ü&žÏšÖÞüÆ n~™Køâ'ßç32%Ax³ûâ7.jߩΩUý; úsÇØ«îÑDëd)€LQdùL>z>ÚöÞO&Dj+§º¾¹>ÍWý×<æ,¡#ö›Ž®ÉÖû(ó“ŒÊ¦ýH3öLùaEà™lnþ¸£ÙK÷έž¢ðv¯+hÒ¥ø'KR®E Jü¯sôLÌžã‘-—äãx¼ìD#àš=Ì'{[ç@È& [òxÃÿFÄT– z…¡§#b|˜° £2)“¢p‘ÚVXˆ!’gWÓF¼w ¢ºÕ‹¢ˆ}G? •& ¾C(~(|‡ ~E<‘$Ñf-ÜÈïÆ—õ[‚Oñ¸%dHI°%„‚¶ $„x¢ˆG?zâ·š¨`òÅ»f³M,ScÈž RãWÂ{‡•:³#Ï峄¶ÓRÄ_~BѾn!¤0¾ë-K°f'zötoÜÕø… LÐÉ…ÃV­ÞÅ1:CÀ¾H=fþóf-¢Œ­¦Ç%,+è: 7ò0ªÇ¸,çðÅÌûÓMkküAü< 7ÑásÏÆ>¿Ë[!IG®Z!4m†ñ,?ÊÐ_a{åO§þ6o;\@Â^Âxž’Få…/Š›n$Ó~GFm|GÈm,Ì´­ªKÔê} tK­ ÀVo[H $• ‹Bßx»TšäËÈ4Ÿ/Ç&ù†92á‡Üæ‘„&ú™êCæ¤,TÈ´R4¡B//Щ IZò,p šVˆÔñ(§¡Ÿ1|>–Eb:Aöè™Â1»€¦Iô¸c“Á øÓ‹€Ñ b.Jìs{ÓNÅ ,¾"®—%,;Da ø‚U^¡ ÅYÀóÿ°7ôÊwŽ*Âè†ÎÇ|µ}ÑÄC§A¾I¯¿'?‡ñ{!"¿>@ó³äd£KQ‹øî -°¢Ž\š ÉÆ)½ ÓL^Ît±í”±0 •- [ë Ã¥Cþý§þÛ×ß\õ"å.­¾ 8µt!a“Ïy“ ÈúÌR¿@ßì–…7n\Ï2‡+cÍ–ˆßXVJ[ÙX=àÆ”k!ùkPÊ”þ[£µäA»ã‹#ØK)Üþ¦^W; QE¯Üü h Gû6ºnïσlž°šýaÿ¢c©ÂÑžMˆøN¹Œ¯Ž>-Äå²øþz³£.Öû,|šO§5Uxû~)hÏN#‡ß3¯6kÄiľÏbÿ°ìÓÔßèC¦C¿cÏñ ïd*p)(d d‚2¾;6›úI+ï;–²l+ëÅ#™ n¬”|ôño}E¬±™„_ß< œßºý€ßOR ðm*$äeÔXèѸ®l½F¢ƒ¥ø¢õõÇXà;«:‘äÔ“Óù³¨‰x@},$lWÕâa߆£;?FýgáE¤|‰áüa7ØaÄzQ(E‚þ»Ÿ’/Q.ã&"–q3‰âDdjýõfÛÕ«XRø5|áXã¿­ñèbʉƒ‡SÉú={žžFõ2HG½?#Šï¿«¾ žÛÍKÓ¼å@š_27Òm‘äÔVô a§ñô¥†/ Ÿß‡–vÌmø‰ù›—½šK9>ÁT†'1™þˆfK62ÓiÀØN:ÇÁ§bîZAã§G,¡iHN–èÙeì¿Â쉂Ào)ƒ&Å£ŠNøˆ¢Âï°Â'›'¢-ë¿°-ngÞCàn¥¢ ’|Àî Â×. è{ô2¨y“Tk’]yF6Õ+tª _  ™ö¯ñày–ý¸÷'øŒŸ›cÂWHõ¼@~ÓиØ›YÅ(ëÃÖ6gBßÌ)ÆÝj‘„ûG¢o™À(xµFÁ{ö¯žXðý“°x|6 ø‰2XâéÔŸ¥5”ç¬KÏünÁ¶]ߢ$ᯧ,m¼ šœÙ61$üvÒðvV"0Ýêß—²„(b“ù œªë[EÂf> "ú_átøÉ˜F5ˆ^óP上¦£ðy6Í?ÇMÆž7? …TRW~G„ê¢"¢FëéHg—“ïñ\ÎÇôÛxë¤ç¯¬$íÊcÂ’°1{ £m ^´½S¤Ö¬/pþ`¿.; o¦jSÑfè&-m­Co'Þ¤ùDÑì}Y–6<­k%„îÝŸÁ‰'äë·û÷7ß¾*Ä=i¢xþõµž qEÆ8íDÑÚ%5¹®HÈÂi;Ohæ^øR£ü¾4]¬ùi˜¥ wˆ,ÅíLÒÅ{£\Ä·™ˆnuàlãªêDàBU˜ âèÛLSD›¸-)_cÑ ’ÆVXén˜~©² zmï D&Ö¢êÒµñ>P‘­Mv¸W$Ô9F¬Ñ•œ-n,ݹ”pË¢IöTg.b.䪠L\õúKh /~‹êÚ"!oS‘QOÕZŠ*¸½¨Dð«ïlÆ"¢{D.€k´é¯q,œ¾Ôbê¾ØR¾nµÁ’§æ=™¹þ‹\®QˆÉ’8ÚôâYKô·Gd9µ&?®˜×a\I;¯­è’N$æhëb† ßÌŒ6Žj!q‡†òZÌO‚'|²%î¯?~Oð‹ŸFlÁ¡üQ0å¹­ùlá@E™Âó,aiú… ÒªÈ %–°ê$W$Ï~𤄰~¥·± µ"ó‰ùbË ÿÆ"–„A¾—‰æ(o*M_É2Š ÌA)*"…ó†vC!o~DŒd>–‰¤šo8Ÿ-Ú}ÄÉvzŠŒ'6Eo“ƒþê§ø[R_ùè$G9îuH3»×sØ[©8ÆgñÏs~*Šâä5úß‚#„œ~CÆK ˜¨ !¯4Ó/òÌH€—¦( ø_IH€ü=œý:õ£ï¢¾ÿ˜Œfbßy ?«™)„M°!¤~«ià#rCŒà¶™nº|ðßæ4r:.ò/3LØcøF+£. [FM*?¶ˆ¿Ÿ§·>õ{p!µL ¨{¥¸_nåÜb¾K!b;ñQÆVS\ ?x›ùÕ\DŽâ5üoD~’MQYÈ×ø4bRJ1¹A]Cµ‡Àï]‘³HGÛÉ O¬·‹Ô“DØfö—ºcÏ~7?¢ßýtµêÐX1»/:(n¨nne9£MM>:¶œ•é²Mp‡y†Õ”œ¢ªçZSw®LŒ¹^íDŒªÍbê• ²¤øû|¶ZdÿK,HwèOÏ 9„è¦$º3´TÛ€]ʧ0IO`äÂD%½,Z°ëÚ‡,…¡·*ª‚×´lG½(‰[Åf©ò ‚¹iøo“Ku1mß½qß‚ãsCï…îZ¼0ô3‘~]•µ®åükgŒ"º!~¦E_)§ÝÑDÝDKþ~ž’ ùÆ_…\È(ó µy!aÓ9…,bÙ«(¨!S¼m–ÈäT B7Ò+'®*§¦d Q¿ŒNäXäò]»Ö?ÎV¹Cmûp£ÅŠÄù&ùb eWÌ++±¡Æ=% ÏŒNѸÖÀF2)VB®®?Þ$P× EE®DlPäc¿‡çŸbº‘‘„À»)¥–À_JMß d!4m)*2hZSTD oÈÐk¨Æ1ÑE·Lú)â§ÄM4Þ’€¢Ä7$Ô51åˆn$ôê¶*æëˆV­f/Dëö¢É ¡v_ ¨ÕïrÈ·äREo£M1ÔZž°Q½êIx ä?Ók°ªÂùÊÁÛ$–F¿3Š”œ’ ZM\ˆ éùº!„R/Pkâ¥j½²’C«‰Wb*”'·¨ÊLÉîK±ËæŒ'zËe/EZA'Y‰ô'\þsÑ+èDçІ°Ó¼Û tùBÐ)4z!Š\¯¯ÄœD»¯¤dg­¤R9BOø~'ÕÔvr!åÎ=…²|ì’$ê #Ÿ*.à–Ÿ³§øžôÜ”F½;ÿ<Ùøç ÏÀ?OtþyÚSðÏÓƒ¶rþyƒðÏ“ž„žæ(üóDg។‡áSrÍK$¡Ûü ÄÙ…”Eîx!lþ›JJÂ&\CÙw5ùêx’â<éC\âEçÇœ®¢¾ÜMäo,ûËO".jgi3š¬"z$x¿Í³Ùœf?3V°ŽÑ¿Ï:¯ü²b·`ù®Ä_òîDzkOãh<û‰‚1åÐÓÙ.D5f—@{;¡|wñ1„ìGa‰úãjt“~dæ/j7Éß¡oP˜Îžü&6ªHóŽ Ç³0šÐ‹í y‰ÿ¢3— ·^ãã)…ýJ$Œ[þ¡NôOâWšý«Ÿ†Á-Ÿš‘ÿÊ¢ 7"i°¹9ÿyq™#šöx?Ç1)¸ˆÄqõ‡^N±òvø¯¼:|â‡Óé² …è#ÌŸ6{¥âhì_ü[Vû2ç»ËŸŽ~ybIü)»øù!AæëÐ’0·ð/~òèUvI{Œ“Ç–j%öwúx‚·ÛóJˆÂ¢,‰§Ã0‡ÉÈ Sƒ¤ïñc–„q6ú1ú~òƒäûÿHÂé”(޳¯w]a½Âµ 5b4÷¯köâGþÄÇç÷*àùŽxð‰‚ƒ(täã<0ÍŸEšVÒÕÿú|Ë„'^ø¿ð]HäÕdOa<#Z´yÀÞŸR»@cñ3Ëø'=ù3"%Åe$ªhão1ÿ DŸ aŒÆ–Ì‘I^¹_–̲0 Ðw¿ÍÿËOøÂ¤þQ c4ó5ŒÇ"£6YDˆD± ¤ºãóKwîg²(¢+~C%mq%ä¦c~ü“˜SÛbH ¨²˜ƒ*ÐäGU½PÏå¦<šIýÁw-B»÷'þ4žPŒšC?øÑ+‰†ß,Fœð–ÑŒ8ü{îGÿ‹+HBïÕ½ÿÒõ÷l:ŸÐd7ß?ùT^OM»XFtÃùC¤0Å#Õ.W|ÂÇÜøø'á$ŒüE¸Š*é ·;„-?bSPÛRh“Yþ“6ÖðŸ!m ñ?Ãÿ¹dì;C"­tw3H¿ŸÜ x”á_ÔïnþˆØ¢öþ“+nºÁóF§¢>ò6Ol–L¾Æ[ ÇøöMçø™²ô,Æß˜rºñ 1¡çèÈÑ4Œ¾oö£GBŽƒï·áC²xÀOYö5Ýì†M<ãºz̾MÇ_S(VNöë<œŽŒÞüæÎЭÇ\Šh1·ìûÉv7kD“':±Çâ•BáRäo˜àk®¥ ü¿TÌ9ø)gÎ/5|Øì2N"„ôUêš–Pà bà+!zöc štè5Lð”ëôëÕf[jë üË}üETè„çФ7ïÖM+á9s Ä/²h[Aº 2bBKߢú†FÈ2ˆ5—°j4O%cÏjÞ¡ÍíJÀ<}ººö3ŸŸö þE¨ûîâ}ùü}Óù˜}JËñ­ŽÌX¾²WZüÖ°ÝÞ€ÿ4݈ øªêDlî>Qà†‡r6ïÍøßBf";„j$œà“¬Äl~¾½—¢F,#y“¡Ÿ=}sSwô_ãxÊüH°ÉR¤Íä2®ü4[ȹ‹\&z94NØ•±ùW¿éOÜJÎ &î$/Cÿ&ù;œ`,ä¿NOÿ:K9ÄK€þEN𠔟œ…SŽM«øŸgb'Òœ\yÙgÂÏF!!œ¢_ÉÊØãÁ ¾#mK@í^@±J IQàg´ ‰ß>ü0JÉ…ð+?¯üàiÓ¼·’_ÊxaIFªš ”º©@©œâyD¼¢²·¬fÛ¿à|ç¼aÈõüy&d Þf4b%åÛñßÁËE7ỦðiFdc/ÀGq’á³A,D¼ž@ƒÿžûSJü$©®~$XªCM“í¦%8KS*­#D &ò¿ðÖ+ sá.]J¹céFƒ4YŸüiÊHµô§i\tº¡“;O uôï,*þâîN»ÑUá&à‹ÞV¤b±Loãø;~öXˆj{I4!¿ûéÈft·›1鎾‰Bšœ7-MáÈÓ›|wüÕGg©^" _ÛüdÝþÖ'vQÜú)íEã–ùcªkқм½*⢤sô%¦ q|Yö®£ÿú±~gAÊÀ7_?!/³ þ¸»!ý°_Ù+¥«CÄ¥ ½õaoLxnßâwvY‚SZ…kx2£‹ 7Ú¸Ú”+žÍX:¢€·ìc°4‹in/eß’›ÒØ'¹ªD®•„<©› ]°á±HtÒ=âoñ)žNcŠž~ÛFáÔRYfÝJ×RÉkø„ŒÌ„¬H þtk–ŸE”†v ŸÐØ^œ¨ÇÔð_‰,á•€?¢ð¿ñ“—ËB–ARy vJ ×ø¥SeøÜwG:E_X2!¡;ö¿Jš ÿ^´¯¥ÔJK¤jiQIF{UŒ3êhAû )¡ïwÁG9þÂÏЫf ødÌ’ë8Yü•lýb£’9Lò‹èvUÚÔødèñŒÒ #JKÞDwn¢ /ǧtexº\ŽNè`ÆiÎvHªîØ$Lù÷ý8.åÐèç¥ !…\¡ª.‹! Ò-EYwKøœç(rSÈ ¾ÈRñWay„3½*—ø¿ÌFÎrîhÅQÔÉÀóˆ6î<Êü$Kÿ ×az"1â4i>„§V!äïqË¢ õ„Íï‚è3“±y¾õ+{ŒÚÛØJ±”gR|ÒÛ÷ nÞ\D”NýŒö[ß'sZùöû4 g£pB%Ü„¨Š 2 þJüeD[à“ÞÕ„ÊËšÀ'œ–$Ô,ù8~ñ£ OªÃ€Ë ¸ò Iô=Kh2¸ Ü;?š0Â,è,~o‘¹TÐz’LP ž$^S‘@ˆ¨!‰ET$ *2¨âY’gM§þ,eã| “ !JwÉÑKSE¦§ëXß¹Ê/‘c‹ÁSå¦W¥ ã" *„ô;äo@Aé¹%„ä5røû˜ÎÎa¿<™Žð÷ë§iøðï_Òøí}AKòä¥üä¹¹áùþß|䞀[„X,M?bj~òÃ(ÜB;f–òÂ<ójšû%v¼ªnÙGf‰çOó+Ê9Üãtž>y‚ïq9šÈdcì1fþtúÎOYbOŸ´à‹åù!ŒÊëÊÁòJD8 ~ÎSœÙ’2×ùã¸3=fÂÅ@œ¤¢ˆÄƒAÑŒ!JªtŽ2ôEÓR8L>Wtû/.óŽ¥,£ˆ»X˜[ ~ÿþíwæE q·ÜÏ«ÛÀu¶„ä»zö# 'OÛ‡ÏÏ–q ð„qc% øañ0ìïÉ¿ƒ)ó–$•å˜D§ !Ã$¿’à|ŽÏX`ñ#èqáyƒä¦€¯–ø<@+Mþ ý³„ß‹@ß`6‡Í4 ×S°ç_CÈi7ùwÊØwØóÙ xKÐt À~ŠäÚX"fEzä<‚_úÿ=€ÙQÿö¸!öœN¶'Þí…øÓ¼MÆý;xÌ iQ°¦áÂÿmÁÜŒs\ Ü?Y"¤Žsæþß=T¼¼?ýWq”f¢7s#—îOÞo_ÿðFßþ¸»äü¤ýtèòn‡¶Ùü_{¿ÞüöÛ`tï}¼½ùíë—Á×{Ï[ÿ /7îÍÜ7›~ÞÅÓë ë[2’÷}Z90Û¬ùzšu}ÝüùÍÏ×ðèZ<[ù~\É=»kÿ ×”z‡ÍOi¸·êâñ’ t Ùö©$ì€ûõæÚû$ïåŽçÅã¥Oª7}Ðü)Þcpÿû·ëÕÃÍžÞ ®>Þ®%F:¸ý$õfƒ¿¯Ãû›o_GåæÑ€¯¶ûß½o_oW†R¯Ñ÷÷56§ö‹ÙÓô¾kÚìgÓj´Us õi´ÅÄ3››û­¯÷úz¿Ç~v ®ù¨ßþHótùèQæéòáãÌSñô¦Nkf&On™§ ªå³eëT—zr)Ž/.ÝÕ S¥não\k”6³I—WmRÝ’zx½@Ë웆ÅMÑæ£¿ûx}ó·”Âùíꊯ‘?Þõ_ï>éÞÕ§ïãè‹Ä:Y!Œþóë•wõíËðãÝÀûøõÚýõqèixP:”ŒÃà”+õõ«ÜÇqóõöæë@j?æÏò%òínugoüØðãýÕï·ƒ?·RÆeþìÝïÞÝàvðq4³lò‡%Gú›Üÿí}üõÆûsp7â§Ùò.Ûk¶ðùÃw÷÷72_€?ò×àãg©Ïvóõ^h¥²•¦ë†Á¯™†íZ¦ãXnÏitÉX •FÓ8š4uñÇË£Ð5Ó1]Ã6­„Ûz¯‘ñ‹mZZ¿ošëêÐîé–ÁOó¾¥5z§ÛMçQ#U[ã=Ò~鹦ÞÓ5G7]ËꙦÁ­ ö³Öo>#é[éæEº­s#ÙöÏm½ÉìvÐm'Éæ7©‡×žÛw ¯ÃrtCsl«§³ÿ!ÓüÖÞ¡™Wè¶Þ©ÄßHòùÕæ0l]ëñw24[›†Õ³uaê6~¥o_+~: =š£!¨!án—Z¡_¾ü-õï¿~;æxÞß]ß|út´zåÎôòŠÔiÆÑïwU»SwìfÞüïÁ·OÞõ·?~½]¸‘ú[<ùéöÛúJÛhÓ-¼ùzÔcùª·™%P~>ÿ鈗=ö¹á7þ¶ƒ»£]®¨cýþínõ`#uº|ÿç8‘å+ø¨Oû—XòOno6ÙÖh4Ð Ÿ‚Ì^ÏŸ’|à()rÿþþš_¾î×òÏÉ<ðÇ.KPvö†óãÿ11q>è=~Zšñáÿ½ãP¿ûÙ‡üÏùIøÿý?MPÿÚÔ¤r¦æb—Þ­áÛ‹NõŸÇR‘äüßK}¹`6§âÿÏL¢¹7 £ù›”¤ï2×Òï®v>Ù/%a…2Ä?—ÂsmOêSHÈ›£òûîý·[ åTŽŸò}Z‘öS‘w0ýâ§±ÿ¾ýò4›åÿr_*MñO½Çpʼ0zŒWíK/?”ý˜±tõÔ¾¢¼ÅSOqü}ý€Ùðïñu¼zÈjúPø<›®žÚWE·xŠ+Q>¶zd_ö×â‘i<™°dõÄ>êÇÅQ,ÎVOô?‘Þ< §ëYÛ™æS]Q¢ÍÜŸɰ?]ýÿQ]M·áCâ'?dñ/riµÿ¦²0{¿X¿T]å? Œ‘ =o’ôÓu.'‘ý›©ø—ÿø‡ÈHýÒÌbùÌ–ù|ß~—}îŽý÷œ¥™HÓ:â±agüû6ʨ^>:jTJ±þ×·yŸÉ‰ì‹2?›§W’Oå¤@¬Q’Ÿ8ßÞü‡ðEkøÏÅqÈiô¯Ó¬Q±øwÿøG–hûwʇÍÍ2úÎ*úuû¯7Wùö¿ýx~ˆ§òã~òþ÷W+ŸdÍzʲ™(þ½Iÿäkv<›¼h¡¿D¸ó?_yÞ}¥#Í¿Ž<­—ÿEž°9„7çÚôF€ä¿±h\ÌÔ`àLX&Úq †£†yÔr°/Gc:âWw,`á Ãí^äãì° 5Âo,Àñ~èã‡Ü/ãÆi†9æØ=MïFñÝç¾ñGj†Õ „Öoû|ËßpÛ©Éѧõ¬~¿‰z¨’Àª8Tt)Ñæª}1¼¼¯Øb(fÓUxx [püX–¤%?~`7h‚y’°(`¿ù™:Å 4ÊSÌt¸îü)†èÖ Kêùû§$~•ß0—!ÍuAšJ:s‰"ùÈ–³Õ&ù#å\£©ä£ý8*ùèðSG«gÓ1å,„ ÏXâó«ùÿD¼gô-骲–vf-i8YKmŸ¦}˜Ý¯röä:i*×i¦röã¨\§Ou/×IÔPç›ë„ãwïiB¿~»þÏsOu:´#l.ÂL'œÔ6»œôÌ2ÿRrœÄ» ~|PHO:» =AI.y`O‚’òL”ÑT‚Ò~œ³ñLœG†R匴z ˜ÄÊOÓ;&tÝ‘Ïý˜ä14Q×%mH•t¬m7èÉPyíþÊf üì?2<|eáΧpÊD4ü&ÊXòÈOt•u±D#Tò}G;¿û×ÖR96þ„¨w\ÙÌ •rµ7åJÖ'ª6S@•r…™r¥KßÊ+6CO*áéø0HÍ…®ÄÚ%sœÁPöÈ\D·u…¦}#Áž%úFJÖ{ÿ$¸¬XÀí$éño,¥ÒÐò¦øÝ…œ!¶aÈ,¦³Ï›’Ê<7Õ¯æM=$±?üT%Om£QžG¶pSuþøãÔ‡¶m]ó\¦.oýw'ø´ÅÚR/ç¿>^îÎ=ü_¼â ±Žˆm& ºYš Î_o1¶KI(¿âb° õ­õÜ~{|'‚g°ö 7ÿ…éÍ‘„+}p÷uä--qn¡ñ߬ºÊL#¾ð[šÑWvZm=Ýn‚Óo/C:¯qßÌôfslœZ }ˆxH9š<9›ÊÆèf6† È.ÐT6F׳1LMö¢¤b²x1Y9EÑ혬iʦ]×|ÔJ³«£¾!ÆÎ«öÈÐôÀŸó)?œ¾\[ƒðn$£¿vñ Hmð±€t*”)GF=ØúLxÃÑJ9Øì88ÖbGº¡ž¼åìëy6›K»êK»æ4fÀ©ÿqÔÁ+ñ}**SjÏm(ʲÀÓ”Žâßutíˆ ÈóÍ^q€†z9{Å®f¯Ì£i|W©+[h”ž,ÇµÏ •R¥®ºÊekKóþ ¦®`páplpA»ïPõX2[¾®º+ÑܾÜVAæ†ßhK|â4K”µâ ¶DÅ¥ZF#M¤4zgH¹6_,ÄïÂʦ5­/Y玶óEØ¥7 ¹ä²Ÿï0‰ga4^¤³íޙִæU»z· ‡§Š¢–ÑJQTùÌØ˜*–º­Û½;ŽžléøåªÉæ—|ä”qÉœ†ÃÆá„i?À:)H×8PÔ)È]UÔ)XÁ4Ž˜2á 4Jö•³È )û“,K’lÓ--VâÞíkò’ÝI¨F¹u÷‹LäÑèöÜ“©ù+à- «gË/ ÂLj”tVÃ(gĉKèo¦YM<~-½””êÚ—Ã\¨i·4Ùª{JÔ†b.WÔŒÚþÎÒ PxRå˯óå5•/¿MåËÀQùò‡Ñ}Ê—ÇÏ—·tdx>§¶’Þ1-bÍʼnZ”¢"`ñy”汉uã6Sü4éª ?G#Q¸=p_¬‹=¹òk nQ¾hJ{9§•ÝìTV„9ÿÜE˜£)œƒhŠ0çŽ"Ìi4 E˜sÔ‹NƒP„9ÿ¤!Ìq4XͶãôäN[,£tþ”yЍ×>Öèýˆ£Ì.†b 0“öîÝñykyäòÛv 9® ¢|° ½K{ Ø, ãèX!Vx”õWC€º{—îð†8®%ߣP±xÉ> ‹WO±x­Å—W”HkÜ6 9muk˜ªTZãýêZ|Hbø) ]ÝøÙ®ö>,ÛV– Š„Í ¨%ëÙœ4kÊ¿ð§$~Å¡Vp3tOÛÔ£ú™]k¯¡ën&ÁŽ5ó³'o¦éžØJ»‘wÈå„;õ3®_ãä‚fü |Nï°ôæè ´-#fãLCtXõõ÷¯ïO &ép;D¨ü;å±nñGÜú0E$NÙ¨cZÜkl¤È5½FÏ<‡5¢+{Oûº= Ö”G=n=*²&I4EôxGÑ-4F×/~Šè±GÝù=0HˆÝž #zTDMµDMÊrDSDMp”åÐpÝ·QÓ޲=IO¤!jr{¬¬Át%¹sºf;à8|5M MQ<‰FÚÓÌiQ·*Ëá¨Êrا,‡=hÊr¨úÖ¦ÝL9S; ŽU‚Ç–S]Í_'Ý¡…D!àÓ´‚Tqømtó÷¹3Cæ/¨Gôž ó]*nÈ&Oâ†Tý,hŠ’šÒÕù-OHu†sÿ¯P%Ï—DuV¼ êU1*ª³‚ê XòÕª3×0ammÙi¤¼t;rFÕŽjþÇßo„s°/~µ´áã4¼±`0p&,»ç'‰:¦ 4ÂcZ×_çéJ6¹ãÈ©• U°X\Pò^HU›š¥I¶‹¼0½'ç†ÙeþÔi-(X $¢bX°¦=·/g…`òy‰ À¡å¢|t‡ÿ,*PjÃ]N­R L`ˆï™\•õUÄ«‚VŠx©X×&]a¥¬ zd©¬Ò±Úc—íz¸«‹ùÌ'÷W-%DKÁÔí‹÷š[S|ÜÛhŠûŽâãnðLi"óq»æwùmg뿦^ø<›¶p9îã\“Ä;üƲ›¯£ÌÈÍ}œGà»ùô"îM•rÅœž†ÿ?³_˜Ðÿ7£Ìœù!ÿo:J#ÿfÔ÷ƒp ~Ü}¾÷€+.Ê·a*©MÁñ†w Ž‘/ =Í<ÝP‰#i®dQî†fY,þÿX´<[:vÇ&î?åH·à‹mÕ•ÊÎ×~î#¿wóÇš(rù«+4xP¢±0; ÖXaíô—yŠ ƒké rßi)ÿÓ ãìÈÛ˜$»N ®f>øixa\Œäæ•ÿ™<ù‰—%~˜¥7¯ƒt•UE´W²eN* ¬'Õ-py¯±£8ˆg?Žï€jȬòíå¢i_ãèŠÀ(üüŸGR}O/½g)Êu½œ`nyt.´céLÊ UV²ÃÁ.òn¥Ã$|ᦋ´ÙÐå݋֪ÔuŽàWM Êgpµ©l×…55p]D_a;v;¦Üb=å“xürÒtxWeV ”7ÜZl‘¡ýµdÃÔú–\"ÖZZÌG¯#®–ú«QÐ^ Z_%}ÙVË5–yjxó,œÊ–UJÏA¶yá"ÐG†Ö{boÜ`7úÁðó“Ì}«Ö üŒ¤®<—nåE=ªýéós.ÔÌ~d õB¥»&°µ!¹©(ÛØr¶¯ôšµß×d÷f® 'Q,ߢb$ATå4½ÅwŸKµ2‘²‹WoòNºzÄÒ®³zÐ öe*8oޫܠùY§Un–ÔÅS¹Å3–øÜÐþÿÀSn¬©³ê§'úéëÐνŸ_Dª×Xs”sê5†ÚTï2zõ-­µ-G×ä>ý%¬v¨[§´ÚíꂜGÓ8øNÑV¯Œ|¶ëÜy¥;ÑSª)õÔ|YöÔSmõv¢©¶zûqèÛê%á‹÷ýÀ­FRmõ6Ñj¦þ²ºv½ìòºJÛ›;pËä¡§ŽÍGìf8ø‚WƒÒ·\ù»ÊEu3Ô»jY\êe¨Z®ÐT+Ã8çÓÊÐ8ƒšçŠ[=2@ÿ–ö4¦îíËS{a“­i6 9×4ÄcLT™Ý.4ô$nò‚•&Bòüx"¡H„Xdé˜ò¹‹XìgZß”S•X®uH¸lê@ïúÂCj “xöFK¢}(õÙœAµ]ß±`)Õ%¨¦Kê/(‰¦ºÀQ]‚£ë¾sÕ%¨Gùo=°8HºõT*¨Ù¦dŸ‹ŽÙ †‹Ó!H¸ª»à‘h¤dáf_ùªhÊn8ˆ£ì†ÃPvƒôÓÛ ¥ƒ Ón€u%6DW1PÜv¡¹ ±‡JìayÌk=&ÿçS–çÛ©£ýíÑn¶©ûº~²ç¿êZ†Ñ‰cr¬5I/ÅnÆT›.¨’jʺ»)+°¤SMYû®&O騙¦¬’ »¾o¯ègúûýýðÜ{²Šw@Ô"}[~uögD©aеrGÃçïã0¹¤«Â\ˆJGºKcîºÃÐ0°œ!XûyÍ2П°l”%a4Qmû 4JOœaÚgÐ]·¬r› VË m×뽞ÙZ1³jÁ×èI©|À²Îº|í¯|…Z ÂLÑeRŽp¯û=cÝòwJ˜j[‡FzöX8Eÿ´gÏe´ŒÚ@þ²‚u^ÙŽ¤›ù"Î+~3@9¯j”fÇØÓ2‚݇TÃØuÃØºÌGÕ0v?šj{çLz@©ô…M4Õ0öŽj{è)€Ñ€Ý0Vïq} w ·Ûú§í«Ö/qÍ9.zû×jïCÑ QfvûìÃèx±v†Ø*ȹ©¢wcçÕ1^NÅZÙ¨v“Gþh»Ý¤8<¢Ïíž.ŠƒD¾o°ê \ÅyG§â‰Õ´aÛ Ü…]G,_°š^¾Þ¨iÆœ®º~P¢+00=ñ2º‹U ê ¬éº+·,1}ôxIsRÙa©”°hþÚ“»b¿[€€îÍí[]ð%·è€Û1ŽÓ}ÓkÛa¹Ø”ˆ>KÝ窟úþ~êÀó¹SýÔùb9ÂÁ] …÷%çýRVË­‡f7‚e€øTëÞRëÞöÚ@w¡u/_K¶ R*ªuïžÖ½XçOÛ«„o9˜Æ‘íØ†P•nÖT2ŸËÝÚÌ×'?S)ÁeJ°éœ[J0°Q,,9¯mWš=éùA.«UTS3@zÉišš¡öï;ÿ¦f|ò·|¤uîêÚûkU)y½Ù·ÎÍêj¤jÝwkÜÝ#¤÷aÕ-côûºý?×7üsžüôŠ%Êl\ ÑšÎ™U1kzÄ¥¿X\x¾lM—UÕª.]æœS –@=Æ2¢×_ª²¨Ö ä{b’ÇÉV3™%Ž †ô1px =ù*aüö38ÝLAFûGþƲ!ŸìcK£Tj×.´nhžVÛ}9Ù¦6¯,UD¥.i¨¸ýzR:ÕQ£D¢8ˆg?$õH… ¤Ü5ík]ñøEéåç‘L|×#mzÔ=mÕi\m ‘á±ÙHÉTó<“²ëÑʆ2”,÷(½*ñm~&ዟIû65ji÷6}áÃÚÔ„]’5·'I¢‚—(‡ÁÀ"Ù0q§a&2ð¯üà‰ÝÇßYt%K_ð *®žGoRm2ST ¢YdÂîºF{vÌ(r`FQ±ûùÏB»n6ÕÖQR(«‰ÎjÒMh¸ôBÍ&x±*ûÄѳŒÃ=Afœâ0OTÍ{Щ¦6PëòŠ…2D43m!¹fvKõ8ýŸš@TJ=·û?RÕù©²NÃíY†ªÓ¨ ©ÎOqÎ…Ê£ÇÑ“ÝuÞ$Õùiq¥Åîü$,†öø±uDs˜k?óažcÀ®¯°ÿ£\ µÞèêÛpà}º¹œ¸þ‘,nýˆºÝ6a± C¸)Z‰M´ÛÐYªl·gãŽÍ¦aà«Ne4Ò tp‰I§ pÜ鎓ו¡[º~}š6íbS"jY§'ï† ëtbH’µíÐ]º^œñ…ÝÇým–z\µKfü¡ž°’ØÖ—¯#Ì… «jŒªÔðæY8•õ&UùîRúÈЬԸŸ?Ó_X’±dp7’Ñ×µÿÿI]õ:x¯B-³LŒO1jE«æ•ò‰oU–ŒÝ¼å©.Q¼‹•£hÕ ~8Ê[η2C›¥V/Ô‡HÖq& v6E’£‘æè˜ö™‘dšrW¬mg 2›šsDUJ%ϤÐéÂU¹Ì̈råÕz¢™ç}ÞfC‘ÿ,ÑHw¾eœÁÎ߬”\-ÌìÊ÷àª+³žåïEtoÕ¤8‡v* S,‡‘ØÛ¿Z±ã4¼±`0€Ö™Iõn²ÎZk¡Yšñ×™ÞCYgµË Ú£òȺ\ÄÚo¯dœkB9;è"V¨ÖGñºiny9%,_ À¢ñmÄÖ×§ ´µ §­^éþË,NÃ7È¥ZÆå?ÅHÀ5Ø ÄóÑíËÛaÛnŒ'¾lS/|žM[ØÎ6R·pñ×ì‘ãró&3²DsçQ ÚÎÝ|z5N"«œ¹j ~ä—+ƒÛ0ÿó{¹è¡b¶ß…†É#X¹ˆõ4 »ØØ£ØÈ÷^Û>³n‚°ô¿µ*ùE e}¨X4ºâŸRîá{m“—×ÊÎ×~î#¿wóÇýž|P¡cG£‹rsÄ;üƲÇâÑpÍQ¹, Έ²zdªãòòËëoË´A)~‹5¿­¿ïæÑ«ïÅÛ]‚ö6!×VÛ–¼µ¢y$ûÁïºÖ8ŸÂ)»‰ã›(cÉ#W›"Ô{Ï÷¶ øh„Ÿ¾£A¼g8OØqŒƒ•±ãÈ­Øí(±X•ˆ¾>¬l[Óu·%únÔ$C ‰+®DäRôáRIÒe’´íÂÛÅ\¬£žŠ·á¥€W„ž<:¿Þ”˜šÓÕjk½~¿*b~™L×2Gºû%G½Ý‰v P>øixa|Ä{tÝ%VÚŽd y„ÄÊiøSæ K7Ky:öÐÔ%sÞ¶“+G™író:°Æ±¦ƒìU˜ˆLœQÝ©S*¹m=Ýž'¥Rvà•f[Óµöºˆà³ŸÁ«°«³í†³ô~÷ ”ag,ÈØvŸÌ)#'i®r[?@û¶|#w¤ìW—"jÀ3‚8 æI¢€Iž¿ÉÀˆGßó&ÑÜ ÞÞt“ïßõ›xÜ®øî1ahCm¼]¸rå§$~•Ÿ)‚5nô¤»xâ—ÂhRÓ>Œ«œ)'¬E#³UA«]hÊÚyßÉ»d Å40*šÏùbè=i¦YÕÜ|K‘o67—MÌ}úV57ÏGMÕÜöŽê3ÐpÝï3 ÚÇnᨛá§€Fz£C×Zóªö±ÍžlÜ>è$¼ˆö±†®·Wæ¯ÚÇ6z²aûX`aëñíc»´˜Ûã0]».v³ÑÇÑΚx%¤NÈ%()’%iJ_=U?Ãý UdI4ÕÏðŽò34F÷ý ¡T~é—ÑÏëTX`¢ïØ-u@²°zYüÆTäcÑ(­«ßêÊj8ˆ©¬†=hÊjØ‹£¬†CO¬†õ¹„i5X þDÒ]±HÖš'kr¾·]DëëîÉ“­îÉ*;)G£´ 0jié·2fŠâÖ2ÃT6HH÷óÅRhm€¡õ;úO­C‹ÜR¥r4Zµ Í©óS «%†¨Œ#ÈD+~·„N8>b %ORï-©~D^ÄSÁ§¢;,ÑHzœ0vò[BÝrAÔ&°ŽAõ3môä¡~¦Šª§„¦ú™ÀQýL?P¹èýL ÓF pÇëgŠXÑ{åîŸbp—ÔÍtù>¨‹Ô£á\ûº8n9¦Ó4Ñ¥na)‹¹@SMË: / ݺ— që[†j…ˆÊ/µBT¥Â 4Õ ñ­ Ë”¿'«Vˆ +ö‰Z!"4k›Àʰ,ù s¬Õé’Lju֭Κ>u]ëÓÉ—™¼£º ‚–aDÄ6Ýè‚hX6¨ÐF„ R/o);(Q¦µZqŠÏ°ð…£ To‰*¥íhÆ™¥³`µˆh_È÷–A:¬ô^O²¯Ñ…Vr®—Ýp¶t†TÄ4ŠP†X+í50y §¬n°(§œÃáq÷&c‰Ï§C¥Q,ÑHÓ(ÌÞô ÝÐË%‚¹ñ]XêDÏ•¬›o}ã—‚:¨XÔe©ô‡%eúƒ¥`rz•þ°°bý»ç§*›QSÚ( ]3É>hæ´ÿ2‹Óð  )q¸/\þóPŒLñ³ÀiýzfÁG_1›µÖ”¡-£K4P(,P«ÍÊþ]¢ÑÚ¿Ö“ðÅÏŽ¸¥Õ\ÅÚÂ<ލQìXÏvIž¯ â%®Ù#ÇÅêÛþRmÚ.Ú¸Ÿ6#ïè”6n¿X£üI2¾¾°¢¿í3sÉër±æ ¾Ö1ÿ±«“ü?¥ðïá[m——Ê®·~ì#¿vóÇœ˜6¨I¶mKÞŸÐãšH祳¬†º‰2–ˆî¡î„eWÓ8RÁÌ¡åÛw´3ÈÎvmYåZŽ RºËe‰i6;0³®»-€Úì‰0¶Ä×å” y¦šÝÀQÍî#ê=xt2íæî--L¼ëÊVBÕìÜÔðæY8•í•RvÔÊÐ+í$šŠj„ûÄR¡éXRê³xWwI{€nïüc$u)¾ô-. YÃÈŸzódŠ{ÚB{Ú]èà.â@‹ÌºsíCp¯§Ú¯Ù4|3ï!XšpÓСތSžb’là[çØ†ŠF;̬^¯5Ú%Í09¢a¬:qHÇcx1¢ÙC)#Ö ¾±XƇ3”°vd"…ÌS1ÿ;rú…ÕÓÚãUåfa;¬¿í.f©6@¯´\ÊPŽß5ÔÙ.ä™[MIJþ YÈŽVÖWõr!yðJPR0$KRÕ4j}Çn©ód]•£PÚðh½uéÍèúÞ=Š{w©^J&2ª²÷›–ëÌ{ð¦ä›½¿è÷œQ •^pþþ—ðJù,iï^”Ë&ÊÕ‘Á1S*Ä|éNêÇ'?Oqx†-˜»PõEÙK²¿­^‘J`Š__%lÌÿ*ô§Ê­‘£ª Ë‚S’\®Wcz_ ¸…ÛšÛ&XaáÖ^GÔ³Z_ÞÖÂê ¤Ù’×»ÐÅ+WÎ:ÝEr½¢þãj_ï-·lÖœ÷3$tÅ–£Q:·í¾Õž¯µëÇB±pÕÕz4`Z|¹C¥öb©DSçƒ:tñÇûGð½ÞÖ4”&?õºZõo_¢‘† õÞXŽ;Gy¹ Z€z”w ‹|–÷¨ $[ãîºØëËÏ+þR5þ*£ÑÚkŠJp²ñ—Ëíã³U¼ùŸ *\[Þü"£ž6¤(ÑöúO,ø^ʧfX©¶+»ÐÞ{Vž_mcÉbnq5½d1 ÁrÓ'a‹]P?ÊDdh:yXI;—h”¶aÚgÐÇ¢Zí%™B_³DW0gA²8VMÀƒŸ†ÆÇsªëÐŽž£¬¿ÅM0Ê4-xò/Kü0ã0@ËUVèG« ®«µh‹f;½vê§Ú½¦K±¬í´oM‘â "-Z_üjŒÔKXø»dW7¢Õ)߇kuº†dïWµ:ëV§[^ [,Nh¹_'§#]Q€¨îõZ:Û]œ}9kg“ºbM,|aÅËa,È `V'̉nX¶œúCïH¨I1Õ5PEù¯F,C Ä•.OKPWºòJçºÎ™¹rLÇ‘K™Þ¾Òå±Ö5+ïúAK¨rµv*ËÛ=§ n§Å9µ¡° µåU4DWƒÙuoÖL[iwþËc8emäÜ¡,‡ÿ,‚BîMV0ñ«¬%iÖ†Ù;ƒFMÛ¹DP7¾(¬eÜwìv¨[^Æ&~n¹ŒcX H×HR($ RÖ™Œ—–âG“å긠¤fH%tv0j‡š<¿‚×¹’ Ú¥pÇOùÂb@]í—±ó“ jÉì÷õòç“Uhæ—B5#Æ3 ŸeúU£pÎìîW=JùH=šêT½‡®S5<õ¡3\]¯lTü ]íTíZ&ˆ«AºS5]ËiÏL5íR×Óe'àÛxFCþâ¯q2Î4UŸ¿@#<Ã, Þwôbϰ©X’êÛÄ¡£++6çfü´G™Ô¬®*¥FŸ"h¶+­$«.a÷]¶ËÕ4¶¢ú¶èª-X2;ÍÒ{í)𮟗øÙizÏ8ßV¹åŠª€eÉ4T¯ó3èu®©^çk4ÕëüŽêu~è).µ)z»v¿µÜ nêhG´þSº~Ÿ®B¹®×•®_£êz£gªb’ 4:]¯÷¬3 ç묮w¤IòT›õµYWÕ~%4ÕfýÎùøST›õ¥ ¾ò¤éѶìã󫓆ë[–©&úvþ›I²"*]Û°²ùõó+õ-/ÌÍDQD¥Ð×êµSØÐnK’‘zWã›MÃÀ‡–æ,`δ.Çq@¸%éGPúz¾ó$l1ès±†M›¦MXöGÊ¡ Ô R ‘rs˜6¸ûý R%é‘,ÞP1¥†xúÈ—@m¶V7ä¼”8}J§ˆdC¢Õq¢gê}â‡YŠÑ}µ@:ò0A\vkUǪ+z£'늎°B;°6Ûë¥nX¶Üu[­Íºµ¹Ñ¶š/L`aq¾0—˜Ó^v‹jˆÞäɦ Ñü!ÝjˆîºGDâËk«×k‹Œ_ÚÃ);ÛPºÃ^ ÷&c‰Ï§£Ÿk*:“£‘f»š½öúÛ½¿èŒ~Ž\ŒË]‰hô{òW òõ¸çöå\cˆýRµ¥è qÌRe"ô30˜ŸV%9h†Ó“;F7>Ï,NÃ7ˆï¢‡âwùÏC1[töÍÁpWO QÖïŽø?Ê}œªÊ¿”HÓ„C_ì!ˆÔ·c# ìd>z¾»^#yQ´ ]ï`,Ç•¶®Ü ½¯·7Ù8]%‡Åá§ŽUÉ4BÛ¶Õ CÓT“îV5ÕtÝ•3Õ­ððMLÇÖXZL¶#™e€5ʼG?`YzôZÒ ù<ʬ@XB7¯­7޽,žÏf,¼*oÁbo#"¶—ã-€ÓVœ‰‚³~÷m|ÁÁ‚ŒåµK…([À°V-[ FO³[뢛}[®É–•ñ8Ñ7Ñ—rá`Dø G.¯¡Æ<1²DÓœì-_Ãã‡Ýj¤lž§¹bôô»,¨f!žlÒ,Úôæ¼›…ðelHû U³î5 jå#›…th›  ‚npÆ£ôôZqÆ›Ãñ2ð¬Êe ´Žóß6¡÷4ÉÂ’ZíåC F𠫘‘¦ÑÆ*–CcßF!>ï ßžÔÓo+å£QæVÚî9$ûUjé Óq×/6D-a8íÑ¥i¶dçùË ƒ  K«ç8ÎiÓ”^ÊÑHõRß:ƒߎ²xqäÊ_ =:1=º¢ó*¡)zô8gT0¢èÑ7d ÂaPÃ%]ô‡E ’¯ƒ´^â/¡å'e,Äböä} ŠT¹k·„-ReE _BS¤Êp©ò¡§.â:fjíy„ì¾û BIu½ TúU4J]¯÷$jJê(]¿®4Ù†Ý;ƒ’¥îêzäzS„ÎlFè,›€¢”sS@Eè\#ƒO…«=R„ÎMž^`wÂ2Å\BS|ÀÈ|ÀÈDÀºÖ‡¥àHù"•®)x>ѹcZíât[Æìâá,§$t!O;š¸p‹·p}6âyŸY-ˆç_ô£IruœÕ!—M×ų~)(í.þ¼g?…“ƒ–¶— Œ{^êÙŒó,ßu `”¤ísyý*?C¹³ÑÆeÕ‡¦Ž¨OP}ºÐÑXÓµŽ>†dHª’ØV•5ħÖ~Œ“@ÔÄJ ”ê\d„o}~­çyÅ(^4Íò¼b(ÞëKïµWïÓùò*U‚R·9Quo‹ mªëHƒê:¢-ÐTב®B¬=³ê:ÒèÉf]G€qŽ.uáëJ¾ëÖ‘fé’Ž!u¤<ÒDÏÕHkFYÔ3Ï¡²³»GZæW <جáR­¼áQÛ'šÝ•’ŠSé=¶:’L™9¸®Dw#~ =«cèù1¤ƒíÊ)¶­|‹5Ï÷Ä;Ñfâ–çÛ¢x—Zõ',+hÚ”¹^ ©E•‚}Á¹‹GË qÛ;Ìjo¹„ƒ’¯TÓ B¸’Õ&ÎÑT3ÌFcùlbî_Xº¢t3œs¸íû@µÏÕ}osÍ*J¯Õ†ÏÑ(o7¶ L…>ù†ÏK_a§6_[˜[Þ–%HèXÇ·c€L㔩–RhªeÀ²–¸úT5 ØBS ޤ†¬#þÌ+æáuD€Äâ‹ågÂ#ÿf®~ÞfÿUާM4Z¶¯O°¡þd˜=Dçm;-u¸Åáq4,`|n”éšçåDŽžÿÀ_Ͳ¢ªûu ÿÐm•dÖ ©í²Ù³AEçLjCk±vÑ…_‡Ÿehަ(CàPM·çM¥Ÿv–Y ­^{W×®_§<ï)Äuÿ;–yî,ŽÖüm‡kw8ZÍž ;¸Nÿœ­7½×²p2'š?{ܰ¾yeZ?ä¯Çüç‡ù£.bù_hÁ“ŸxÜ” ³”ŸÀƒ6m»Å€[_{ND¿ Ï'…Í U.c¯££¸´ž÷Ňé,NU˜{FZ›ÇœÜ]ió¹Z—ˆ¾·k¦8}j8}€eSÝâô1û=P”âô©áôAX!áô1û¨^SšÓ‡ŽœGÃћܮ+Üïø´A;˜½Sã™ÕVO™ÕºfíØLíÖ‹¯ü5õâõ4VƒÁµlÝ8Fqñ_ÌÿŽl~Y=X•‚bIkö¤Kš¦XÒVhŠ%íÎy„*–´MY\÷šòîvE)ÓyJÅ’¶@S”2]¥”±„ÛrÁP”2 lF)ƒD’ÖJ«gÉ;s±N4»ï¾G:ÒM0a(’´5剦÷lp>â{>Ñ,؉¦Ø¬š<ØŒÍJSlVšb³:€sÎ Åfµ”Áõ¬ ª‘?[6+ ‡C°YYì¿çþTøx{*Ÿ£uÍêbõä\CV”Ðfö'/àÔûRS°©e󭌨^EQÄŒm›5Ln2³†…"¯I]Bs4ÅVa s{.h‹¥…ºAlŸò´a¸Üb°ºƒ5m²;6›†Ÿ†y®b5Á±&1Qmó´Û\³4£yºRý˵‰ŠL`lç^{6h×s—a ²XÀVR²í{bÅZ‡œ€­³èY(¹]+½~Ý2 tÓ[9µël¾ vτڕ¸ýµ§ƒÒ¶­ðÑ´Âí™¶¡¶5tqjŸV/F²@‚èˆÅ^Œ¨üÙMÑã’ ««u-c¸°Ä[i*b|:a¦Ø :a¤*Öh¤•FúE9´‘Šp/ÀFO×άÔÈèë’„áÛ9¹¡ù?ñœÚ6HkJ³s0lë8ÁÁ2öfúãq1ÔO!›Žó$Í‘®”hŽFš•ÙSùhëé~kñrò»ž”ùâOçR± ˆçFƒˆw?¨jQÄsËì| Òm°hðº àðlµ˜ìl7 Ü9©ûÀ=;£ÖÕä|sÛ•KÔlê¶¥l\ŦÞäA›ºl|ƒ…ì¸~\ì¶¥ÃÖ§aHr°«õyˆøPüKD–ĵr_¿bØì<æâŒ^ )†Í®2lÚ–õ>™ßt`_·óûo‹Y£)Ö·8dÅÆRqÜ{f}[Eb0C1¶iB1m3Gá„a–ÌQz/áÃãºOt¯üuþøÈ’?Y°ƒBªøCþäÍ7þn¢Ù<+º`®þìÛ\üÙ³ª€­GSdSpÏF³at=¤ Ýà½0©z¨ë)7u]kown#Œçɬ–Û^ʼn4Oë²æº"KÎ;ўv‘6và(>ƒCOmYÛºd—¤ ÓºÎêkß÷a;0Û¼uN;…ÖuÍi'>Ó‚ÓN³ó¿óøo½'?OÙÐÄÊÖ®GSœvp¨¦›/P\C;'ÑR–v­Ô‚Eªðh\i²5eao )»cmw˜’^ú«™Îζ]Í èì*¦Ç¦èìv ):»8J z  J©èìl»Š?ËÓÙa ñXð Ô854x–ñ_|I'*¥@£Ôž| ƒg§µ«ò‚X~o±¼t¡oE ؆Læ< Wr[ñì‡äþ/÷Ö’Ùý»Ì¨~þóˆdÒm­š82Òu߇C_‡2¥‘Ó;ù ½Ö>ïc䳯±¦ƒìU h…~ß¹¤>¾©EëÙö<©NÒ;ðJRM×Ú»¿à»ìpIê¸2ÀM ëëàɦ7w„KÃyÂŽ«#ÁÌFËU5¢}Õ7A=HϘ|Ôì[?Õ“?#ݪ³4GS¤p¨¦Ûó¦Re;KÓm´ÇwÓõð—ç=…3Ù]y9 ®¯Æ²zgà|E"Ù‹ ft‚b×î[ ÓEQìM±Û.Íi(vn;Ü’®œ{¯;nIKfÇìŒîZC–<ÆÉ³ìÚÏ|ÉÒëÍ5±ÖTþÈšl ª¦qO&,9~Æ]”×R–ÝÆ“[ö¦Så'6šqUUòË<¾Ù ]lP›÷”¬‘ébVá˜å\w˜-r”)"a‰ÏUÓºg¹,ñ¶­ ¥€i›‚º\gä#8–JÚô¾:qnjO·D%sÖσ¡l}ºòm4Dæ–¾Xß2½¬é8àlÓ\þpÜÏrLrÛ à%¥€ç…vY§ž¥åG“åê8M“jXSÍc•JNؼ†ç/->qoŠ{„º¬›¨4¿:Fú -»\4cgÖÕ/»fðµH û# UúUFx‚š=Û<—^Å’v¥®×uéWë%†¨œ] X×Úpœ¼ô m¸Ío/‹_aÙS\‡«ý8î§X÷ÐÖÓýœ¯Dä:€÷Åc½¹­1U© rMH3YRR“'j©^º¤¾'a4äoþ'ã%Wð`ø)¾Üå @Úˆ¥iG‚/op7JG–n Fš"`ËÑ5²e9ÊYQE+Qs,Ö.êŒ;z‹Ä]ÏÆ˜§,‹@nFÆ;;÷¨aıoƒ2ú]{“Atí²±þ‹¢kwú¬eVß}tíšd1ûŽZ¿&±ˆÚ˘Rx4ëL6¡Dµ8M[€vÛU ®0·tMŽqV­°C+ìw?}êbã ¾V@íuÅZyÍ#¤rµvûD*ý"®tÅ"¿F£¬×ï™ú%ÕfâNwœ„äøœã€kè¯Ô;t­Ø™xúÖíõ@6énøm3PŽIÑ5CÓYø36Ê’0š¨ˆÚ ­L¶‡Lmx†ñWnÁolãò“ÃÉü, Ms·3·ZoaÊI?Ð BÓJ´À;z@¼ßבŸðÏ:x•[ Êîm x¹ÜîpÊIBþ3½géí¥õt¿OÊøÑŸOq£ñ¸^¾Ó–X%°,çHÙ¶¦ ­Ûvý”kØ sTšmý͹s«t’ö9“¸î$=’kÜæ+€?5ÞÝ(sÃ8Í}Q¯ê þ@|›=ë’²=±üÙVΧ*Zy¶C\WŸåºí9VñOØkû1œÂͱ»Ãu(Ý{¾¥\;ðJºDô˜{7öe®8a&f:Šô¥3«<#–Œ™ÕQdaÅÉH^[•R}ëœ|šÁ-Á0𣨵+dpð›÷u˜#øŒ9™¡}ë9™õÞ„eùoÇw"}‹ë¢0Ž5s¦¨™‘©™·V^Œ¨/ê¿!ª¡ ÍN–`…¡ÙHYQ2*Ú¤ƒ»ºZRµÝ?û_óÚFÕh¾3u8„M¥Q'ÛvÁzûlìËKi3Ó‡µ64£¥w±ìBY^¦’7R²‚«®ßLO8£óqŒ1ÚJHçé×=<€¥dè9a¢”¬W{N˜ìóŒ-~?PdõhªãÄUôqè©vŠ>ªû-ÒÌ5*ìh–î5AØ4ر«¶g„.ºù||M?Î3þAÂû"oü3ûQTꪄ¸¡^µ,§=ÿ}×ÕjÊ‚„eÞwö7uÈ)±Ê_SF[Oº,Mñ'ÝÖœ3¸Ú¢&ƒ×iVÄÃͱ@ ι%ŠÜ—´Dqó7q¤z¢,ÐTO”²Ž°¤%–«ëH'–ÌSø„ÚBÁöTS”&OÊ5EAj8qöMQøê„u”oŠÒ™FÐ3l³±‰êVE£<]Û_XNìjµW¦ Ñ«®7M<ªëÍeôU+Lu½iúÜi»Þ´ÛW©uãÉyÚïÝ ’Ø×»Á~Lâç;6õ³ð… ýì©`=R¤K´2¹rEk]RÅ8îd'l*Vã;'íV5ŠzssËatÍ0{.TX×\9í×±®¦ ÌZ/%­»’Ö»Ø5£ý|6¾øt˜SOµl9ºe‹ì¥æÒZ¶ðÅg[ Å×vËGN:¬e˳ʄ«GS=[à(.õfÃP=[ä~t©²9)ü7óø1Ž;áºk¶ÇHÙõâ•V{)mr¸]ç‚8{Úo“ƒ³_µÉ±&úî>9#ËSÖ]=šê”sGYw͆Ñõ\Ü4ž'óTÜ2•â'üм¬9W†žô³ªŸ*l ÄÔr·KJP]sþ¹¯kަºæ¬ÑTל8ªkÎá§Ê³[]sÌ^¿J9”@V†ÜlXëú¹®ÛΤÔmG¥,çh”š×¶ûgVÊ“[è0Wz÷SëõAixgÜýE’ã]²û‹¶d¶âLµ)£©ö/ûqTû—&ãèºkMµ©Ã9¢qÕþeç“í_ø!‰jÓ€bòý_Œ@ë YÁçrïóõÉÏÔý¥@#´TLÃ…³žž8WÀË™ÞØêbaëüh9iTÓ4Ð%é¬éÝá=2‘éÝ¥¬X¥œ*z÷}hŠÞ}?Ž¢wo2 Eï~ÌËML@§w?›R±»—MÍÐ¥U°bw¯awGhZzÖìî|!rj Ým©¦º$™€j’+¾~à§Fs¦kHïÁ”Q':@[ØÖvHY¶øõ¯ñøÇ@1s,ÑTO€8TÓýÀ×aç2ˆOë‘(—¶4^øAï ZHé¦XùUh½ 3ÒçúfúdIy]í% ¢9)q² Œ9+Ý`¦eN®YlˆjBÓALçÌ‹O¯¾É«hÕ7Ð}l‡hÕ1•ˆ R"Òü±ÝQ"”Ô¬¢ ®¢Qæs÷̘¨â´:äB(¨u;ê*‚à“·KA-óA°.ò€GÛ;\—’{q—÷³²¯uœ…(°¤pH–• “´Î;¢yï´å…Q¨²=h”ÙžgÑwj˜„/\kÁÂò0Ÿl¾ 1},ŒíSñÍsÜ.Õl2;t–5Ü:Õ¬‹H-SÍ~šO§;ÉF™ý‚b9ùb)r²z4E={G‘“5F×3ùóÈpy›LÇî+f²*šbÉÂ¥Cg\ë$/ºn‚œzíÓ¡JoҡΣi}ßM‡ªÌz4Å…zG™͆Ñusã¢9•©!ýã¬9‹Ó ÑQ¦[0_…4)»›‰Ã©Y&wë¥üËÍ ³`8\tfÌí…Q>ê«xÌLñÓ`d*–§­Û{ýb­†4§‡»˜s¬ëíqøÚÛ¹ÜPDOU´Ê„IqYeßaÝÃâ,“C¡hDª² ®buØR•€àܶ¹ÂõìI+¥œ¼(–Ûe¢ôóŸ¯ø@$ƒmµ ÅGC:bvx1Hû¬ª‰=ׄ¾n5D{“5[Ëéd2FëÎPÛU1Œ+¹|¸Šdƒ¢žØž«rÜ3ü¨Câ¼ØÜá‹…ÑtÐ ¶ª¢Ø;cÚ`ßOÜÇ^Ïg3– äßÁMRñ×áPqÍ0àpy€èÍìÖUóiX÷kýè4-¶?gþC)Ký$ü‡oêXø@˜Tü‡[hŠÿp?Žâ?l2 ÅxÌŸ¯äËí›æE™È€¨›6¨†Ýuú-û² 8Ò¾´ TKórÂæe(c^Š–Rܼܰ0ù¯5Ý»á¿ãÿÏüŒÝ=(“ó±ÉiYýKâ:Ã>–nÐÏ7œ³¤CF'ö|³HŠubWæ»ëQíË2ò»otb§$éºÑÓ[›oé×8çbäkš£Ÿ–•ŸkN˜•Ïí¼Ö­|[v™V2=\¹Œ‰îdzH±ïLFµ†,yŒ“g? صŸù’<Õ›Kb /,l; êSy2{„»˜ÇÞ!©Ld¯:°•Ð(99,Ó9ƒ€¤êÀ¶P, ¦õª¹hn€Ð"㜛HŸM5ÜMÓx2aÉñæ€+ÃZ¹»77ènãÉ-{aS9C@ f~PÎü”yþ覚Jéå ™Ü|ؘ’Ì^¸ ¤G‚•L™³v#˜Êý€ou :s”/ ¼ý)˧x'ÚËØÀæMÚË ?¿¨.§9šj/sçŒØw4£=i×Ó|¦,òĔ㺥]óÌ8µ»ÙÑÇ0{ ¶hÒ}[óà4G«èh6Ÿù‘q¦YM¾ˆ:øœe§òG¿Uô:9áùfYN{Wüã ·p;5¼i±½gìnÓ±ÎîUïVö6¦æ•%ëÆóÙøÑ¤@¹:îR®éR¡Ÿ^¥á[®láÄ|«ùéwÔë4Ð~'¿L½Ç¶‚¸ùJæM¬foŠë63ûàN çÚDˆ²YÑDHu"Û@S]„.±W"°NdÒm„º£D(;‘­€T'²*¥Ñ{öÔt§™ÌS } æœQ}¢š<جO”\V^Ÿ¨-FÔ]J¾áL‡Š™´žmü}t»™Åòª\ÊÑ(»ÿöz-²Jw¿r 9hé˜Ú%Õ-©:šÝÃx‡Åò-®müª%ìÙF®¢Ñûg@™ŽUD“«M€iÚRyÃrlyÙrK9½‡’<µl)gˆúõ†í䔸8J5ÛBSÝ\áœQúJó¸Ó:1ú™!óí0ý·í¦d8­·WMɬäy&ª'™,šêIvGb͆ÑõSLõ$«ÁyO}ŠNG±É処µ ¸tG×äŽk´¸f;3çʬ™…ñ°YÆÑµ\¡_}ËÚ±Á˜‹wëPÿ: ãt]ÿº`Êü¤Ô¿NÙ‘”îGÌ_¯/9ŠžR†«œ¤gÜ›Z›Ú¼7ÉðuøYõ'ÉÑT’ý8tÁÞ)n°—Ї¾ŠVží§»Jê è—Zï“O,p‰ÞÆp PÁÈ9÷ƒ‘"ð9I?™®ên¨úÁìCSý`ö㨷&Ãx‡)nªÌ]’›%ªÒ.ÙȼÀ~0†kžy?˜£­K͆7—=A;)…¨,ÎÆ€ªÌ>4ÕæŽjÓl]ÏD¸,¿û6§jS‡s.6¾nô¡<@çdä_F;~U¹å ý;Ð)Ä•«½©³îWdþªMH ²Mˆíº`ßïiS9Þo›Ó±`i`] Ç¡ÚO0N¿xަøÅàP°>â^(á`‡nï¸ ;~|Lå ¾%“Ûtö&¼ë×÷)“JˆÞ§hܱiÜMÇÕJÓ¸#\9Ùß¡­ wпO6éßÕ½$G£¤]²EšóYiÍ”\ÛÅÈD4ã¦+k.U|†TÞ5VsÚUdOFv¹o©T·³šÆ‚šõà§aà­RY¶ªÝ!ƒ$}Ál°N,Ð rÎ$·”LÙÉ­bÊÞ@S,·bÊ–yŠ€Y”«kKÑÜ6y°Í-°îùÓÜš®´Á´ÉCæÈõyÇZŒ8‰Z}Ü•ÙÊ‹ìnYûHܬÚÌŽgýÆ\KçN™||5‰ ¬õÆ'LV¹}9š"L>€s6Õ$Š0y íR3ÍÞa5ÉE&w;ÏÌ>‡<Å—\B4;½§´Ë—¬£ä‚¬ø’…ÁWË6ªtMñ#ÀQ̒͆oø©ô›úAt=$ ÿÍ¼×„ßÆURÀ Ö¢]`I/›n1QC E7˜¨ÍxÆ¢ÝDÔ¡b¢®GSLÔp”½Ðl]w)&ê2ãlêO«XåHMQ¿VÚ÷äü ¶™003ÖÐWï#þöèÅ!þnÝ/hƒ(fºDn¡ô¤©Ð…›³$žù?c%Êð‘¦XÃs´õѱ×AO‹5úãé{¾µ^߇ÐÎÊRÙÚrHlí–I½×ú–L˜ +õ~‘es\â}_&¨\›woIñ‹QÔgÝËå(ÖgÝñšø9÷–Þõ9c:Z®Õ€Î¿²d ¨üs4E忇*1f†‡K±ÚéT jù|š`9 ýwù·tXó–ö©å³ 8¶ö3WŸœA»û¬Ð¶8iÆ‚4+4½³ ì/SÏ‚w÷‹ÿö™ý(ž€ÐJ°,§=çEׄÔðžý7ï;ûá±(KB†\h»Î{SªË­¨QuÆè§Ø!×ì²\£Æië@¦Ñ³f‡„çÿ"³Cªã?GSìpÎ&L±Cn¡]j¨è¦ƒ)vÈ 4BvÈ3¸7(rÈ¢i:¨™Këä’m^&‡~Vv_¦è!à(º§fÃèºåÇoˆÈ¡8Ñ•úrL?Ź÷©v¼™¨‘¶a»ßr䜠{³¯‚]ÙW;­Ë¦ÙWÊâü@lqjŽuIŠ:Ÿ}Õï¹à£¢C6g糯Zo•}%ÿã’­N•}U‡s.V¾¦9ú„ì°Ìü\sžö• £6j½A„%wÉ8ºAÄÿÃÌÈÍ}œG ¼ÅŸ¹É®GähªqÄÕ8¢Ù0ºîú üéôÁ¾ãš†zžðr±–¸hkª¶Ç1gŒ¦l·Ý6¢$ïØhaͶûFLUÆv=šjqG5Žh0Ž® ªqDŽjÑd]÷ÔÅ©œëbdiº]·½ ^×=uªÔÚ¨c†Û©Ãq4Pæ¥|§¬2¼&P~’ú.VÄ3¦ l 4BSÙêö™)M²ðfO±²¤ºÓ·…+œ>èÆÝ¡¾-Ž\vTƒ¾-º>Kâ™?ñ36LØcøÆÆÅ…{8õ¼‘æÝ}Iíž÷ Q"ö:è ]q±·ïx:Æžo­×·U†v-*Û|\ ‡E °Ç㬼ƵjU‘a€~Ê^Ù*‡¡­Ë”=g{WP±‚ÂèQ&™¨\ÊjÈœ˜µÉ¨ý¼•ƒ‚fz^˜z³8Œ2–x3)S~."‹¨JÛÌ®ô€v„?J_H¨‹ª…­÷eÒ)6ÕEueÉI›Ì‡UDßµi·g—d뙣{vÙ)Ëøß †¯RÅ5ïÁ>VͺêpΤY—êá²…Všk©„½p¥¹vßéžÑ×åÒ7P¹¾m;ëÓíõ@î¤óífipހݽÑÜq콆c)Ž˜M5EÛs&1ðZéN+xœ]y?XA@®;ð”n58ï]&R¼]ÃÏ*®™£©]pΆ#FµèÚB»ÔúÑwÈsa-º:^?j¨]»Ÿî$IŒÛ3@NösnÐå OOÓ KÕ¦æhªAל3¢ˆQ º¶ÐTƒ®C8ÊÄo2Œî›œŠ"¦ç\L|ÝrΡ«ƒjÐUB4]SV-T“í ©d»­¼ó žýL7/ÙéRÉæ»rÍûùÏW| ¦MÎã$¡0Áÿ Tç­2êá•Tˆiõõ±êÉÖ¦šè4ž'œ$£Â‘a•õÑScfSMõ˜¥Yù¢^íBæÇÌ.Í·TÚy=X©T¥ðŒ ê»LZ:z®qŒlªµÍd3üë1‹‚Nš-U0±i° ë é»¶»,ˆÝeèRº…g5™YœÈZ½u6[”±7Ù*Á’ÙfK¥¡ï"õ»*†q¥©"J“Ì„Ÿ[Ô;|cŸ.ÞVµeP@ÏMÜ­ é»YÞ°R—¼]5½UÎÍ+]í[Ê}kYб{ê}[Yx»Wš·âàp¥Z‘a;8,™%¶sãYC–<ÆÉ³ìÚÏ|{>û+<šSúÛ/~ò)©‹Ã…rO]¨‹#D½n;‚²ÛêíbRlgDÙå}h†aOGò”e3’ž£Ô.Õ©ý·³8˜ú‚fê×i| ƒgEZFJÚf>j׋, 8)ûªÎrm=ÝÏþ›×Iâê‹ÍÆPD‰š­÷åê^6,…Õ †X†ÔïZ JúG•¢"SÎjiæçÐ<¾bI>†7Ó>Î3þMÂìÇÐÏžŠ»l‰FɆv…\°Ù0ãËPÑhtêží©eeí¡m=éMãÉ„%€t©KêõhóQŒ²d†’ºï'6šùÁ1G;sOj ]šµ°úZÿÝqT¡Î3_ÀÞ”½0x5ZæºÛÉ8i†š®?›ÎÇ+XèY<¯`¿bE×z®ÓrËðcËÁ´ž$-P]9˜•“ÊÜ­7޽,žÏf, ƒágÅ&“£Q6ú6Ì~{~•®ßߨÓý"_¸4ãýÔ]o «»XhßÖk/ú}X{^]såêÌ;s¤ê¦ Е |‚]>Áf…u°›À'ø¡ÎáÄçp¯×bçÙîWS#‡KNívÁÇð%Õö¾Cúž×v÷+©q+{-ZOsFf¡6afØ{ú=hg[;S®ÙH삾'ØEß³Ó¸lJߣXùs4JƒSs¬K ývž¾§ßs/ÉóÓyúžVç»ë c—eâwßèTô=u8çbäëF„>'+?ל0+¿ô=ýž ³ò{"³~ɯõ R§í…µ(ç?â#1Ÿã6æumÕ4ÌÁݨç){û­½­YšqIüìØ©– ÏI5ö×¢C½ë.^L&ŸJဠ¥D8¯ W¡TñRYû=Ë…9¦œ¨Ûù,NÃ7À™eôäfsÇ™åòŸ‡b(ÎL”eØæ`èæá=އ/ÏSU`XFZ`hªçhëé~Äõ]˜ŽÓ \ìÙEPÍÙb1g×=EA<¤îr;;RÉÙuWQüø˜ÊÝw@–™C]£½õÝu_‘*—Î.Œ4L;عntG×äì`„m^H&¢—óNÒaôúÀ0í¢âÖ,Œä·€ÍÄeÏ â1“bSærsÀR8¤gØç¦L)ÂòбT‰ÝO÷OIü*¿ç(\ņ!mT8G )ÀªÞX¥O©*,X›?Ê4ëÁOÃÀ[ ¥¶ÿ’“2öÛ'ƒé*]cÄÿd&ü÷Fþûo3=Ë®¥_š–nˆÜ¦» Ûx§›@›f¿½P+þe^ð[™k©Ù¸ryIIÈs-uÈì€+Û(ýËno^©ê÷䂹ÖÍâìk=¨-ø–ŠíHF•;“¹jI–¶Õ%®êšç嵯žÿÀm?ÈòôSnܸË&ôƒáç`¤{ÃWeÂ| 5aú}§½Œ±®Ð 5£=Ÿk× èeÇmNv×ã ž'rp3=lxü¦Ó†Ìpž°µ1q´ƒÇák¯ËêËOHD7¯á€Ü.¦¦Iu×ìØU“†-ý©G3л+.þØ[ãZ®ÕËÖÇ­€­Ïu Ë鬛²sEOÓ”]†“NÕÍUSö}hª)û!œ3ªêRMÙ·ÐTU×~UÕÕl]ÏÔA¯êrL8[§ïØ”½oAz–º%saÄí8èÍ“°å~g¢w»ê úß/‡‹û´Ãò1Oº òEÅ…kõ4Ôó¢²4¹lÉYü^l¿° àIñ5Šê˜µMuÌ:€sF5¦c÷UQKMõÌ:Œ£ÿ=ÕZâ?~Ï,n?À:lJ÷ÌÂÊüGkµeÉQËíÌüßèµåNÃ4ÛÙlKUäh”|k¶«Yi¼¥;R}¶ûlìYrˆ*C—îc~9í7 `òMûiüÊ’j½‘£©ÖpÎ$‰ßèYÐæògäì-Þæì](‚–¾\»÷¥5CÇ:Adœ2-éwM—ËÙ:A/©€®:ª^ûÐT/ˆý8*¥ É0T/ù—œÀÝ B?ƒ¾êQB´zF¯<ã^’n–zAÈ­ep6T½ ö¡©^‡pÎ(kXõ‚ØB»T¿ûF§Ê®Ã9#_s ìµ?+ÿ"zAp+߀k·Ý ÂAíáŽÙ”‰JÏú~ÊÞþ@œ{¨zAl¡Ù£?Ÿÿ'©Ø;;ß\â´É°>K…˜µa˜}˜ã¥í^:°MûF¯{öš„+·:ø¬zìDS½à¨^ ÆÑõðI¯ƒö.‹]w…à7;0áYGë !èu`ºn{†u×]!ªâ¡oZrFÛf§ƒÜDÃ4‚-|49¿JãF¯O~¦Ê 4Õè‘O,¬ódH³zv¤nLݰÛ!Ü[d<b,ìø”·¬ìešÄÓ©Ÿ1ïá‡ØW7¯iò=€s~«éFy,­»Ùm˜O§Ý>} ?GªÆ,N£Ì|äÿ½Ñ4Ï{~È“]¼l šiÔ¢©fûqÎ¥§ßb¬ú½5ÓP ö<\Óà+ãöPDb{Æ ¤®d<ôDZù ·Ä¯ª´5GS½öãœÉ‰ª÷õö¬—îç’Ž‹´‚n•ÔtúTEê6-)´5¢¯ÕvaÌ2ªÛÀªÛ@ïÝwàË V—~ÎÝ$s![ê6ðC™y¨óU·M4ÕmàÎÕ ©n[hªnh?Žªj6Ž®'Ë wèk6x¶;}o¼¼n–f©»Àf.™ùß„Í\ÓõëˆMžY” †"0ߦÌàœQâtÞe´C¶·¢/ß?Œ®[ß*™…¾|q†á¹™5Aê ʱ“$0'd"—›Ý]†Ãy/eÙUEÜÊ ãè>|fñœÛnÆ•Θ Îæh”)»–sId?Ø@QäeÅ¢ÄM|24\šrZ +®ÛæˆjÖ‚ÝÌ,G“‹Š¡¦šJu¡k˜jZdzf…ü¯Øàîó(³‹àÒ®hµ«cÚJ»VÑÈR_\Û8$—L犠uwšär?çNœÉ½¾SÇ0~VVsަºuÀ¡‹–Lqc†aÛ3_¬»ÍóžBd>#Íx?ÜÕÅÛ¢SiÂTéÈõµG1€©øíQÔ +GSíQà¨ö(MÆÑýƒø’r T{ù]Ê8Ó¤Œšpt)P¦¦¿£ ¨Ëè¢Ù²ö€ÐP1öÏ—ÍJ©ú†ã‰ $Ëh¶«h*"d¤J“uÌ”;ç>:À@ùiúèü—º™| ¾™¨>:[hªÎ!œ3ª‡Q}t¶Ð.õ.¨êaŽù¡êaöã•g[sÞOðþBúèh¶b'j½Ž ÂKõÑQE1õhª³Î²ô«n6Âé®j4êŸ:öÜ3åbË»ºÉ`”(bÏ= –¸Ö~³"”ƒoÕ¬È-˜ðmSµ+j†¦ÚÀQ튌£ëžjWT‹s>íŠZ-¹íºË‰ _‘nºF{Uå]÷9)û\ã¼´Ó+ïlé”`Ï"ÂæC(Vñfï!MÏâ’¬Lâz4B“ØÐuŲ¦Ô*V-]yw#êÕ>Ì·®š3Õ7g’å*¾ÔæLZß„ñ_Ž)w\¾ƒõ¨æ_ D¾¾Ðújµù—°6å|šé(P}) ´Ž÷ô:›ìX”E¬È¶•‡¨é‚(3n{äÂÉôµ=~~é^0TT9šê~´çl˜L§Å«~×2èD­Îv÷ë;Ùmêb2|¾ùWwÃI~;m6â4÷ʵ,›»½· ADòí½LHhg/Ûq£µ—)ÚÛ«ûiFIÂjZú´¬Ä" 9÷߯ž ëØD¾Öo§š´YÝ­^oÇsìØN¯¸•®Ù›œãOi¬¦€ªÙÛ>4Õìíηªfo[hª¸u?Ž*nm6Ž®'b·=×<²Õì­„Èïc°È§ÍÞ$ïhMš½¹¢OÎ}üi<U*c=šjóvg=ÝR™w;Ðèª{T$©Š¦’F‘û =Šèôvœ>Èé-Ûl Á1…Ü£ J½£IÙ¤®I™r‹çh” j¶«}%ä’¯[iˆÂ…Uë´Û'K2©ëè>YvÊ2þwƒa Å.¬¶xc@Õ kYƒ,Õ²x­4ÕR±óp%—ûŽèÌlKÒÓ±ÝRöT pø¸6¬wʹµ#»‰Vg«”ür3±™;޽×pÌ¢JJÎÑTÿ²8táD©¸3iólΣgõ Þÿ\ tà89Sμ•–‰Db×JkøY9\r4ÕLëŽj¦Õd]¿‘]VŽI÷‹UT3­mœsÉ0A Å; óBZié® Ê"?ëI®ÜÈ[j‘ô¬ìÍÄö¦j‘´…¦Z$Â9£,rÕ"i íR-üîÛœ*‹¼ç\l|ÝrÎ!FµH*!Zz_Ñ µÞ"I2Çñ@‹$Í|ö¿³«x:-œê;%)³û­Ù­ú"m£YAÖ’J9ïì|£%ú³d·ª6"û:°QuÛ­|$Ùþ·òyé² ÒÊ'WÒü·7ßøßÜD"<7¬üÙ·¹ø³gUT¦úýÀQý~Œ£ë»P(ï…á&Ϙº®µg¬t݇Ï3’I7¬W]w¥ä–Ðç¼ÕnK]÷¦¨‚CxóŸ…e‡g=ºcÙ³4MîZ€ÜDÈÔÜ>K”$EóçÙ<,Í«.íuØLÛþ3C7`%­ªMEm› Õ%GäëËea´Û¦ÚÆ·i›Š~ú¿>ûÑÕ«b¦zU • ˆ:9€6Y-ÌÖ‰Ñ9ÏšÔ…W€TʤTWc@E ºM‘‚Â9£t.E º…¦Ò¹öã¨t®fãèºT7-°»÷lìü !5úýó'•tˆI’‚ª€hŠôŽb=4ˆ®'-à¥á¿¥Üº;P;íºÑ­â¢$b5ýk¥‰XéUmc¡šá­õS–}› Ç^‰OuèfüWéL.­B K7k˹¤²K䔪Yêe æUÔŸ¡égÐ/i»f“cêXpi—ÊV2êu4•­“2ö=~|LWáÿ“q˜ˆ^ùïù'Šžã±\(^)ݦ€Ku‹ë¬G¦ºuLç’ò´q/ÄÈ\·–k^R;ò\K¥í€+Íu¯ÿ~¸$mË’«}ݲ?ò³¯m§±ÙëØ~Þ#±ph Õ ?#ݪ fަø…àÐŧ¸‘rÑŒûr¬ìÉ~ /f²»îŽö¼1K±Ý&¶ ¶/ÏÆæÑ$[6v”=ÛÔz°f gÍnìStvÃ7e} 6‚»ášb7<„sFé°ŠÝp M¥ÃîÇQé°ÍÆñÞÒauÇ|OVþe°ššm™Ö*»¡Ñ“û(ì†*?¶MñÀ!k}ÙMzÂâ*e³þ©c?IÎÂý\2H÷OIüŠ~šgN!iIl6($­×$ÌX…?òEU…ì@SÌp3dƒqtýȓ̔܇ÚïêbýN99!îÚî©NnU4eÌ­¹¾iÉÙæ\n- æ…›¦´ïLq6à$l2®cœ„¦Xðf[ºœÁÿVX X/—ˆ_` †ÃJ`“,_<š˜Ð~K',‹ÃW©Öµê:Ù——ðbo“Ø­Á [S4U´òdKyývà•&[PvÞæîãf¡qÛ?! Ð yÎt›Ždûë–è6UAiަè6àœQ~¡¢ÛÜBSt›‡pT~a“atÝÏ«ò ëqÎ%¿Ð0ú.8>w6Fþ…Ðmšü%ä–i%±ÂÖe¼`Ç™ø _,·0z”QËe¿ª)ãV­5ëûbž‚fñó!õ…W3Œ#o&å[…›ãHÖ8ª~Á¶Å+þhQèQÊEB·TõƒÞ—1þ6µÃÆÒ’A’Ö•„¥Àü«pòZDœ¼BÄ`¨ô«hŠ”÷aFÐ#CNP.ó ´õt?ûoŠ˜·G%zêèK1o~F¢](, ˜$KÌ‹6@æó•#½Ü¾dì ôÔúª^9%Àíj`ŸÝiµ‚)Ìu€R¨YhˆúA7¤OòîÊb¤e5&•Åé`”™ü¿7šæyÏyØÏËŠY¶M1ËîÇ9fÙœ”òr®Ýf–Ul§{®a;åʸmŸ=?Baî¸wÈvªIòìïe;íc/ò“$~H¦©£·)àåbç„H­Àx¥0KÏj±­ë8ȧ¯ö~Î^ÉŒÊí`y¡pÛ?{¡Tg̺)É$Ôëæu" >‘ëæšbÝ<„sFY±Šus MeÅîÇQY±ÍÆñÞ²bõ¾fƒgû|¬üË`Ý´têak—uS“ `Ýt…a}=Æõt›wüÏÜÑòŸ(ëûqÖ›¢ÚÜBST›‡p¨æ[2`Ét ÷ÌÒ°Š!CK 剙fáÈvtŒ2ÓA9ÂÖ”™S½+QfNC•±]¦3à(ÂÌãèúÁ?>¦r7¥ wÝö ³®·é}œúdº¤öŠºî5R©ñù^˜d¹¹€hqb)FÃŒ†Š3³@ä+Ì•\`ÕJnCª’{«|"ˆg?$ÍýÒòpe¼e»lý~þóˆ®ó£}È’Ç8yö£€]ùÓéƒpóÿÓË]î²J{ígþ`ø2™ž*à¦+àÖMhZï±ç5’áO5ÑÁbu¢VËk} ÏêèÉÆ1ü©&{>æ»s¦¡%±'e%Ê‚ÝN®Ó©Mßþð&9&%ï‘ö-)ûh>Þþ<âƒ~œÆ¯ªø¯@ë8!ïÙÄn Ã5F_-ÌÖ-aÖ3ñ¬™K ÄM:æÒ¡Ò]9š¢.=€sFIšŠºt MQ—ÂQIšM†Ñuw»JÒ¬Ç9›$MÇxO­Ñ/ƒºÔrdmºm¯µ?ÏžŽ÷ZK]vy­u“ÏåÇ×ô#Jœ„ÿÎiW>…l:Ü}¥#Íãÿ“‘#dŒfü"QÊ…(¿vTJ¶JÂhr ¼ÉI%MÐf[\¨{–„/‚·æ;“*Í«‡íÄ|wÛÅíKÓN÷i=Ýr1Åm¬ZŒçívd,K^á¡:.—)¯ì2— 8ïâã­Ö"\É58¼ø³;†Ë—-ðÎM®66rey í^»×‡$[¸RžvÚ|„ H¿Ø¯›‰ZÏHS–²±Ú»”{×Ñ¡T_'>À¥Û7÷ýzUámzM¶(ð'±ÂáכƓ KŽß»lï.Ò«FW߆ïãí­Lø:Zñ\%±?ÞŠÐué«Wç#ØÀˆaMcM‡ià'ã_ãñª³©GSà¨ìøCOë–dCÜôÿ®77^†<×¥² Ì0âx:xœÒÅ«­!ršï?JùY”ݱq˜°¼?Ðh>›ñ4xPzõ­^…ß;¥VqcüÉzEâf¢•Ö;R¯‡ö9¢Î5z Û*¿Ý#H¹­c4ÓQ ²m ´ŽsìŸMÞ”[¼›*‚¯È¶ãï¶Ë×—4ä° r ùðs0Ò½`¨ØÈs4ÅF~‡.1kŠ›vh袙Q[ÓÝu Ï{ /hºñ“j‘ÙߥÎìp˜ìïœP;f).9 BïÒ³1.‹m Ëðìß¾mèÒ&FÇøö/æ²¥âv­îË]à•ÑÙPîïCS„û‡pΨ–Kîo¡©Z®ý8ª–«Ù8Þ[-—ÁU ˜…ñl,ý !Ü· êKn—p_—+¨;@¸o úžl˜ÿJ©ªGS´ûpí~³atÝó‹ì34í’˜‹Uº`ýS-«ù%õüý“ð(ù¸]¾_hGS¾_k®¸~×hŠë·#\¿]àù•×Û5_ân:O«¢-_Î,u°› ŒŸSQìe±WÔ}³·€ÍDåÇ \p½s"0¸ V5 ødñXªwK=*žv¡$`iÏPçYÑUÀÖ3ýœÂ“aΙ÷ À±Ký¢F8º ‹sv‚0Bn#z,/~­ø"v )¾ˆ8Ê{pè©v@ë½ç=àšT–‚ FŽÌ2!Wz½“‘m“fbrˆfBù"r4Ê|oÛÕÀš§Õ9I@GZuˆšÃ°¤ øîèr~›£IúéSüúìG?óÁM1 ù]Gî±™N²\˜mûó¦ ËÜ9צ¹@EtšÚ4©ô¥»ªÚ´}hª6펪Mk6Ž®çÆªÚ´:U›Ölï®6-'5/†þ…Ô¦9† Ëo»6M’ ä@mšfN¹¥~O§…¦¾LM™Ýˆ#6ªm ­óåh§uÉ꽞d¨v3å³²Ñ1=°°ÌÏökqúrçÚ¡Z+˜Æ)+Uâ¨x=šªÃ9€£êpŒ£ëu8*ß–okSÄãÊuùiµPA쳓*ôg~ðýѧƒÿR‡ÕÚà £X¡Cg2M+\Éðµמ) Y)¶½6.˜8´™¶°ÃE]¦­-ZGé+K®â(c‘ÊçZ u=½ö´˜\«ÅÚþÙåE†gñ})}Â\Š>aš“²ìÛL$P„qÄ?iòc E¯vxcÀ‹m †KuÍŸXâ%b-vŒñàÄYh_°ê¾ÆTª}ÙÞÆ9±€t4I~tZ¬ý–ò£- 9 WéÔ¦€¸Y±Ò©Ø© ¸“Ðãbý±ž‡ÛÐ2Ï€îüÁÕ‘tïBá¶îN0µ÷Û‡ÄÑ€ìÆ§Éõ–¢P'rc@•ë½MåzÂQ¹ÞÍÆ¡r½å¨\ïCˆ*×{a®·ÑwÁ).gcå_H®wž1óÛÎõ¶€U™Õ\o7xbÁ÷tþ\Ÿä}7J-2»?‡U®÷Zçs½;dvãÎw¡ž±/–Ê•'ü»Ç±±«CiýN<k’º8Ë£f¦ $€h¹ŽÁì¡´-[÷yôÇ/a¥’aúÌ ·øc/Se 9š*c8€£ÊŒ£ë†Büø˜Ê]év@^nKÜ Ÿ2Ü8¥îšàÌçùçp“šÄ‘À­+ºÛÐûgjŽ—Ñ´0-2Çå1á”ê@B­@nå¦Õ:ö[:›‹<¦Ï¯*‘)GSÕ:ûqÎ%‘ÉtZd²îºI¦2™ZÍd*·íGŸßùåiù€ÔûšL„á§kÆÏ¡yʼnìÜWŽÖE¾ŒäREO&ï öL5Š3u1ŒÚõZ“*¤Ú\28ÒKäð 1ŒóoR5¤êJçú›UM2ÅŽ¼@SÕsþÇîËÕݨŸã+ ï–Ä7ø;ïÐÖÖ÷NМÉVéR9šj–€Go²µÈ5ƒÙq¶ÛAÒws|o„yÄ­ú²®Ñ:^v6WLË‘ìï±Ù—u¹0[¿ešðqÎõ2†\`Kõ2C¥¼r4U0sGÌ4‡*˜9æÇåÆãUÁLŽ*˜i6Ž÷V0£çý´Þ‹¥!3}Ó%\´^0õS0£Ø½ëÑT ÍUBÓl]OÃP%4;pÞ] ÍÅZãŠÃÈa¿¬V’Á¸JâWt Ï‹Û/rÒ€ øENšFK"êÅ3Ãd6«7÷†ŸaîOY|õhªꎲøš £ë_p]\,Ò^mN×ͽ‡xŒK4¬L½-´õlÏ©’x™ì®{]ß§]=LÂ?c0—«a8¶œ¯qÃ&ß¶û3¯½•kÇ&е}ð9.4WM÷ÐD÷•1 ÂgêÍâ0ÊTô­@£,Eä*í ‚óHîb½¯ƒBw› ´mõ£ëèb׉^³}”BšjšL™ŸTz€*eR ©V³xIïÛ« ÏiÃ÷6È´è†Úl«¥,»Šg?¾Äc6årË߬~¡>9šb2ØCUSðeè=óuˆ…ÐÌ3¨uF¥2XnhDíj ›8IR.™à‹|³<)û-ͳH°±Ë%I(uÚðbó¤°;¦![«-R€w=tîynž‚ë€óÎÆË¿,àÀ+4në¾ÂùZÏHžÕŒ´>ÿ&Ÿ’øùÓ¸>-|Vùfõh*ßìŽÊ7k6 üC÷¾÷ˆË×'¬»Ø\³œ å5 å€;`;ÂÒõ>%*¿Vöµ²¤@zÒÙºÕ‡‘ª¨”­š”-•¸X[Ò=€`)[x àäI?g]BD)]Këc/ˆŸ¹Çøãu¤{ÅÿÔµâuTÃrÛë¡Õõk…çMcÜ’EÓ‡;t«Àžî§ð‚¦»ëW ±º¥ÜV;;2Ý]¿UˆÕݽé>W3ìJ²¶/Z7툳B%fW³ß}¦¿,y;çÄlÊ¡R—˜=ÅóÔÆ©—²™Ê¥,ÐTbvw³+ ´uõãÈÞâ*¡S[j6ŽS=Í#Ö](˜›%ž/;Ôd6S­¾éç>,1­çyÂ0ñ³ài0ü<ò†Ã™vµpmƒ¤lPu ¶ª)Çôlh"̱×$WÕD{\§$^>QˆÓ­é&îîèéÆquÐNwü Õ›º´4Û=ð1zôtã¸:PÃÕ•éŽçƒÇôÊ©É}`rÀQ‹Ä÷©Òuè}¿Ú¦É±>¥d@¤mæF¿ºéØzÏ–«ÀB¸é<ÄqšyéÌ âyÄ­GïÁO™äç&ZY RãXÛ-¼€ÕÈMÓü±÷ÊüïÞ,KÌ×'_›-Ð(i¥MçÜ:¬ˆŒcÀ%G,¬c“Z¾ºëöÖBU£‡SÆV)T<‡‹__‰Š5¥7r4U¤ŠÊ7]Zax%T†s±ž?½¬\¯ç¢×´I©°U)„MÐW™ ¹êÃm•€_RièNJ*¿IêØ£ë)Ýø…%yWhE;Ÿ£©rÊý8ŠvþÀS-„« ´óKÐv˜J¾›PÅ€s¥N¡Â~;.çbÛˆ{³zý acIû­ìý‘¹Îí¼Í™ó\ñ°( ýé•.e±©`U#¼’Jס¶¹yc¯W×GÓ±ÞºðöuΉö&<Á¥œh¯‹ôÄÒÇ8y^¤Ú+ãìq‚‹J²ßB«¦!w.-ö¢sì;7Ûgc ›}]®;@MòÖRû¶n[:¬)¸t"r‡ŽUÌúµ`³~-Põk4Ê£Õæ?ÔÑZA£¬_SLR›h”åkmÎöû«^ks¶ß_ñÂlŸÙx!µk†e‚LƳ.5Ò€a³ÍR#×IÏga4Q±ïMUaU™’]j·uÎrm¶¯tdiV**GïÉ4*ÄÜ‚)ÿM6¯¤ul©±ïâu¼*†q¥î>z2—R´i„Wò†¹V[%/Ý®0‚÷§-Ͳ«›úy…Æ[1&fÁÚ»nO.©cÄf®%爭ÉbZ[c­öw[Ž¢ísÖ”.®©¤­»ŽLžB!ïâ„ý¯°¼ˆeR«5d‰ðèûQÀ®ýÌ×4ÿerŸûùY¢’$h“$úÀ¼·“â™®+•G´¡*JË í$15éú}±Æá[כƓ K»Wj*wÖ¨Œ®¾ Þí·«Ï#óŸØhƱ1G“yþør©ÍeQzÄeKq–/cBpõ U?i@Óâs]ù“%ZÞçýÓŠ‹»Xz7’Ò†ÊñÓ°T=©ëØñs±!§|1z²„º;pËôùF{)O]¾øÓ92Ÿ»_ãôÎM'A]aOYâ÷ð“O6U¼³Ý(QúÂlíÙ©(³ æI¾°¼rïAbˆ£—Õ}·¾'Y.Fü”¦¡=gײ²µÕªùŽéò-x츔ÅïŒcïÉOŸTþ~ MåïÀQùûM†Ñõ«ƒÊ߇¤EØRî׺¬¡w[Ô˜}Ø åœ3÷1 â‚킸@¨ 4•µçlT•´¿‰Fxž¾§¼fÝ5 Y†)‡3-Ô—ã¬s›u™<ƹÍY2gbŸ©ÜæMå6w©·X›P:Ò•?*oO_{Ý€º’Ægi†û^7tèݰ.qÃÞˆ4¦ƒ»Qf¿0±‡nF™9óCþßt”FþÍÈð2YDê¼k¨R:ö¡•² XàiÈV†ÓÇ O 3{r£ý))^0Œ›k°sÿì …%M¸¦„Âöd37AÝ>r4Å*Œœ|D&·tÙ´ÛíMšf~6O³§Êæ”%£cveév‘íÍ’$â¯Ø[ý6N¡H‚iÞpøuäi½üAþ7§ÌÄî`Ñjÿ#>×FbL%/FU9®ÀÖ31n 5xí…¶P{N¥ Óëá:1Ïè½ÓPç9b¯\!cNuß1´3*ْʧÛr5î<úÐ u,Ý‘5*ôrÜШôÞ< å_2Ξ]Ö‰ñG¼26q-†N—iš} Ú/ñ2 ¾D Iš•zTÔÓŒZÅn(J¾ ñ4¢ +]<ëô(ÌLã œi¬£–h*1êŽJŒj0 •%ýã|R.#ÏØ2û Æg%Ùvî`J”H4~ô§©Ê‰*¡©œ¨îäD­gÔ°RP6)ª;jÇqáÚË QšÍ¿ì˜á³?õfq©~í 4JÕã:p+þlTʱØ\ž­+Æ6kËܿ٘åXó£JEÂk0cIîÄÍP´’=⤿þáïHs¡m8µÃ);Þ¥-(ß"IïFáÝ’õ—ÿü‰F*’~é~í0Ât³ºVOyµ×`ëi»5dhƒY•O2Ì×Åñ 1ž±ÄçGÂ?ÿ‰çw,Ù(ᇟ>&Yø¢•§´P:m½g˵ƪQxˆù©â¥3/ˆç·s<~Ô0IÛü&Z©g©q”šïʽ|M…ƒ‘%š¦?øcï•ùß½Y–HÓo¹k,)œû§$~•Ÿ CÍî¹ [âY×9@»×ÕÕ98ì-Kü »òƒ'vg‘º*h]¯d ¿*Vbú0ïöÖ:ÃËžµ{}Po‡¸û î>]KY¶¤Î¾ÄQÈÙ«‡ÁÝçÅ1ã> ÇQG7Ÿ^Äz"AfÀÿë.Ÿ2ïùâLŸªÎ©@S¬ûq¨f;bÜWÒÄÜjæ%žÕß¶&@TÅ&°½ð{ñÝœ¤hË‹Ÿ=ÅóÔÆ©—²™2Í 4åÅ²<Ûöâóòv òwt×ß!Ëëpþ޾!ïÂù;(rZfgÏ–²ß˜§¬ä³Š[‹fŠQúSuZ~ =-¹ÍÓ"kk×ï*YîæÀœoSïigÆÆ»®Tv9â5¥o’Ξ‰Á„r¿Õ{šz“õýríhR×–M±1T³¥…ë ê–žŠpt÷ýz2P»Þªë}šrb¨®÷ˆ¶#MUV9z_“j(‰”‡Bò5©3 Îo E.áb7¯ü´àÉOËp˜¥7¯Y†ÈúdÅ#Þ?YÑq PuN'’õAMNʲOS"¢–š¶øCñ•ߨžešr ÀÁädªäHòEˆÀì÷mpóèéÆ/gÅí‡ßr3çë¼e…/Šñ^å—ÒhÊb]Of©ó)ÿ#eÉÇ ‹2YŽuf5T7{Т² 6ñ|±Qç£Uô™)ÒÕ®ÆÓ¦®öŽómPû—ªIšòRu©kR7ú—¸FDµe=­þ%¹2% ¤É}Ñ]I/¶7ªŽèæökßó&ÑÜ ÞÞ4Ý»ƒïÞ,ž†Á6@ë€6ŵ¾žÌþù'¹ÀIOkÒȧ¥ªÊ¥uç}¹´N{5@è,€ëeq­Þ;Op‘jcмՈ>){gÔ%!GS‰-ee{6`Ê€ÂSÀo[ïÖS€Jë(Z¿Z4å*莫 3´~}ÍÕf+_ÐW¬¡éš¯ ì¡g}©j=•ÖSïò|O}Ýù2»á{Âa¨X%óh˜°»yô{W6NÖu/Ó)lœðÅÏŽ¨Å ¥VV&Þ ©¯›Ò¾¶®f¦àT\nø>Œ0qã žæ>ikù÷‹?tW«´Å•²r‡Ê%=ËuºÍÐûÝWΨé*ËÍŒ¨a]”û'¤4ÀFב:­ç}ñÆa:‹SåyZ QRõYnÿ©Ë“@¿¢:=ËÆ—:tE•lhŒ{EvtüCmýM]Qq/šÅêjù:!´Èz¿ž^˜C«§Zuh”ÚÂvÜ3(¼¼P‡–Ó³a.ð%ùŽ­”e_XæOÃèû—xÌò@£^þ“êïT¨1GS¡Æý8T¡Æg¾q#üB~v½€‘Æò~ÆSµšn³.]倵îÇ^åL~ò‹67¸§,c‰à#Éúbµzaô(cWº·1 òÝ®CÊwºglQ%vmÇ9ƒËX’áuÛ2.)L•m«:tŸnÃûÖSÞ·:4uŸ¾Dï›fÉÎ?vtÙíˆÝY“;¸R#9šŠßUÔˆ&Ùôi;~Gtñ±hk¶.c§*:A¬ÉÛTÙΰdìŒÚÚæõ…NÓ8åmðè©ü¢}ãj‡²2ÒüÏŒÍ>N溼h*'`?Uבï|!z¾X‰:9¦ièz÷u1jvÀj_ãéS]ƒxˆL9>¹ÂC„Ðh-WÄoV¯$l,©ƒË­Úaþ¢…6ÿæ¹âaQúÓ+9^ åj„WN ‚º‡ÉïÊ;·º>šŽýðÖÕaÎ])žnÜ­ijÇo[W†Óe×¶íç?_ñ\éâÎÚóÔ¦¥Û´ºië õÞ"\PKÓÜ7 ÷SrÝxd í¦N]í^ï?JY¢<ì´ö>Ôt¢>ÏË[ßt]© Ôf˜ÒºB3 é¦s?‰Uß¼Þ4žLXÒö}G]}¼Ñ·«Ïƒ{b‚ŸÚhæe?ŸÌóÕ)ý¹±0ʯ€·04ë´•:tÆž ¤Ë«µõúþx\ Y\‘Ó‘.sIVÖ^sÀ‹Í`ÁíïLª¸o^é®,Z"¶5Ù8©õt“ýâO;7Ù§½ÆÀR„VºïcØÖ;oŸëÛ™ïðiôø³´"˜^ )Fµ¨ÔÔ@Ú`½ÀðÔ©ic¾â´ŠÛØÖfÑ.æíLj%/¹ûuä$¡bgËÑ”»‡¬F¬IožàX:8 á¼ ¬êæFT«Ò­·cšùÙ<=®©F¹§†)åLÛ¡õ^áJƒxƼe¦¶œÛÓ¤›®T®÷¦°æeÐ\B¦){¤VÏ䲨Qs,¸B ®FÒ®•&ÎÖ"ãLæ4Q1Fx¥„³¾åªtŠØz¢ùðø† #xuªçâÔ)|âiDËù†ˆvi]LVÉaKÆ!­“¸˜¼ãV‰Ïö"‰%»[Öþ#^âã»À«ôc8eÇ_jÌè[LÓ»Q|·¬¨á?⣑J ¸ô›Mkîñh‹Â´¥ƒ6t5r(Û~¹¬,Œ½‡ùããE”È-ÞïÓ÷e™KTâwãÄoŒÌßn$~»–¼Šø˜dácˆ¾,²»|µ{RÍYÇf üL¾ ÒQwÐJï$©ãa— tDzóMôßD7]¹&SÜØK0:3µïhª˜s FSÖz}«ë× u¾µe¶áýS¿"ktròóÇ¥JÌ‘\þ<{4¥ƒÕò,]Úˆ¥iGâkjÆ„ew|˜ÂKsýUù(•+ßõö9:ˆñJí’íäæõÒÂ2ùû¨ÖóÜûRb´cÚêK© «X§{S^¦a'!*?†¦¹ý3#È éÚ7{l.3v>2†m¬rï–`*y7ÌYÜ/8¹b|r=.2¡ÎÚë›–4yDWbO(Vã"ötõínpÖ±'ñh‹Â’ä”PÙI ;$EJ£²“©ì$è ùÄiÒ-QéâÐéº^ŽÝ >ÙŸ¤²M¶:Š^¿Úa`kÒ CÂ׊Q'•óµ*WÔL¶î†¡#lE½ÃkÑNìˆBdjíÛ:Dš}¹ !¤ÌœBµ§ÁøÝ¾ŽBªÅ#Þ=ߦïH7Qù6Ë·Qõt 0•o³æ,|¦*ßæàH÷ü»Ê[ü4úñüOÿd‰È!)ÖPÝ?H-¯Ÿ¦áC~õø%éýbýrüÎçjL³ò»œ÷”e3oÌõððs «S«€N¦±k÷4È~ÉïøÑØOÆ(ãì?=û—>ùZÞ•«kÚÊ×û«°%†Ü’`7¢MÕßÏS÷kø—tBò¹|±nµk[Þê2G‚»cêøât¢×ÐOúyi6&Ú±RÂ$8*V©X(¸¿‰ã2÷q™(ý4¾<Ï”#ù4®IH UŸ%ì‘eÁS>¿µb§Ïâøã—0e^Fð Ì1›²ŒÝ±4ž'«Øgÿ;»Š§S–Ú‰5üñx€æ,#›ÏñËŽÉCsßTäÅ3¶cÖB|a ×õÂø†DgMSƾïØøogÍö¾žt:Èa¹²Ù!ð3Á„: KYvóíD»Ì žXð=ï9X(¶„›Ç?Y°kfÅŸü¹›oüÝD³9ÿÃÊŸ}›‹?ßW ìÓ|:Ý9!§¹²7nd&F>‚ûø„ç©›.M•úw¦µfÐ|AP {Ñ/R¼>®9þ…eþ·YÚ®í»Ä‰í®•ØÓÚ] ±'³ŽòN}-Ŷ£€ÒqДbâ* %(Åëã* …“Aë±hép s¿”äiã0 üdük<þqâì±É3‹øϧ©?°‰Èú:Ý´É<&ìn‰ÅB1RV´3à'E’N»®#ï5OÙ•ÏUè}ü_2 ÃÙÿ¢ô§øbM~9/RÚ?…l:ÎO¬ØwU{cÁ\œ½§[+æd¬A}‚Åb¦+ÅFî2¾ùÏXY<ûÅ¡Þ\wIÁ=·wI §¯bó%ð1J_Y’\3,{ý&ü{ŠÇD3ææùvä¯Óßœ3q½Ç—ãp1Ÿ¦þ$Ï…Ò(þ ò|µà¤ä>  Î/碄çD§óÚžVÚ)^®/Äý:ƒï'šÍ’ÀmGÎ)À¯¹íëàÛ×å1J!åÔ1Ë}ÂGé)Äê'™ÙÓGƒ÷ ?ÉÌâ^:ñƒÐ%P´K§¸ÅNÃè{îõêFº4¤S„•JâNç) ìX@¢<²ÓøæËOï+IÇs•A)¶)ž–*ƒR¼>ž–*u'q•åiß Ë’2Û´"ñ1a+×Á žÊ÷V–yß[Ebî῟Ys}@æx÷2Q´‡{™(êý°îºFg‹} ç÷z]‡iö>X¯ócËlä&ÿgÄFþr÷‹fÒ?Ù,ý9Üò7H5Ý•åÌ£ ÅVÞ3N±¯Ÿ'£0Q%?Šýu°Ù<ÏýEL¿ú/³èn†RæÚi­‘yòw+êL) µ"ܹ#Šz"wDÑNä]²¬ï¹Â\y‚©ÄOñe¢hŠ/ES|Ñ©üó›ÛHM»Éw¿^ÿ2Å%y÷ëôöw4’éP‚§¢2Q<Æ^âå#ÊDÑVJÛ “‡wáS¸Ä%™ÃWᑜ–“JmƦíê‘‘kŠ6~@Þ}³Ï!¾“¹)iÉSÚ”´r+SÅZ(QSè?ËmIõS¤þf›%Ã,ýª&]á§$]áx^9èêÒ”$¡«,•g¡+ìÑÌ~•*–ݯPEs¢ªT¥HíŽÖÙvxИ¯š±‹è³?eXö}”ÑVÚw+C¿)EŠ„´gÊ«ÀÛ3ªhÛáDO£ÿ ñöL…*š*TÑ$ëÿï,è«i³dµŠÈ=8 :Zo%0G¢¶jÎZxÜõÕÑîÔ2céHUn <†2?XU~*° *€TøáÔ U)æÏ V¨J‘¶A¥®çz£k ³þýv™EëRyL3Ðßß••‚ª®ÛÜD«í’¼^ØÒïÆ´t‡Ú8ºâ(Xæº%1–ÕŸÙƒ§¼4ìÓ\PE>ÍU´Ó<5îÒd}Ç&jÆC˜Ñ߆ds…Xe5ùPÅëy×÷7ÑÝ/Hyã*«EÏo–áª`„Õ®Ze•OI§´<°ÊìN CwçÅiV’è‡K ”'jçå†ñ\ #¼û¿¼”ƒCÍlÔÔxm²(~xŸÌÃÚo‘Œ)7[Ú’£$¢›A¤Ø‡­)JÙ‹x×X…ª#^c9(îÍ›Ÿn>"å® šÓ_¯¹ù„Eó÷÷ï¦o~/nŽ »9®·ñç¼{°ÂBÛ”®%"3×A”Þžš¼4£“`¦–Ó1¦GÂJå96rƒ +ŽA™¡3+dÐ3þj<j ãìlÖîU~ëÁ»C+TÑ,j™*ÞR¡*Exw Í`Ól)ºˆ¬Ü4UTßUÒâíÉðC™~òËø©À¸¦ ©Æ^uIR•=Ú¯‘ÅÚâ5²X{¼ºÝXÀu²þÊ\^ºáv¿ÙÿIöM¶Ä)Ì’Y²d¾¸µûûâÝýßÊb?5Þ_~ ¿"–jtÂá—0\¿YFO!^L ‹ó÷æ6X =Òk\(âÙtúîú ëï”óMÌ|7|ù: Ó'j%q vjÜ,Âm×6½Ûöš^þ“êï¤,"‡…šmÓ ÙŒ‹ÉÚl£—ŸµŠÞÛµuP\¥ëeDÃ0Í~·&^Q…lÒ__§áœüUÈ9í”ù¯kêà±®§,ýŠt·×øxe>ûNh7#¿Ú¬C±©¾í,õ 3ßqœ7©áIç§4ˆ7 ÚUÄñ› »4âépˆéµ²û€Éf‘.WHÊÚÒôý6{Gkÿïhé’â"¶°¬n.rorv˜Nñ›çÍ›mö˜¤Ñÿ0žä ÛÈü‚Våè^Ëå}0ûÌŽðÝÛè.×s¥î5OßÔOvÓ©»Áê“>ºâ·Å–,ŒNe“F-‹ÿضx9ÛÕ æsºÄhÍ‚,,Ôš}eóŽ$]èÆ¤ýŒìÛ©Ôd‡Y~K{£$5úÎάƒ”¬¶Ôd9Ý®×IšI¹2‘ÓV‰{{DU‰'–bÁ¡ÍÓlÆÕÙ -ãCáÛd­sôlƒ´ aà=y«då¨NÒ“uܬñûûw15²hò­’E“oŽZó4šßÄOXDçô?þ6üÙj]¼J3Ѧ0ópl—™°w4NÖLjŠì³¿´Ð·ïÞ'²»fvvMK¯™9Á/³pM/iMÏ’ 5LéݧŠži¥-wöx¥®Jn˜—f+m¥rC³øuºX&¿NËæ›4±Fìåùæ«ÓE“C.šªSpÍBƒ¶œ5£Ém)kÆÛo5º’d,k¿¡:³µÒܤ#Òú«<ޤ ¥V©/¡; )o »ü‚ìJ˜:#©µ0uf ªaj,õIõ÷y ¨SÔà¹Ö5¶]¬·»¾„ú.V¿<›\£‹f“ktÑlò´ÈÕˬ©o0‘f2jŒ,òmò?È}jIßG®eª1Sa™ª,%—ðwq“PÄ_c…ç•ÖèJ:xVªFW’ð¬T5¥¥YË$˜¿M“½î4}—‘8Êþæý޽²à>Õ´¥( ÷©Ö -eÍx£FWÒzqŸT,aOžùF¶É‘Ò¥æ#y ’wÊ?ˆ·A³¡ÈUSæªð–ü¼ò GØÖõcšÄ ~­AkÛ5cí;kç«Y/“”<^¬"Ý^@‚PãXÂqP[ðwÜwž¢"j„ñQ#Œ¦Ög›üÎü "šEß‹h?>Ey¹ucª ®ë ÀÛcuÂh{¬NmÏá&Y±$)Nü±¯ –Ì4T­­#WÈÔði— -®sv™Wœ•2s/?sg¼ì5ÆîÆõ,/+zSÎ’yx»ù\is¤â<+Š£ÌïÉ7ù”†hvƒzÆT¥d/.hÐßøÛä?t§Óz‰1‹6²¢MVR Mv B ¦hÏŒ&e,»× Œv4)K“Ú-`ÓÇn9˜†·æe´5†£ìæèTäO‹ÓzÒxýïþÍÔõïÈæúäk…ž§ÿâ#Ne§=/dîöC+ÚÐf>.—ô65Ni~¯1OÒ§o(,=ìKŠ(¾Ú<ê×Lˆô;0§`>”ù;&ä‹’ßøA<_†w&EóÄá·{|Þ°éd4‹aÝ'ɦìUû#[Á…ÈKw|šøMhÈ©íBRyÕ.»¸ìZž‰µ¸‹ù{má´Ýœ—Ì3Kžu¬]‘{Ÿë {ôÃÍ,Àœ'àì@&«ÍvÅ7æaºA[ŠKþ“¿v$‡0ZÉ b´1“Æhc¨ ÑÂ-”ÑFËä¶ÐF»„ÚhK” Ú5ä–ÆfípúMòD,ÏÄd‘ÝC;xnöµÉæ1Hù¿ÎÒ[âU!¥µ®'·¶»EwßÍÔòÿ#mvz K]“‹<ÆòŸŽìˆàHã\\seÖ²?d¢jÓ åx­‹¥XÅì¼`öÅH ÆmÌÜÒføn’åS¨h;èE»@üu¶$pÐc¡›MIL‰ì—ªäaLº¿U-C+…؈uØA]SuhñnâÚo¼›¸…¶D™àÝĹ럆´åÔ_'b1ïz…ˆïeYÙJ(ü‰¼«°ž9Êé “2Íþû ¤„X c¶º[Ýá siô~³Y21ïP‰$©À+m¸›/æÍÑNJ+q¬£ÒJë¬x5|—/Y°¤ÿ…†ä"-i¨º#סécn[‡®‡ô?³Ì/2c³e4 w~r³¼RØ`c¼òiÿ~»X`)’êlE'zÐÚ•5WÜÈ;a»äϧôëÇpMtlÎ:×sÁÆâ¼4üÆ_Y9¨TuΉ…uTÑ'[ê“]k‡eIƒÁXÆ·ƒ:’õí Žd~õ Õ,²ú+vú´@k`p\¶¨½•b‹Có*ª´éCÞ`s4Úáš<_È“nî÷‘? –K¤ð§>ycŠm~ â‡0‡®Úܬ>6ÍEôq9Õ}$ 4Ê7£Sf£9ù:³ÇÅåÉwýÛ_ý··ï$}}²«üTÆ.‰ŠÌÜ L?¶âY|Ĺšõ ­ç Ê Ž@Þ…emÚÚ'IâôÉÆðó÷7y ùˈ4/|½ËR›áqÏi«÷S”þœ?…oøl}Àçµ¥Ø&ƒ¬îÔ˜¬‚ÝTÄMûzzí’ÖfÛµŸ,äÇ4ùËòî—JÂB×*"/ ôAë ébØÕÁí¢î uSwǺªµ ÞìžÃ÷_iØÞ80YºV |¦¥dxw®F½HY+׫8蛦‹>֮颵môº‡—»óCûxz¾áØ£q×Þ¶M—|mHiÐÝbòÝO~ýëzƒ¸ý+Ô÷]R¨j§°¨“{5o“/üŸ( íq³rz(‹5JrFyG*£(×8–†V§å9ÛIv»Zç8Vh¯‡¼˜¡By,j[«_èŸzl~UÇhÁÆYÖsH-ȹ8W» 21fþçðëÆ_¤ÉÊÿçÇw»¢=”ü˜n²SUÈûSBßàèFÓ“4.–Qnú8Ù»“8{Î Ó4Nü,ñsFá®8nÿèÁaóÐDK…Ër¥%£úNÒ÷Ùg笘ƒhe“lÓ¾(òRVÁ瘽årWë1ÜRÈ¥ÁŽ©¿}³!–²ñƒââºO¶ñ< /ZjSiIæy-b¥c}F[å7ÆNn vRqîP«åŠ^†ñCöˆÅ “ØgÁ²hæ‡Tµ…ãKL€ÔNÑnT·¨*âVv±íFã©9¥mPrxž‚åË[söÝr•oâ赧äD1±ÔC$‘ª„¾©©‹G­AK0ˆ­£ ~³B“·»V˜ÒØTžò¦r¿c6Qή,JöÏ»C*³» ù%M`½æ¦†6y ¿Ü¥ì>"{ú'ÆFèj›è!>ø}Uåït˜àZŒ½$ßzÃÐÿþŽThIץςål»$ŽñûŸ,6 ÉÓiÐŽ°Ì%¡l­‚löøfõ?E:m¿S⃦Җò\¡‘vFC5Ñÿ„ˆ[¥¨….ÎÞP~ù˜§$]U¦¸µ®¥¶’rv©›¿úŸë Nâ]†êØ×Æ*56òaιÏIKò˜WNAürbån¢šïT¬<# ™a-ƒ¥p²tç9À^Éœ¥ëkèÇLþ”ìݳ¿\-QL¥Q¥XO%ÄGü¢§&”ÆÉ8_'„ª‡µ…ŒJ°î¾ãE ƒP‚ZŒM«\g 1OÁ=ù:»§jÑîTËÇù–fû•\ –!>” “y㛈Ëè1ðéÛüàÓßÝD YÏ3Ã:v&>%É»„úfrxÛÇxÿ½xkIŒ%víLKZàœWíwÄÙKE½vux‡7)ú5¶­´Ú²òª ·pƒ• :Å)'T{j“¿›hFþ0 éïßWK÷ ¢Q¹c¹Díä“% ³zjù·t6û”ï-¶ I"ÞÍá]¶Çô•'€N~XßœiMÏ«K§YÊTH¾7#mîJWe·éáÿ’Iôî&4N|L˜…z˜ËCÛ˜zx_qÇcÕ0Zˆ*À<Õ˜ ¹Æb•i³ÅÿJ#bƒÈKIÓÒ䙎ӕ46:ñSh.{>gñ²ÙVÏòx=Ó_úódKüðÛùÍÍÓ'—š›è-yBÙtÎp‰ÓüCåüÝ5ñƒ4ô£8+4{Ûà~C•ðñ—OþÝ/3”+×R¼7Ëè!V·/W YÅmÔ" ¢ OòÎX‰ù†d¾’ù—!™Šù&£¿!;üŽlðUnJ{_ ÷§œ¯»ËçZ¿Ñ¼Œ¦åÎûÍí'òÀSh£Ð®î6ÚXWym¬«½AûYÍUüÜ¸ŠŸ¥]ÅÏ_Å þНâçþWñ³äðÈRªW±ü… x?y?y?y?y?ׯâg•WqûÙ]Å•>ŸÉs¢,Ü{­Ý0F&[t¾Šá-Ç×à§«å‡ë• £zAe¨.Ðôë& WŒ°IQÿo¢.ñÓ?wÞ¤ï¢ X?[€±¦e%´Î2¡£”‰uMÓ¹ ä¬#g”‹¹x;çu~>Ã9¿Ü|$ײD†ö"Wr×Ï¼Š¯¾[ ýÂ5{döòX?·KÏ?n2<*õguR.KýYÔË{‹Xyü½]a £2pƒ÷á*I¿îÞ†yá ª=?ÂÓºaƒië=òþHÒÌß0“¿«¤•}ÛZÌÀ«µæÏCSýÜ?N¥lO]ªøÈür·^Âiºé¾*i˜ñM³ã߃¯–Ñ ßuºJÊ³ÖÆú8*-åpu²÷ÐÝ/SKÞjئ;¹SÎVª·Üê$GÔïé,˜Å\ e°MÁ_)×½s§M®ƒôSDÙ&OÕ2-ø‹eBt1¿¹‰(Lß/³ÿDxšîÉ04ö—±¡6™'y-(y®ý3\pàhÝýú/â[ú¿¾%W¤oèE{—9‘ÇÄ6 &šÌ…™ÝJÐEÏŸÿ»V}€è<º’ýkœ±¯¥!UÇhŽ®ÔÙí8̬ÑŽÏ-ZzDKÏÇ´ôÜ¡%y1£+-iéY‚–¼âöª<îÛ÷®ô'iUEÈaŽ“ç8¯,ŸÉ°‹öÎæË¹ÊJäe\\%ò2®)û§ÛÜ~šîà?'˜´½÷Áç0ÏKóíÛp¶ÝdÉŠî÷Û®·ù4uð}«>+Ú½çòEØ(‹°êÔ-}8íF[›Ëp³aµôXÛæ8¤Íc_?¦IœX×Ëdö™e5ßdÍôWÞ]΢ VU•™®–NªDquàþ´Mƒb Ê“ …®œõê’Ö+I¾È›á@w½m¾Kˆ­s¢bæ»òÈû¢DX–@5X",kÅ«ÛÂÝïL#wà³~'“Ï’v.&о‡ç]ÓXÎÛ4¡SáZñái“{Dþîiuƒdákx;o_C„ÉÏZ§l6k#ÚGÈÊ¥œÞn—ËÑJ(óþ”()šÍ,ÈaÙœÖÃhG÷Ë¢Ùeò@^µ7Q„Õ6gg uGoWÄÅž-Ѻñv]áÚd™ó÷É|»Ä›L²'®=„ÙÏIò™:P¼']Œ[«`¶£îdôŒwó•Õ¥¾ç(k€ÞŽ5[&qˆ«Ì–ÛMÜ5"öÊ–h¢®Ëjîé!ËËnîèa6¼î ,˜ÚMäiÅ“t‚÷  ^Ea“®Z :h¿x\‹0›=2€ÉåŠâMó§hú8Þ있].‹œ¸]Öœþ C)þ-C±üÙ 1)Ðõ]µu…¸) ëùq”,g«øÅób72ø6£Óo’T¾òI,ÅÙËãÜ¿…³aäH>yû+ùG·ñz»ƒrÜýÙ¯[úg’f¶ìÖLæu o•=_ö}Û%ƒ3Šý4'yÝÓ¼q^c;>&Ú¥FÜΤ!:4ÇþNî~¥ÉEö¾î¹g密½¸Ûu<(sɆÃÝÙU“ÍkÄñÌ´ã`…õZhÒ¦Q\Ú³Çpöy³]uíN‰uû5ì ,åßw'XIþž›~y»¬Ñ!ÎwŒ=bÓ‹Ðå õ¹[¢Ù€ïëFó–Ο æû»Ds(¡µ±Fç‚ØÑà ìèaþ‘Fó›ø m};zXë{ÝS´:´ ÔŽòúÐä·£‡µ¾âŶŸwô°¾ïŽÖ÷} SVG‚BÍ%ÿ{—l¢/Úd¶L6áuÙÎS¢ˆ±LF‰"úFĺJÑ¿5Þñ»þõîÆóîÎðâ‚ÞtŠKï÷÷XôfÉúëõ㶘W›iÙ÷Ý*çáth¾BI¥Þ'Ɇµ<Ì>ç ûºIS|g7iŠïí2͇m²ÙdÖjKìŠÓuœ>Öúµm‘éS6Ìý·Òp¶M7ÑSèc—>¼°¾—Éî<â±úð¶î31¸a(¨œ—•=ÒQán)ûnÎ}0÷w…—Ì7cˆsâøn9O{Ï|Ã,ˆ–,s‡þ}°Á(jèÃk_炵#:¹Ðù«ù ÙŸû‘ÿùÏ~xg»21žqÒ–&]7ð¥ÉS(×J$joòTÅ·4½sHG}ï—ƒ'ée4Ù5(cI£)j„÷I'iy«FSb iyÁR£®$ 7É6…¸îny$Át‘GŽáßG佟¤ÁC¨1<&ŠËô.Ò¨¹7ÍÇg£³«Çzb¸Pw…s—¿´ŠHà Œ«­DWµ’²›©le6¦ºO~©Ëãhð}ïS§´ C‚ÌÊ‚~Ùí‰ÚS» ¹ï¦®ßP)a]–èº>L½’è,¤%šþj«…q»l=>ézÚ Dèx‰÷SûœZþÔöW(Aåèg³œ¨*œhèµèÒÖbò©éöÇͨ—Þ,רn/ן¾AV©Ì¥ëgµô§Õ²qX…³> ҥ,è>ŠçÝ‹ÑÚ«µ)Vk)!"ߦj“ÉmF¬ò*¿åˆ±·)?»ýDÿÝA:Ó·tß'Íÿ¤ûŸ ÿ¹_È'~ò=Ú/ïO¾uûÉò?Ùþ'ÇÿäúŸ<ÿÆd¨ª7DH·þ[òùéÿןþâOßùÓ÷þÍôΟþ/úÑŸNý)N$ ¹§6X§¤aÜNÿ^‘F~³íEaÞñì¥Q’à ‘Ãß}*ŠøÓŸ‰vâ˜~NËv,O·í¯ßލI‚웽$¦¿údw #¨eCD§·Ã›Ævp{l‡ŸˆÞøD¹nÊãëç!v¬§WA é¥e}ó°”²EAJ‡©6ÿ€†/¯ý;_xÕi¨’ü“…7ðݶ¤b=% 7ãøõ5.éŒã†zÑ2E½„ÎNRúp/˜¨ uJì_aHÄYçÅDºUü"¯Ýö73rÁÏ}¤Q\½Y!ö¬œVVÛXÊ÷:Ê é›•Ð›þH{>/`cŽÿÍ—;îj¾ëQvHßΣõ~Bü»Û»·OO7ù<{ߣâ/–ÁÃh‚ئSmS3îÙýy8£ÓÅ›넉“J ßýò(8KÕ™fé?3Z¤ž[O×Ë()B6ec–¬ÖAúñŒ,^ qAícÔ—+áñ­;òf–¿ò£èÞØ‘³–”fm¦ë`F³¿„úT÷Å›höH-âÑø)a3r %l"~)ÌO©%`ȯ¦ô’‘@ßËÉ¿ßú4CùÓ,UX/mB'Àá~‰zM\'ë¯ï©K&Å7F"‹©ñ>øòK(\[ÔÁB',~ Ãõ›eô$KR”ùåŠÞ}2yüs¦oÂXxXDz6¦Ów×o®i[¶$&f¾­¾|†é1¡r¸PóI2(ƧÄ3b3kR´ÇKæ35(2R?Häã0œ­ˆl±ë0Íh•ˆDF¿îRMÃ,•uþ½2#:È8ÙJ:>ú„Ùä8Î1ƒäóú”ñf¦ï“8"öõ½$^Ôô¼yÞ¼Ù&Ñÿ0A{-éfcÜò-ø.yˆâ»`³yNR4ÿ§…[uþ.I›Q·*Ç뺀“wÌj ß¡/‰ ]6cð"NëŒÜ†dÓ<’]“}¥cäð4&í;f'^I\õÝ ¤Áš˜Üó(ÍOþt»^')ÚÉ7óö®çÝœ!šÿ:íçÇ@Öº­ fHäÌÃ’¹.i®Z=+‡Knáéoç%u£1Ûù+dƒGÞ˜Ù® ólè9Å"o]?¦IœÈÙJÅ­$Wë“ò´ÞZÆkgO—úí·³éÊt-öæÈßÄóÿµ ÑÜ'JÛ"ç(XbŒ©*uØPtñè5’ˆ×Êž$ží¦$)t-¶†Ð­¢)´ŽG4üoÄ}dç6ƺ¦™W#Nž‘ZÐuÚæ~ ¦e uߣ‰~\¥{—Dq¶c²É‚ÕZ“\ü¢™¯.êËL&õU„H}ÏžE<Þäx»}7 Ž>ÕQ\"ÒWÐ-º3ÖYZí;Âp.e¡’Y3 pyësÒ¡ "­°gL3M߯AúÕÃ:|ŸÔµ£ÍÏá—àæfFÁÄó/‡‰÷;G”žâj­é+1ÌS šscn0¼Ý#ù ÊDÓý÷>Cô—a|#žXŸnÉ©?KâM–ngÙíÏ÷â­?ûBüVß“t,ý¨˜õ{K’埻Ù' ­@L=ÍôÉ"IŸƒt¾ÿ·~<(^\±¶©î“Å™Šw7#œ'”³&³G¶A®—9T´Í0Èf=¤Sê}“—;Щ["4*½©K¿çÓóåû‹`I‡9‘ç‹à’‰¿àÿDÏk5>y˜Èúß‹ѧ9Vþ*X‹”ç]‚x©7Gኌ.Ž6›òÊÚb ¿{Aw/Bž¨ð”%ìÝÒDÜ`-M°MNèâ$÷¡½Q"¿=/|HãHȧÀïþ*y oßÝOnÞÝkô–±Ó ž'+?˜ÍÈã r×ܸ»ÏÜ>“kû“÷ËÔ W7¹ …×£û¿± ¥ø®­.‹FÔGÌ„ÆÓgúo÷eç„©fø´ÐóÐÒvÇÛ×ÉÓûíÐ5ºÈi›™Ýfb7§™äzûþ(ýÐ^÷Ni^ŒR°6!’(ÖI+U<ÿMüÕŸ“wáWzãºþûzÛòZÞ½]Rü¥_f«»Õá ÓöÚ÷ûûîû•DÁú¿* L6§%ðn ßÿ;E#z{÷öi_S]ŸtÇÀÆ*SرGç´\–ýDÎ=]y…î׊ž—;ê³=&Ë9áÌÄ8}[1ÿ…A~ñwÖ8wB\ï‰ Å$ÖibØBËŸ"h`º e¸·…toÉ¿Icr~ß•}dÝGƒë„Üd_oôBÞHXAˆ+"g&Y , )+/Ζ³,ŒS'aY(—˜€hæoX°þ~» ¯QâÙÌ⯤A”mèË™½Oq”ÓŸŠÐû³Ã¦]Ö1ó”Ú8^ö(åfŠ¡Wn¦Úu÷f>ð6½}}Ü÷|Ö=ÖI‹ÇÚî;‡˜|ðà Ó×U %î=]÷àé^û9ÒöO×c/¶¼Uô—²ß’Ó–"ê²¶}YêÍ’ïwpgKݰz§;kôqg»¿æD´ŸªãKóO'Mÿt’û§7—úrµä¶Ò/EÿýIoõfç­Þì¼Õ7>ë¡>"Cq‘H˜ÑNÃbȘQyb_k7¿ '§ëòÝU’:ú"uôEbè»LAÏ=ÓNä^zﯷ›GŸ úÁöËí-Ë;Ó^ÝŸÖ¿Šv1ö_ˆÃr»HO¦»WÄC}YáëöHx^µvOd dëWnŽ ?3t7³».7dwQµÞ°çZ7Þgìh"‘üßýÀ ¡˜äô¢èó}-—ÅÊÎdU v^ƒ©Nõ‡Ï>Ù+âKoü c‡P<„}гÙÂy‘&q†Æú[i·/lóRMæÈÒ%j§AÁ&ìÒï; 4ù;Üei²‚ã÷ÕÒýÌC6èž°Î\VÌêg ë_%n4[ Û+NÓŠ0å±çÉÓ©b€|¸ùZZFÿ^NnhøŽG_ÆÞÂ_Ô9nÎ`JýtQ@¨æÂ´]§Á§àAsªmä½ãpèý{±J:}—/í 좿]¾Èímá`ž“æ³®zbj,R¹kò@é·Æ³[!ªî[HØ«sqQïܲ5g}Ö4Ã?ä]+z=õP¿¥¬„-+Á»õ\ÿã½Ï¼ê“ä;•\9Nµ±ØÄŸ†K²0m“±W !° 7›Ûb§³Gøä Ã›»_XYVÁ‘Èkž‚Nÿá³·ù¹‹(–â6"„õd/Õ%bÏW{G>`TdÎþ…¤/p§éqèoòÔ»¿i¬Öl¬Öì½K~òQœ.Ô•—³‰)çå~±;àoïf®®·ñçæ¶(-w©pµ¥ZÏ})Û¹¬Žbkc²WÐruS$UŽ>7c]cPB!÷,–¢ŸÍR0œ<Œeˆº‚ÓL×}º4æyÏApºŸ°=š &XääÛ»hÂÁ õ|j¢ï°ÚÛí<D ñZâtk@Ÿx‚0oŠ¾ÊŠ$QÃõD$\­FAÅ´Øm؄븘”sȵ}g$š”-º‹©³~ôlòJœždA·T   ÄÙYøwÉ,X²Š<Ú ìU<™P=ßÖî–œŠ·o}Å“ŠWöX¾da<çhK×'»½²C¤ý´ŸÅŒA^«\0èçS׫拺¢[¬È—Eÿ•ÒÇ3}ÝâKßúYùÙ(®DFÙaË~®ÈÞÞ-¾&ÃäãF…5=ç•›ÛÙ»•5™ÜT8ŠûŽöŽžNìÜwE“ÐZmûªJ4‚»X#Aj·ÉãŠ8}Xδ»¿)ºfõ1„·™+\:¬,7oj Æ p°xD;PiFcÓÈÂ[Ű9]kã[ ÞB È×ÓÛÊI·,‹vR-ý2AsDqià¹N“¨©Ò¼s½9Ę•;Ð}·Gi˜ÔñȪøDùiH®£Nï}NƒõšÂ_œÖA©!MœD^3›Èkf;òZû7µZ¾iez¹”/vjöºM“a‡5[å5K~“Ï^¿nÌ^ÿIöê—%µ·»R›Æž3›{Ž‚l¾•yZ÷w£æÿÎ 4Îï+Eœßˆ¨-*þ«èû˜|*ÊÏTmOÞUÿð×-ýÃò7·Nó·D—oüݯ®w¿:O)<­–|ß®¾SÙ—¿[ f±´Òê¼,ÍÁ„ä¶ÿºX)ù/ûN˜kµ OÂÚTqÐ8%Ô—ò×µzP¬kø4ÃÃÍ„ÇÕ«ûB"’+eá Ú#^4R'8OLöþÞ §öý–Ã>8Yâ‹–t‡!^Ä0 žŽÿ¯0øLýØí2cÀí·ÇQM»ëk¨¦;§›Nβ¾=U]o#«©‘ˆÐ–îI+¼Ô¯šÿÂÈ‹ßøâºž¶•ÈÀ©ÕKdÀqœiw‰Œ®:m–È m”È`m–Ȉm+‘Ѩ6Jd°¨ÖÂ^HTñ%ÐR"ƒ@µY"ƒEµZ"ƒAµ¥DFœjk‰Œ!N¶­Dl[‰ Ùj‰ Ù¶²-%2d‘Kd¦79ݶº%2–8áÖ ­%2„ÛKd·—Ȉî*‘»§%Ê­%2”;JdÄ)w–È8¤;KdtWœvW‰ íÎqÚGJdé,‘6UýJdൠe>\%2¸%2âÛ³Z"ÃìèÕKd„¯Šz‰Œ8ÁZ‰Œ0Áz‰Œ&|ô)‘1p¹œ(‘1…7F£DF±'%2"÷AÿC|íÒJd<›€Y"ãˆÜF'JdDí©‘ƒÕ£DFÈf®DF|œkŒ…ûÍTÉ9]gZ%c ›…3+“1EâQ/§NÆ6Ég\(¯$mýrr+e&š8Q*#ô†”ʘ®¤TÆ>ØÍR/Ò£TF ÒR*•ïuH¥ŒÀ} ±RƬRÆ‚;CVÊh›úX©Œˆ4†.•ÈQy­Œ·Š¿ÕÊ[à¬ßºË[0ˆ6Ê[0ˆ6Ê[à‘ÎÑFy ÂJ[Ê[P¨6Ê[4x¤J¶³B"‹/ƒf Êb›.‹mV¸`PmV¸ Pm«pÁl[‰‹ ö®d[J\P–ÛRã‚B·¥ÈE3ÀÒnK•‹+.ÞÖ*„]ÖZå‚A·­ÊEƒ‡8÷„ÛË\àoÙáÖ2„ ­½ÌAÆíe.›­½ÌãttÔ¹ H¹£ÎAÌu.”»ê\0$ÝYè‚`ë; ]dÒYè‚°Gº ]0$Þ]é‚ –c•.ÂÔVºˆïY•.{ú'*]„”*]ˆuWº`oVºˆž~•.8߀§Òç›uWºˆÓ¯Uºˆû®µRq™×J]VK]Ä ÖK](ö(u7}\¥.ÂÜZJ]DäÔUë"t$ú׺ÉCr­‹˜¿€Zì"®á®b=w»ˆÓ>^ì"NÿD¾PèŠɪ`Ø’/æÚÈ Øn‰É1/ OŽ ñìJ2Á·þcL¾Hk€L3ÂŒþ6L³(ÜŽ¢9Â觉DÚ¢“|ª´«!.ä…׈㮼ß‘©Ü+d)թ㊩ž‘)¨3dQ5éã «%¶"S\-ìÖÆKd²¼S4H[ l r­Gº¸øVƒ ëÜw—Ü"Iði+´ØçÏ}•N’·Uò,¸Îåæã4©ÁD ×³‚’L É•ä"Š#‘ÏÓY{ŸŸ³j$rïúËäÁ_†OáÚfF®raj„ÒC˜ “‰C²a?‡_‹¤§¥Mñõƒx¾DXÙUøOHò*èè„Öi¸ˆ¾ç&ðŽð|½ŒîóeÒ)Ý$üÕú넱úK͉^ÿz÷ÿó§äo6INÊÿßš¶I‚59žäÿgw&ýÍÝ/³»hª L¤Û×ñÅ<ÌhöÛ- G#NOñaéY¼ÐüËu"—û¯dé{ÁÌ0“l³ŠØÉêQ¿®ÒgÂð½'oìE_’Î MöÆ^:áGùR4ë:4úænóøÿëC°*m¬ý³g°ÉÒ(~Àg`í5\ù ¹’QöÐCå; s Û¨¦rpåDyÔ4ÎcÝø¹¨,\Õ¯ÈÂf,æá" eþ%“F;Š7Y@ÛQwG:ÊÏôÝ …SY~Ùì!÷Š‹1 Shç~H#ü‡3ý­Ð,“Wùµ“‡FŸœê(ž‡kZϳS4ñè!NÒÐóºFdâäHX¹®ýããôÓkâ½>‡wiòåëu˜fÔØ¹þí¯þÛÛw7SŸþ?„Ó ç.Ý&Lóáæ#ÀbïM}sçß|øÍ÷¯“yé¢ÓÌêß ì^ýàw´ò­3źI ¾•¯û– Ò÷µj…ù…éõÒ!hbâdŠzÝɹMÖ÷„ž»6ôÁÔÊ9ŠX;î‚M/XU·SY¯ ¥¢m(³¹¡~bA®Ò޲뇣ØÖ´‹¨|á”Yç'õÇ0Ø$q;ëüï0YWRõÓ“$ç›-G©Â»uŸ¡&«í0•xcž&«å4U6usG£§6Þ•]ÝÜÒRyW¶usO#ó®nëš!¡ûZ’)iã^³%5î˜Ö¤{͜Ըc«åPW%ß¾ÝõúˆàÛ÷»4æU¹·oxæv›A+ËÓ¢µ2+ËY:³²\1™U_³½œi®n×£>_¯ƒï‰ÛI"çw“DÎ'n&4·çg¿÷ƒ8ccÒÉø¸·…ÀzŸE¹KXËŧ¤ëa,çe¼_À>Öþx ˆõ(CÿkP*óS× Tæ§®A懬×ñ­Ö Á¸‚ ýÈV+?-÷Ú!]vê|Ѱ»œvH©XC«ämŒ%G¬L=| +~ptõ×¼¬çü~m{°â "nÂc<+N¡"žß‘§yÌÂT¶YÇ‹ÅÊ]EeŸu¼¯WÑaxšmi‡îè:š^içÎmJ…mTâp²½ªUþ‘¼ÍjÔ6kmYòv«Y1á%²fŦ”}R]MúÓ½šòßËXUõA{Ý´’±7'-jW$£R[N‹ŠÚõ#u9{׺ 3§f×Ôº…+ R³‰×ÇÔ­1 Ø®àV œ³þäÙ`»fƒ››Iž®ónJE6ëá´HZÆÎö§aÜy¹-ÿBÆÑqª¶®uI]ë‘dïœúÙ}c{mÿDž˜ö&¯Cs…ÑS«»õñESžÓçÔ^e=߈èëpk&¸Cc#l7ÿ™<3ìÖLaÛêäC·áßtx\­ÇKÒ©wÛ‚N{ TŽ}ÇëZÆs®Î1÷K™9rOÛ²ŽªPÂÙ¯®õ~㯄Ñÿiÿ'ûñ8t†€’LÓñ%(É:_‚š Ôñ5ÈÈFà(!3u‚£„,UÑ Uy`´Ú%b{Øåæ´ü+y·›×tôU¾3ª'¾'¼¤ÅÔ³õ{­ûR“tÛz­YŽë¶#@(ãbÛ­ëЙÐ×–UQ°¯'YšbÉï{…~ˆW½ð»v|á_ùEsd#Q[˜´³^ðo$"ÚÎWÇ.–sÀŒIûF®Ç¼eíä‚#1Ò¹•ÕñbiDIëf>¢4 »YëÈP(ÛÎZóêâŠÈHZP)ó)LWQÌþöSµšžªËèúg2öQ=ÌûE_Þêwð<­%-©üÒïÐßQåI2‘z}o5<Óêæê“ËØ]µÌò±­_˜P¥›¿–m>²¼“ª•`HëècÒÛ‡à ­ãßJ{©õ”tç:å™|£3Ûÿ‘ iQmжEuLI–£Ù,~$³¯.µßÒWÝ•d“æ÷u,¡%×&y méáNïS­i7¶³s§··4ëYslø²;èk2»“·Ê¼c³;‰Ëñà“´¬ ¦@—9:RÇ"aU+ÚS[UëXLÆI4÷¦¢‡%§Rêly @çÒŽ¨Õ‘µ²æ»‡+„¾ªZÑÔÑÝvj«Ir¬#…âhà\ƶ³ÚïïÖ±´¼VàuÂrw¸jÛQ+ú:¾È>;N‚¶ŽTCpoÑ×U/Å:&úÊœ£©ge–Íiµl°ФÅímÛ »qÚhH²nN»ÝèÈ0J3µÊÏ“V¶°êíl½¦ðøJåí}·]o]¹4iŠk­FƒÆÉÑW×R¤"ôd’´ÀîÌ_ûƒét _ÆÖ¯cC †õ°×WàØÉ r{”’–x$SزÄÓÊ–s5˜ÅÝÙYFƬ•Yô9&ù1ÈA1k¥=–Û[Íønf7ü#o }eõB‘“‚”vÝšMˆöSñyi‡¡µ C,.ƒ¾Fýtð”ÿ™…¾ÊŽ,ÞÑ04µ¶¤]®IK=kP&¸ŽXî Ç\ÚrZ_íXWúj;ž§-­$ùé u…À¿ºJà_]%ð¯®øWW ü«+þÕ•ÿêJuÅÀ¿ºbà_]-ð¯®øWW ü«+þÕUÿêªueÀ¿ºzà_]=ð¯®øWWü«+þÕÕÿêÊu•À¿ºB€Õ:/™«„yžèÊÛøªh.o㫤£¼±„6òV6ø½ã­lðÆõ¡àuµð¿ºBø_]!ü¯®þW¯ Þê]ø¿Fõ/%lå¯zÖ´ùÕ[¾·—X׫*è@6k+C •6¸¶ÝPX•¼*-o-KéP¾÷YXm“ÊWJ«ü YñR½†®ÚX“¬ÔŽñáдáêÕwª¤ccÔ6k'°Š“cÔ¶k+R›`$lX³¾aO@ëÕ%oךõ]«X¯Àðê,¯ð[˜nhR¦jdíÆßËØ,Ví5—Ó¾Iɪ §€±é¾JOYYÇ×#pV¯"àvìž®ªý³>¶ î $ÁàØÅ:ZrJžÅÇ ä}|ljÊÇV ãÅ|”Ÿ„§óQ~ÞÐ5TçŽS¿C\3ëÿDÞj×ïÐÆºäÝ¢ž^¯&IË8\Ÿ +-·•¤ ´¾ º–ëJê‚7Ö1SE—z}IÇpäÝëvómm©íЛ„‹Ôi1:Ç`Œ­Æ¿’gxœºáQ‡òØÂ\œüŽyÕìõy÷JZÈÞ1>†(ïµý‡È­Ù¾N³ÖI²nUPÇPåYnóßÈÕÁÇ•W¬Áõ‰eU¡SØÒÐÓ/ ˆ¾¯n”O¢Ë;-ÿNžaöê¶Q%¾¼ÞàåhHZLÅk÷;޽${äUíÑq¼û޲Œ£ïÕ,R—¡,!àª1•^Í&užQ¤«ÔÒ{Ö7Ø‹½–oÅY<Š î¶ý3iv©†ܵ>i†Éhôáq½Ì$-§‘nì²jûRŒ“1©§ðà]É V V¹™ì’U*U…U>f·K°Êj,wVùÈÒNl'|YƒUî\š¼s¯ÕÚ1Ô¸®Ý,騵¶ïµäÁ¤íh­¶£O"…«<îZmOÅ9¦9i»º~ñ÷N¼ ¯G¯Ÿ2Åèåz›ûñ/iIågÿ4LŸ¢Yø>Ì‚yµ»Ììüw2¶wsuÇáÕÍΧfuõTF×êêÿNÞêZŽ_߀-úŠH΀צ¤EUž¿'àøö—týµ,ïþ[÷þW·¼Ž3püH]^ù„ÞÒÂÞE0 [‹YJÙÆ?”qF›ë;·y${!s}uç«™@•æ~ÕKÖŽÝP%°luwTËO BP{Mµ,°óžj,PÅMU/<¢âÓ6X‚#Û²¾cYǰšõu)ø´–°¾Fqå±3|˜v¡wýcyñ·¶•ö˜Ë¡wýcé+­D Ûe*ï9Ó¶µÓAÚ×оùe¯¡µÆ‡#T)iY߬Ëû9áúHòÎZx ïíˆï#uµ1*]µAw ë}+ë.ñ«yŽGŠ¥®°î:ªÃ4î^CK%Œä5T¼¯î7Há~)~…´,ñ$ð³â‡ˆÙtq:¥ØÃ˜IsrZ+ãZ½°ÖLÚ ë!ÎÒôUY-.W÷)ò²†ÑùoåݧV‹«Ñ±Ry¾FÛ"£wïÑ^ÝÇ“2’´°‡Ú¤¡öûXÁ³„ÓW‚©9yeŸº¯%¹;µ&¢>óŽ–mɸE}|²ÝD$E^Y >§‡[¶ £Ø1;tBõà±C‚>¹Io©dB_W©ƒä¤få™ÝzÏÄI<ô£§S’±«Fä(²hyæJ÷¿•qZg®tÕJ{Ô<úÍ‘RnsëM§‹On< l z+¬È}eNŒ!¦IéÍ™+ÙNU‹å:U-”é”´¸®úí¶Å7·’î…Öi5®ÒL®S3¹§î§Ò´µ7”ÓŒ'œ‚`?­W f×i5» :4ôµ¹uÃ{Tˆò,¯Ûn?€ÑxUËÆâ%-¯³¤Y¼ù~àOW%ªâ…´¼’`YsuëƒeÍÕ­–5Ç^_s’ð[OÒ”vL¿:Ó—p—¶¬¶ß¬®Óy}y«mٞЌ‡ºB3è+ÔÚ¯4!ÇXÒ"•ž¶ 9}„äxðmËí1ãæô’ºÜcµŸ§¾GnIƱïjté.ì‘å`[ŠÚùqG—ÒQæ#y)Ç*Q;gÙ síµ,¸ïð½an¾z7S ÷·ˆøoß¶õö™ÕÏ$J[oû¼@ÎúÚÝY'•/í½Þº–aÆîÖr´Š¯íÚíq‰Iºwõn‹ÝU-!ÍdYKWHòZŽ‚ušã\’: tŸ%sl> ®½éM0a…¾ÊõiÁÊ30ÍŸÓ)ni‡ÄèQˆ}£¯³«²tˆ¤ºÙV…õ˜TµX”§¤¤ÅžÊZ)Stš(žC€¾ÜöÜšW¯n½8^=úzÛßoiôwåPN;ûÒÎÔ‘% 4H×êñéá& ®Éú)xоhùÎÀ~©¡ÿ¤ÝÐjlç:!«ú’Ý|üeºù˜ «¸ 7Ù]«ÍÍÔôóÿåe·Fó&M“cõX©~Þ+µèo–†tl9Ì››ÖÅ}œnòÅÝ)]»cOJ]ÛÙþIº âYø1öv=g+ËQ,JûžŽë“Éú³½‹:B{u$¼ù.ê¨k·ºywó7ŸnýàO¯½»Éuúƒ¸ÃþsMžb̲ÆÁR×7aVúB×ÁryÌ>ßܽ}ÊwYýëÞÜ=ÝàÌ'è^”µJâ(KÒÆ'Ç®Iû9ËÖÅ1”z›k3éC6?€Æ?ÓˆF"þ#u àžÄú˜ûÙX¬2Mû{°‰fÿJ#"ÂÛÙ Ò¸‰# 0%ÔÊ]Dcð>\%é×›i@XIÖ^è‚; [†6ÛÆÙ͇éÄ×LÆwÊf~ ”!ýsçMúð."F•³ÆAÓóoú÷íbA¿é»•5™Üäß×|H“ç _Ô3Q"‹y Jdqvþ/å8†Æ@=«¿k=èEÔBçý ‰Rn ç„õã¼Þ¢3;Å8le_סݲ„KkŽèa¨JÏÇW¡Jç}V!]ÿÇ!s/´ÍhW´ÚX+Òz7kÙªnã,U¿G‡U*Rôéq‘ò5~z ÒUl Ø{ #¸§M‚ûÍÍ2Xo¹\FZðôð) â ñÎårÒçÑb¡†•%Y°ÜñJ‘d8Í4ç>˜û‹m<£{ê ¹ í´qüÐvÚ8Îè4³ŸÂY–¤·Ý‘=úHžjþÍfúïýE´\Ò´[˜f7<߈·þì ùœïÇôcä/É“1 $ïȧÈÛéæfõñòKñåN³õòvFä¡ÍƒÔÏÒ Ê6äMš¿â§÷·ŸüOÿY+ahûSç§Û'|È"Ô®Ù˜lŽ»*2X¶]™RøEsAbØ„•À¡;ZY0ÓM4f½âY[ ï;¶‚pyxfcÑ-Ù&#Ÿ}b4“³KhkgÒÆQq«‘G!=íi¿ T6½ì—)&ÿi_ûeX˜|zØ/ST–'í—îáq8i¿Ì 3.û%mÃ~: “¦ýUPûeˆy6Ó’ý<‰ÇÌ—˜€ëi¾\¡R‡:›^æ •åó…˧‡ùfxÒ| žºß¸Ì"3ó%h5[Ù6Ì“†ù•Ùƒ ´äEGÂ:B#%«p³fáfgæî|•bë¢Ë:Pš%óÚ<Ì‚h‰GoÃj,émïѾðC˜Ó¸ cmrxª%ÄÃ`¦(ÔI­h¬Qjë-ª9<%bˆ’Ûçð¸'Y^&ŒäÿéúØÿ)¯ñõ§ %[“1z½Œâí—×-ý3[Mn0ÿßSËy=žÑ2üëãºoª„~$úÂý–Ä‹èÿstyä2Y$ÀÒ<Ćÿ³Iòú1ñ<‡~4Z­—üŸâ$ L—ÉÃC˜ò.NhýÿçÒ¼ÜÅ_³z¨r6†¿Í¢%à“@†Û4âþP@ ÷‡fyuàsmÊÈuÁýéMdÛMAƒûÓ_¬‰7ãß²ëdÃi|Âu’'=§Ç,[7¾ÙñOÕL5Ùg·Äh4ïÿ¢õ3Õù¿þ@<âüøë_ÿúºß Æ“è6¦.!yɽîñÉÿsŒükm³î7ˇ8_‚ÖwÕäÅV®9}?wM`½"'j“õýì”\çœË<,ñšqB¬éÙ²}U¯Þsݯv5—ã³)oÉ~zˆÃù«Íc’f\ò~U9ÏÒRÕGð.Xð<«mmÍñ,裸÷÷ ó,ù°Ü¬Iä–Æcÿ^•EÞ?€Ö¸;áùî?ü×Ô Þ(H_äA¾e¯|pî£'íêŠüzlrOˆ¹¹ãW¨©^¡HOI4ÿ~Ä’¶¼¬•mèгîBàÀÃ3¿ºÚ“±Ú°ÅP›e™6PmÄ Í¶iƳð¯ Õí³lÌÞÈùÏA”ù!mõð`JÅô,Gä$!M‹6Dà:@Ç£w]"übªÝKÿÖ-û¿>€Þ¿ù±$æ7i|Eòà©Î\#›ÊÇg¹ÊNRë$¯ë|=é¹I»~Ž ¶›?ù*œ1ñNRû¯¢‰~þ÷ÿö‹H[Ö¡OA¯37½bžØëûpu/°ó8ý¶v"ÁlF q¾úušdá, çý¿CQþcØN(>Ž0Ú(‰ yª›¤©ð!,«pÄ…7žš¾°ZÝÆÑTtÃÃø,”‘µ“*½®žÖbp\'åE$£§ Ž>KÑØÜGÕ˜fi†1†·ð¡&ÿmÄ“ÀkÇ€Þ–/æVUyEq+£Fx÷@C'|Ìí.PJ‚ñ½ôa=¢cpÉj* ryêâ«WWt‚òu0{ ?%ŸÃx7Ýxô]6ž5„G«»çg;4l3=N Œ©’zÈyï$¬æ×âµx¨#Ãõ½™°–çêÁüpóë‡)q†^BÏ›gƒ ¬Ði„nM¶ôó)J"ËœÂì×9:òßxN¡”ódƒ£5BŠÂ#œÅ†U,NÒíój̸ž=Ìí&ÔÞÑ„ð{c›Ç°ñ<κ$Щ@ÜÄÐmŒzEJ ¯X¾çÙ%¯^avGH}º—Oa”lÏ<h„æ8rõÝÓa>až¥a°*‡Îg¼.ùðÇàá3©qaÿ¾6ÕKA*7ÌëK scl»ÒžûHÄ"æ|ý,·¡¸©Y|Œ tIlž8D.Aþ£Ü[€%ûÆÛÕî=ºÞK~ÅSµÑú"=PSqC¾ J(ù"ãmi\¸³µ{ß'—0¦]â;WWþ¿’t¾ù·Û¿‡·¾çÂsõñžT ÇSë?CK"³ÈÀš¹õWŠFAQ˜võ&…âWÁF€«FæÃ ßiO6Ï0@º>x½‹Ÿ·ºúÁ=qåƒYÆùãs>¹{äÕL¾êõj;öà50=Ô:Òº&¢Tpú€£x ²éßäv]«äsƒ_ªæ@ãŽÃµË¤–îN̈mà@¸Aödð»mW¸WâˆÓš£‘åñx²mñß'Ér”Xulô¸ôÃÖmÂÆì§÷€Dͳ\9{šÑQQ PÛÕO*€Ñ=ÃëeÀÆ3™ 3æ9"šk_æˆt̹^‡ðâ]ƒÖ¾©š$2Z¿ÜuÔ ”çœé6ôö“¨Ò—1Fs½JâÈ­ÉãÉ5’¢•9ºÕ;¿:ׄNgQ°q*Q£š£y¬£pΙjfµkSÊ!ù®ªÊÛ³µ¡[PZ©eË5­ÑölÉ/Ø`eëÞMq8¨A;©ƒ€WÉØÍñ4w´@Š26pE+LaZC¼Cò]½ùâÊïìÌäËÿY‘×id·üÑ;”W®™irJ.]o€þ‚sš7LHÀ2Þx¯:ðOU @À«' 5qÊ£_!âCm¸g¸fœ’‡?xõj”ÓÛxFì\Èåés\cÏâ‘:ä ÿ½ÅOÉgT4oÓ5Äf(òXö'Kµ««Ýýñ¯ý«X7 #ºn€“I1n;ÌÊŠ‡¿-Š5è€b;Æ|½§‰ ýê'©±_ÃF‚Ràî£Q´Bj†Õ@ˆê¸(»—³l ëà-Õ£ë°Am…~—&ëEÏ‹áÐC¼Ð.D­ª¸ºú¬œ£&‘¥ÐB>Å„[%5òÍ )¨äûä '>æ ¾¤Éx#bý[_+±m4k@ÌäC¸¼u×äÀ´C×h”dUa4ú¿T@^.ôrJcçiÄðr‹,C#á:]• ›çª: ÿV¦†Ø×ç¿÷Óp1K¶1¸(fG´ä†y–PíøÅsî"UQ\žyCT›e8Cteât½ŽMo>nK¸9qFÛP;ÕÍèè»päpuÇ£7úDµéº6Ž8s^sìêÊ¿]­F5–hÁUyŸäÙXý'"E6x¢™€ûܱ Øí3ê`½Oà›PZ¦ }é“77PuÏäùçgÿÖ-†ô<Ñ9¾²¨g׫þйŽ78Tz%x´ N›¯ß p౎ö~Ì´ZÇ8›)#x̉¥ÿËY%¸ã0Ÿ§TéñOÄ} ­"¤þõ5%!ÝÆ´ŒdÍPÅc´¸c›µÝÞ{ÞWI´OI4ïkPÖfJNÉT€ý‡O祃ï· ?"ß"€—}ÛüOie›««d±` 5p¼ ºè¯Ø¢Pnƒ+hÃûo\½èÚá ØCî]à­{R“!‡ñd²êI Yÿ[3€Ó¾&0àxDoÕÐí!6?ò˜K¾ ^ÿé ¢ƒgð©Dës„á«×'ƒ¨õ“ ‡<Öƒ ÇCæˆkHÁ5æŠCJú3Š6á›mÆXØNiZï ߺ\¦4jÀŽ¢t†È‡£äUëÒùÄód…(} y”r((`rà¨ÚÂûYìþÃŒOln@£aP¸cÎ]„d@,¢5Í ÈÉå‰ÇŸÃ…yéQèâÿMUZ¡÷(˜s w^qÝýLŽþ<­ ¹M %5\]ýRJA­MŸAŸF­ÄhÐNÃpFïtÁ”ÄÀ”œÀ¦nï:zÂe˜…£Øƒ„äέ²"hwL15&õþ-)LúG£ÂjXóȧÏ÷õÞ"í)¨¦û(d´Šûa4X¨Ô/Ç5÷ò·2j„k.ánžSðØ¿S4™¶æçYpkD”lÏ<ðgµêìû`Íü}u` ~tÌ݆=PŒ(Òƒ» ÕÛÏèm’ëqÜ*ÔàU²¨qî¨Þµ¥g'2'¨‚›,Ô×§ u†Ð“ß(Ô¸áL.9üo0‡?žÈ¢£/ðŠ·Ñ I¼Äl:øS |î2í:³,[,ƒ?d(h$Jóé@ñd‹¨5Ûƒl€)íÛBHÙøä%½»Î¾)täò&ݰQ”ôÐ9ï¨W4HWåÅqw:ÈñQ9ÕQ#Ý_E#Ý#–ëî˜ Ìu´!ZG]Ë61J¤m{›£ÃÛÛ ]òQ= .øù–ÎxróR:ãg‰«P5d&…Pa[èw3æ¼ãªŸ¹Ê­áQ«BÇ&\­—Ä«Í#»8RwiÔ¦(ŒÐQ*’ÚF>‡!Þ©W$ËH•G«A“3úÒ_¹_Þ ÜÏÇUFW˜‡O0à~ <&p?Ñ,ؽÔÁ&VÃ`èûÄÉ€baŠ•««U°ùüo ©hpÈ@ D9±À*¿‚Ù;CCÊ׎/ÑFçKˇ„{Ç–TxêÎ"×&1ÜÙF^;¡ ôæ~‹ 6<}ˆªà³Ïßõ74í„j€ùÑRx\m¹Ô˜‚`Ž DÍî­¤‰_¸a«*ú9ÇêBc)àÁK<ppqTJÁO6À§ýƒ‚PlàväS@Wca’xú_ØpLèïR8•#* ä}cÜ‹¥Kñ×_ļ$,@7[‹áÕ–dA| âöS ºµX8n@¡ ƒÿýº¦Nd”Ä’xº]¯“4÷­ËRøš·_¢ÊAF·›Iöæ§( gÄÝþŠ)õ@€ä¹ƒ,˜|¡hþ–<Ê~â9Ï8 vÒeù¨MóAýwR)%.Ƀmþõã6Ž£øS8ÆÂA)†+ g›=RtͳAB“wÄËR_—ûZãLY¶S9Hè]òÅwÁfóœ¤stYˆ³©ÊA@ìcb¥ß&ÛõúR_ŽÿZspt¦«ˆÕA} Û îõ®~Ìäk ðª$zsÉØ:ê'9¾Ö8AíTÊž·G}7F»DI0ÿ ïimgš÷9‹Â y]lÈíŽ`Ÿ±ÀRB~^L¿n²p…}mé<*täGµ:7_"8fØŽdY.<'t9ω7éÃvŠ!/Kg€Ç„Žü˜(¤3 Ó§0ýnÖI¼Á|pé¼)x˛۩”lÎôºÁà!¡#?$¨ŸüS8K¿®e<µô^:öK"ˆg!Bj¹$Áæ'˜XßvòAÊûÜÂÚ ¿>†«$ Ñ%3„ÁA~<àùÄUÑ `inñ’`þ™FrÞ "Ç (ä÷Báßüœ$Ÿ1·ÌQù½ð)o€ÿÎÙƒ\†5 –Ã78´‹JéhÅŸãäß¹`!xÅe§8ï„$N ÖM^Èm“‚s\’-• ¯©d¹¥ÂyDËmŠ˜&¹±`âAðŒËŽqǹ͹K“ûe(8ð«,‘ƒ ‚w\qÿööøCÎEeш˜c˜h\ãÖ]ó ¼¥,‘Ð:L4¾q[ÕºdD"ëü寽eÙ1Ï#÷-0º,€säÇD‰ƒà¼Û6GÖ]2×èG­ZoÕî@1mÖêxb ×É: çl©¸µŸ=\§á,ȸS(‡À‰>á¹îωUÆ”¨G„úüR„×5¬1 ‰¢Ý »ôN²Én¾„³!Â`\±æ—kªƒF«D”TcX‹IgX´E”þØÍüoWWaö‰kbNaŸ¸œ×ÂzØøœ6Ha½}y>] -¢emn쮋ü‡ÂìqKýÙ8XŽØ‹†çõJ¨M`R™>«Šµï¬óB"ŒHbQØb /ا3yîÑ®£x/âæËz™¤!Gk•¨? SšSoZ=‡K*¦–Ö”êÞ Ã³l÷\Ï?Aç©WáùÍ(5…Ö  jqÈ ›žw†jü~¼&•Ë ‚ÀÞEðõË.Mï´vÓ¡ñiÙwp=i¬ö›îÔÏE¶föV>D¾ÀÖ±SÒ%ï£â[6WøA?Ë$~ø·z/A+.L6' 8lB¤Ø”ǃÓïrLg­RªìS=­3QœÅƒO¥ £T¨êK'Y82'G[>û5–º4!¨b5Ø>ÕA¬ý«€§+>¾•«‚M¼€ ·~m_¾VýÕÕüj¨QÞÕ©áSÞ¤Õ)û~´ñ×yˆ×ç(¿¨R7'G¨/ˆ«B¡È»]äç‰? ²‡³\¥lu¨’QÞ®g¸UöhEÞ4óöÌ@xýlËi_dˆÖ1mbûŽT"^5ÇbÓ¦Xõ9—cȲ2¥Þ§I0§§ø¥`™Ùº.)5À »y—5?(i•”ÇXöaío6Ds¾JUÓ_ͱ:´mc2ÄIötjZ¢nZP Òy£¬–Âß’;rÔ'–³Æ]üÅ_Õ®¿‚q€ûƒ*\žýÔ^Ú³!…&EWsUW¦)¤,%þC×Aôåšt𳟯Xýòðo?y ó«¢F»Ö¢†J»Gs˜·gëÃyæ •¶ŽçA¤»à¼zé Ÿ#UY2,Ä+P#„©ŽÉ×l..!ÄŽT}cŸcáràÈï¿–.n7ÐHæŽØ š_q·]žËÌ %N]yJ½ˆßSuò_‰¹x:ç2–Á6'`GxĘÐîŒË¤Úœúáæ×Å2Þ°´©©ˆ$j´†Tc¡¿»4Y/¢xŠ:êp–É;2ö3]ú̴Ã1×ÜöÉ&»ÀL÷ !_§¤†««?@J©1¨+ðô‚™.1Ɔ͜P}³™:i=¸ Ó?·Dï·ê¬”q¾zmøø¸{21=hÈØYZêè‚”7R}?KØ{]¨Ï¢Ls´ùZŠå9@àK×ܳh:8`ˆŽö‘b»CL úã²RÛFF»Â®:ÐÅ%o”oí‰r(°šƒ ë çxþ3ìT<‚Í*ÄD]óâ‹{8ž†-e ©XÏHÙìΔդœo?LývtÖ›a¶ÎD~™ØEjr¾À»‰].Ò“DJ©ÇS|¨ 8õÖºC;Õ†4õS$Ô¡©çÚ¨a›óª¨Æî–º v=/휋" u·Éyè{^7'Ý @Î>\6O“/€º ÚÓ™Lm>@@jârM˜•©>ÚP¢ã³Bbxê›,ȶÑÜ/WùË‘ó}¹¡­wH'ó ¤7HÓ,ÛNmŠþÚïiu'`´uô|ˆ¢RÚuðßdðQ¥-4“›?ÖƒÈsgrcÉ–$G¥ÔóÛ–£ì}?r1i õ‘Ï)áP cõ›ÛVŸ].…˜4Ö~v£^2yV5 Í…©¾ø,Ͷ˜Kä=0„#P^­‰Ûà}ÍvÂŠÒ ƒ{tÑö3Æà–ˆ›m[¶{ÁÍ>ÄÂÍ®¨lDKQÂJÚE÷DšÄÔâ]'-x×ÌñrjF^BÂ|zÕ×Á ]3ì­Þ¼škCƒÄÊ1¿FûvíÚæ< $$³n˰©•ÔÈ×aY‘É÷q/'>ú–š/‰ƒÆâòF¬ í÷yw»À—ý7Ëe2»ºJÃ{â\]%Ùc˜^]“}ᇼ•.¸¶†­G¿ºBŒ¿²Ïâºø4Ö”]rWÃ4‹B+:4@ jMÙ6àš;G×WÝ7M FózÍ‚Q{¸†6Dû£fØôJ„Î:Ú‡&7â)èüa›]®2÷³J¬ 6I]Ò* ÂÅ΀L&†X‰¢â H’|þ”Q6ˆcryŽÖµP@¸ñª¤F¾)“üÎ÷g_½MCÿ)J³-OMJd¯îaéþp¹1O/(祟oœUÊyµxþ–ú ;T»S…x\0Îû“ë‰q¾UqŽÄí ÁRçm¨©Ãâ›3œeõñâƒû¦Q0»…‚ˆ×ÁryÌvš îù  “øFA¶Ĩ6cùÜGY$éŒî˜Þ|K˜3½wªPàáªE«MD z`…<¸¯ø¾×{¥ñ>ß/O´$ßÏ7¿Ÿ£¸w?P#´'Ù›àŒCa÷Õ9Ù»&Gô@< fj¼vމ ^Ø/õã~‡69|'ͪ}¿Ñëì¼, õó%õ‰f@K¬æÁymG_`eï(Q'žLx¡êY`yõŸü¯—Òßc+ôû.ÛБ åðgêÊä¢d#2ÞV×x4uI»‘´ëøïýÕæ1[eº£è\fyøÝ®¼º¢øƒÄ•à ½K抇ÜÎSnW q\¹•Sc°s¥1ØùÄ] žI•šÓÌÝñs vÃFáMýè—ëv(w®o¢‡8œ¿Ú<&iuÏû“0éÞuÌa¦”[ྫ¢ŠjFí']Í|ç”ÈS÷vµï´×á;1 6#³dý•ë RF#ëoìÅœ1 _ Ïo*¹M÷áCîí,¨•&Ëpš@õSåSRD»$®2¼±¡ 7°l9_¤­4dÈv¤ŸÃ\¦SÐ;×Ð5oŸßÙï­Ž–‚ù0]$é*ˆgáO<Eba2Œ)‡Õ¬û÷½>wâ¢ñ&|Û€PÛ~Y„»ü5-àØ`0Ë¡¯þý4gpïŽÝ›m–ž¹§`¹ Å£>Ã]iÐny}0O ô¥ÇúEÛRVÛlïEØs²´#rÎC–¤©Ÿ£N°Z€ÝÑÍñäŒ.Úvd.Ú<“/§Hvˆ¦ÑËYô GÀxø÷3ÒˆÛöŠÖõ:`жr_%Y8ËD1âeèê½O«ã£ …æF‹WºŽˆ›Ô™'Ek²æo>')âÌ×vÅ`aJ“àžµÒèÕ’'TñTçØ®˜c7\òe,6ò9šgïìV‚ÛGŒø¡T}õÐ×J§:èv< æß\S(À Òg®•Æhô~™…ë Õñ&ŽrqeµÒÎ/tZq/xŸ ­9„pòxn³YÑŠg!mGWŸ/åÄòh¥1QoßÿŸ0ÍptfiB3a:ChÎΘ£ðN+GqÉúxˆwîZÃ¼×ØIÍYRš˜÷¨$=k¬ ±—«»9š2À=â-¸] ð··TévôaÓ=Ö!QjõEôÛä§Ò_4 RyW-Ð7û—ÐT A–¬¢³4°ƒÑ¿!¢‚x}૬6… ?ä´†ÕÍk(£Ùê6O;pN$‰gÛ4 ã_¥Fbâ!ÞÒö|Š6P"çocâ`|öÃ4MÒ| äh»3ˆƒ‡0õùî÷Väì SB¨“¤<Ç€$€Î—x̲µè` ®J²ÎÁ7¿~˜’[“hñm0Ë’ô«ºè«¤0ªc¨¯Ó Ʀá{¡96”* ÃÆ›¢uLð˜z¡ÒLÃBd#jð§pfáøuhu(PWaºêíqó ²;ý¹àÒ±ÕTJˆŽ¸f–#)…˜–R á‡áJ\•%-ÿ0S>ê2ˆ¥>Mù …««? *©‘¯OÆ&ßc~±69ðtLŠçºœ6f cHŠS„.'œ–£•¥@©O!} aR5‡Ç7©½çsλqâo£ex/’[ê°-ˆý^˜!´`æ 1;…9`DŽðZûvö8üuÔåp\œ/·–"­Ö‚•’ö ¦ÝÕÿm¡¼jýb/æQ’yôÀ`ö*Ý?]³oî-|¬#â—òUUû3BŠ\ïü€¦8—Ûˆ=¸æUtPß|Úš¹Ü îø$”jã‰ÜhöœgáJ©‡RÚÔxuõ‡˜vk,ká,wsok,ëŽS™×ß®®ÂLˆ«9r½^&1œmø’>ic>p¤ÉSi*g¿¬ Á|}6¬çÇp½ŒfÁXÓ^úd2+œöò¨ÏÓ\1Ú—ºõ™Ðdߢ1¬1v¬¢FxPµ‘ã€[ŒÅÏ`µ.äç$ùÌÞ|ñˆO£5ÆQ£ ÅxÂ3¥T»!rÉ&»ùÎÆ}$mx‘lÚüSÍ©ßÐ,­ùÓw<>ùyT–š^là ðÉ­}õúc˜mÓFݯ´œñ.C³>6gÂP1#w‚Ð.‘»ÄŒN)ÅŒ¼KƒÖ¯› 3}a9c å÷ô,ŒžÂb{ PA?xqaŸ†2®®þPPY-à#—Y-ÔC ÿØÅ!ÆÓ§˜Çi02ÒB/hu„«&x¢ØQð>þÀtgrÍœñ|Þv/Œ¶X¿¸F1Uõ€ØCƒ§WW·ÅTUÁ‹kOQ} (Ž9Ñ õ%ïšápÌm˜â®G_„;‚§;Jg¼q"Íg÷áÍ „kd 6/×1ßÏ䩃+g—8‰#rw÷Ê! à­„éZ:¸¦º?öZÝ­ €fª“Áå28—'¦YË"3à¡=0ù=û…8XA•.h;Ád˜8úÄá{_€¼œÚv¢£¼{´¼™ œëþ.#_pð,OA¹_~žÅ™ßßÜ€ž!råd¨û1)ZÌ`¨œ\3Ö·¥¦óÅ1­nêý[ͧ6Šý'ƒ6pgŸRà¬5=‰•§¦b"D¥ŠÜK!‹&BoÝÉ%Â+#Âë¿÷×âs”Mû^Bxò‹Íɦƒœ "è§–òíü¶Zë·×p•OÈCñŒ1á7ØMl,Å3¸óˆÊ×Ï›ý,®1 wŽø 7¼!nÃ@%ú<ïùvR/a» ó€ê,ˆù C†T%jNl*A}@{|>;Å©wòx§¿ äæñåø/~^Ÿ íç&¼¬Úd!ŠÌË^9?%.GÜÂÌ߇iDÍÞS°Ü†Në~F]8l{$)FuWI<£½ÌËâ™Ñ†Ü€…#V° Ƴ­"œy¸ÉÒä«ñŒއÝm%§b6ž¬iy 1·y °ÌÝ ù6XWœ£.”QJì8àœðyØ Û˜|¶¼ÞÄ_ýy°ú2`i'Z}™F‹[T×—‰ú(†Ç3=à|YèhÉýÂæûî2(¸>/Š&ß$Èy¯àŒKÊÞû;£@^ŒyŠMØŽa Â, è„É÷ŠXEâÀ  ۘЪ€¸t‹üC2KÖ_ó!ö£íeþOúUÐü5ó)ЏO’%íªëö¬~èü«¼€æO?œôÏG j»Ù"ä` çj®Á3˜BÖüM0NL± ¦B  6 V]‘*Ô„fj40תf÷LQ#*>m%L g…ø­h«DŽª8]ûÌ&ߌ¶`ÓôTÔÿÕÏùÃëEr‘®Y|7¬æ¶aϨkÌ¥X X°ÃñÂ{p•Þ[Q<9:}Z©\sâ(Ÿ`ŒàJ‘,B}ÃÀ’EpL¥Hö>|ˆ8Ò­ÔÊH×–ú±Û)¢]™Àl©‚ÜÀ²åôÉ[iÈm–ñf¦©ðpô’Y dT ¶Nª€ß<=Œ[Àœq®V2|K|Æór2÷GûOUo:ëaºHÒUÏÂ÷Aú™#@-Öd]òô­þ±XSባÏgýÕ-a‹â±å¯i tˆb”¡¹úwKŸß8€o¶™`íVéØp¾ziTR´aÀ†h)ÎÅ>äm-}Í™aUˆ ç$òû4KÃ`…'‘*5÷K8—Õû0 –Qüù}2«¿»µ ´ åa ê°S7—‡Åi¬Ç‰ûß7%EFqöçï¿ÿîϽ„` 0ž{R¾¼óІé#´mÞÁ!¤Ðº¿n›§˜ sÖ×ÑAFê°„‡½úØ6!.ª[kúòìµ{ûÚ9ó혦&ïe¤ZåÛÝŒý0õ;æ«Ý Šû­Ù¦ºéN>n¼Sg»‰[à,Ümræú·âWhU¯#äúKƒûp—®Mõ•®y>mÖXt¸˜,zz”‡:/âÀMº÷ ée¦Ãº ßå (kàö¹ý‹ÀªrYÅ‹ç9âf "§Ñ¿~R²¯wÍåI=Y`øwøÜ…‰ë@ÑûQ‡®’CùB†®²á§P·ZüŠá,Z<–§Ç­ªs6jœ²µ`éÑ?¯ h-cøñÕÍ![•ù«÷ñtÁ="•í–f(?ܽ†é޶ÀÝ Ñ¢@N¨š–£È4ûPdþÉ­ÃD²4×àÕMìÉ:I¤äœ8<-Z=.´òÔHužÊ €ëûzÉPu‘?óõØdT6“+f$—ÙùÍ|5Ù»æÃÔoþ:pÈÕÔÀú§,›3ÀÑMìryž$Rº<Ý †Òß.óÙ“ÏÓ0ž_†³Ÿ&!ÿ¢>h¢¸+!ª©±i¹¢e°9q98(šÆnV¹|ó… A À(]ó¥ëÁáHÖœSïÆt»^'ivÄYoCm>¡éAp;9nçájda¼ÃA8“îŠì_ÿí2x¨üF´\Dêlªõ]8ò—@jÃc»”§T³ì°Xôô9¥9zðƒîtÉ…x"«‡¦4”kÓö`pÛx=Äáü¹Òaâ†y‘ˆÒö†˜oéiŽh<>Ži“b»l7Híì?7iš¤Bp10NS/¼~7TÂle“‹ã€éÔ©bJ ¶Ù#TcDô…j?qVÇŽ³nãØy»¶¡A‘3WW§·$ª7_é¤Öø*iŵËD+· ÖÒÿÉXÒ1å7ÒGŒÉõ„á×iÓ”öýÆξ| ,’tFSž½i”_›9' Îíç„ümüÅs¾# Ñè@žÔÜå—¶¥A;Â/³pE ï<ù’¿¹'1þÎÓ`ÖQŸ ®ž¥7ØkâÍRñBËß kB'Œ³(X¾mºÊ]—#N]C4#ÏÝv‡\‘èŠdÇ7çÌ÷ñjJ{œw¬ËùÎÄ Ì/Sƒ"½£iãÜCƒ8Øã@¨ÂƒÊ k?Y,8<à3+ã2]¾ö$ ëÍq· Ý¢}ŵ9΀§Ã[ M]‹m<£ÞcÀHWÊs¬dro÷Óþ“ÍKÏýgå´x™×A¡S¶.¤3ä)¬)ácTù¸mè8ºŸB=7O²­xò>˜û»Uø³`)Š( ™|h¼˜îˆ#¹ºúC@K5~» UüvÕ(ÃÕÕóc->Þ1Í ò½4§ñm…`WTXñª÷¸ÉË@¨h÷ûذËØ_±¿ùާŒY°®§¬¸„y¤B÷ V Wªü5¼¾ À\‚Ê5-±/ø0Ç}ý1̶éÎÓµu.,Ñ›ê-±DwR™1›Ø¢ú­¹øü.YsbÆZ(nM”H¸&0é%›Å3G€°æf&ä‘+PE„îp„bñk"ØHõñErÒÜså³ý$k ä‚®p†$õý#| “|X“’êp°½©”Ê>ËuEÁ_æ¼­ÀrY–W¥ÀaôìÇÖ ïÒ$KfÉ’®oÔ§’ú2"c÷sî1ɳ‘ÁpRÕÁˈŒ¤f!êÔœþäzŽÈ(°ƒ•È@ã÷­#1wŒÈ`°ÌÂö»}øvij㠩w ôÊY\ï\øF/vDÍŸˆRË4¾aÊ%„Á]2`ãú‹u'¨dJ·9Ÿ6k,:<L=ÊCÓpà¦p|e:°—ÀÕ|ü '˜ãLàEhÁœázÍ sà¾q6Cµö £ LúìѦ4 ŽŒÈ¯=MW~ôJ•nÏÒ»Žìoálˆ :jI5›ž1DN’¢‰mzKS;Æ{~‡àçP½qb¼Ãx•ª®¶b”ÏäPR´¿è)ÌŒ:³E¡£Uh² ®CþR…Sq.þôC©»¯ð7Ëô§qWoÚ†ý2 8 Ý‹žM']!ôEVprâ<«òM~ÌpÐë ¦Û°xwAßÙ,ÜQýu8 ×J‰#ûï©Z0#Éôq/J-iÚòx”–†‹Y²Á],;¢eë«»Ú’¥~K‚¾ÿßÃx»zåûñ–¢Ç:ï’ÙgWú×ïtµèü˜}Þ »‚äx•¿ð‰4®zçœ €^ähŽüÍ‚ìRdëêfõ+Ô´¨[wô Ï7ïÂVë%FLá]4òÒu ã¯>(äžÀXÓ@ê~ѧú‘çäPÂó.Òf{lã±Ï‚`SÃëº+dc¥NƒPà4K9˜·ˆ”ŠmAû¼äÌ múÄÑÀAw8"ÃÚ5Ú¡ÖÓStOç@7Dì>&$šùEòÏþÂÏxçÈŸV4C‰ÀÔi.WK£dtÚ±Ú9;€ö Ý(&œv¼Ê„#úÀA8 [‡sa$O«<Ûó“žuöp€=dž—ÊAí¡u'¼á]Ë''& ¿ëï:'3~PpÛà½`FG‹C¸¦Y#^$áÎX #öj‚1ûEìêÄ#µÀÒ¥‚ 6÷¼Ô}¢®–Y8ÚƒZm{Ö\ìyá‰Ô›ÊÀ"ãö°(\Ë–ËuÂÄŒÖÕòà5Ñ"§ô®Gúã>ŒŠ@k/0?ì#ýv8r`~X?­:׿óÓÒÑ/DýóÓŸ\O˜Ÿ¢Ç\Ì¿o½c¿懵ï óÃZé‡ÈEX“á´J ?È7vð#:g¬!ª@ÞFpçÌ3 ÞÖM¬ÚdáŒìÁ |Fx,PÕarKNÀžÛà9‰µäcücõ<‰Õí¿ ?ªÅX\(L€_‡÷^ü.WkšªÆöR?ô¨r¬Å\½Ÿ O&6ÏÐDU­ícÆ9Ú °ätrŒp©FV‚>zxGsàpøB©.®Ö #høÍlbÁ¢Ú 5ã^¥Î Ç•X]$·œ>®ñš\ÎÙå8î7ß›¨éf™ÑJ¤Y'ÜÇOƒƒ4ÉêÀíñÓ5u:I^}sssQ›šn†îñ88çQ‚Í’ƒwˆt·À P;|’sÖØUÆ0G¬K1@yÞÚl=A©”ƒ6,¿´œfUWW@UScSKeÊbSË`ÖÙͱ®å+ë´7³D$ê%>Kær±ÊÍ*Ça“º@®L¤¾Ø605ä5ï+µlˆa0]Wÿ´>×Þý‘>± 8: \…°H$Ehý~”½ÞŽ ¼SÆ3a½ ´¥~¼}õŽeïótZ¸¾LfÁ2ôÄÙÍ6" 3úNØ7ד߳_?y‹¯Ã øʵÔa)&ýmT‹Ã'ÄiüÊu¹”´ù!‰¯ÉÇé‹‚Ó?(ß,ý?$"ÁኦAü¼LïXQØìË—à>úË"Ig4ÅÙ›ÆA]¾ŸÓxbHœ9!?Gñ¼÷™ƒœ8ày;©8(.IoëY•϶iÆ3žªòPŽú)±x#F¸[÷¸ê}µÒ©àê®¶YÈqi%XŠ[ÙBa+þ¨Uï UåÀ8¿=^µ'±Üfÿ  ¼ô¤à·Ý·K3Øf|7æÁpxºÇJ¢/ôÞå.h‹VkN)Ñã‹´cÀKi6ÀB¾Üeªë°¿³+Š*ÅåêžT_r÷6à€ˆ``HŒNDŒþÏMXòÚ<¡0w"ßYª+Lã°u2ÎØ]˜w‡í§ F âæ1}1/¦0¨w%ßh#®Áú}»äóŸX^âµpà–^.Gè_}Ÿ}íß<ÜJªòšó¶^n9òÀ­4KÏ Çì¤æTìÌ÷÷4Ø¿©H¤§x;œÉPµÃæ¡;ß ^R^.'¨&F”Öã¨Ól¦jm„Õåœ@+î{r`5·ÄÄ©äC\+7/pÄDŠ&Œý Ñ—¯Î?储:©ap ü†7t¨–y!¢Ë\vÙEU`J«¾t/^Öî p–À÷‹Ø`¡âx)(š£}°X|]ñG$àãoÓH0~ðÏ4âmJ9ŸxETætM ‚M1êáh¢ E¯Ñ™îHà,úÈ®rí â©fÁ÷¤tÍÒ8j<09ˆ!6Áâr€-Çko=õ0%äTzÃã^•õ7æþ\×áLá¨Ð<è² 6£¶£œ@âµ.kD),e‹p)èG+¥Chy¥<›­•Ziع銌g5bô€Jí&$'Y°Q¶ê²=ô<þÈ~•g|~(ýZQâçür8%ˆ¥r`û gJ»Œï£(5…X ÇÀé†x-¸pU x£}?¸ðPœ€óiÁ‘™¤iôª6î7=¯3ŠvJ5ðloYàx£=•|²Û¨FHÇÛRùœG<Þü„'œ žì¯àôî®áÝ£-bõ45E ðw´æYœ‘Ú.J%\-¡'¥õ¥Ù6X2zš1™Ï4œò ‹£ ãŒb&xÝlOÂLåW=1Ó£ ˜àcfÉé<|`sŒñjn]GçLyÍm”4íûø•W6¹<í‡gµ)Ä6Š^ñ­§ÙêA/,ÓãñØ[êoÇ4â geL¨›{ë aø>Cñƒ{b®‚Y–ßÙ¬1G!ˆV/€µÀŸsŸ¶‡Ï *yÐ÷ƒ%9xœ$ÀSyÔŽR|ˆ™Uµ]]ýPaô%Sé2f´$æ1dÉiæíÙ ‰&ééІ#à¡ïüJ€GÍѯ}8N·1ÍÔ‘ŽHáÉ —°YIßÒ¡µ:ª`Ñ@^ H$y)ª4Ïâh¶‰\µ>‹“Ú³xœç1Ä °ó¼èÑGˆì•–7ëŒ4ÖnL4E/ƒÜ•Ê-¨éqYÐ*ZêŸ È¦Ž,¥øtÿŒçá‚8¶sF¹\]‘Ûý;Ãl›Æ»Å©Ìs½³Çd~—ád*‰6í!jB lóbÏ(ˆ7÷¬­Ò¡d»€úo;b>¹f—#~°]F„‚h4¬†•*cÔvÔ‚·+s$Rkas(<ÿQê–u`±ÃRÞ„a?–’&BYì Q˜‡ÚD\°[§·Ñ CݰìáE޵övæÅÙÃ0íÎÄå)â:(b±Là:ôÊÛ^‚spl|nT•Ëõäh\õü·)¤ä«6øæLæ;Ò¾²+£Töïåm´Kø±œK¶Ùz›–—?Ф]ízß“Uc V¸ögx{¹¿ý¨lÇ:ë<®dtøœ6»Èàß‚3ZÝNdðoÁYÄÕNñ[ð¶ïµIœº®4(ž2mUÓ9p‚«7WA[ ;pàâžQ‘“LMÄ\þÕÕ¼j¨ÑÝE—±é °7§`q ÷Ûë§ïH0ðµˆïê ?÷µËw¥çlÔxH e˜'æðá Ëx_”êCÁ½œù¼iøßÛp“­iÇó†ÏómhðcN‹uOoòÈ8ûôtή8˜9ü `8”9êRæç½B¬³P5†’"*<‘°†IZ–*!š_]å|w÷Y)5ò>H?‡ˆBB£ò@E°ÀÁÎ×ëþ·5pØ>c88Ã#ú!S©Ã‚ñÞcçæp6GaÌåÐ\§ÿ##;ÝðDJ‡ø§ Fê… ÿo8ø…‡:oþêê¶¹u*X‡ž?ðƒÀáÃ!ûôåWèhãèº5DM†Ãa?[THËÑ·›âe‡p£/7_fášÜ:ºbð¹Œ(GŒÛ’FñÃâyEÊ!þLNƒ×xŠ¾Þ–ó”¶LK=²´E±!‡ežlï—á8Sæœ5cÑ0Qþ6ÀyVçòŒò¬ý7e+K–µJCb–MSsSS¦g‰€k(Ͱþ3.ÙÕ R³«DðWWðˆ¿F¯–U¦×#›jòCfRmè¸e>¿P Ö¯Û@ ¯ªAyáÿS”fÛ`™‡‹Gâçû:úÚ®—és(¹ÈZ&4ó wJÅ”’*ÎêùeU¨Ì¾µ §±VŸhž‰ÓM?º$/ü.~N_Æ­òÞÏ"<ÈÓÂ(=—·,²¶úÃ!´ÒYm³ýƒGTEñ‹hÉÑ ÞJ¯t$Ò; â7ªw?Š#0DCA´ |ç‰bˆØ8#û¿÷ÛšÎl:jLµÎP€ Ç¢³ßL»V‚%°3ÓSµ¢€KŽE_ñv寷xVѳ õ' ²rL{ﱉ; È»}\„<¦Š‰Ø£®4ýc"Žü2¨Ã¥ÓŸh®þ÷û¢8ûм¨äüŽ£ úæÀ• „˜ë £ÞÐ~ôVÖƒu¦³ÅhYH¶M‹^žz|ÁªŸ·Ûxv—!Õ½:*ºÿëóÈ-à83`9K[Æœ³A<óW'éÚpY(¢ mعçîØ©Æty°¯*óß,—É T¶õ)\­—AæWK?'…ï‚‹T/¾üé/°¡1|Û{¨: ¸j}/¾½HÈFð¥Z+ vùX#Ü@ïÅ"Ü@îÍ KÄíuw\†í5&Ðúóþ͘õûqDÀvV›Ã—:ƒ|'RÖãðH_D)|‹ÔOÃÕ„j7‡KM¢ v7q4Єu!3z$Öé—(ÿi¸ÙDIL¡/Š^JíµßÐXF¥1'M“ôûï¿û‘Tˆ;¿ˆš4¹Š…é %½ÈÒabEÀq²‰¡é` ^þ!ŠÕšE«ܽΦÐP ›u8m¯ºî•å˜nV/óï‰.GŸíð.R)w5õï“d,×à=ü,·»‹x”þME*ó#¨ÓJ®$ü=”|CE"›ÇäyMϸ`»@e£LÈ9W@%Þ"á!ëå=31E’öƒÎ¯Šæs´~Æ”Œ9*@tvwE2Û8Ê„+©*¢q5o´C·«¢Y¯ÃtFƒÌˆÆÆ6Ü!¬ F¿VU:Áü?ÛM¶ˆÂ¥ð4ñ²|„J¦¡ÒA¨ª;4dÛ`ËÆbã ̦­‰f±Lô}£ÛB© p0òGUáÐÀb•-–ÁÃÆEãRÙ–e p¸0 Ó«û'ú"\€W¾ÉGY«]‘ÈcØ¿?½\ùúetõ1(yžÉ~­4+×ö(«+RY† ÑBI"†ú÷$F5oE"É Q ¶zC‚17¾"4zxD‰¦«7&ãÞ«OÇYÆY´ˆ0c1–z{‚1«½n¸~•Åb‰%%•$ÏÂx»zÅr5þ-ñÕÞ¾šê’sРö²vœdºNÅ•6‰+‹ª×²¥;ãDn5L¾`#J«ËÓ—1M¶Z¾º ŸˆÍgÓœ…ÁV¨*Û:˜S` Ó`¬‹éMxp«ŒÚk#Jùørnž¡ŒD6%¨‘IÝž{F]›ÓyA‰æáçu³œêµ9‚I®#F÷e“©Pªí¹ç3;©}"ÖhëAlÞ7w¡5±ÎÇæ¶*t¼ãy 0Ô"t°«äߨª{^8äßpõÏ2Ñ0ǹ¾÷£Ø¿ðJÖm±ÒêÁ’W£ ›mñŽØ û¦pˆÂ„SÄC+ì›AJ¶Ùømâ7ƒD56z£øMÁ QÞ*bdvGä*Þo~>7MmŽ-Tg©¼jiøãs>ëQ9ŠÕ¸A¬ ©¢­ ÇŠÍ)…Fy€NjA©‰5F•ÌG…eÛöɶóÕåx#ÅthéÁÿÉ„&Aå°Ô±fæèèX6a{ÀÀr~hÒ â:ˆ¥ø²¡ÁçÅ—˜ïÝ—«+r |.ÔßÖò‰6ÚÊ*¦PK)›3œˆ’>Ò'<¨KM(9j˜7pÛðæ·ÛßýŸn?ŽØ RpA´§“x£w‹†þÖ ¼õßß²Úû1+z›ÛÑ9Fó*ž± r À«†Çyæ0|SÓyêØâ_&ñÃ+‘QÙÀ ZýŠIÞ%&¸È,Ÿáa ›P¬ÛïG\h¼Ýø1;x”õµgŒÆxFLB2"'Œ½+{·^£.­9<û vˆrΜ“2Ñt…óH Ô± |ϞѴ?ï±FÉè.ÇäØ!z:†¾X¡ïOÏó¯ñeÏÂo$èlÛîÿšA û•Zñ`—Ô>ZÒWÄö´öxa¥æHÇsÐ=ØÃˆ?àw$Z™€TyIZä©ÖÛ®½#]³Gú_A´Ü¦E2}Ì-öRàRõtÏEz!5jkYtYéK‡Þ—ÈE‡üéøë ,ǧ<9†® :&]çè¨V¦|Ó!ª(¾Åà‡å˜`~‘ˆ¹£ÙÐG6`æV‹SÀ¨ÌÇìÊÙœèÇ™­ /®íLIèÅ>ÎÜ«ÍYº(.fM79æE úÉ üh?’…óxˆª /ïjp´ øsÕq-päÞDÁ6{ RtÚ+\/)Tßu˜f¿[ïÕ9 õðVt‹# ¬³Ç”ü¶ÝA*Aµ GÁA `ö$ùó FRš2­O¼q @¢™­”ʲÝP³‰&[Wy ˆ eßËè#|ÚJï \ÛÚ·Ü…4Ñmcbú_fÏ_m³ð‹ºÃM„•ÃUñOÊç·Mp¬~‰»W @±gdüÁf–t$]„‘®3xäמ+òçQê?ñœ§‘WÒKߦ­4êO“Žû˪㦣#_ÀÙâlÀ@)æ¶¡¶ä6úË<\Ûeıå(#ÿPºÿ†º1[¥Xt€(á ½ eæ_ÇšþaâT¯F͵­3L£«¬0Ç4¼®ŠÆA„t:0ž\ÜawaºHÒUÏŸȓ|7:™Íþ®?}Ád J*¦òh5Eæ“G9£LrÆšu.5 ùúc˜mÓbê—¸`D—F"ï2¤@¼ ï9;°6ÏýW~ƒo¢‡8œ¿b-5cv3]x“ˆçáêà"\Îö³®þ³€¨Ö=8fMzê{MgúDãñW<ûÖô®â{Ç7ß~sZìÞÛpžH˜ÿ!%±åpƒA²‘Â+¥g›3N”fdäßÕZtö^ÙUš{ªÈÍÿmæûÿØt_ßéç£å ÖÇû9?X·.1~c8oަÊ@×8^ÑÍËl–¬¿ Þa ­³¢†Õ~ àSjy¸I”|g?| ávAó)XnCñàÔp9ÈRºgu¿EŠúÄ,zkiŽd²þJîl±ègŸW ÉcäUíbåÂyܪ7ä{à\©JÀ¾›PYŠø¡ò‡¬¶u¼u¬ìî ŸžE%«åº/ ’U°zRb û% ¹´ÚFq¾AÞá:ÙLð@foW®+.$y¤˜ h{ ¾Ü\h!£²•ÉS(ï—œí o}¿õËÕ5çq`RáFO5x¬¦-zzuEÌ kó0Å"³rµ7ÃÕcxdk›Å‚Ô|w ü* 2Á­0êž§C ¸}Üà ¿¢_ù-p¿].ew&"”§›ªÊ³Ê°ØPùZ[I¸NÃ9msÑv’Ÿ³l}ÌÃOÉç0†õ$A±Ñz’=S>\ÍAp R—þ²­~Ó^Xràp6»9¤®¦¹ž@·ÄF|•}øˆ5¥ž5ótžñÞÓm\ó¥LµñÜ ü0ñÂÄþ.¥½Â¥½–ÍsÍEi/œp­W´:lG´Üµf5”,§Ôy'b„ÙŒ•81yÕ gœ²"´á—uaY²Úø‘à˜Æ² =ÃÐ&"Ä ’ÆéœCêrmÈ™‚ÍâíË¡ u›ÀÁ’sUÌÛM(ÃD zH°Y¡h óŽhÉ@;Ö@((`.rnÂŒ_ÄMˆ8#GÎÂ¥ò;ªƒofNðv"’…ü"v3g{y;<¯®Ö,ˆÑ”³£\BÛò›a¢æ, n'"ÇÝ@iJÚQ\М!µv"²ötþPI¶xûYô¡¢´Ö÷wíVþŒ¦,”÷Â^šZ+8øjNlS= °©O´sKÛ~œ¸ÉWmÁ¯FðXÍ„Ü|.úË}Rýgÿ”ÍÑPÿ¡á…K!NªÓá|ê œL£EÖɤÑ4·Hu!ô=pRÝÔ&œeXðQ*Gušç؆øh† Óªiœ5Ž"ŠHyÙ/ºk'©‘¤(!ýôÕ~™…k:ï”Òt`Ã¥÷›îBþ÷]=ÑCN‰ û9/ ˆ¥¢º««?€ª¬±¨ ±ÈaQb©±x~ àÐ+ÇA>4£Âk@œbËá3è/å&ü¹”›p‘[ q)6¹›ôá]l‚\!¥ÔD!v)59JöRjR%t)59JDnÄØ/ÁK çϥΤ“êÐ{ùRfÂûse&¨÷Ÿ¤"m1{%&ƒˆ·ÀUÌrÊKD'Ö—ð1µ%Tßba‰nä×ì¾k¯wÏ“-Môþ¸èÀuÔ¦bSPC¡LÇBdÑŠ (£Ñ}J lÖáŒwãA˜:—±.¸±&½óàÕºŒ( ㌣⦡¬œBo% ÖÐð¨è¤†4ðü.p ¡Q°³¡khZ«Û¶aB=ò¹|0x0alþuö˜’ß  Ç9˜uÃC j´9*tZ)•|h™Ì> ’CBu<ƒ©¨’%[a8ßÒ{Ï%̱Ù&Ï11#Þ¶¡{I¢·›0å(j%8ì¾EÚKîçqròÛ!L/I²›5yŽY´Ñy¼¶ñª‹!R·uÏ;{`úµôWÛ,üâg4ÒVý#øÜ—il$«„iAy×´¦O`À¯¥ŸAS³[Be³b•½®Yœ÷$ŠMÃ:“9Í,X>ú>4]×À zðÆ%Ãrõ¡¡ËÈzWWä?·¿þÎnãõ6{F·h5l´íR0åí& ÿ{n2Q3Ëþs³«`iK3x6ª„¶4³I6鲡`›=r)¡Óp³!š£Wå-=q°ûLŒ$ÄçáI±R£Á98m ¦4Óp ŒúF ­•A}/ÃŒº»\áJdØåé=©OH–Kâjú÷_é+ê2ÿœ—Ìh¡"^XÛ]Ç>¾ºú£ú78xÒ¹Ušñ šÕáÛ³dµR8‡Ê@ôVYÄ›E’®à<ÜS<ƒ ‡Ñ«‘?ÑXhVu1ìqS'·²ú„3Cк›Äûý;…Æûæ1u88¼H8Â@_²òÐF϶à©h¼wŠwçš:1|1…’Ûgq¬àœ £ýOë /±ªk"£*,˜ÍÈóµØb2‘¡«¹©+Ër„)+IÌÁ…ùag/x*†3¬ Z¿Ê÷:ྠöOƒ6'¦’݃@&cî‹qÖŒ '˜Ûï@œºL=h]7OðP(äôÚô`ÐÂM2mQ]/â‡ÅóV~höσÕ=Æ¢[„&Ø‚ÀŒÊf“ÃjŠ£pbQ˜%0Tÿm)#ÏÏó¶>³ßšK;º'"`v&´ä”là 7\f¹4ŽŽb ìÅ}’,9 €gÚ1³ŠÇd-$àÙƒY›©mþ¬véNàÀP*é8gœ¿}a5ECÏ$'š/Ñ´¢™ä%˜,£é >º8¯\QsÛ—ÒH.¨à uwpâfãì‡ã0¢*NÊeJcWŸW{ ÖµtèÄPiUfc Í3Y Cë¬F…°,<‡ù”“gåzê5¨y–Ë35w˜2A¥’t ®ß…€w<}ð™ØíýuK4:^K‹/ÕŸPÝÑ5p÷´’¢O•5Ÿ˜§“» |:á® ê±x¥ =᱇gz\In&Y8G• 7ów:ÊËŽDWyÈvºŽ#Ò†¦ç©^æu©$íIæRIÚûGE%iKQ'jí(&ýKµhòÇ«E‚áÀU¢†cª A \î¦Å‹âv„Ø¥s£×çŽwn(…S|A—í˜P_æM[ÙÁj6YµÞ¿Y—D›÷À@e“ÆlØë×U8ÍïÜÇ2Ž7>ér‚^âYÅÏȦxÙÆÊ%žuŠP}?ȼ–éxžH…Ú ÖÞ^¼j2¯º' ™^uuï'w÷8ž4>ùŠ÷\'OÜO”1 U'º… ÊŒª'ÝÂEtœ×k똪Ùc@l–Õkû˜² á C'^îŽçàOúµMKçJÑ•=ª8|)"šçSý^dÌðT”_V:è.~J¢ù÷?4… 8¨ÝßünM¼ë4œ‡qËýòj‚4MÒï¿ÿŽ£ËEìæÇñiË£ÂÆ:úµ„ùi õ:†²”2Öµ!¦¶¡ y<| Ï1ÄFUJ|3¼þfÛtÌB&Xîü–ÜwΘÞ±ÂÑk#<µügd}þÜ¥œèwéäGÀ^i¥mûâŠö$séXëIBâR •n ‹øë¡›vOˆ¥a»X‹•ªHOµµ«?D»ÄÖ®±¢:0ù©×›îé:´ÚSoãÌe[º6 ŠiÛ:ô°…;L_1ÕíÉŒ¹—Ò2š`m×…V‘Pç=Љ˜î•ùø[aY£€úÓ§MlðU§²Aa´JU…nT:“Že‰MG¤Ò7,P1îžÛâJ9è'?°V7±Kî±×Oä/Ñ2—hOO*³Žu!©)Glfì"/»¨™`6Ôe“÷Û¯oÇ¿¾òmÇñ±jçåúÛ ‹ÔÊ ©ß§Úe: É8æah,65€5mÂ3jJjLl¬Ahš"žéºP‹*!$6bí qò ÍР^ñµ7Ò«Ïuˆz¹ºÝ¢A†âfÁ&Ú1  *M¦ „UÉ¢W'dcØ'%°Y‡¼‰»2æÇ0oÝŽ¥Çt8NZIä…[Ï{1ˆ”cYàð¯ ÎјÆÅóYçØ;Õxm²(~xŸÌÃÚon°ÁÝ~–AQï|x†-¢2q3Ò‹Í_lmŠ‚qK©¬±ñN²9á½0<@Ã48`«Çg“-ý§p–%©HÜ#§G=x²›ò”Ž3Q¯Ó›pàKHšâþÓ›ßn÷ßþ4Ú—¯ÃY3 îÐi&ºÐË©~d(?:`¯«óÀ{µSêò´AB„žîòøIR÷/"bÏ2!(R7l¨Ñ”Ÿ­€Ô:•Æ…’¦LæŒûdzà“ wf4ÍT¥x&Í÷÷YêY0{Üér¬§Ò 2³“œJpE¤¤¤è˜£««Àn®¹¨¨9*¥cÿ6'ÿzB÷Å”Äü&Mƒ¯(~%Ëg pV_¨_‰žG­Óí!Š? ÝuÏ%6RÓf@ßÞ<¹‰FÜã‹5ñfi8ç z” •Më8<ªç8Àéçþ:K©•°Î CdÈ—PÀÖ¹w|÷n©`QS–åÛðãš*†Ö2à–Äföc–¬¿òÙŽ†Òï”öªñ,ü)ÈpÌq ǹœe´ΩeÙßI»dû]g\h=_ËoáLÕ)— îZà‰À‘å©‚h*ý1I>oühµ^BOnQÂR¨’xAYø%»¥^l,ÇY_áZ|ñÜQ£˜åeR4¾…îF‹ÈêÚÚõ¦çÐbÍû$ÙdþfíÏ’-þœT¿™ÉJµ«+Z%øãŸY¹Œï?Ä[ö…¨Ú—Ì>ûëd;~§ÿmôõ‚®KÊwbáOËâ­Õ+Ó›®j(¹ÇÔÉ3xVâ@Ö5&^¥¢Àù‡W áhã:!E¶‹(ŽàVÅ…‹1¾BŠpÃxî' ²“4xÀ›Ù&*d%qŒhÅ‹gàá×¼2‰™ Aß`µÍöH#½ï’vR7cdÁz¹åÀÀu°\޳Ϭ¦h8_``0Ó¼Àd€`ŠasÌf¤°e¬á1Í6ꃫÌ<X5Í(4¢bÔUaÆYe¦9à1?àòyb¾ÍÞhåóüÙ¼³RM© `Cm‹£ïAi*o¬¶SçrÛ ]ßAY|°ƒWß5€JÝþKhTD0M&Ûl½ÍëÉ‚.а=æ¡”â Ýáœø‚Rßkx´ 4¥q~s ?²_瘿㑚vwRž¦~4ºejàV¤6ü&{‹sšwiò^o·1ïC)êaÛzãÁ¡ò5]ïoæ”—¡³©lçªWˆ«ëP}(>0ƒ+sïÿ*;Hbžl)*¾*gú6¦G8ó(î´iªÀ*« VÀ,ƒÆ±ÿ_h–!{ò7ƒVÛÉ•’ º~ÉÖ–d£ wÉZö&¡gr³æ™à+š`Ń®"&La/=|ï¾¶^tÖNRXC$!8%ý=R¤t˜Oƒf[ܲ^ÒÎIˆŒS9/Ǭ/òAz,¹òú€:Hˆ:ØsZ@°:<¶žôéÿÉß>íG#‰‰üõŸ£8{õçï¿ûó_ÿú×ï¾CÔ½ÖŠŽÛ¶ ýÕÕ<ñŸ‰ÏNª¿Ö4ý8ù8HÓäN_ŸÈ¥oŸ2 WW”ÿÌIoèA'ã„J"ðˆ­×æ mˆv“ÞÌ‚X„¾ÕÐt ý8§è_Û'Z–l×ëŒøÚ9¡VQún›áùóŸ^ùÿûÓí4ÓôòÞ¼}¾ùÎèÄ&Ê’eò,òENì$QúÞ‰”[TÐ…÷°´ÂꖭχjZzÄ]n¦¥ƒƒŒ"º4 1ÆpWÒ×â}0÷×yb‚1•yÚ?j½Š0,G0À¦Ø,¸gráÀÆÞc*@ô:jo¢‡8œ¿Z&ñûŸ‘F›É‘PTqýÚç,ÆNJXQ™¡@áÆbŸgÛ4 ã0ªïrh¶uޤï—Öà?Qæ‡äiØßÍC&¹[Ã'GQ8R®…xˆ7B±÷P%y k¹Æ}÷*†ûî¥Þ‹ûóc}œ}Û}ðöìu³‹=yî8÷3Y§n ø%‘Á _¬‰7Ky±KÍPÌ»¦(ýNÖpMÖÆY,o¾di6gg0‹¨Rý”ÍuD¦ôð¢v´GÜ…é"IW9Q´N‚³8¢ìïò éãÃUõ),(b£°XéåœZ’mtY6—§[äX–oöZŠÍrxÒ„/%Ã&<´â’^ã ×?b›^~ò•MK樠_hÉ!oÆüËÄÅþ-©#<â-i£q±älKÆ‹4W²h†›,:|ÁäoK¢¨A{¸4Že¹`´Bxèß¶9¢¸J‡89`Ù*&9‹E<=Cç…Çì¤%a:£;`ÅlÌ"¨¢ì…;À0¡q¢x…æ«¢”;¿yn IŒb¸fü…æèU=àK]³äAm¹“]0Ö¶YËV­Ír š#¨e4j¹yä•ÇO1Ζ †c’ý˜$Ÿ7~´Z/¡ê38à*ºÂáÄ!ËÂ/kËq‡ÂíAFÿQ¾Pÿ^RiÏx-0çl1¬ËT›œ—Çú$ƒæ¢à“n'wXK&ŠY?ÁdTaCljúbÙ|î+ÒõWtLç Óà|°È$ÆByó…°‡Õæe\ƒœ‰:”ÙÅ:8ænàÒëH(M jVm:%r`u¶éq¬S©-Ëå"Xi”ê+Ä¢ªˆb°¤!p@Ñ^CÄõÛsþ±YØò>H?‡I~¡È"¿êŒÃ‘ )Ž"*‰‡jëÁÕ™“³±“ÒÅÜt~ꔹi޵VdoD˺_‚•j ÿ[3SðÚU…f [dtf*†[<Ï“+8J„;Í7˜ÈŠ¡1±yý œØ±gØ‚ce¥U÷Œ5 `“¨*áeZŽÍ‘U7qÌ5Z6x:"¼O[3yò¢ˆÊ™Y¡ÌzžÎÂÓÅ-‹>£pÛç$ÀlCçiµo¦ó·i$éüg3>íLTǧM—'õƒR5ÓQÿò[8ëb Á°>%{ \ >*¶ÅQï€]³dƒž9ã`›=Â`1@g Ó$:œU†âh¼SQʳ_ûêŒÀ„û{Ž­tJÃÉžÖ¸y¥ v»Õ5{œ@ÂøõêÒFÉÆþ}Øù¥âAcÞƒzQ† ÊÔÞébúšmñNØúB¬8"}…1Þ¬æ!ô…¾’m6zƒÈ9Ø¥•ƨ6v‹Èñk¥1*…Ý$r‚h¶ÒÂî· ?ò¢é̱]sc,ö.7Y+"Nð¤”G–å srÂ"ãKÈ9:´æÑ„†ÿÿ û#Ú¶S>Hy¬‘q BNÃ<…ç$`E!ÖWéûO¿Œ6äi€¦$è ç±1Ö(+Á‡pm°ƒÕÓ:mÌ¥…¬ZseNlìk…U¢c­õu\Õ˜¶=–ÄÌÃuΈà9ìÏŒ–Ο1>ò]øˆsx|Å'¯mè˜s£nmøgN)1õž‡m+¹§`¹Ý··ŒñaR•G&š‰)ÉCåS¢"ûŒ<\+ÉC(/5˜×_‘¦8Ô¿41ÊM*âH¶¢Oï²ùP_‘ˆQÎQyVÄ3<‘êMFÁDõÈË5Y‡ñ*™‡Õ %騖eí%Ý0Þ®^1ÿÚ¿%¢øµ…êD7è™|CÖŽäÓAýqhÖ–¼Êá%êÞ 9ã@ï8_]mÂðó<‚Ä«e†–…7x‰›&x¢®ä°ÊXßâ®3áЉ£IÏv$ k’ÅUÆs!:¨=Ç<йÇ$Ô.g”S<<¦yiláë¸ã^åè©,%4Ž®küVLoÅÝG2] èæ:ÙåÇ 6W˜é7¯!M ÕNõà œž†™‡7ê:<Eæ¸õV­¢’@´§æÀ•Q¸˜|¸ž952”G®R½O÷8§Ló0ðl$úùy¶c} 0S½MÛÖWc›c;R=Ú®»û×R%'¼ƒ§Ëþ½=­’Þ>$ñ5aɬöý4ƒÔ½qBCšg'% œ4[ŸpÔpWµ|Ÿ¯Ö߬ýY²%[uÎûiœ¸,ÕòáÏaðÙ_géˆgsä‚U¥Pxfâµmp6|t“p²!Ïìfb"¢pÎVÊ1'wç—À[xŽß©ÃIª'ô8(€ …Îè˸ÝÐáÕÕ0•Ö¸TæmKãR·ÝÂåù1'ÂNhþ0Í ÂOÓËün¾nØ1µøàh>g XÀÞ뎋ÐHÎH]ì=ÀÞs•&·Ù{ÿý6 ¿°%üøg–B÷ý‡xëϾ|!ù.™‘“,£Ù×ï´þ¨÷A)EÊa_O×áŒW9ÂýæH ç傎ºPAþŠëŒ€úÑOÄ!B°Ð½@|^39xŽ´ïgÑ*'>"Ñ­ÃY3‡ð$oŽŠâª~³l AnC"%¤Š1Y¯Æžð´u[ýô:Âhú%ïAƒìEcU#Ì?Ê;“ |µ ŠÎ;‡F)°—Å®ãxº¶R<´2ºšn²¯@Žx‹´ šx=Š¡Z¼çÚñ¼o–,“çøN›˜ô•ŸkËóAÊÛõzôRFð”"eúk<;¬±¡ØÒåþ¨PWyÅù•}ñ ÑËh,·uGÕ¸ÅR™h ÍÿÛü/euæoÒ4øŠ#ãf‚8tªõ:{LÉoñ°9¾_p.@ÅV *JÌÇ<Ï}ÈýŒ/Iko¢‡8œ¿Z&q_H À£«$¥Û˜ÕÛD³>r:%¥‰ÎèrÄ6Ï+\Í5¢K,\=*\Íó©ñEž•O¿|5|ä™U¾Ûk¨â þœa71´tœä|œ,S¥Mxl•P” çc!g#ÏÂÁ†{8¢™êPçy©Š \îÖÛB¨óí&Ì·?žÚ4ÏJ8õ†1_~ý¼c9û~˜Ø1ƒð˜¼³,*Y-—£¢MµZǬPK39QsÝ­¶Ñ¿}º ±»È—øyÂÄ/º©å­ì Q8:•û}2¿(uåA†—£\OÅëÏL”9Ú­Y°5y¿…³þƒ@³NêÀPU7—†!œ§f~9§l³G¤³A˜( €ˆ_¢Mi§ñ-xQ×ô€'J6‹gŽÂéšOA|’hæGù,ДAár>¬‰H¶¥ U«¾ n)LmùË, "¾yH%¼@>+¶Äa–«þˆ¡ŒÀ•©0Qa÷ÞcX3'†úéÛøXãq?žWÁñ³,[(™ªèMËøéªÅï™ §ïõtÎøîÂK£þá3ß`¹ÙÄìÜéWWóDèV¥^ÏqêB^¹£'RÉÛG¨ÿ!ò«Î•À%mœyd¿/¸“@Ù=Ny3 bòÖ1EîÈÇ EÝ>q†²d»^‡`Hxç„FÉŸb1†·Ï7ßéŸØ6Y²Lž–bï’÷NìÜ>B.œè9_œR}(Õqx‘Jº(¡…RA®>ù³Wåï¡|ãp!aØ ?gÓ/è©óƒûM–³,OŽ æs„¶/Žõþ3ß°cמ°÷¦IêèM¯ùøáÍgè4ÿŠW­–õÚ[v^6EËÆ¦h£Ÿ]3Çf]kÝX4âW@ß ^÷VÌ9æ,bFéŽrx<7«æ/ÅÛ¶·t`ø.WG~ã@aŸ `%-ˆ\yaMyã¬Nu-8D%¼ ÜÓ XÖ%Ò°hXü”ñf¦ï“8Ê’ôúï¼m‹Rñ\G=üÊ)Éa™Ä½{ð {¸$žÛ8K£xÍz 鄈Øn‚'ò`sÔìo?’MÃñe-­³Ç”ü–ÓbU°9F~œAý;¤¦•R¹!‹ÜÜOx%êš-Ô5\‰ºÙÆá¼ÊIQÙJÌB¶ôº‡ÓŠ Ù¬}W]t ¯ñ¼ñT5_ÃÍ‹mè|-Æ”ÆÐ%Œ¶H®ÙÙ6MÃx„YrDgEÑãýüm¼¤ƒaš&pÀ¼¨»b4&Ÿ$/¸½•™g/E5][n½‚Cµ× ž9^.5VG¡þ¼ýt»{Ãáþ9:÷šqu£„§ñèùbM¼YÊ‹BÛˆAþNÈ\2aœEÁr¬“XxxõsL9¨=[5O·QüÙZ©ãïq: ¾Û8‘i¥ eptCõPÃÕ8 Ï Œˆâ)ãnÏ»ä!ŠïÈ•ÿœ¤ó¿Óaªv AÝ:6oQ*JDŸ\iì}˜Ë(þœOŽ+ÿnÌ0ÝSSã]¾ì½þIô¦‚gÉú«àE¦‹$]Äçú)ÈÐÀÎ3ºï=h ¬Ac"2yWƒïƒôs˜ @5[ X V³cèà22àø¹ýì¢(~ÜO8DVŠ$¼¡s¦¯®Òð>ŠçWWIöÈÑ9ÓˆT¨AïJ¶:=Úœ©5(ÒÔAžOI4§¯KŽÊO²m³mZpÕy.QŒ§·Ûxv—á`<9†{îO–ma7ôœql×¼èÇzF.L8wµ•Ø!cØš”£¢ Ly¨Ù9¥VŠÜÐûÑ\à¶èf Îãc!dŒ»Æ´Ô#ëº&îö¸[PñIÎx-Cnf ,1_átX­je›ž ,o0!wŒõ鎩¨uº<|PÕg¡Žõ5m:PÛ VÏô䱯 Œp×Xãd±v¬ñ9Ymœ„¸¢½A­v²ùÙ·x“%8hÑŽeq ¤?C´híoê9 «`c生WË6J›u7ÆCkq:Èx‡väÓ„F=ã<—¿z½¿€)Rp3Í‘*‘e§-›é´»AÉ3Ôúä\Ñ.çD"4Õs„ŸÎXõ£5ô.çDË —²ÞAjçè_tÚm)¾Œ Ò#Yhð¼¦^,é$%­ÖPØ ½.¸ëˆ 6S— Ë7¤H,m„™-^8Ïs8õ†1®Dø‡ôi‰ý>QÚ} p@!Ë0/Õœ Î1Ym³}7æ›4\àÎœÔ Ð§Zä• ‚û*¢A( ^€Ž¢í(O›ŽÈ qÒ£:fÏfœçJRm‚|0”¥.Å œ*7=Õ öžÍ1VJ} +PÌ18F|w™|C7QLŸ¡ÛÀ42tÊ(5fñ͉DyeèÀ³&¨¯š ôÔ]¸ü· Å„ÜHAo²¥‘dIÊŠ¦w— ÑîôÏì7.¦\mñz›–“ýFËT!ܰËð”æÁ˜f ³½œ/–.:èmXxùcUá“#æq òïç*rU¶;4ÊyŽ®Ÿ}£\cj$‘4´2w×V>|Çs €ðVèÖÞH9HiX^­"TúÔ4à< âÍr÷ÂÕ=Ú‚ÄÕ•ÿ¯$4àâðy·8µ‰ôÁŒ¸[é'mM¢ccfÀÄ“¬XÎåÐü¸HIµS*Š&âCóhlrm 84e àî·m§T“ì=žhuGQC‰³èû«ûMF\w?»º â$þË6&^ã_Š#úžóÖ¨"Ý“†XEPçÐ?éâq¬¢£zº— nøšýßÿ·H›žjýFôý™?"À$Ì\½ãÐèñÔZÈKuìŸñú<Ê -àÈYAYAóx ˆJ›¼Þ/®Ú¶]F‡¬àñ5vñ{ õâÞÞ~YisSÅô3ö?òNˆ–úEªoZµ2^øÝ÷c ¥AA­*Þ'´ú öj×÷ˆ =C÷8í9M¬™p~ gYÂÒ©d™yàž…‚:8—6Nn%ÃD(‚Ź9ûGqϿߘÞsTì"ï”o ªÝþ~“ã„à!9Aåцj×û—baµ€=¬çd„ÞY€Yàݤ°^Z’1¤éÛè÷¯û;C£¿É‚þè0]Ëðèša Y}ÐR0"ñ5Á,¢8Ú¦'ÎA2œ3åÛ‰T$Æs?Y“¤Áƒhmª„óØŸ¬ƒ(Í•ˆþ¡ôë¿ýíð >?«ò™—9  )ô¸>9÷áÅ™ç&"Ï™§ú3Æ{0‹Sð-;ñ%9|£î;xÄãÅ}çýÈÅ}ïøøÅ}ïXÁÅ}ïZÁÅ}?ú|/A²ŸÎï‹ÈrÈÁ#,µP;W5->á±ÛõŠåb?ïðú¡HÿàJƒ(Û\]1ÜU²êÝß|¿ûÅŸ¾qïòh£œ˜Ã 4P(w z9üë`\Õ« ¾©úb(]{-zú~ ïÃiW»È4¾ÏŸ¾Ñ‡ Ã7yOÑ ÒrI±*ö¿—ëéå_OTÏ—»©õç|pí…\L̲|“·’1¢6iND÷Á1Zü<â\Õ®ü$#/éã&j'*3GbL´ÑD?~¢[©Ríô1\/£YðM; UQ|£–íRçúC¢Dä1µ±] [¿ úÙtЫ˜zý%$IˆPü -ùFK˜çE$IójtÇãý"7¯&.™3ñ›ö‰‘6BqÏä$Žˆéƒ:½ûÉí0žËJ„qïµ q`òÿ¾3 ¬›ÜNÓCq*J`0]oÔ¥³-t¦Ôž^V;/ÁçXD)G£}Åáƒïrýä‚ïqÄÉÏAvÝð6öY êUôCõ·ªýþûK$+’s6)žšÆ_J¶§¶q¿Ñ¸ÛyîKƒ„Á浉ξZ)%²¡ßòM6«ÅáCŽºDú‹Ÿ1Dú/-h©KKD…äð’¹´Dý¢_ ¯‚×íËæC׿8ÝüDä:ÝÞ(×~0øÓÛhyA:ˆâuÄùš/ŽxñsqÄË;;cqÄD.Žx‘‹#Îå+ÈsÉáN‰$ç\SQc_›@îéýç(á@}—µ_túýû¿™¼IÓà+šÊT —6±¡ãBÙÖ™%ë¯|;¥¡söŸkBG`Ê+×pì1¯ž¡dj$UQØbϨÏô+–Ñ+L{¤c*ñænÓ€ b"XÎ]G8ž#2á¦U¢ xÄÁCˆ(`϶…ÌýQÈÈJö*ÉRxEo‹cÊB1àKpGbMuИJ¼±S縟X#lE|¨Ç$ù¼ñÏs¨ãdq誥'‰ypwi8 ãùÏd-êÝ'T’ÿ¤lâaý†>>Š Š<%¿d‚>ÔuNåøÑs ð^M&'ŠJIsÇ÷ÈÛìzØm‘We¼»%®—Qg×ašýnñN‡„z9Ç×´ ›<žØn€m‘6ÆSç™ÂWrh{>lìôà[Óæ«®‚ﲂˆóÍüb8m•Ç®—\o–Ëdvu•†÷QÌ1)µ>hœ‘ê-Eq\*Dmm Y!~ßÏ—.±ÞŸ9Hë6¦[„쌡ž6—ýž—jõß¡-kœðoJªú@nòéà~òEj'°ö÷8N©JçËOâÄÝ]«Íf‹Ê„³6Gœï èœ1 Éôî±!2,®sCíYq5øU`9? lê7Àâ.Ï—–¡9:©}½ÍJºgjÓ¶øúXQ”çÁa‹ˆN¸ÍeЊ©æ0 <hèæá: gA*Ž˜лY¶Y¶¾fá§äsçÉGŽð>Ú;š§Œü¤*UMËq9BÆ› qòè±»É-5_Ô¶€ÀÀ35u㳑°®ã8%Ç/Jâ½&ã`9ÎËÏ1 ö~ùy<Ú†7Ym7E)FNÿ†ÕñŒT}&D:ü³äšgq¶íwQÚ·áˆ$J_A“Ѻ§ñÕOtRÂj'’™ó-Ÿ»(Ù,ž9b„%×”?`Ï‹<2JXgi¬~, Íûù‹4–“Ì.Ï!mWÄéVDžiRì¿ÑddæÇû&Ž u.‹ùŒ~}®©=õ#“‚gWö(½"`žgöïX2Š­æ-7n÷ÛÅÞ¾8BE©Z†Á/V¥?ˆúlX5Þé³Á§#–U/mСe½,nÌjÏDƒÏŒÈÕÕ*Ø|†›NPM¢òå1L¢:±ûN8íû¹þ‚{r ƒY–7…V éhïBçÛRÛá±Aò’A; ŽôäÿˆSª›çñvÙ ½òÎ÷äuþ«Šf_ÿ+IçåUíÿîÿü?ÿ×ÿçòsù¹ü\~.?—ŸËÏåçòsù¹ü\~.?—ŸËÏåçòsù¹ü\~.?—ŸËÏåçòsù¹ü\~.?—ŸËÏåçò£èçÿÉÀeðp0davix-0.8.0/dist/abi/abi_dumps/davix_0.3.1-gcc48-x86_64-linux-gnu.abi.tar.gz0000644000000000000000000045054314121063315024301 0ustar rootroot‹ÉäSì]moÛH’žÏ÷+òá€ìÔdÙþ°‡Íd„Y#™Ä°³¹»ýÒh‘M‰1Õä°›¢5‹¹ß~ÝMJÖ %KâS”X3Ilù©§«ßªª««>žÙåE÷»àÃèНKóÕï÷ìŸÞõÕåÊŸ«ëË«~÷¯Ó½ö¼^¯×1Ÿó:—ËÞ\’°YûÊ•æÙ›7?Q°³õ¯ýüúõŸßÞ?xoþúæ_ÿñfñõöýwì×_î?ݽÿüaÀ>ü}ðáãà}<<Þ}ùüöÍ_ÿëÍ[ïâööâöí_Öï§ür¿úÉîEgíc™?.ô|ÓgýÞêO?$Òt‰ÔÊ}d™×Æ×ÛŸÞ»ûöã§/>²Ç»^ÿ•­P<YI+p“BÏR¡.ÆiºÂoÄo<ÎE Ø»¼í¿=ä÷‚«Öúò3{ÿéÓ‘M¯iwœŒF";²áË­þÓÿýéòùòòÏ>´é{·ûÃÃÝ×»ïm| Ö@ º¤«ƒ#:ÿ5ü4øñ?­¼ÖZß;¼õ{7ýëÃûÇO{ò¦ß6Ý,²?~yl°æ‘ ý5tŽù{«à¿ß?|¾û|üÐoE™ ~yÙü$|t¨Kªðú×××ï˜Ð~½¢‘¯ÿËœVŽPÃfÛ¢s•‰_s¡ô*Xn·Îf‡4ù÷íŸ]QÁÛŸDú8› “xKéÍÛ8“Di¦fJ‹É…JŒÅÕ»¸l6l*töÏÏW¾_Â{=‘eIÆ|®Å(Éf?]¦NwôPÚW’ך¤™¤«òÏ…(2Aý‘"‹|rI}=Î’B•‹Ô;¯Àÿ¸³w¼K3y£)…Ôƒ‡Ÿ/™ùVù‘$ƒÖÎxD‘«9D:Jä %2n BžÇ𭀩ãë]Õñ^G&ÒOÒÆ‚yÞÒ¿€£`!nK‹+Q@ÔãÞ-ë"Zö¸W˺€¨o{‰ºn.*Œ$j¤$]B5AÚmU,m›fý2FÕ¶é]ƉÿTÎJ‚½r¿A®ÀãwEÏÓãHU=àÝDRIyj×-–&柴;—A¤ÜT_–ü@{H%Ön½TŠ!³‡Tò¶®Œ$!-ƒ€ZffŠ$ÛKÖ.¨×Î8ØŸPçÌÑÀZ©Ô#°³2+w“z ^£@HÏS±)Ë¥Žbc ßèh"T*|zÑ·¥ä0ÉZ“;‹DL¡Ö\F¦Ï˜Ýþî>?²«I®Åó`гßhO\?—4»âÙÕF«I,‡5 ®[ͣػvÊ1c² 3áFv93K»ußc>‚¯nknüd2‰ô阵.‰ã!7Ûé8xa®s³Ü’‡‰öL1´÷L>â;Wµ‚Ù”g•_wƒ}µˆ(”âŒeÝ„¯íb:­ˆ¡ž2F↠‚A7edDïÊ…Ùbð;à²ç9 ¦¿²V䮫´MᯚàÆfMòÌ´ú/[tµ…]pÕ3ëº||ôZÚ9PŠÉ¿[ ÁJ°[ Á²P#Ð)Ø+Ñ’J—¶£Ò%mª4š¤ñ]yÐñÒ©ƒA«ZÞÆ¡MÅ¿pèY/;™.6yœF·¥ É01ÿû.|d5Ûè©Ô´7½3Ó^1pv*¬åx^zÜnל›6w1mE§L„~’Km£&we¨v‰«ékó1) £ëLÄÂìDm°Z[æÚé´u¡­è]h+Ûü~Ëc;Zß“K+±'—ÓöÑæú{⎪!tÚÞª!tÒ.ۺȟ¶ã¶Ó:i÷m§ÕF'v.m+S5?ÜÛ˜öÒ?[ t®GB3›AùK{D2´Êªñv𯞃´¡±×Ynx-í0­ÆÑB Q ySMyCÉò±!„b1ØB0µo^v)Ï"›|àuƒ„<ÒóÃj; ·…R)×pëY^¯0jE6R˜v:œbðÖ‰Á·fË.H0å·I«n›$í]ÉDGáÌnŒÏs.Íz3Ÿb58hsꕸ4Ù%6U*Gâ(b.t@qS¢F Á-‰yÄZ0Z)pÍqG&G­Éq¾¥óLKñû ?\æ) sé;“s0¸Ÿ‰xuÃHm( '2®„“$íÝ :IW*-‡Ñ¬=?¹„ÒYBp-e›@ªpÙ67£¶‰¢›ð¢èf}Ÿ“¢XŽÎH*jóÄ3vmh÷Û6´û— ¬-ž„ƒpSÝ(Ü”E7 ¯—F¼=0`ié4op <ÏnTYX´°)¯úÖ^­u1”3`wkÙ™JÁ‚å¨í:ˆTš.Åp!œ ‡° ›:‡°hyR±WOê:ëµ³™rGq?ý„<†öi¦ë1LÛžÌGqlyªÅñ‚Í õk1¨ãÿYj¨Ÿñ¢PÃö,†:žç¸8Ôñ$[ Öînúcá? {ÛàÞ»J+“ŹPLß{½ùw¬³Åt«Œ:çÆˆnìl‘G7ºvYôó,ráZ»H™@µEàý[™ˆGφ@–b /Á G¤sU÷3FUÁˆNU°f~é‡"=¿^ÍU€ZY„EŒVåЕ0Z•CWÀèß城’T•¸è~O"ÉdRî¦tb$×ÑT°1—AL`¢Í¯ÖyÜÞ Kd¹zúýJšgëù.Vç…má%æ]WßæZgÑÐìÆ ¾ î¦AÕê~0͘8.Kb¹é‹„ˆøQT)ßmLþ˜ªy· ÂJAþÄ¿LÜR¦ÝR¦ÝÒ¤}<äÆuOò r±;Høµ™‡ŠÊÏ|%ëÊý”@‡¹Î„»äz*në)õ²Aæ´ºÙ÷>Ö)U¶/Ç3Õdݵ¬³TgÑóÔéŽËYç¨Ùtéô[ëöŠ1GZXÿ.Ðz0™ ´.T^à•Ë¢+‡ œ µjg«o¬7äRjpuZMÝjꯧÍ#é7•XÞ¨¨ÎÎü¾#…4Ê_H=ê^Ê£ìî~G.¶\z‹¼]K¨oy]ö‹”JWšçσϷŒdÎüçgïš7›ð˜EfTq+èÞüÒã ³wÌ߀-¹aCã_ qwÿq:oŽ ;®gdΓ1ËÄ´Á£é ö(b£Oé»Çkf¾Õ‹pg~Ù5Ó|kpcZéR,÷æ7ºsaÄ}Õ”—âÌËÖ‘CÇ”H>Qñçýœ/’†nØEBv–m©$^Aº³ª Iê6¶Ûì>Ú©ˆìëùœ¿:WâÜHî°Ê[¢º>ÎÚ‘ºç :1™štZFÛ‡ ¯õ‹˜$›ÎÍÂ)¨¬vcª,üÛTGФN·,òÍ*ë8Ì’ ³e‚mnM"_t"ö½Š-7'(emIPx×»$v@F1E_óÏ“dMÖ Ѻx¥ Âg\î6£sîq‡‡…ðàNôÍAVï)y›‡mÞ>V÷–XↇՒÄW<,@}èƒHló°úˆ§Ž!r ‡usu.üvxX·ˆ½Aòuë–x†×{X½.­Ôƒ<¬>± ÷°®¡›Îú†î9[=,¨”íV¹ðïö° È=b<¬>r}ÅÃê"çùkVùþàñV¹øSyXЊÒú…vê« Õýs’[=,IJöµ¡= qó!±ÍžmÈöìùðÛaÏž É×íYÕoÛã 0Þ·c~À˰K’·8üØæíãðc›µÃßCøÚ¯K|ml›Åö²m&/‘gCpçy.,÷Y$‰¹Ö{ýÔSý ¯ÿdd¶{ý'bôª×åµÅë‡î<»½q¨¨W<à>ÂY—µõŒ9­xÀmF{ÀgFr»Œ%ºÃÆN‹0tIÙð€!þõXö.Ù^†,ò‚à!bÙͯŠmíñ³†LN©Ò‡ÐlN©›S<ŠFGò,5Iý@1ÓsÔiK¥µÂ·Eý>Qv¨è[ÝþËa Fç #Ú—»´Î@[­<š…'‡ÔÜô’ÉNMa†c‘WE8†Ô©Ê@¹¶qáI¸ÅÛôŽv·süÌÁß—?†R E<Ž¡uºBP¶íÔ¡@RnµÀƒ#~.ñ’¦\лò9ÅL|N«Ÿ“ÄMiž©6Éc'Ô\ÏS¯mÅOÚaŒÓqIT©ƒT•¶n‚ôûnoãhè¿ë\x·ª¬æÿ¯ƒ¥½eƒçHÿío?ºûñë\t.®ŽUÁ[v÷…u˜Ç”L÷°MÐwcn±-ãF’6É5—ßs¥™ŸÄùDâ´[ÁhÜyå¥ q×mg—ãqÓ!÷ŸB³œà¡ó0N <ì³ MÐ{Ï*Í¡¸ +²:Êñ5ÌCfh6äI*€Z E‚l­Ûø€xaœ#geh†vš¨~‰DÂE±°eµ¹Ô£Eì&Cnù–bçpÀèm£Oq‹iM>0ä÷|’Ö ÔãE_` ŸLE†Ý,¬µùÁJˆ'È$D.ò%ªÆî“Tsô U3éƒ!s '°5ã0ÑFWhC3 i¶xZ$€dq$…§Æ.È© ^£Ò,’9™L§#MðBg+hZ·(O7Ð`ä‚Zá-G…¶µ€Î"ͦ{. @Ák§1Á»†A³ëÐE"¡¨ÀÁˆ58-›ðìI½KZÀQµÈØPŒ"àá0….Â; ¤ÏÀnW]d&ÏCöOšµ&Ì»c}!iWJ0ËL˜m‡·\Öq eŸÛGu5pŸ£FÎ$”>pø§<ލÔxm¾ë¤ášb W´Ýšf‰+9Lp³s¤u€µÕ31I¦¾UÚ ‚ÅÄ"BÃjN[ÀÝh=Ä¢9ß 9…ÆuÀ‡I ½äØøˆuzY 1•Ï%²Ù:+Í_ëÚ'2ž@Ûh^„ÔÆGr-*Á!­…Å/q” ú¨r‰uxK@èø/"í™N¬—Ê&I´^°'<’¬°°Á£ 4Á©%|¼zréü%$ v´åRñ…ÉÜÿ+Ü<…|§!x˜Â7Ú‚2‹§ Jã)óx ¢Dž‚*“§ Jå)ð¹<E2OAtî]R4ÀÁÉjAu´Zœƒ4á©è 2>L2c ¨ÑðþáîÛû¯óšèÇaßí“õÏ0Ž¡ O’Løæ?6N’CãX®™±‰ÒÌר5Û Ž~+Kõ@1óÐø ‘E!Ê«ck,ð˜?^êï›Fˆö-J?÷²%p¿ŸC¦å$²µLtÆa±ì@³ÆO†IŒ2}7Yˆ n³¡ ¬o˜Ž²ù›ÈPç«Ì·é(Ú49ÐÉ‹3±¼$‰;þËÆ‰ÒjËÞ»£î ع¹6N»½&Lݵ.ëû¥¹û{Õ0ÏR¹sT»é¡a%—‰Š…HÑÀŠ€/,}z¾Ã|cÞ0ù¬Ç*n_öm mekj4î)…Û›|=KE·Ã†(;i¨cx‹ ›§)Üx6´'­Kë\Óî)£”CæçƸå0k¹Ä^άÌm‡IÑ÷sP´nIT äšgú£ÃcY>sÆ5û5ìÕè•K‘ÞešWànY:Ä0’<Ž~Ã-ó³ºc[’u·r—TÐÄuðg#›%P^½È¥Ï„}õF}¨ë€Ïâh4®Á;Òæ |kìýÑyÈpîâÃpÑ<Ñi§¹<µsX²žM%œ˜AŽ‹c9²¤&Àvärg¼d™0wLÕÁÇ2æ¡.K¡/qÁ¥ÐÆWǟׯà™Dšñ’ÍØÒUt¯É†°¸‚»2‰3ØK¸2¡QXÜ̳ !jMLÜ,qh°Øa ‡›vñG-%‹Y,…³•Lsk?LÍÒÉŒeݶÙ,L¦¹u™u–Ô¥SQ¥½ÄÌF¸í Ñ•&_7†«ŸÅqí›Ðv#½®=ò±ˆXK)¬²å‘Í.ê&M£)cÏ¡=m‘M~¶É€°Ësm•_£î¨ð0h#1~ÍE éŽÌ;ua*ã¨sÅ‚!¶Ïý1 éIä±Ó¶„Íæ nÔ#dž?OùrÄ¢ß Ï/€öžÁ3ÎB4AM(‹—ØdJÉ'Js”%y 4¡ ¤=9ƒóŒ“Q$ðÁ`–;ƒE¦ìi) ¤Cì`#Ø™®…ƒ¢)¤¡Z &aÀa‰Ö£CNì‰eˆ2c¢ÀŒ{g]òئ¤åK¡©æËïݦCVè/:â«| ºâ±Ì' æñZÀtÌ¡€Ê"$à0æò è‡2†Úc#ÌQQ¤‚hi$»QÆÓ10‚e——`X4`C«#K ä¸eÒ‚5gЀ MüÛ[¶~¡IcYà1  ¾qS‚IA”’“¢í˜XHÁB®’i.}( Jmž)°ÊÁp»®€vÜ+à–X±fŠað  áö]7ð ¸áSÀ‰¾Jðe¢À¯ÏðáGœò8 r…K›z3?›¥Z ¥ì³ éûôåÃûO°Ó"+CHz#!¡ÀÀöu…òAÎü\/]ðkrXÂÖ‚eZE°“ h[FhºtÄßwR ¼ýXê° \Ÿ0Êì¬ÝÁƉ}Ÿï=9Ô‰YðQ_@Á»ˆƒL±ƒ°«mZ¥Üc/œ”ÐS¼^Ó• ¢Fp¢Y껣Í$C«UçVé°‚fÓuš„œ¢éF#š¥@inKp°ù¡fJ ônXM²µÍžfeg­%©{M^°œeC³Ì&<˜FH˯ܚ° ”¦]ñ#wƒ ?Ì€ë“AÓ ¬ÊœSÒó‹ &$±2À}-&~:C&ÜDWÜ ™–°!TÂ0dj‚{"Å‚*¡¡4ŸÌÎÜÆ'‰t›x«æ±ýâ‘|£~ƒEl’Ö)EM^—Æ)är䬅©”«‘¬]›%×G;àš¹"Ž”Í’7÷q‹ìòR+Æ:h¤2y¯î,À('Õ!_à+•,C#)¯"b¸–˜îê÷rÆ$ÜVëYŒÌâ¥\©" +ØHÒJdÓÈÃ71Ö÷Ÿúºùw N…ĹT%[ºß$ø¬ƒÃBòb¾r'µÅGµî-’%×04lõR–F¸œŽ4Á™Îk-ÒÄæK=ÛèÚJD¸QI—MÑÆ§pK@‡s_ÓÍë¸ÍàÐ7š+ĶE-êÉdâ×\Hæ¿à‘µ a>ÒÐØ?¸×±Xª•Þ¯*p£<ã… €Œa 1™? ì©´Ò5Gêø®'ÃNB‹æ^iƒ#òµ°GÃ6ãC°4åzŒlº?Å¢…Y2A"Ž"eë@s½ZA£{Ñi«Xζp˜¸—-ބφèª~WB+m:DtÓ3.ƒd‚»âi1í™ ®Õéâ€®Ìø2+0¶šú, ”À)wÛ¥{«WnyM\ÕVN<ËÛ¢*i¾vÚÄ×Y`®Õ‚obe/0WÓŽšÓ´e Œšûf†,FZ‡Ž;o_ §<ã°Â T÷—<Æå+—ÈŠ y‰7¿Vr:P˜1°È±Â=vì°&[žÁ8QcË'*lݸ¼Ÿoäþdc#e<®!pâE#9ÄÙ;ìún… l¼”ç8ƒÑà™þ]ÊíBæ*E® ì©}Ù¤!¤‹ìo>ÇÐSã p*Ì¢(ѰÄçPL‰m´Ühu³6g>7;=p.qÙfmT«"4·Å"Ú:´Ñèž ðÌW©d¾G„UÆ^ vˆî0Ù •7‰Ã;œ$:CW%jù¡Ÿfx’b™øY½¹à6‡Äžt˜=a§K‰ˆœ.J¤ÌƒeáV€4` »kñÐË,|•…/²: …ÓÀ°X¼†f¦ùÝbvVë$¦Ñ$Ö03xD3F̘J¡hæDDsøô¨ð×b_0Æ*xTØaj,G¨÷k±½¢ ±zƒ‡Õ— ØnAnWéa2Q0˜QÒ ‹‡’V°X<|x§‚ãõ:2YR)­QüÄ$jÎqÑ€dL±T±!ÈÂG0àH ºÎxQWq§Q‹k î4E¾u¥l¢/2ãÝš ø8s tðH×óäI&0·«DC½ÌùœŽ˜­TSy<‰ë0k‘š…(ÀÅöµöx®ÇBêÈÇÝ bƃ÷hœÁ›¸ÛCf:s]Çñ\Å5ëŽðQ¡Mƒîj[,_xm}5¨È"Ónúÿܽkwã¶Ò%üsžï:Y–|ÿ6n·:Ñt·íGrg’ù‚E‘Ä6oM¢•Yóß_¤(’¢lK¬ *sV’¾ž½‹…B¡P((ñx°rã¶»Ç}-%ËJͽT,éÞ¯w“ÐbùáQÞªuˆÏ:P)ÚI'Û¾ Û¢ÑË£°ë=d;jÁ·=ndU|~ãŽ`'°@ªÏ­ÔKäÅûN¼Ž2Ë`32læê•÷–CÎã ^"ûbÁtJ(hí^pq¬LuÁPm bÁí³›Mô(C¢‹="EWÛ>µÂ¶ äð¨‘,zW™Û¦Ö摇QMå òŒ/È.ºÖ0U è•ð ƒ ¤Üo…ñZ@SEåä€gö2 ¨bÕL{w}¹:ʦT_e{ùÑ®‡G!F6sÕ’ðým¹–A¾”6ò¨î%‘^ák¡ZØTªþ6ËÖÙÍYWÐݵðìŒ ô¼„<Ê†Ú /6—GU 2¨u¤Ø(ó(?\ÂÑ,Ð;pç”`ÁÔÛ5;<ßÈw9<Úd6 »~gp”—(J∦_QGƒf]]e.­Yå!Œ®PD¥y–mó(©$7:tä˱èätßH%•ãPöCЭV\µ¡üY­##ê£b9++°©D󬘨WŠ~@ÆÎ®9Iê·i…œêT9Ã.¶—,ŠÉªÂ­x©_'|ô}û´mK}̶©|¹ÂS½Ò¶öøG#.¹G9j8½™¥Ä‹ÃElùl–.tn·Õ±µ­Á««­­XÈ )ûj|ÝBzøRa-è†ï5d´hr¯C÷½1¢kU¢ ‰9^í S2@b5:Üã¤Rò×$¶È"…è‚Ó­B®¿†Sù‹,ÆPˆ"‰Ý`áΩâ3aÆg9ÕuØÍÕ"´$¤CrɨBž„¬ÑºJ0«G³IT¹àI*q©|s½ „'M÷ º9¡¢ŸYö‹ò×D²–pêÄyzD[éXFÕ •¶¾dFvgxf‡T½¯fŽ>Ç&s©b.…ĹǢv(g9UÃB.7«ˆlûª·ÒaR݉› ‡ô:óLpµ]'£{Drö‰ÞŸ¶Wú>IîÅ>‚¾)«°âˆ L.˜®¿[ªÈ óœ¶-¨&¿Ä"s$¶•¶y—hª92ÝMöÌ–ñÅš*nÏåwº"âTQ  I}ë…ÇQ%­MW `ϵîµîT#nB¼¥ãm'íåܳÚj«Žó©j£íe˜QMÕe†TóÔ“ }åáy 4ª6h, TW2có‚„ÍâÐrlK©QbRîù4`T>‰Au‘ÃJÀ€*ŠÚ’J(@_.È?]P»\È )±#rÌÔ‰Ø,#`É1©2ºI !Û9?q¤ì࢞OQ?¯6UÿÜI‰«êþHŸÞ±åÙðΘ‚Vʶ.aGB‘íL]¦Ð*³vD ƒ9Ys =¤¢’t*ïB‹Ft‚±#Ê iJU[¢Á¡8“‘zêQM†„Çd¯¦½‘¼Ù©à1ÕG:÷©žÃq¬µç.–-æqT1c«5†ìÄ×±Z<}þNj¾ê´Lè—½È*üÚovçsºY!W-ªÓ ½—¾Ž#ÚV;s¥GR^.Z:DÓß!6cÊS|G½[yqC Få64"êû.‘* ßo»à D×õÒYÓ]¼áͲìã·GÜžQæ¹¹½"D¢²Q8–窓m*ágNŠV»LÚm ºêxõš!a±½„ 85­ú¢8LBRÀŒ-ŽlJ8õ®Hñ5´YXD)Z’¬)áÔ†A,9U šB$iòJGÙ”B¢Tk4ù¥1Qp¯ñÈNß5šÏcªbtsÕ(‹PUØ…M\=Î]$˜]°Šý6ìŠX½zÓ.ª÷ÿ=¾à%‡«£urûÀi·d§£„çNyã*+ažK•™Î!}´[ ¾ïfÅQéœYîê'Z%±úОî/G¹ÿ8&ºÎÈ“%WCE•kÛ⑸FT9±„Æ©ñ‚$´¨ñh•(•‰ Sס¼ÝÌU]Í»"V@ÉEÞ"Åk4rìøÊmª WAQٱ¢ b$QºRC~âŠò£ê!î U“¹y>)izfÎ7M™ªçtv¤%Z&î|ÍÜ ª½ÁñIÆÑ·ª¥ô“Ä¢ª|Ÿ6ÎI+ç„¥9‘ÖIæXTrÑ•ZäXd‰Ï퀪¥Âœ,›='ÌfÏ¥mYbÝb˜;œp†;t%ø9VÍat0XNuV!—àÎ 7¯9¹€„1Ìœðú]ŽEýµsªUe.¨<‘D¢‚Rµ„PÔÊ_ç”pdÞWF¡ *ü*àÁèΚJ8JÝ~ª˜ÝéU‰VÕ^W<ºã°Žrp©îµæX€áÍÍ/CØß«ÜoUŸL8Ìõ8ÕÕŽ‹úkÕ®—*¤ÐXTž£ZmUNºA¥»i¡¡ÔÀÁ©>Ít¡¿Ÿø‚¨Z~øVB¶¿QßH¶ö*LAÙaøâR'ÙûÄóÈJöô²>ް°r¥d±°‚¢v‘“jÁRPñÈV|…Pô+~ýˆ§3½xTîD"©ž—n0§ŠI$¢;W˜‚de•ptžó¼>‡nÝ9é“ѽHi(*×®°¨‚8ÂÇÑç‚sª•UA…dF¡ÑȰH“$‚2I"(wYªuíœðC5!ØŠX¸tt' Y ®†¢›R ‹ì‚Ø7Qï:»ž“­Ÿ ‘ð4UÂ.î0FMôEL*°ŒÎꈺ^Íóø›ÐÜR5탊Ï=¾¬8Ç¢‰–s(¢Z‚Ìu¨Ô•‘f_>α¨÷ga`º°ÜòÕ^"D²ò‰O˜µŠ–kõÄà‚… ÕNc}:è¸1a÷F…üÂã€ë—f Åõ×{_Ž82ˆâÐ&Çct? zÚt„TWLgkR+ª`RÓmPÉN+€”2¦¯«jûÞ dé õ riÑéMD ºÞ /£“Í!Û.`¬õRÒQ—h6ˆtãëpÏ%zsK¡¹jõ‹]N–%¨ÒA¾ñˆ÷±Ä¯¡JH¾ ê¤À¨º*¬”P0ÂÎn·¤áDÄé¼=å€VµQµi<Úo•h¤ÒɹO‹F*]˜Fõ×])éܧº67Ó[$¡"sP忉z Õ1!’ ‰å¤t;±„„žGÁ‘ á!³B‹V"Lc›Ëe/©>Ž|Þ!…¦€UFŽnTèn+°Ðr¬Q=—Æ[P=9³A#4hÊnI%¥|T•uKÍ4Ò$JÀ©ª‘P…“ÔË”ˆ´RRbG+mLЇÅ§]MBªN{9ó€n6oYxD½”Ô•¶¥ÜfGaþ;✰ǩ¤ÜGE‹˜¨¶JQ F¹ŠD¤’ÅnH×èW†IHìî+˜„Îjƒšú3ÂP°†J--¥ûßRÊH(]:ó\û…&QÕí­AêKƒ2û£ÑH¥£Ì®j4Béb.($ Gùµ±çú.Ù+ % \d{þ‘rŒ5&­×¯`ÒJJéhr8ZùèžÈUx©jøGGö nÇ<¡\Taâ¹²…$â”t”·ÄrRΕRB²»òÄWå5\-d #”p¡ýB;ç$ e’’ì&샰 nƒ ñ(ÃUF)]:£_Ò² u†Î‹nU¢lùžÃQŽ-e(MÜ^!’¦SâìqJyj¨ÀHe#=?ËáHåóéÒŠ Œ¨³F£{´ ‡#5“WÒ¥KàPÝÃ_ïhLÊ× SäšÑA‘]0]xáŒ,="±èX$¿‘Ç£ò$SݧüZº ŸîþeŽEæÎƒ”9|Å|ëgX‹°;] )§_ƒº¥œr²1ÏÙ,æ·¨nQÖW2°r©š÷/b+ ;VPe‚Ìç„™?õB®EC&TÇpKU“ß^aùŸ‹³£º*ÿ¥%ü€îhIù8{Fåm–IR kF&áíEUH8$-ÿX nÅTÈ 02ÍÑ^ý\&!Õ;Û Š(ïíÚ!Õ¥ Eyo?¤»¹ïΙŠ~ò=‡mÐ$ªF“cB6-$&½” 1 )1}ëÕšQ¢#{Ù ®ty£´xåÿ ®:@zaͬ¶–“ÇâÒ‡tÍWLU¬Y‘j¿E¥Àœ»D·ÚõœSE¨µK² õÇH(ƒZŠ˜Q>\FøL?ïB³7©ã6L” ¸n§d°u ƒ­¬ˆ,›SâÆÉ²þ:iWóR€‹¼å-(ídUˆ1WÛ]N *øÂçAµ|µ>îÝ Ý¥ƒŽì¹? çÕ&O¥vˆ¿XþK*¢ü7#ëBœ# +¢gI÷vbŽIG”£Õp¡e»ÒC'¥º®)¯Î*<ÕõP< Gµkw}å… ,;NN–Õ[¦_¬áVž¸#y Úm}3¯»€±OùÑâWJe3¡Mõœ™F<&*^XTRŪrª#åYTK‘°¼ ¥ÒZƪïŽw‹–T EF&™°]—L2•›¤ªº‘pd§®˜yV@e¹9ÕØASÍÐŒL²d]}u¶ ”ã.¨Šý 0ªœ;õ¯ì&Ú"¶"¢sƒŒê;]ª.Š‹Ìø½0£:]-À¨”XT¸‚"S¾Ä"S¾îçJ F¥ü( l:É•d¼H7É4•diÑM% F%YFåe¤a^Fçe¤^Fe¤!PFe¤APfSÆ9™l¤aUFWe¤¡PF e¤‘BF*d¤ iFº’f¤KiFº–f¤‹iFºšf¤ËiF»ž¾Ò:‘WR/B+¥l?c+p.nhD+À¨²Í/|ÍnÇë(\ЕÄîⲈ(¤PÐ<Àˆ\Ç%yÁ‡ª{rŽ—0ºÚ7…XÞg.á›.9²jºEŠ— KéRݰSHQ¥/\xWD» ¬bγ—~X+uvÁ 3"GàÙ/Qæ¥N<9GTο£rþžCöÌ£†¢R™C÷Ì£GV’éÕë²:AQÞ&ó\ª½ºB¢yþIÝê *z&}lÝ#ô^„¦EütÏ‘z¡=ØEúÏÍqP- À…²¤£êQâÏD½ú³#X e£š`3A GŠF8 ö’·Ý <‹åÿµ¨ljÄ+H\²ÏSªƒ4ŸKÇä.¨f?÷m;"*mT`K¢0VaQ…ë «úƒã‘T󘪹Ž“ÿÐaÉXDi`1¥…‘Aøn`‡1•Ê^—êMÊMB%œlF¾Ì]²}ƒÆ¢úHõT™U·¨×Ñ(±jo®ÝñˆÐvÔÖmH¥­+ŽTo”ßI—aôUŠ.<ó-:+“XDH!ÕižB"„¢Òzè¨ënžCµ\†JDÅ!™|H¬8IÉÆ“.\dŒG5+Õc5œªêͧLbû´Il?æt“SÐU9H¬YÌ(±MtÀ$±Õá±/ÖÕ¾7‰É !ý¼u+)ݲ”tö*}ÚôCIÈ–r~zœUÃäÛàÀ BáqNôÉEǼ¡jŸG‹¨.öR!fù±0ŹN0êi 2¿Ì“¬uigS`Q‰E'H¤Ï.Ù<õ˜g ºã´ M•q@/´ñB„Kª©$¡ˆ2çA¢:Çü¤Û–)ÀâÅ rÀJ‹½Áñe’áLây>>´ÙÜr=îkO[ãÜcÎÑ6üÕM4CÚ–x;ª'ïš®øQß}!ÚØm0W¤ V(XĪ]:]wS…ÄfkâPH£ª\2a¿ ™µ€vÓª=𨋠‰,Ù­À¼¨8>Œ+nÁ:ÎeE ]ãpÕÀ°m¯w,XkÁÄQ`‘ ^¸:6cß"ò'êñîÌ’]o‰¬di‡TÍ "+¥*ÑŠ›CG„­¹%–Ë#{";r#^©9¾µ—¢i&,C*£õ-\ɨ̶@¤{‡R#Æ~b“eB4"Ù¹ªFK:¼ì;éâ’(du©'UØT¥…T¡½•KZÀR‚’–Ϥå79¦2%ªªÅQDVõ²Ú€X>6wUn«~ÌBu¤\üÞ qÒ¨å¢5 µha!}Ve/ ]Ùd…BÕÚÃä×àrœ{Ö‚jéÝEtÓX¼°—Ü‘5Õžr/Eè¹6n „»pøÜJ= å¾%ˆN†šø8ëPXx Tà Tà 4¢^á# ëQöñÙ¡(&; ‹bn9d«#„ZÕJÓŽ¿O”ƒAÑ¥–‹„Ý5Ÿ £;0‹bÏõÝZŠtpüiYF„Ú\¶òYs„»|n šÅnÂÉPeðH5 áB®.rˆWjg¨ƒi}@쨜l ºX†qBÊ!¸GV¯Ée„ìêaDùdg”,•]2@P_E–¡žÃË^^–l¸Á’ËÙ  yØÔŠO3í„d)×*4a¤]…h«p«AÛ­ø(««±ÃÀa³8´ÛªÖuió´›\ì/I&ô™\äæûnDòjXra›Ë™¸0¹ÀªÇÉ,ˆŠ·Øäbƒ$†‹ OJtú5ŒÿJ©Ã4º:Ÿ "0¬ñÓ„¿bF-‡¦²—®X½ŽKY¿A–Ûª½~‰˜ØV`su•ØtÝÐ+Ðô†LWÌ%‚î 팪7J¢[# ©0s²pZB.-Â/•`ô"rª~sksª+lÍDeu+"Ë(?“ê,F"-jruÉÔH°ˆò#ÓÄs*¢à^Iñ2:$:”RFê‘2„KZ¶d‹t–™ìF£Qb‘ÂìdÓÇúÅíÑÄ×PTký¯9\sJ¹tr ²"K UýÄ›ã¡R¯I_?þ•ºÅ]‹MÃÄ";µ-²ê=uߌ‰Ê`VH´Ñȱè$Ë(ÛyŶO¥~‰DöPoÌ™R5`)ÀTíÜÜ Ù…ð nd% ‰ê %.åDË»óÛ›evAcD…šïus[°­§ô1÷]$*esäŽð«UoÙ˜/T»ü˜hwS ŠuX¯tŽ©ËMa@Õô›®NG!YËÜñõ ÌqcªX¸„#óý9 )¥lt/RlÐhn36Šs: F·õR`êÊ‘íæX4‚ÍÈ®[Åœª™ŽBšÇda™Dók)¯×ë5UúL® ”ÁÏ‚ð¾¡B«…&ç¦eF$]s€ÍÂ\^™UP’=7×D×MÜÜj†û¼&¸ˆ¸C¯ôÇ™kU7çyl¾¨=úÐÉÉÒ5à%~DÂýJÉD£;Íʱ¨ÖñUøB&WFö¬WŽE™îþ$á®\¢íß µU“ŠãT»Ÿn"›Ù2¤Jx{ˆóáQ ”;q¹]^Ñ]8/á茅®R¬ºÅ…T[‹Œî;žj„A'f1ч ÛòfD1KŽE¤±Œ(-ÁÂ={G VoïÓáG‰G†F6¢K®«ÍT`Æn²Vi=¶KfÖ¶5Ÿ«z³ZÝïñqÊ.,EðY¢ÚQº•óøg|J<¢ªSÿ$mm.wµƒ÷T`TùT–]FVÝs-AVø'g)U¦±æd\†”Ï’ª¡o¹]vIBò…K6»è*}VJ(ØœÔâæ‚RisAù¥”’[k´0¥j(áTS}Jñ¡îéDu£Õ…ÓØærÑIªNªSœ-ÕjMçóÈ^#—Xª›Ò½7_:è · ÛJk4ºv:ÏHçGÀ©áhÝK5§Þ)tJ"J-bºù°Iá†IH9 „W$ZLÄœtÝ–p” wLðì6ý!¤ƒ‹lJCQ¯Îâ‘ÝsÒ}ÒèÆU„ö ÙSðQ^ìRhtWm7hti&ýÆH8w,:Ÿœ$kJõQzuV'–œªÙ´B$ *Òä•nE{’•ªˆ©Ú 1š'G8ÿ7pdSvIö|ƒ„¢Ëå.}ªWH%]Zx™&N˜QmrÜ…EX ¨à‡¬‰¾‚óý`@*ߌ®G†îëQ Çý(YSʨ„T@ýhÙÛ],C²£9wá.‚°íÁ¯cáÔ!oœ’EŠQ°+|îÏÈrOî ƒ]þ‰°•dŽ5¯˜K‡SWwÆ”Ã@øÐBSO_TgO/mÒiû+åT•¾-VN”-I©îAJ8J+ÄÞ“v¡©ŠéÜqKßºŽˆ+ª¢d‰E*˜£k7Mø|²(Ûu«Ì‰%M˜¬>Tu$¡Yd+‘W{Á· åP¶Ñ”ïö Úw{][AÙKAÐ6S”5°¤á–H¨fyb%sA–G×htX+ZÑVt²9í?޹í.ÁÚNYÅ Ó¶wA#[éè.{ˆ$²#ªdt„`±m n“mÏJ<šwà <‘P9G…GH,ª–59VR¹Z G9¤d/Y`tÆA9DDµÉKb‡ê1,õ*7Ý]÷ Zu:ܶؠÑI7÷ÉÑ9™©Íc:S›S.-9ÙwzTOIJ¬€zq ¨W—€r9h?•з”þ( 4‘ˆîn¨#WÑμêðä€Ä# ]˜“îò$á:Jù%!Õö_c‘ù $¤Ú®k,B¹\º¯ Žn¢K, # éŒ_bÙYfF)©Êê:ë*Û/BÑ·d ŒpRÒ!H‰Ç ¥u)ݘ®x,(µ×yL• ÎÁ¨l„¬$}e¾ã£Ðæí8ÿ JùIÄ…ªÕ¦²‘OõÂ¥Ûna#:÷Y‚Ò+KHÕÀV 9oYŽê‰¤@÷;è›ktß§„ƒ­îèÆ<ò§a³•&K‡ ¦ÎÚ:` nÇLa“ ªn‡Õ/‡ BUÌBIUl“C*ÀY[åT¬¥%ù­‡BP3n½üÜ)ú–‘!ÆVF ™Ø5dêDl–ΨHX3Û–½$Ä ÜWrY%&µAeÖŒ )¢mO Ã9UzAQ­i KFYô°öéš~`4½BÅ: Z¨$RÞI6¶‚Eet8 ’s¢ë¾kÁäJâ¹Õ—–‹NÖÿœÝœuÄÜÝwœQaž—ˆGEµ-ˆÄË«#ƒÚ¿QäQqÝfSÐD;'ĺ膥î‰Ìfqõq­MNä?—Ãc­e‹º£ÀËÁ1ýW ÐúT¡´}ª-¦m‘íy%XHçíÝ}±µ ¬Ù] l¡}2¬ÕΓç]Û‰-ª–‰=÷B¢gV*ˆö1‰­zg&TÇYŽ®…†#»ŸØ*õ!ÝœEE)@Rå‘öIîqªÍDBúüxÂI Îîyd¥'ŠªFŸj«”7`#›“uЧ«EPH *…I,Ýq‰.nÙOÿìäq‘·q „´DÉ8 qǯDéÇïÄà?aÛ3ÉGeÚ?jöçìô¹9+ÑXTeIh Ûu©ÀdPC•ó/ÀhN“0":É4•d™ÄVÛ«àȤ#ÒŒtL3ÒAÍ(G5f”qeœªP:ßVà¡Q>ø™$kºÎ—™¯LÔ^—(åd–Geÿ´«ì?ƒc2qÉ?dGô©åYTE'©g¿D™C”NI ;Ò¥tWÛS?Lƒ„è©ÛŒ‹nR¦zGƒ+#£;OɱhŽS$V(mŸl$){mK´¥Um=Óá3#'K¨êÝ 0¢Ò¾TpÏ%:;UXNÂLJª§Þ0à„Í¢S ©ªÕ!‚¢ËRh¨@T%;~›n°Ó|gGö™ÒüéàV„o/¯,ÒÎ+‡¬ÎH!9 UR¥^~ c²¶¼H"ÀyHuEj5'Ñ9aÕÅjNZ"á(…[ZÁ‚êÝŠ0D^ùt]eV¤ú§Ô>mÏ¡­“¤ì·²¢-‹Z‘ÖE­(O¤W„ëû*³¨Ú³i(ªµ…v,)‡Ru;§ƒ"Z9é¨éîiDÇx +¢£²TBCÍlºî4‹îâzfÇIèí3[v#ØâÑd¶5•ýK,ª»æ9YkG9d7© 0ºÁ¤›‚®5#k!±™lÐÈ€¬K…Ä¢mdR$ûZºF&ŒôS g]聯¢(TâÑõ2‘`tÝBí‡Rº#²‹¬ÃGŽE69É:|äX„rÑuøÐptæOÖ“#Ç"TUOŽŒR2R•QêŒÒùõ÷ÐX„q-]ŒV4RÙhÝUw &ÿ¡ÃrªkÌ®OHF5žIH¶Å¦Ü®ï‘–îI°uD¶éQXTrQÚ«Ï}ºT‘í(ÙŽB‚ùáŠj4%a*M¢‘UŒeaìðWª!`ó˜Si2MžÅ.Uù¥†"*ç¡LÞ¿:ÜŽ×TeK¯NÌ,ÛæQÂFØ­FãÆ1Õœ®èTcÇœ(¯¢®xL6@9ªn_Y±O´Š)ÜYHµ/Òhë„êNÁ©+¾K‡hÑØú‚èÈQ.-JñÔ4|ák+^•–6PéAcÊñVÓ†ðõC ¦3ªËA )QÐ­Ðæ^H•eÕpdk¨BSÕ¿Ò3’ŽðrMvDÁÉu~pÅ5(χĀWÄ€7Äxt`Ò!°@?¿MékJTRS”¨d/?xªŒ6%Q½tI‹¦þ¥´ž¢¤™,ç^`†³Ÿtxadý¢z r‹GØ‹PF¾E´™Ú Õ[¸tF õc³t€¿RËaµ3ÇßHPx1Ÿó˜6á@Çü'·Û G†Æ~¢B[¹AZºŸ•ÔëŠ%Y³†sÿáTga/‰ÉžµUx)ñ!¥Ž RÚ %^³RȪ•’{Ÿ”Ú°SòÐ6%mSòà6¥ŽnÓÀ¥ê0YÀ½Òf‹Vr…¡zŒKã…T¥¥ -‹­ˆØ%úÜ'm–*!cn# yà„rGm‡1F5.á‚¥ðÄ‹‹©^ã iu*C3Â$s'ÄÝÚ5ä›íÐÄü¿o ñ_ž;Ó áoƒßÎ~;Ó4ÿç`Ñ ¼»ûûÑtÊ>¦÷“ñÓóøñ¡È=>¦ÓolËq„~ö“¨û]ŠÿÓ\t?IÀ3âMÙÌeÒ2©ñí™ ŸÏÃ,>){CuS˜Qs{†“ D!ØÎÃ(Q·kéO6†¢rƒ‚B-‚4Pñ„<}°»‡¿‹’‚þ4~fÓçÉøáw¹¯ç꜊\ú `ùn0,¤ ÍÚuEG‚ Ý;JW}`¿„> i¤>³„%Ñ5@`#_2ÝïOà X ¦FI²ØÇÇo£;Hè¯àG?¾&wϣϨ¨0, ³¡B€Wf+Q!HBöé@ñl©¿ä|ÿïÑççñ÷³œŸ€¯h² B&hò5i f–4YPQH“3%[XÊ#1v­­“`M ºæŽï.±šÚ€´´%ièáyôûhÂôͺ¾íCGm v6è(»)à±Vƒq¨tT€óðãÛ7”ÑhlИjlÌ€>~úŸ£ûçòð …RzR{Rüýó¨Üž?|}}E•ãík—_£@YS•ÃÄh°,Œ£~ºþ 5 [¥Zm'lîY êㆠœ ðñ¡ëàIäÖK‚™Z±'¶'aÀž„ {h{’ÎïùîÓ·vÅhÒ€& h¢lXàÚ‚ë ®¡¼9Átôß?F÷#ä©lÉÃ†ŠŸO|,ÇAŒB•Âö¸@BÚ &×ú7àa„¨KØì&¬Ä¢#äE+ÅŸ[©—°ü¥“ǃ…º¼…ÅíT +fŽ:ŨÂ3þŠg`sàtã{E‡‚³Ùš=Œ?c9ÌÌç&¨ú¤`KBöãùË ŠmÑAÞãùj€])¶ XlKÒ¸ X…-=@Ö ‹ €•Ðr` ¾p@3H/¼à-Ïý‡;yÛpz¦¿ŸF ½††FY¼ÂÆì¿6ÐêÚ0 íD·å ó†Ê h +h9@l ´©1ð1þñ0þs4™¢‹š4 E§Iƒ1Þ&‹t¸¸ñy¾F.tTðRâûÓ/N &å†eº<Êd x©è¨hiƒq·tä ûrv~[˜• ;ús<ÃOØê$ UÕI0Ú²G«ú¡“zMÍØŒÖKŒoænà&êö*âÔÅ‘˜¡r†.›¹!’Du܈±Åä›M9€Ö9’`uA—1öLõ3€»Cd} b}r*úʶÐ(•làzAMÍ2?54EŽ©:NÂÄxiî@tL Ñ‘z*è¸6ð¸Y8|ŽTÐ\" ²ϱA!£î"@b3;iœŠÈðÓ©öÝ9¢lÆŸå›bTYN‰€ò°K·* «1Å¥ "+©%®Œ G+Òønâ®8jYÚ`|d”&Œ‡ˆ… Ûþ åÙ4Ìœzb-†˜% Y·\§Gæ~ä©M(&Œ.áA³ÄÇ„E%OîÆÏ»Úå WÔ.½ª¾àº*ìùìê†i§)qaÝ467„jÒìR⪣KòfŽŸÆ¿?üøŽ˜ãG50×ø«èôó\‚ç¯+pEŸD1Ÿ»ÄÅù5‘Îqýø꽕™ í$öð· WT5x©wº^Ugö$&w(HTm•1·ÔS?¿Rò³~–-R+¶‚á|4Sć|Q¢Ç\˜QXû‡ÏÒE9ßø‹ØòYln%–Çx‡Ä;vMCžB۠ʀL}$R»Ã©sÿ pœV |Œr"õ•KœåRÐs½&"pg–àWd¹xsÀ\œ3Û–dŸ8Ÿ•£37d Ä}KðÔ,×s¹âx®5£®8ÓØÞaK± SÏAEIséHW54d³¤P™…°nå»%&Bû…ºzwC "ªèL¿©‹`PU3äM *àr¬W7À~I1,C‘0°lê½°~Õ¬§?“¿BÂË]„€e_2(µÏÖêé<`ƒŠ Õ5)ÌÞÔWjvFÉ8f©€d¾”#¹ÿ>ūޕ䧯÷Ók 4*¨°UlY. Rèväep½ùÆ@ϸÆu­F, W½ä)·RpT¼¦ò“T• #îSâ`SÆcWi΄B@'PÊÖÀô¸Q˜€ºÊ0÷¢$Å2Q*ˆ[n娈H33l¹ôUì9,l•zˉY¦d‘ %Z0/lì…ZŸ°˜´ž€­øä—¶ P`ÚGÀÓ>š”¬È”¨!õ:±#u¯Æ³‰Y m5u0m]KtP6\c«‹Ñ hx:_³`ú¹cdnh'Ç›£B-¡¦ë s±BMÒnþ#6.ìÓ·ñÃç¼r°âäið]òް5ýºxDrVX6YA½îѤH–º²Ç¥¢+4.Ø¢\¼AÑg¸+à¨0§Aa`¤ P¤‘CþÔ—ÄW¯zwk)p!~¢xÖ‚ ˆÑr`Ä4Òï±$ÀÁü>z¸ÿ¤÷fôÐ_†>ýó%p£Ð£O t?‰-•è8pÇ]AÁ±ÒóWêý^+½\¤¡àXéýä p¬ô"ôVœýJÉóÜ­àoù…‡KX§ªè8ùÕŠ2D |xÖË8}OŽ*:$ +Ñ!1S‰ŽœJpú¤yœy*íDï{&£û'ÜÈ–è‘-Ñ#[‚#Fö¯Ûósx¬:¢¨Þ(±ñÖ$e“Ä¿¢_`؇ b|Õ‹5 c°°‡3ê*Ž6s¬D%¿å¢aNÜŽ'‡]ìKÂúq÷ «³ù±H‰è{©TFÞ‚§D†¬1ä¯(LD%gb #6äjs›^± âvÉ{¤JLD²2æq¨6/A²}N~¢úÀ6ý€ÕÃ0<"*Yð䌮H ŠÁíÎ1RßïlḼ‚sœßà¿ãrH}Ëö!¿à¤Dé™t§„g”bÙìè\U—™@¶\ãi6ÀSbÏ-‘®·0 >ã%n¿×Î=0O,Ý9õsa%.9¬~kUZ8½ûÐç>€}rË~¥.yáæÃæÔd¨ƒ: *´ÏD¡ª±IYw6 }Ä\¸~D^cþ°9ã作 l”Ûª`g,Ê9–Ð@Ù‡›óGàlC!'“Å¡ma¾q0;²ÓÀ)uw¡h„¹ˆ82a¤%Ct€8Ò[J5jˆ ~ ŽØÙoÁ[ú±—/Á›ø @T_©‰ì7À˜ƒipû€xTfƒJ?_ ž:!欦‚­þ³ )!b#åÅE11(²Ž11¯ªì@œ·)Ü€/,õæ ”¨,("²EŸ*ðÄ( ³èÝf2ýPÆèáÇ÷ÑäîyôF1~xý>šã§ˆ¬YŠ8”Nö¶²¼”³0 ö?¾°ï£ïˆãÎy‡Ô±~9¿ŒÁ§ß¤H`ŸûôGà7æˆ,˜I Xâz¶E½¢n€ÉËBrà€\÷wÓgÜ '9:îå yåD#ÃÞ9ÉÑaÈÀ·N4>äU’{س$÷£ÉóøËø^ÆO߯÷ãâÁ£63ßB¾PÜ¿»Ï/ ´µ¾èúpê}§zŽ zwxÉ uýHÞâ…þQÙ’egLI¿¸As/M‚;Þ)ò ýÑrÿ˜8æ"m–vž²û0HxŒƒyˆð0 €wi0·©‚K,zbŽ#iìÐb.Δ¾»óµ%ùG½›ÿ£B†¥ `[Θ£©1à<}ó%îb›ÿÁ£b9X²oŽ™©z3PÛ¬ü—&ÙF¹(XÔ¬Ñy‘£~†ìe+›2”z0›ð…òèØO“¨à £ü ]!fbÙKêæ[ \»`¬QV¶ï¥~U7T$' PUT¯lƒÎ<ª·’Ó7ØlÍÆÄõ—ûˆ?ýO3D õãs"‡{<áØáÑN[Ç»`­é—›Á_bÄΪ<&&#ŽoˆD¿Ä'(Ü4ÀíQÓï·v9`ÕN1ªv*ˆ÷*© þ«dÁ{°*•¯1dsp?¶Ëòd¨mvqN‚‰Á¿£ÚÚ–Ðôõ yãÝÙLuüð×HÝìCÁÇÔí84ê?žK|÷¥„żwÿøð…9©Ñ?4º…¦¾«‘3FÂê-ºÃçVêé¾6swxtCU<ª ÜV¢(ô$vâ',5¸ë‡NêqÔ«X;ùOÁ$EÝi‡"1âø¦I£k  '²v8€êòBêç7JXŸÖÐ?]hœüújlýfŒ&gQ¯Q.õ‹êuÌʹµ"o8Òô‘ Î<—üàBçéír^4"gØb·ÀG΋FäŒþ–¶T--,6/ðéûüÔàc.£Âf[>Z ÜîbÝ]èz˜"7Íé(¦b™+ãÛ,³ÆͪqºeA®Œ|¦ï\úK>j˅ܵl˜Œ…kP.» Û°)\¡µe/¹ô  Kw394r¦Õž7TØ‚Ëöcý%:³©«F›ä¥=%ÁÎ!ôÀ¡ÁV3©Ç{ÞJÀ…ù»4m‰Kz2ä>{—ùM©¯ýf†ø“‘(ŒdÌ;§.Û+ÀS±Ôè Ìò؈7 JàÒ&ÁÃ×ç]°ÑÆrÂpŽ@˜Î£9Þ½ ³»wa`c- o{…Ém¯0µí·½ÂضW˜Úö #Û^Ä£2t²”ÎÛ¡o¶™£¿"cKËçžçZÀç`JdÐW%ÁSÀ¿Yn³!ÁÀlÐqÏè” PtèeCySçóhªg³Ü¼¥Ä=&6ЭhpÜ#F<\§!åpª 'n‚UŒà…#8§G–Nà§p˜‹Ñà?ÇÚú†ÁGS`çÔ†Ì|ÞLs¶JpäLúâcËZiƒøAã 2ñ›öd€³™ƒLÃ,ãÖ f¡VË… o§ ¨÷ÏÇéP ›fAUþ+•{LPT§t}Œë½ñpÓ³ vMÐÞ™¥Àyäˆp‚4€R„Ž‹yó†'ê¥ï¡ü€ñl cüŠs °ÇˆŽW[ •Eé  é?to¬4álúR| ºà-Ä%¸œ—–Ïò®Ó팺ÆPÓ`;,ƒ£-6¨Sw<È1QºF7Ì((PÙŸU`Ävÿ¡÷2i$Ã#â¾!ŸÿÐ3^0òó”Y¿‹Ä&/Îú<žŒîŸ'OŸ'ã‡ßkFƒ¾™J“ÞµŒ§Oßîþ~ýõ QСœ-:B1E öp÷}„QN¢ RIPý@UƒÔŠ^[#ú;Ÿ§w ½†žŽ!β@¦W·vQÀˆŽÊZFŸÿ ÇÅ psTE‡íŽÚIè·GšP˜ˆz ŽÚ!Iˆ€í‘$6"üÝÀÒG¾¾«+8`FÛ×)lÈZ¡)’b“ïÁ46ùVT¢Bö¢´dÂ6¹%4fšc·¹ÓGö}ôüÇãg6ãÔ/ýUÀâ»e5è¹M>Kô õp¢‡2‡¿òq#š¹A³1úLÆ ºr½²ˆ;d*d; ¤ÓJtKeÄvíp;S¡ZÄkXÀâÑ@`œsà1¿·o9Ü“ÀÔã…3˓߾Я¢€®ç Õçñ gÀ&ä¸ y”ûÖd9[[Žp€øýBΛ6¸ CŽ­¤Þ¬ÔMš"Ý£Š42ìˆ_££—‹’²‡­¢ƒ2)š=qKœ–P3W‚£òä94&S¾Å&_¡rhH¶¼MžW-Ñ©…Ü€»A&nkð8‡c µ¸e* ësPÓ 8·PÙË :uþ2ÇŸƒ§¯OÛ#"@N°<1(IÐÿöû—¡/­G5wÍWI1? Pþ@ã«^Ahüh8¼håèz'½Æqyç¸`kš<þxBl×±™ã ;v}7°è'ö†ÈãV p7ÔOwm‘CêG»Jhò㧨iý0|Q'/ê$‚Sßj©â3KõrÌ,á –¬#àhH [6t,Ô»r+®WP$¨I±å OÖH¾€Î?ÆuÞ°†©æWAè»–—›0’K=UWdC…lÆH+S^…yœ|SU¡P×ÎðÊ[ZÒ’£˜oR§¾ÜEƒ¨ò‡…ä9åÚ"³Ù?íõ{1h'Y%A9I3% ¬¿Âĺ% ¬[Âĺ¥HÐQ0ìîEáîÉ῎þÞö ç¦Ýš ‚«ÆGìj0bO£p!;Œ+G/ Ô†)AŠÑðQì®àߥ3ϵ‘Ú/`<†Aõì”:Up“vQô|(Â1Ćæq¡*ØLP!"¿÷)t°”sòí[dD¦]c#¼ Ö_¸¿P¡c:ØÂ££9ðº£9°ËN‚Yó¹¨ê¬0vÜ@~fh0%Z›zì¼t•{&õ˜ßHµúÀ:GžC½MÁ# ÀaDŒÛshgF\T¾E8 ÔUñZM¡ÿÅáOn'îªæ [ý-ë®Â$0ÞaD}â’¿Bg·«ËjQà‚Y‰zžD½#‹š‰’$ òÐÄà[/¼u,c\à§(o…Ø‘äÈ¡@-_cgô'Uø%}ÍX _* „/zñè¸GßˈüDµ ޹Ü1ù™{Y‘Ÿš„à@àý³€8P]ñº^âËõ¦ùóøénòü7¨R ž¾QP ž~•yø}ü0lÊJ\•l™3?tRZñ9ÇlMþÌN¬_Ä#ß…ؾ£"6þÊí4±f ÝÐßù­«o€‚x!Ê‹%šÞÅäÀÊQR7lªBOï`Øêš(úäîá3(øôùq2‚¡Ûn´$¯&kÂ3,裙& u¼QÁ—NÌásê—ª ÊWnžÉƒ±ln['qIœ¨7ªø¨w*I ’¿:‹·aw!©Àðh‡•³àÜ æÂc u5tK’Çvx‹š»1РÇÇ[tЖICn‚W¾gu¯ÚÈèSju¶‹ÿÍ–ÎŒªZ*àü7(‘>hWÅ!ê˜À Ú¡7ØäZhˆ çZ¢MžÁÈ耵ó \ÙžËUí´î.‡ö."±×Ö?àFEçË€ë£ZÀ ÀÚÑoRݹéb¾@é¦Bd^šÂYËåÄ%n´X%€´·¬àJѪ$¨Z´ Gì¨ûˆ«ÎªøÂzÅ¡7DM¨Ã“íº:WíAQKxÌ®HxŒJÂlñA»ý’–~©2 ?–xÙ2 ?— .),σ۫æ@ëJ‘àí¶`1ñ1xûÕ,&>Å# êD¡ê  kLÈtbÈÄÞs—З£0cFŒÁ¨!ÀÀÉ‹msh;êÀ£~<êУ~<êÀ£~=êàSr?%FNÉ+=IÑøHÇ€>…¯r@þ¾ÊuèSø*zªox±F•ÇD¸±Ãg† X)LÕepI®‡óßDµÁž ß„è za¤@=²ß²8²/ÉŒåmž›òËü1ú42 Йÿ*(ƨPÀ¾:þC`A_•ÿ¸½c…WVh±D…Æ„÷jÒ™ME&}ù‹Çq#â¯þj— óá´$È;~h zésÉ!A|QÇ_Ýq*à©R¡Ëج ]ŒÇy¥CÜÀÛ’ ̧„f}Ü>hëjau´á«ÎÑ€h¶àPe©å×Ìb+¦®Ã)xeo%´žÊ C•ZÏ7½‡¹›> p^CS|?¢Ð?¾€î¿OÑ ßŸàp=Mþ~zFÛ“zK ž¿3 •”?Óˆ¦€+jt&(òXù0ßhïñøé¢î§èx}G3|½Ÿ†H®Á*Yƒ¦€»gô²ýc &øëòìöÏs$`Šün˜†qþ‚Ú˜n±A;ÓhkªYÔS¨ž¶He5XP #ÕäÌ·bêw¸n:®¿1*èÌž È[§+‚f¨1·D€Ó1÷$ ǧäòšMT¦¦@O–RiŠD”©9ÌD²rúõkˆ§HàÚ9²ûÑä™?ÚSWÀ-Ä*èôá$øx:ý1š°éh2¾û†ÑN££:DSÓñïã‡ßóá€(ªÆ€ÑS‚^Mrÿÿipñ~%¿4+±ïÇOÈQ¾þ‹Í¼Ð~A<_§´KkP@ÚUîr´>0FÍCÿbAƒ€¾3f¯#ÀÄ®è&ÿQ„3êD€† ‚•z»uAÞ’¤Î¢Ê4 Ð@¼mŸ¼´Ž¯úz!ÔI„)ÛE•æî²2/]6i9ý>¯Î“¨vyXÍé­$”Ÿ[Ô å·,"'T—ZÁðL„qBþìé–;Ö‹ÍËq.u¿›-~10Ç‘î]O45ãÔHÀX„¡¼€¦ÀQ»ûÅ ,„“Ø‚3ò®%þ–Ø@ÑD}¢O¢ævèðOjyAƒL&Ç iŽ Ô¹:ÚÃé¥D‡dAÓü)0®Ê9p¡ÆWA éÍ7$Ò˜Ò:åp««†ßtÀFs  *¯L„”ò5HòGÁà4úY0‹p¨p¦îêÁ"¶™KÞÂomû¨Í¤DΓ'ôKu.gqò: ,:è¡Fz(u¸zÀ:\:!” ÊÁ±C ´›ãˆ’Gͤ¥èH5m(p– \”žŽí0EÄü};å::yëÞüèžÁß9}ïá <Òunà±[ÿ* nç_² 7!‹—90·4 8ÏïAÁ‘K~Ϙ|Ñø»y‘Î’køÀ¼HŽ[Í4þžœ­’pÛ} ¯·û°ÓÜ: .ͶåÀe.J쎧BŒéKlP\Ò ]¡(ÑÐ,zCm€˜©qØ  r±N³Ò5ßfXXÌípÛC6Ø€Ês…P=¼áùÜú¢j}ËÆÜÞ× à¹¸Gz¯¼Ù›fBpAMSȵ°V?t¯/°{}ßë ì^_?‘…©Z¬ÂK˶‚Fº"Lm±†Ž)4¸(b  ÒD-uÐçL¹åj½4¦x!z™2¯‹Y0?tRòΧ>ª Âv@׫-.Ø`xÃì ©€³¥ŠlÅÒjœ9Pä~JÛ‚Ïgò Ž$>){3: T>«zzöcz÷ûq¥t—¤½Ðõ?—W”$ä÷~¾ŒŸ¦ª•X?%¬ò'´Ð¿F“»oìáîûh Ú:>ý¨ÖñÉ´ Oß ©†NÞ¶·†ŽÙüx˜È ìùær—hey)’k¦`+Õ×Ѐø¢jú<Â.p¨§?>=OFÈ©±aÀÙӆܤþø~wOˆ{Lg‹NÞa¡„¦¿3TBƒZÑø€ë7—þ6R Kþ”FF<5žNŒ~gŸÇÓgöô8~xø“z—ÒBBîU¾N>]²»§Éè¿?=~F´ZkÐk©AÔT;PÍ ´òãùÏwÏw0ÅlðQºÙàãÔ3zx†N¬ PI ¨žÀ:뤛û?F÷_§?¾£”S⃴SâcÔ3z¸G:  ÇV æaLü^„‚F콿&®Þ‘€˜»„ Ø%nÀ.!¦×ûLJéóänüð#H@ZbÔRb“«äñÓÿÌ+Ž,‡8ž+‘!5/%º2‹úÂQœ‰0N8J= ê²Ö™¾f§„Ö°u©J‰s?¤~üD«Þ³áì§Üua°å¢Aýd•‚ž nÅö’áù+6óÉ«‘5hÌɳ~[ÜÂ숋Ü>yñ´ÍßWÖ¬úL¤®ÌÖ /’?M§p•÷ûÎÐ#Ž:7¸Òþ0À °3t 8yxÿÜ”éãJ ²c©0½½ÝOŸØ§»éø~2šê6ò¹l%ÌRÁ‘ârOD£iæY'ÐoÁªAq†.š®­‚ò2ì~*òça÷SÙ±›¸6õ‘ï>À›´ &úwƒ€~÷­ðU>|üÆUÀA¿@)¾@Çi}ú|÷üqJÞd*¨`)iò h<¥ ŽÑÊãÃHUúƒ- h¡+ ¡GÁ² tlY°J‚‡»<˜Xc—h4ÈPQFAòV:Æ]Iäñ×GÔ$ÜÀƒT³‡éæÇhúŒöåÙ0@½ù†gIìÏ+4`=Á=z Æ¥·}z“ åÔ7<8ץᱮ Pn±Á××óµk\rË¡~ ²Æ‚s)›ó_ŠéÓ§¿Ÿ!„0;Ý ,uúº;XÇês{°„Çí² t j`ûlþø0ET½ÖñÊÑø`õàV€?¿Ž>c7[ Ø(l)01Mþß¾="ª› -U@Jÿþp÷üc›Í[”ŠJ”†~ÿ62q¶Ygm‚*$ÐMi…fY%xkZgÂ+ ¾AmçÂìQÛ¹€ÛÔBÔNµBón%ƽY¶Í£DnÂD‚ Ml/Ýgvš„ó9ˆdf ×ν´ÍcÄ€W‚0°n­B!+I© ð¶ôW)*àˆ{^,s iô\ïêš&Š! y—W·×a¦™£¯,ÏuÜ2¶a´ÆI{°=±ÄVO0ˆ0Y4xúêêX70vƒ9ñíÞ ¼+DÊcøaÀcþ«øÄŒŠ¬Xp–ƈHEJžr‘(g’¾Â[k¨É»!q…^¶È¯ýT9 ›B eº@b§o‹]çÀxX(¡‚^à0Kpu‰ 5Ì6óÍænOAgtDŠdŽB…\8Ê‘7ø¨¡`xH`'Ü`áñ<¾€²Œ.˜XÙ^h¾¢Àú<ž0NîŒ*àê2 ºJ†ªû¾–·c7YúB:í`nŒ,t¦uÒ²ÀÒ=µÝ€K¸ÄMŒ6X®u>´­ˆÉ" ¿ƒ½A‚Ç+—<®À')ýmæ+ïó”º^âêy§ÔãÔ¯À B¨‰e˜Í­¤™`îú”c Ÿ8<Ž1ØÒ ¥[ ÖËó£ æÉ¨-4à §Ää×KlúE7âÄúìR«#Ç-©üfêÚ Éßh&&yú4>ÝMî}Ý·ØôF³Å&7 ÔP!0}|ýüh$[t„V¶èôŠ}gwÓ‡ ä®AÓïKøL†ÖÔZÃÆÈ>å–èÆ¼¦ïȼAF´NÖØî"@)DBƒ"‘Q ÑÒtQfrÖñ1V¾åN¥Ù:áøŸ3[†/3‹ºwŽþ81ÓÈ!¤ª_A«jõ.óýøIF¾z„éI¢8´Y²Žs 3£´ ÞŸ‚?ÿY±åS‡Ï%üôî)vWÒ—}¥î»Yå`O?>}ý#€*itÿôõIð„|·T%AÄè;í½ AdO_ï§×@ì$¶z€èOýl;Æ‹æLȱ†ëÄ€gRéÌsm(v T´„fw?þBÂkWñt7ž@I&ßð“уà!¡íµ(tpä¢) øˆ‚;‰ ¸ÂŒD2‘‰AG4ŠÃhT£‘‘ÍÝ”øF"͆#óÅÈl1RmxÀaUAƒ}`xµ†X%:ÌÚÁB­’nNò ($ÐÊ¡qQVõ% l&— X=¡#«’>À˜*'0Pål hj ¥*àøñnÐзÀoP¡# jÂøQÇj[\ Vr€¢m±1ñYœUY‘Y–•øréø_(Hª­„ÎKKD"#Yâ—­ë4ÀH³€7ðè˜Ö@ê°Föàäá–ÄLŒ‹OVy ŒÙx˜AlðÐøº$0ckãlcYØ |™ñr0”#þüÇôî ¤oAñéîwD'á*:Vvú[9ø÷»{ê"Üd€)¨dÀ)éëH­âr$pøÓ?€ OŸoQW°_øÚ]-8q‘‚@ùì+p“`CÿÔP· ï§O2dä·[+ôMŽ*àóØåã­ôWÔˆÈûTˆ^ÈÃÊ-¶Ú–§&6Æm臽­9f¾mÀ©÷*9º2Ò™µ¾ÒÇû6uï²  yOíp;^G (ó„ùi¹„1ßÂ8uÇJ’˜¡ÖIEPõ<úÖ`ÔÒ(÷1~i’䦫$îÐa<ÐD8’Ȳ_´o“Â"'­ž¨rƒZQ!Ä,YQô Zi²Ä-Zš"ºv¬ÄBâKûRÄÔí6È3ÕÍ5o…t̨UEõŠ`èi`À2  m– HëÌû\†BÅ‚Ã"0„È`ÈÁ¾ÿþe@{‰Ko\‚³ _µa|¿»óéwíKç©ý›¹+¼B?Ëû0Ð/μEó];™åè+tfïšÝ=?Oô@ à¿`øs4ùÆñyü;æùÖ< **9€j*9`ªúsôMÂõTà”T€44žNŒ&ìîá³zwn|÷­hýg† 5,»L¨ñÙe Ôdt?~b  w(Ex¦AJ…?@íZ‡8#Ä[´5xÔð íkô v6T96ÓʨA‡cU 䔨P¿?²åÀÇ uä¨Ã#ý‘:¢rgzPÜ`Áqt?7TpáâÝ9'±Ã áA‚hnפ¾Tšm7ênÒ¤ˆÓÛë² Ã»6䀸 @kçÐ1·ÝÈåÔϵ šH–,jZIÆ ‰ oMš\»ÎcœÇ¡_pÀÆcã<@Ž×N0³Au|ævè@ÆV¡#º—à€þÁ%öŸ€WÉ t:I¼.ÊÜâËi ‰d²zÁª#®Õ{jKDŽù£TÚoA†pSoó튠xÔRoÙÉ…Edb±*yp ‰¦†‡¨ýhá‹bW®ªvòŠ×{*Üga²Ä ¢:Ç ³X1äïÄÀÐóØÛ܉·Ô¶•üP¸àè»Ü àb)áú‘Ç¡r‹Z#'!{žÊž·5âi]…ܸ¸ š,˜µ«ÉYÉn6·1Ra- ª‚í*npAù ‹òb_êgˆ+à®|þ,_è+_¤!þ˜Þý>bO£Éøs,Ôä@L­&ýÄzü6¾ÿ倶àålÁAZùïwß š) PÚ) @R)ÓçÉÝøárõ{—¥© J[ßƘK¶5ÜXlà_@?“Ç¿þλRè)1úëY‚ÊÚËÐÛ^. ‹Bi­€G)ª€'×ÍD×4M¿q‹x¯ É ï5ª~`€«U§Nnkd¾@èA¢Ât1wåÞšþ¦¨ÆV‰ÎX¥…}ž,C„fôcçêØQèg²sXÁS'„篔Çk¨ÅÎC)6ÆÂƒ… TÀÍQ$V’"tžwbúýÙ3³ý×àóÙÕ’QÀܞᤆ‡Xm« DÞÎarAÈÂ(qÀz&J`Œ ÆO£ïŸWÄI¬–*4¶àô[ìgé¯Å<Œ‰só[Ä#ҵΒôUuxú}Hµ_%Fú"<ËïCö: }:eOw“»ïm¥®×.Mý hô³%ØÙfR|À_·ç¶´Ä’Q·RèÒvGU%‡ó98ç¯Àí%·_ˇ„ž{õu KžDQ¨ ðXú/Œ*ªèŒW•ä‰z›ÞJ½³•(8ø+£oTQ—“ŸIkG©¥Ÿû¡Üâz¡ýBNŸwËAaÚRσG–£¡:ØÎWÕǻѓ ¹F¢aþb> _w¹tqó7˜†X&‰»žc9T eBòLS…!_ïMLœ*ÚÎv¸€––s¡m-gÁZ[β7UA ‚esú  BVûWPú®B€I…)½‡~@Ž“_ˆa2†À3ï§·Ù ðÉë}7¨ùg÷Ï£g6}žŒˆ[Éç<ÿ|˜TxÌzDyìׄ¾ &`\Üd„ÄÓÑè3î¤)GŸÏCP%«&€8{ ;mÊÑaÈ!Zåãúˆ qÈ¢qéÏW4,èhEc#NU$ðpH|T˜c‚FN!CÆN£4|y…ÀDiX"c4,qóC¡ƒÆïü†~†HLÐø)dÈø)`†/Ä鎤a… ѰÆÍ…?r@ÐÈa† 8f˜û>þ>R}‚æÌ#ê8PƒÇÜrô6Nþ x[ßE 'ü•Úü4n^ɈÒwŽRxŽÐøä‰Ý[žÍÞ©ó¦{ƒû „k{ºÖÎŒ@ðxÅc A Â}¥ÇýóÓÝ´­…!¶:µŸ­Y*š½è(vŸŽ¢Ã&/fÒÐEžù¡Ã`øŸPøEÍQf[<¨çsšHXôCry"ÑEXOƒ€}¨ªZ׳ ÆT#æ˜J'Â¥.W›þõ0z#.¦oék?7Èä5<X× ¸?<~¿^c t­†žz!õ™VŽ2•¼ÅTïHï:Lï ‰D?ž§ìîþþÇäîþoúºò*8½%VÑum£kÇ!q½í.‡ç¹`Áí0p€$P#FB  u@]øÎ¢¢gæ·5”4÷_´E%ÂRß’G$}å—þ‰ðxú¡Øâ“inÐu/BÛNcË2Õ£áUi·´Un»*°UÝ](Ÿ:¼eè¿rmúu£¤‘[ u§ÜEŽÌfû‚¸C]ãÑ cÂ…È;{ËÈÉ^Z.È™(ª0vä®’:6«2èQw©/ãW}wkøyG\œÛ­@£Zžè»]H†ïÓßÙøûÓD.µà¶Š‰o«ºm´· š$¾ ŸvUDøYÅÇTUab8h8?ýO š&£ÿÖ‰ òÓªÛáWuä(x€§P¸R^Œ—Pà0àE[²˜ÿ‚ †²ÀV(ãÏh 9«Ðvì&® ˆ*ªbÄ+ø  OÉ ¾ tݱ‘ÿJÉ_ëh’$ñp^•ã¾ phžµÆ‚ɵÖ)Ìä[kœÀdhGFh<Ð_eϰLy OÌĵ!²quÝ3ì Dê½#à: ®ÏaÆPTCÅ\Da @ë&7!qKØÂ„=éå‹þQÂßþuyvËî¾ýþˆ¼D Bú_Ïìó§MâÐõ¼ ØN\ÜÍÆIî‚þL!‡V* Àº#-ò1{Œx áÈq<¿å];"â ÚWïÙ“¯¼’Cg€â8Œ‘ú|Š¥r*…¡ZH€ ÀOP mu ôMê#¿9µ•§}ê¦‘Š wñˆÞÀ =‰‰Ã@ êp©’p’ÙI#ì´UÈi›ã#§í–ø ؉EyHPuœÉ½¯ºÍ‰’[S„iT¾¦ˆ¹H=zwSÁ†ŠŸH%À-*è÷’ H«ù-6赤‚ w>€úǨ÷Âø}땾3|ƒBîQPùÔÒšãçÊϯ·xáNw-Z†¹—Š%–"ŒÔkH†<6Ü‹!”Mm›°ß£7ª07,7,7,aÔ°ܰΰÈSˆ9&j’£jsA¿r¢_É)(P‘ êœQOG“‡Ççñ}[§KBpú¦YpúÙóüåF­#ÄýÉ4¬Œ;‰aÿ×ãÉ·§ÇGâ j Ë>¹ ¢Ùô–ÐÒ{ Nߨ{‹P‹:úùóœþzf÷“o:E(—Oâ§šZH(˦q€ì§H$6³<×"^[ hõ0Ï¥¾ÐÖ €pÎÀñ›ÇÈÉz©!­œ€º ¤B@^¨XÁ–+;ªwˆÃÆNªn3€B®&:ù󬂕åIâÖÿáðCÓ,²`‘~s³På”EbŽ;Û{¦˜…RŸËZ^Š íJt}¾f€‚¦õ–5ñ¶ ©½´ˆ/‡öKô»ß}k©@ÿ¤|@+fÑ·æ4¶§0xðdÛR Æ7²bÁqQu1¼¸I 3æjšyKK,q ñiaGaåçE¤S@®R¢J~˯‚T‹>‰‡CUNžó¬` ¤Vt’¼!v}í%‡~žŒ?ýx!îÒ5tÑ› ȥʽLä×*÷2%ÔRL T⣼RI k„èO©ÚXÂÙO¹þãyèk=,(‡[€œn‰/}ã?èš6è÷£É3»û¸ÖSÇv‰ì´Ì žîưÈiK€M‚ñØr6J/ ¤’É7TË:>J5|œz¾žÿxD<Ð×dÀ}‚å8ªvz¾p@ŠvC1Ð÷ !Yàò¬š¼ŸI‰nûˆÀQ!£Úíl ô#1(pH@­3J‡ª ùMË Äõ* Ðný{ÚH0»Ì ¦sÏ*ÕPå€$öKU°ˆÚs(àŠï[‰ H&klÜ* ü7Ø3j ®Ï­¹B¤<¼Ucñ,)n¬‘ ç˜>Ÿ®þ!†#[w„Þ="É;kø`ä·Xࣿž%âøñv8T2À“ÙmL˜0cË„‰ˆ·ø ¸xK ïÇá¤:ÈûÕI`IÍ- |ª`-¾05êÂĨ ä¨#3bÀlÕ·Çǯ?ž” U’Wæn°à1*¤ÝòÁ l—½e)Êœ ú–&Uô¹ë!ÌuƒŽ™ ºª bŽ ¨òÛ0з‚«¢C§³X¦‰fˆYž'õV*L¤ÖJ…©;¨Pa¢Â h V€áZƒ¶rWx@[…3í+ÀHªÁ‚}r$1b7[';°Ð{Õx€® s襡7§^Èa‡|åè8ž-ê ¡¸óƒ[.ôr`óNMÏçp>ëþòУ¶à×`Jù·Ø,ôç ã0àžÀ&4j¿gÔýÜvñ1Ç_šB .«):ºÖžZ]’I¤KE$m ×yŦ9 ž˜'±ËWÜ,êH¸àI#I5‡­ØO_G° žÆÆ¸¦§Çoãû¿ÙÃãgœ yúñ ©œ]óDVlùP8hY+ÐAÖ“ƒ ºÇøï§“§ÇéÓ¦D‡µ )@—áªð¨jއÀ“è# äh&>¶˜U8àºJâ’Øp`<‡êW…~}F_w­Ð€îÿm —S7$°,‡ÇÝ’l0 ¥"T¬´C, o²á‚³:ææä†×äð¨Ø&GÏ”X…¶¥:ÿ}Æ\«’å¥Û©?£~?ESMÇ¿£ü‹‚µ‚ÆŒóôùq2½àÝà@i¾$Љ};c¨ë+'µ‡,¿y€çC}íÒh":eîp…žk¯YbÀ8Ì^Z."nИ13_³P˜þu2ý$®ÎF ¢ ¤Á…xGªôf+Y$g­›³ÊºŽ³%@¯­QG¡P}Ÿ—2¼Á~‹.K"ÝÒ`Á¯Eú*Úë#Ž´ÒÃÚ¯ #žö _ à‘ß–ÂÀy’§l€ª)ê,Åûìö ʤ¿…ë§ClÀcN“~U éÏ4pߣ_í ÃàFºIÌ÷rpS=§@.À›ª/X¹tNã…–ì<õƒûdð¥{cÔj³«ÈJ–8EáWvü:hb Ä/Mèeéyòc z@²ÀÆeûr|P‘ðu[2Àjw· ¨ó-j2oP-gÀÔÓ–ØÀ ÙŸw°–µ tР 1ëñŸ£ÉøËßìénr÷=ï0 KíR%Ö Òî¦Æ¤\j ›q5*”aU9Àhc‡ÈˆÖpÙ· l{Tc10KUðl‚µ”ïi—ãr¸¥!#õ"#s·ïPÒW»< è¥F¤W`Ä ®.Óð1×å°Æ?šD”Tø¥(¢ö<98È«T˜;wmu¥ôðV~oÆzl¦rpqll €¦>؆> f>ÀF> ÚJÒ˜3'mn=‰ PëHÕb@ûçh½ÃÚA‹4ŠÂX]«*;X€ùŸ 4&t(ºZ©Tt]MƒZ~a=³6÷*0·ä*èE‘H_± §²dSâ*:ì4£I9Ñh’@Ú[ ¶­®Ä×;1"5…kñZGÚ¼½k•´K]ãJ %6²ÄGÂÃW·Ø0ªS@ì§N;b­ðÌô{|@t#“Æ)¤RÖ±¼,Âcg·Wš ¶'ôåþ‰ºð2§‘±.î¸VÒÌfö‹H‰/ï’ðÿ-óÙÕ…!"#4h‡kŠs$·gç&”%yŒÐ8üÜ”=ç\¦ŒZ³…ÆØ›ÅÜ‚9Î G&WFâ¤Ù‰ÒÕÐvžâÇ|gp˸õBM¡N£Î#„½Ä-ûŠ$0äeŒMùÐ̪F€>0uŠÈÐÐüJU ::+ÂXðœ1,k¹¦°ad ‘…1õ[-T&<qµN+$ËXgR§M`SS¡£ÆF.þX&­.• Êo‚ZÛ– ¬½WœsKË 3öy4-®äíù”ÿ\pÄó÷”ou`°†»›> ŠG”iUd Ý|ôðãûhr÷<"NO•ã‡çÑï£ }ú<?üNþûèAjå›~¿œ}üt÷ùód4¡ÙÃ==º‘7á²D0`_ÜÀ¥>ÙÕÀ¿ódÊ¥ÒÍoÎ4ºN{Ów}ÕØ¶Œ-œbœPJOÜ«mì…ÔE³Ym³éë"Khú®Ú%tÌEB^vT¢ k~e6õu¤ °;´Àù ¡ksšyÜN S÷gr¹Œb"êƒG/Ð_1“Žüéϯlæ†àü*çWêØ±Ž ’=y®} <Ðë`*‘Uë ²ã®PÈi¤žc°âHEBç°Ä9X‰ë§pºú3ë}öä+cŸúĹ€BGV¬^ ³ÓX¸ÔËsAEǘ¢ø£L±„¦7E ²H…Èt†@¶7ûOãgÈæÞ†æ%JtDÎ&Oe9|N}ÀQRßß«¤ÁçÑô~2~z?>8»%øþ„Å|ü6ºC©•+ ŠÌÖø>?©“[Mè@Œï.±øQ¢?üøö p>[ðûçx?Iìç»OßPÆYâC¿b:úû»{øFe‰ ”ûùjU=б=ÿý„‚þu8?ÆŽ&S°Sþñ|Ôþç/7PñÿOÇhÇ0['Ô×ÒKlÕ³FðãùÇÉøùo¹2~y,"F$Í×ÑßÔUóš MBTšRẛŽïÙýヴ¢;9§:ºMžÇ_Æ÷2N|zü6¾$ß§ì> $ã`NœµÜL¸ÍÝ(™¨C:êk÷ò”«ž|cŸÇÓgöôˆãÏèng€‰üy<‘ñáãäo”›“zyúv÷÷óè/@|²U:pò¯ ¦wH×SƒÇØ}‚ºdžsS ³§ŸäڂĆé~ƒR<›Žþ`z‡òe£{˜Ô£û§¯O †“>èhªè[¯1 ¬}tó%4J5H/0ú<~º›<ÿYU’YE¯ Ù+ðñtúc4aÓÑd|H°) émdܤ¿Àð×óèáóè³Úþ°Ó»ß£€+ol¢c5ÂJýÈ@ðëäÓ%»{"ïDRÇþôøà}r|¹‹þ|÷|„៣ÕsÿÇèþëôÇwüèá¨|‰Y¶4¸JŽßcü‚ÆKáQ†óüd4£çéýÝÓ(_»6©} Ïôéëqw „W-ðÒzF“Ñ4O„mEœM¦€iûx?}Êó‚“Ñô „¯“‚€¨ªŸ>ß=ÿ,è9ÁäLøG Vr .‘U>‡þc4øË}úôéïgD”VâcÂf4 üña pòüŸ_å^ g:r ô§t—ßëHN ÷AÒ#LP*šÊ(ÿÛä1e„9Á„9OŸFCýÒ)†üõó˜Ø_ï§âªé-®\X8°üûÝ=ø°‚`z÷e$¿†IA؈ü“‚¾Á²Ïãß!«iŽ.÷“¿ŸðêXù²ñÞPü) D‰KŽ_dçî>Ã2t9Ñdt?~b˜Õ5gP«¢J³‚>|ÀaÞçæ|nÐGM؇¨dΟ:Œ³£ Pc "œÖ€Ÿ€zsPÀž¤O}Dø$Udô7Ȉ4öÿ¸ûŸ<þõwqæ¤ìFŸ¯L!rªüƒè ÓJäQ%ðœy¼ _ÀÎW>3Á0MðLxÓZÀTEÇi¨d)H`€Ÿ¦S¦óœ@×'UJ|ž€‹Ç&Øâ±é_Õ°ˆïóTU°ÿ˜Ü!–j þ}ú;×WÐø{ip lFR@Îer\˜Z6Lˆdw Tˆi$?tm`%þóôÓ|I€Ðþéh’¹Ócc ô›Fwß~\¢ÛbrðççÉøÓgºÙÝ¿@Èzw †º£Fõ^N!ôâÞ ƒW ñZ%:Âeip`†§Žr˜séšž'€¨Wãòü Í1<»€ÇùÙ5q-Ï.‡¸®®³ªpÜ n‰uµä¯ª9?âwhÁû€id£«’ÒM¥DGôX*Á÷òÝá ÓõWÏl4>îÀÃÚØÆt%È sÖA«ÈöîÛâ#z÷•è8—æèÝ×d¨wß6×0½û\äc/[pXï¾’Ô»oú¸Þ} Ô(Cz÷•è Þ}[|œc£ïÝWBC›ëmYÍõ*è˜æz%°¹^É!ãCµ7âñS†[úæzß\¯Nh®§ÀÍï¼ù&A6¿Û ›ßm8¦6Óî‘Íõ¦¹žFF6×Ë @Íõ pHO•:6à€KàjSwà1ó Û\oÀ©M-Ð!§tul˜îQõ‘xò©åË@Íõrh\s½‹t4Øæz; k5׫A£Tƒô¸æzÕ\ol®·¡À5×Ó àæzŠ×\¯‰ŒÑÍõª¹^›¾ØÒ\¯O~Ç¿‰T¦¹^ i®WE‡,[Èæz%>¢¹ÞÑ\O¡›h®Wã4×kâ7׫ÁÓ×ÎkxLs= k®§Ð‘ÍõJ|Ds½8¢¹Þ–€¾¹^‰h®W‚CšëUÑé›ëUÐ!Íõjø˜…Ö\¯Nß\¯j®W2 šëm 0Íõ*ø˜æzšÓ\OAƒšëÐ0dPs= h®·Å4׫€cšëU Íõ*ø¨¹Þš¸¹^ i®·E‡4׫ÁcšëU)½Ö¶øàæz[¢‡Ïˆ]¶qß–Ѹ¯ŽhÜW§€̳]C+0­7È•®}ª*§¤&‘2ò1F>$p3£ˆ`„lÞ¸‡¨5póÆ-ð0BC›7j PóÆ-6¦y£Æ7Ó¼qK…hÞ¨ÑA§áÈ£pà98²|¾¤W3\y°yãÆ^ÀÍ ȹªyc¦Äa ¬yc¤XóÆÓ¼±Ó<¬y£ÂG5oTؘTóÆ:6à0 Ù¼q‹OÝ]±DÆ4o¬ÃÓ7oÜâ“7oÜBS7o¬"ƒ®yc á²ÍwñQŽS÷mÞXÐ7oÜBƒv^˜æUdäD…Eº°æp@óÆré Ó¼±DÆ $ý †ê*Ï%Ðýv¤çŒ€6ø¦< ²©Ð Ýl½JµB^¥ò–ÌáO8=lhy•Y1qGI‰<9½Ü@ð˜¸a†„ xF:œ‰ÄJˆ¯!× é—ž |*¬Tþ æ+RŸ¹ §¾/‘cžÄ._Ñ[7FÛ8‹$^ZbI‹X>g¶Oø„CøDÊÎ/Ç%wNѯ”§œÍÝÀÁÓ+"Fxÿ tÂc+ c8jþŠÑFÄù 8$ž×ÜØ 0ªî?ÄÆ,¤+Âm/JtÜöB¼@bÜ–E ñ¸íÎ][©—Vî _HûŸ&–Z\)Ÿå^ŸÞ&–+ naÂEê“JªYËŸ%Ë8Ì'Ú”x>L©æ³fbå¸C2,Aˆ•l±.~»è„æ8Éü|3Ù»Šæ8Reç4Ÿ)±!V²Åêª2±ô*ÉÄ2¦Âš‰ÌŠJ‹í<˜NÁÙ·bf[ö’Ä5I¼XÌ*_{M—ÂýSñÌMB%TP~”y!;J™ô·®­2÷ògn²ÑÜMw`?t¸×ÄûÏàêHÄ„n,²±px,ã‘ð˜ÍUÓl’Qi‚ÊÙDrd6“!‘ ÁwWŽ]®C]6¥9˜ Klª²#ŒléV`Dë„z%Ó>÷ÓÄL½ò*Wñ˜ AôÁpiÕvèû›0¼;x`Í<Îø+·ÓDWZØ/ÛècØ úW2§Z“徆Ž3§F䈯„ˆó¹ Šë%Õ‚:w_å@¸TX‚+™;.•îš EKÑÒ@8åÇÁу„´ÒQZ‰„£5 Hi+Ø\^iä•p@è°¼ÐJ7™SiNá b¼Äuæt_›¸‚ú[_ ¥K걕†Lޏß®9é-¢ G¤ÿêW*Õ1YÄc–ç&k¶:+Ó¸Z}(`N›-j,‚Yâ~ G˜ðó•åQ)˪ïóS.' ÁèrŒ.'P€‘ F–P`tCIv2 °¨NÝÉ€D£Ë||A7½ÑFUB‘‹),ªs1…Ew.úü‹à#+–+7U2;G£ÊgGad‡2`!“®À£“/“ähr*4AŠFgn42Ñ^É>pä:ðÀw´¡'*gŒEÇ}ð"Ñ…0Œ,îPXTq‡Â¢‹;’XÿÍ2R jÀW2À”ð,;uܕ޶\ÁQÅÍ)áv* ÂØi[fEû@Mn”,cn9ÿþ6¸ýM„šçˆÂÜBôñ£Ê‡Ø/s×ãGk KjâÛøÓ=þ6üí’8‰×”rVàÈEMJI·h¤‚2UÜÜYÀ…X°0¸PáÐ Çã8™K•–ÃÑŠ:·ƒÄ£A!,Œ_H@hÅZRnV\¹ØÌò48gq"Ü ´Æ1&ÑãÄ·^1¨pÁÝîÒŠJ,¸à¼ûlÓ(´‚V óˆ©*àUgØ0âÝGX\¿©ÃЀ¤EŒT`Jðµ±pyܬ«¥ƒ4bq˜&nÐ=Úƒ»¾ËeŽ] ªcÁÄõ)E¯ nW/Ý=ˆIDt]•HJǬk ! @ÁEq) ‰™ ªâݵ<÷®ôãúV÷ v?4Jó/|Ílù³„ÎÔ·½ûiÂ_™ÃE‡k *Rp5¶H¤ÈÊw ‘"y *Rð<Šm%IŒ™’UdôÐOÍ-ºŠ,ÖßAÆ|@Øt2+0Œ˜Û+"–ä [縘X¼A"'ÓœÇXtЇd:ˆ¦v3uX夦‚ :vHW¤*Tp¹Zcd/Ñâg1Hü*>q SC… ŽQ:Rã°}èís VÕdÌr´C#×B‘„1]@³—õAª 1*q‘£ë&¼Lb g±›pŠŒsD;%ÕÇ“€P‹%tûôîªD¢Pp‚é¢@ˆÅr–Mr2\"Ñ ¸"9Y_Ñ­gA|®@ˆÅR“ž…T°æ‘Rv>$mD‹Lµl¿ý„T,˜p¡i2û‘)?À²U—>J±(ŠãÈKãh ãeq•fäufTe­’V‚…šz•ž‹uÐu›«1H…¢+ûE•üÒ•û‚J}½0Xüô»F ©`¥i£ó°@!ÿ8J@Ÿ`~úÔ󓪈¯µ„¯«p|$å{ôÅ{Ô¥{‘•vw4©P隊D@=bDÖÙ„ëV¢0Y)B$FÁk>W§ykTüK—KÏïÓÐe9›,Ž$²—ù»7‘£±H­ØQ¡p‘»Á’Çn"ì%ïì›Þ€F~‚&ˆ¬ØòaÀxñCϵIÝPûaç‚¢VL¨ÐµÏ­˜p¡Uo[.\x€›,qaÂSWÎÔÀ…™å\YÎl9f–sZÎ…‰å\à–sah9¨å\YÎl9f–sXÎz9€å\ —sZÎ…‰å\€–s^ÎgV»œzÛß@E NP܉™ V¢ (2 3Ô‚ŒþGbiÅd@;8e\½ÅCcú*‡@Ž€hºÏ ©´­ƒAÄ ©•8´ÛµZÌãNy“ô ;.ø6ø ñ듉Xv \¸‹Àò`¢ð áU‡§¾Ë¿e}Tz à€¡ ‹r—›åÛ&¸¼²TIh—Õd¨ö Cš&Th2aÂdÈ#±dˆöcêöä<™J †“ÿJ;·K©aA„|%›Ï !"¾h^/ òõqn¥^"I`À[ý nˆIÈ¥HKÌ*èÒÅåüÈÙuP”ØQª×—ÊÕ×0ABª/:¥i€C¦ ­ðZ º¾a-ˆ†»qV¡"’uÛD‰ëp“Š›BÄu=ª¸GA¡Dda²ä1ËGT~:ž¼5•\9„ºâP…ZMX€¯lRйøä­üT!e½VL„Uæj'»¡Í]Ï ºö‘~ ¥u¦÷_03€éûWG8óFÌCgfÉ•^¢â4OÓo±'4I‹¢6H˜È€5´Ëâ.‰t³/ºÉ é’Ù€†ÈË´Àƒ<Í–)LB;¤ŠI[±ÑŸ@šnƒ†›SÎRAÔ‘Q1p4§Kp°ôOÝ‹‹µ ê zòTë,‹Z „¡¥p¶À#í_—af) ? lƒ†›h)F–\ „¡¥€¦•ö^\„´Ñ®B!D$mÞÜ ›p…µmnÀ“4>nÅ ­óÉ+ÀhñIºïFŠOÔ.{,VtˆÞ²¤9(X“ìBÙhMRg»À`ñÉ“g­Øø Ó[±ÁA@÷Ü òMw+6þ#`&„Ýë îÍ ¡0"¢k áM ª¦pPS¨J§õÕ*Ên uPÝä „»ç&Jhò‚H/ˆÔµ…Y[ˆèþoüPÄn€ùUârHÐ+0%¼»ð-Aµ‘(Ð@‚þJyJæÖ ¸Ê\PAGn@¼Í©BB”«ð ê&,áî·Äƒ K[šS…„‰Lš© "NäÄ ½V¿„ˆ«r‰ªvœ.v¨B"®ûIk#¸Dˆ»v¹Gµ/ÕX¤f@ñ– ÑsVˆÇ¬"òWnbËíÜsZc Å;·œV´"Ù+j‘æqØu˱¡Í]+F JÁ÷Å«2%µp€@TÁ.x²²¼”\\ê8Ta<°¡- ;¯l`¨E+»žPb‘ ¯©DÌ‘¨”´t Í·@Ôâ)^s_Ф~'Ráu_ jÁ’®)·„T,¢W5!ojJPšç“¶@ÄâQLÌ…T°µHx×ø0¡+±¹eèji ¥`/·’¿ÛJ`ZÔv¥ð¢Î­* RÁ¶ÿû¶ØGáýß·Åø/Ï áý&Âß¿ýv¦™þÏ1LÿõiüÈæL‚ýÿñø4z˜N¿±-äqÚИÏØ,Ïy¬ÀYùn%9 FtœÌ9r´f‚ !<¦L™œA,ÓÄ ³€úóó·éj ·¯®º‚ïódRJ^À£pWÒÉáG“ óBËa MîÁÝ`!áŸFßõò~:šNÇø™)´o„ãã¾a:yb÷–g³;Vœ¬W¡»RjèTŸc^Î-K†NªæÊŽy‚âÚL—¹?ý1š¨Ü”»QÝÓÉ–`Á9ø å¼k 7}4•j¶ª0ÁI.ÇXÿøý‰YŽj éGq±‘ûÖ’I}È.ùxo¨#òüÓ^Dþ89§6§ |ž[%‡×£û§û;€v~ÐmËóf–ýÂì$¦ŒKü%—àQì®”o}ákFô¹—ŠåFõäsªÕÞI`µSàq"£®0†l,žy® Ü ´è±g ÕˆÊJ,ºÚ6¹Ã_An0Ëy âø•ºò¿€ÍS•D“„)ʘä‚ïÎ×hE,’%–ÂÄäÖ{¶‚ m+9?9+¨1÷î— Y‚öOŸT2(¿e(´…#pE ¸¢„Eæ˜}ж1§dž%Þsk*7RMLAáŒ03 1S“„ 7€¾¸¼’‚}QN´15Íæ&Xd ‘9yX*x Šs«„…#+Y‚<0`Ï—«28†¨2¡ãvÅዚ"à¯ÒÎTÇ&uǔۻn‡$ÍR§Ìr¤©%®à»³ˆŒ//¥«Ã*Q1‰g4SGºÎ‚ß'*’íÌTG‘‰4 Q)×iÅ i‚ÜÀ"å¦[‡ž”M/aLž¶¯Pˆ$–1AsûKJ¡³Ýd4„ÂÄ ”‹¦ŒÔá|ÂC} ¸4ŽF÷„ZäðHÕ%HK‰1g‰öÅŠ…ÛfxbaÁiⶭɧ–´S¶ú”Ÿ€|…€Ô ØÝôa€g™»"ŠP,“é\_5¤ÊêD@­©Ý¸ºz¯v «ÒØKË i I£|בžêb³tj?YÔö Î7Ð žœ±ˆó˜xÍ­à—Å ô…%UL¡Á€:ö«Òç&ªà*ŽÃÓ‡‰ú㥠rãf¯Æfó¯ÏöíšÉf.GWeZ'n¬tV9Y¶-#cbU ˦¶ãÆÅñT:ûÉíD0• Lèw?ŠL†Ø<Å¢*G‹¢j4>S¼ $ªIò#*øˆ°-{Ée(G=Ûyèj<ÛãVLI~Û$GEÝ4ÑèôCç„liŽXZ/Ôëž“RtÌÍ_£PÎmiºjZûÒŒc×òˆ§ `¥7O•£²€/ÂÄ•âSïs*ÆÃÔ?©¨½ØÓqé‹´ºc‹N}à ¯³ÕºïèæÛ{ @é¬Ä±©qÀì tÚ ŽCÄ`¶cdö×åÙ-›>?NFù.Ä¡N{€³* ~NhP¹!˦›'F(|•ë+ É–º3Žçø5pŠ`š>–^e!›¬1‘”†ßÐEÌ3Õ™VÝþµ–ºí=8ÄÕäåWÜÑã*ÎÜ=Ï /‹B%ÀeÀ:8Ë»¸PAHþ0N#U‡ò€0‰K]>µÁU5:jªŒrøí |áa®ãoRoQaoPUÐå^Gn0ø ÿ•a–ÒŒ|µ[ZBå~ì¥JÁ²xž;‹­xÝr¤ÒZݲÛîí…šAï'ÝWý « Õ©Ićþ|!¦ c^fqÈÌšÍb¾B¤«, ¥ë§ˆ0F5lÄaQq3b›&V?즟€å|r~²ÌŠG¦Èáé—3ìEAø%Áü¦›>Oƒ)Ýá³”:àÇ•”DÞÏÌ=2ô2ðý13¬Ì\®Â]¬‚_ªÈ\—€äº*wÀpȸÛeU’¼½ý=à*GâÚ/Ú"?dKúœõë;k¹{ ob¸‡‚E‚•ôÑà»á‰ÐØû\ø»\&îq¸Ã…º¿»»¾·U‡$ò$/†ò’M÷•¹É•‡ìKp©tæzyqi}aÐÈeA#±— \4p_ÏÄ]=ÌNf‘ Z<Ý@‰¹žÃ:åð(\T§|U H'8•äO¼ù¦B§8cƒ~C1øC°b†8`¬bP“ôög肞}p‡ï¿»q8ðGÞöIûÿûÿÔó>WÊ`n5ÕQïûhDö¿gŒÙ¯¯ÖÌ] WŒñ õó›c*µþùl´úÿãþ¯¿î>åÇu|óù#„Ó„C,á5cV[ks:ma+µ…¯UÛ³„0ªÕ&#^«MF¼V£™%¸Q­6ñZm2‚µz+C¹‰’Kœ1½¶r‚5ÛʉÕíPþ|žú}PcÊÝCŠÕîR¼z…kØÓî!Å«·…¬Þc+߸~÷°‚¼‡¬ás=kË—»"Ë3§ã½¼`-ïåë¹êûC¹“ógW»÷ØÁ:‡£ùE² ŒýÁ%ûæŠDþÜáLÅ5Ë0|=MÏXñäì_±óß.à´"³¢ÑDÒNf™¯Ò@òÊ(ëuÌU›¦½Ib+sëF¨z³ë"FÒM­¹´ãDUò…±a0dßõ­?Møkãû»5#Õ”ÁJË^Êe;Xx|ôô0e›¿+ø¯”v®²Ñ¬7 ^•°MÝ–Šú°†ŒÉ•«0ƒÚØk_Ü“ ×e8ßZˆåy½¨á¦n¤©gÅ}È1TÃ!ªå¹Ž.&èQ–k)J¹–A釗9½zdÌë8‰N:>Ø+ðIÇmRoミ§!P%>8‰zÚ$ê9>h©ßø M¤~âƒVIÐñÁðš©+-³PU•ñØwåtT³zÇä§¿[Þ«›y¡ý"7ü¾iz]»^Ðû†ØýŒö`w´Ÿ¾¬žV£Þè~dÞ$`“¥îâ:&µÞ£¥ú¶ôá`kéí¿ðõè ªÿÛ2Ñ^ |3é¢S'²ú„}}}§¾\ý±£Ú)%êàñë4¹-ÿèéiõ“x!{Wš–&lK$Jœ3öôu5y?.YñûEs‚Ñ ÈöD½Ò¿+ÄP áÈHIáiͨBÖtÆ^ÜÀ)u6=gÓK–kNN®âÿГꆹ‘Í¥€,Jgžk3Û#OÊ©åZ¢Æ€žÍ¾)Íå¶ž°I›V’¶ò}uìëŠò÷#ò`ö"´¨C•Dì*n„VQ{ ¾Pê¨ü°’Ú+Õ›þ¨ÐPãorÿ90ì?÷ˆ¼ã½ÚDnú³öglzÅò/1ëÏÚ?åM—¶g(ÀnnO½ýiÛÉ™ÿ•†Òþ-§h)oׯ÷ík{Wl¤zÏÃØ·)’Þû\kÁGJ¬söYýMÝ·SnÒ¨‹F> Ï“jÅÕÏ/¤lŃÆ.÷ÊpÌîS¨áY)”zã4v#µh増뼔% c¥óª¹,EÈ;Xõ"Äõ¦¸ÌzeÉnU%EÆò=9ÔÞS7̧¯»ýúŠyµÑÇUþ~D5am+Ð/õY1M ³b:kKSO-•«ÖJp\ñSE“ê<°n—æùM~üP¯‹žZ¢Ã¹b÷Í*—¿W¤ù Y¯˜€sÍ>wã¾, E€~%èÃ"µêÂcå™+Á›ì* È_ /Vbßo†Üð)L*âjë ‚°§éØ.CïBô1)w¥0=׷ЛEì¢)ú°‰1 ÇÐjžŒ¡ÏyÐ<{ES^° ô WHl½ð^%ÈÙ4-ª Ûٕ {w¸à¿Ö£õèÉ´_¹Pïû˜Øyž05ì8¶´}ðöà¬sbÓZŽ{ð–b·4Íy9ã 70Mj«œ¡qÒ–!5à/¹%ÍR38é<ƒÝ ÍðUç2îÇ)Vx{!îÁ-̆W´E†ÍùÊnsS&ïU로5îÃ+_‰t¦Ü²á¤ŽpzˆÞ­k~¿Þœ4O(ŒkWÕµJÅõôÕšÚ°ao¹{Õy¾6™þöVfÀcßlò¿£ì³ jÏõÝÄ´ ½±­È²]ãQæ:vïaÓ¢:ª¸},‘î+"gç^-ì0Ý ×‰°’xm¯fø /š§êã¤úižÛCjc1@#a€£±skc4&x`CÓà) ~ž- žZïå¢ÿ¨¶Ó_̵3¢‚Y÷.F{­g²F©LqÁ†ª… ¢@Ðy­@Ê Cg¯ÂÐ «@ž£ äi©(ÎD1“ vò)6é´Ç¡£|NŽŽQ êØQÀîQà ô8PàýôhO”ió® áQ󾀇hx®&°§gxF&€'ayÞ%§Zyv%*'T€ô¹¨žC $þî>A±ÚÙ XIÚYb¾z$Ð={œ# ‡6z4#°0sÌ’ Îf–£o]»ÎE¶´v‚(Šçk4¾ ÊìÐáÃs‡Ï­ÔKØæ÷ÇÕ‡›Ó¢Ëæ5rW.jònù—±3Kçˆ!’4ªUþQ­º¤û? ø:RG3c»hØðEqùôq-œQ(Lsì4Ž™Xû³ðÊÑ>R'd‹8L#u§Ûé<¶læ¸ 7ÆHåÔ´]ßòò. iCÖƒ+Úlø\~ª•¸+õ6Õ²\´ÓÊOu{ M–a*¬ÀL`vs­´ª W¾Bñö1s¯TW›^&ïU>y{°è«|þö`ÔŠ¹»¾1º zˆ,=Dƒ>"‹A‘Å ÈbÐOd1è'²ôY ú‰,ýDƒ~"‹AO‘Å §ÈbÐ[d1è-²ôY z‹,F#‹¬‡œEÖCÎ"ë#g‘õ‘³ÈúÈYdýä,²~rY?9‹¬ŸœEÖOÎ"ë'g‘õ”³ÈzÊYd½å,²ÞrYo9‹¬·œEf:g‘õ³ÈzÈYd}ä,²>rY9‹¬ŸœEÖOÎ"ë'g‘õ“³ÈúÉYdýä,²žrYO9‹¬·œEÖ[Î"ë-g‘õ–³ÈŒä,B3u#[š«ví9Q=Ë×çEÒ'ï kù,ò7.R4ÖÎë¨W-sZ1z2H¬~Ã8ñ­þâµ`Öló•+?Þ1E®iÐêîãÓõ‹{rÞ&Ë^>^ÕGi¢nI§¯ÃRE×`½.†ÛÔWÞl&²)ÂÛrPÍ0f­Î Ð7§·é¬Œ7g¬â}ÎÊù~ge„}¿³2A_:«Luf2㬲š³2ñ•5ge‚°î¬0Œ^¸píý¥¿D4C¦ž–qóÊÕ:ã FèUixÆ­%{ šinØIªyš¤1«všì«ÊX[ÆóÐpû\é¿Ú\¿Š­®?ßš…z¸Þn6k²G`[iÐÒ-Êùжj¹…ûýžï'ê¤r¨p´™€Á8ÀQ#ðŽ0¸oðÛª}ŒÚ­!ìS„X*X¯èhà¢Pw_>ï#üè)w  x%˜v{á7=Æ_!@ØóLx“ßÐ |T¼zš oò›ó3¡¸Rk%|ÆëÁÿ•º+Ë“Kžê.P»‡ë‚n§¾%ƒ«…¸l\ü5#Èþ{Ç(M\²íþOm¢çµ_õÃÙVå廓ØÊ6ïËg¯i¾~_{õ}zƾ¬V£~øó˜Á›OÉrËßê/¦§ÒGù£~ù/yK'9³ô<—¼ï!ˆÔ«Ñ= pµà‰Ú†$h[MÎÂV~ƒ&Йœ…íô<Fga«&ga{‚ÆÈ,tƒÅ?0µ”38õl‘aÿãœ0®Uf~®Ž‡Tôa[ž×~æpCÄwSýæýû3´ê¹Uk¤38H ¤>n·‰Ó^ ä09Œk¤9L OÄF>(‡qôg#”¨‘s¹«¾XZb9ž¼ùdÏÈöFÓ+ÖXìÎBM5„S½ûµxòoh®h8†åÃÆs RgÃpPšw¿òK5˜‚£–ðÕ|gÍ"Jvâ­óÒVéQUN}¦î„^˜ñxôdc PÛÙL0¥Qdð»r6,Ó9ûÎ2×ásÖsËw!ùKÚ}f†ðFjRŸºA!—»'¨:·lPš[u‘I+±ø*ûY>H”å†/lKZ£%O_3ÈC¤ ¾Ò]e˜Ôv6L…»2ô]9–i°± LŒˆªP¶Ã`ÅãD~"Ë|K¼Œ$å¥üDiýù·=™ J c¶ã ±AUÍgh\ãËDWêÕB]GÝmq!o5lH.ËÇäñ þKT üµŠÕíU2¶mu•ÁŸ‰D_ˆÉ]`ˆ¥;OFÉ?Ùr2iîSÐR(÷ÈùǨ{·û©U‹ÕÅ÷¼Êäê–³åeêfT*wm–_ûÑ wéã.äÀ_( ¸’?¹2jJašœ‚(Êeư•qkª” ;‰I¹#…¹I¹CmrRîž”MþöI™˜ MIê“239)›¢˜œ”ž'9u6CÇÐå3M˜½F¨ZªÔóÀ´êUÑ$¶¡îÆæY"´j‡jçµ¥4 \L4Âtm~¯¥:}ß­ÉËšÓ´s®Ö¦afd ³i¨²Ði˜íNC¼r7ÓÏtm~+Óÿ}·&.H}¶à‰>¿uË:3æ&<¶’0n-û̳åüUþŽÈX&ÿ©£¯üŸÉ4¹qC¡®ó‰¾>–¿’ÿª¥~ò|ÊŸáý¿ñþÿŸ‘ü¿ñ¯ÿo|ÆúßùW•Ϙ{¡•Œ>ò ˆçBý„sùùÐOm,XèÙ¿Pfç_(3ÿÊ<ÿÊüó_(³÷/”²sËŒ83EËüú/”y}:2«ë¿qý>DîZÂû„VñCÄ>¡…ü±Oh-?DìZÎû„VôCÄ>¡Eý±Oh]?DìZÚººgûÄn»x{ºyÐŽŸq*yÐŽŸq*yÐŽŸq*yÐŽŸq*yÐŽŸq*yÐ?ãó ‡}‰äAABC7Q ™¡;(ÌÐíHfèÞ $3tã’ºkÉ Ý2d†î—@2C7K ™Oh§t:yPœÜ'´„ŸL'ö -ä'“ʼn}BËùÉäAqbŸÐ¢~2yPœØ'´´ŸD4J‹ômøá*+UÚ¬ßÕT)U5îÛUáŸìé-›¸'$°j/áBÝž®%<«RÛ¸Nw‰ýįÿ:‰×§/ñE9ñò¤žžzÓ+u‰ëú´fÜåV·ZÔ±ÓªÝÓRïŽÐüô…>Wï6%|ú ÛTIÛ=ÉÛ&ÉÛÉ ʼnäƒÅÜDòÁ¢T"ùN(Õ¢ZÎÈöêA¨\OiITÁþÉûê}Bž»Þ'â yì}"žÓÞ'â ùí}"žëÞ'â yï}"Bx¶OÄöj…Ý|BVså<Ÿp ÀÉ'dØ]B7‰[ó '-qk>á¤%nÍ'œ–ÄmùÕ¨àôfÜÇò xkÞUèÖ|Âi Ýígà•@Bh€J 4:%šÈK 䃥òA#RùN(Ýä²z>A­‹§´$î ìOËWïò„Üõ>OÈcïñ„œö>OÈoïñ„\÷>OÈ{ïáÀosxb¹ÞðŒ=Å®ÏYÌUC.…žk¯õŠMØì%Õ‡‘ìi¾÷dÐ/Ipî¿=ò}” êIBÛIëK„·D$›ñ¼žËONcÞFFDås!¬WiªÁM½¿½2:Õ<q¥Ê;<«ðÎãÐÏ™!MÔ«¼º¦×u]Ÿx¡_’WDêaõ¢5yœ˜Çjª´—¶ >BÄhUšMÕ–™ñSM{Bõ€ uf{çþoo%êÇ+dU¯ÐßÇ›÷{8Ñþ"3ã/²†¿èod{ñ$Ú“È(6Rï4«(Bµ¸×élT‹û¶$N9ì‘›êí;·©±ÍH©—õ”*c±r-¦ÞˆùXC/õ% 4Ú±Sß™œÒ‹æ£s¬…ý6èù“nþÅÁÐÍ¿8º9© èÀþ|æ¢û;¹èþHùOƨ”ÿßjØ'Ý(¿ÑèþPÙN/”éÐ]õd¢ûC¿á£û?á­è>û÷ŒÄiF÷‡}Dçè>;¥ùPtˆ…¢ûÃ>é´¢û#dÿ—B§Ý“µdÉ7ãÓOˆË^ô¢Ú¸´eD$×çrW{*QOJ£ûï¹À$]YžÇÖzì.„ûædðVÕs[žÚÈ‚nÉ"\›I­µÎ¬Áµy”¸a P_ùÿ¹TB/¼<œ÷›¸0kz‹÷B•ó÷Cìzý/°ÓºŒéÔzaÎ\‡#„K|‡ù*þ2ÌFwü÷uìè °Û«§U¼ ò¢ kÛRlr±hã7±X´òX,Zy ,m¼F‹vb‹E+±‰Å¢ØÌbÑÊld±hcÞ,Yܦ‹6n‹E/j±(ÜÑ[? øú¨òÉm&rümv6úð3n }Tß1ø·~Gå›Ùÿ›r#NFŽ»þ°À¿Jã‰Vú¡E§ês:}Ç ùœÃ¾ãŸ£.eì¦O8©™p˜û9U埊':þT§&³ jV@,åI)²röpÚºÜ+èI©ó¶ì‡Y[OZ³5™}É|ÜÉ^Ͳ¢ùÞÕR ¶Ý£!ÿ5jÝ+óIiö^ᔕüaB|)n.12¥X’\Ev˜¢KÉ:âR¥óPîD˜êb%örôôuÊžžVˆ§)+Œ͘FªÑš¤|P"د¯ÖÌ] ×òçž%+ÿþè ò|mE  Æ\‘_)ç1ÃÜñ®Ð]jº¹ºí†‚ON{t?P]hÈ«a6Ø ¡‡@¡‡ ¡?£´ñ#q´ eÐ62”md(ÛÈ0¶ñFç,饧ÌýÈŠùh§çš}ÈîT[º¥‰=©@o —aØ“ ߙǭ&ÿpœú·²€@†'©Œü^¾¾"Áøá–±EªàAÅ *ë÷¶¡ä“ŠG*Z¼bÏlzô¼Ódx6ãLª¯ü«,±€šø>åé«ü½§LŠy}ÒbÊßš^(m^žž˜Ü’5‹MzÞä>×*ŠÖº…¥£øž]~Í SZäIË©6YZΫžåT »ìY†|ÇiV±ŒÝàE5l»;ÅËø9¥nÉÙäY6gVúªÚn“ß„zS€ËŠÂš«°C]m2*ÃMÕÿ)5°aëʇ¡ÕlÀ&<çáã‚Mx¤ÏF.5®GÆCŒŠ®ˆTKÕEˆù\9¡¾AÒ;VbõAßãzž  š<ѱ6ïe\ù7¬™¨§{W†áU©…`‘,™8[q[ÀËȰz®õÓ~Ö,w†C-îëî…A᥌.Z€[µ<Æ\•{ú¾yO9³ì—Àn‰±ù…QdV4šÈpÜ$ëåŒ/ÜÀì—^Úžº‘l–SnxäBÿ±tÂÉ fx›VÈæõ9—ó8Ü9ÃÏø++ŠÔœ´‚ø ­Q-ox¥?7ëpjÄf-kC-ÿüÊ Üĵ<÷3Ϫ…qÃà†¤1»á¾²„pÁè±9ìøÍí†Úø +i [[ÎÛà «›ža9õ©Ì°\Ã3,¯bùèŠ~š:HæSÖg/¢!úG}”×ìüÞ›wj5fÃ^mÃmØðãöfW1×­ZÌ*xCjT¿×úyºhŸ>Nu5ÉÍ~¶Nù>×¶J´š5gÅê‡+ÞÛWÉ ~vq¤öñ´ÂÃô‚mO­oúöÃ¥5¼Þ% á£ÿ£d4êå—Ðx”q¸ˆÓKÓ‡GȨÿ9qObt¸Ü†C–|¾é-G¹¿á›ßv4¹Ín<*ìÆíLîxV†·7Q±Öã¾k0³º|´If UÃÃÄ&¹9…+f?Mò“]£C}¥b™µQþô‘ùVµì_Í—Rç´æìó›'}pš]6œf§Î–µ%ï‰ÓÚŠ%ÑÁ𔦇û «Ooò}øÄö„aõ͆g–ïØÌ³çä—=ÛVt¼ n%õ±š {ZM†=¬&ÃV“a/«É°¿ÕdxR«I{Í?žÕìj2<õÕdØëj2ìq5\#~‹Ï°íYÓ>ö^’ÕpªL2_<$çidP¥ F•í¾šÍQEßL›“d4nN’ó4ÌI B¯lG%F$ãeÞð¹ìPÔÚ¹ ÂNïwž÷øMˆµÄù|A…貚ºµ&²O«Ñh2u'Ï5”â£ÕÌ“cŒ‰cšcúiŒÉ3ÆäcJŒ1½cZ#™t#å'Û£wtdòÇ, èIokãü0 €«ÞEÄ9¢Pнšw0|!ÖùRHe,d<~1B1V­ý™î–Í€µtÞtÓš{ªèvcSÂ=oQY€,óÊ]aÌGu¢)¨€ÃÄvq*Y!U²¢[ð ‰×ê4uêÎj)ð‡ ükiážpŒ7«¢Žë(MtñûFùxú Íôš;p!¹·×Ü É¸Ü É¸˜ÜêiöE:Ÿ) Z¾mÎ==CÒ¼óçôEÞß´ìú®Ø9.`=R°–¼Í~;ÇÀB,KÞ°=‡¬ –þLFÃ’?’Ã&ØW ìš6Ô‡ÐÇbáåÜK۸…z›™Úoèð»âPïŠíðÂË,v„Åau;âà‡PxHtW‚#‚¼Pu‡CŽkåY–§¯úü)„¤–«D334Žn†Æ3C㛡y5C³Òôš(!‰‚°×DAI„DAˆYJ0kˆ—o²CD¢`N”4}$ 4ùWÐÀô7Ý$;}ž@¡Ò§ *}–@¡Ò' *}Ž@¡Ò§* ¨”¨ô …JŸP¨ôé…JŸP¨ôÉaàU(±ûö“z V½øž7ž \Ø·œDóÅ&è·ò2“=úa¦¡zJè‚b™|L¨)±Ü!ä`?ëwEO@œ)í úùƒØybÇ~÷Ù$m5Ò\N@˜)Ó²*ï[dQ_¸nÔÂ$? Âcà%#Ñö^}ÚZ´¿JdÓÇ,¢ýí¡VN¥CÌCô’h}/³Àµ¾ „¦Â½ÿ#L¼ò#̼å# ½Ø#Œ½Ë#úy}çC´O­¾¤£cĺûbŽ¢¸»Ö—q@¾÷Ž@½s#6¯ÙÐïÈìÉ{˜F|ð•ýöË™–¸‡dò¹±}eVÀz©¼³˜ƒUtĨ¾ùTËN`Lr ¹äDì(¶Ï®HP¿}ä(<ÊPËçJ †ºEÇê/žÀ µx×1Ö|m#_+L~ô!‚õ­äÈø˜9^AGL“ÊóˆY^…‡Lóò „îa}Üs[h€F¶¯cØ;öH´nR >!f¤ÐcbûjT÷U òOøh÷ÍŽçazÆÊÃ@;ÿÃ%‚8ùc¤€œÅ#À…,fõ:X õ5â°èpAô?§ ˆÁHô`á +dõ=8>rîù ˜°A€ˆ «ï3`Æõ ƒ¿µ ªØ åEM j_G•7Æ£_:À$›ô»¸:£wž’7ÐGb¼YŒ°Ã©•= t{¡Í:­Þ€Z)`óõnÿE]]µ¨"‡®–{fyÔ‹cÉI@’a‹#¤YtK| ‰ ÁŽpt„C”#âáî÷´¼;Â}%eTèGø~£z3ŽphÄ 8BÈ•4¹’&t¯xLôªÂî¼í;Àãíëíò’ HŸv¡»±¤Í{®Ær_cuÐXJ:zí$ƒ3éS_ßæ Ø”Iì æ-Në?7”dÃ’,LÛÚ|в]J¶¹Zu6÷B+Q6±½ÇúdCT;³–¬#îbºŸ×+B±:H[Áëa¸´<9`m¶0¤e‰–œÅ’؃³8îÂm=¤,‹ØŠ–p/Ìx g‰b7Àk,JÏ""•±F³¤Q„—«W )Ëe9ίܟË0nlË‘'=MpÐßçÞ!1ððÏ¡‰ñâÇcˆT0TaCP0ä‡_ç!«ºNèð¹•z ‹¬$áqkP~AÈ9<«]aܰژðxË{³Ù `öšH¯ÈcûÛìl4^è¾Q›Ûþ…Ñ“Ü*0/´-³\ ß±#”r…mäô{í}ìònXE̶ì%/þ‚11  {Õöð4´=4D„rù»D Ï¿K„\J¢Á)úªA¯¾j𞯙=S¾jЫ¯¼ç«ÌiÛˆ¯˜òUS¾j`ÄWe§We½ÆUÙ{qUfd¥ÏLÅUY¯qUö^\eTÛx_•™Š«2SqUf*®ÊN1®Êz«²÷âªÌÈJŸ™Š«²^ãªì½¸Ê¨¶ø*3qUf*®Ê qUhà¸bËq59ÿ‡×ht¦ß•¿w®ÝxŒxà‡}§ß&)X{:anü³à†‡š¬!õ‹‰, ¿ÓdÁøž&‹ÿ“”ÿÉúó?Ùþ'Ã[nfÄÿdýùŸì ÿcF¿üOfÄÿdFüOó?õ×J†ü×hòÕnö ¹üöò‚*3òa56úóÂ…k3ÇaŒºÕÚ`]«³ &k•4S« i[Á‚ýʂô jЫ A¯R4è«bá þºGW–¦º0,8%KW°dsËQk¨ð8Ôm‘‘üÓ+{‡Ax㤱•¸a0ö¦É¥þéø›7©åÿ¦&ÿdÈ6¿y¶ùŸúÓ†Ø74bË›»žÚçˆîÏ»<êDZq…×ÍJwlôÏnµ°‹u`Ñé¥í©7 LP]½ŠOP™o [”&ª8ºIw­Þvçs¯;ï’߈µ`¹ÁÞ°ñ#û2Ö7á‰áýrÉKïÐçCÎòŠxéM ü­X†™ok3ó5OsDùš¡: ÉU ‘]ÙáöÃ Šˆvh0¡ðP]bÌÔËmQŒ‰ê4° ¨N‹Š†Åݬu`ù“Çä™v˜†¦˜@{‰ÐìiÒ€fO&3f™1C€¥ývhL,ñ7tBßrtJ¡NË)ÔhPã_ã ~·ÌÓ$÷å`ˆº4iv×PͮҨhŠ7¹Ð3¦Fƒ›1UÔŒ©q€fL7cÂ4aáœé¬pðk4¸Á¯Ò ¿Æünðu3áeè9<C6hæsšÿPó ñœâ¹0ÄsiˆçÊϵ!žC<·FxÎÙàÌ‘ ‰Ì¸IdÆ'H"3NA™ñ ’ÈŒ[Dfü‚$2ã$‘)Ï04冦<ÃДgšò CSžahÊ3 My†¡)Ï04å†8ÏPÞ0˜¥sØ  òŽNHðDþ€:®R©—ÃÔgazZÕ©ö 9 Ý% Åhš\ÌåcUqâÏ„z›„%f΋«ò¨Ö-Ï 1wv¨¤y¥‘ñéæX¸Æ®x<÷Âl)©RÝFêí—¹åz¸ÒÀ)¾ îwÔYÏ—§•/ÿ»’CFßɼ…ï«· \÷Ä]š¥Ë“Ãc‚È6E´4D„ž¡á9443‡`/wi Ì¡¡©9445‡†¦æÐ?‡P5ÐCt2/Ö"áþÞÃYªêÜÍîá,„f÷ˆ†ˆæœ±âxóøŽÁÕ/p5bo‘Â*ÆÞ"…€5H‡lÂ…je«~µÓ–Á k/ßj̖ꬽhؘ5ݲ;U›Ïòm³ú~´(šäýÓ‘ïêÛ ù®Ú©ÈU­)µy¤î¾€Vá fn`Öáóm5³\ìÇêÖJãþêhpžgA˜ü sCB§ˆ¡ºŸ-¤ü5a*5©å¡@“ør]J¹l-I)¢–7Í r%q¸ŒÜÂuÏ’¨Ç‹ûn ´¦I”&} 3ªñ ƒ–„Ê|xX(aü‰ªå¹8›ÙÕ—–®7YU5b'"Ôþ»t}Ê£ÊÕÞè·Á¹9™`7þ>@¼øvWnP¹~í*ï.ÒØ¨½ ù1w&? ÁµŽQøËîyÙþ(Áœp½æ}TÀ~ø> %ötì€ÏÌ>"öÒèG$Àžå}@P‡Ì0÷¶ÃícßeîMÛfv¼Y“9ëeÇÛ*Æ ìx[åêcÇÛ*H/;ÞVIúÚñ¶ ³Ç›õdÉ}ïx[eê{ÇÛ&TŸ;Þýòô·ãm•ÉÔŽ·ÜÜŽ·•½‡o›厷/‡Rîx{ Øñö%ÁÉìx[…;¥ï^OjÇÛ&åvÇû³*;Þ¾$0ºãm•À获M3;ÞVæÞö`fv¼­Ì½i¼ãÍkºNç¤å]yzˆ;ßÉ@è÷ûµ[tÈë‰?/@?ó(zSœŽm€=ô[ÌÃS—á©Ko¼~½ÅÜ›-šY¿N&oò®<ýÍ…žRo°›\¿öÄЧc½®_=ì0ÞbîkýÚ#̉KoÕÌúÕÃþë-f¨¶Ý7˜gì»:§‰-;?­F£ÉtÈ&Ïw\nû‘gvZâ8§%?-qæ§%ÎÏÓÇ;-qüÓ'9-q^OKœuïâœ/x‚=òú{Ö#ýDþÁeþw˪òo wÔ» Õ«ªú$ï)ŒºˆÔh_äê…‹þ¦'¼,â-òKuœºØs˜Ú«H&žÕùˆ4 ÷¼EoÓ=ÎÊ+w„1o”QR½Jy½~>ðý#ü«¾Õ¿êçó’x­Rn2zC´£;@ˆaŸB\Kà¹ïoªJÐSxr¥‰®î‰ÿFE "ô{…âÙñSŠ£±ùç7™‡§§ŒÞÒØ¤ï›Ì½@IßXŒž¾¨õ`zÞ—©"$7® å_çÓ‹¾E¹-þªÜFè98½ìS¢s R¤ÉSæ:é)rQÔNÔÀÓÈ÷¨çýQ¯¸¾GÝÓNIQ÷“)jD;ãR#Þ_ú 5ð†Â{Ô¯ýQ¯qÔá[ÉYu-¸óy‹ûrî¥b‰ ¶Þd×>Œg(? ’Á å›Ò¨ eÔÛðd±›pðuª·¨§‰ú•aØ¿ ØýØG€nËÞ@5ýïÛÕur7@®Q»gÿAiNmhúó­ êCÔý¤¡Ålw–ž¦Ã~zœ­Gòæ³ÖB}“‹Ù¾’Ó1‘~3ƒÇ5¢îm1Û#Í© M¾ÕÐbfðøèCÔX…ŸÒAîeêM†r?(S_êOÇNs?D Uxxj‰’d~zS(|lù&½‰ØòMŒÇ–ïIsbö]@Þ¦6[¾'Í© M¾»˜½MÝŸAZÌN%Qòzœý$JÞ¤7º˜D¢ä=iNÌ> -f'‘(yOšSšþ|«¡ÅÌüÎìmjÂmiFö*a³u`ù|lÛõ ~¹‹BÔX½Ë<ì‹e`ïÑ‚Œë=Z3†•õfX;ÌÆ «ÉlȰvhÍÖ-̰bÌY/1欟sÖOŒ9ë'ÆœõcÎzŠ1g½Å˜3“1æÌdŒ93cΠǘ3Ã1æÌtŒ93cÎLǘ¶ùÓ6cÚæcL»‡Óî#Æ´{Š1í>bL»Óî%Æ´û‰1í~bL»ŸÓî)Æ´{Š1íÞbLÛdŒi›Œ1m£1¦m8Æ´ ǘ¶éÓ6cÚ¦cLÇ|Œé˜1ó1¦ÓCŒéôc:=ŘN1¦ÓGŒéôc:ýĘN?1¦ÓOŒéôc:=ŘNo1¦c2ÆtLƘŽÑÓ1c:†cLÇtŒé˜Ž1Ó1&7cró1&7còbLÞGŒÉ{Š1y1&ï#Æä½Ä˜¼Ÿ“÷cò~bLÞSŒÉ{Š1yo1&7cr“1&7crÃ1&7crÓ1&7crÓ1æÜ|Œ97cÎÍǘóbÌy1æ¼§sÞGŒ9ï#Æœ÷cÎû‰1çýĘó~bÌyO1æ¼§sÞ[Œ97cÎMƘs£1æÜpŒ97cÎMǘsÓ1æÜtŒ¹4c.ÍǘKó1沇sÙGŒ¹ì)Æ\öc.ûˆ1—½Ä˜Ë~bÌe?1沟sÙSŒ¹ì)Æ\öc.MƘK“1æÒhŒ¹4c. ǘKÓ1æÒtŒ¹4c¾Õ4d5o5Œ~¥áóÍFñ8Íš1ûjÿvx$©éó¾ð¸qí#Æ|¯Æüi>Æüi>ÆüÙCŒù³ógO1æÏ>bÌŸ}Ę?{‰1öcþì'ÆüÙOŒù³§ógO1æÏÞbÌŸ&cÌŸ&cÌŸFcÌŸ†cÌŸ†cÌŸ¦cÌŸ¦cÌŸ¦cLÏ|Œé™1=ó1¦×CŒéõcz=Ř^1¦×GŒéõczýĘ^?1¦×OŒéõcz=Ř^o1¦g2ÆôLƘžÑÓ3cz†cLÏtŒé™Ž1=Ó1¦o>ÆôÍǘ¾ùÓï!Æôûˆ1ýžbL¿Óï#Æô{‰1ý~bL¿ŸÓï'Æô{Š1ýžbL¿·Ó7cú&cLßhŒéŽ1}Ã1¦o:ÆôMǘ¾é3xóôkáo>ƒ~ üÖý¯ Yßz¨â7ß@~î›!'ò{ßzÊûÆè@Þ·ß?ð;ÏŸ#™ß~ý¨ìw?2¿÷ö9PÝï=}¤~ÿåsyûÃç¸!n÷÷}{ž=Ç}àÞWÏ”û=Ç©uÿ›çXÎö'ϱœí/ž£8Ã^¢Ô°—(5ì%J û‰RÞ¢Ô°§(5ì)J {ŠRþ¢Ô°·(5ì-J {‹RÃþ¢Ô°¿(5ì3J G©¡á(54¥†æ£ÔÐ|”ö¥†=D©aQª0^/ÌŸ× óçõ¢‡ózÑÇy½èé¼^ôq^/ú8¯½œ×‹~ÎëE?çõ¢ŸózÑÓy½èé¼^ôv^/Lž× “çõÂèy½0|^/ Ÿ× ÓçõÂôy½0}^Ÿ˜1ó1fb>ÆLzˆ1“>b̤§3é#ÆLúˆ1“^b̤Ÿ3é'ÆLú‰1“žb̤§3é-ÆLLƘ‰É31c&†cÌÄpŒ™˜Ž1Ó1fb:ÆÌÌǘ™ù33cf=ĘY1fÖSŒ™õcf}ĘY/1fÖOŒ™õcfýĘYO1fÖSŒ™õcf&cÌÌdŒ™13Ã1ff8ÆÌLǘ™é33c¾š1_Íǘ¯æcÌ×bÌ×>bÌמbÌ×>bÌ×>bÌ×^bÌ×~bÌ×~bÌ×~bÌמbÌמbÌ×ÞbÌW“1æ«ÉóÕhŒùj8Æ|5c¾šŽ1_Mǘ¯¦c̵ùsm>Æ\›1×=Ęë>bÌuO1æºsÝGŒ¹î%Æ\÷c®û‰1×ýĘëžbÌuO1溷sm2Æ\›Œ1×Fc̵ásm8Æ\›Ž1צcÌ5<Æ W<ž{aÆx‡ñý`4ù:»LäDCCDŸÏF+,#,ÃËoƒK¢KöÍ B‡³™%øàŒ}g1—ì‚ïp}Üç@rJWˆ¹ŒûŸ¦lzÆÌ0_,ÃðE1†p‡KdV4šì~†î* ôÇ!¬³Éu-ǯU“°»n7Q ÙÍ[¶‰¡¼•m@BÊõÚæQ↋’xp^ûåÆZÕ×Jê»Oc6øíü·s#är1ú.™¿¬V£~Øå Õׇ¯ú öªïaúö¢ïÏý óç~¾Öšš_þKr=LYC„Ñth„>àféåR!· B~·åÏÒùØ–¿9°—V¬Â)µ°G£ÁY”Îç/á|>òä_²q(ØTþŽãÆò×çú×äþ†#·ƒÄŒB1š&sùãXF†ÌŸ‰ÄJ8KF§#ë1aÍ9[ÌR?yúªQ¢ÞE¹Þ•G])ÿSþ rïIx.ÿêFÞÇ¥0U#ôžz¸ÔFåÉöý~%9‘ ˇä<•]Ë{ÂÞÈáÍó“Oöô‚Á3÷ïÊc¨rã=9ŒUL¼+Ⱦàù7ãcc,~}OâjöiÍ$)Ô‰ 4ÃSñóÇ ¶ù£ƒÚüñR!mþx© Ù|¶Oª^üüñ‚™³ùÃ3eóJeÈæ” dóeºÝ;‡ Ö<¿É„2³& Ènš4°þùWŒ•ûHÛ²—*½ ŽõÏÁ3Ú¸¥-"œV+ÕÐÈ[©0ÙJ…qO»TY&™™3ÉÌœIÂò_­T¦L–»rƒ•å¹³âEêó Á-™»T°5s‡ e;< ƒØáÁ-› w¶ÝÓsÕÝo[¤Ãˆš½÷aDÍnûDD׌©¨¸¾” †lªûŸPÊÑú`Ô`ay÷v.Œ{oåÍåv.Ì|nçÂxø®¬7«„Åí\Ƭu´s³JXÜq=³6WLê%óz; $[ÒZ¸š DrÁ–êk_NÞuýýÛì ™»ÛO ËÊí¥D͸½| Y·—4óZùæ­f`Þj†­f`Øj&­&3ïk2ó¾&3ìk2þ&3ìk2ó¾&3ïk2þ&3ìk2¤¯¹a¬ÂXl´™šJ–î—´}yƒ³‡ÙO2Ú71Vû¡Q³ôn¶Óf;0m¶8_û¡Q³5ëm³Þ½mfÚÛf¦½-4°|ƒÐœÙBCË=„={ÛÌ´·ÍL{[hdû¡Q³zÛê•ʼZªŸ` b°ÑÍ¡ržLæÚÝ*×ÉÉ„r#Éò,É`ÎÙôÛLæ ‰úè™p¨€§'Sðäd2è‡L·P8L²ÃÀqõ‰èÊŠ]kæñÁY&î|Í,¯Ù+þ·ÁO+ƒ>ƒ´™Tóh¢Ôž3¹+yO“K?MøëȘ ;m¯¡d»'ß8²–#} ìËnóéêö¿A8Lƒ;„ƒ;A¡Ìíìô„­Î Yž³>· ÑïFá0‘úØ),á ÕÃ^á` OO(“þÈôvá@! þ(<™ 胒˜‚>.Ø e<ú¸`§'Öé|T¨Óù¨ÎIA©Ç èãž PýA—ðô„2éz ‚>*È}´QX5“QD÷K“ÀŒÚº‰˜UÀ^ ¨0èkà<–¦è¹¾¤bÒ.ùàli æð Œý¶‹{(ZWþ$Tí;œÖû‚@Z7Hø‚Ç&i±úT&’µÇMjy¨× æêµ‘µÉúÖ+sÜ…üÁYó@ýÑŠ›¿FaÀƒÄ¨¶}7è…ø\ ó¯Ôå {°LŽó…œO"â¶kyî?f§òEu˜›F†Õ÷Eu ÍR_nÝ5óBÑ~ÙŸÁ:àBþ’ÏøՓ¡¸¯Õw wHC †Íü2¶÷Õà0_Ê` 29¶W¹¯6ø‰7í«–Sz+þj٭ΤÙ[qpûòòÖ0©Ü×¥^h˜TÍPÐ20Ü=8gV°†Õ ì%DÖï#„Õ"ì%D}áy«i‡'–ë †ŒE±êûèÉQ3F<Ë­fxqqÖ‘ôÒNÖ‘îs–è/2Ri³Ð2¢sÛ³„ÚókBÄ~¾äº­³ì[ÔÕÚÁ%cù½Uø•ÚÉÓ×d¸!P#ES ûø®!ü»0‰´-<$E¶…‡$¿ øl4¸eßõË›ùv…é߇2b§gÖ>=qö…j¸´…o›–`B$ÂZ´¿»@Æ!]UbÅ­5„Dyl¯Ây½Nâ"Ù<ÀÃM‹_j ÐýøNÙ)økJC3¦4›ÒЀ) ˜r­ƒ®ÕÐUÚš¢Ì'YʘёÙw’YqÂòßP׊ÎÄÒŠ¹Ã¢$Ë)28ÓsDŒ0}i i†g’ØÉ$9³ÃÀNã˜öz']L”AÊ9/~†n€ÊùçWªVÊ^‚Hdäp{•Œm{0`ÌŸÉá”{U¶°—ÏTÃ[¥3Tæð–&é0›ªýt§½ŸâÆKºÌðälòŸœ-¥3=9[0Ižœ;tØÉ¹C‡šœ:u°¯B3~J0¹)P¡ÄÀ̼$@vI€5esÕ¤uJ0iSFÕ”VÀ¦Œª+­`L9H}u£Û |¸ßÊc<Ç 2´#…Áå‘Â` 8;¤_Ú€kÀ‡ 6à…ÁðÂà 8J‹Ùž€>Bœ. ЀgÀGƒ5àlŸ0¦=ðÂ` ø0aÀ| 0X>Pˆ¿_½%<èBMS­7È?p¥ -Ã׫àÜo]vBs¿q÷‡ˆzf9̶¨Zk ñ[xŒpÃM·³¹ZÉÜå^ë‰A× ‘°]$îSé´%XÎÏT˜ø¤siË8ÌXÆŽ¹3ä@]Šu`³ÌM–L$ŽŽ l×úIK}áÂóf–ý"FªœE:êfÛ2¢jÛ uÌÒUð¸ä=}YmÙ'Sæ"îä” Õšä¸" ¯|?¤ÈxKêPc=·¢L€©’ÜÌøK`§­éŽõ}ç<Àº¼óeóí(j‚°½ó!AŠ%¸n‚)]lp`#Í nêàïðø;â—s÷µ½¡…+7‹à祷d±»X‚U–Äi€õ…W2‚ž¹ØÏ¸š¹¨â}ËÁÃ9ü;Ä‹eÛ[ŽWI…»%ÇuÑ» K2—ûYôˆh’4.êìÍì2 M16ä;4ص«¤Á._׋0„û±k± 3¹ÝÁ’¤rfÎÒ9”äFun ÒVaË¢ô¥ Ö‘,êQŽOcÜÎÂг¼hiairs1mÏ·4iñØF 8ÀÇö` ö¼ »¹#¹¿£)¢“AƒÍÐÞÒþaÓÆ*È¢« £®2€ízOñ&zøQœ5†>ìUÅYe@Û5ªŽ³Æ€±ë õ£4°ÕázXoÚ»ù££À bª:ºÉ9MW¬üì¼K–ü#<3šÁPev“³'}bÜI…äNª wRe»“ìT܉¹ËMÎVó졮 ª ÆÝI¶ßàõ v'°è¤Êv'°èDµÆ<™{&GKƒ± #¥YÛ±Ò`,óXiÀV| —MŽ–lŧpÝähiÀV| NriNåÆÉÑÒ­øTîœ- ЊOåÖÉVšS¸vr´4`+>…‹'GK¶â“¸zRy:`Óè΂°¸*ÃÐÈw`fN…dU¸M¹¯-Ý2&'ŠïÚgƒAþ6÷¬Å`˜p‘0K=ÛÎÕÛnès?Œ×,Œ7®µ@E¹´=nÅÆD°__··7}¼Ïõ»±'ºÞbß+]Åu:$óWÉàä{^ëÂã_ìz‹|Ÿ­Ã?û‡»ðÀïºUWàtÍ(&L«àC¾ >dÙSåaÒû»¡h݆ Îø«Í#õr³Ðë‡Bý«šž™—F¹f¹HjöçRßo³—¼|EYZÿŽ4ç‰Ëå4_Ì]Ϻ`¿Ç«‹´Õ±ÈeþËM‰üëè—ýŽ@•ð©W»4qÏã=bGéžÐà\Ûa´žû‰R â‘wèoNÇmg³'2.˜Ø÷H‡'¥‚>VvX8ô&iƒ œÚ2_ýN­Òô8µŠÓ[àÔ&M8%ƒóüïÉMùwÑΠMš<šÊÌóî¦úQDÑT«f£©VÞˆ¦úƒÑT}OÑT›(û¢©~ÆMµ’zRAË=<šj%íc°AÑT-4¹ÅÇ(m‹Ñzo}2¥€Ç‹9…ŠÀãÅA›ò)ÔâœJQàñâ MùTÊiʧRXç*mʧPx¼8hS>…êÀ[IŸKp.À2\ÍcÎÿáˆ6ª[•b°]• Ô™ŽÇˆ~è RUJ¨ÞTÊÀô' 4Õ·øà!MÆdqæó¤Ÿ->F?[|€~þ$ª ¥x¥w¿,+ %A2œYN%êXè¥ÿ? >ç1’ økÄí„;Ôö¢ÖPö‡%–l¶–æñôuåË`GÂß}³Áoç¿4½W‰â$êè\Ú4“¡ïVŸ¾¬VÔybIrÁÔ Ý+®Þ ÙjìŒVO_íÉ3›4 &_áwò[äá'&ϼoy”Ql'È*.Ù—`Å–ðIt9O“T=/õ·>³µºµÛ[Ê-,€W0‹™€gRmãñ54b-îïýšæŠmNøå².¤õ·n³'»õÏìùŒ¦WìéëôœyuánA²µí›z“-Yªw*6ŠV·«x,¿ k×ÊóEëíQe{á×zªYªº.Ú J²6 èG²íðë‚tÀøK¹¹óµz%Ü`¡Ú¯ít&¹˜ èì4Žy°òônU[ ÎiXbžk®dyÐëÐö×,JâÁyí—#€ 7l2“FÄ9s¸s_~¹tÕß/ïeÐm¹yn7èñÃ·äæ¸+“Víd]Äžä& l+],ëóˆšåvó-ªƒkÑ6[z ‘.¤åqÆX¢Ø Ü_ðלHû ü×r Ãü ƒ3ýGÚRšïø‘D’óÒêgže¿Hêtÿ\lÞG#– ÕÞ†©—=öLÈ ý}l-A1Nè[n€÷-S±KÐLnëN„ŒÊãÁ"Yšø¨0MX8Ï'–©Ø—´ª$"šV©_O1j–ƒÐ“ñp~L`<™öûä;"<†É·]k á–(–¾SµåÀ͵a9×dX>÷T ã:ßp¥'»(ƒ‰`ey®ÜÑÄ‹4 l—UÓ˜«–*ÊW.=K¾­ÏˆùÌò¬Àæl.×uKï±×©|Êm%öUé }žQÊ4Û#Štoi²öm~%â6Ó)!ÞÉéà…8·Ý`ô?ÛNO4O“ [ÎØ6àëaW`‹c€eæãœY$é\ŒC“ˆ1Þ|¦Äè_hþ]νT,û×s!GÌPI"ƒ<’D¹¤ëO<7àmö1µÞ^ ¯åŠ<O/Øô’=Óßê¡Nþ '_‹QKùÞ\ÁÍ)@8ˆò‚PÇ¿-VÝùvi©d Í“±*½Ð…ˆE‹ÿo³³Ñh4ÃÝÛ|‹=3ήv…r3¸yß 7êÌ$õ¥­R•f?·à4ú×¶ÜÙ+9°¶Ò¶?Óe,éE†¬W$<ì.Ži ¿bч„‡UΔ°ú¸\/´Fg]õ ^hÍ~í‘Eô"âÉz™c[¼÷"âÉú™£¯)÷#ãÉZãÑ û‘ñ¤ì±,I§?¶»Ms§:ùúÌ ÷–ƒ^ÈúÖ@Ö‡š;öÙ3ÃìÛ}{´¦¿vÿî½1v6ð¦Å(÷ðýÿ#wòýy``c^È#"›~„<0´1*dmWß³éyXÛÛ÷Älü›Ýá÷$å){Ÿ£÷ù=IyÊþçøÝ~_bž²e¿çïK̳MOŒ?V4c?³Ñô’=}µN@úRÕÃeXö.Cÿ#Ñÿ8@FáÐ:²©j0å‰ Õ6DœˆLçJ¦(æ¶+ܰ¥î®¡.Ø„‹SSÕ¥Òuëù#e¹Q²@nE/ŽjÍ?žž*¸ÚeÚ)|kv­ÖDhe™”Ëù¨²Îòú±+½P_Û¡yüUŠŠ‘ê£Å¥F¥â'©+~’ºšŸ¤®æ'©«£º€œ† ØèP1ND&¤#dÂHGe @:\*\€t¸,ÐéHq Ò¡2™ò<;öÆ£´¨õ¦Y=Jf-‡"ÖË‚pÕæ£"höéM 5°×8Ì Â‡D@‡€i ~/oâ6òWôÉ£ƒE ÏÝ*¤-L Z8ôº÷"P¯¡ÞKçõ#Ô)jê½d^?B¢¦mþ‚ I•’*‡‰ä™ð!ÉBI— ’. 4$9RhHrzÝ+žÇŸZ¯ãMcˆ«Ž¨‚:‡ º-Ýž»£-ÏtGYgŒÙ¯¯ÖÌ] ToìyÛÜai¹So†=DP^1ÆUÝvùÜO3g^P2^3fűµ6Ki{–f)#å` RÞjëáî"ضá4`A’6 Ý á±¹oU-jË~’FY…kÚ”TßÓ•ožö\«Ø±TwPË3H\5¨ùÜŸ¡MK2.‚TI08‰ã†L#\õÎm-nkR†¡µ0,ÂM.‚Xv¯ªh“Ø>ôîfÓB\ùòÁ@ƪêê úE{Ÿøî¾u—u¨v3©—¦½ewZïùmI;ô}½œÔدÉT]¸_ê’ù¶á$øÂõ‚‚ú¶ëâ„Ù<µ‡õçš*ØÖ¸¾;lk`ß¶5²ïÛÚw‡mí;Ã~™ÂW-|ÃW5|™ÃW”=X»±KwÐÔF€:PŽ#@—Púê!@}(È«„XPA‚]!@3è+t E¬(ˆ±ž –Äj‚XLk b)A¬$ˆ…±Ž`–Ì*‚XDkb A¬ ˆ°~L– ÈeÇLËÔm½èôć  ÉàlûB( ¤tïµ=ïœvÎj)un]ƒ¾À í—üM²Fúo@Ç‘wÈji§ñ$ÂòÛúKây2Cß“!¿'[q£ë¤’ ERyŸÄPy˜Ű}‘·ýDƒ€d¨|{Æ­õ°8Ž¥h/ t^Ãb Y–ÏaÆ[gAYï°úú/ˆ¢úìocÜ Yª/þ‚>¤úÔ/ˆ¢t»³tŽ¢¨<# ‹ ÎkÏÏb¾¤(|ëDÜqÛ8–xsiÍøÄÆ¿Ø=Œ˜`'Ò¸DmxÓ˜¸‚×ÞlÆŒÜE1ræµÉlÎZ7ÌZ AÀ^0‡½i;ìAÛe¨WDb†âfX›mÌa¬ºk8:êlò âÎ íy˜-©a¼nC<ÝEýÉxÌÇ\æS  Ü>:û¾o‡úƒÓ”Ú {¾:¿hŠÖzÁ¿÷V ˆ»PcçäjR^núƒÃ¿¨Iû¢MGïò‹¦‡ty6$Ôa=‘BEi]SîàlH¨Ãú5ƒ„J¿¦\¹ÁÊò\‡Yñ"UEÿ š€‹„×¶ê»ç™‹ÅµÊ”wDlËó`Àëm޼´å})y]{fC·÷ÀFûº›êš¾+ƒ +ÚD0YÜn“½©¡U†~ôž€Âõ ®œå‡–ÜeÆ–n´GgÝs ûèZc4ºsIWl©ß÷þÎIÿ}wúò :$:(ºÞû –ÍHÂ¥ò<56Ç=ö†•åö9G>݆•åv57*>·-Ùf”Wý ™¨ê#r7Z}+CPy3•—ß0G>ð†Qç‘︅9—sì«lan•ϱZÖwê;¿¡¤= S_ÇráiÇN}]M«{§¾‹[˜ÝêPŠÐ¥SßeWïBÔ©¯³Ó.Íë.ºµqž~¨y]×ùþÑæuÝîƒO[[TuÖU1[öŠ1[6‹1[v‹1[¶‹1[ö‹1[6Œ1[vŒ1[¶Œ1[öŒ1[¶b1[öb1[6c1[vc1[¶c1[öc]1ÛzÖXˆ€çC…º{Ó÷ ÛX¨ë!zõG§%õ…ºÖ´´ñrÝ›‚ÿc…ºg?ØXˆ€èc…D°/"o,tÕ}oDßXˆL(ÊÆB¡:_˜¡ê…º7j,Ô݉Ô…§ûJyPÝþ”6Šöu]»ðt­¨$èÂC Bç.<—Ý'kç.YžËîº$ëÂC$ É­yBY:oºËòVžîžâÍ.<ÝÑßîÂÓ½â.<owá¡$@}ažÎ!e"ah\¡0Ý}NgaÞìÂ3èœ);¼ O×[¶Çtá!à|³&¡» »ð\uÞ Qvá!“†dr“JÓ=©Ø]š7k»›å›]xàßêÂÓ¾å"OÇ ¨åOGÄ–k<[nñtDl¹ÄÓ±åOGÄ–+<[nðtDl¹ÀÓ±åþNGÄ–ë;[nïtDl¹¼Ó±åîNGÄ–«;[nîtDl¹¸Ó ññ¾ùsëÍŽõÞÏ­Ww:ƒ¾wó¥ãûñÏï^J 8®Rô¦[ ÓBüÁÀžŽøÀJQc9®R”€øÈ Kë:²Â’ÙìÓæC+,é¾ùÐ Kæ®'ÌÓºë 3O˜ F¢ó 3 ÇŸ0£d0«‡7÷êÍíÏÃÛ^uˉýyDArÊ÷{¿Ýt;´Ù¥|¿àu7Kùó¨6‚¤¤n#H: n#H:¦o#HK{@AZ-ÜF°³i5Ðt,8xW¦m» 2Ýi¡7`S]i¡~ÑlwIró¥uÈ&\¤^b˜ö~ÝÙßíØqiÿó£ý»~Kk~eбføÏÖK×p¤5ÁÒô½æ(ü^‡â Þë]Bñi-28븬ìµW,Sí­Ä¿èÍL¡½ß^¤«ßk’´V½P¼Ý^„`¼Ó^„„/økë¼'Zg%ÉPyÇŒ[/,J€,ï·1¹í–6ÛeÙS\Û1›¾ßÇ„B_ï÷1¡`y§ Å;}L((ÞëcB1äï72!ø’w™ÐpÑÈ„B‡Çu2¡d>,›Þ=J>ö„ŠùÀ#*‚â¸#* â÷Ìž#Á¾îÈc0BæC ŒøÈs0º>ôŒ‚ùðN#]³Œ-¬¸ËCÃú~§‘Žç©m<ˆ7{5ÏG:tÍN?Òi„À×Ûi„bÅ>¶Õ-÷½F ræH"À‡ºÌ—u¡ úP·‚™ù±n#DäÝFÖ.ún#dBQv¡p®äÝF(„z¿ÛËGºPÐ\nÙkûéí)åæíM‚LãµÚ´—'ß¶åy°,Ú! T(ò͇tPñA÷‡ôP¡àëZâF±¥êZãF!Cç"7‚U¡s‘ ǹ¡d0«‡ƒÚ¨Ä·õQ¡àëÒH¥û.»S#•îôo5Ré~æóv#•ÎÂÒI¥»ªé¤BÂöF'•î›®·;©à“uR!XÓèZ©P Cr÷¹û¥ë¥Ò]–·z©tÏßê¥Ò}ŸñN/•îÓé^*o÷Réžy§— ]/•îQa/*aH\ÁD¤ë¥Ò]˜7{©ÀÚK¥ó48¢—JwNlYe/•‹Î‘e/2ih&7¥4ÝgwwiÞì¥Ò=’{³ÛIÇ;Ë`pŦÎç³Ñj½[»ç{ÃþPYðÛ>ÆoðûÛ¬Þä÷·ò#¿ÿ#…)P|H¤J(CUq˜$¦u²7Ÿi\'û%êd»J!¿·Âø–Õ †¨õª‚Ž”Ý…ÊîBe¡²‡PÙkw´ ßQgShì›BSßÔSLw Fu`*¬9P#:x«|݌ޔÀˆL‡·J€ÕÁG îÁJøfµÐƒ)|H3ZèqBôµãÛáÍ;f´ð¶fµÐŸ-¼-V ½ïÿ–ż^ŒæŽ–«—à ïÀŠ9P˜4Ó—É(ŒÍ|°HÑŒf>*LšéÙf>* T3Ø|c+ý÷8ÖròUÊ„É23ÖRˆÔÀ£—ÙË´vEÄJœ‘KœA%fVú*ŸãY 6cf9NÌ…h½ŸJF”IÃøkä¹¶›ÐSÙ¯V^W£JdñÀáA²çºÏ1_+ ǶF¼éƒFŽÍ®ºý”Ø»ïjtW—ªXH[âvÂÒÛi׌G뉞ÇáWwÒVnœ¤–‡0Q‡ûV°ðÂË †àyÌÍaÍœ¿êöëÖŽtS­ÊG9>E²ð™åí>–B ÎæO´H­ØaÖ,Œqàö¯ÔÓ ‡åLÖ¥ÞÔð‘jûÕâhÐc® z` ËU¡kÂ_ÝÚ˜þvMF‘Ûg¶É JìçïŒh–®¸Íl; cz¹5tCpZp˜Øù"8D‚Ÿ#ÁAØ0}<)["ƒ4-‘iu½[îLè#ëÅë+‹x,ÂÀòÜdÍVg´øa`sÅák{;¡ØÕÍšò%1l·VeJ¸H˜%cIÁßÛÇ÷ß–ó¿ó¹•zÉôî¯?äHx<” @`>Y±à÷aÈ]AG¸bÔÙë?¶ N†æ„r×B†F ¦"²Ž`¡çHËû_ŸíЬĹÊÅuÄ”Ò}Jçsß©lÊÔ^r¿ëp¼–æ—#OÝè É,ºùM%’BȘ/\‘ðø!txAð§å¥ÿTzä˜ß/¹ýâ ZüQ;t$pw°ßyÀcשÎE´hÚ½võ@4ù_V¨ZEþ®·ëãÀM¾§RÔÏrC‚‰ÚÀ•FûBú#ðH`Çr°`tê9æü1M¢”`ÔÕ—ºrýÃ?»ÿ?{ïÞÜ8Žä‹~•úëôìÜ>õèØÝˆj—ªÛS/åîésnÜ`Ðls,‘’²]sb÷³_¤$’"%‚È)ÞÙj—Ëú%‰D>~éà}"dõ󠞀ÑgjížÏ~@¾®Y› è1†î|òš|Hæð¸$Y@é²I¢+z'䣿 Œ] h¸Å} wë‡IÐuKb(ÐëmZŽ›ßéšöCY+Á‘¹K§ØÛL9är¾qý˜íåjü„KœÌL¹r‹;×{JÖ_Z±1áMŸ™ûL¾†“å*ù~ë>l‚™¿\- ÞÉ,‰Öë1dzxf뻘ªzÎoÔ ìkbçtzbÏxâ‹â½ør@nÖÜ„>ÇÝš¹¯ý[ÔăuUxs7qf,ì£Ëxʨ®†¥×˜¯ôHˆW®;Ŭ%'3…ŤGq–~­åŽœJ·Oå`ÿbmur¥fþ‚Î Y6ÓàK™0e?y]åA?m{K®ˆH0ÿzkðµAq'éDÃR5ý~n_é^\~Ø߇Ñ?§Gø«{ ÉU¸X/ƒô*:jŠÍOÄïШ»«42ŽÞ¤ÀÔ¦ÐtàÌÈt}·ð½ë94îŒ÷„‚ÆåΜ©~tã Þ>¤è×z²\¼§V s¿ÂœÛ?òÐë$¼bjìƒ{wMïzWÉ+üä¤B¾e}¯cËåbä¤L×ñ#æ£PÐâ²s³¨Ðá ?ÎÑýÁ¾þ†…œ®ô’*€þ-&ßx’] N­ŸpN@ü_•‘Qh³»R¸ÙÍ¥„^Žý°^®>†ÑÒMRŸ$²(r3 ¬‡ý:Fä·1ø[HÕÏaø´†_@)8w’!IøLsä’|!‰» ï‚ã§ZîÛÒOÂ/Âà˜Ýš…ðèñö‘‚ÿ†,;”YÌè3/òWÉ{W%“𕼔l?@دá‡ävõn¢ÚXÞìæñ Œƒj\¶ZÁÁ÷)X˜¦ÈF"|z BŸ€iþÜ£Ý{ðagàëÖó¿…ÆÐ`xwìÃ)»çfÚÛDÑH7yœ[<Ö çöŽws§÷H´M¸ÁFYm,n L-Z4l¤Cr†l‹ßº—ÿ!#÷nAþþè'ÞpªÏgyf”kàÌä4¾ÊHiîl’‘R• ,„ZYÓx5qÐuüŒŠððcjswÀë>-+¹ Y• (rZzàÌÃe@MZçÎÜè»ãôVÄ‹¡ã0’KŽ) Hü¥<&K„^lz­›˜ xpžM&ø0Lð)é5‰®$ð¨¬s©vÓ·uÒ¯¢Ð#qLÏßë æÙvœ~ð!"rO"“¡úâ™ „æ©ÆÜ\Ųjhxœ0zœ¸Q‚r‰äÈÈu°b÷|‚“ÝóÌüÔÐ$…V!¯ ?xú…®¼Ô„ù@âÁÎuI†…ÄE\ÇŸ}`ß Ç¡OÎ wr–‹÷WnB §‡÷sXßzܛþ¡WúgXU@ç >MºB’f`! ùíæ\Â|þ-#;Å¿zôð‹?ÃýìÇÀjcÓ3ÁÌȰ“9ö)!9CÏÜ6ï¾ ÅNñ¯aƒa)èWòšÌ|ª€ÝM:Ö= …ŸFäoðÐÞûk¼¬F?_uˆ.`“C ¼W>|ªÆg$JË{o_“,e©èŽ—b®ãRÖI¸¤‡Ò½žBû¶sðÔheI,‰&ã:fVe´ôŒ3$ò•¼Ð×¹¼Â܉¸ ׬Pœ 1Šï[—¢l­•‚ý(d~1ð›pOöƒLV±¿vß%|%{±­hñ-ðúòÝ Aœ+T…Eñùø}fpfJ6Ÿ¾NÖ“Ðk÷GŸ+0§‹ YÈL3Š 0\܆·851%¢ö ʯ²K[¤Ï’ÄOPµ9üìúÒ6ÅùÙõžnÃÔ€»¢wu”}ão,™‹‘óª0 iz¬»ŠypÔ.t½G õrSðÒaæ¼Pˆ[¯>àæ~}ËÒ/09N0‡ß\“È•äLqXB=L¸SôF÷>íY@ß&ÕÞ5½RÃL…c)°hÚó—(|€¹î0Zø:†ÚÔjxH tæ=°eW•®ó.y5!_|0`0'á e›ÍrÛìj ñ^fQ)dóV~+ÈÀ€þ=òrõëû0¬Gb9ÖßÖaBæœC;6TøXå˜]SÀw®°é2[ ÌÂÇ;ðþIέnLlv=@Åç7ÈŒõ­€ô‘‡A#üSdn à@3›ùÞŽ9µip°Ó»Â@´wŠÃao]Lxz#Âçfx1þbþ7–VìæÀ7„^0ü½Œ“d†->B&ËÏßvq‹×KRªÅ’z^éÖW<…V|ƒ}b€O^‰]yÍ Ý %mQÛrM(Sd¬Œ¼2Ë"ÏÉà¯6Í–pÐÃà™Dà#b®bÍ ÌißåÑ‚wprwø8iŠ~æLBBçï)c´B …šS‹›R{ŠŒÚS$Ô¢çÓfx^ùÝÜêËÃs]4å¥6èbàUµ¼'ÇYgÀë\wøý(æ<¤Øø Žà}P(Èëq’!Ÿý۾칀4ÔëàÆ @É2dz]œ#Xw)r€M¼§Mƒ ð_oo§|‘O7ÿLßãÚ} ðÉç¼´yœuÿ€Ç¦×ó,1€§0æ åÚHrüôö’mH^N•^ÁŸ1©¨BÕ0ûÞNÊ/›Øù»êœ/þm·¤'¨¢o±°SÅ‹ýiŽ=xDæäžžÊsÇ [ÞÀw§¹îÃù' >#ƒOý³_¾|άSx «ïÛ,+žo„!Ãå¼ÁýB-uŸùA1@ó/í`·§MEÁŠ.¯B™Þ×Gaë,m5nT¢€õ’D.F29‡gtIÐV!ÅÅ¡k(ƒc¯rTËcáâ9—è‰!`³BäpQ&…g(|ØT¢œ©\®؉¨é)O×`÷ÍØÊ¸þ†.!HH¶ð‡ú~ÀIAìû±•á΀?×24KK ¿dÛAúpÄiˆ’C†eRÍ“©æ aùTsÀð”ª[pà^(y\ÜÅ“=öDzO€ÀÆéãÂÀ×QÄ. w¿ß¾ü=rWïçá*)Û}T@á_1òÇ |élŒ ŸEï+´!ÔðY=6ú ñÂÀ£êekÙ—‹¥á$±Ø1Ê{fáJîX®â“£LÚÈ%lJÙÀ·AÃß øp (ØacPùU ÀHÃß Áòn`Üo ਠèÛ¾"ÅÇÉ7-v"ƒGçiYVq]b´L zë³*àÏ BQ•þÅ4dD,P©¾>ˆ<Ð-Fx<"{ bä GïbU%¨uc^.‰qSæšàóåSüý¬Oï8‡Þ«ã0ywÀ³õpP‘aO^éË-™Yºtò;C.WªM½”ÿ»Å”€òD½ßòhÌß^À¯B öoh¾©"žž±ŽÖKº,œC—N<ˆ‡TÙùs?ùÎzª•êt ÌñÊzdâDrÐe» äZ‚Ðxs›öQÁ©©Ýf'õ0ŸNÒ+¦Jý& QˆÒS3\ebT(¦ "<Þð1pEV tL Ü= hìÝb膴ãïvéƒtð~Em$¼‡~Cè¢\x­“Š™­ˆç»<1þA¢%r2y]17ò×»«½<æœY:èåuËIä?—]ÒØûw10ØŠx4½¦å8è3Ö™ú:þê/e þÅ}½ ŸH€Í–“p‰ƒŒ´Hm„ƒ[Q–]J晸%r{ ÔÔ¹Ž¦ïXbÎz ŽÌRà›ÇgÀ_ÜÄ'IaÀßV<‘‹áÞ ¿>úÁ¼¢¦^Lo.ƒ{}UªsjYzdä ÷È%d´ÏØH !­>ƒÅM«çBàÓê,nZ}NÚZD½Ñ§ÐR]üõ´‘óR6zм¸ŸÁ¡*æó½ÁÅH7H±='\øÍ=EÅš¼Œá:b‹ŸTHºÕ9ȹŸ!ïÇX`ÐÊ/6¸XËåM›ÐË Ú¦L•ëþÍæÌg}0˜³º:§ÎƒNfàùü –ÇYËÓ Pûý‹÷…,!%Xé;#I1þLz-öö¿AîypnÖ¨p(Y°œq‘ÈÏK’c(Fä䤂Np-I)3PB‰—«ˆÄñ³ëÞí_N—O†ð¦­H ~wLÑ·U4ˆS³‹Gbþo¸³ÿ7ÜéGMídø¯iÛÌô1l*æ#q“u„±u3d”[…O™bPZŸ±v(àÕ ¼Ç RÉhV©ˆÒ"± ’Aû,aÌ_ïqù²dË×…f­mÊ|ºPƒÆÚ,ûsL/ëÔr¡š í(*áˆ@™z;Å8Rb£kŒÎXÖ0ª+)ôßÝ( §eŒš>›Úê8ëäW7®8+!ŠgR`$ØGÞÆ>‰¾˜à&&86K°FÁEi³CfÉóÐ^.†ŽÑ­„ᦅ(k/…FYyûåPÈ«˜û,mâA# §õÝx *‡²Rrøð3Ï PÆÍ€±p?® ´A3pl„æD ÷·Õ<åƒBZà9|”9ÏáCÃ_ûx;EÉÒâÈ(iZ#O‹c$j]clÒHÓÌ ‘æ™AãLôùï8Ð8/‘ÇÚ¨8®ƒ9K ¢æ_JY ~Óc”§ ¿frp8©2N5 CFd(fð8Ñ;dŒÜ†ŽD Í }wA{¤Ç€òU  æѧ¾‚Ï~óËެò/QX}uù‹ õ Å_¸ð­ 3XŒä»ëgž1çø*\ÞùÃHkìüx2œ kÌ,” „/wÈX#‡RÌ9 "wõßû«Ž5'ŸI’`¼Ë/®¤ç3¶ÿJæHÕÿ×ñt}çÏqÔàÚIÜ»ê—id”ê»`Fýǯ·_>CÃ~"dű¸‚ê ENŠGÓñjëÿ2’Hìã±úõòŽ^³ÞÀ¾¤WàO,I¡Î‰ð߯VôTÂ@æÝaP€"W%rÅ?AB†Ò0X”®®g­}ŒBøÃ’_1Bkd†ü…D(Kb®~v=ð{Y6ÓŒàmÜkßEx{”Ùó`EïÒ¦0 ûsX‚ÃLÈÏô¾ð´ }ù–Ý)Þgx^ˆ/dù3E~*³&€?øñjá‚orÙ,ʇ(8Fžß~Õ&ê'|C°÷êL¡pà ØúÞëRúgƒŒ³©‹ ø=: ðc0c¦È8]î¿„óuÓ3| ½ÏG…\ÎíCž}_Þ… plFÀL#ðwÈ€ ÐÛöLô\Ý@àc5=øÊÕ|©ÃÍŒó™·(yΪ¿†_OC}ͬ£÷ó9Ö£€Ž¡D©€Ÿ×÷i¨zßu‚‘¶¶Á=@ $‰ÎúD¸a©q½d-o‘ g<Ó)"TM"ø¸ÛPŒbâd}½X¾„›jˆ2ðÌð–å uYîÐ‘ÔØ oÝSh” _ ¼¥VòÑ’3.ývsAX¿Åÿ»Ì×EFœVdoN Y¼%m$„’¾PÀ‹ß÷›Ø ~4¤ ¥}9Áï€2üvÕR0îmõ’*ø,?êÒÌîõ÷*·âd*$öå]ÃœÄ z÷ÂPmqåíÛ’r/°~…Äœ'.`{n9ãE‡ƒc#ñüûä@ -xÚ;=å&ñÀ™ ŠRʹM`~vnà‘ùÕã:xÂá'­“sC¼ðþ¦ÏÅ]}˜!dÿ§Ði ÆÑ˜â?ºSѼ* TBŠL†½†çÊL‘qrN2l”»Zм&¸TXŒÑ)nj†¡©O„¥ .SȘã^£­G$ZÄ<6PE$È–>Ú<óF°Å`ãsÒJôg < É›,ˆƒŸßº8ç¢öL¡'…Ác¹):ž•> ¨¦‹èÍuŽfânDøa€'ã5e²gçX°OùxäÜð?úòå%°–là‰Ù©F¥ïGÄK°LÊ(-áĶ21ÈBxž9nà¾NÖu¨ZFÿˆ8¤8þ©8Áü¡ðýAôŠx"I¬áœ_Êt‡—õKOv¹'dб'ƒÀ!'y¢G?{¤·œ¨`ôÅ}ý@Ve:(ScJž0RáW‚{†­<³ƒW5øÉwDÛi#âïn„ÑÈ/’ßÕ–¥´fGzòx–îjôB%MUJ™Ã–•ïÞ„!8WBŸ&awY®Š”±×[ ˜g ]¥!àFîð—eŸÎ¼{·([3Pã÷ÂåÊ/£ËÏ=™»ôèmn…(½É*…à4|˜†+~”?B†{å.wî>ƒ½¼€ˆ<ûá:F-ã†/Ššn(Ó~ƒFò|ƒÈòÌÌ´½úSÔâ} tO­€Ào[@ (5±YÉs¸_4 òæRdœ×DZQÞ!GF|‘ûŒZÐH/’!c½HNOƒ…Œû"Y;.p¢€ ¥9Q†‹Ð¾ƒ¥Žž¿ðÝ„À3Ód‰éÙ£2†c6ƒÆIô¸!“WâÑ ~Ù‹Ñ#CgdÜÀ.Û©P˜Å—Á¼„M¯,H/€ñë3!A<ýyç ¨Œ* oètÌWûM8p6täëø¡÷ä¥ Pà§"øõ š˜D' ]݈ÊnàõZai-º4F< c|A§™<Îù±ï”±! •= {™9Ã%•ƒþþîë×_2Ö~–rŸD:µ4“PfvE.S%Ù?Jóõgèå¾apãfÈÕ|{°2jŸ DüB’\ÚJiõH·èÜ á)ƒ57ØÛM63üŒ(¸æØ)ÔþÆ^WµT‘ "W.èÙ¡M.„Úûk/YG¤b ~4 TáìÀ&|&.ãÈ#IGŸ2q\½À(÷†zž€ëÅ¢¢ênßoMÃÕiäÐ{æU¹FG âódû‡$n©#41ü Y†Ï¾’)ÅÅ ÓM‘ÊønÈjáz(MÍoHL’½¬dÌXÂbðÙû?Œ-±F9¿º 8½u»½ŸÄàûT@È5eÔPèÁ¼ªl½B‚ƒÅx£ÕõÇPàµU@8%Ôb½d5wà¡LÂ~U-ög? ˜c§Ç¨»d^Ḋ˜®ï¾w FÌÐÓB)ô_Ý}‰RײŒë‡ ŒX¦Ößýd¿zJ ½†gŽ5ú× .¤œÐ»;•¬_“åâ4²°—A,À•㸅k—Täº!3§íbý€3÷Ì—¬ðà¥éBÍOÃ,]y‡ÈF\m’.ÜqßV,vZ>ꤳ‹B°SiTTj‚°£¯œ¦6q{R¾†¬¡%Ž­°Õ'Ô0A}SyAÕÚ~™Ø‰ªJ׆{Ai¶6Úá^På²F·rö¸ tçFÂg<$Uæ"äB. :Áį¿ˆÖðFà· ª-ð6eõøW­(–W_áHèt¹'§"O^ §*Ú1z“_­H€t-⨂~ÿ†Ì‡-¦Ê -åë^'( <Ñ7ÛÎJJ{Rºú$“DaPvÃ5ôÚË0°œÊ ¬˜#·{XIµ·ppI's‚´wÏ„…ov+0,&±Æäy,âFÞ#¢Œençk Tâ.§!|òo ¼Wí‰ÌJ.ðÐËæHGÿ»$ñûà;’?x¨ gáêÎÐ×QÄNj1 ¬G*àñèÔìá)-ƒ'¨”»ð™õÏs>¤RП䶮íØ_lè¯!©ñ'ýEפ,à¬SÔïô p9û•”š)K³§q`œiÀ9épì’x}‡€šwÕU)I-ž‡¯h,8ÌÈy¥¤¬ïbªøÖÉV"õ઄Ӈköâ'Þã†Ïüa8:§à®qnp ·!Ö0•N—‚&cÈ_Hô~cfÀiç”-ãßU¸†¿4ïä0—0BáfNÀwö A¼^’r’´¼“²ÇD@ßžC§ãO*f `”„To5]úˆ,‰a)P‹²ËþiN#³‹¡¿™iDîýW\U‰PÐ2** Eü±\|v±Ÿƒ ©$6Ý+éýr/…òYRûyä€2öz²ÂjøÉëÊ-æ"P.ïàI)-øaˆ6Ey!_ÃÓˆ‰1Åpƒº‚9€®¼ 'KG«¥<•O¬WÇQŠ"¬œý¦nÈÒõƒyù5 ùÕ·«܉USÑ‘pusË‹à=éõÐr¶¦Ë>_äVQA ªž+MIعÊö¹^l¬ ªÍ21ÕÊXRø´^mÚÆÿ2!üÓ³$ñ-KÂ;CSI•ý$À¥|ô£øFN*ŒUBàËÂÕu×>`)¼óR¼¢=èE‰Ý*Ê•[ÀSÄøòþ¿Ü252èbÚ¿{Ã>ŧ†Þ3Þµx#`ê&,ýº(G:Ôº“ó·u˜ŒpèNû}«œj›%‚‰ºý±\  ùF]È,qµy*¡ìœ±iê•Ô )ÞRרSÉ)×R '¯X|ZJå@“SQ¨Ëf'rbÌNrѯ\×À/g¯´¢²s„tÊ‚Äu™· 0¨S×;òzŒì±¨p…C àYØÑ$˜Wó@æËVÈÕ‡÷·ïQT5òQÇ[¥îÐO@áé«X”²ŸÈuËR*¹à¥T´ ‚ÓÑ£ §«GAÄô ½‚¥5ÅŸ"zJ\ó= J¼$¡*€ +§ò†@’ºÅàëô¢˜¯3\A¸ÇG*ùI›!!•‡‚ô}¿‘ƒÑ{ª,û(AlU-{G"žZüO| Vƒ8_üO}XÈ2üàW‚‘c”“«‰S(=yKB05ñF¶&ÞÈÁÖ+[9¸šx+¦À1rbqY™iŒvqÙˆÝ4Ï<ÑSnz]â :ÉJÄ?áøŸi/§C%a§y¶èòLÐ)4z* ]¯oÅœD»o¥dgm¥R9¥BOø|'ÕØvr*åÆ}9…´óœ$ì CŸ**à3A>gOñ"~?éX–†½;?Ùøû ÏÀßOtþ~ÚSð÷Óƒ¿wrþ~ƒð÷“ž„¿Ÿæ(üýDgáácôÜçXO÷ O˜ÀS)Y2|*læÿ KJD¨†HÓ +ðá$…<³„]âYgNοQ]? &ò’üÝ*ª¶VLV¢bÄ”ßÖÉj3‡ŸIiÔðŸg—(Y¡;Ÿ¼&’9º¨ô夛ê*"Yc Ö˜ bíCôvHŦ9HÈÝú¡Š§ìñR9¼®ÿôÏHæ.}6oó¬ÈoòæDzë@co8‡™!åàóóf¢Óe€=S¾u™BÀƒÐ^ýv5»Žß“âfÅ–e6{Ù'H,Vîa•å­©ã™MàÕƒ©¼È½óÁ©šsÐ{ñþ”Â~FF-ßç•ÊÀ£ðçeÿìÆ¾÷™ÎÎÈ&Á5"q°©9ÿ„‡œ]æ¦=\…Ëð>Dg‘8ªþÀëC2!¯"÷((…\±ØTè ½„õc¹—-ŒÆþùû¿˜a/kº»ÜÅìûò.\à<ÄÕ_?±Ntßù‹’SMÞáS–t='áCä®O-n¶^­pªÎ7‚oÜ9['”­?7˜O©õ˜¬÷"×Â~ ü{ŸÌñ_Üž ®ï Ž=qP$ŽUÐÈaƒ{…Œc:2dðŽH[dœƒ˜!#-7ùŒ N±¾E^¢!£½ÀÏh;ð3xד ò4`´½ý¼êk‹ŒtÒ¹ÉW4`“!£íí¯h;pŠŒ¶š§h/pжO¦h§ëçþÏñÚ¹=CF[Î37 CF³fhKãÿ £)çÿN›¾EFÚ'$ Ÿ’² —w> 2ð]/òv ÿâFOHR'í>Œ*CP>¨­Ø_ÝÅý žîÀ# ’(\L}C’Á`½ï¨Ïñ}ùa2û¾X¸wnôåýüÅ)޳¯v]A=ÂÆÒDpî_ȳ¸.=.á»ïïØŸ]œCçcéÈy\ÈÆb‰˜EÌç>Sðœ÷eáDãÓ+ÐÂ"˜ÎÏþòn²Zý€¸ÑÏ™"_âìˆTªgãsø‚|Tqîwúÿ8Îé/n˜G¹#0…Ç\Ty™ßVôœ„HGö?ö}û ×±Ùã½ÇXÇ„þŒ.õåU¢­ý¬`”'»%ÞcÀæçÙÂà!\`¹2Nùå»,áÞ9vZT€wþöðˆ¤ã¾-æ×‰‹å~þ¶â›{{ù¸!^øøh.½o‘ÿÇÒþ/Ý໋±‰Oc¼ïnè(󳃔iºYH«töè>—Ô g~ðHíœa/ÝÅ‚éœß݈)†1[¹‹†s–QeÑ$QÄó±îøô’FÇÍÝ!ìLfEté_°¤eWBj:òãŜڃb@åÅ5P„Fß‹ê{.Ëòp&õ;ݵ8 íÖ}páƨ)ô¼ hør0à|øŸ Έý?ÖnðWª ½W·îÒÇ1êoÉbý€“Ý|ûèby=)4NtìÖ¿# Ò ç7–€̪]®è„Ï©%ðþ.Œü?p³pVÒ·;˜-?# âaûRp“Yþ7n¬áû¸1Äÿíÿƒå’‘W—ù‘´ÒÍõ$ö\øy[àYQ¿¹þ- tŒrØÛ#vÓõ–¥vHcä}ž"Ø$Zx—!‡ðöMŠÌ×ð™²)ô*„ߘ)r\z…Ðë;pä`áOŒ9ôž>ûwQ)ð“äk\nJ¼¢ºzN¾-æ_cY,NöóÚ_Ì3Fozs'àÖ#—ÂúØm™’úî“`òXkù=’Ï\Šô #x͵Äÿ‹Å,ÁÁO9sn®áC¹m:ŠÔG©jZ‚ÿÑGˆo…$àÙ9hÔ¡W0u"Àc®Ó¯Wå>Ûöø—Ûð‰X舧Ш—·Ç•°LØÜŸBòƒdm+PwA&!&´ñ-¨nh,Y#Q |é®\í)¦áªâ)zén¬ãÇ«nâ"âã>ÁßußM‚/Ÿ?®o±ž“!Üßkû %á+yÁ@o=‰Á áüÇE)૪QÞt¢¤–ä”ïÍðï‚‘f;„*$œà•lÅ”_ËP~{oDÍH‚ò$S7y|?ŸsS~w0ôŸÃpAÜ€±Éb¤ÍpWnœdrnÃ4— _Žv+‡m@úÖoÃL ¾ ä‰ÛÊ9ÁÄäaðŸ„?à V@&ùqRxüÇÙÈA^ør‚GÀ|åÄ_Pl\Å¿\±ˆsrñ²Ïˆ žL‚¿¿’å±ç“gxGÚž€Ê½b•¦’ÏMp½}¸~£ ¡Wz^¹ÞcÙ¼–îW¿‘ñL¢U5¥"0uS*S9…ëyE%¯IÅþüóžyÃëåŠÉ˜¼®p^ÄVÊ·»ÞÁÀeø¬ à]S|œøÚØSðY%ðl™ˆgÄhòϵ»ÀÄ¢âê‚Å:Ô0ÚnÚ€“8ÆÒ:LÄ4",ÿ Þa½•°fîÒ”—ì€Éúè.b‚ª¥?.Â´Ó žî{¬BD±½$˜_Ýxæ. ÞÅízŽº£¯çó¦¥1Ay|€“ïfÈ_]p–ê 2óµ}‡OÖåðŸ]dÅg7ƽh|&îëš”a#š·ŸCÏ]°¸(ê} 1C_6½ëp࿾¯ÞY2 åRà믑7Ù¿Ý\£¾Ø¯äÓÕÁâÒˆ^ˆê°7$<µoá;»lÀ1­Â<šQHEàmTî⊧Kðš¼<'!Îí%/à[4# û„‹ÁJäÚJàIÝhèŒ ¬“î D ¿‹ábbôôÛ—0óÐ2붨–BHÜÁGÄ#h&dAö»À[³ô,*;Ç?J·ÇÞbcñ9|DC>;­ßϱá¿"YÙ[¿þ?á£óB6ÑFT¼½;¦„ðeYyxîD¢/$z@¡² ŸQ%° †ËZãbj¥Tµ”U©á^CÃ;’FEà>BŒèWÎøå0ÇŸº÷¯ÂxEn ÍIô!ôX…@áÛ?@LÑœ1ü’»_165)>z¸Âô𰲕WÖù) Lñ1Ý$ /‡¢#:/¦aÌ™QÕ yðcú~ß/98úy#ˆIA€¨ªób€HÖÝžïÜ!¥W–…œàlD!¿£§ñS¹ÈODèeî4r6s‡+£/^¸1íìRÊÜY¥Â/(/Ç,q£$þ»¿K2Ày~^1W ⹘ 9Ás|&Áö„­ïo-Œ¦”?Éûûù°õ3¹#ÜûÞV²”%*>êýþw{*"ˆn‚û®o£5®¾ý>.üÕÌÀ’€n¤E ™(Üf<žá£Þ™Ìë ÃGœEaà$z?v§BÀqú0ö@ÉH"œüó÷Æ bw1Ï:Ë»JIIQ&(*HÀ u„ D; ÂX‰$â¹L‹…»ŠÉœ/a4!HÉ:=7UhzºJ‚õÍÅ`¾ ŽÍ•Y_”2 }Œ$ˆ¢Ô÷ÀŸƒtOÊcpøÛÏN"f¿=™ZHøïŸùïüøÅ󨆉Ö„‹û¿GÄýàüòõ7göí·›« ÿÀú?²'ïw±z°ôÃÖ£ ¿ð+qçôŽå‡¹ûì¿þø¸ZñßÔ¼‡ôW{A?¸·2~(ù¾"ñöS‡^yö©Gz)Ø}Àløçþe¾ýÕôCþrµØ~Ê>þ©Eøð@¢í'u(¾6V6°vRkõ‡«ÿçÿ)¾´Œ˜ÅÒßà²*§ðöµÍõâ¯1 ÖÆ4YŽ?|àrìÄô7úé aݳ‚§/ MïÍçnÈ?×$æ¤D->6Â$ôÂ…ÈGg‰›¬ã«¦ãtïõÕ½óŸ¹/é¯?kö‘F¿'ó¦¿÷ÓOI¤U\ÅÕ5{òW…}¿ÿÏåe±ÿu~%öƒó¾Ú|šuû1IVdÖ¸€Qûôza¼A¸ ùØ›ø7ŸfñLw¦Ó¯3G×ø?LØmr"oýJwù5áßÍH0Ogj2>„Õ M¦3ÃA€}n9dßÝøÏv´‘Ûx”Âf{•L^‰5âÃÐí‡<Îã†q9æ#ØÏÇí’ýíÉ>Y½wù¾½¦s…¯kšf42TòŸºZ¸qœY+}øÃ‘9)|6]f¹cÍKodüb-|³1h¶Ð'¿‹ÝÙº}aÃìn¨k‹ÐÓm½ ¦x„À§nä.Eg´¡I}|‡ã.2Ã`$ò5hÁvÆ’G_hNj™˜íˆÕ{ôë¿ÛŽç½ç³Í¿ƒœm[˜²³Ýêã"ï臒¬£lB‡†Ðœ=†Q²Ûà»ÝÜø©Œ”j=#\j©6 ÃÓYèÙ­Yÿ'á‹ò¾ÊÒ³hÅTU,£xuÅ«››Ã‘èƒFD‰÷]úÝ1'Aƒ…"ºN ËD×àîzh·JöIîž.“[¦È®Ý_ºþ5 XB.‹ ^éì$vD¥b sô`€>…sÇ‚¥Iž m` kžW:ä,ëúÀ’œæ6Ÿx7?dÍ_…5HI çvoÓn¢MR·•±>–¹­0ÿ¥ÌyiˆI¯»¨Ð??Ò‘ðdøq>™~b×Ìâ):ñ+œ%ê"ƒ}‘±ê"S@Ë)Raƒ¬2§Mt?w5ßÂ~“œÝ|[ ó}?‡k£»;ºÙó¥M¢öŠn´óº¢›c¡Å[6²“ ò‚>Ö‡ûw ˜²ë²ÄÁošBë­ö¢è瞀DGÌEÊò`XŽ¡mþ¶Éä©7“TJs4DÌöÃP)áhŒ©¤‚ÍÑÙ©àÍÚ‹·Qø³7ôQWª{d륺óª[76c¿IU¶¡Tö Se뺭ÒòŠhx*ÛЭ3ÈÊë¯Ê6,Æph‹dZõCíx44±¨M]\¢ ¢•_#†kSʦ.¢á:6çç8ÎïLHï†9”Ñ·#Û:?/Dß ɪÛ_Ýø1µ‡•ºMÑpíá¡­Ôm SÝ,Ju®ê–íL@uk‰&›[¡L|Ð*/\}o_C04¥JRu9ÎêˆWß™ªü:s6…~Õy³ªÆ¯Æ@—v_h‘:ËæXÒoÓz–arbÑJ9`2AÑË9JÔVÂe †RE]Ë«¬…\…qF{ÓÒß ’k7¢2:û׺\éã§óªÇÁH*s46ÅnJÀ ˜%. vkà äÔ­ FÁˆ(©ñ"¶6Ô¯)`¡<Ï–¾ãá_:Z–èíé‹ÍÚ¼© u)>õH]Øó¯¶6ö"©à§àÈ÷6ü§Ì½cýAÇrEÇB‚ÄwÃG7¾"Q¢¶І¹ý¡&]À‡¿ýóUº=”ªÂȨϞțƒ#MäÖ}öC•üè#dá|ý®òôæÑÕÀh­n²ÉŸ}¾zï=ïIiÓ Q›ššqIt7ÀÚôñIiRIMºÝÌZttÖÄÞ 3X3bï¥ò@U£)fïÃ8ŠÙ»Ù0³·à×åzŸbÿ_ĉèa:ã–|ecë¾­Ôà(ß±OµµÐúÆ¥ÎÒ6„3D.u1§c­eXyþq‡t²±] §zþ™@ƒ”¿C˜[š†¢ŒE‚Ý™ÊÇÝ¡)zôÃ8gC¼püè…c$wdRu¹Iý' žÔ-ñC3OÚ ¥óvËHÓR´šïWPäÑöØ4/) ×s…­›º|vÔÉSª6(¨ú «_Åá g æðU´ë94Åá{Gqøû€Ú‹¾z›®m@*{lZ]÷^e3*;E»^DCå Ðméæ Je‚˛ΆqÑþªì¡Tá‘¢nòÁf4ÀŠu=‡¦h€àœsCÑodЕ'G«G­Ü·èS‰™öGÕíÌÿQl|4\Sxt¡¨š½Ï– äÞKeȵÎ(5!n¸0Iºõk’¬X ¹ ŸH By4Ô€­µŠh¨!ãrÞÊ5®…­ ¨9 Mê’jëöY³cè;ÎŽƒ× è_'ß¾f?SE ³‘9뢴hm7Ût£O¶yT°:œ'@ˆ¾ûB«.ÂëW‘îÉ^‰h]k^ý™rMd¨Ž Ö0Á½[4åSÄ^T=báåj#4Éê…¶ˆˆ|‰î%S†Ð—´$¹/f†²Çø¬l^h]j©f)Í>x´YŠvÍRô-\§š¥i–"ÚHG]Gšªf)€;$ÕEWµJø¯ºV *žCS­ã¨V G>%ge·JÐGCñ3@™¢C{$Š‚2À¡º,À8ƒíi®îý`ÃJùA4^Z&%8!¨¿÷ Ú&£6HÌ Ç¨­Zq¢)Fí#8ŠQ»á0£¶ð×år½M†S0jëcMø$)˜ 㱘qÙ7³Á€IµÔ¦ëDõáh‰†š96 bMY Gq”ÕÐ`Êjþ:½Õ°;— ¹–éÂm8 Z¦tïÐÅÊÿêZ¦ïÚw<ìµïPq@ކiXš~ü3]Ó÷–œ:04SªÈK¸¡”:ëCaH†?Õ4¢xȸë¯x# ¥8ª^`™£oN/l—¤NU …•㪌O¡ÊFX}oŸ»;”KÝMõÀ˜ÿÉ2xˈÊö *·/·—.dÉö…&÷z ³,í3h=Ë0´j˜> m*ÐÓ¨«ò1˜2Ki¦{ZмëÞ=6yV¾wÏÇõbQ}¸ÜÌ’Á3aGëµ7s¯½‰òb× ©^>‡qT/ŸfÃè»ûn}O`=«úÀ–'5S~ìƒxçæÇ†í/Ã8ÈÛíHÜŽØ_$õÍ4ó½Xæ~ÄOýïÎÂ?xpèûRÍT>äòK%UØCA‡"XÉ\§,ÉÐJfÖÞÕÂ÷\ÙüÞ ¦ë¼^ƒ9—%ÖÒph‰Ýz°–r˜ $JšàêF“‰ìziEqг`:#¥^l} ì’×\dÖu«T±ømÐ0Ã@š´×÷-s,ºèªQ*DþÔ§ØéÖ:%݇ÑÒ <òÁM\Á¯"<𠱇3sˆ—œ[\7U¸¦Ÿ;U8UžCS àãœß§jW’Åz1Éñ%mÞº^Üô´¯¢}‹ýÞ |ü'€ Ä_ ªÝÒ }¯Ý”ê˜CSí¦Žà¨vSÇ>u®¡8SÊÖ5Ã3ÞÎf­.T‹À"¦Î6 ynj¥³Áå«Ì3¤Ýê“ÎoÄ­zV¡ô¬R¤¨šêYu’žU†>–*eT=«ªzV)vMõ¬:ŒsF>lÕ³j+E7TÏ*ÝYèY¥«žU5hªgÕaÕ³êØ§$u(8©Ž1+Jî³Ü+EdúX¯‹UGÔ”$~šÅSþ缾 “>_—7z.V;ªRÄj¬ùfU;“mkÉVn\†(Æq_—÷R»S$Â'm Ž*ù<ö)‘ó¸ÀkdˆUƒ•L4fÚfCá”v¹¶Gˆ‹Äb :¥F•{/ES‹ã¨ÎEG>ÕZaZ£±”ÊnÚ@oŽ5ñ;­j{ÄC1XmDCª€mv­HE>…Q#;ÖÅ ôÖåÈ4ÅŽàž­K ¦õ¡ù,HB€šqÀ:¯ÀRž<ÕSc¿§†êÄ%ˆ¦zjÁQ=5£ïN@ÕS£G9¦Ž}JÆFè©aŒM¹žÚØ#%í›Õ ÛYcc5üBT'®¶h¸=74Õ¿³ˆ¦¬†£8Êjh0 e5ÞjØKVƒuÚN\(-µÄì–:ÞÇMG-ý$¿†áÓg?NTùHІÊM®AËœiä?»I‹§|ˆe46¥",¹… §Lm8”QÂÝ·ÛhÁ„ ’+%ØÚ8½èûþ*"súO¾»PWކ¨*LÍè.½ª÷7€…ïxt‚Îø [ó´al¡Î_ûi?å­¨guCJÏvÝ4fceeMcÆ«uò1 —çÕ9ÚþR¹XªÑT›˜Ã8*7»Ù0à,Bõw5h»ù¾ŸCW©+÷J-—™íÿ‹8/‘ŸÀ&ÁYC• ]D{ë-Àí­ýi¡™#a ±+ -°žo\³|šûÑ%uâÙ>ä2ó‰Z¶àŒG•ÏË:òeHÓ`ZAýù²)yôJ]¾TG¥&Ÿ<ÖQI2u¸MG¥Þ¤ ›’¬`ªSÓ>L’«¬\–Ù¨»Š Õ½©Á¥º7)>» Muoê+ý¥©ÅoQùú[³A/ý +¶l4÷Ê M¼ñT9”èrQ‡NÃu¦ZnÐ0]·Ï ý¥·‡¡I6ªçM“O6ëytïâ?iw÷\Vr˜#[й}Ëj ¼ªX_(c‡aA0ðZÆXêÎ96-±„­,«Y>Œ ·]è+ï®>Pt¹(¦á:S]6h˜6Œ¡ÛÒ„7o؆15©ÃFѽ7ø`3ºw û8§{ïÚ„1 aET:“Þ¢Û|’ÚP¤„§‡ÐRBïСQw54oËWÐZ½³ãžmHÀ[ƒÙ¢G!8Ù3ÈEє̠ß³þš$«+×{$·á ¤©A hïÚ’:Qm]ˆo®o,0ºâÐuö~ X`vP€ïydKíéÎ[5ÀбìZ5Dt|¼Uƒ>àÿâ°¦÷n0_U˜]¦š4ÆÁšmFÀjUrVø®f[Uf ºk€.Õ3 Ó¬g×@ªªSõ (™¦¥žºêpMõ 8‚£z4†ê öu¹$dªgÀõ®g€5’K‘Œ´ŽR$ í } Cל»AËúDvHpf¥­;ë8¬½«½%“­.€ÐÛf-I»JØQ„Þ{„Þ’±ó¶„Þ}Z5ãÇgÝŒ¦VMצë(²°CBAYWÆÅ‚dëÔŪvÑuhŠ"ö0Žj_Ü`*!ü¥(bùá%YB*Ì2‰GiÝã ìq†ohü>‡~0¥OþFs~¤©ˆB††x†™šÑZíû¶`KRbe¬é^e›¿w3~â£LŠ|¯ZŸžh¦!•Ö97*ˆë§!7ªº”U£)¶ÔÃ8x¶—ä¦{¢©{™.X›WG%Ûu¸×fLT¢Ç"-Hã)CËóµ²Á]ÿìæy mS8UD±Ï–gŸ• Þö€}Ö6‡RA aîOx’ Ú¥Fü¬#ÿNQp4ÌQÍІçe!XÚ@ÊDÈ×™ÍÍ¡8ëŠ"wÅ%wÕ¹ëM‘»Æ9‚õóp‚ž”ÜÕ6å˜ó¹ë1r×nYÛáŠ%GO¤¸ðŽqá] °méÝ%ä*½lÅ §X€34Å ×W=ªyƒ^ÃÏ!3è=}`г-ÉH¿fXgG.}"ˇ±p²wíŲ ñNX@–ø*S¦OÃå©Èƒ7h˜¦i˜Ò +oÙô‘ É*š×&lFóª+š×MѼÁ9¯¹¢yÍdP-kIiYEóZAó*[0^¤yíü²hI¯)rØ}rX€"Ç(¶:š.•.Õ=¥,L¶Ô†Rvä-˜(NY!4Å){S¸^@1Ê–ÑTÁXÁÀF±ÂÙ¾ÍVDo(Do’öMŽè­kóF½sÁE¦VbyT1Û¬¾ .ŠÜšŠXìu+bÌÿ¼¢Œ†T.†Ótë­†Õ£•nŒFÝä—ݯ•\¹Bü-yUa%­åYb&‘®ïܹ³Žã¹‹…¬ÊØlë¿îZá#ñ3Iqÿqg÷ŸdÔÿì¹ÿŒo¾«õ¨¸ÿÊÜ’Z²%÷_ŸVc‡écCìôëÙr¼¬Ô.Ç_å©ë<—d§Ú~PQ‚xª·T”VÊœ¶ñlªŒ‘­ç´“§õéŒÆ9ßf‰ºv„9ŠªÞÑô2™#Ð7w¡âóZ?œ’è>Œ–nà‘/nôD"Ádyùí´ûA7?ôÞ/8ÏMÉ:¾V;_`ãïÙ’å%ç±âVž µ&ß¿.Y8FNÉÐO5”œÕ”œêdçh¨í½¨…x^Gû@ìï±ÏÞ€JW8°åJcº¦+ƒÒêÖÒ}"WábA¼zÖBµÏßa[ðŠ£°„6'÷îz‘¯?ÕsÔöžôð´zZŽT¶¨5 µ³!®ñXõ›ÙÖÝ‹lï‘xO¹ü-ÉŒ.i†½7 £UâŒÜ/-YÐ-.uMæL„º¦IÒ%ÅŠë.gŒ/qLäYùÁƒºƒ¥h˜w°±6:3=Îî$wK—ä®ÈñÚuÎ9‰ƒ5âÇñKp(‚Ì Mdæ··a¸Xèê:Ó`¾=O-‘ái;¦Ý2ךbØ-¢a*]·ÏÌGÛ-Ã. &K16*"¾cD|ÂØ8HúüqÑ1â¢n)»6IFgDŠî¨Ñ[Ñ)¦Ç MÑõ•îh0£;RDD²Õ½"â +DÊß®ˆ8ö‰8HOˆ8††)EÓÒ9Lê-Ç8\‘`îG«Uu* k¢ø8ªÑÇaÕijÙ0úÎÉ±Ž„Ê„kðzÒ\Øz¬ÁQyÇ>ÕÖ[›äH˜Û# .œ;4R×…q:òZ@fˆcÞT+5&^=²b uW†ê^ƒ†šm?ªdE´·®ˆ+)†6ÛRŸŽ¤Z+(N©:N)É«z8¥†Âõ"}Pw(R)¶Ý}1?iÛ†,U¬Ac&ßa P•—ÁGCx_V‹…Š€ “€JR¿\ ÕÐ6Åó;áb þH®Ês'üÚ–¸9¥Òåˆ@ø#™Ò’ð§?ËqØ"?D†™b@0פnq”ìxSõ}E¢äŠƒw®÷ô‡­'Óþôù†‡bô‰czN²Àû„»G,ö+W™ÓOÒ}[á4™ÌtG9NÞá:NLÍèÎÝw¿‰—­fXçÉÀRœéE´\|&&ÑÜM\ЗŸïÓF äª?kõ1 Ëk(š“[ ERØ¡üÞë«{ç;÷aä±Ä¥vn [ä Ý?BuÍqÒq<ëºídƒqÖÁ‹ÌEýÓÈváLÌòz)Bd­î°¾ú%Òê–ÆÐ@"QbÄ0*HU¦¨bã¨L˜fÃ軥õ6c‚€ÝiJ<:]g“‡#©*ý³åæ<;sܬòvJß±*IÑ3 ºÈÖà%ldJå 5Áî=(‘¯=ÓYÛklíjúYvü*L!< ø¨E<¦Wœ ì/eÎÅúRBS¤ =b}Ô¶”ŸE˜µá¼ø[RæÅßRDÃT†nŸ™oÿBø[†£¡TpEËq”–£[—έΑTÚ=iºªQéòv3aÖ(.Å+ƒUÎj*ƒ£ážf#CÅ h»é#ÿ6£Y£3 ~¯QëlgBú’FRTÂT$à'²%fU5¤qgJ÷íÐuߨ´¥ÝÁ«úVBk»®@Ûtn¡:ª«ëËöë¨#—Úvÿ ©3ÇRW ar‚¦:O°£[î|žõ£OsN»23” åhˆ*t¨YÊz,¢ífûž-ÅËaþè{rɳ»X ù¨ja§û´g–\oQ‰ÂZ#Û’Jéœ4Ì‚q½mIÃ":¾Œ4Lðsè_G7˜/ÈÔbõñ*U²M‘†ÆÁšmº>ó$K‘:Ëòh»Ù«\¬Ë3ÕŒ»[ÙŠ1LøëÔYf‚} KfÃö4ƒ´†R¡ÅVr1–øÂtUŠQƒ¦øÂŽà(5|ìSª‹/ld¤ü†Â|aˆœ_0î9Íg{*‹r‡†yÁŸ[þý@LÞ+wÅå”pÛx4P<5=â©‘L—:wžšÑXT…[´Š8õ *òùaä…«ï‚K©mõWÝ:ó?¯è@$©·8"ðåðcM—òñ sA•ÂQIê—O5\Gµ\GÊbáh¨W6}pnuúP°<µªð—Ëe¬‰–tòl5‘â®¶?m¦ì)‰îÃhéùà&®`àwc­éKnòŽå(ÿ;æGISÙð£ð˜^ )ŠŠ÷@SÔ(‡q5J³a¨ˆŸè—ŠøÆ;7W3 ¯;° ­Á‘T»í³e‘‹Pb‘ÑuFõ‘18¨{aЦ¨dò[ž'3Ê] 7 pëë†â“iø¹SñÉH’¯KóÉôƽ=Ö-©s©{æ Tš”yB±Ð”ÐõÄ%²ÐŒÙÌËx³„¹'΋†&åP44E4L]`¦´÷ê´º [šÎ‰©Š\…\DWö;4E.rG‘‹ÿÀ}–\d¬ËD˜uK¹aËèZ€°eK5›v "Ó£Yâ&ìU^ F¤¥u+jÝêЊ5¿Ñ [².¹Õ6ØååM¾YpÙº\v0yDÌ„s(ˬD:¤›ÔºÎRá~‹|uKÑ0³t–ÇÔûÓ:3m[Ö™³[b g½”o¦¤8LŸÌ)Î Þæ—!Éc˜Òâ¨ýwc+Nœ=´Ýl/ùBT,-2É¥] ¨H%;çi±A:£oyZtÍ[„1©gjQ9›•hŠ£å0G‹bhÙÃQ9„Ç>ÕQáNµ`c]*cC¸Ì*“Œ/D¶ÈõÓ~yü˜^Ûf||Ê+¢azŒá¹5²RìAÛÕ¦ Í== Îc,ä ª/ckÀë‘ÛøbCÞÛö³dÌä;l‚Uíå÷¹Åé´™*°¹&UŒXX ’íY*;3µxSçù9|ðƒ)}ò—0šo >'Óþôù†¬é3Ç~0þäfÏlÇß¿ûLfº ©s4ÄóÁÔŒî€û~ÿñ²µ í^êîÆÙ÷[Ð:&ÑœU Cθuf9®Òî¼jÐ(²ôÌØu=¶r nê±GÞ#ñžâõ²º&›r*V²AS%؇qT v³aôý0KUÂ6H¿Tv-?áOÅjYzÖá@¶Fd<©ÙQi+{P.¢"{$6êCÙ¬æ×0N”Ï4ESÅØÀÅØlqAîx¹-ª»É'Å ±š1Ÿ}!6]œC©¼”_¢Vb§Å—ª»„¦ª/{T‰Ý¹ ‹]H½€dJ\M½€¡±õÀþ:¿aYÄc ”æIÑTÙpÙÀÞJ´|mMª0»Õ0=1 ÕfLRo8IHOnªÜäj·¿ÃÝíª–`­äç«Ø8<³LLéänŸêÕh*f±ÛP$»* Ë{}uï|ç>Œ!L7â7h³.èö+/ŽE|3 éQ¼ó3«3˜£å‰”#âÂñ ËÐmu Ðvî¬a3ÜØmᬎßtyHœÀáŠD.=ºþã?àŽ_ÝÊuü뺖oR½­å³—OôòX“íóiÿCóU£©b¾Ã8*û§Ù0úžý³Ž½ËCéQæ«m7Ù‘ÿðÛð˜ÝyJ„ˆ58ªXõاÚÚh’ŪÜx€4ÎÆr¹ØÓÞ¦´©ÜÞÞPŸ;4ÕÑþÎù|Z†}~Ÿ¥žö"H9ß!œîe e.Æ¢ˆÅþ0Ú3_ëokýùm8ýþ*œ‹ý¡®Ä óJ<–Oeí‘B…½5¬„l¸¸|á™1-HÇù ‰ô¡\bæù7ýŠõ5númj‡‹óUžGS¿‹qˆ¡ Ó¼®ó7r)²>2κÙIæ+EVá‰j4Uœ|G…'š £ïá Uœ\ƒó抓U”â ÞŽRl Á;÷±Ì·Y?Sl³©ŸºÉ£ºê¥hª~º™7]\Wº±ÔŽnoxõã²ú¢ª»á±æ[‡û±‰à TmÒ‹¾‰gj³L˜ M¡6Ë"¯Ä['$ûûD9ªÑTeÖaeÉûTG–|qÃÓ†.z ,Á YåP5YÜ0÷ÂÕwѶ˜9ö ‘S NùŸWt ’ Ù[ ø‚(CŽ%} Ä}Ù"•­† !¯¢ÇrnA5"¯uà_¥ÃPíNßÁŸµ?¼&‰;u»Óla@u;5 Kf«2ˆ³TÛ6DWbÝž’è>Œ–nà‘nâ~Ð¥´w îÛ¢»Zu¬nüÁ£«ׄRáMðTÇê<Q‚E‰”‡®÷wÎÒ’#C(¦J°Äþ¯3gcx¥¤4¢Uðjó6ƒ̃hëért`M´9˺9–µrÛÎ2LîÖ,Cf‚ò œú(Ê”ÜI4Ôå* º¦‰ùÖŽQ ÖÁž깔{½MQÆQ¹w͆Ñ÷Ü;E P£bGÇ>ÕQì(=ÍcFCC*¯ƒ‘X*·ƒ´*:ÍÝ]ņ]ÕUu;A¯cEDP²€VäcÂÁ¦&«H؇­(xµË”º¢<Ø¡)ʃ#8Šòàø§$”uÏ(¨î•*Ó¦<€JÇSºº¤ÇàSUÂIè7_â•¢¢a–âCû̪qR´ÓågÉ›Æ@ªîV¸\±îÆŠ*:û ÖóàýKü~ÐwáÿËeÚûùžzg†²®8šjoÙšxIœ'"’8X›Ó­ÃQ‡e }÷ý¹žGâ~ÒÇÖèÜÚÔʲÏTiVÀÃÍ”‹juM*a‰­G2%tc‘{’x,‰e²X~9#wþìÇÄITøŠ£)êˆÃ8hN‚û{ª €çÛPá«"ZÎnðÿEœˆj+Ð)·ä»$õ(†KTG-¬Y<6FoÉXÈŸ] ‚”ì\Y Æ0u,ÏR×Hò[L"nU(¿GSÔÀ~¯ÍƒÜú#©Ë¢'hðÁfô’qðÖô½iEmšã³o8kIfFT’ÐKAöýÏáü;÷¹ªæî£h öÐv³}G—aïÿÎÉŽ/îh¸ãÜÒ¥j%{ËÂ7ˆ1Äê†ã¬Öqæëåò»ªjÄ,ŒÒ¥ù3ÑKIÚöÿÒ%ÔÆbj¯<ö[ï–1Xé‹eÈ1Ow^ú2´+f´<ØSU¾T£©Ê—Ã8ªò¥Ù0ú:P•/8ªò娧:ª|á‡à-Ãc1V…/¼ðEŒ,íâ _,FU#crö§ßœ`—û†ýæ²$jåîÛ ©ör‡q°f{ÃÖ®¼Aotƺ5J)Ïóo0'LmØ`Î06ù˜ÅDwÒçhª±\^- tKJ1T¯5@-12Î:õ×qêmS-6ߋŠY-|ÏëÚÊ%öœý䚪e¿;™¹×3Û™(Bù4•2|Gùýš £ï~¿g"ÏmWH`ÕõQw«[9þ„¿Nla°”(IcwàA¦ð9tÃ’þ¿|ưõšzÌÿ¶&‘XJ‚2%š¾õ¬áü"ƒTc©Œ•9ÜàƒÍ2‡% çŸ9lµ¡ÌZìCæ°-YŒÒ$sxúéY¬ª:dšªÌáh¹Ìáõý=5êum`©ûjm7ß 8lÎûVázfá”dm{8âí:çÒjŸt<çÒ W$¨O¹ô•ïµMå\ÆQ¾×fÃèûY¦r.+p°˜îîðÚ6º£‡®+­ÁQŽîcŸjk¢£±`´·d¥1ãÔ6“òn‰§¸x¸¥³[ÅrûÞí|z«õòè&ʧ¢a†ÇGãtñ´{]ˆ‘”–v:[XgšólÇ'&ûóšÃrý‹¥5äúÿ ÖoºïìäöH“óô(Aæ}çîþºžfÕÎêN_£3ÇüÏ+:‹&×xf:ÿr©*ZŒFxyˆ&K‹Ñr4=ï‡ëȓמ°ÍlÛNu¿›Ï©%箨[ Û‹ù†ñ¤‚:RsóÍZ­ˆ0A^è]5Ćñ£b­mÂN0ȉ–w£¢óÑ 1ëŒNÈ‹ ¼]ÄA$ÓаÊf ò*zÛÍ{Q…8Ôêj–®Òa\‰±‚*“¬^¾¸H“Õ¥Ø;¼´O³…¶UÚHb« ÖÃnU™Zâ|ê¥&¤7›µÌºóEªÛ²!Ö©7nayÀm_aÞ¾B¾P ´ƒC¨W]í¾³§$º£¥x䃛¸ƒõjî&$õtèÃÜ¿~q£'¢\¨.s,™Àt¡.ôºmiú›¹˜¤ÛNaššTébz}`ЉJ (Cw>¿"Qâßû¬J*ëL—|ged*жESÍ>ãàeÝ&"ìâu€o7Îv`{ÃÅݦŒYª[ši(O;Ó²´3Ÿã ”ïW[ 1KÜ„cêæ}.y]ûU¼ËÆP¶+¢/Ȱe¯”—i»Æò=) ¶«)*:Ûµ°‡MØÁÛdßÍOÞ±oŒH¢X7rhŠu˜u˜nc`‰Æ^%ˆü ÝômŒ±\0M„áà•>¹a¤~Y%— ¥Ì*Ì›,ß…šUòLrEÇkWI!ýNx‚¨…Mt:qÜ)S~pÖ§eKÕ°ô‚lÆszlÇ_(®ަ¸vã •pÏ/¦~»ïÔáý=ÝýÀ%Ü£ "'g5R„Fío§X„FCÓ’² :'4Ò%LeB£ˆŽo2ñŸ:÷óéóRqU£)£Ã8X³ l#¤,ÊJÈ£¡’ZÊH(¢åÜ+á:€5ɆÝñL*#á¯S -1’ƒrNj+@šbCÑ E4ÒœhD¬*‰hDäc\6CstÚþPQh°Åeµ +К<ähMTlš£a²gCûÌšÎĦáy6†£¡°‰raý(%Ošš~”£…'µéØJAp4Õ•²Ð3J×u©®Q‡– Ê —®]D›.höJcSe>ãæŒR)šÊc+Ø ‚”®û¦BººàvýHÓ¤v}²„Ú¶êù¸˜>O½åd9Óµµß©<‚£8hWQøìÏ×cÓVŠh½Žo_l˜`=w·g1•LÀ#‰R=ý:O&0A¬„m2½ÚÏ&X¨t‚j4•NpG¥4Gß­•NP…£Ò  ¢ïéù´ÆÀèîÂ!(­ÁQéÇ>ÕUúÆ 6c4fPUùÍó7$;¦_DþÆXÓ„ÏÜž¶—1ÅúI5i/£Ñóg½JïTÓéLsó¿l¥ñ«pN,öÇdf)ÿ,Gë÷qr±w®~vžéÑ­ ¶ªŽ®m¶ía'| î]E´Â|‰z·¾ÏÌE›eb(ô ó=h«Ã’KLîýæP,Ý~“WaÙ–·þ’„ëd2%ô»xE„H#Þ‚­¡Ø7«pð¼`Aà$é¢võJ;zÏL%ïmr8ïÁØ6¥²qÏ6µN¡‹:œZgS­ì.ᱦîw­ï©u«t×B‘ä8H £“7 ·‡RÃùVT¯MJ½ö!‡q(™„\•ÃhÜ‘?Èþ6Q¹ Õh*ñ0Î[rJžXb)I%-šßÝ`ÊÔÔ„›Ü÷§Có¢Õß®C³aÐkA®_Ñ•»XܹÞÓdúñ9ífTîu4™> Æ}i#<Õ´¹,ç ÈV'èd´®ÚGõœÅ$K0Óë|8ø«u*ª©2ç—êŸY×?S5¾E=ÖTÿL.ÃÔlÑ÷.Ñ?³•›¼ë¦P'€Zž‚²)ªkî]]³ÈŘ}· ‡q2y%Þd2| ÉíwA;B]×áåïÙžß§½GQúVÐ$³%%‚ l4Øü¢uµ?¼O)Þ}w!ìX)¤0‰M^{¢p•c™>µG•¦ù`ˆi˜Ò’ª@»¢êº~ÚìÞõê¬&jÚ«C{¨*ÝVVަztK1l±RÕý#¯~˜jˆ±T#ßó­†Q ¬~˜üSÕïÐTíð´Úa¡X÷–k‡Ã‰\j¬þçêWCŽÛ¼Ä#ö›|ñ˜qhþ¼YÅ›§Z¥× ©úáÃ8g”g™Ý%iõ=qé¾:±ÿ/X¢=Õ¥Œ¦"¹Æ‰B9B•¼ùéh(˜šT6¡›•AÑ@䥥e!Û]m–Œïܹã.è«mÔ½:Óà°n ä\}ƒ&æ§€Z?…¸Kzæ¶µOÇ’WùY¢Ûwnì{Îv(×/ô‡º÷èFN¹~_¿L&òK¬ C aŦ&×Õ½ëâ([¤"óxqÔˆûÿN¼By»™˜ô¯×ßè¿\+ÆÐYøÙ·5û™ºÃÔ ©ªÃ8ª†ªÁ8ú~ƒñ™^pžÅ({kP‹|4Ý•šôý®”I§–¸­ê© h¥â5ð9ïò®®*ª„¿Î뮾±êà®ê†iK‘‚^Bâ¿XZHÓÄËcmvTGSyÿy-À§È$ï 6ré‘gÇ`ýÓeîéýIûŒe6Iû·VQ¸rÜ„äRÿgºJÆàh;—IM‰‹½‡‹9ô|ôôuð´J[®à¢¸³»/º0†cá]ÞÓ†F#NøbV¬>ŽIò'Ѩ~FµhªŸÑa4…¼ŠU;#y¥\±ÅoÖ#[ªÂU8<­XPÃ×(V–U¬$öÜ™%‘<° c!eñhœ´g×-ÒÖl¹v9¹%ÖKðž[ÌÈ^ ×®Pl ZcíXŽ ŠF ‚w_Íèú×0`(Ü»¹*`“V,0jR©Ûd…êX9…ÒF4W&?L£0!^Bæ¢ ±¤Fr‹©áã6ÐÚ@ÆèCâü$A¥.qþf– ž Sa×Þ̽ö&* ¥M%ÒÆ9£Dz}`Ýyûžˆ¢RékpTxþا.'•Þ[*•þð§Òko;•ÞÔmáƒU¥Ò‹¥ÒK/±^¥ÒÓ#§qFúHÌqxÑ+Æ+¯ïâŠ/ÌñP.©£ëâ‹¡˜†;V|aW5¦Q×Ùj4USqGÕT4G߯²‚JºO5¥9€¦šÒÄQ>ƒcŸjë3m’Ü#ÅÒL)cìúÅÆß8¡ÿåÑU¼ˆšJè$òg ëLýKô]I…6{”Ð/ëvÜOè·âw5¹QtŠæ]o¬ØKhxFšnÆg¦¡%Eé>4Ñ,™æí†-ä^•H«P¶¯¶6ö"òr[ˆu½NÉZÐ\Ñ ñÝ…XÖ—jŒÐ /g’¾7F(íØâú#¡·,¹>içOB?B!¡×Çå6ê®ÅÑ=0=^чekRt Ý}˜’msEÖ:Pe•hªì®ì£¸Èº/ü°l9Šƒ${|²·®³ì¸yXR“L¥×£©üîÃ8g”ß­ˆÒËh*»û(ι8Ï/R Ý_€†&—Ÿ+œß àQHí–$Mú”ÏíVÙf@v8´ÏÍIðv²Ñxl!ûc ÔK6¸à…AB^E/.yí"rm©»µ ¯Òa\ÂðT\¡^.k”~rq…–£ºŽ`M´<'qÞ*¶dcã§ŽÞd[.l3’k¡jZŽ×´\V”­‹Þçòëe,ä@kg’WŸ«ï‡§\`~׳§$º£¥x䃛¸ºî>?ÜFnß“HEé1OSKÓF=×ó…ÄéïÏžÂÈ-+°s¶DœŒç±.ô@€Æó½¿ mýÌn¦~ô9“²›9¦ÝlÉæã\¦ÝF¾P°/§RmYò©Mçl©D{$•Ñ` M³Š05&[ÎcIVáYSåÝæ)0ìa{,—çßu÷$¯eW㽈 yÊÕx/|ЮFSÞ‡qT…wƒqô=œÞßǘŒ›Ý.'š-ù«AË-î…ûœ kHǸZ϶ªòþ:u•·˜³bϘãæ\Ú€=H‘Ë‹Wyã•kë0u—¥jmÝHœ)¦Œ³j4ÔڂѰ;•ÚwëL©T¹’ÌüîÕ«—ÒŸnÓ)§2 cÛÅj‘{ÿ•Ì‹}êTÇMõª;†óÆzÕ]ìÅwÅ5Á¯aê XЪÝW2ÙCÑÍþÃû(ñï}•\‹F4 UÒbÉöƒâùKèböè{ 70„ÎÿÚSwük>m*¤Ã8™¼O0žP^eˆ"hÂ1…ËK´”>¿FLm,²éÀ_´>qhÕ½h‹½•kv5åßODØë™L†$¹¥zQåÍ æÍØã¾çGæKÓŽûõïlIu¼÷G¢v ÔÑ2ª®íÓÑ¢EvQíÑR¡h>Òç8YR@°ìƒ&Ì•Ô×6Å‚ÅgÍÚ›FL·3Kƒ£$ArCæ>]hÌ:[¯Vô5MîÔü®£óÂZ ¹ãkÐv³íV$¬wÙJþÓ%ñØ>‡ótM4 ¶g6H?Îa3¸Âå YÐëõ3™ºÉcšÜª<´ÝN§/ V­Úæ›ôÝÍ‘[oÜï&¬jJJµ¼¹»÷¹ ô°Ç·oìA:<{Ј‘/܆ç•fYƒ¦xƒã e¢Á¦Yv™†Ö÷X“Ê™ °aZî²0ÔåØîÞpyHÁtOÊC†úPÊlé¼u1áÑ@²ýqÇ~o¦ÓÏÖï=¼wçÏ~Áó½XRa”þØI”}ÀÑ”Ûû0Žr{7Gß-N$Û–d¸½`ó`A`3¬»4Åà ‘`ïì8ó`-_slH¯íÓZc’¹—©Ii‹‰rüCÕ”Mqº÷ž•‰UÃÕ¹‡†Œrö:¸¯ƒ„D÷®§X ·`ˆ]ÙG¶lÝjËÑôœz%_”?Çfß˃Kªuo7ŠìÂ\+«†:ª™Çš~Úx;ZàÜÐ@J‹JqsUqþ“èýkޫЋ6hªhó0Z)]‹ŽËã/0’®ÙÜîj8;w¬›RŒü}Kš0Åð{aI&B5¯GSqÉÃ8ª¹x£QôÝ󨚋×à¨Ðä±Oušäç#œ™`ˆZ …+—-Ôð¶ð«­½HÊ­ÑÑL·þ ¹¢¡ö›ï.® ø”?« ^Á.ÛÕìÄŽ–âúc½›ÂžìÜÖ ]Z [xË´ Aôïó?¯è@”z†·guCS>èžz,ií£«Æ–ùßý ÓÝ §MmÑ­B§”.R›­Nyt‰Î®u˜µc§öÒ§ ³³«&™r|¡úT„¬º,§N­Ñ™…ô²-§‡¢ûj_;¹ëäQÂØƒ J7¬’¼‰ßÓ¡„‘ÿ/—Uý}ôÉbΣh3µ%‘ÃdÌV,dº;”¾ÛmCz¶ùÁÃm8óä³Í@CCª÷V©Yå<‘ï2ß0Îc¬ùv=Äq§ûÀÉ;3mÍ2z÷ë±+u2àé%ê—H'5ée2QòuܚРj–‡¢&0D'§tÞÉ¥t| Â*]وݩ­üÂn„Ó–‚Uì]© $¼IhÊ ¢ ö"5ä×ÁVE ÈΩU‘.¿ûZU׿†s^¹w ".’V¤0zrwkÑüý]“Ó¡möuómýÃ4 â%d.ºKê ·˜>î1]`iš&•Šk†`N_§/Åש öeÝ'ìôû¯Õv¶y xÂNºl©uÐ}á²X;öc…ËúÈgÉò»p æ~´ZM¦ŸXaÑF¦?ô¸kiè¨$Ãj4UÜ|­+Œ]ïä©§.6Ë0öB¡>zuˆùé–îit±)†wá\Þ%]Ðz¶á œ¡›ù,.g²E³©êpTöì±O Ù?„ÔЄ^FÙ*ß7ûÀRp©‘-“y2âæiÇ1 Á7 ênh…í)‰îÃhéùà&®nÌýû{ÎñzO"•…‹Ú ™m¨~{Mó Àˆ¸ìö¶~]A9\-ù§$.×gÏ/nÈz[ªùÅuÆ/¾«“VÌÃMq‰C×BgPUì¾f—jÑ–ª…Ô±.¤ãÖ÷þ‚H˜e8Cú'c´Pé§0ÌôSK¶ç2£Óaä?€ZYö¹Å¦³]g$ÙÚùÓ€! 4º>÷cÏæ?‡óïb¨FS<‡q”§êاÚÚ—rŒ0¹½ h\J8™ÚHÈJë{!k– ©ý†O·‘ë',Ry—0½KöHR»žÚîÙ­ 8ÓGp¿þÀ| Ò uqâ&븕ՓO¼ X]õ;nÆsÎÉgCg™â¬„þÞ÷x²¸¨¥SYµóÓO;Py]o‰hÆòº©|(¸ßÝÅzë†Kÿ“‚qä,!Fû¬1øCfQ©f1=rͬù1ûnã× ãdòJ¼ÉäƒàÁS¡¥àôÓPÔ…Z%†˜Ç¨G«DÌå]««‡`§ðª¥QBAN><¾¼FÂÕ;PJHŒîºGËK‹˜uµËk”_ á«KÕèÀêJ»]\ºiIuè|Ë Îbz¦ß Îú@´ìE2‹LéÑTŽ¥ê1IX¡Bè…‹ ³Kìí6N8Úþ«ò9¾Ãõ9^5l¯•[† ÓmÙÖH2Ìu^nÇÜV‡s;êñT–K8–ä¡YÀÑH0ϾWñ›4¿9Œ£â7Ç>Õ:aØ"æ+kÒÝÞT¤Âz´dŒÅÙ,¤î³ìõûÁ½È™œ¿¨Ør1›O³dÌFà°!è–C/Î*äiÜÎJoP¹+ ­ï,”…­neXlŠ+«[¯†1Iy5. £X2Õ¦&£XÈÝ‚UB1GS Å…„â¡ØÎÙÏ'†¿z™ÚH¸8¶wW/¯Váê5`ÌcAüB"Η©j6h=¿oø 01 *Ùíòk p[³Ë‰LìÂhbÊ *vA^=²bY-µÁH²­â,ÑÍ;wîlÇ!OÖ’ÊõÏì8bŽTCä†('hˆ¬ªW20Õ¹æLšQ¨†È2#ýÁ²ŒÁi „ñîå:L'Ïҵ܎Iò…$îž¾„sÂÔFþ'Å¿©° GS!êÃ8X!ê¥PŽq-`¾×äh$ÝÞóÌ"Ôùý w§²LCŽðr80Å.'PwªP*l,›ÆoT,¡+Çõ ý‘î=º‘“ðrˆë—Ɇ³Í“"Ü—,s uýöª8Ùœq¶äýûS•7ÎÜzJfþ¿ˆrÅ¥hˆg´5gvjH¶Í-¬0ÈCc,wh(GÜÖ'T|þŽ8Ë®§Qý\+ú¹*Z¦ú¹Ö܉ Mõsm7FÖ»Q¦±½h?Wøž¬bêüHOVw¦tb ¦z²Ö螬õj›\hŽ…J•Kj1\‘È¥&Ú‚©E[Žöªžx zâ)£3S=ñêaTO¼#j¯)QzâY¶)£-Ï’š]H¿7§f$aâ.6Ú™« EÏEÏ^^[pûß&!¹°‚ ¡kpó‚ û¡”¹¡Â>MU˜Õx~ƒ\à'_À¶Âí‚T¾@ã|Š™žä Øöøì«pl±S¬QÎÈ[7Ru8hª,cl‘C”RY2þ`J‡þe{öìÅþ­—GWmý 3ïg¤™ÒmZO»÷%kðØÂ:Ód[¸’_±µÿW[» w¥r65ÁSlíyt„{w)ÎìÓpfËS×vKëb;ªÐ5µ±.¾à¥UA‰Ü/6v{<»ŒŒ Á–ˆP©DaEµU[•OJc>Ž9%@Št¦–ç@uW)ÞuDÞu8Vÿ>ð®4™§–62uàڇݡ2L_Güg’Žu2>ä–êueÁ¼²ØCK6—è”ñqKëx²cKªã­¯wÔ.Æ´GBÚ¹O犘¾«å™ÙÓ3–kÌŒ …Oˆ¾r^’Er5Ííc’|"dõ~A'r§¼æïp½æÆh!_Ÿ”Ÿí'º—­Dç~áÊ·¾ÎOüX³%SØÎ+R™ß×p1ÊÁÈ8û샌"-dXÔ&ʾ¿Rùg[4•y× ¸Âà¶ôP—ì]¦<}©§€sà¬=}t!ɹŒÇû,’.H'R±Fìí{nœ@ø‹ÎÙ®!™ ™óëJ"YSèJbóÞ÷ëÀciPª-É;T—ßlK²[Zݺþ†£‘QÒù—ѲY“5Π‡¼3HÝa8šª¡‘Ð#U··ÄplIiKšÝ˜ž]÷_ÞÐøè„›=éÑ<Ò4©ûîn ¦?7#Ü´·tˆYÌùæÓ,¾™ iJuz4&ÞìQ,vºùbtø gÝÖÝp„}ï58X“þì.Ö°Ó=¤_oÎBÊ«S8#idê'vôœ|Ò>^I×ܧ¢“W—åÐÏ6ÆtnûþÍ—QÅ"JŽ©ÿ{Ž€ðÑ;þÇÚP*xÔ§D-ɦÁ•¾¹±;ŸçîW3C„PAÍ/6U v¶ŸÈwu­*ã ^«z7Ù§5®ärᶺî25Öm©D8åq>ìq¡lê‰Çylèã7êqªpjêq”\$ñäf– ž Û׳ÄZ¹>ýo<‹'3÷zf:Õ¨‘£)_ô´ó›xNêö’CýÌâÇ‚ á°o´1ÝFm äÀ7éÐÅ:˜×uéx¦3ã‡Xþš­X—bŽÆ‘D>ŸÉܾlŸl”¬llË-ˆû§ºw|ëcÙXoÎ7¥¼Þ94L¯·>:»h×›õz¥(Õ {Ô]ë“W[{‘L%±dârfÕ[Ð\Ñ ñÝÅ•¡ºž¤`ˆiËcc ºžlÁvF¾|Áin¢úàÌzž7#œõ5–+Á·tSðÒå)[„ž» ŽÇÆBâ[šbæP’îz– Ò¡Ø÷Ô>/šFaB¼„Ìŧ£´D¸üÎÝiã6¶…nN Ñ,lלV5bÜ€©æ´õ0ª9í‰ìœ–Íió÷%jùx°;8Úš!Ü'üŠ©L±ØbÓb*í$›ø„rp4UJUð’¶%FE²ï ‡öƒÛš¥Iåòs¬Rh‰7ŒUÉk¹^råzä6|"bny¥ šG#OìGÕ !Þõ=e°·Îàt‚® %«+Õ ¾xƒÍn¹¬¼­ Çã ,c½“îó½¿ õÂÍ‚»ôÏt’Œ› Ø-B7eÞ¨e‹9e@ƒ!Î:ò;„˜¿Eþ•à Unœ&xyŠf]²[Õ©ýñtQÀíOK;mçaÄëºdbCõmÝŠIBOÙ×ï3=ó"‹¯3‡íK•;ÈÑTÅa¬Ù^±5I(ØÓ¶ÏŒu„$¡-2‚ù`Ø–èMåÂò}-IßQM¾/k— ª4?ަr~ i~Ñ&Û%’Ÿá%R²Î­ñ’?Å‘ÆKšãÌC‡š*ÞãdúiæL§ÏÿP—^·^j9šžWd9Nòq¦jÐ8M“Íœj;Ý0ÄŒ¸ÓÞ‰löÐ\üc$Û§¸õl _ªav³-t¨ËÏv¸N„|±5¹•-Ëžu^-Ü6‡T·~ c¨IUô"ü,IkX~Æ$ù¸p&Ì«©g?d?(üer§nïTú(¤ÎÏö=]ƒ ³mÛ£‹"~–¯‰Çí§Ã‘³º2Kg~2½ xQYRd‚*›Fc% žû5-9v#åu?èu‡¡ïÞënŒ7Þ²Øb¯hYL¿]Î7Q-‹34ås/ÿÅN­ ‡ûf}ÁYæp$ulôâ SˆW¸?4º«]þNÝâ¼­;ð‰ã˜òMNa¯e–9â-²†– cz?úñŒ/“Uýx¬­™ŒÞ>ìEGÛ“w÷µ^5¨Y9¼¿¸«É³¨:j›ªê÷h¹êw¾Aç{d™’ñÕ3s€Ò xÌŽ„ûäôîÞ"TÞÜ´v4Zӈܬ–Ý«ü)ZÏo(øÛ¸%c0äþ/,L8E`kRÝOÆb®:/)¸¶ DDxŽ' ¢³—>d¤m×Á}x$$b\~’µ{x"X'îlnˆ-ÌRŧ"¸ Áè:\‘ ¥1û+RÙ½ƒ?úò†‘Ý÷Ò;H%“kø¦e̱ò5ødk_TÔ¶¾"[’:Ñ b¨KY-óËrÚ–p®jøW´Ê ÿtÕ¾(S ÿêaTÿƒjo—á4ü³©¢“â«é…P¬ßs#á Z7äžÊ$bÎÕ(CSnÂ^¸ kÎS8f¯ÚÐ…Bô/uÛyÌã…srf-çdâS&žéÎtÊ’–4þ“( #‘4¥˜¸ÙŠÝ¹LŽræfhõ›uÐÒ?C¶ôï2­¢Ø a«‡mM6·éB«‡I0w–$ŽÝ‡K™oðúaØùŽ@k‡m»÷æ~kë lT{`·….òÉ t¡šh¸^P¬tW «D¨|¦¶!ÔU: É@`†÷Z•oÁU¦ ´ÅlÿJ+ZA±í-˜×.—ç¢1Ežvoèú×0à½ÀïD»‚µn+W^<¹4\@Ç×¥Iµ%~Ë^÷‹ ¿ labíö‰º°^w™ß¼‚ÐA.¯Å ß+ƒQU)×;ªë]:µ÷B/™@i½ùëüàܺûv#œÙ5Öåòs5[ïèØ”e'0 ±fê‡Ø †÷®¿XGÒœñŒD.á¥ã£w(Lm Úô–ÛôÊu¢Ø´é@€'ìê2Ë@õöü+ÁU  ­&xª·/G¦ûK&/ÉÔ„z©uŸŠÇâ›]Œ4ð¼åÙ‹Ìþ)ÜËo¬®Ú@ž¤ ä¹7Z¢—D°~"b}¿.xeí·.£ K^ÁiK”µJuµÃëj'¯qzÔÕn8. TíŒpÚÉwK̵3êvQ4©æ6ÊýUtIF’ÎÛý5²ÆR‹ÉëB¾$¸Å´=wAVj—´§÷Ô ùz1Ûc·ôëqþ ¶±éýUè‰6Ä@YL‚K©Â—µH$˜ðÙ ² ‘Oí|`¯´ß ÆméµÊÓ¾=ºÁ|!߀"ÏE#ÙǦex&:ˆ4Íë˜Ds7q§Ù’#üiãlþfZgé•Õ\ª$b’0Eálk3´êKØYpÖíÁ„’ ´Óyç•õÊsãd2ýô•õ ó^_Ý;ÿYׇô{6QÎö÷'Ó© ¨îa`ðÚY¹ÑI '{8²m•ý¿+t³ºû‡³J@sÒz‡aÇÁ Z¥jµ[¯ÃÈ6¤øDÌáÀ+޻Ԩ̳_ÂÞtIç@¿”d)õ§ Ç”õòè&ª|:EC,Ÿh†-Yåtrfr!Û}O[°…u¦þʱiÈ•L(eÎ_)êú¾0娔;¬”MsЦ¹¾VM—,ÓÖ96 ”º±ä-›­¾±é]Æ'É‹²iÞáÚ4öp`Iú$zŸ/¤ekÐò~ ¡Š¿¼<ý˜eH7m=Ûðý]a[ 9Ž»¶Ç¦~Ý $l%È&D\åv~‚L92Zs,ÈüÔ/«ÝÐ5鮲Ã`½tHÂ{ˆŽ³ì»õ½ã'$réƒV6í2'!pç‹odK• žµù6ìRa¾M?½Ì g*ö^•×ðr8Øévœ…Hä»0ç4 S²ÂªWVôt?ú4Ý04^˜ÓýL€ÍfÛJk“³1›ÓÕuîv³.U•¬þœ@"¹ê©Þ »e%ð!ð®EÝP]‹¢ô·k‘*ч·ØU×"H-cʵ޴ŒPMeïE–`[€:GÑj9ŠÂ3qÑwnm™–\-”òR¶öRv—‰Ð/¥nÛ¢¶þåx)G’ey/¥®Ñ«[ì¹5§ÎJåª|§\•ÇqT¼¹É8ú塚(Çpÿ=•}t ¿)GevÚuoÂHy+{Gbô!µ)õtgªÿc ¦ú?Öèþ?$°w ¥æ–Tñ]¸Jï¬ÿ Å56`w4A Ì÷ª)9Ö.ç·Èÿ…$S:gTÅ}9Œö­7„ݾôMƒªIÛ–lyÚÒY±žýœv lš0­òPy¨»uöÀCm–\í9; Ç’Îé‚“Pß\›‚0Q^Â<šòÁQ^Â&ãP^Â_ÊKxPy ›~ºÆKH»ÎáZ „^é[°½i{ÿî.üùDd_âí÷ÂÛ¡Ÿôö+GUZ™p÷_ª‡Ú;ùU+ãm+c¹”âM+ãV‰Ä`ka¨8[ü:šxBUù ©&8öª iKOÈ€çôS“™éÜ䘣¼;u…}‡{…µFCÙ~§½ºÂŠxXëÐòV>ølëê [DË϶{…5L[¶Ç\¯®°Ð‹ûÞ_,`×÷Жäí–™paWr Þ„ ¹ûkðrö?³¨ßŠÇÀ°E³¹÷=}ˆxŒ„›såsŠ Cœ“꾑9)Ò>à{±(h«Â,ôâ¾Ò'S•”ô7)I“µ/4))Ý žÁ¹õÆ-ìF8çÌh$—œpÆñaSùñ"’$\¯V$š(ºBަÃGpÞÑOu`§O+ggš kcؤ&…”z×͡Эg¹gc¡®³‡¸¯½·Þ«®%IJÆî}÷íS‡’)Œðž{!¿’²1*Ïý!4å¹?Œ£<÷Æ¡<÷­¾úä¹g/„miÅ}6וTqž½ßÞ´D ŒBšÐXÊσK¢Š‚´÷Õ 9Ïj3„蟌—K°Ü¥¼2”n3„Láz•ý8Jœ¸É:–Où´äúݦ/Ǥ5˜$Šæp¶ £‰óiÏtg:ý:st`ÂÿE¥…Â…è\÷/3ô2#5±Šy*ªs®GmÐUL¬ß­r—1h~‡ó sÀšç€¼P :ÕöyQ"ˆ­íÙ–µgXÓ´%}ÜçÂì&Ø<„9}™~RaLŽ¦Â˜GpΧâÒ6ÆÒ{/ØÇ¨*.;®¸ìKØØ–)Ù2µ‘Pbç]$rê@¤yimê¤ök>ÝòždÕÖ¨c·ÌPÆ;gëb  ²jA*ÇBöoÝ’Ð¥cÉrø®ŒÉÍ×™³)ìËQaÉùzèÇéu¾íP³dÙ­.Ó‹ã ׊Ö@æfæ¸+Y¿ý8ëH>ÎËØv™~òæœ8eSbwÁù^†Â¾0=ž,M(³¯W6æÂÆ´˜exͬ…!ûî†xÄ&éX…[³TYÛ›#aÚS …5Ð…LÕ ^Xü» æÛUeȯ*°Âþ2^_•Ù¼ËlîŽ&³™ÍcQ쟭²´,éÉ –"XÇ'ØX’yõ¬Óå{Gt#Ä”©bYUºü!4•.G¥Ë7‡J—oõ¥Òåãíf{ôvhn.$]ÞÒ†¢<7—“õdAû§YO‹ðE7lÐTÆÓEÜpôS¨vâ® :Wï†pÂE‘Çl0ÐÄZ$çõôö²ÝRCÛBÄÇ•ÎIݦ×vßs¶C¹~)_÷_&Û§ÿDX»Äd.J¿ÃUà¦n %#ù½Ràð)«°*Ü[šdDÿŒT¸P±ÁžþæÚ sÕm›rç‘©þXæšF©æëÄHוbo ˜³um,­hz¤Ø¡]\À–¹mÉû·ÎF­§O{¹ñóK¾Õ¸žPÐ÷$q=‘Bwu.4Tq½Ch*®wGÅõCÅõZ}©¸Þa¼\Õ…f*"¬úO÷3²gÛ¢IõEÓ zQzÔ#Í–MkÝX˜$³0} “~ŠY˜%#“~¯Î5ýýÿÄMÈj›ÆÑ0­Îñ¸ÃæÈý·:ïˆ<ýOy¾»³òáíNèù&Áü‚æ»ÿÍ¿/ÊÎï¿Ù QYpoZ]F EkÇêpÎÆÌ1ÆŽ·bç³Fub²};ŸzÛùƒ\ÛXˆ]wúUÁfÚ’±ÂYbèŽÃ£…Ž{GÍõn¯_¿tÙ¬£rHÝ/6áJíËIyótQE’·ES)£GpI^£qô?¡Hò:'ÉëGŠîPÖ %R4Ml*úe¿¢í¢+ ¸­«ö¥ÎU[•õÛ¥u— ¸óÅ7KÙsç‡Åîo­óÃ1Iè¿QCMµKãh*1üÖt¯ Ò…ÉXÊH+ å&[(þY—skSúr6&šak–Ø…¹tD¦:·ór,×Àé#±iè}UUØ[UPU£a”¦.ËyÁ¥ª ’SßPAeë¦\Šý9WP`]JTSoúIUQq4UEuçlœÕöu&P÷ <¢³ÚX–ôtŸÍQš>­¬³ºUk¶n 'Å\NÕPN1\ÕÚwu¿Ã=‡UÕÚ>šªZ;Œ£²YCU­µúºäôaØtÖÁÀ¼#óBªÖl]2›µûªµö‰²ÎúÓ­©8GSEkGpTÑZ³q¨¢µ6_}²;•™`ý·:UÑZιXùÖØ´ß9Wrf~òNmc$¬†UÑZÓ¢µîú°õ²h.¶·[´&˜|v°hmD•Ç‹?'¢QMÑTµÚœs¡Q}KÑh€î\ t®ÖMMŠ ÛÖLKÌáÖ/°lIÕ\<ú¥.ÝÇ©>ø©M]*-\Uíµ¯ÚëμíIÕž-èS)Ô#è©Hí]±Q0ëÑë°Ó6ëüÃu°]r²óö¯ÈÓî­Q]ÿWáê»{· bJ¯õª+¯¹ÜÚ(Ç×-×ô¼ÛªÏ&™ÚÜ´êsòÞßOÛØŒþdîGôï&ÿû· –á\»p4Uzë:\j¬|àrâa°Íõ «BÇ#³»œ ø`ðd 9»kàr“=2´·Ó.ÅÒ†–Øq¯—€Û»¶!ÇRÑm .KEUÏ–¥ÂS):MßÁ9– S—ñöÈQ,ÕŸêàˆdWY©xz?X*ìáP.möœKM°6î^‘—SE99š*s>‚s.QNÕ,òð§{ËiGç^vÛ¾—® VOŸ ðV(Z Uáí!4Ux{Geä7‡*¼mõuÉ%°)ùæà ™™¬Œ¬™Ù‡„¦áøíÞŽ$=ô§)¼[#Êèl ¨ o¡©ÂÛc8ªð¶Ù8Tám‹¯K¶:UámιXù¶¡›Ò³}6fþ¥ÞŽ”™/\xÛ3_4ÂYeå×ÝÚôýúñ$Q}ü8fÌÐÒ¼^=2Ò!Ò7òZ~ ëË[Æ%y†{¡5òñð^Ÿ©ÓuDvçZÛÓX·‡²dwT+žª¦T5à93 XšØ›hÈ00ýäÍ gªŽSަˆŽàœM§f>_ÎiÚó>]Nvÿ½]I>÷Úv)X ‚×ྒhPó^ÆrQ$íI4ºå1èAÌy ¥Z_w\‡®K¯:ôUOf‰uOÿ{­ëô–ǃÂN2QÅè•hªýι£ó"ÖË1™û]Œ®ê£~º¢>š*䜣g\ÂçR•l¥ø\ÑTýôœs9BMvISGhMñ¹ÄQ|.Ç>Õ…½bh–”ש'|.K—c?çjuYæ÷ÚjuÕ˜{‹¦*ÖàœM¸L5æÞGS¹{Õ˜» jH©çÍ ÄgP.ަŽà(†€&ãèÿA|Q¥CŠ! ÕWŸjµt¡¬Œ8¼â!@›œy!Ë”sÛœ5EÀYôæþ‡²:ß![Š"`MQÃQÍÆÑÿ¤é‹²óE@›/Ep/?Û¬õî[1ó/„"``Þ,EÀXžiö(EÀôÓ «lTl^MÁ9ŸP­9wWHÚ1t¨¶Óéî¿¡þLÀÉó‡—݆š!]—rV$7ÃÀ–+2;kn‘ö·‡“Í^&cúb7ŠÂ—É‹Ê3ãhŠ–áV18ïÎØÔ»‹þõßË8¿w× ¡K h¾®ï¢Ób™äy˜ªÝî#©“Tœ+ O9fš`~ÜÁ31¦€š³—;u ¿C>…íáXUzÑðrÌlÞçêrNa{:0Ž7˜cÆ<ÝÅVrÌz|â‘oÅĤ{YÐ>égŠÙH—êBÓ1#!I…ٔȊ¿ž({”2ÿýœÑ ±¢Úrq1]“ÝëCªQjÇL(ŒbµL(ŠQLMÑ¡Á9:N£p9×Ì~Ó¡(†ŽƒŸî'£ØP³äŽŸCÇu°=†…äçÄC@f¾ µr4Eéqç\Zœ¼¡¸Ÿm[–¬S¦,áCÍ–ëorÞì öÀpìÓOÊùÃѿĜs‰ý)~‰}4û;‚sF±¿Kã—èwá™® ¤9ãÏÆÌ¼z‰¡6ó9œ3½ÄÈÄÄ¥—j-ªŒÎÆ€Š^⚢—8†£è%š£ÿUkeæ÷ßêTôU8çbåÛS¿ì’Ì ¤—št¯ì3¥—°´1"½o{nÀH&’”eBÙëïc‡Æ1‘ü‘WøB7Ƽ\šÔØ2”“¸ˆv±Œý7ÖûÈèÑks¦? Ù9 G314t¹ çL3aË“ãVÑL¤6Œ7U)PM±MÁ9›ƒu`zyûoǬÝNwÿƒÝ½d÷¸`¯c«M,óíĺӭ,gûõƒM…ŒRM»{À¦Ò:Üm ûuÁp©eû(³1 âR9„¦¸Tã¨@k£qôßÄT\*•8çiµ¤§úl,ÌTqž6¥eKeSÌ`%ëBm°µG-/Ócc!íÌáH2¥’Z–.Œáî;Û[Ô€ü ‹Ò®´_•¥uUK÷ëk(Õ%¢c¦K2ß”©g?†/K7ø®èz24Eוö¯ L©ƒj»4»×%#©Æ’³ö`°~U¥ê+Ö¯ZßÉxÎF\ë×Ðõ¤´ÇØñ£Jعµ3'«ˆxÔ ›ÿø¸Z‰  WINc …ë÷õ•ýÁ}ö_õáGA®ƒûð:HHÄ\Â4!íT^J{x"XmÒJ~ø;qŸ„Öâñ¥8 ûÞ=( ÷G¶TËÁó®Ãê]OkE1ÊÑTÖU‡Õdý7}.Ês¦ê°Z}]²«Öu6z;­/¤k¤‰Å,Q–jé¬#_4I4—_g‹Ûצ{štWÄ{šDQMn>}9æo‘?™NéwºÆ+ý7qLÔlÅ’=¹<Ž"òyi ÈU!9 Bg].牱mÉT½¶ÊÈòÚgˆRÁì“-!h¥©^N1ÉŠ8ç˪¶ š>öqÕ©ë#™›¹*a­.aËÒ¿ÜÖ‘nJQ6,óPÞÀúòT‰t†ÈÖ—ÃP‰´DëKÁåݺJzð?$˜L SŠÖ÷"é¹ÿ /ìà³-߉î‚ÝBéë5x9ï/‰+i€TëvLÊeu\ýÁ$R•ñ¯˜DÊhŠ /Ф7L"#S²Qý,¿Ö y2Ömùu޽_ðÖ¡ÔTSÀË­¼†Žv ­À¼¼O×ê°…wÿ‹ŽzI#6‡°%æêé+­ùÈHñžs90ël’N‡[ü]ËïpÏeU¼¦Êá¨ràfãèÁE%5ö?ÇN•WáœKN£=Ò éKìù˜ù—Q<²Fo¶‹·`¹O‹.ÞI¸^­H4»Í)K½)àåÖ÷܃fäý•½Võp•’b®„ýC"Ó!p…’#küvÖz×°N‘ºq4U(yGJ6Gÿ3¥.ʧ  %[}]²Ö© kòÊ^š—X*ikR-ëlÝÖÄ’ñÀ Ìö©ööH20;|©‹ÖZ˜Mc‡wÊê|‡lu†å‘(¢aÆÙ|Kg™ôÈîì{ì°ÛùV±Ã_—lvªØaÎÙ˜ù#Ó~;TÂt/dÝÂ}ˆ º‘+QáÉÄ8Q~øì)ȕȧr?Éš¾0†on# 9°+±vÛ˜N¿³tã'iÈÜN6ä´fK cðBêËÜ4/ciS°•UÛ1qsÏñÉ…ÒâÃͽ ¯E™÷TuNÏ5|ފגÊÍX#!.)p É0ž>K¦n°bÍ`½\­–±±eTéŽñ¢4˜îv¹NÞŠR¥šREQöpD¶¾¤(¡€(UÚÖŠ:ÅW¹tÇë€ú~¾¨Zñ­ï„*gs5ÇæHì-sÅm–f÷ºd,• Ä;Ñ3z¦ªê²-=“§è™8Zß™'zþé9=“©w˜”Ñÿ¤#EÏ¤è™Æ¢Aœü!©t!bÙö×¹}/± yMÚ3gE :âìáU: Á;\y1d("‹¡ÁZK1¦¾Iz[ìÂÙ”^gúÉ›Ž7U,;M±ìÁ9ŸîuKžöå‚m2èîuNwÿÁ{ÉjtÁ 9 ¬6±Liúݳ¹q¤[Y.?¤,RcM“+/ïžEª½[o èVìˆFJ, ¢ Ϧ€ŠFꚢ‘:†s>©àŠFjM¥‚ÁQ©àÍÆñÖRÁíÑX¾ÓÆÙ˜ú†­kbžÔ^¦‚u¹’Ïs¦‘ˆÑ€IÐHM_¦Ÿ•GSTRGpÎÇM<²_H ÓMlÆ—»‡£î’åb§î뺳ÂYSw+ÀQw)vަ¨»Žà(ê®&ãèÿQ|Q~œþGluW%ι8r[úÕkC󩻯ºqîÔ]­ L](M´3æ.UºÁÑsלó ×*æ®}4ÅÜu G™ùÆÑ«S…k«pÎÅʷƦüê|Ì|®:Ï?\kŒ”­_C Ó¿GÏdÆæh,µÂlk$¶ÑÞ óEÑq0¶tá«R(d†‚²[SÈØkE³CSô1½¡éu Õ!RîN ê˜>ÑPU•“(ª2Z߉cÎFXÚp ôBzKC5¶EÍ‘‚½kŒDÒHÛ…Mö©5ÜuòØžWÃñtVÄKRb ]Ÿ‘8öÃà:¸u“^oè0Ý»ùðUŒjCZÝiPe­krªfd™rTÂ퀞)è :\¡WÒ……Õô±l{ÑfšÂ0Dì‡ý ‘®éÅwÅV~Ü~'ëºö©¡ÈÑÍ›t8|#Æîlrói¦9j ãmaS3$½¯m]Ý@J¬‰vDvB Z.¦  %m²SkJ‘É,kÊp•&+ü'œ–˜RîÀ³æöõœ†@(Ȭ®vÀ!4Åp ç|KÀ>šJ,9‚£Kšã­%–Øã¡%é8#?è¥ð -©¾1çÌ0”¯O<ʰ_H4QMqÁÁ³…®Â5xÅštibÞ^«z¸štÙ¾¡™¬I ¾úV“ÞÞµ£ë‚D'¨JW~ަªÒਪô&ãPUé-¾úäÄQUéÇÑ7¬[ÁX£‹65Ëæ¥²«zR•>Hyκ*]¶íiªÒÅÖˆ2:›ªªôChª*ýÎùUUú>ÚÅšùý·:Uð° ç\¬|ÛÐÍ·SŒuUéCM£W3 3_Õ ×Ô «ªô‘®0QÚƒBܱ.r‹„©Ñ¹÷¤}^ÿ@hÀu:CúçG:ŽU¿E¾*ÊÁ-ÊJ^óNšjnÚ¶HH²¢(‡®(¨ÝÌòñù n¡l ËŽ€íK)©HPgˆ!º¹ I3C£HVñ\jÒˆªÄë`«E„çð†œ»4ó–ÞÕÂ÷\ªN•£Q—‡²ÅƧÞÜÙ€Ûঠ嘩 ¥–IË€öwn£ õÜ­¥+Ò~ ç[~·Œ‘•ßìHDø Ô`E˜¢tTijbŠ ½#ž±(¨òÝ4T<+‡ÐÏÊ1œóI•T<+ûh*UòŽJ•l6Ž·–*9ЬñÛ ˜^ÏÊP³¤\;ºP÷0×Îc’¬¤#+B µW?ýW:–Œ­öJŸÜ|9Cú˜ yM&7ŸèߘC|2ÒïtdEa4QD‡ŽfI²€\¨sÜK&ä\ë¦,ƒA빆±×ñòÕÝù4–ÙÍ<ÃØéXó a4H"d³5Ní Î@paË|³ôk²µÍéצ/ÓOŠ‚£) ¶#8x·À¬“ÃYŠe§„–ŸîGvºÍÁXzº{}놣¼Këŧ¼£Ç¬õ–)ï[ÿž€òN…Ô8š¢¼;‚£(£ÿ‡ñExå]«¯>EÔt¡Ó¼/Äc õ7ĤœwÔÆ´ß0ç¼/çœwªtš£)λ#8ç“È¥8ïöÑçÝ1eç7‡Jäjó¥¹ãågÛ½3ÿR8ï,aF²÷Qâßûžï.„“±ò¡^m$TìÖ§êŸ!DõÅjv®Y~×}wC<â?“t¬Qμªz Ž+lQs ja t¡ä ^Xü»5·«J?÷U5”‹|ñ«É‰IvékJ±6xWë$˜L?½ˆq+)?ASÀË¥Xƒ64¡£Sã‘t•y  g;€½´jó²3E Þ{þ´f}ªv;7ë‡Ö9³ÙaðVÕMçxH…Ò«Ô!٘ѮG‡d¿yHSF½·¢¶¥ù{ÃCª‹óÈ]ƒ†%–ý߃ÆTÑŸr4E¡qç|"¯ŠBcMQhÃQ‘×FãP‘×6_*òz/O3j›o'òz!º®ËQåo­¬­‹ù–ÄjeGôý¾øsLÄ®!ÊLo x¹E²}÷é\´’‡«Øs€ì\}ÀÕkêº!l’\P½æ¨ƒ<\½æô“òàp4U±yGUl6GÿcâåOP›­¾.ÙëPеuѦælêº)Õ½ü¬ 6Ç@&&nÁæRïNU°¹‡¦ 6áœOØPlî£]¬™ß«S… «pÎÅÊ·¦þv2»/¤`S·L)_2PTÛ?Á,ÍÖåO£ð™D¼U¹bIáhªúéιͱ9z;ýRÒ§•ÐÚ=нÞn™‚Q‘Ó³ÊÕªTì]媧*W9š*Ê9‚s6•«ƒ±%¨×#w‰ª\­ùTaŒË¨\ÕGºTåê9§Eš˜-Dvi‘ô`ÎTµáh*;òÎÙ´a_­y4Ä"]NvÿãI›ãôÚ’Éý=úñ3G¦\§–³NÊ,æÆKÊxUfÐ;•”qG%e4‡JÊhóuÉÆJʨÀQIÍÆñæ’2††%½º{mê_`R†¡›RµÜÓía$eTEövIŠm£©ÀÞœsIÊPl{‡?ÝÓ¤ ƒum£Á&[Þ;SlÓs9p£ˆªúÅÂÁÑTœéιèú”`B¹WòhùÙžß»ë…I^ªˆOŽ~²x*K^¤R… ü0líÍV¤šMGÁïêl~§‚ÇqTð£Ù8ú:«àGŽ ~4‡ ~´ùRÁÃxù<'ݾZõÚÔ¿Àà‡©ÆoÕ‰6’·ò9ѦŸ^f†ãM•/£)_Úœ³ÉÙfÎ4Å[XDCÌÚîvºûÏ[ØKßå›ëÀyò–yÙ´…p ÙR•‚¾b“e‹Ÿ·¯¸}eý@0ù§#g±X~‘2>›*gñ!4å,>†£œÅÍÆ¡œÅ-¾.ÙúTÎâ*œóqßK¹l[›>8‹­ Ö`lÚbÆòBmáµG-à>xŒé5Å”N¶7RñÝw¶¹¨ÿAŸö³i¿&K«*?’î×ÖHê9° Á*àµå±±ö‹k ØÇ bm ½p± —½ŽWU:ˆÎÔh Ù:k§ÄP&¶#§„ÐE9%*§Ä!4å”8†£œÍÆ¡œ-¾”Sâ¢rJBCtJŒ‡ò ¯Ê)qÁη´±rJ€;%4å”H×–T¿z 3ÎzmYcÉ{äÞÚò”Ë#-]Ž+Y9¼Š¯5V?^–nHÑU¬ÑP̸àÕ­šêÉ‚îI[XNº.²šRïi»ÕTXLs÷yÆþë«•ˆüü:ùÜÞ*²?¸Ïþëˆþ9eã¸2&Ó¯3gHŸ/!¯ÉD[Úã äð½ÁA»;s¸‘4mRÛË2«k¢Ý`¾R(Õˆ9Š*M—ê6Ÿx?e­ºÙMG}\?Z¢ËmÜX¨cDQÇ‘UD|Ö¾Sì%ñÅ é[}tãGå…É¡)/Ìå…i2Œs°{7ÛgsšZbÄû‡)S»ÝŸ¤#ɨÆ{_ £Þ~TÃSçi†¦ÐEÒj÷¸½” ±}þöPäMÔåoo8moа þÌÞM2} °,¿Ù9½aûT~¾ À2ø–!çL²­áY³ŒƒÉ•?£`½\­/é¶9Úf]ëÿe˜,ºG·*Hÿ¤—÷OªûÔMݧŽà¨ûTƒQ¨û”ð×ùܧ.Â;9 Ñ*ÓìiÖ]UvoL³ñH.Ýp b~о-)[²f7¿¤:mäÑ—%5ÔE ˜ Þž±.äm)y{îýéÚÑCÿdDõºþ@’²ZøžS{ýëÌÑÍòÏ5Ýܧ?dÍ:tlEa¤v z…,Éšì mرâ«rªõl½j멆1㱦¢R5_:iK÷ 9¥£sl EìðŠ } æîê¢ÞÎý£ÕXÇQªÚÛŸ>¦Â3æcrb/\Ç»õý½X¸¡ÎVÔ°J¡9¬Èçó¯ÜÖ„ ¬½›×þ³À½zC4¿7o¨X¶O²å‘uäKtãz#5ëÌü-ò¯ôÉͧ™ÈÉ¡Œ–Fx9 ?ìì$í·ÑBw€C7”È3ɸfÏÔ’†¤ÛN#𢛫ÀÝ54ºÑˆ­”][¥("<ç>r~ÔÞ3«æJÌy ti#¼\0ghžÙæÎÜ·EÓ[óÜÔFB*tA]Èý[k k¿†áÓ-çÎSýw`xûÎbŒ7ýÞw—Ø?ph ïvÉp8gk·þp,O%éŒ`sN<é.œU艨Ÿ_%_4Ì×&[€o%D=›±XÔ~”º°B;Ù¶hÏb[<[Tájº¦Dí×÷Qâßû#¹=ÛóÞ¾.r €CXÍb>÷«ÙbFó5 Wòïf$˜§ˆ®ËòÚbp"^VGWÕH·„£F—b(4‘Æð ¥ä1\Çn0˜¬”¡”¢)C©G†Ra…v}ªQý#×lEØPêþ½¨yê¢V‹†©,]“æ'?ý3Ô4S¶6³Wµ=?Þ¬ý#”nØÀþÑ?w®W~ð TOЦL Õ#˜MSÉŸ­Í({‡z¤t@/]žºtÕ¢)£§GFO¯.]cÓx³Ñ±‘)VNÝÈèI¢5aÛM©žM=€ªGŒž´Š ']œ=Ð:'®·ë‘Ö½jyêªU…¦ uÕ*!Ç£ñ‰ëÆ{¤t,É’ñ²©Ãh-ïÝE¬lš²uzdëlWgôŽœ_ùœÐ+–§®XUhÊØS;C]¶FO®X#MÐÖ©¨®\„$K¹úá³K-=r%ò©­Ê°Fû>&Õ¶$aí,È3Y4\õÇ_„õ†=ü f§§ÌÎJ4¥ÿ{¤ÿûbvŽt{$¸Z ZG×»ªë_…±ÿÚ>Ñw ²¥êò|GôÏ)Ç•>aìDÚjÅL„X 7Ò¥i\ZަçEþn0_)”jÄÝTs®m¹©nói‰à͆„ª éCÞclŠ$/€—3 „¨Òëj€‡Œ¡í:¸¯©v‹˜µ7¢6ð•¢æOÁðTÉŠ¢ú½ÿ@j [ä>WU |Ië?2tQM_ØôöH¨ôªü‰íÕW[{‘”ÊáÕ²þ ¹¢!Aâ» A¦Ïò .‚Á½fC†|s0Ò„jÅ@9­€XÔô!»Už”óÊà,WœªsÆyΉÅþ˜ˆqð«Ó¢^Î0dO‹Ë4Œ9#äL_µipÆN¡Š¢j°c'Ûé sMoêÝL5LûxDrÔ/ñ§sÛ;`6eJÙƨ;›À]'<—B%ûu–€>#q쇻-RS@ÝÏû±aõ}¿N#ÿÙMÄIKû<·¨à6º0AáŽÇîÝñ2«?%"—°ýu‚¸"KÿÁ=¿Gá—Â{ÕR>¼N›,|k²`h\v‹þy}O¢ß‰WÓm!ý!ýäõ7úK×ÁjðÇîgßÖìgKÕ—aLõe¨‡Q}Ž¢ß}|¦ œgâζ¡ »šî~ßôüp`L¸©Ëvkl=á™®Õ0Hî…ë~º-C·:šnaœjÕæåЇZƾL1¯d0Wt€v³pn^»ˆH¶aä[¤°¦ÔjˆIt_v¶l]†}¨BIV—Ðâ@Œø²n™j›„ –±zá‚Q]+wÚ;\wšiê=?7J»¿j•Àí}©ö&CÍÚ ÝïýÜYâ³~M’Õ•ë=’Ûð‰j÷¾CÞ½½O•*SùÖྭ#)´%ÒÅâ@Pûö‘N†|6‹’7“yCY:K>±›å¶(‡ç>b"Í’í‡r™O/]’°.¡±¬ t™Ïu´èY¦Åeº:ßž+¨Â(ÈŽ0‹`$Ø´·çÖŽT k ¢®˜½FÁðvÞ¡Ø7týk\…«ïîÝ‚¤9­¹«Ò‡<̹KOø|Ã3MN¶T…0§;Ò¯„êK+Ár§º> <´Q‚ÍßJË$¡²æÌíW¨šüñPÆý)Z‚QË’Ý_ªåÐíEèÎ?Fá’ùŸ¦zšð?3u/ÚC¬ *d¶›h–pµr“Gg¥Û?b¹÷û†´¢zï%Œ.e²Õ5Ièë¤s! Ÿ=;¡txݲÆ#UL^L¨«bƒ`ª˜°F„*&ýº\ƒB‚ŽuC&;´GBj¯b±æ¤žÐžFáêÞæµñXú7ó·ÈŸ(ïÃ>bºÅxÔU2s¿Í•­€A‹Êú 5Ûî*Ó ÷ÖÁs7”LƒÒ!f– Ï”"È“ 2L©¿ ž"€%›<™‹€"¨!c•+’ àÓ0_â•V}a(€)yÙPèz®¢­†™ày¹P—½}0Å9P£8Ž¢ßw½»õý=äD[ʼ+•¾ƒÎó°+²ö~s „÷÷1iÛîjI+z¡¯ó¤€» „‰×ÐX„º´7cx]..‰U`÷8€ @´«sþ²cÙîZÎÐIYG¾„× bµ±`WZ ©ÄK=ìÌï÷¥§Q—Gè„Ó…¢µY=é¿(rpö¯J:M)·X'È¥?Aìrñ^äzB/<‘*»j3¡›&ÝV2ä¾ÔÂèÆÄè¸H¨s­÷†¬¾ç*ûd†È‹04»Jí·}F>h&£®ëšl®Ó‰-”l‚Y)¦!œ§ð>Jü{ßcŽQ­”O µî&Î_BDs•ä‘­pEjžÂ‡ƨ髅MŸáש½ˆ yªYŸðOg¯>ž0§Þq|ó×ü„0¡ÃˆÄ$¹þv¢U?ò‰÷¯—uÊ6s·Äò÷ø;ñêf–÷·¢Ÿ»þFé:X­é ?û¶f?ƒŸÿØÇõbQ;!§¹=ð]#Û$W¼«pNž>÷cÏæ?‡óï§ÈŽÁyX’€>¡·<…LãŽ<°ìŒÓM«­ƒiDnÖó4b,“Z°<+–jî(N(ån¥R×1Ùñ%e6d‰e A¬EïiôGŸ,曂rAä•xëm*ÙIÖŠõ° ª°àÂb±â­ˆt£\LŸéæ›,¡¢í‡Å^âê¤ÀžÛuRü£ èxÄ/$âÕŒ‹`°{z„=†s¤ñ¼ìÇÒ)û¸px.žýý ðøí:ŒɽÌï¬|ãD§æî¾êŸVÚ)nÌÄý¼½§ÍfNྯá W.Dÿ:ùöus¼aH9u\G˜'\¬q’™=}Äìð“Ì,ìe>P—» ²Û垘‡¤'ºÜNùȉ;M("'°g>óüÈNã>ÎK<½Ë*'Îe•ÅØ¦pZ*ŠñøpZ*wÔéšG—fBœˆüí,*È;‹,/ïT«¼ÌÓx¬ ï#Âß!—ˆ°L ªN¢ä”dzapï?¬£tm"<Ó©ÜE™8|wÑAq`î¢CRàœ‡¤€¹‹òBÐÜE!™ûµ-æÏ Ö+\!Ñ ·Ðp«fæ*u•#<Û0 aâgGãé. aà<†á“³âšÏ›Lu#؉é^þ4xQn²F؈À‚˜âƒÆÔ,¨xRö wëû{"L¹Ò`«(ôHßd‹˜E±Ñœe9ÁÆ€?úU0Ž—N0‚ðÙŸ“hÂ55¸È“xËòýEqÿ¼aIa u¼ò½'º<ãøûÿ4žÍœÀÌëVp‡Ô¹ªà… ‡»øåAÁ.~yPЋߌ.eªê Ý]'_©&ºZøW$J¾¸«Uª€¸ŽÓ_£ZøÓô“n±ŸÄ gÎhKœ(m5?3SÎ"¤w'‡sßÎû€ è“çO=¨"é¼Ôz‡weDs?nFTë(îjD°ûd ºO6 `û$d¾18OVl¤iUöÖÑWa¨Z8þ?f‘çÙ]¬³rð¿X’Û&™3ÿ_l!Q¡ÞoêiþèÏÜÖu/\.ýäsè¹5©ÐB;ª³) ‚F×TZÔ=:T£ ½2¥( ?@Sw‚Ú”¢¼SÔŠ$ž X¤ ì¸(¢¢¨8…Z@E™h…Êb}«ØÐ9ÁÙ—õ"ñW9ÿöþ­¤yìÉ$+ŽÛŠýåzA[>ôé9 }Èt±ï.ÒwKÿá\F߯sahл9CÞÍ*ØnþãËçÙû?¦lGºÆwóÕãš¹O>ùÑŠ"t›,ÈòêŽ!kåúÑõ1Þ@ñ˜ÍlgRC2‡0R“OFt5w—ŽÕGš”Æ2šólR˜ ¨ì”à2šåÞ@&lŠ"pèes×â=ÃfÌl$½Ù¾ò^ŒÎò* ¢h*8]]@E™0]]âš?u®©Õ=¼x°P‚…Z%X°%PpBqŽÊi&¡.xF¾½ù÷쇣í¿bˆ7¨øO„¬Þ/üg”ó_!â7º‰Þ?°0*XÒBI «&›Í>_½çÕ±8Ob¥ïêõûŒDÏô¼ŽÌ”¤ÙTÚ&õí Ë“a«ÃÈÿ¤ø7”A°b‘«…ÏÎ\%¬Mjæ„/µLEÎø6¿­Ø¹é‡Á­¿$!»JŒú]¼"rÜÕ" FXKõaÆÂO#ÓØÎñg÷™f-AkK"Ùnyÿ¿_'aäÿ‹Oð'ò=Æ”i–Ò•»XܹÞ_RÓþô9]WùAzm,¯´ýÃi•ÔUñÐÏÙXý{ßs’ÍVò}ê&XŠÌÔªWÃf¾jçꆾ8Û©HÞ@š“-ÛÛÈ bz%¡£Í¥ÌÖ«UHï'J˜”¸>ÞVé"nVÇƇ· Gµ·aÿ°Ò#¬CòîAcLœE\„ÅyuH1(Õ°™föÿùóIð 5Þ9û³Ž|Ç[®2{(Gx F>mÎɽ»^$ŽËMç4ž<’]±û„g::5d£Ô&+nyó3ý*i¥€¯Y±G7’0'â4B™"?• ¸-Q‰K¢^iœjÞ O€Jì“ÎØñPÆ…:ʸP„Å›jGáŠÙâÎ)ã‚·H'»}÷°qÆ ºuö°QÆ ·?J¸Hs ·?Џ ”µq1a‡ÔÊ‚Pƒjea'«•DZñïi^×0 (ÁyJb÷B'(¿/¡v8ýà4E LS”pÁ4EÑ—¦Û‹ÐsÒrvêÆÆíeŸ?ù²²ÀÍ{Ø(/ öhÞÃF3ÜÆ(á"öeýMé]ø’LÙ•8ld-3]ᤡ/˜ ±7êùuµ#z^Ù™³ù£ËTõw¶kóDCÐ|ÒôM¶3è>݇ÜPep°£fjKíCí)›§»…¿ωy F Xvcck»Ê¢ØÀ©ó(Ê€[ce`°5V[cî ‰Ã%÷ðr¢Ú›šBŸýKþ†fÉè~ð¨ÕõÇç™îÌL‡åf±`ûpã6†)×ÎøNJ{çæ—nSÝ”]Ô0¢ØÁæ…srÿNO 9P9ˆí~â¼Öiü6"`zƒ›ì•ÒµxÏnðÇÖ€þ‡­ô?¾|Þ\—xÊHæaz’ 1X·ò}Q¨÷ò}q'¸™ï ³Ü÷‘¡ôÞ2ذŒ6`§À`G‡’©“R÷±b–S‘•XÿìLf#gJƒk¬\YúÍ~fàó¬$bº%¿¨*Ÿ¸Y,عd ¥'·Évy€z ›‹È„sJ1Ž}†qþˆ-ÖÜVÐ/îø¹ÕœÝÁýÎd6pnf¡Áhu\Ô Ï‚ÞpSJËÍò{׃«ý­€†ÚâÐP{|¸)ƒã•¿LÜ„ìCƒMÈ>4Ü„l.lT­¦‡å€ê©×åÂ!Áœ,–Žw7™>óÓHsì‹4X2—™‰æõ";É0VȾ\s+7µ6âyiRùÙ§`Ï?›}v˜§È™’¥sà •™ÇRç'Ž=?LSXøúI—ÔúI•›<:$öÜ‹: ýì…9…fE™{rì™ïŠwãÈS^ñ+ÒvHÙ9 kñ£‘¹³J¢kº‚€B•ãÉH3{¥ÚHá+Ívþ6Š-•Ko`Œy¥yÁÓÿÆÃSc¾!m­ª±dÛ-?˜š·±sòt7XVô‘æ¸Þ£@µm¨6Ê-ÖimñLN´@ sKÐë}÷tKvºQL}«Ý"B÷I¼{ùn0_òòÅØ=µ ÊL©À3ܪ°çÌt¥GoD–á3qVaL5¿1û†ÿmš?-«ÏHºÊï°t sÕ:<ÞÉøEßr CXŸ_&¡“Îs!Nü½+;Z‡†#´¡÷y™q¾!ŠçVÒä5aÆùl T‚CíJp¨M0.Õõ¼&‘Ëý¥Î+³°}î ¨¬5›Rýn9PdxUã0 Âþã%Næùñ¾G6±[œâ·qÎ_Ðù8ïôñCÎ( õ"Ù;[2¦+’ü›+]ðvØ&q›fó,\?»šaÉÜøn£ï›'½vx5p‡>¯qDþ™Å}0f‰ t88/ô¨ÂÐ6N°Måöí÷˜³ªHã× ©|Cco–Q$:K~ê:lß=5¶ÎÖ}ÎÙȵՌ|pqäc)b³c^dæ`ØdE/Dô^4wÜ;ßñÜÅ(Âhh$`u×äÆ HZO–7ûê¿YÌ ª¼€Þ;JžY,™>Ž÷H¨NGÎõ7çãõg¤½ohŒÒŠÚž¼EÊŽì~_õ —Îo7Ÿ7ÑwPañ½ž=àmÈnÂiew…Žç.Ά‘©vA†íih°ö{eî§>Yäs`ù±ã¦Î]¸ænô¯*K@œ@;o4näÞó'„Ñ«v…Ú^à!y„Pèûè܇‘³ðã„Z¨KfÎxD†+tßs{™E3ño*In`ÓF–HEá.$ÄG€ìÂ5†¹÷˜Óyùî²orר¯ À¹w­d–u<È#޶583æ^H#^¾t¬c$ on-Ï] 1Þ0kéNîá¡ Íñ½¿X¤Ö8?!˜óhµK¾ŸZ쟲N‘úä¹ÍÔ‹”DÔªá^¹.ýI¦qèͳþ,o±„iöiff3{ÅKÝàÏûÅGo"µâc ´,Ó,\RxžKH ¦výàî¾bš|‘²9`q²Ê…Z½Dᯉ¦U½Q W‘l»ÂÈã§L쳫?ÙXÌ®³<Ó>´EnÃðs< éHspHöϙՂhfšƒÒu,) nWDï¶éÀèe€iUzÚÄ7Æ?aX\…¢e?Ù+@™,§Ÿ<¤ùå1ig“F°³CÙ~ßÛ`h¡qö¶t#M&˜%›¨”mm20Àl²nÈ‚^QžÉ†tUs e@Æ:vxÃ9u`Pd‡÷¨@Î_†åçX€¯ÊÁͰ )*ÒÃè›®óÞdœ¥¦›bfòìÕÁ^o ¹†™(ÞùãzQÓ7/wtyô¼ò`N«¼lÞ J¡ÆhÁfpPûrû°P»sc/é«8ÿÎ× ¸D¾-8k{Ê>ûPžÁ-t–n¿óuâòYÔËŲж± (6lo@LH“%‡ ;F@[#‡ :F(e´ÅžChui0l.w\ m’I«ãÜH;x;€\+Åš ùضƒ(¶F輕ă7‹Åá)§ÖŒ=g?á÷ðìwù=œ1Û Ï…U kVŽðô‘ŸÚξ٥š<°–»i†ô~Î4¤ì4y±ÜM´f:î$º3÷Ä× ‘ÿ®ø!}9ü2P·}J—üÑðëAåh‚ê …#¯ƒÑ¶<üP8òxŽÈITÕQ¸Ï9¦û:»Úwò®AíÖfµ‡T ¤5›ÃÄ9˜»Áƒ²q7xP6nFÕ6¾ Ôø2# ì}lð žwƒõ¼Ï$âE£ hÛ²h–ÀÆŒ†`µšLy<ÇeÑÚ¬ðGí͹{¬‚8Fµåñ¸é)ue;$‹ ¤¾@Éx؉çÜé(}÷sz×–Xo9rSÑzÜŽÁæ«0ÿØÈò1!O9y ì÷jórˆúiþ¶üÕþÂBºÄïdF˃ό-žÇ^òü }3 VUB±'z°xnAW3=¼O}3ù ï²Ù‰ËΊí%>€“Ÿ˜£ÍyÝ…l®C¸+$·¼»õl7>b@œ`YŒ³eQcJâ eô¾“0ïÀ Dp(C~dÉïLùÑ–Ò“-có7žA:áÞ£ïPÔþEX_d°hÚAY`o÷ ¨7~PÆ*¨f‰@] u"1WEL”ÕQ+ c•Ô ƒZ-›Ä¨¸òh„c/\}ç¥kµm­ðã1#]„ÞSZ°Öö1å_Ê>¦ü{I1õuàÓ·à0h®Ðìˆxë(öŸY]"=È'‹ý8“lº•2šW°™)ÁBMNy.ØM n.ìä1 _œíÐùôçÞñd2y¾ù$Íõt@ØðÎ;›¢`Nhƒ.ÓÐéYÙN”Õ#<ë`·æ$qý…®±¥zN‘.°h"É8•$0­uX Ôn=,jóVHáÙaÎCjšHAœ±œôcDtójNþEf-£ÏëN°Åï~í´O½/ü„O>NË’yÙœüc[iT:£N:!ÇÔ‡yª<^û1]5CëÁ¬Õ½˜¹CÃÛ=#"÷^¸Þ ÐÐrdõm®:ŒaF‘Ž6”’JB6§ÊÒpMª’4ÄõV–„·tÊ’ðŒ…fºqRo® ƒWP¥ï»x•ãèà…TŽãôï¥ö4éàÝÔåôï§~,hïÈИ‹ÒáÿºÓ—Ü 9Îýïô1˜;Ÿ³©0F í?†wlZ*.Aî -8¾ÐææøÐön*ˆÃËÖÆ›Ú ¬ó¸·Í÷Á6í2ÔÜ×Áá‹Zh¼Qƒ½Ä h¼ z5ªjRêà&¦hrl6  ØðqˆjB34 ùdv‚¯~ÿ%sîòÎIœDáwd) wé:)P;¥èÍÖâ¿ëaŸùcœÕuކc2á5°Ñ,g·Kƌׇ‘'ïÃCÿ ŸoÇsÒ©ÎýxB/ÐcR¡ìQyÀ ø¨¼,hÆŽuÄ i”íýNW~»w³EZõt{©ÕðN±éÚ ì»³ÝÀz³÷ïÆg°•«Ýçí\1Þ¾méŠ!ög[W ®7[»jp°Û{ÛA·ùwœ;p÷GšÎ?¸cÔ—ÉõÍ&GrË KÁr–÷¾¹¼7®gCçëÌ.ñOÜð•™Èè¯27™éØŒPÓ¼æßr6ìëéì=ÿ7Çt£‡ëϾž9Ô†Œø$"½¨¾Dœ/üz6àóA¿éˆym³îdÂæë.íc3›:ì_L­ôˆ¬¼2âÄô¹v§žWúÑŸ~Ê&·œ z³XÌÆã5ÝΗŸ/ÞÌâëìƒs½˜LfòÌýâÐoIã‰úÒã‰ZäÖ›Iÿ–ÍXyÁ +Iþr Î*.¸QÅ‚›8׳Ÿì»eãÙûv‘³ç N]Œ~ößæS÷õL¦Î[xŸø÷S¼‡û•`“š-^=É×t…~p6ß}Ü|×|Âo/sŸ— ±‰,ouþßÅYœ,ƒG7vÈr•|wúH$™ü CŽ¡o;¼û5ÕŸÃ'égcP¸Ù•3¤g2«^%ý•'¯ã³mÁ¦õؽ?Ï ’?¾ÎkvÎㄺè9=„z7SFw7?ƒ:6ü·@f$þ'd©éÓ()dîgµÀtÏJ`î—Jp(÷I%8ûc¼µ¢* —tY•·õÄæm]Áå/6À’8x?'Ï«•Í;á^Ïâ|Ôg–X Çô§~¯Æ’¤ßâàg7&K7ïø9á]}äéÏËÀÔ¦dÀÓO’݇³$ú-a^¾„5#ž­~Óõh‹lzáråFÄ <¾G_,¥3Ä6ðC?ž­\L|0¼xáÆ²x[Jy•¹ƒ’Þg;(éô)Ó=¹êr¤¡ßÍX“2üq ÿ%~@ÏÚ©çköu“cñ ‰8ñ†{+â׬+nÚ¹ AÔ $*®ê©L•HÚTÙ”î®U9ˆaÖ¼jרlZ¿N¾}E~syÈo./ª³7—DÚâw;¥Œôw3¨ÙÍšf0«Œ¿ÀŠïÞ-ȇ¯P"Š„XœOø!J˜rÝС ‰0¨ˆO„¬Þ/üg°•^!ƒ~»dºSÆo1‰Þ?@ºùL ¶ªf³ÏWï¯E8’+}ç¯ßg$z–Ϩ‘ÂÔÏ—¬£âf´âˆr.$Ÿ¾’+%ØÚI;Ê¿müè·þ’„k¤U`°mOo]AÚÚW–±mŒ¾í‹þ‰|GR7\Zú¶>‡~0uãø%ŒæHÒìÂÚ¸r‹;×{Â[#ƈ9”˜,ÿÞgݳvóÉwÞÇE¦©UOéæi‘¤²y¹AÌ.a= ÓîÁtõÌÖ«U-W+5¦7Y'–¨JÊØ/.Ö¸íòúb1‹ug¡òc#ë·Íœ8RRµÄþ:Ͻn0a›³"mRËÔ:¤el±]‘9]¬¾»>º1Û§@ð¼q+‚)µÅevwâÚÜfJßó¿­I$]ƑöéZtý#r CÞûO¾ï_ P5o!áôƒdtÐoÜ1±å-‘á@É?×Ñ®âÃ^D˜!oš|°+1ˆ.nGÎÓƒ±­ôaD8ëÜ åï%§ž|öFÐÁ,4ef:ùä4XŸæ¬šž©?SW=¾Íàš¦ÞÌâ1ÏdeäÎ1‹uÙ1ª8‰ÖŒ bì8ÁÚñ^_õ¡ãa´tŽŸ0ï}ìé'Å='“©wëÌ=_YÇ¿Ybh÷aôâFóíï:‰û<¸©7™Ð7B%ëÈ’]wn׫E¶>/ÍÉõ,Ù&”\|Þ»Ëx̽ÀÌ”Ö&NØ·›nY %§ªtˆ®j¨=ŸYÅ*ĬZÎÇmæÝtX𛕳ØÖÏžŒÜÓСÎtázä1\Ì©džü4û˜¥>¥ß˜ô›Ÿy&ëd¢kΗÍ0Yàgì¼¾;s7qéöþâP¼‘󥜉,=]6$ßsb~߸[ß_{ìu{.Õ‘ë'1Ó+¼‘©|°\Lĺ±ö†»µ—vB‰ï m‘iÙÞ(¬Sº°²u–[{,£šýþÑ%7Ù,¹ÉfɽwxfâdLWÜ&ëîS~ÅmÊN‰¡9Î:🹋ü‘¹Ã˜©®?ßitÁ››K8ÝL”ö3{kÓ$"„—Ì™,£¯áœðN³˜Î÷Œ8IÈÛRÓqò ¤ O$¿å‡â{DÙÑo"®[Òú˜®ú œ¸2_f³\EÄ,×\<rô `t›.äÏ#óL#¦øŸ¤p¾m}@×ðj?:ÌMï¸ë×ëkžgI'éùÃê›, »Ì@þÚÉ@ j /O$k¼ WÎ}ÊGr‹„XªME/ãM¯ÔݪÒU3'÷îz‘8¬Æ%˜C¿¼}™c.““qmÏ+;Á~ÂÓ½|_LéÌí“ÔÜç¿ôS݈§é£N¼7Zko´{öî}ðµ´y¦“>qÕ« Ä{ížãð¬[³¾ØvÃx3ž,È2ma~h¸‹޶Y6Ɉyæ†É¿f€¡C¡jÞqîY@³D4orëÐ3‹þïæÓ-}¥‰1 jv.×óèë„Ë k>²ÝÀ,ö¿Ó lú‰ÛÏT°Áþ‡/xœ vüûf“Â’5Ö}wòà&t%†½ ý€þš“„NúoÛ¥èßÑeuËèÿNø,t˜Ôjy&QœÓ§°í¾gÿÃ~BòOj7åCw°*töÐÄŸ?vX®Ðõ­3¡É¹­è‘N—ç¤;üŽ9¿Ê)EÜ–èË2Î’Õ¢>i‰Ê¿eSuKÍUºàM–*™³s{­ë_Ãà*\}g³Á±þ¢Z£mYM¤‘¶®É/ÈôÆC*òÔ°äA ç[þÊG:]ÃTgô¨9Z½ÕÒ`PY°êÛ*kq ƺ ªÁŽ5Ç×8V†šsÁ-Wƒ…XXÍ%/C›#]Z?§Ü€Ð°Œò…|ù<{ÿGY…{cæÞ¶|ß–l]°µP*æ†p©ÄpÄÅ 8Üˆí¬‚òšC»€²ÍÙ˜õ¾,ô? œ.fèén´Ÿ{Æ6!Úøzî‚G|Á°G9ùÑe.¹ïpàã¼B~MH0's°)7´Í”oŠío·œæðzA‡€/sÃ(nypü"6H°ÙÝÔ_ƒ p› ¸Iî„d÷ˆiÓãêømu«-Ú)°WUR³é@¤eÎà\0hE]h®L=c˼á#å§¬Ž b!µ«Â?Á¨~?©ô¦ååýTuáv/Æv s|åÕƒ(ªáRéb•뢃Ô/¸Á”ÚÃ)ýŠY„®›(|‘6–³«õÍu€0*:ØX¼ÆWÛu°Ñv †;ؘY¨óL¨iÀÕtîÂÎ?«¤¤ÿô>mÚpµ×´áC¾iÆè¶ƒ±jûåh»~0¹WcW¼šŸMŠŸ·ÝKúõH¾à½Ï:ܼ?ÙóèŸRõŠ>ñï÷¤±ª{ÒT­Ðê'ÿHßeÚ@Š}wµù®Ÿ³u‘iþtå•Êÿ»€}¶MOS;×ÓÔænÚ­ìoÀÜ£‘Uô…]¹ú¸l¦H¬,žèówâ>1#‚e ²ìõaNúŒ§Ç†ý`R"XŸ‰Yb{ÃN_îiÆ.5åͨS¤‡ZÃc±1@ÒoÅØáš_ö­ÌªBÞíÑÊ!ïÖžªY}ÈÛhßß@÷BÞ û!oyЪ·€ºò†B-…¼Pág "ä €ºò†B-†¼P+CÞ¦pðŽEé†ñè”mûrl€BãAŸ.±ÑÌ¥zy;Ýñäe¡?×AãÿQ‹?ùÓï)ÚÓÏÀþN> M¯9§ŸœÆ#ëÍœ¸çôgú {&Kë}RÊò°Ÿ¯Ù’Eì†Ãèj6jW`gS?"é9zÖœÀ°œ¯ŸZž‹6ÿ×F±w6u6’¦AÿXmÜ÷nœŽ¸±šFûM0ŒaøÒÁ8ö¶A‡ciºú8Äê­ÐÑØ £íô¦&;S±óÛÄ :˜‰ÓÝØÇÖ§yÃòâ±G³ˆz÷=Í0egsßÌ›O{y3-ñîýÀ—ù<ýx"ñù9ÏY ‰³œy& i4Šô@"i˜€Ð7ÿD¾gYwHqöxn0_Œ,š®UDîý×ìù„þ»îÿÌ·nD_/òÃÂÖ¯?Tü3KŠ'QÌëÿ ›…{A~|\­>}:qÂp˜¾½[~”ÕxÅâŸ} ç¶sî_æm?Ê4›øgÓý&þ¹–“³Ž|á¹ëäQøC^šô×âs«ïŠÒüÍÏßþtœ¸É:Î0„?ýjkc/"¢ËfÅÒ…>C¨ÆñÜDLÒc’¬öžìð§JˆˆÒ=|T»üð½™Jû«»$©^ûñÇh¦ù`Ò]Iä±ïýÐà“ÿ}þ]ÓÆ#§Ÿx¿xø'Ÿk?üìÆd7z]·­†ÏL?›ê÷ô“lÛ3•ÚüÓ»‰Ž“ùO?¥…³áÝ¡qòçæ@,×45ÿÐî™§iïæ&ïëøÓEÖZþ‰Œ}ïÙíÞYYa7ùì™p{Üæ…§‚™úv’“½göÝœÜC½gSèE·{ÓÅ×uçRµâÄL¿<üø(²{]ºn|î YÞ‰=eáãZûÏî@Ò&ééèW‘ÿLÏ™æOPÙæMTC-×É–\½•µžÃ ¶ÛÃùâÌÝÄ]-ֱ쓚0µÝlñWÕÞ |¤ùZ+ùµþ/i—øÿXº n¶r½¦À‡Û(ª_x•ŽÌšÙ1…•”ÍœÌkoõâ…^ýNE_-\º×›}𸆶ÖÐzK ®W~Uk¥žòüŽqÒy‘µº; ½R¥š.^ ©7Ĭ ¶‡cÑ#³å{+Þ&Û¼î¶û駬ÐÝKš°­N;öøë¶ß9í_Ÿa[í·ÝÂyænÚ–ûŽ>pë“ÊùKæYñÿ‘-ƒ½BÜ?ÿ×O?­²—$sˆ5wÂÅ'dW]|†Özñ5wæîÝ tSÄ..¨Ž¢÷CBwlÞbù­æ‹ÿëÏür|·{Åå½[]ÐÀQ,CÍh{スù—y¾'„a´õr4Wñ’Þ¥r·¼#yÝ­½äãx¯¯îÿ¬SÕëxÌ>u¶ž*1Üœ&ß¡¶qdÌøÐ`ü†Ñ‰ºð2bïHöç­U­ÓiU o16 ×Ûw?¬ÂÌ!¤É]l‘]WáÊ'sAßÌjßi¿A»+囄­ w G{“™Šym§"*T˜ž”b%› ÀÉ1:˜×Mqræ„~áw„é1Ï¡Þëå»´ÿó. ,ñ³Þ´ú÷ÚJçÿëßÚçg?ššÙ2p}I!ãÁEä¦Î=©'iñá–Y¤º-DЯ4Ò±všJ©¦À‰LYþzSf ”(*(ux?ßÈÒXÌ)áµ&[|‡È‚$dóϹˆwlœÎ×#qc·Yå6€¶w6E¼0+7—p¬‰ì›½ÿ I²å~ºêÛiF»Ç>,PÈ,mz_xÁéîUþôÓÿ´y¯%a‹K¡…5¨¤ÔµœN 'uÍ: œ¤r µ7¬\yƒ·=‡×X„Á©”¤²•Ý!Õ¤ÈBë#³ÁÛ¥šã|Þé–¦-¹ ޵ØÈüß<ý¶MH³u-ÞÑ©Uq—C·M‚ƒ+b¿!«…ïm¼jí"Òíî)`MN“׿`(@áÕ-;ß¹:蛫‘…Ù—z˜ù¾X‰MÛùžµ[§Ë¼Y³­‹ÿͲ_Œ<"Òú4ߤK`¼}âá…#×sž¥M¥B )So|J½bsµtù8ëàÅš[³­Õ$ݤbÆ’¼­k*ÕXJÞ 5]Ú¾­’èj{é$¢«­&&ÚuVëˆ8Ï~”¬EhŠøÍ ]Û=£n—ž¨uÑlÇ;o„¼UâDz»±¹½è­ñ#$Íš ß0ôd¥2‘ଯ’öà4-‘Ê=-}ª;Ü$Œœ;ú~7›©UHfÔ69{W×à3¿ìnH‰û åÄo·:¯‚0b†Q{%Ü:®Å ŽŠÂß01^ò›Æe&W¬ln—Œ[1èñݱ•¼±§$º£¥xä‹=‘¨y| *Gà蛺‘»”Ï£‘\p¹ðiÝ,J­ÃQP…Ø*[ûUwð.G­ûjã.ŸÒ„¼KNAï Ðõ-GÑ+Ь¬q¯¸ÖGZ8zMÁ2QˆÈîP„¤·gÜÉ´f¦  ` èDd¯Œ>û«˜ÞÜkW)Jóë³t"vãËóÑÖ–+°ý 3Zr<@í±œÑúÁMܳíÎÈË»:ðÇm½W8UeçjpZZûˆöÎG[oÅ|}¿K( ´´ö Ro°µû¸í™Wè?a•Õº7±È І¤üîXþ^Û †!P|¡5¡1[sr`¹”ÿ¡ŒÓõ²¨Zƒ…<ͬ9¶Îœ¥U A¤i7³Ëp·dyzþÛ¾R³º¬É ØÔënÍžýÌ –‡Tb`̬ק™EŒîÙš³ÄM®eªäš­¾£D˜,½}rCû+Æ@oÝ.MtvI\±¨eûr¥ìÝg÷D/à¶!‘$ßž}«}KËD±Rñ‘ÃloG¦n°/®}óU™¶ÖšÑŸÍýê£3òƒ|§½/U9ç ÊòÓOÿNuͰúSX¶.rÑò^+Õý~¡ç[d Ò)@DõM»dO† 2ò\õ.¬žömdQSäÏÕÞˆy8϶—ƒ€ÌR/‡ô†r²<H^kÔž^Vb“šºPËn¾3J vX»êK¸l4ìÂ!£™}ko³!P?kg̨}Îoë—ÙÓŒßó,þ²Æm»¦¶N`³’ïK5cn"eN2€óL µSÕäé³E';—Š-`r_h¢DâÌÉ3\ É:}@¿¯©tjý -áï.Ò—jUÙnja9=e'·4»w‹Ð{’lZ gmð$ÀZÎ1ÀúÅ›c–;7ÃÌ=sú †(ÁE›àåL0@âÞ{0Á]ôp&ØqþçD$&ѳlÉüLG¦LÒJ/²A àÔË¡ÌBîC‚ \ê%SÃÙ—–}ú„aØAй]û²}hvSkÛ§Ïk…ÍÚÀ©µ§_µ‚¾ìJ Œ©uœ•;o݉3ƒËß,Nwèu’EçîrõwnA+_ŒÑéçV±in³Ð!œZ`±Z‰ùþh»æe[‡t«¬º v Fáê€8*ÃU Gט½±r#€ø<ã vûšM†—.Z7Ô½¸®7ÞQ¶åØh[›€S¿~®¹•¼Œüô/ÐÖÚ“Ÿ¢U¯Ÿí;d™ª]lÂÞ§<ŸqRŠÝžÃTÀª*½Qzþ"¥g.}Ïy £y»h»ÙŠÔÓy¿“Ûª¬¯ë”={h¶>>óG´cÀ$:Öu‘íU"qÝ ã?ò¼Çá:)ÿûsèÏKˆ´ì‚ Y–áˆâµx·=8Ë’”Ã-¯Ë‰ï ÉVGGÏDÝ‹g÷öåY "«ÐÏÒæÓ=bQš§Úö·ôæI»3â. O%{P\¬»mì{0Ö€ #¼¼;# /Ž${;w†ã<kÇ{¥{a Äì[QØ«Bѳ×~¦ÅÖ‚#ϰ…Âm®ÆÅ«­‘@ é8ÏÎÖø$•r °ÐÀÂ(¹å:—Ή…J‰mc2˜¤8“Þ߃MªL̯դÊÛÆ¹Imîc¨ÊOjD¼  æÕ”Éh5¯òvzn^®¸U@ùyåsµZ-‰$ÁV³*cÀ™Uþ=ЬZ úɦ¯¡"RÆáÆçi®±ç¨±S»]Lí¨¹rª‚­WëúÈÈsaHªyUí§Ž5¯ÚD:xŸ{zßù³ê^ueïz´?oì~4Ð4ÁÍ QË>4Ús{ì’ ä(é>¼ÿýúçÃõÍÙ†~šÑEøž¾=[Àš.¼=²¡ h"—À:@_]­žÙ«kM%GÄÈœ[y¤[wˆ‡Hw­îßxÓ·yU-7üÑuЦ00ýèr!9…q™Ô%Îó*‰àj14stžÔ%žGâÌ¿²Šüg7‘-PAyY|»Ê9Ó ~_{,ÃÕqÒ–Y²ÜqØÊsÓŽQ”;ð÷[¦÷å}>?ü‰.‘wúó¿ýéÇü·k[|ɺ®ø*~úéD_JIŠaBʨJÈŸþ×;çÿÜ^µ¹´a&bòom¶C³}pô=½½<–9zÛ7­hÖ³â,ë¬FëNÚ‚er!‰±”ûZ<5Äx‰4yÉF:XÊ÷3}ö¶¡;Çžƒ/•‹ &ç˜f&ûdóTÄ\$Q¤¾ ¯á‘·ž=Fußi<ìéÓ3ÌÙ"Á‘¯…ã?åSö“Hÿé'ç·`NîéΜ;“òÓOÔ`ø77$YGÙ3 EÿÒ±_HòΧ ”ÿÎ8}ã±&`kŸ¢Õù™Ú Vë(¥T¸Äµtݯy»Ýæ é{'!ß¿wîÜÙ€9ž»XœuÜ«uïÖW‚±ˆ)‚¼ÓCTðÊnD¸N Sl‚0fŒ‚v˶4weeò¹8v@£¶Ñº]"Ÿd8jÛ¡ÕM§îΚZü—‹>þ@ÈbŸý½¹oL…Ÿ›46Q‚N‘†F§HÒÌ/ÒW–ý·jD•+¯oyç÷ÇIE;sj<¶Q.€|3ƒQÇÏ åñÓâžý?ÿ¿ºùÿµ:´V\ï£Èýò↚)È•ÙjË`²äîV’¤ÕЋažš‘ Õ&>ºXîç)C94`[mïr’9§¹¾""ã¯HUmõò„Ì»ãoÏ,Ë‚¹‰ìÐm÷ö@sNÏ5w'~žZKgænc£¶¬1¢©¦íur¥îõ­Ç¥Í[/7}lžnVu!hqh>Ò6^‘cók*>šKéÓÚ:EØùå÷ÍK­÷|’ÀagëÅZ­¯o/L$M:*@9»{Û©`ÂúžiOTî½ïÂVDâ]'Šœ­åÒšA¨mÈÀÐ-ý4Þë«{ç;÷aä!2Ä<9N òÌB·’³^ü`~¾—¹gOuåTøøØ2“€ád½ƒË%j•!À'àeo—PtÐ;*—KéÙœ èh¤¾Ç³¥ÙR÷fgù²…w¿Eþ™Ó[)æåc-œjÁI"×ODœÅy†[£UÄÅyÏ$·2šÉrµp’ªˆ{dЧÁ„qYd›ÕÎh[ö.ï6VË}Òxå ¼Ù¦¼KΙû‘óèsl ¬Sb$ʺ~Y®m1ïÀ9˜V&ÊHtÁä©Ä@ož=õÍÓ†b3Û™¡ÚE¾¼Y¿%>2þוëgßÅŒûáßù÷wnì{Nú“ôòýŽþßiÊw.D•fwFëgú­iª‘XŠQ»¨N©ØæÏÿö§ê2‹Ô˜ú_¼ïÈŸ›Ûü ¹AÖ_¡š~tú^ë0 >ò¬¥2¨NÒ¶µU²®ýëÀk\VulãOŸ•i† /r÷é2÷áB4¢Ôm¢lÆ"›åBin¾8þr%'®Ä+æŸCÓají8¿ó…Óz».Wß¾ÎÏŠkv”ª–n1kîÏgÛk£Ö“-Q+Æ‚½‰Ë±Ó•ÖžÚðÓ5«}5(R5ïɬvÈŠúqkn& rC™r\`ú¥|Š×aœ¯áÜ|YÆÀ’qIŸ”Õþ眊ß/™Õ0{?ýô?¢/¥$å «!˜”&¬†™ˆY YAðÉÍ‘ä*äó4w†Úémèôwy·¾ßÖü¶L~J$Ì¥ Üò$¶Ÿ~ ïíe¤P­ëOù `nÃÖ}rÛ»›MMÀݼ{ë ö2?†QrÆ$ ¼ÞìäJÏ·tò¹çÛ2:©p“ É´©p«I)ä%kçúâZ±[æ±A”6&:üÊÚL>»Œ!ÚL æ`ÔfB¿·Vüf©à˜^Áϳ*ÔЬÑéSÛ }4Ém/¼j²Šˆç&¬¢PÎí¼Igdo#ËPi—5ߎÎ*mž¾Âqkk¾õ+jí{‚½Á_“duåzä6|"Á™¾=±H0¶¤>ìgIïyš)ƒö|^íëéš›Å7¸ c)毶U.i6,q—1{s­¯Þm™¾ÚÅ!É¢ ±a+ꈆeùʽƇtu›³ÆŸ–$¯iœðpì ƒÓ3óÁ 5×^=î…Šº1 Ï }8l͈׸5Å~úK+o«EL©h,PJ³+>_Õ@»ß½‰dnTÃíB|c$UuÒeª5ÂìÆ„ÞOdé2Î"|ÏhàåÔXc!0^?ðï™ñ?£—nNS÷ÿ·÷®Ëɺèù}žB¿ì±W÷ O‡#z·åmÅZn÷nõx9fb‘ „ÓÀ ‚’úDœ~öo’ȬDŠ¢&búfV3ë’—/¿œ¦›ú‚õ¿üekþû¬x¸“<gÛ¬˜èÊpØ?¬j^5ÿ½P9ëÄÛ›äÔÖ$SŠäRƒ€kϱrX\ ßë-(¾òu~)ź$x¶oZ‹ ЊŒðÑaƒ õ½d7MâŠÑ*ó.T Œ×òœG?qÅ£Ba]©Ã±÷>ÇÑ„'P˜8L®beýÊMVæ‡(gÕÌ“à‚°¥àRbté!xi]‰£Ñ7„Bµ#L{˜È4ºLôü¢c;Gq¬·¹¿ç=v¼PNÜêq¼z€©[ýž ¨®âí‘y·ñŽ~²è.NX—ü§®áü ÏÁˆL †Idhh°$Š+\æX, ¹z°¹F%’¶ê¤ 1ç,éGx0¾DŽ‹œ• ¹TËíR-×6âà«åLMça-Z-W£¹ÔÌA`Í\M!…ÇSPcÆ£õs½ÌØ¡–N7k3É+©+ZÑ]Á æä/cß;ö·y˜ß(ÜDÉ0„8ñ¦‰áX@¤÷¡‘T Å„)BàÕ&À8O³ó!M¿2¾2†ÌoÅß¼'é"¿~‰­ øÌTtËÜõ*Œ e† г5ˆzŸ½=\™ýíçŸG£û(gÚ~{xU0U}]¬3¿eB™6šk‹ï¡cX†éûDÚ|¶ÙdüR?«kù(Ln¾f0˜@éêyF€4–4§uq›¸dIeFæ€u÷មš„b^Ǫ¨T¥7·)¡žV·LS~=m+ÔGà{@ÉÆi˜6ãƒä·µî%W =Æé¢¤Õ°4(›1p•´†ìRZÓ¶ñå[ÏžÖl-4Jk•’/“£èfîòw9(Ò‚?Ú‡Ú<öTŸiÚøÙW^“¦„0’'ºyn8»OyŽÆ¢b:qY‰÷u®Úz\æÛ`]É[ð{°¸[NéjÞX;keÛ·ô©^õ¦4¬q3ÚVùL÷>ê{½Ýšïò>SâÛµÛÿªë×2xuy…ik+$Å4Ñmפ©Å|½¦‰¥u]L“SõkN›ýbNl‡¤g=(t6 ãYDH|P6UWÅH/†@e˜‹!°fÈÉ77!—í8MòèEÕÌ€#º+;+*²)ò¾Ò$—/Xš‹.Áå#j™,†fèÞï¶ÞRßÅŸ<õ@=)lCψhØ.¨3@# ?}†<‹í/52oèÞÙKÞÄ2L´w©¥ÇM`™NnÄñWZx}iE²†‰jU±ªÞlnbœõÑ0!¬iÈI=Ú2RÛ. …ìÚË8šçqšð›Òïnè_‘ðé¦ À¯ ‡"ªŠ:±@ÞŠ"¸ÜÆÜéΟç£ê½I™×"SÐõZ®‹Þû¦ØNƒ Ÿ)ÖÔTNë^¨b÷?‚6Ï!T±nÇÆŠ.Œ±ÕaÀŒ±¸üÃ!™_e·?jÆ«mh)œ¯A©ÔÕÆõ-å§ !ä Pª4Í£qΟì'ÁÍ€ü1»Œé4·jn#Au4L]}(N{ õ=§ÿÚ*†›îÛ\ªCëŽäùTKwìÑYµ…&Ô éú®)Cƒ@|û ]œÏñ$X í#Ê¿4a´1éWm)8hÞc)¶#VÔæ³˜¦xµQÐ4«¤¶hw'T]Yú%^uÀ,wû ©nHŒµ-_@LHû ½t……2» Ç_¯MÓ7-ªÆÚQHuÌ=þ¿(K U瘮Œ6k@´Iû ©®ô (ü»ª{gÙº ÝQpÈ©ôä•ÇÖ³¶}ÔJ8Ìà33EæTEÝDˆ',ÀY·™ØÕìƒk¦1Í‘&”ÓïÿàmÆ—ÙþÁÖ, xUÇѰl^[;eܦáVm K”ÅΔ,X$”$þ„‚B²©ò6Þ÷i:¹‹¹ÁOál¹TÙ¦¿5¹Ü…Äb‘–" ×Ä¥SZ±ªYkba5Ž´r±TbÖäÂîÖ53QñCš*òqlÛtT0Á£dùxU>×ÁM!ž&ìL×Åê‰ÞvØ K5Eh£ì•ò\¨™(£PêP3ÉA™ ]ÿ¯ƒšÉtxŠR3•Ö׌ .ËG¸†SÛªkR&ìRFÉ…”©·Ô½!á_ ‰ÝR¦A›m¤L൚¶ïºoˆm(y(šíU[ÿZœþm[ãi±‹T“‰IR°ò|ÐaTòÔÔGÿ%ÚÃe¤èT!Œc¨’&l›C–’׈”´Æv±Ýçqm#™·ñ «GXãâøj‚ûdŒ_ŠUÖœ·+îf¥üLFg™L:ÛMÉ;#þ¦Ðudž|Z<ßHºÂVm¶‡îÆÃbùbkþ8Ã7ƒµçz½`©]Ñ^ºËNî*å*ÚâÊ m/ûW±ß»1Jò8œ¡or`gYÞvÛ%0“äN÷$°àú~÷Ö\û÷Ç8å4Ý?{š=†É8ú%ÌC(kY5ßwˆá,;¥=Û߯=Sƒ4ã&&ÑtkéªW®åOqý£y;AƒÌ÷“[EÄc¿·U¸è®YÏóE?Îgœ×£Ñûré°'áLMÝâwøc-¦¦n¹–ûº”:畽Ö°52÷CKÖ8Öi súZó:¿±5• «¡•î 7kþvœ¤AgbмQO*TLÌï¾è¦CQ”K˜¬îÓ²' uGÎ ÁŤI'7ëÓÃŒH]ó=$5*—L‘JîG¶Ó8‰œ,)²…KPÓÐp£d¤ŒU!ÍÂ{ÞX …Ä4Vøö?Ë›¯,¦z»ïðþf_"UÞüw̾F{D€ÅùMtáÇÀæ<°Æ6 ŒÇn«õqdRw{-N»›m܆8¥+ì˜XË­s9ü^ Ù¶C«.ÀgÛiõ1D8µJp8&º©:¡[>”9g§W|›‡9à (ʰ`æ/ML r05VE¿0üÈö7ŠÇ¤,ß ‚i$tÃáê„0…""Òµt$$[9Àïþ¼ù+øõù¸Ç‚éŽ" èâS·æúÌ©K´°V)ôÞÄ6LÍ#â~W!øô>ÇѤ\&ì„E%V¯3µŸKÓ/o+¿ÿ´BË|LùõK48oT)3g?›Ç] D% 1âÃÝw1–ù‰Ÿø‰–÷éíSÇ­>}c» JÌÜkÇöÈÜŸ‹)išä¸7pŒ¡êƒ]Nh±ùn>ܺß2óõõ5оªÛÁ8õ®Ú“„ íièv«IôŒÇ3ß…“êh ñÓU¢[”ÛÏc ù@cèøÕÖ3Ý(ƒGé|À¿#›Áª­á|žºB¡ˆÎê«’E¥É%Èxý¸Æ÷Âv>M¶ã|mµº.×RÁ¹OÚj=ÎÍm«­¦ïÓTÓ½ýùdšgŒåS„yÆËZÅDAxIAw@õ]š µÒ/_7©Ò~â$¸‹îégê–#ƒQñµua*ô6^8YzS  µÞè9åëM>L¤zK—ùy\” ta"WÜYÜ”¯­ûSÜY\• ô^"6*ßIƒOÊþžB‰¯5ŒFò ˆEõ”äËZ‹NƬ3訣îuÓÜ×ÁûB9Ÿß\ŸKR“ŸG£9ë˜ÇHï6{þÍŠ“}õ‡õÉæ4\aC[ oÛ\ë¸È—Å|™'=¯ÐhÕKǦOQ6¥Ï=¯ñpó¤ÓKüvà’ëg©G0 m©íqߎK‹¿ú]ŸÅ³1QÞ»­ÖÈuçF_ÒiÏ+´y[á<]ô»B‡ç¼,¾&ã~—çòœ‘ÅCúü&_{^ãñflºÝXèÍsñ—ze 7Ï ê‚žç”¾,8ç”.“‰ˆÎç9§ËîëC™—4àh·ãót Ëï¡_I)¬l/>ÇÇÒ}@*²ø|ÝT5}h:c@R<Þ2B\½†’¡eÍ:Ø"DÍn,UÅìêXÎ1ÝAˆj–&÷W“ty8aqè[iÝ$y'ÅED#1Úx}sàØ2)2?å` #_”°í)Îòe8[m"ÎáÄõÛ€ó ï' ÊÔAOóƒˆ1¯wض ($ÝõÃÒ*uq“ö–ıÉûâë“‘ÄÍ‘:G¬ž¹¿°<Š}Æe/p@Ô=Ër\ËÒ\ÓÕ|ÛÖCáíQ¿¿£S“‚t;èdl­v)FÅ|OZVðá6ýE¿~ê/lvtfcæVåàJThpSTŠÅlk LÅŽr«m§Ž›0¤›Ç ¬\u 6yL Ð0 OFy0ÛƒíL;g݉á XÙ¦osÝLç‹ýôâ$æ$%íPxA’¨Aß Î£´ºÓÜ*™$^u¯ L>.ENwïzŽ!ãå}mPòdùÌ—„7¥¥i¦}’WíMq÷¥âtÓã³tÄŠ Lµ ±òØåKøèÔÀåS`vÆL7磇xéɈ³¬…G¸ùÛùoÆMhÛÉâDüCó#*ÄÚ­k€&•;QÜ Šw»ž Œ–R Ù|˃¤#÷Hf×Gçì‚ÒÌî‘Û¼{^ÜFã,Êÿ3ú m[ÇlëÜ·î¤&}(;( Óši9X-ª0NîAÁêCèÄbœÕ ­¤KÊ:ñ 4tß‘L•§*´åŠÐØ…=ç¬ALg›‡:wŽ©Û2¯ äO†Í#Io¯-ãAÎ#Io¯-ÝAÏ#Iq¯-áAÏ#Iq¯-áAÏ#Iq pç*îœÓZÛy¡Íé8Ì%õÔqˆræô”ç!aËékm4<9}­Ž”!GV~q‹$`Å鹜…‡§¯¥Q0áô´6œžÖÆÏ~ÓÓˆxo¤àöoÚaèÙ oú ×MO«#`¹9±2yH†£šùc»3Σóˆ£îIãý¦Áìó‹yÔ=ùˆI="'5¤yØ´cçvëû˜ Ï„T†Uu§‹ 8}Õr–&(?Ýpo7s–ë÷Ue… ÞÇy­CŽæ)…ú601LÅ+ûÌs@ñðýÞ÷·« ò`ƃ@u¦ÆŠÇpª‹^ÆÑ<Óÿ°n‡Xa&Uîwê›0íaÀÍèàiHêÔÀ“/ßC û¢C} íßùkqGß$Óô†]ySf̀Ƣè=BºŸsÎ=ŒFßðzjÌ|´ g¯3·Gƒ`üóeÞ@äøí±cºñ»ôðt÷¤%±…gYK´=¸pÿ.ÖøQ¡¨!byâ¹¥M]7U󮄨]à 8“òR6Ct.À«hfÁ<Œ!a™¦;À>þ¶üݪçÍÒœ+o8¯ùòñN*Md X;¯RvƾàX±Ï[1P1÷§qyZG«€ºX‡¹YE‰G~Ô"*îeN<¡d…8RÀ;í_AàsXFu^ð v®º¡v"åBÐá0¯4•T½|ŒOv³i^Iå©aõ]À{GœÄl<èð±RšI @’œ§¿ça!¿´ç¬j¿$ [J qAƒà>Yã——âÆª«x¼cbˆf|Èw;ºÊ!Ü †ñŒç30CråÝ–µ#4‘RfóðŸ2Wÿbkþ8Ãc­îW÷~ÍÍ:ÅÿW±†÷Å¢$ÃÙõKq–DáÑzR%¶ù.>×ïk€ŒÏÞ.§ó¯°°‡ÓøeÓ4{ “qôK˜‡“;ª‡ÖɦlçŽ×>Å^,’¦ p/Ô,WtÒúLæ6±OÅwU"US¶iH®æ} Ì(‹Ê)£šT{@:¡ÎŒi(e_GRþ¶{è3½à S3AybýÏÅ û—·ã[<·½@ÜNðg¹qJw{¨÷îå}}7(,øFäiúeQ^X'ÐÜ¥‡œÀ€ϣ—¼¬ HåtMM‡"þæ(º£w=´ù¥ð9]Àµ •Äs:CÇ_ÐN;¨WeEåìz€}s´8C‘BÂf9Åžè1-·;JtϺ¹?­†,-ÅæþVô0°±ìÅ]¨“çâ&Qg›ÈUîÂ^ºði Xàw;ùûU†>¥ñäÇ7kaÞ—bœ&¬(t]µö¦â^4þP °ù\ùËu–¥Ù?ˆÜ¾ˆÝ_éÐÉ…¥‘ Ýß} ×q¸€è/B«µ–.ûÉø&˜¯a|’˜{•2Âó=(ÐUÕïaÛ_œ¿WgUñæË,ÙÉ\2û×e2þ˜Ó ³MÍöÐðžÊ~Ã@wgLWTox”Í*.´fR¸¨fEÑ$^…ºgƒ¨òz¦†R´4ÂÔ\l\‡#BÇøÔD0<rïŠ_½Éö74ºíp²Cuxt_ôæÞ{ŽÞZòŠºèÀ®¶¼yF~š5@W;¤Tã™ò¬aÖ1Pâ…I@)X³0㟿]_a¿¥é ó.YØÄ­ð*¨ëvÚ¾!TÓ˜ë(Yñ\}ÓÓu¡Óv_Coœ©ù°“Ü#´§ý¡‘T(€"VúµßÒo+¿ßd²èú%ã4b®î„Ô“6©Ö%9ÜØÛ+zlôõKÕÛ{ØßÔíÏcuêÏÅ÷QÎôLqÔówx>-6Ý͇Û@÷ö'¾¾–ú¢J€ØÀÿXø¨pÓ=Îf¬ ãZå½öú %º®£»±à_ °kpØGk VYñŸÁ\¯ô¬­+&\ FéC¯š©]÷Ä÷ä°u­IÜ}Ü ì™Ïâqøg4–}œ GÌqÚ‰€r˜áÁÒTÓÅ€2‘e‹um} žñçUÛBTÉ'æÕ½IØ;±ˆ;z?§¤eaÓ y …½er^'Rÿ¥›ÿFùÁJäï²,üJ%nñfNqýtÏ»Õ/ãñü£3˜a™FÈ5Ò¬V ÆÁjràŒ4¸{Œ’WdÅŠ}4$ñÚŒÑàèïÒtÎæÝYŒzv¤„€Oz`<ɤ„ÀʤCÃԤºbÏYŠŸ—7 ¶a4ƒ‹ - jòï­€°9ªÝ Õ½£IXohâùÏŸI¥ci>óZ:4Xçšt–Iœß-§”âñt_¨ý{¨Íw`˜ºxæó(ƒxÓ [ã¼4=9· 4»Î¤;ù—‹|G3nb—šŒ\9GŒ‚³iðÛ‡\>®œ ,~:0LM<ÓYÒf) „þÀ0{$ªÖUZÕáÐWOãnn©ó#°~ˆºgªŒwv Ö1c~`Ð󣱞ESJrï3a±NÇ”Bqd\,ïv](Y|ÿ@Joȸ\(žë†»9ŽÓè4&åpa§±Â1.d/Tc¡n´"[ç»dàŸ¥`ÿ•¢‹*æ.™ÞÔ-Ž@ S×±¤9Ãõì £Ó3;øè©¸W‚ñÇĵq8éà‘¶q$™Ø´h +1EÚÚ‹•·½]§ÄV¿)Ö©lí«n¹èv€h}¶fái½éSå ô²Û†béTÝS;ŸÝšS\Q³ÁdRÇKÎÂEéÙeúømû%ž}íÝŠ›cÝ_çÒžªtLn º )é—Æ€1MC50S/N¦)Ž~£P5 ˆ·ìqÊÒñ §£bjtÌU$·Lñ}M®iÖYZUªíΟÁâPO‰ËpÑ`7 •Ía"®iÒô¹ªUâr¦ÍØh›rm6¢Î9\¿|Í>ÓdU°†—b¶11Ã!ňT+»†>½¨ì÷à~œ.¹AƒUbHÍ1m,ºJp!®2Û‰·é Òz“»$ž¨&¾º˜àDS8\ôŽ-'¨ßÁëÎ{ÎT¾¯‹°oc@eUcàöºö–ü/”üùÍU°"IaEíû§çÍÊGZ…èVÝ87}D° l¯~Эz=Ër\ËÒ\ÓÕ|ÛÖMÃ+Üj­ºÿ;€<£9¢Ý×rºn¡RÒ…ýÏÏOZVðá6þE¿~BÏìvÝ­3k3·jìxõtZ…©ö›´ ©tþpöî½4„>§~¥·£.ÈÕ×ãìãg¾ìˆ#v;uÉŽ(û(ûøG™C‰+˜äÀ”ˆƒ 98;™ðM¶4 C+‰•l;6–2´|–y˜/k>n^çUoðF/M…Í,˱D%®p/m5]Ü'Ë`üò¸\«IÓ·« dX¬çgþlf—Y¤';¡µå$=1, ÐÅhï ¿Øš?Πm1µSý«í}1£ g›fªjöâdr{€9²;Å&ÀÑ‚©}x Kzi…k9‡µ’8ÒϺáx}TŸpÖoþÓ Ž¿wååƒÄ—öÌÐI€í"ŽÆ¸Ìâ§0 ã6¤A¼iúœ‚{ï+²Ä8£Û˜ð( ¼ ºk>?„h|ÁÑÞe·¹nÖæBu)#ÂïZŒd‹·¥ö6^'÷8;\×»'‡ÐR»V“µº—¸P+»‚,È5Õ:Òã2ßÞ@ÝïÉÖ¡jÅ]“0ç³%'­w%ÕmY>O®[L{êz>¤ØßÀè'Ï›‡ô ‚3!¬èÛÑ”ÄôvÑŽ‡Wì>KØc®r{<Ý…ß=/n£ÂÌÿ3ú*ÊñP§HË…ykDÎ7‰Þ]|Óèµ\Èy8à®ø~±†a`ûÅr6……*c l_ÊÎ<'ÖKú¹1¼ªIh ï"Á£øz÷]E›dAuE\dýYÎ[®ß‚µ»l¾>ófy×É”´-`˜Ìv«³eÅ€Â§Ú Ôyr…|2—½â)åOÁ‚³#]ÅÁ¶uïvañ¸þž¤šŠÕá)š»²]õ°oV³C¸˜wÿÞÕ'²33Îp>u[ÙX¸&–ÐÒ>÷­æ`™ÅœÆò?²xéÞÒ¥0Tð“ú² h0u®n Ësi#jœ *Cwl[<Œ£8tØ€U4Ï¢q˜Sa8~KÓ/«ˆƒšnj‰j Ûõ±lî‚Ðtª"\m dKC¹Ïcå nÂFé"¿~‰ÆÊ2åÚ@œ ÷ë—7¢ÌóùZ”ßu/Sæ­R¦á’¨$ ¯yü³Ý3GÈjXÞ- ª…=¹I±Pè=ƒÏØ[šGÑëŠÖgî #¹Œ«í9霠1Ȱ»˜ÁCñÑ!.v1H‡Ú <Žâ§h½©eàPø¾jIKwW ïãG÷Ñ‚û`û©r4ú†WocævŸˆ™ÛÑ~•™ß~þy4ºr¦å·‡V„åh=Šü`—ÓéîÞt×(<`·“â‰wL ‘ Ö9ä‡4ó’¦ùª‘¦‘=] °Þü9͸Iâ+˜ºìù= 8&°9T'çH{Ìà¿ ðõSåd)ƒ0Xãp~§/WOL9¹üËT¿~Ηk½6¹0}Óâkrq†×ë] ²®"à²ÿ±x“pdî ÈtµU¿’IÔÝ9;0"mÌî„}I8‹¦ÄíptÛQ¢¿aÓLx¿n ÌbPz”Ü\e‹û1,ÝD»{3»ýL¹oXêÁqÙ¹l84¶Ãn”Ñè1\|RQ¡zúõ•+w¬þËëv⛤Kr•\€u?<%ª¡!R¶]2DÕ4´ËAeÉ£?ÏT1ôO´¤2²$@AëÊó:¿4{v:«¦«Ìî á*‰O2‹“/¦­lwÑààܧTꉖ¤4•eË$¡Ç¾ºº4•e_ÞåêÒTvÈMeEºcõg†m¹Ü-0snˆmM×"¿t6=8Ä:3îõÕØ´dh©œ‚›çâ¯ôJ÷Λçë뛟nßÁÞ¢ÓÙÒ^tsnûl:Œei„ʱA4BEÇ®OôAíyÇì•Ú¼îëMK;­®ß–ª <«Î«p“Y†eoØšc682˜*„}”ï$o=k¼Fx•æÑ8¸á}˜ø¿yÌÉÅUÃeè®Å×DNfr¶W¥YœÑñ”5sÇñ¬;mÌ«ÈÍ~¢É÷ºxµÖëâ$&ͽºÅô’3Üê\ÞþšöQ+½mM ¾†‚ÑX%Õa$?í#Vk&\‰S1»}…Ô–,ƒù’ð¦´\ßæêʼnT°£cû Š)î>¢Tœ¯»J4LndhÕ fÚï\‚ÙÕ©ÌÂá¾9#¶•SÒO´ödì[îòŽ·ûÛUˆÏJ º¶„Yå;€ Œ%Ñ3èf²ês¤~',×òwàW=ë5‹‚1»ë @šz`¢øá& ˜øû2×âÇ9aTÊÖlG[mµ5EÙg4_H®ÏpÄÁ'9Žâ¥êÊeç1N¦)êª54ˆÐòT–³CÆ¥ýR§!Ķ_ZiqÝ ªÒÆT'/QNu¢åÒfª>û-i»‰dÚèž%ùÇ’•¶ ›ê…§í×xÝ7_Iš8-®eYÚ<Ç…¸¨2íi&¤ÿ^ßõ ¬ÃìªB‹ýŸâÔ‰eíˆ(£k¸ÍÁ•Õ_~¯?6/öL’†=Ö›ŒZ1C÷HK¾ô¦f Ê×=‡ÍÒl@ oþ¾·Çتgôu3&Ï0Ö ¦ãÏF6û4lõ•‚½m×{ŒÅø9zœÏ Ëw•M£°}K™ŽîR`™<þxûÞ·vJWÖð÷ lgäcK£ˆiá8ëRW9+„£[>7ë.þnò/¢wË.kò)œ-#þ# fBÌÝ“É-cé.d¸:ë¢$CXݓ̧0™¤€‚×ÖA+RáI™ˆaá’åã¦+EXÊ {:]/T•îu±t𛙢IpK.?œMŠâÖëȘ¤®Chz@PâÝks¨cAÎÞ™&dÞ½3wõp…:ú螉ÀÌan‡Þhú l%ÜònÞï…“líUw•ÖyWU)£Â§`±(ô¥"¹‰oÁìN¬[…·‹uJ¨}h$úQv‚U³¯¨Yáfœ ífÛçê,!ÍêE¶Ó8‰ ¬uDÉÂ¥p£zn”L‚tZìß4 ï9Av„Bâ•í·‡.ÿfÆÙÛº}'÷«ôÛ›Uüo7xºi5ת0Ž"OÓWÑÒÐi®ô… "Ôâu3:º Êæ uÊc¸–—tÝŠ‘…¶æ×^çÀ§uåÙéÎ@Çl ¬·¤5®ôC€Èû2§w¿µqp„ÊÄþ<0SÙ<4*?ä—Ûp„‰Pz&ÂÒC–Ý –ÞwRãð –w°¸°ôzwÎáv0È8äìLpAÒ· !IÏt¸·ÃÔ٘択jšúÕ4=âç½Í,Áó P/øÅ¯tæ u”#âÍöO8%—àÜ+ œŽ2alÙ.ŽÌÁe*E§¶ñ®nºØhE_ ]ÓΜA½A¡ÓþÛÁ4j’ÍûÉq:ÿʉüeÓ4{ “qôK˜‡¨‚ýÁ@-M“r¬Ä-Lt ½³/Q =U(ýuŽ<Òž ókO·üîd#ø‚@ÓÕ‹”®¯Ø(é*TO¦$d$`Cï^B‚ØØééCšÎðWæ;ÁîCNF÷Ûð¤¦`!xŠçÌF#'Ž‹Oö¡²€µÇDBIŠŒ³'á=l:52Q8éei@Ž'”÷Ž€â©å†\f1§ýñ,ºr¸¾ßýŒ¬zMüÁ3-GöÅ#¯šSÖ]³±î¶d˺P‰oÛ€wfï‘[Ÿ¸ßÒôKÉ×Ð} pì4x[®„æì9ÂÍ}ø¹’Í#W†½Ø—Ä×\G“íâc¦nvO;Vî›u®@ÍoñEuŒÄß7˜zÿÃmm'ÎÛòÛé½ú««ønIó°>@9ºó¤ §¯õä {…ƒM&–@i:¯\±VáqŒ†PM“ˆ°w¨n»®Û)uæòt9Ÿ£mËí˜UgÍtM Š"ÝÛQJq³ôùGa“(¥¸Ò ¦S›­»27 A@û Ã~Ü—ù6bAúP>Ç“( x#dµ]Àe‡#·ÓÑ>ÈkÞ”—·Œ;ôkä•n€$̲Ðׯ}HÙ;€"<òºwÀž^C1m,‘`X#M$ŒcévêçG•ÁJª{®¤œ¸½í‘WÂXÙû£Ñ7®h×1@ÊiŽðÖ¦™¤¼!… Ýž©ZóS¦âò·¿·;n‚©œŽ[¢˜ŠË ýÞí¾)ø&:Îi—“ÝŒ¯ÀOÐ}Ïñnß{Ý·Üz&ÔÛíC§Ótè:L@šŽ¨g—¥1 h’¥é!Ôô4Ï ÃƒºVõ,r(+¨ •{ѽè©} ÞÜ‹,šŽÓeÂÙÅ©ž’qeü‹ÕE2•é^Îb¬ÕX(O€D5æoM5…e TQc¢#0íDG±L·¹³šÍ.'Á˜èžm)…ñ¦ê6"‡ÀWè)¦+»ÓMhhPP2Ž¥ÐëS£÷ÑYP2ë.ž9] Îu€\›G«àÆøÌ’r´§8Ë—ále;q'‡ƒÉ%wž ¨ŸÛű9<Ü9:6ƒ†=Ü;#†æ˜¶2ÞÈú!kðÁŠO|„aˆIŒµì.yŒƒCh›uIì¼m®ºYÛÏ7ÏÅ_é+½daœ/nž¯9b±G;UQð¾˜òó›«às9ëÏe¿£–söæj^Ý-p{ýd›Ë<Úi8ËÜdStϲײ4×t5ß¶uGÓð¤=qòwˆŸÔ±=?"hËɘ´ßÜ…'òÏÏOZVð¡Ûê~ѯŸúÈ´Ð-PãX`ë~À¡ˆ‚ Œý]´ÃÌ|%,ãP_œóêzÇŒ§†*Š¥¡UHó8—†Ù–^¼7Ti:ÅS‡Te!xÿ܆&7cwñ§Ùd¡ìQ44CBÃs,#/' dÞÎl¼ét:6^ÞEÊ hhš-ô•3=¯#â=ÑR:5ÜEI)wÑGÒŒÃ]ôñâ0w½ð›ñm®û- +ÿ¡– _óä’”’ X†2ïyIâß,Á'¶u•‡«V) r€ÓTAÎÒä¾ãwE„*²¹Iò,N …u‘Ï)áhPFS‚ö^ Š[Ú 9f'ñ› Œ2Ä•Á@o¯.!¦íÂÙ+LCÕM)O ²ºdxzÄ¡«å'hLÓB«ñUC5Ö†PO8 |œ :‡ï§½Ë]¿rE§LÀï^Œx‘÷î)Ѳ¼¦„[×3ì™%ͧ*ûZÚ6ºÕc¹  @z½Cµ¡¨¦‹n~Ù=‹MÜO Ðͦ²l9ί6ý\ò|þ>?DŸÓ/Qò®¬L…õ'Ú©ò¶\I‘’n@6Œ%½% ÃØi@ÆŽhmß‘t°1|nÿ0%§ÒW¼ïŠSá”r%”¢û:Gˆoô¾€R@Ã\@)‡ ¥hÇsÊl'o³t7É.I·Ùâë,\,2³¨ëÇsÊÃ\ôqÄAûš¿Uo«>þèªO€¹?N`†¹æã)þA®ùògk>üäšOà~¹æ°Ÿby+ØOËÂÃ~†)B¯_â•€²UI|ÚÂWĆ-щ Ðì´‘Ö›ó0Î>]Ó3c[þnÁÐ/÷oêiµâo6zE*pÞ.PqJ§¦&%~iÛ¦ 5Á© ;ñ ©m²€ <’“iŠZëÉ·±5œAó;M®S ü/†‰’<gj6"·l]zihÌ$ÿòþ `¸ó÷.˯DçÏ•R‘lúŽ-7ƒ^fbUÍŸ[@6kŠ[ÓÖŒîÛ¿5ƒ‡4ý²¦Ïø<.`ú½ÛöSô¿—Ñ"ÿ˜EŸ¢qô[ hÇ™¼ÝmR›Ÿ;¹o`,pÛÞ®€—÷wMaÙäÑKÎùÔ¾_²Âå'ÎØýD¥6†–Áª ­/ÔlQ02fâà™‘Îi‘LÂʧ‚8l•Âpp/p‘’Sd°¨ø­ëôÖÝOwû`•ž&O#×>wÍ!íÖ/ÌÉw³Y:â  ÝqívtaÆ*SHsïh˜ €Þ¬{yŠÆy ‰¾ÔJfp¤)ApŸ,ƒñË …å.XÇÏŽüK¹[Xì­Ø:Yt'¬„0ˆVÄf+{•'^›TʈÄj†q¡UlæÎq¼†ñ£ëA{ÑQÅscSµÍ÷˜N¢ s SB…´hO©T—BºIÉ1úȬpõb¼ºÚ€ %l*ª¯^@ŒªFGl]HßÕfLÒñ;Uµ·bFãJîFÃÅÅÛ{Ùº'Jì˜ Þ»^NaíKåôŽmb#<‰WŸ/ä4ÿÊoúeÓ4{ “qôK˜‡Ðƒ8¤ myè‚X4ã âØÓ`¶ŠõÎàwReU—Qq¯šÑã4OÇé¬ÐðúwTÒk¡5xgS·|da‘‡9QVr±€êªÚ¥ÌÑÜ¡„È0J]P™¸¸ƒ²íHáúp\4‰wOJ›4.6÷ŠÎ¡é¯2g§9Süòk1вé3XÐ†ÑØ~¾{™ÅèL7 Vú,Bü-jé:Ô¢ÔRô§m´§ŸÂ¡k‘\U“€RU¶«›ƒÏÞ­oÅd±x t ªÝã/Ý£­Ü;PN¶SÃhô ¢ŒÆèíe_T£+³ø`—³˜Åð×?`¶}·ý~êu†Ù(ì4&I²wxlÕOhŠr'ÇéBOBMƒcuǾ÷§¹·•ßoB3é"¿~‰ÆïpPa6_80O·°NEߪ̢•&•=™>š$‰ãd²Oý©³®B5Ï",H£(L¤³YÇ(ÅQ"ŽË“Àåuì|Èóù:…Á{"‹‘Ö'RÁ°£‹Ò>~bjÞ+Â=¿Oçq4)—Ù^ILæ§»}•=5¦=&éoÚvz›ê´Ÿ‹)é—÷h7æî»±ØT7nݪOZ’aÈ é8ºxÄÖ]Á¡Ê£à&ûÕaálvŽ¿¬×$ü@9<”UŽ)ˆ´³+7f—1Ä‹©)Þ…¸Re4/(}N§’Ô@ŠÚ‡ªÕdeÑtœ.@š¾}ÐJ&Îv•Š#ÉÅõ¬8À!jª¦¸þ”Nm–§ù®½/¥öA”Ó[°`/™ò<Ç– :`«ôöARݘqßÁ‘£ TVIoì„jÓ}ÍæSü³6ß.oe‚FÁÍã|ÆYûµ „†´¡ÊŒOÀ@L0Óµ»—kÒ™ÏvAùú¨ Ì,´|vʾ SÃ6@V}U¼H Á‘b± ÈSŠúÏݘ7iågYû%á"àè‰ÒSÍ™ª{Ç&ßÉ®rtg)R nÛ1(}“#;æuMJQuÌû—a;™ÿv.>O‡wçü;%\͸ Hhï5¥! Ń*¸u{î"+ñ&…åú軤§zf#¬^÷]suŸV%þ‰`«^uUèâŠséc™°˜žã žõATù¥÷ )$žæcK"{ò¼¿Taî&Ç^g§»¥2o›ì~ «©f c,ó–a}xÓc™<éZ@lº¤~€ì}¥éÐvUAãéÜý‘ø²îžúÛ(ÔÝNPá`]î‡Ì¤:ëWl u« ˜Ðû®ewiqxpˆ54а–Ø$ÔѶ†öráÎýóó“$†|¸Íu«þßÝ<7{;=__ÿ¢_?á×x¤‹!å5ž5¶â*·±:-ßÿêHóÁ†€¶í™Võ‹ `Ù.–^LáöÓopX Ý4ôðG«½çßß!•Û;ò‰ÚdGzë;…‰îˆ¹'Ž4Ò£[ Ï%Ѻ!ð-i7]ïtϲײ4×t ÏÔÖmßÀoÛö¾t7ÐðÀ]ã ÛõÓx§,Ñ.!ÌP¶(T˜A݃m¡¸à±™!²œ^¥/„ápP=×Ò¹›Ç•?Ç_µ— Ç=¥ùËd­„뀃5¼§$±²·ç¡hZRÀ])„–ô÷(gqòå÷tÕÿ¤2/i™þ:mÍD3] L»âî\„ëK­h Ÿ³óu4§~J]¿¢çM/“¢R2xö-í5«ª!W.ø`6Ò®š«ü)']…‹,N¬§dÊö¨„— B="îhà^.\?ÂwËÓðÄÛï–ac¯·èeÍó8Mx^­I°F}”I‰ö¸„¶(eO¢@$B•?”¨ÆÕ56@%Ùp×½ù :Ý14{n;ë±\ ÅNûm9ÞûÒevÕ9IÕºŸÆStqN:*ÈpM` ¢#ƒIG™†ä²?2ØtìsÇQAÐð÷T)›¹à!´iZÚLDá|Zçî¿34‡}ë¸K)Œ€rzZ¢‚pŽ=Ói³;k ß ìŽ i™ø‚Œx3‘ zñ\í.£†­kâ ¡k  H¾ç8h".^™ ‰žàžkH¨jõ}›^í‡ã@ù°¦¯;è°&P8[&ð:<˜Š>+ŵ¦ëŠ3]¦y4Î#€×{`PšfMö¶`§…]öíCïèÀLÝÒ­ó ¼¤Ö_w£} ‹[–¥Ïšez;j•ªÔ=ÊK4G§6»ðdœ¸ø.©õÖöØ>PMoÏñ$ä—ÛG¬¨Í*\¼ó »¤V›A©¶»˜ÍÙ.®HtÎ@›·}…¬“çÇpAø²ÙŽkúÊp”–™Ä"l röv¡”!¦i.•Û§† mêr!¨š ¬ZéŒ.WZ TAãt™ðaª Yƒ#o‚ɘ ûëS8[òÉ+bu|Ž8rÞUû/~<Þ1¶ qmnú© ËÇ×DqùG¾‰å'ì³*JY'ɇ²}œi_¥CP>´õQáªø“XIZÃH¦Ž±:Ó®n‡•_¸Zl ñT|¶®kþÎöVê®ú0Œ …oh©»Ï6Nç_9]»ò—÷Å8.àjîçvVG½¬Í[Ùw»Ç=jz[ä³à)ç)À/¬±Euî0¹!ú³œw•„/ÿfÆÙÛJ¢aÁšT߯Nó›Uü¯øäÚ:ÂÆËˆ$,z7Žo\[šöø‹öFÙ"ipd¨?‚‘}Šú¬«f…VüTø•œEPWtO8­³8k·Øt™ŒYæ1¯Ø”^÷>¹œ¤¸Az•W‚;£§u¤ZI^œ<¥_ð@ðõ•¡ñT›÷¹o[žé£ÑfW¾ýé§ŸOBÛÓTŒ‡ySÌî¾Ò¶“æIÁZ°l^a.ÆÑæ×^¶rÛ> ~¿ÞEÁ2 ³¯³?âòwò·àCýìØ‰3H$ïÝð­áñéç©(…˜Ò=¾æòØ.8«Ž€P¦/ù>†IxOøû ¨¡ÎSüº>¤¥s'å2°'ös›š°ãO—(}J|<)xHÓ/‹`úŒ†æà’û±¨u[–Yt%“ßRq'‡×‚# ˜ø4WÊÑöáâÉ8¬ën×xܰ=gªax\ö ÛéŽ2QQl-K\S4üÛ|)7¥¡œµÛ:µ½T˜‡¹T˜vþ!¯0=\;¹ÙÎ[žù?–ùM±¤ô·ÆV_“̯ùÈï–Ó€¥­ÃÂYjüUúÍ1%#šë?Ri©ÄúðÁYÿ$Æę̂°úÃŒ! ¬þŽ«?B¬£Àêõ(°úãU¼îúÜ<ßæºß²¼òôʪnž¯¯û¡ RA˜ƒ¸DP‘d­@šÚaÃѱ0M¡e¦j7 µbkvð‘8ÝÑ9îdW’G/°fÇûµ÷«Q€ÊãFvTwJs,ÄËgrBdƒÈu$ƒÈB„3§@CÙ||w;3Ì›@æiy4q ÊV‡˜D÷ ÖK*ÆÖ•è «Ž÷ªãž… R& ±!O"~xÝh(Єt ífF{qÏ;^…í]³ùú˜ôº%¯ÍfW².çñl™ñæ”6ã 5§Ï9º»§ ÑèXUéŽcû˜îHì´eºç‡Ï},dòá6÷6ó¹ëé®%v‹,î  óFBjyów—ÅSO~T‘Õ¢2,/Lá!›–ƒ¬}ªÖ€@\Ö¨Gµ”í'£jIÝä•qLRÚ’á³g)â ^­F‚›ÇùLÕ ñÒÂ@lí!þü­ŽL‰Ãøý€=ÓÔõjfÑî¾üJ1 %DoÍ4xâ—á2Àb]½×:äÉ&~ÎfwáøË¥÷qò±¸`žÓlò?Øm/O8€½ƒ­2D5;(÷ÅÒzE(JPek®è“®{>O z¶ÂìÎY”sÁ™®Øà˱T­Gg*ï±ØºçbM1•‰“iÊ“?œ”YÂxr¥: „­k– [Ú6t¿ûƒÛˆš®ríùßrœmXm5úø¢ ÃÂ*‘Œ“eÕ²é,YV7£®²÷â¸uTunKqJˆO˜>úQìQŠ¢ht!ÕÁ ãÔ×»gôšÆé4žEüìHŒûV]n¢•ÐTnO×@úüÔà:gâ|Ã?#a‚~|~]àÍÔ<Á„ð{êc£ŸK@i÷—’×ñ½“§Ôf‰¿aM ÃêMmo+¿ß•_¿DãŸUÕ¥'£ŠwUâ‰3y¸«xqYÓŽÝ‹81Tu¼83Œ´ŠW·|qh¶JÝÄ6C"vnÏ"@a tmaÕ>~©Å&aQÖ!Ü \ÈK-6p˜K-vçAÝ~kûy[Kv“ìJÉ*}](‹/„;ÐIX•Õ¯¦m_ü·Æ-#où'Êà‡¾üUðÃÞ:'Šà¾øãå«Ã^ü‰øa/þDü°¢~Ø‹ïPÿ^¬sUÿÞ²<Áõï—¥Ê÷G{knÁ‹GÈDî4šùX™¾¡ÓÔrö@AO噋*=~Èóùz†MÚµŸ+ ðÓ<§c¨Õ5ÓS“X zÿI@©,W3ÁÓ WZ5¯sBâñÛÈ>(~þ¡Þ ì«£p»1ÊiÌÖîï÷5ÛÑêG»œU×+ó઻S6#>o»€¿·|ð§hÅOÑj|`šg8uy0ÔF}ènì{p@j£šØ0;ã³*Š‚<~׎’}=©QÍæê%Åì–Ú¿ ¿{³_îRý«ïº;ñßs&lh¨0vƉåh9êi °%ëŽ)á[QïíƒT Åâg¨Dߊòe¶>^¤/ïÁz[|̉pBž+¥Ü¤˜·»ÿÛ{½²Àv&EñÚ3=ÃŽöÅßx®„2=SÓ ¤üôЇ‹\ý"=C7¯5òLÒˆ}'ûe²ˆï“hrµxH3@Ek­™Jâdü0eq¢ø{Îr­áEªúVÅ¡‘ai˜¦Ž½ò¨uXÖ`)}ï±úR :4 ¬(¦®U݃hË(je@^È&D‰(Ú®ôbHöÐLñÖ£hï×Ößoè„gÛâ³å°Fc(E²;c?#¸êwÛ ŽZÊúR½îp©ÏYZl-Ýeçnð±wÙí¾é»ÞW8ÎKÑ­BÕ÷:`KWù9û*¼RÖörä°û¦Ö "e¢¨¶tTú(ººøPa·ÉüRÓð*# 2N ¦a/QòÈ«ª·g)C éß±å¦;vºSóº,cp,Ïp ‹ˆý){ò˜ç/^{ñ8Ž òÙ£<ƒž‘ÐB_Œ H´ÝY‡!;)tð&7U(ü¡‡ãó vn³‘F!Êx€OG“ι×%¡îKà£m0|tÉrMéþkçû@u+› 9a&餧N®È¸0åóïâý^­S\ÈŸ‰û_ºáý#ëâsQ¿Ë²ð+•¨¥x;<ÜkýùÔ½|³DJ´\ÞžFtœÁç©5}MJOuË7±zDu!=Õ3ReZ†'+«ëœpËâ2Â…È%GÈ-Ë•Û0m§=/,b摚ªcnö²ƒ¬}?ù/ýѺgÕKyºZÁè ÙQ(fM‘Z}..Ð ÿ—a;8?@3߸GÀrmt LÕ«a88¯¦û@emެj\µô$سÀÁþüUËÒ9!°ut>´§DUÚšø†Õ†oÈ`z¡Æ`Íhn’izÃ$ÉÎ3¾3dj tþ0V2Þ¤âÆ0:;T5nŒe.~ ’ÏÈü%Gòûò]_|ÆÜv\@³aAp/åk¬aæ\4„¹Èâ–*†7·˜6H§S‰smÏŸŠu\ìû‹í/QÕVTΫmgñr¬_gá}í*c!lßC|9nݪB£!Ö}mð÷íª¨p;ÐV8šxÕÖ¼F-ñCš~YÓg`zmw[€Ðßžw´ëWþi™0òzña ÔkƒÚ6:ìÛÝÈ­©>‰žƒpÆ,©<Í6T5â‹âd‚ûdŒ_ Õ×ÖÌ»4•¿蟷=/MwÞJ\”ÉMp×)H(³òx–m]HŽ‹©‹Ïryk¨P=K“{,÷®‘ÁrK[Ÿkʯ$iÏ2«n¢±XÃëîêï(á2Àš&€šÌ}Ó„Mü¾x îÂñ—÷³8Jò÷Q–ÿ’Ù(¨ 0©‰"$3½‡øè¯á¬ÄÉ}iÓb6À^s1bŽk¢‰r9®mó¶Çj+žYü¾¼¼±A|ùu¹eÀ©OÔm1¯ø8~§@­²/° LcŸq…µÊ¤Ž LkSåÕÄÆ\®o@¦?QA›W«Ž,?¯Vl LÆ®3Œëºª åój2¯Ö5÷B@©躧çx™­J8ëÿäÂ÷}ÿΖë¡8š±c “ÈÉŠ>†Y‡³_Ò„ðXˆ.Z PÝÊÖ˜GY˜Çiò!Mn—óyšåÑ„ Z•Ç~Aʇk»“ÏÍâCš¿û%΢qžf_ %ñq’!hÄY•LR|›x À~ “ÉŒC\•!\6@(@ë ;Ù¼›eÅãóõÓ2IâäžP0<ý[q‚’ ´RÌ2ˆ’<—wN à$”ô%`ʤutþ+½“ábñœfjáØÂ…´Ô[Ù ç}V¸ {¿‹ù×t™P>SŽpáé‹Z©X6Qö/Å™úM— Ò'œ§Û2N6ÀHNë ;Ù°ª‡-#ºŠè{zn¤jÙôbÖø¢ÅÂoÕT„òßÑÝ/áÓÇ,-Ìâ<Ž…ǰ(^pþ»¸*#ë'!Z—áöë"‰Ÿ'C¸£`Ð: ì–¹~‰!јÖ«2î"½¸ï²ûåcñtJF¸ƒmvÐ:Èždn£ì)Ê>E‹yš,(C¸Ÿ`Ðú ··ÿE}Áw l±­ƒÔíß_¢qöuÞƒëd÷  [©H'LÆÑŒÒî5Åß1´>Á/…<îûð³Mñ· ­Gð)zLóˆZ*â/Z‡€ÌÖ­‹EøÍÂÿRW„ò,îÅà8B8¡ÐúkûT[Ð>fU&£0&­ðäK’>“?ÍÂÅÂoËUM¹¨ŒKæ Ñ[TÇ‹’ ¿IW‘ Ëð¶:[2Áüº"@$ ǽ‹ ¿=W5çÒ$‰ÆL,³ônºîµ \ ÇaB‰…ߦ«.“2dÇòµQ4á4w«báò¢ÄÂoеî–Ïñc”h|Z®ˆ…#È‹ ¿E×–Û§– GŒ\ÕUŒÊœoKÌÏûtFìÿA5îÍ"ƒêpˆ‚w æuñ](ªÝË"e,>߀µyÅâcEG«Yï^(U|Ûõ†¤Ò3«$ƒv‘ç¯Z^¬/³]ªÞ½KËA>æfgñS˜w·9ËÀzáÒs8"’‚.ЖˆBó§u¨&%› L°qBŠGhU·ÓC>œb¤²qÏçÉ£IB8/R“¸¸ªtÚÞ,>LnZžù´,²š¡rO‡’<–ŽcC¶òŽ0êf›< ßUo¡˜Ž/½-L¬Z‡wÅq ÇyÙ#¸­^CÙ§®´%‡ÉRÊS¼-_wºZˆÓ#îu3-éÅSžïëÜ îZËq![`'þé, sÜ›†“4Ù›æ›P>G‚>»¦nJä@|þœíÛ'?ŠƒÛK¤Qß•Pôh: G¥Avº¼›E*£Žfà›#á=Í÷±]œ.J³‘ç…ÛŒ1MW|WªGËÍòÅ÷L1\×Û³tàxN 2Bwl@·\ÔM‹¢;’¡zVòøpNªÕSЊRÙlAçãƒ9<È׿”.Ùe$ÞÖgób=ò>/AE]¶•8%¸Þš­c]ïÕ¨fˆÙ#`Ht³ü†ª×€º[ƒ`ñuQ¸,³`ÁÞN¯YØšÔ€ÝÕO—®šUÜ0Ê‹CcUp‹ªßž„OÅŠãtj@ùþ¥õÐhçPJ}–zQVñèæÑ /ûýN]¦&¼«Q•«ê r¶¼ZU²hºl X­2Ú*LÜåÃoOª²(:'¨¡¬I@ûl9.W‡”Í=T.ë*Äl°—¤(Àvó:ŠÒ7º¾ÕÒ˜çhY:á< Ó½Íò*ÓH2Ê_–iY:²,“±HÍÃ8ƒH5,ìãoËß-ò,NîßÔQaÅ߬ aW«Ty÷x6.ð‚‰fŸR¨ƒåXC×Ùº>¶Î–‚[óÇwÅ_Å0»†“Wxõ¡ª(è´³-pq•}^Âi<‹‚u É) ¨¢9O§O¥iÑYL–¢n~_âM§ÓEDçèÙ¶xù•}ª”ï‚]ƒd›×åŠz1ö넸Å/7üo’9 œ@føÝÁ:½0$Ï wÀo<¸n÷´éþ»5Nç_9í†ò—÷Å8JÚzÂù=ÇÖ[”ÍÖtŠ+{)IÃáèž+•ì¶F*¬ gxËoÖì<-åÁZ >DS´îÙHùé2)ÛªF¾¡k€'ª¡ü<ÓG£Íüoúé'Vñ|“<¥_" X¶+»?¼°k„–=µ Spx¶} —ùÃ+Iÿ¨¾ s,/þf°ÚëÅÕ•\H4~ßH„çèAsñºèbYoÑ´ÐUœ‚(E”²ø V«øf¾«RþaÇuP •ÍEQ´}ˆ 6´éð`<8r/»gÞtÅöîõÖdµîUO„ÀJÙÁ]ȹF‘+([lq@ƒhZ–*™¢+ßDño1#Ï…{‹U㲦h¢O «ØHÐ •°[ŸÜY:²<ŽÀr¹`ÒÛÚÁóÖ€?G¬Ö± ‹¨e1aoá^cl­—Þ˜9aJî«:MŽ/he㦳YqLƒ»¯Ì}Ç06q4Fž‚ÅDŠ«Aµèø6¦91dóa«nÊnˆënÞ´íêà}¡šÏ…÷{»7ÖÐ^”#v ¦qj »É'i0NçaF0¯ÕªÏƒóÆX²˜¦Ù#ÁÌ­5Jg~ü“«‹ºÍu«®Ö›g\mT×à”àŠÊ‚T¬m IŽ´­SÓ—ó°0=4´Yƒt¢È]—e›–ýzÄŸIàˆh¤ä„û)hl#‡;eé¦KPá¿ìÕºS¶ñD¸RÂDh¥zR8Í£qqj9»¼p÷ýÛ>P…@ã÷`lt´²–xWY¡ªÑ-Ý*²æÛ}ñ·¡Ã\üíÎ?âýí}'W„‡ÝǬŸz>µ»žX²/]èN9b£éžK¹-{µæe4½¬<¸<퇩Ðr»¼ë‡^¸Ñ ¢ó-ùÚóMŠ~ê9§E¼ó|3çc¹=(€B@ýݽ 4õw÷ç¡Fý=‰žT$ü¶<Ý{K¨õf[.ÐÌ<<˜ÂÖ_3,Ï…Ø>û]rç¬ ÿ†Àý\‚3ÝqÍm½3¢ø7|cG,9«8bÎmæªÙ8“h?†³`Î2F½ÆpZ§ÏÒå"L&‹`Í{ ä´NŸ¥Ë9ãåžÙ>½&í2¢Ñ¸szßÕfž†³ÑÔ'¬[»±»eDzÀ!¢K"sû£X$ë’È\ zIdžþw"óê„ s uvb)̾ƒ›äS^™ò™ۜ¥Ü0¦møâ*»h[ÙÊ?x`ðb³o‹_:„Ëâümv^Rš†ÕÎOLSµÔW%K}¹„µÃ\ÂÚ$„µ["ÉBÙ½Ì{ ]_B× ]{›é%‡¬m È~++ïèýð`¯Ö&Mà_‚’a.AÉŽC 1uß[RÔø,ŸÞb—ÌžÞ˜Çm¾iÑß´xk§W ê^–^rôÖò¥P©:ºyºˆ2Ö݉T&Qµ}CµªÏÁ4RÙhQù¦Yp#ÿŒßþ(æ‹\‚ñ«AÕÆ{šoªŒ¿¸¨a..jÇ!††ïÝ)¥Ÿôâ†^ÜPYnè.â.×ý,Ü@q÷ª»âzœð!:÷ó,üÎÒŸ— È’z ŠÜ‹#¨ stØ‹ŽèT†õДYÞÂJŸL9]Y‹yl„¯×ˆ²‡ÒÆöEéNκã2YÄ÷I4¹š¥É}ù%À˦y“äY\L?&áÓ,·¡øíoé®ipûã\xù}‰‹7 ÏŒ‰­]¡›H ‡Bºx $ÚSärãüÒE/Yß$žØ%j!4}¦û©¯Üˆ8X° LΞcË3Q»_ÌÝy`¬š°Ã<}\qÂ=êVоeZ>Ï`XISl銤uZ9ÏØEÌŸ’©Ý¶ËuuHíîN%纘—‹¨+šSÐ2ûÏ÷õn±tR6LÍ e ë°§—p#ã³x )Îz’ó6Ưüf†…$ Ò³Ïb7AzíƒÐYu xE53IIObÊxÑÒöAú17jiXåMQÂÒÛž^9*é’n?ó:*BQCA°Å)Ãñƒx†Ê!"«É½-ì¹1UüÕų¹ñd‘\ „ë…çãk¤ÒYA€ Ï²½Ù@R¼g¨÷4qýBj§ÒäTúÕ¢úz{sí¡h±·Põ<º,ºƒÊQÖ‘DÏ›XošôP#ïìþ©*Kÿ}² Æ//ÅûX]ÜPlÚ‰Û‘1ˆ€¹-L“ؾĘ—­Ë=¤y§Ï:4†L¥\Rû•ŸKjÿðÇiSû½d/‰ýKb¿ËüÔ‰}âtsi}[»¤õ/iýãƒ\Òú'@›Öï%á¬ú#xÉé.9ýƒ£ÊÞË—”>ôg)}Ò÷¯§„¾Ååì^ÒùGG–,fÚd>©˜{Iås9'rSùB‰@†˜ÇW‰Ñƒ2‰_’È##­èVާ¹Ò[uìÑf³cQžµv¸–!…?ÁÓ<Îp:U9\â\dä€YÏê(òlø\Ë’–òt [sÜ›2•Gg”X)'Ó5†‚ÎP–a‹†eL§ø¥Øôyô’ÿô0ïîÜUR¥‚ÜšÚ˜½xõ [Àhô~µ„ë—ù,ÍŠÅa1åp2ˆùzJ‹ €IE‡åXSáCžÏ³è/£Hƒº7Wž›À?ªøF·Ëù<Ír¶qâdéšÊo5òS8[n±9è0A ‚ÔtE.7“èqžæQ’Zm 2±pÔmÝЮr¬\(Qñ¢o®“õWÿuÞ×þÐyŸ·]+¸‘vL÷ã½»–®‹/ÕIì§î$KÊáÆiô¾Ôl÷*­xaŒ^ç‚l¥—Y ³² Jóî;a AŸ¢)Í‹âÃr£Ú3l¯;èvߦx±5œE˜Q±SàúÄýU 󾦸Îâpv3ÏyÕ0ÎO(ÐÓD(pO ‹<Ì— „qPçü, G@¥«ë¯ÆæŸæyw›´}´JºT3=ލ.*ïAkP©ÇO…ÃÅ)”>”5 (•åù‡9ˆˆ¿wÇ8ï]–å/×Y– óŸ*xvÀS¥çg§%?À¾§ÑèB5¹Ú©¿û™ë'ó»_×vÓà˜™»“«‹/„bò«¤¡ŒæO":ݱ!Õ‰°$WÆ•¯©òNÂìw“®æóé]âI –mêçV?[Qv3ŸvAG­_–N왤„ uJ©&-:˜ä“úY§2•'åjqý L!*{m؉‹QìDø”Æf\.“8M®Jæ™^\nï’¯e#¬U´ç»7k÷·<Ÿ¯°ß½)ÿóUd¯ùŸ•šþ3oþ¾ÑÝ×lj£©ä«¸Ÿ†ï¨Z,Wz:š%á[îTÚ©± ºøoARS>¹¦¯jéIåkä~9Áǵ1A)NxslÛŠöfðÅ# Tm•2A£°îr,€z—¹Ñeåvì~Ö*'Í뜒Ž* áBj¨’2 Éñ V1vu!iT„·M¡Þ‘IUs9¼R¶ x¼cŽÂ„Â$Mþ^Kþ¾>”±=î²íÈ‚lÿ`+§€²Á’¨ °a³èÝñ±Õ«³xÖ‹WuwšÝCÔ•íò\X‡Âô 1NjÔÇÊÛ³|j2ìÕ«Y>$'Ú´ÀÙõݬ¿â²¼Qv¶nŠŠΣqùÁîå⃬GVŒW†."€㋘‰r¸+{y*®è$ žãI„¦6+Þ92YfYúŒŸÍh•U_³µ"µ_)£Ñ·êߣçmGmõ?¯ Re 8%‰,y&j¥šh1žÙìû¥e¶$E—Ú|yž.çs@‘\s6´9xg;&¼Íu£ºßož¯»çj÷&mÅ<¥Ï<_ ´ygóAûqõ ÞY’ o:@Ò¨AoaCËes ™©# 2ýiHæê7rñ˜±¿È²oâcè„…ix ‡™¯Xç#é“Ðlä 2¾œjûp™? Kí%y‡Jí?\ÿñá6Z,X84ذÊì]M3Ôˆï WóÕ«Žy’‘cQ#¡¬r» Ïv»WHOÄH%»3uŒr¬í±!ÒIOÆ7Ö³ø¯'#„Sò)«Sñ9”'tS nì¦â `žŒkPM iŒû iì¾g€ôd8co&iá…Âò3ÑàT™È5ÞøÄh=_ ói" ò=B¶±Ð€¡†¯ 6jµ¾ÈCVøø$jÒÛnÂÃÐ×”«¹Æð×–¥X —9ºš+&£ZÑþ[$E­ÐU“è%Í£1A''ºàEŸ¤*u×,x*¾;¶a©¡£pÉå ZÍûv³û5žE7É4½aðváÿˆo[ `TŽ  ½ù;–”ãëêa ¾"/é‚”Ï)÷ØïAü8ŸqŽW©(¶|žZ\1„V«~ –'¸+^ÅËEÈós¹›C!Œ7JŠAçZ4pc%,¯÷é<.¬L/]Ï®Fó,*›Ž¢©.»#ýÏõ¹aæ~Z¸odï­Ù<Ý…(nnÅk!|†„28säׄš°ý!`lîˆ6G£o\JnÌ””QÀüíi°Æüo?ÿ<ÝG9›¨iGU´ÕWÑž!;°Š÷³4égX+ ­mFyü•®f¢1HXbhîWÒ|õä…ºã5òAû¦­ 4cL{Ïh>§_Ùî 'to&I]#…1€TQcΣfHOsvሶêSI}g±¬$ÝãžDœ `²¢hètñ»fNìÎVÄËFâ*:¥=`›Bíu{PkoŸð˜:Lã“Bs¢Âl@…£B´¶ñ¾êÒôËÛÊïo£d²šÀ6¨èêhu‰µ7C@\‘ß c†€µr¥t„fóJ(èꄨJJ&Á•Hūұ ^ì\_ªDiXì åäškºeH „ÔÄ_áXU“¡ñ4›…~Ñu}%–¿¼/Ž6ÈUÄÂ(‹kÐrÛ³¤æìqkv«†Â¢«¤1ÑQ–r¢6«¿e¬v:§ÞJ`Ôœ?PçYž`Z½cý)šÏâq¨lÅ”³IFÇðå°GR!Š3b)Õ·§É BBšBVÝ9gC§Á«qñðL"–ï<ãc5Æ o´»¿±ŽNüMÖqáqª,£ƒqæmù+?ÜH®%]vaÉ0<[¿Ç?DÌ.©½zâ,žžOëÁÔf–üÀ%s×e – ÓKÅ$)µ1_' „p>nKƒM.ÑÂàš¾KªÒ¨Î$Õ„€a_ù»Ó  ¤IúÓþ2øîA¾!¶©e4`êéÐv¡ë˜â …-AVbU”|LÍD³p”ki¢Ô¶â†š>O MRøäÕêÁ:fì¼0k3ÉC^”ÅÚÂ3RFw®Aâ ÀP‚u~§¥ðYÐ9ßYð1| GÒw5ÀÛJøg€)Co”Xèd.‡°k}eýG mR¢‰Á ­4a²«µî°« 0.ô,Wt‡Kßô•h*¹ïüñ†ÕTýÐyâ;$Ú®Õu™¯Š‰}Ïò±6ØYÃ{Þº \âÁ‘Tó¼qvU…ñ€5P‘Nw¾ãÖq*œ/¿‹<̰®ÞfÀ*ï‹îr%i¤%Êzî4N ¶uDÙÒ¥Hâõ"Ý(™é´ØÁiÞÓ•šqK¹Ç˯á–—_pW¼Íâ™’:ŒQ!ÿøóî?ŒçÀz³!mÇ)Å¡]WAŠ—Z#{aó`?g^ÈÛ ›¬°íÂâÑ"ÒRÖ<ƒ_Ø;:FÀÞÁUÆIÀÚÁ5ÿ¥†ÀÎÑ(¨•ÈÊáÙºSØcî›?â·éò˜c÷˜û¯ž”ã!$ôGyI9ä;ûÄ’-1jƒ¯?´ñÜüÙ_’(<þæyÛsL‹ƒ ¤ÔÆ|ì7Âù¸í56¹D{kzç ›I¢æûýá¸2ê¹0]ÃæÂÄTËÍN: boD…²¿m]ãÿøBVÓø¾{ʧÊËæu¯wm’.@ZݶO†Ðu©õ¨‚·;®"¶ñ}M®[BǯÌ×Lø&aªE<æo'Ì:§¡Î G¯6Ž¢qD¯¶½«l5Б³îÂÖ9»Ï¹½!¹ýSŠC–Dv€†Ð*ïˆÎâ->+ brôÎ-Î÷UGZu¦$Æޏ-¦D’c­vûCš~Y”IO^†¬b ÿŠ‘µC¾T¬ aÿP:ÙWŠbr;Ïh]0Ï¢ [&ìÚ¦ +9ššµì½IxÁ$¤"ÖLž@üp:ä›8G¤"¶,KÄ"ƒ£›×C|Æ÷ôÐAj|W4±mùø,ò0_.8k2-€éqˆµüå:ËÒlÓÉQÔèƒÕó=QIÕª AéRn…îJUÔžG÷ Ç;`Žt]î)QÕj_C³:byt©Œ¯F«K§Á?Øw 1´%TÇ—²°{µ3G8õÑùIºDÓ…¤NIjê° ‚‹¹PÔíP)€pE‰£Ñ7ŒJ³…“ÏÖ«Wæ‘-¹ÆúÏœpÖ/Y¦[åá±Âñ8Z¬¯Ôy–æÑ8ç5¸Ëq©îie8M @µ|šbŽÇU¹Ü¸"%ÊŒé²|%Ëžð,#âÄg†z¡öS1©çÀ’Rþ¤ž®±ÖCѲÙüP íû9s¦’^hÇ`µåÚ±‘–Ô*¼1ç…îFûÅŤ@@;Æ5ÿ…ÆE;VrZH¤+óáwê*,8‹äšTÅqÀ{îLæóDQ1ú ºê/W™â¯ÍÕt ùþ—Äw—$˜LF•7¤ÔÆ|L Âù¸M 6¹D“‚kz3›I¦ a‹¯²³|[™ÅÔ©W×ý–çó÷áø!úœ~‰¥+ì MŠ®°c¶4E¶jPݸœ­]æPžì Iï³~«ÎÿG:ùú1KŸb¶ªAG™úh±ÍÀP@Û‘ ÜÏBM˜ÖI¨Z­ Ùý®àôKh"s½$ 률)Ü:*lSèc!¢…ÝkCöºÉü¶R­³ËºsÀìâÉ.ĉÀ-àµ(Dg-®@Åå;Ül@êfãŠj­–IÀ³Œ,®ÕóÆ„¶ˆß¿;§Þ0ÞÚuÿv7–ŒW»íMžÛµŠº¾}¡üñºjÀŽ‘ ‹— Åu@Þ.±±a,ñb¡h:BßèR.1›¶ÿ3*Ûï‘Xg(’¯öð¤¡íƒJ;q пúÉ™aÛåó<g³t ì$"dÇ€œå{x !â+ûU ¡E°g¶ÂîÏÄÅ8ÐÍzVМu6kw@ñaïN¨<ìq¡”0O»ÇÊÔ<æ ®ŠéZ÷@èšñ°¡ÚÇËëæ9x4Ó8ãd°‚\èý™ÂT_,ôþL’Nèœ_v :Šy3›·©ñ¢¼©ÿñ»ÆŸ}¿/â£?¸“@tuùVßIúZ4݃_ëÇWÖuð»`¥ß'É®3ø½vìµX ð{8ækOŒÄàpEózžÔ®l„Ä•WyV÷œ«tn„<î)cýYj}åT£èPÎо¡¢DQ÷¹„ÕvHË‚ÃpkG{]Yp¾›^5$U¿iM];¨uZS†\è£F¬_V:-vMš…÷¤>ù ÂDØýEÖ—Àé+ç |f(r¾6蚥½à! (À^!Íø’îbïMŽnTµX>€šŒzÃt'´ƒl¢ wŠ´éÅÏïÍÏ× %q,¡Öºú„¤ZÊzûº(LŸ·¯Sd?ËÁ.Þþ‰!.Þ~eÄÚ…/Ĭ„·/A.Jyûꀼ ý9üx‹¤'ŸúØ\|þC;¦7·ŸbÏPûsâÃçáùïm›œÿîãâÿùøðýCMÿüf¯Úëgx¾¾¡†¯o\|ýNŸºøúýùúÆÅ×ß)[.*ùú|ò‘kôçáCmŽžüzèÃrñë뻣7o¿?¨}²‹øc¶Hžûpö—ÏQFb>[ßY>Þ-§Û dE©x¸·ÏL1Aþs‰©Xÿ#»®ù7D!Ÿ+ïƒãh‚BWÚ°pÜ­Áy-›j„¨ g˜x~ªíamŸât¿†cÊ`TÝH¢|eK)/°%‡:wÈV!k~ìÕ_&óe¾[aÞ¿YëëMð9 ã|1¥ÓÕ¥²ù—7¿ùîUG7‹ñ\ʵת>—2í½M-é‹Ñ^÷õÄ[xŽý>@oîÐ0{߇—@Ñü° 'dCð€Ò×ᙇà€á\{ƒÓ’=6Õ ,Y4 Ï á á†hs2ÖQ±ó¹ÐL*®îáI iÝ=8¹ƒ‰š"8M^Ahd½qzŒ‹ gˈÆ*aÊj‰ˆ°¿þ±üÿK,äüc!x¶K ¤±"ò@Hy$Ï% RÞ,¯4‚Îñp88–6§Í÷<7Ú1ü\òøGÎÁy†`®Zâ“¿¦nBüÒêÆ™¥ãpÓBÀ9ÌÂýÐŒ…ÿëßû», ¿R©Ì–@Õ‚tR(ŒéKUm¹@VÔJ·èîບÄçÅuôÿjî_÷Z)>8=…ÛÔh8?…9'*úûÑ­»}¤r»ð 8‡Ûñø–aòù£ r ÿ¯Wu°¨­#5ë2¸—¶S˜å;<ê´³‚›Ñ´¸<6±› x¼+ÅIÑðÄbøC14‘˜ý@LE\Þ#Æyì®Kœëxâýò€½ã*ï å÷»,§ñ8g03¥a¥8ºÓ=r^{4'¬Ì:˜Æ³mð×¥Ýê^4±ß}¬øåæ?£ñ ùuggíZîõÔeݶã7wJͱù\dŒx‘£ugbt·¾"Ö*üð?ÿ×§Õ*ÐWf9F„§ÞB‚q§¾~xuÍÞÞé2çqš„Ý‹¿ª&¯ë 5_¼˜y¦FÁ¯ë”é—²›DÞG,xÐ;hs3´ÒÏÅà{Ø‹¡süqo?ù€®„µýôçsÔe²w¥ÌÒù4N&ëKáÇqš@®N¾/g#QŸvcÞŸ´u›(c@U~ß§åN²_w— ©wÏø·lóe.øÙû¸öaæâî¸û4xdßO÷_¿¼÷—ÿ~÷Þ»¸½½¸}ÿ_ë¿÷Ó?~~Xýd÷¢³ö±Ì—?z¹é³~oõ§w‰4]"µrYæµñõþ§ßïÿ—ýøùëÝ'ötÿÏÁÛ¿²êï‚"+inRèY*ÔÅx…Ýþxßyœ‹®wyÛ8Èï;WmÿüõoìãçÏG6¼¦Õq2‰ì¨f/·ùOÿ÷§Ë—ËË?ÿùІïÝê»Çûo÷wmz m ¹¤«#:þ%ü4øñ;Zèæ¯µ½wxÛ÷nø·ÇwÇOwâ†ß6Ü,­?~}j°Ò úµæwŽó{+à>>~¹ÿrü oA™~þˆÙî$xËs˜KŠðú×××Ï~ý¾ý×VTõþ'‘>Í&Ã$ÞÃbx÷>ކÃ$Qš©™Òbr¡’ ïâªwqÙL™:ûç—+ß/὞Ȳ$c>×b”d³Ÿ.S'È;ZÅûJòZ“Ô!“tUþ¹E&¨?Rd‘O.©¯ÇYR¨rê~ðúüO;{Ç»¿æÑ”ÇBêÁã§/O—Ì|«üHˆAkç<¢ŠÈÕœˆ "m¼ÏAKd:Ý@„<5['SÇ·ûªã½ŽL¤Ÿ¤3>Œó¼¥GÁBÜ–W¢:=€¨§½[ÖE´ìi¯–u;Qß÷uÝ\TIÔH3Hº„j‚´ÛúXÚ6Íúe̪mÓ»Œÿ¹œ•{å <~ƒ\Ç§Ç‘ªzÀ»‰¤6’òÔ®[,MÌ?i%v.ƒH¹©¾,ùŽ@{H%Ön½TŠ!³‡Tò¶®Œ$!-ƒ€Zf&”N²±ôhí‚z=àŒƒý uÎŒý¬•J=;+#03–¢aA=¯ÆQ ¤ç©Xˆ”åRG±1ot4*>½èÛRr˜d­ÉE"¦Pk.#ÓgÌn÷_žØÕ$×âe0èÙo´'®ŸK]ñâ‹j£Õ$–Ú‚ ×-‡ „æQì] ;å˜1Ù…™p#»œ™¥ŽÝºo„1ÁW·57~2™Dút ÌZ—Äñ‹ít¼0×¹YnÉÃD{ ¦Ú{ &ñ«ZÁlʳʯ»Á‰¾ZDJqƲ‰>Á×ö 1VÄP Ï #qCÁ ›2²@¢wåBˆl±aØpÙó ÓÇOßX+r×UÚ¦ðŽWMpc³&yæ Z ý×-ºÚÂ.‡F8ê™u]>=y- íœ@(Åäß-`%Ø-`Y¨èljlÈ•hI¥KÛQé’À6UMÒø¾<èxíÔÁ U-oãЦâ_9ô,‡×L›Ö)U¶/Ç3Õdݵ¬³TgÑóÔéŽËYç¨Ùtéô[ëöŠ1GZXÿ.Ðz0™ ´.T^à•Ë¢+‡ œ µjg«o¬7äRjpžtZMÝjꯧÍ#é7•XÞ¨¨ÎÎOüþ©‡¾#…4Ê_I=é^Ê£ìþaG.¶\z‹¼]K¨oy]ö³”JWšç/ƒ/·ŒdÎü—ïš7›ð˜EfTq+èÁüÒÓ ³wÌ߀-¹aCã_ qÿði:oŽ ;®gdΓ1ËÄ´Á“é ö$b£Oéû§kf¾Õ‹po~Ù5Ó|kpcZéR,æ7ºsaÄ}Õ”×âÌËÖ‘CÇ”H>Qñçýœ/’†nØEBv–m©$^Aº³ª Iê6¶Ûì>Ú©ˆìëùœ¿:WâÜHî°Ê[¢º>ÎÚ‘ºç :1™štZFÛ‡ ¯õ‹˜$›ÎÍÂ)¨¬vcª,üÛTGФN·,òÍ*ë8Ì’ ³e‚mnM"_t"ö½Š-7'(emIPøÐ»$v@F1E_óÏ“dMÖ Ѻx¥ Âg\î7£sîi‡‡…ðàNôÍAVï)y›‡mÞ>V÷–XↇՒÄ7<,@}èƒHló°úˆ§Ž!r ‡usu.üvxX·ˆ½Aòmë–x†×{X½.­Ôƒ<¬>± ÷°®¡›Îú†î9[=,¨”íV¹ðïö° È=a<¬>r}ÃÃê"çù[VùþàñV¹øSyXЊÒú…vê« Õýs’O[=,IJö­¡= qó!±ÍžmÈöìùðÛaÏž É·íYÕïÛã 0Þ÷c~À˰K’·8üØæíãðc›µÃßCøÚoK|kl›Åö²m&/‘gCpçy.,÷Y$‰¹Ö{ýÔSý ¯ÿdd¶{ý'bô¦×åµÅë‡î<»½q¨¨7<à>ÂY—µõŒ9­xÀmF{ÀgFr»Œ%ºÃÆN‹0tIÙð€!þõXö.Ù^†,ò‚à!bÙÍoŠmíñ³†LN©Ò‡ÐlN©›S<ŠFGò,5Iý@1ÓsÔiK¥µÂ·Eý>Qv¨è[ÝþËa Fç #Ú—»´Î@[­<š…'‡ÔÜô’ÉNMa†c‘WE8†Ô©Ê@¹¶qáI¸ÅÛôŽv·süÌÁß—?†R E<Ž¡uºBP¶íÔ¡@RnµÀƒ#~.ñ’¦\лò9ÅL|N«Ÿ“ÄMiž©6Éc'Ô\ÏS¯mÅOÚaŒÓqIT©ƒT•¶n‚ôûnïãhèè\x·ª¬æÿ¯ƒ¥½gƒ—Hÿõ¯û|ÿãë\t.®ŽUÁ{vÿ•u˜Ç”L÷°MÐcn±-ãF’6É5—¿äJ3?‰ó‰Äi·‚-иóÊKAâ ®ÛÎ.5Æã¦Cî?‡f9ÁCçaœxØ5š ÷^TšCqVdt,”ãk˜‡8ÌÐl" È1 ’TµŠÙZ·ññÂ8GÎÊÐ í4Qý ˆ„‹baËjs©G ŠÙ L†Üò,ÅÎá€ÑÛF žâÓš|`È_òIZ3PK}…%h|2v³t°ÖæC*!ž “¹È—¨»O:PÍуTͤ†Ìe@2œÀÖŒÃD]¡ ÍXd$¤Ùâmh‘’Å‘fœ»D §*xJ³Hjäd2Ž4!À ­ iÝ¢:¬ä0ÁÍΑÖÖVÏÄ$™ øViƒ‹ KX@¨9m t£õ‹æ|[(ä×&)ô’cã#ÖaNè9dÄT>—Èfë¬4­kŸÈxFm£yRɵ¨‡´¿ÄP‚è£Ê%Öá-¡ã¿ˆ´?f:±^*›$ÐBxÅžðH²ÂJÀ^%Ч–ðñêÉ¥ó—€ØÑ–KÅ&pÿ¯p 8ðð†àýa ßh Ê,ž‚*§ Ìã)ˆy ªLž‚*•§ÀçòÉ<ѹwAtJ]Ð'«ÕÑjArZЄ§  ƒÈø0ÉŒ1 FsÀ‡Çûï¿Ík¢‡übŸ¬q mÐx’dÂ7ÿ±q’ÔÇrÍŒM”f¾F­Ùqô[YªŠŒ™—€ÆOˆä( Q^ãXs`ÇüñRß4B´oQâø¹—-ûý2-ï ‘­e¢3‹e¿š5~2Lb”é» ÌBTp› U`}Ãt”¥0ÈßD†:_e¾MGѦÉN^‰å%ùHܱðŸY6N”V[ô>uOÀÎ͵qÚ½è5aê®uYß/ÍÝߣ¨†9x&Ê£ÚM +¹LT,DŠV|aé Ðóæó†É=PApû²whm+[S£qŸH)|ØÞäëY*º6DÙIs@Ã[dxØPš£,ÉS  m íÉœgœŒ"É€‡³ôØ,2eOKùH bwÁÎt-M! ÕêX0 K´°rbO,CÜfÜ;ë’Ç60%í,_ M5_~è6²BÕ _½âÑe>a0צcT~!‡1—ÏH@ß8”1ÐaŽŠ"D£H#Ù2žŽ‘€,»¼âZYâ%Ç-“ ¨9ƒlhâßÞ²õ‹MsÈI€HIÐð›"L ¢˜m'ÀÄBºr•LséCUjóL€U~°€Ûuܰ+à†X·ÄŠ5S ƒe·ï ¸WÀ Ÿ¾HðU¢€/~x8â”ÇQ+\ÚÔ³˜±@øÙ,ÕJ(eŸeHŸÙç¯w?ÃN‹¬ !éeŒ„ „Û×Êy8ós½tÁ¯yÈa [ –iÁN‚j m¡éÒu`ßIòöc©ó eÃ<ô3A@9Ï\lÊ(%ÓÀ¼áZp*µ¯ˆY«'jC—/¸0­€WT*è•û0T[áj¥ð YÍ&`Ìë×£0æRê 20«r¸t®ÁŒ\N±Í†veøÀ*pu|Â(S°³v'rôËxïÉ¡NÌ‚¬ˆú ÞEdŠÕèDÔh„]mÓ*å{ᤄžâõš®”5 €ÍRßm&Z­Ê8ÿ°J‡¤0›®»Ð$äM7Ñ,Js[ú€ƒÍ5SZ wÃj’­m pð4+;k-IÝk‚|ð‚Åà,³še6áÁ4BZ~åÖ„M ¬0특\`øa\Ÿ šN`Uæ œ’˜_d0 ш•ñîk1ñÓ2áÆ ºâ¶XÈÔ°„ ¡Ž€!SÜ)T ¥ùlvFà6>I¤ÛÄsX5í7àõ,b“´N) lòº4N!—#÷`-lìH¥\„hdíÂØ,¸>²Ø×|È t¤l–¼ù»ŒëXd——Z1îÐA#•±È{ugF9 ¬ù_ѨdIyõÄtW¿—3&1à¶rX·Èbd/åJÍ8XÁF’V"›F¾ ¾‰±Þ¸ÿÌÐ×Íç¸S8p*$Î¥*ÑØÒÍø&y(Àg’óm”;©-¾x<ªuo‘,¹†¡a«—²4Âåt¤ Ît¶Xk&6_š¨èÅF×V"ÂJº¤hŠ6>…[*8œûšn^Çm‡¾Ñ\!†°-jQO&¿æBú0ÿÕ¬M󑿀ÆþÁ½ŽÅR­(ð~Uyx€å/ld KˆÉüI`O¥•®Qaë&¨hÄ}äý|  ÷'ˆ )ãq /É!ÎÞ©à`×w+‡Â`Jl£åF«›µ9ó¹ÙépˆË&¨0k£Z ¡¹-цԡFðŒ`€g¾J%ó=8"¬2ö± D p‡É­¼I„Þá$‘ÐÁº*QËý4ÓË„ÄÏêÍ·9$vð¤Ãì;]JDätQ"e, ·ì »h@Ø•X‹‡^fá«,|‘ÕI°(œ†Åâ…44C0Ígèãð°³Z'1&±†™Á#˜1zdÆT Ek4'"šã‰’1ÅRŠLa=»—0Ö"Rðçj¦lÖ9Œ ÆÎf*NFÐÆN]€7 ­‰ÿ[í3ŽGæ)è\õsñ\\‹ÇÞ»Ò—°¸ÙÊ®FtM#­gèü-ýÛ–¼5¯^ŽÌeE?kÏrµñÌE—}Š{ Pm¨äíy\̦ȧ{¦¯âlÔílJ¾A×ÞS‚#ŸR¥MÛïn´Í3…S,8îôÖbß"(üÍ#®FMõÁ§G…o¼û‚1PÁ£ÂSc9B½_ ˆíÕ<|¬¾Åv zp»J“!°ˆ‚Á$€¤ˆ’V°X<|”´‚ÅâáÃ;,¨×‘!ÈJ¡hâ'&APsŽ‹$cХРA>Ú€GjÐuÆ‹ºŠ;Z\[p§)"Øð­+eÓ}‘ïÖdÀÇ™ h «€Gº^&Ï2¹]%êeΗtÄl¥šúÈãñ˜èL\‡Y“ˆÔ,D.¶‡¬µÇs=RG>î&X3¸Gã ÞÄÝ2Ó™Ûè:Žç*®Yw„ mtWÛbùÂkóè«AE™6pS$žÓ(«»Kq\kÅ ,*õÿܽkwã¶Ò%üsžï:Y–|ÿ6n·:Ñt·íGrg’ù‚E‘Ä6oM¢•Yóß_¤(’¢lK¬ *sV’¾ž½‹…B¡P(æ^*–tï×»Ih±üð(ï Õ:ÄçG¨í¤m_†mÑèåQØõ²µàÛ·²*>¿qG°X ÕÇçVê%r„â}'^G™e°6sõÊ{Ë!çq/‘}±`:%´v/¸8 V¦º`¨6P±àŒöÙÍ&z”!ÑÅŠ‘¢«mŸZa[rxÔH½«ˆÌmÓ kóȈè¦òyÆd]k˜ŒªtƒJø„ÁRî·Âx­N ©¢ò rÀ3{™T±Šj¦½»¾\eSª¯À²½üè?×ã#›9‰êFIøþ¶ÜË _JyT÷’H¯ð‰µP-lªU  ‹eëìæ¬+èîZxvFz^BeCmÈË£‚*Ô:Rl”y”.áhè¸sJ°‹Ž`êíšžoä»m2Ð]¿38ÊK%qDÓ¯¨‡£A³®.ˆ2—Ö¬òFW(¢Ò<˶y”T’:òåXtr ºo¤’Êq(û!èV+®ZŠPþ¬Ö‹‘€õQ±œ•ØT¢yVLÔ+E? cçFל$õÛ´BNuªœa HÛKÅdUáV¼ˆÔ‚¯>ú¾}Ú¶¥>fÛ@‡T¾\á©Þi[{ü£—Ü#Š5œÞÌRâÅá"¶|6K:·ÛêXÚƒÖàÕUÖV,dДý5¾n¡F=|©°tÃ÷2Z4¹×¡û^‰ѵ*Ñ€„‰Ä¯ö„) ±îqR)ùk[d‘BtÁéV! H׃_é|€Ec(D‘Än°pçTñ™° 㳌ê:ìæjZÒ!¹dHT!OBÖh]%˜Õ£Ù¤NªÀ\ð$•¸T¾¹@^È… €“ƒ¦ûŠÝœPÑ€Ï,ûEùk"YK8uâ< =¢­ô,£j†J[_2#»3<³CªÞW3GŸc¹T1—Bb‰\‰‹cQ;”³œªa¡—ŽUD¶}Uˆ[i‰0©îÄÍ„Czy&¸Ú®Ñ="9û‡ÇDïOÛƒ+}Ÿ€$÷bŸ Áß”UXqD&L×Îß-ÕdÐyNÛŠT“_b‘9ÛJÛ¼K4Õ™ Œî&{fËøbM•G·çò;]qª(P†¤€¾õÂc‹¨’Ö¦+°ç‚Zw‚Zwª7!ÞÒq‰¶“örîYmµUÇùTµÑö2̨¦ê2CªyêÉ…¾òð<Õ 4–ª+™±yAÂfqh9¶%ÈÔ(1)÷|0*ŸÄ :ˆÈa%`@EmI% /äŸ.¨¿].H䆔Ø9fêDl–ΰä˜Ô Ý$…ŠíœŸŽ¿8RvpQϧ¨ŸW›* Žî¤ÄUu¤€OïŠØòlxgLA+e[—°#¡Èv& Š. Sh•ÇY;¢…Áœ¬¹ ÈRQI:•w¡E#:ÁØÀå„´¥ª-Ñ`„PœÉH=õ¨&CÂc²WÓÞHÞìTð˜ê#‹ûTÏá8ÖÚsËó8ª˜Ç±ÕCvâëØ-ž>'5_uZ&ôË^d~í7»ó9ݬ«ÕiÐÞK_Çm«¹Ò#)/-¢éï›1å)¾£Þ­¼¸!£r›Nõ}—H•†ï·]pÈ¢ëzé¬é.ÞðfYöñÛ#nÏ(óÜÜ^"QÙ(ËsÕÉ6•p3'E«]&팶 ]u¼zͰØ^œŽV}Q&!)`F‰G6%œŒzW¤x‹Z‡‹, ,¢-IÖ”pjà –œªM!’NŒ4y%„£lJ!Ñ ª5šüÒ˜(¸×xd§ïÍç1U1ºÆ‹¹j”E¨*l‰Â&®ç.ÌŠ€® X Å~vE¬^½éÕûÿ_ð’ÃÕÑ:‰G¹}à´Û²ÓQÂs§¼q••0Ï¥ÊLç¾ Ú­ßw³â¨tNެ wõ“ ­wÖÛX}hO÷—£Ü]gäÉ’«¡¢ÊµmñÈ \#ªˆœXHBãÔxAZÔx´J”ˆJD©ëPÞnæ*ˆ®æÝŽ?+ ä"o‘â59v|å6UЫ ¨ìXaQ1‹(]©¡?qEù‰QõwЋªÉÜ<Ÿ”4=3盦LÕsº;Ò-w¾fnPÕÞàø$c‰è[ÕRúNˆIbQU¾Ï 礕sÂÒÆ‹È€ ë$s,*¹èJ-r,²‡Äçv@ÕRaN–Ížf³çÒ¶,±ˆn1ÌN8úü«æ0:,§º«ˆKp焛׋\@ÂfNxý.Ç¢þÚ9Õª2TžH"QA©ZHB(jå/HsJ82ï+£PP~p„`tgM%¥î?ULîôªD«j¯+ÝqX G9¸T÷Zs,Àðf„æ—!ìïUî·ªO&æzœêjGŽEýµj×KRh,ªOƒQ­¶ª?'Ý ÒÝ´ÐPj`‰àTŸfºÐßO|AT-?|+!Ûߨo$[û ¦ ì0|q©Æ“ì}âyd%{zYGXX9R²XXAQ»H‰Iµ`)(€xd+¾ÆBH¨@ú¿~ÄÓŠ^<*w"‘TÏK7˜SÅ$Ñ+LA²²J8ºbßy^ŸC·îÇœtáÉáÈÀ^‰N¤4•kWXTAáãèsÁ9Õʪ B2£ÐhdX¤IA™$”»,ÕºvNø¡ŽlE,ÜŠN:ºŒ„¬WCÑM)F…EvAlž´µo>)Nƒæù: ÜšxŸ›¨w]ωÉÖO…Hxš*áw‰F£&ú"&XFguD]¯æyüMhn©šöAÅç_VœcÑDË9Q-Aæ:TêÊH³„/çXÔû³Œ00]Xnùj/"YùÄ‚'ÌZE˵zbpÁ‰B…j§±>tܘ°{£B~áqÀõK³„âúë½/G Dqh“ã1ºŒŸ =m:Bª+¦³5©U0©Îé6¨d'‰@JÓ×Uµ}o‡²t€z¹´èô¦À"†]o…—ÑÉæm 0Öz)é¨K4Dºñu¸ç½¹¥Ð\µúÅ.'ËÔ@é ßxÄûXHâ×P%$_PõR`T]HVJ(açF·[Òp"âtÞžr@ «Ú¨‹Ú4í·J4RéäܧE#•.L£ú뮈tîS]››é­’P‘9¨róD=…ê˜IÄrRºXBBÏ£àH‡…ðY¡E« ¦±Íå²—TG>ïBSÀ*#G7*t·‹Xh9ÖŠ¨žKã-¨žœÙ 4e·¤ŽR>ªÊ:‰¥fi%àÔ U‰H¨BIêeJDZ)) 1‡£•6&èÃâ€Ó®&!U§½‹ya@7›7€, <¢^Jê ‰JÛRn³#‹0ÿqNØãTRELT[¥À(£\E"RÉb7¤kô«Ã$$v÷LBgµAMýa(XC¥––Òýo)e$”.y®ý “¨jöÖ õ¥AG™ýÑh¤ÒQfW5¡t1” ’„£üÚØs}—ì….²‰=‰H9Æ“ÖëW0i%¥t49­|tOä*¼T5ü#ƒ£ {·cžP®Fª0ñ\ÙBqJ:Ê[Hb9)çJG)!Ù]yâ«ò®2€ÊF¸€ŠÐ~¡s2IIvöAX·AÐx”áªF£”.QŽ/iY:ÃçŽE·*Q¶|Ïá(Ç–2”&îF¯IÓÇ)qö8¥<5T`¤²‘žŸåp¤òùtiEFÔÎY£Ñ=ZÑšÉ+éÀÒ%p¨îá/w4&ek†)rÍè È.˜.¼pF–‘XtH,’ßÈã€Qy‰©náS~-]ƒ…Owÿ2Ç"sçAʾb¾õ3¬EØŒ®„”Ó‹¯ˆAÝ€RN9Ù˜çÎls[T·(kÈ+X¹TÍû±Ð+¨2AæsÂÌŸz!×¢Š!ªc¸¥ªÉo¯°üÏÅÙQ€]•ÿÒ~@w´¿¤|œ½£ò6K‡‹$©†µ@#“Žðö¢*$’–,·bªNd™æh¯~.“êmE”÷víêR…†¢¼·ŸÒÝÜwçLE?yžÃ‰6hU£É1!›“^J…˜„”˜¾õjͨ Q‚‘=‡ìWº¼Ñ Z¼òW ½0ŒfV[ËÉcqéÆCºæ+¦*Ö¬Hµ‰ß¢R`Î]¢[ízN©"ÔÚ%Y Ðúc$ˆA-EL(.#|¦Ÿw¡Ù›Ôq&J\·S2غ ÁÖ VD–Í)qãdY´«y)ÀEÞr€”v²*Ę«í.§|áó Z¾@‚Z÷nŒîÒAGöÜŸ†ó‹ê§R;Ä_,ÿ%Qþ›‘u!Î…Q³Æ¤{;1Ç$‡#ÊÑj¸ˆÐ²]i‰¡“R]W€”WgžêzH(ž†£Úµ»¾òB–¿''Ëê-Ó/Öp+OÜ‘<í¶¾™×]Àاühñ+¥²™Ð¦zÎÌ #/H,*©bU¹@Õ‘rƒÆ,ª¥HX^Ri-cÕwÇ;EKª…"#“LØ®K&™ÊMRUÝH8²S WÌ<+ ²ÜŒjì ‰©fhF&Y²®¾:ÛÊqTÅþÕGÎúWvm[ѹAFõ.U—? E‰Efü^˜Q®`TÊ,ª@\A‘)_b‘)_÷s%£R~”6d ŒJ²F^¤›dŒJ²4Šè¦’£’,#ò2Ò0/#ó2Ò@/#€2Ò(#2Ò (³)ãƒL6Ò°*#«2ÒP(#…2ÒH!# 2Ò…4#]I3Ò¥4#]K3ÒÅ4#]M3Òå4£]O_iÈ+©¡ŽR¶Ÿ±874¢`TÙæ¾f·ãu”.èJbwqYDR(h`D®ã’мàCÕ=9ÇK]í›B,ï3—ðM—Y5Ý"ÅË…%‚t©nØ)¤ˆ¨‰Ò‹.ÈÎ ¼« ¢Ý†GV1çÙK?¬•º »`…‘#ðì—(sˆR'žœ£ *ç_€Q9Ï!{æQCQ©Ì¡{æÑ#+ÉôêuY (o“y.Õ^]!Ñ<ÿ¤nuP=“>¶îz/BÓ"þFºçH½Ðì"ýçæ8¨–àÇBY§ ~4Ý]ÀŽÌO«÷ç¨îPj02¨–Ét䋟TØ=Ê —G»áòˆŸ‘ö(/ iÏAfh„nˆò}_îÍDßrV.Õm!U¾Iú&“oÉ……¬‘·ß(¤ïŽ¥·°„¥xjý“;´u*ðDJ…H‰ˆILõˆT˜ õš£ëó¬q©nÔ*°Fu_§È—ßJ²ú³˜+‘AØUÅ¢5/;ÒQõ(ñg¢^ýÙ,вQM°™ †#E#{ÉÛnÅòÿZT ¶5âŽ$.Ùg‡)ÕAšÏ¥crT³Ÿû¶•6*°%Q«°¨Âu…UýÆÁñ‰‡ŠHªyLÕ\G‚Éè°ä‚ ,¢4°˜ÒÂÈÎ |7°Ã˜Je/ŽKõ Š&å&¡N6#_æ.Ù¾AcQ}¤zªÌª[ÔëÎh”Xµ7WƒîxDh;jë6¤‚ÒÖˆGª7Êï¤Ë0ú*‰GEžù•I,"¤ê4O!BQi=tÔu7Ï¡Z.Ã@%¢âL¾@$Vœ¤dãI®G2Æ£š•ê±NUõæS&±}Ú$¶sºÉ)èª$Ö‚,f‹Ø&:`’X‚êðØë€jß›Äd…~Þº•ŒnYJ:{•¾‡Nmú!Œ$dK9?=Ϊar‡mp`¡ð8'úä¢cÞPµÏ£ET{©³üX˜â\'˜ õ´™_ æIV ‹º´³)°¨Ä¢ŠF$Òç—lžz̳‚ÝqZ¦Ê8 ŒÚx!HÂ%ÕT’PD™ó Qc~ÒmË`ñâ9`¥ÅÞàø2Ép&ñ<Úln¹wе§­qî1çh þê&š!mK¼Õ“wM×|ƒ¨ï¾mì6˜+RÐ@+”,âÕ.®»©Bb³5q(¤QU.™°ß„ÆÌZ@»‰iÕMìŠE…D–ìV`^HTF‰·`ç²¢„®q¸j`ض×;¬µ`â(°ÈŠ/\›‡±oùõxwæ É®·DV²´Cªæ‘•R•hE„Í¡#ÂÖÜK„å‘=‘¹¯T‰ßÚKQ‰´ ‡!•Ñú–®äTf[ Ò½C©c?±É2!‘ì\U£¥^HötqI ÷UF²ºÔ“*lªÒBªÐÞJÈ%-`)AIËg HÒò›S™UÕbŽ("«zYm@ƒG,›»* ·U?f¡:HR.~oÐ8iÔrQ„š…Ú?´°>«²—…®l²B¡jíaòkp¹NÎ=kAµôî¢Gºi, ^ØKîȈšjO¹—"ô\7Â]8|n¥Ȇr ßD'CM|œõ ¨ ¬ ¼ *ð*pQ¯ð„õ(ûøìP“E1·²ˆUB­j¥iÇß'ÊÁˆ èRËEBˆîšOјE±çún-E:8þ´¬@# m.[ù¬9Â]>·Íb7ád¨2x¤p!W9Ä+µ3ÔÁ´> vTN¶],Ã8!åÜ#«×Šä2Bvõ0¢|²3J–Ê. ¨¯"ËPÏá‰e/ /K6 Ü`ÉålІ%aQU‰©’¶6—;7Ö÷˜ÜzðxEU}™C Œ ˆ À˜ И­]î…Ù‚ÛiÌ• Ô ²Ç?Þ 8'뜙cQ¥SÕŠtëám7Á}²cd‰EÖµ[b…D)3 ¥+ó«x&-§Úh*$•Ó¨µîŒF'[#ŸÚÁ{*0ª|ªKˆ.#+‡î¹– +ü“€³”* ÓXs2.C ÊgIտз܀.»$!ùÂ%›]t•¾ +%lNjqsA©´¹ üRJÉ‹­5Z˜Rµ ”pª©>¥x Pw Žt¢ºÑêB„ils¹è$U'Õ)ΖÀjµ¦óyd¯‘K,UMéÞ›/t†[m¥5];‰ç¤ó#àÔp´î¥šSï:%¥1Ý|ؤpÃ$¤‹+-&NbNºnK8Ê…;& xv›þÒÁE6¥¡¨WgHñÈî9é>itã*Bû…ì)xˆ(/v)4º«¶4º4“~c$œ;ON’5¥ú(½Š:«KNÕlZ!’iòJ ·¢Œ=ÉJUÄ‚Ô?mÐM“Æ#œÿ8²)»${¾ABÑår—>Õ+¤Š.-¼L'̨69îÂ"¬TpŽCÖD_Áy‰~ƒˆ0 •oF×#C÷‡õ(…ã~”¬)eTB* ~´‚lƒí.–!ÙÑœ»pAØöà×±pê7NÉ"E‰(ÈØ>÷gd¹'wá…Á‚.ÿDØJ2ÇšW̥é«»cÊa |èG¡©§¯ª³'‰‡6é´ý•rªJ_‰+'Jˆ–¤T÷ %¥•bïI»ÐŠTE‰to]GÄUQ²Ä"Lѵ›&|>Y”íºUæÄ’&LVª:’P‚ÆŠ,²Š•È«½àÛ‰r(Ûh Êw{í»½‚®-ƒ ì¥ h›)ÊXÒpK$T³<±’¹ Ë£k4:¬­h+:Ùœö‹ÇÜv—`m§¬Çb…iÛ» Ç‘­tt—=DÙU2:‰B°Ø¶·É¶g%Í;ðžH¨œ£Â£Š$UËš+H©\­„£R²—, 0:ã œ"¢Úä%±Cõ–z•›î®û­:n[lÐ褛ûd‰èŒÌÔæ1©Í)—–ì;=ª§$%V@½¸Ô«K@¹´ŸJèÛJPšHDw7T‚‘Ϋhg^uxr@⑆ ‚.ÌIwyŽp¥Œü’jû¯±È|PRm×5¡\.ÝWG7Ñ%aБ„tÆ/±€ì,3£”ŒTeuu•í¡h„[2F8)é¤ÄcÒºŽ”nLW<”Úë<¦Êç`T6BV’¾² ßñQhóöœÿ †G¥ü$âBÕjSÙH‰§záÒmH·°û,A鎕%¤j`«„œ·¬?GõDR {ôM‡5ºïŽSÂÁVwtcy„Ó0 È¿ÙJ“¥ÃSg m°†G7c¦°ÉU€·C‡j‡—C¡*f¡‡¤*¶É!àŠ¬­r*ÖÒ’üÖC¡¨·^H~î}ËÈc+£†Lìˆ2u"6KçT$¬™ÇmË^âî+¹¬“Ú 2kF†Ѷ'€áœ*½ À¨ÖÇŒ´†%£,zXûtM¿ 0š^¡bP-T)ï$[Á¢2:IÈ9Ñußµ`r%ñÜêKËE'ëÿ ÎnÎ:bîî;ÎΨ0ÏKÄ£¢ÚÄ‹ âåÕ‘ˆAm‰ß(ò¨¸nƒF³)h¢b]tÃR÷Df³¸ú¸Ö&'òŸËá±Ö²EÝQàåà˜þ«h}ªÐÚ>UŽÓ¶Èö¼,¤óö‚î¾ØZÖì®…G¶‰Ð>ÖjçÉó.€‰íÄUËŽÄž{!Ñ³Ž +Dû˜ÄV½3ªã, GׯBÑ]‰Ol•únÎ"Š¢ ©òH{€$÷8Õf"!}~<á$ç ÷<²ÎÒEU£OµUʰáÍÉ:èÓÕ"(¤•Â$–î¸D·ì§vrƒ¸ÈÛ8PB ZH¢dœ†Š¸ÎãW¢ôãwb ðŸ°í™ä£2í‰5ûsvúÜŽ ŒÎ•h,ª²‚$´„íºT`2¨¡Êù`4§ŒI˜FdŒJ²ÌNb«íUNpdÒ‘iF:¦é f”£3ʸ2NU(o+ðˆÐ(üL’5]çËŒÌW&j¯K”òN2Ë£2ÚUöŸÁ1™¸ä²#úÔò,ª¢“Ô³_¢Ì!J§¤„éRº«í©¦ABôÔmF„E7)Ó@½£Aˆ•‘ѧäX4Ç)+”¶O6’”½¶%ÚÒª¶žé𙑓%TõnQi_*¸ç*¬F'áãà ÕSopÂfÑ)a†TÕêAÑe)4T ª’¿‡M 7Øi¾³#ûLiþtp+·—Wigˆ•CŠFVg¤ˆ*©R/?†1Y[Þ $à<¤º"µš“Žèœ°êb5'­‘p”Â-­`AuƒnE"¯|º®2+RýSjŸ¶çЊÖIRö[YÑ–E­Hë¢V”'Ò+Âõ}•YTíÙ4ÕÚB;–”C©º‹ÓA­œt Ôt÷4¢c<…ÑQY*¡¡f6]w‰Ewq=³ã$ô‰ö‡™-H»lñh2ÛÊþ%Õ]ó‹¬5‚£²›TÝ`ÒÍAךF‚‘µ‚X„L6hd@Ö¥BbÑ62©’}-]# Fú©„3®÷ˆÓË Q*ñèz™H0ºn! ŒöC)ÝY‡‰EÖá#Ç"›œd>r,B¹è:|h8:ó'ëÉ‘cªŒª'GF)©Ê(uFé|Èú{h,¸–®¿GF+©l´nƒª»‡“ÿÐa¹Õ5f‰F×'¤£Ï$$ÛbSn× ‹÷HK÷$Ø:"Ûô(,*¹(íÕç>]ªÀÈv ŒlG!ÁüpE5š0•&ÑÈ*Ʋ0vø+ÕH°yÌ©´F™&Ïb—ªüRC•óP&ï_nÇkª²¥W'f–mó(á#ìV£qã˜ê N Wtª±cN‚WQW<& U·¯ˆ¬Ø'ZÅî,¤Úi´uBu§àÔߥC´hl}At䨗¥xj¾ðµ/ˆJK¨ô 1åx«iCøú¡† ÓÕå …Çƒ”(èVhs/¤Ê²j8²5T¡©ê_éIGx¹&»¢àä:?¸b„”€çCbÀ« bÀb<:0éX Ÿß¦ô5%*©)JT²—Ÿ ØÝÃ߈EIA?³éódüð»Ü×suNE.}…°|7Ò„fíº¢#Á…>°_B…4 RŸYÂÆ’è 0‘¯@™î÷'ð, PS£$Yìãã·Ñ$ôWð£‡ßG“»çÑgÔTÙP!À+ 3ȌǨ$!ûô ø¶ÔßGò ¾ÿ÷èóóøûˆYÎOÀW4YP¡G“4ùš4†Æ3Kš,¨(¤Éƒ™’-,告 »ÖÖI°¦]sÇw—XMm @ZÚ€4ôð<ú}4aúf ]ßv‡¡£Æ¶€Ç;t”ÝðX«Á8Ô :*ÀyøñíÊh46hL56f@?ýÏÑýsyx…Â)½@©½@)þþyTnÏ>¾À¾¢J„ñö5 ŒË¯Q ¬©Êab4 XÆQ?Ý?ÿ…­R­66÷¬õqCNøxŽÐuð$rkƒ%ÁL -ŒØ“@Û“0`O„= ´=Iç÷|÷éÛ»b4i@‹F“4Q6,pmÁõ×PÞƒ€œ`:úûòT¶ä€á?CÅϧ@> –ã F¡Ja{Ü !m“k€Fýð0BÔ%lvVbÑ‘ ò¢•b‡Ï­ÔKXþRŠÉãÁB]ÞÂâƒv*гGbTáÅ3°9p:Èñ=ƒ¢CÁÙlÍÆŸ±fæs“ T}R°%!ûñüåH Ŷè ïñ|5À®[P,¶%i\¬B€– ë EÀÊh9°†_8 ¤^ð€Ç–çþüm8=ÓßO#Ð^CC£,^acö_hum˜…v¢Ûr€†yCe€4…´œ  6ÚÔ øÿxÿ9šLÑÅFMТӤÁo“E:\Üø<ß#— :*x)ñýˆé'“rC‚2Ýe²<ÈT tT´´ÁÇ¸Û :r†}¹;¿-̈JŒý9žŽá'luªê$mYŽ£UýÐI=„¦flFë¥@Æ7s7pu{qêb‡HÌP9C—ÍÜ„ I¢:î‚ ÄØbŽ@òͦÀ@ëI°:‡ Ë{¦ú™ÀÝ¡²>… ±>9}eÛ@h”J6ð@½ ¦fŽ™Ÿš¿"ÇT'ab‚ ¼4w :& ÐèH½•t\xÜ, >G*h.‘ÙˆçØ Qƒ w ±™4NÅdøi€TûŠÇîQ6ãÏòM1ª,§Ä@yØ¥[•ÐÕ˜âÒ‘ ŒÔWF£é|7qWµ,m 0>2JÆCD ƒB†mÿ…òì æ¿@N=±CL‡…¬[®Ó#s?òÔ&F—ð ‰Yâc¢3ísÇ9sÈýãùÇÉøùo6~øòÈŠÖ€ámådO[yèÇ»¤ù:ú{ ésÓ`@ª*g WÒ§»éøžÝ?>LŸ'wã‡g„]írÐ+j—ƒ^U_pÝFö|vuC‡´Ó”¸°nš „B5 iv)qÕÑ%y3ÇOãß~|GÌÇñ£š˜küUtúy.Áó׸"ÈÏ ¢˜Ï]ââüHç8þüõÞÊLv{x[+ª<ŒÔ;]¯ª3{“;ƒG”N$ª¶Ê˜[꩟_)ùÙGF?Ë©[A‚p>š)âC¾‹(Ñc.Ì(,ƒ}‡Ãg颜oüElù,6·Ëc<ŽC⻦!O¡mPe@ ¦>)ÝÀáÔ¹ÿ8N+>F9‘z‡Ê%Îr)è¹^¸3Kð« ²\¼9`.ΙíFK ²OœÏÊQƒ™²â¾%xê–ë¹\q<ךQWœilï°%‡X†©ç ¢¤¹t$€+„²YR¨ÌBØŠ ·òÝ¡ýB]½»¡ÀUt¦ßÔE0¨ªò¦p¹ Ö«`¿¤–¡H˜ X6õ^X¿ê‡@ÖÓŸÉ_!áeˆ.BÀ²/”Úgkõô°AE…‡êšfoê+5; £ä³T@2_ʑܟb€UÇJ òÓ×ûé5• TØ*6Œ,)t; ò2„ ¸Þ|c ç€@\㺈ˆV#–F…«^ò”[) 8*^SùIªJ…÷‚)q°©?ã1ƒ‚«4g¡G ¨ek`zÜ(L@]å ˜{Qƒb™(Ä-·rTD¤ˆ™¶\ ú*ö¶J ½åÄ,Ó²H Ð-˜6öB­ÏXLZOÀV|òKÛ(0í#àiÍJV dJ ÔzØ‘ºWãY€Ä¬P‹¶š:˜¶®%:(®±ÕÅh4<¯Y° ýÜ127´„ãÍÑH¡Ž–PÓu…9X¡&é 7ÿ—öéÛøásÞ9Xqò4ø.yG؇~H]<"9+,›¬ ƒ^÷hR$K]ÙãRÑlQ.Þ è3ÜpT˜Ó 00Ò(ÒÈ!êKâ«W=È»µ¸?Q<ëeœ¾'G†•蘩DGN%8}Ò¼Î<•v¢÷=“ÑýndKtÈȖ舑-Á#û×íù€9'?Q}` ›~Àêa•,xrÆW$Åàvç©ïw¶p\^Á9Îoðßq9¤¾eû_pR¢ôÇLºÓÂ3ʈ ±ì@vt®ªËL [. ñ4`„)±ç–H׎[Ÿñ‡·_Èkç˜'–îœú¹°—V¿µ*-œÞ}èsÀ>¹Àe¿R—¼póasj2ÔÁ … Zƒç¢Ð?ÕØ¤¬;È>b.\?"¯1Øœ‡qò^Î6ÊmU°3åKh ìˆCÈÍù#p¶¡“Éâж0_8„Ùià”º»P‰ 4BŒ¿\Dœ™0Ò’!:@é-¥5Ä¿Gìì·à€-} ŽØË—àˆM| ª¯‚ÔÇDö`ÌŒÁ4¸}@<*³A¥¿Ÿ/OsVSÁVÿYЇ”±‘ò⢘Yǘ˜WUv ÎÛnÀ–zsÊ‚ TÙ"‚OxbYôn3 ™~(côðãûhr÷<ú £?<~MÈñSDÖ,EJ§{[Y^ÊYP{‰_Ø÷ÑwÄqg¼ˆCêX¿‚œ_ÆàÓoR$°Ï}ú#p‰sDL‹$†,q=Û¢^Q7Àäe!9p@®Šû»é3î…“÷ò†Æ‡¼r¢‘aïœäè0dà['ò*É=ìY’ûÑäyüe|/㎧ÇoãûññàQ‹™o!_(î¿ßÝç—ÚZ_t}8u‹¾S=G½;¼dк~$oñBÿ¨lɲ3¦$È_Ü ¹—&ÁïyÀþh¹Ls‘6K»OÙ}$}“ÜðØ%~ £( Ý !ßåDª$ DÈÁí™=Þ€ªyj˜j‚Âö…Õ\ó:—ñÔà[•¡P¿¼º@µŽ„ÿ-»hñåo¾ýAKX ü|¦àع—“€'xN¥ÈÓ“L.NŒ¿"6IOÃ?¥F¡~y>ÄX"à«G’N¯aÇ¥Jüg¶€ì@Jp’BZZV8|9CLì¦àcŽÅhq‘Äáš9ë@Ùùí´‚EzD¤7,°Õ^Sz`‹¼Ú"gÍ Õ&@¼IZà/°‘ó9/‘3l±[à#çE#rFK[ª––›øô}~jð1—Qa³--nw±Àî.t=L‘›ÀætS±Ìw]Ìñm–Yc„fÕ‰8 ݲ WÆ >Ów.}$ ^ F§â7p¨直Ž'èÑ×C8ѯ3pGµKUZ›§‹„|fÈÜ`'õ9Ÿ¥ µåBîZ6LFŒÂŒ5(—€Ý„mX€®ÐÚ²—\z …¥;€™‚¹ÓjOÈ*lÁeû‚±þÙÔU£MòÒž’`çzàÐ`«‹ €Ôã=o%`‰Âü]š¶Ä%=rŸ½Kƒü¦Ô×þ3CüÉHF2æS—íà©XjtGfy lÄ%pi“àáŠëó.Øè c9a8G Lç„ÑïÞ…ÙÝ»0°±†·½Âä¶W˜Úö ƒÛ^alÛ+Lm{…‘m/âQ™:YJçíÐ7ÛÌÑ_‘±¥åsÏs-às0%2è«’à)à_,·Ù` `6è¸gtJ(:t‹²!¼©óy4Õ³YnÞRâhˆV48Ór8Õ…7AŒ*FðœÓ#K'pŽS8ÌÅhp‡Ÿcm}Ãà£)°sjÃf>o¦9[¥Fˆ¸ r&ýñ±e­´Aü q™øMû 2ÀÙÌA¦á –që³P«åBзÆSÐÔ{çcˆt(M³Ž *ÿ•Ê=&(ªSº‡>ÆÆõÞx¸éY P»&hï‰L‹Ò àÂ(§ÆQP©$¨~ ªAjE¯­ý‰ÏÓ;Ð^COÇgY Ó«[;ˆÇ( `DGe -#ÏÐãb†¸9ª¢ÃvGí$ôÛ#ͨ LD½Gí$Ä ÀöHþn`é#_‰ ßÕ0#„íë6d­ÐI±É÷`›|+*Q!{Q‰ Z2a›Ü3ͱÛÜé#û>zþãñ3›qê—þ*àñݲôÜ&Ÿ%zz8ÑC„ Ã_ù¸ÍÜ Ù„}&c]9 ‚^YÄ2²Òi%º¥2b»ö¸©P-â5,`ñh 0Î9pƒ˜ßÛ·î€I`êñ™åÉo_èWÑG@×s…êóxÐ3`òÜ„<Ê}k²œ­-Ç8@ü~!çÀM܆!ÇVRoÖ ê&ÍŠŒîQE vįÑÑËEIÙÃVÑA™Mž¸% NK¨™+ÁQyò“)ßb“¯P94$[^ƒ&Ï«–èˆÔBnÀÝ ·5xœÃ1Zܲ…õ9¨éœ[¨ìå:™ãbÜÁÓ×§í 'ØÆ@ž”$èÀûýËЗ֣š;€æ«¤ˆ˜( ñU¯ 4~4^´rt½“^㸼‚s\H°5Máâ@Có¸Pl&¨‘_ Žû :XÊ9ùö-2"Ó®À±Þ†ë/Ü_¨¿Ð1láÑÑxÝÑØe§NÁ¬ùÜ TuV;n ¿ 34˜­M=v^ºÊ=“zÌo¤Z}`#Ï‚¡Þ&€à‡à0¢@F„í9´3#.*ß"êªx ­¦ÐÿŒâð'·wUs­þ–u×aï0¢>qÉ_¡³ÛÕeµ(pÁ¬D=O¢Þ‘EÍDIyè bð­^Œ:Š–1.ðS”·BìHräÐN –¯±‡3ú“*ü’¾f¬†/•½xtaÜ£ïeD~¢ÚÇ\î˜ü̽¬ÈOMBð ðþY@¨®xH]/q‹å‹zÓüyüt7yþÔF©Oß(¨O¿Ê<ü>~6e%®J¶Ì™:©G­øœc¶&f§@Ö/â‘ïB lßQåvšX3nèïüV€Õ7@Á‹N¼å‰ÅMïbr`å(©6U¡§w0luÍ }r÷ð|úü8ÁÐm7Z’W“5áôÑL“…:Þ¨àK'æð9õËUå+7ÏäÁX6·­€“¸¤Îˆ ÔUH | Ô;•$ÐÉ_ÅÛ°»T`x´ÃÊYpîs᱆ºº%Éc;¼EÍÝhPˆãã-:hˤ¡7Á+ß³€ºWmdô)µ:ÛÅŠfKgFÈU-pþŠ”H´«âuL`ˆíÐlr-4D…s-Ѧ Ï`dtÀÚŠù .„ÇlÏåªvZw—C{‘X‰këp£¢óeÀõQ-``íè7©îÜt1_ ‰ô S¡2/Má¬årâ7Z¬@Ú[V p¥hUT-Z…#vÔ‹}ÄUgU|a½âÐŽ ¢&ÔáÉv]«ö ¨%<æ W$Ñ h‚_À ÷ß§h†ÇïOpЏž&?=£íI½?ˆ%PÏ_ÐJÊŸiDSÀ5ºGy ,‰ü ˜áO´÷xüô?Ñ ÷SôG<¾£¾ÞOC$×`•¬ASÀÝÇ3zÙþ1üuyvûç¹0E~·LC8AmL·Ø iƒ´5Õ,êŽ)TO[¤²,(…‘jræ[1õ»ƒ \7×߀˜tfÏÀä­ÓA 3Ô˜[" Àé˜{’†ãSryÍ&*SS 'K©4E"ÊÔf" Y9ýú5ÄS¤píœNÙýhòÌÆŸí©+à€btú‹p|<þMØt4ß}Ãh§NÑQ¢©éø÷‡ñÃïùp@UcÀè©FA¯&¹ÿÿ´N¸x¿’_š•Ø÷ã§?ä(ß?ÿÅf^h¿ ž‡¯Ó@Ú¥5( í*w9Z£æ¡± A@ß³N€×`b× t“ÿ(B„u"@Ã…ÁJ½Ýº oIRgQeh Þ¶ŠO^ ZÇW} ½ê$”í¢JswY ™—.›´‡~ŸWçIT»<¬æt‰VÊω-ê†ò[„ªK­`x&Â8!ötË‚ëÅæå8—ºßÍ–¿Œ˜ãH÷®'ššqj$`,ÂÀP^@Sà¨]€ÆýâÂIlÁy×ÎŒ‰Kl è?"‡>Ñ'Ñ?s;tø'µ¼ ÀA&“ƒc†4Çê\íáôR¢C ² €i~Ž6´ˆÐ%.Êb¶àk|½”Ø@ѧî"€ê^ õƒ5÷?yìÎ×Påà˜ƒƒt“ƒ#µ‚2‰\«è·PÀ4] |ÔÐ~ÿŒ=)¨àÃN 6‚ 8d|7ø1GŽoÑ»†É×àäŠm¡¹Ú‚™Ô”ÈT£„G¥KhXŠQ2à´®ïßbB6š‰#ŽŠ·4fÙ~ú4‚¦™¾å-ïhÖÁAcª`1W±È_ï§7篣¿Ø£¿‡š‰ÍfqøÂ©ëë `C Ðñ¼JA_!UEÇQ”ð žœ©"ìrÞÝ sOÔk4ä%ØMß cÁõæwf ##Êt«<š“*:}²*PóÃ̈` Oj4Ði"°ÓD3f%°•£ÄWïƒ?Œ©5µÒ<~úŸ&hò7ÖJu¨.¹ÎÀø2œu-À^mK‚ÉmñQmWå¸ÐGã« ôæiLir¸ÕUÃo:`£9ЕW&BJù$ù£`pý,ŒE¸ TH8Swõ`ÛÌ%oá·¶}ÔfR"çÆÉúF‡%‰:—€³8ytˆP£=”‰:\½Ç‚ `.ÊåàØ!Ð ÚÍqDÉ£fáÒR t¤š68K.ÊÀOÇv˜"â þ€¾r¼uo ~tÏ`‰ïœ¾÷pé:7ðØ­•·ó/Y›Å΢[š œç÷ àÈ¥@¿gL¾hüݼHçFÉ5|`^$ÇÇ­fONVI¸í¾†×Û}Øin—fÛrà2%vÇS¡Æô% 6(.iЮP”‡hh½¡6ÀLÈÔ8ìP¹X§Yéšo3,,æv¸‚í!l@å¹B¨Þðü n}Qµ¾ecnïkð\ÜÀ#½WÞìM3¡F¸ €¦© dŽZX+ŽŸº×ؽ¾€ïõv¯¯ŸÈÂT-VᇥÀe[A#]¦¶XCÇ\1PéF¢–: ès¦Üò@µÞ S‹ ¼ ½L™×Å,˜:)yçÓÕ…Na; ëÕl0¼aö †TÀÙRE¶bi5Î(r?%íÁç3ùPGŠŽ”½P*ž# 17à ¤É„s ä¯Í*2Éo‡@o Àa:WàÈiZàCÑ‘²Ã¦©ÇMS Ž›¦6M‡—W¸™T€£×UMƒÒ¾NØ >);jÂ*pØ„Uà° «À¡²®ÎæG p糫 2Ä@$.dølËçžçZ¸ÍLäµvHð诀˜QlP¨x¸Î7(XðÚ¤@Ø PaÉ ë hƒÂWM ôW` ±Ø–H.Q–¤¡1¡ERº‚ÆhUóåpD ™ 2Â8 hÀ”WÈ£ÓÀ?Ç!ãì#G‡Ée)|”¹(x¨Í`|U†Ú#Ø^ ã‰Nð+h,…@¸¨bâ¶#}8x`³ EôûÓ—æõQólÈ(Ã8#¢ŒEqè#j©}à@|ç ²’ز‹3ÌìVØW8l0fiQÐeEC<lCÔp!Mƒ«¹vf En^?&,}äñå|滀rÇØ¸ï ®Êœ;˜ ™#ƒÒT2'52dR 좸{HL„:œ‰Â½¼‚àžß`ä½ !¸ô ÙÒ½( ©ãŽ¿žGŸGŸU==û1½û}„¸RºKÒ^èúŸË+Jò{?_ÆOSUJ¬ŸVùZèßG£ÉÝ7öp÷}4 mŸ~TëøäZ…§ï…TC'oÛ[CÇŽl~ Hô/ìΉO¸sà¢;6:õ#6s‰_1ª`ωsÓ94ÀK\ÀÃs9¸*ê RÆc^á nÓ?ÆXåè^h÷îÞ⢠\cc œÞEž§÷wOÒŽ&Ïl:úïr£†ØFí!¸õv"œæ¦O_ïî‘Ë €šÊ  ³ÙÕ…jiN^¸³ËÂ4 v°Çy:#ïh\gÁZÔmP€"Œ:02 ô\ëøˆÆ¥%Ã_—g·ÈÙ ñvªñéíôñy,WŸ$ -±j)±ÉUòøéæG–CϕȚ—Ý ™E}á¨ÎD'¥žuYk‰L_³SBëG؇ºT¥Ä¹R?~¢ÀUïÙpöSîº0ØrÑ ~²JAÏ·b{ÉpÈü›ùäÕÈ4æäY¿-navÄEn Ÿ¼xZæoŠ+kV}¦RWfk‡ ÉŸ¦S¸Êûa€]gèG\i`X ‹:œ¼¼nÊôq¥ÆÙ±T˜ÞÞî§OìÓÝt|?Muù\¶æ©¿`‡Hñ@9Š'¢Ñ4ó¬è·`Õ 8CM×VÁyv?ùó°û©ìØM\›úÈwàMÚýÆ»A@¿ûVø*>þ ã*à ‰_ ƒ_ ã´>}¾{þ8%o2T0€”4ù4 ŽRÇhåña¤*ýÁÈ–´ÐÐУàYP:¶,X%ÁÃ]L¬±Ë 4d¨(£ y«ã®$òøáË#jnàAªÙÀÃtóc4}Fûò ȇl Þ|C‚³$ ö簞ཅãÒ[ˆ€>½É†rêœëÒðX×(·ØàëëùÚ5.¹åP¿YcÁ¹”M‹ù/ÅôéÓßÏB ˜nP–:}ݬãõƒ¹=XÂãvÙ:P5°}¶|˜"ª^ëø@åh|°zp+ÀŸ_GŸ±›‡-l¶˜˜Ž&ŽïGßÕÆM–* %¸{þ1Íæ-JE%JC¿™8Û¬36A覴³¬’¼5­3áß ¶saö¨í\Àmj !j§Z¡‚y·’ãÞ,ÛæQ"7a" ÁŠ&¶—îŠ3;MÂùD2³„kç^Úæ1bÀ+ AØ·V¡‰•¤Ôx[ú«pÄ= ¯F–¹È„4z®wuMÅ„Œ¼ÀKƒ«Ûë0ÓÌÑW–ç:nÛ0Zã¤=ØžXb«'D€¬F<}uu¬»ÁœøvïÞ"å1Hü0à1ÿU|bFEV,8KcD¤"%O¹H”³I_a€­‰5ÔäݸB/[ä×~ª…M¡‚Æ2] ‹N±Ó·Å®s`‰ <,”PA/p˜%¸ºNÄÆ…ˆšf›ùfs·§Æ 3:"E²@G¡Â .åŠÈ|ÔÐ0<$°n°ðx_ÀFYFL¬l/´_Q`}O'wFpõ]%CÕ}_Ë[„±›,}!v07F„@:aÓ€:iY`鋞‚Ú¿nÀ¥N\â&F,×:ÚVÄäŒÐßÁÞ Áã•KWà“”þ6s•÷yJ]/qõ¼Sêqj‡W`!Ô‚Ä2ÌæVÒL0w}ʱ„OÇlé†Ò-ëåùÑódÔpÐSbòë%6ý¢ñ@b}v©Õ‘ã–‹Tþ@3õ mäo4“<} Ÿî&wˆ¾î[lz£Ùb“„j¨˜>¾~þ4’-:B+[tzÅŒ¾³»éÃr× é÷ƒ%|&Ckê­acdŸrËtcÞ@ÓwdÞ #Z'klw "¡A ‘È(…èiº¨ 39ëø+ßr§Òlpü‡Ï™-×™EÝÎ;Gœ˜iäRÕ¯ U5Œz—ù~ü$#_=Âô$QÚ,YG€¹…™QÚï¿OAÈŸÿˆ¬Øò©Ãç~z÷»+é˾R÷ݬr°§Ÿ¾ŽþÆ@•4ºúú¤xB¾[ª’ bt‡ö^Ð ²§¯÷Ók ö [=@ô§~¶ãEs&äXÃubÀ3)Žtæ¹6”;*ÚB³»!ᵫxºO $“oHøÉè¿AðÐvƒ ŒZ:8rÑ|DÁƒÄ \aF"™‚ÈÄÀ #Åa4ªQ„ÈÈfƒŠnJ|#ŽfC¿‘ùbd¶˜©6<à°ª Á>0¼ÚÀC¬’fm‰`¡VI ·@' yhåи(«ÀÇúŒ’6“K¬žÐ‘UÉ `L•˜ ¨r6P4µ„Rpüx7hè[à7¨Ð‘aA5aü¨€cµ- .P+9Àƒ Ѷؘø¬‚ Ϊ,ˆÈ¬‚ ËJ|¹tü/$ÕVBç¥%"‘‘,ñËÖu`¤YÀøtLk uX#û?pòpKb&ÆÅ§«<ÆÆl¼ Ì 6 xh|]˜±5ƒq¶±,l…>Ìx3¶`$ºÇ§bk<Léc³± xÄÍÇ68€‘•ýK9Êþcz÷ÒŠ· øt÷;¢“p+;ý-„üûÝ=un2ÀT2à”ôu¤Vq98üé@†§O€·¨+Ø/|í®œ¸HA |vŠ ¸I°!€j ¨Û„÷Ó§2òÛ­ú&GðyìòÀñÖú+jDäý*D/äaåÛ mËSã6ôÃÞÖ3ß6àÔ{•]éÌZ _éãá]›ºwÙ†м§€v¸¯£„ ”yÂü´\˜oaƒº¿c%IÌPë¤"¨z }ë 0ji”û¿4IòÓUwè0h"IdÙ/Ú·Ia‘“VÏÔ¹ÁG­‹¨HâF–À¬(zP­4Yâ-M];Vb!ñ¥ý)bêvHä™êf‡š·B:fÔª¢ú E0ô40`™ Ð6K¤uæ}.aC¡bÁaÂd° ä`ßÿ2 Ç½Ä¥7.ÁÙ …¯Z°?¾ß݃áÙô;ˆö¥óÔ~‰ÍÜ^¡Ÿåý ègÞ¢ù®Ìrô:³wÍ'ú Pð_0ü9šŒ¿ü ãø<þó|k ,=$h¾f£‡ûÉßO8ålðQÚÙàãÔÃîžGP•@5•0Uý9ú&az*pJ*@O§?Fv÷ðY½;7¾ûV´þ3Ã…–]&Ôøì2j2º?1Ð;‹"¼Ó F¥BH v­Cœâ-Ús;t c«Ð݃Kp@ÿàûOÀ«d:$^ enñå´…D²N Y½`Õ×ê=5Œ%¢ÇüQ*í· C¸©7‚ùvEP¼j©·ìäŒÂŒ€"2±X•<¸…DSÃCÔþ´ðE±+WU;yE€ëƒ=î³0YbQcY¬òwb`èylƒ‚ÇmîD‹[€jÛˆJ~(\pô]nPp±”pýÈãP ¹E­‘“=Oå?ψۿšñ´®Bn\\…@MÌÚÕd¬d7›Û©°UÁv7¸ ü†Ey±/õ3ÄpW>‡/ô•/ÒLï~±§Ñdüˆ9jr ¦V“ƒ~b=~ßÿr@[p€r¶à ­ü÷»oPÍ”(í” ©‚”éóänüð ¹ú½K‚ÒT¥­ïwOOãÌ%Ûn,6ð/ ƒÉã_ç])ô”ýõ,ÁÇeíåèm/H…Å@¡´VÀ£UÀ“ëf¢kš¦ß¸E¼WÐÀä…÷U?0ÀÕªS'·52_ ô Qaº˜»roMSTc«Dg¬ÒÂ>O–!B3ú±sõ ì(ôˆ3Ù9¬à©ÂÆóWÊã5Ôb爡cáÁ *àæ(+I:Ï;1 ý~Èì™ÙþkðùìêɈ(`nÏpRÀC¬¶Õ"oç0¹¿ da”¸a@=%0Fã§Ñ÷σ+â$V Ë[pú -ö³ô×bÆÄ¹ù-âéZgIú*Š:<ý>¤Ú¯#}‰žå÷Œ!{…>²§»ÉÝ÷¶ŒR×k— ‚¦~4úÙìl3)>à¯Ûó[ZbɨÛF)ti;£ª’Ãù‰NœóWàö’Û/€åCBÏ=‹ú:ƒ†%O¢(Ôx,ýFUtƉ«Jr‚D½Mo¥^‚ÙJü•Ñ7ª¨€ËÉϤµ£T„RÏýPnq½Ð~¡§Ï»å 0m©çÁÀ#ËÑÎPlç«êãÝèÉ\£ Ñ01Ð/‚»\º ¸ùÆLC,“Ä] ϱ*À2!y¦©Â¯÷&&N• mg;\@K˹ж–³`­-çÙ›ª Á²9ýP!«ý+(}W!À¤ÂÞÃ? LJÉ/ İà `„™÷ÓÛløäõ¾Ôü³ÇûçÑ3›>OÆÄ­äsž>L*<æ€ =¢*Ì1A#§!c§€Q¾¼B`¢4,‘1–À¸ù¡ÐAãw~C?C$&hü2dü0H×âtGŽ Ò°B†hXãfˆB9 hä0Ã3Ì€}©>Asf‡u¨Ácn9z'¼‚­ï€"ÐþJm~7¯dDé;G)<Gh|òÄî-Ïf ïÔyÓ½Áýµ=Ýkg‡FF x¼â1 á¾ÒãþùénÚÖÂ[ÚÏÖ,Í^t»OGÑa“3iè"ÏÇüÐa0üO(ü¢æ(³€-Ôó9ÍF$,ú!¹<‘è"¬§AÀ>TU­ëYPãªsL¥áR—«Mÿz=Ó7ÈôµŸdò ¬ë\‡žG¿ˆ_ ¯1?ºVCO½úL+Ç™JÞb ª÷‚¤÷¦wÐD¢ŸFÏSvwÿcrwÿ7}]yœÞ«èº¶Ñµã¸Þv—Ãó\0‡àv8@¨ #! Œ„@Ž„: .|gQÑ3s‰ÛJšûLJ/Ú¢a©oIÈ#’ ‰¾òKÿDø<ýPlñÉ47躡m§±e€êÑðª´[Ú*·]تî.”O^‡2ô_¹6ýºQÒÈ­…ºSî"Gf³}AÜ¡®ñ膎À1áBä½eäd/-äLU;rWI›Uô¨»Ô—ñ« ˆ¾»5ü¼#.ÎíVH ÎQ-OôÝ.$Ã÷éïlüýi"—ZHp[ŇķUÝ6Ú[Ї M_ÐO»*"ü¬âãª*‹014Ÿþ'PM“ÑëÄùiUíp«:r<ÀS(\)/ÆK(pð¢ˆ-YÌÁPCY`«”‡ñg4…œUh ;v×DU;L©¯®4œ¡‹Ä§ê6àÒ3×Üí©paØòlÐóÝy€ äì£ÀGÄ » ´LS@MSÀMS€M3ï*_¼i~ÿü€dú¤€ul5·\/9à=”&ú.M 1â|P†§ä_ºîØÈ¥ä¯u4Ix8¯Ê‚qß84ÏZcÁäZëfò­5N`2´Æ##4诲gX¦<‡§fâÚˆÙ¸:î™ v "õÞpЉF×ç0c(ª¡b.¢0 õ“›À¸%lažôòEÿ(H º:ÂVFäÎFÂñ®þâ¶5vò$ ÷ƒ,˜Ù0}¾{þ1Í @ø¢*>Ä%U s®Š›z›·Ë`iö’˜kßr ©‡eÝK,ú¹«©±@Çœ‰oãA¤ãÛx`9ù2Lb~‡‘o’Ðoek Èdh“­QÀjaj,¸äkTSãPÛ<0ƒ îžÕ$@%ªKDìS‚| É¾‹W‚;\©Qà] ö§Fƒv%îJÚ• ϼ¶']˜·»ê »‚¿{–áoÿº<»ewß~D^"P! ý¯göùÓ&q èz^l'.îfã$wA¦C«N`Ý‘ùǘ=FÅR9•ÂP-$@à'¨ €¶ºú&uŒ‘߉œÚÊÓ‡>uÓHE»xDo`…žÄÄa u¸TI¸FÉì¤vÚ*ä´Íñ‘ÓvËüìÄ¢<$¨Œ:ÎäÞWÝæDÉ­)Â4*_SÄ\¤½»©`CÅO¤€àô{I¤ÕüôZRA;@ýcÔ{aü¾õJß¾A!÷((Š|jéMÈñsåç×[¼p§»-ÃÜKÅKFê‰5$CnƒÅʦ¶MØïÑUƒ€–À–€–0jXnXgXä)ĵ ÉQµ¹ _9ѯä¨ÈõFN ‰¨§£ÉÃãóø¾­Ó%!8}Ó¬ 8ýìyþr£ÖâþdVÆÄ°ÿëñäÛÓã#qµ„eŸÜÑlzKhé½§oì½ÅF¨EýüyÎF=³ûÉ7"”Ë'ñSM-$”eÓ8À öS$›Yžk¯­ ´z˜çR_hkÀG8g`‚øÍã äd½ŠÔVN@]R! /T¬`Ë•‰ Õ‹;Äac'U·@!WüyÖ ÁÊò$ ñaKÿp÷]Eø¡iY°H¿9€Y¨rÊ"±ÇŠí=SÌB©Ïe-/Å„v%º>_3@Á@ÓzË‚šx[†Ô^Zĉ—‚Cû%úÝo¾µT ÒG> ³è[ sÛÓN=ßGÏ<"èk2à>ÁrU;½ _8 E»¡è{…,pyVMÞϤD·}Dà¨Qív¶ú‘8$ VÈÀ¥ÃNÕÆ…ü¦åâÆz•h7Èþ=m$˜]fƒÓ¹g‡ •j¨r@û%ƒ*XDí9pÅ÷­Ä$“56n†þlȵ†G×çÖˆ\!R^ª±x–€7ÖHÐsLŸOHWÿHÑ-ƒ»@Bï‘ä5| 0ò[¬ðÑ_Ïqüø;*àÉì6&L˜±eÂDÄ[|P\¼%Ð÷ãpaRäýê$°¤æ–>U0Ç_˜uabÔrÔ‘1`¶êÛãã×OÊ‚*É+ s7XðÒnyŠ`¶ËÞ2‰eN}K“*úÜõæºAÇL†]Õ1ÇTùmè[ÁUÑ¡ÓY,ÓÄ 3D€¬‹ƒGÏ“¿áZ+&Rk¥ÂÔT¨0Qa…4+ Àp­Á[¹+< €­Â€™ö`$Õ`Áˆ>¹ ’±›­€Xè½j<@×…9ôÒЛS/ä°Ã¾rtœGÏÇu†PÜùÁ-ú€9°y§&‡¿‚çs8ŸuyèQÛ ðk0¥ü[lzˆóŒ €ñ@pÏ `µß‚3ê~n»ø˜ã/M!‡ÕÝ?kO­.É$Ò¥"’6ë¼bÓOÌ“Øå+n– u$\𤑤šÃV짯#ØOcc\ÓÓã·ñýßìáñ3Î…<ýø„TNŽ®‹y"+¶|(´¬è ëÉÁ…Ýcü÷ÓÉÓãt„é S¢ÃÚ…”  ËpUxT5GCàIô‘r´ Ÿ[Ì*p]%q Él80žCõ«B2–ø u¡ÄǬ E;¯³’q(TÃÇíÉwh0{òLÂpÓc Ù¥…Ó8HÙKn¿¨Àu¥‰^8"¥xŠT(Иa‰P  >r9ÊÀAzØ…ºOÉ}ËEëH«ÙÀc=`•çKTT³!©Ù,ÊÖˆ$Q:Ãù=`ð‹;PyŒ“ ÝÂC²  ^˜²~6LýÒhžšDmL74¸ÂyÍ€)œß@ƒ ç|ê§.AÂÃjç'£?¿Ž>£¯»Vh@÷ÿ6 ÐË©X –ÃãnI6Ò*VÚ!…7ÙpÁYssrËkrxTl“£çJ¬BÛRÿ>c®UÉòÒí‡ÔŸQ¿Ÿ¢©¦ãßQþEAƒÆZAcÆyúü8á^ðnp 4_èľÆ1Ôõ„“ÚC–ß<À󡎾vi´ 2w¸Bϵ×,1`f/-7h̘ƒ™¯ÙN(LŒ:™~× ‹ g£QÒàB¼#ÕÎz ³•,’³ÖMŠÙ å]ÇÙ ×Ö(£P¨¾ÏKÞ`¿EHÈ¥‘ni°à×"} íu„GZiŠa€íׄO {…¯…ðÈo Ká à<‰ ÉS6H@Õu–â}v{eÒßÂõÓ!6à1§‚I¿ª…ôgš¸ïѯv…á p£Ý$æ{9¸©žS àMÕ¬\:§ñBK vžúÁ} 2øÒ=Œ±aJµÙUd%Kœ¢ð+;~4±â—&ô²ô<ù1= Y`ã²}9>¨Hx Ž:‰-`µ»[ÔùÆ–5™· ¨‰–3`êiKlà†ìÏ;XËZ :hPИõøÏÑdüåoöt7¹ûžw˜†%Žv©kiwScR.5†Í¸ʰª `´±CdDk¸ì[¶=ª±˜¥*x6ÁZÊw‰´Ëq9ÜÒ‘ú‘‘¹ƒÛw¨@é«]PôR#Ò«0âW—iø˜ëòGXãM¢GÊ*üÒ Q{žäŒU*Ì»¶ºÒzx+¿7c½@6S9¸8È¡õA>Nrìu¢‚æ·s|”Å´›’¨eAh™Q hh.ì^æN˜¾K…Ú ÍÝÀ©t”µä¯`]e7\¸„>HIyù–¾{Áfn" wÏ ÷æ4xh „}.*'jeVÌ Õ¦7n ãÁʨ]q+oÚ¬ú¸ÂUM¨4ÃÝЀßÌ€ßÈ0s}{óbzv ž]Ë€/F$xøë üÕÉ…¯Bm¹¹ÿ ߉þ@›’]P×ÌÊ´À~Šf0ðÀ  369¯]•,ÊÁAÉ"]¤ã$;öP1Ù–J€ûÌɌڣȑEõ(îàè„Þã+î塃P~HqÀB˜‚IsT®LaBœï0ýJ-Ï»˜ø£rï • ¨RèÒ†a‚xԸÕʘÁa>³`“ åÞp­T°ý¤MZŠ-,é[ê²<önþeYýk˜ÜÍÈΫ€ÿÄçaŒ¶6ÐÀ@SlCP3`#m%iÌ™“6·žÄ¨u¤j1 ýs´Þáí EEa¬®U•À,ÀüÏ:]­T*º®¦A-¿°žY›{˜[rô¢€H¤¯XÐSY ²)qvšÑ$œh4I 툭ÛVWâ똊F‘šÂµx­€#í ÞÞµÊÚ¥®Îq¥„Yâ#áa‡«[l˜Õ) öS§À±Vxfú¿¿=> º‘IãR)ëˆX^ á±³Û+M[úrÿD]x™ÓÈX÷ \+if3ûE¤ÄwIx€ÿ–ùìê‘4Ã5Å9’ƒÛ³sÊ’‡3¸‚eÜz¡¿¦P§QçÂ^â–}Eò2Ʀ|hfÕ #@˜:Edhh~¥ªa,xΖ5\SØ0²„Șú-‡ª žˆ¸Z§•’e¬3©Ó&°©)ŠÐQc#,“V—Jå7A­mKÖÞ+鉥å„û<šWòö|Ê.H8âŒù{Ê·:0XC‡ÝMÅ#Ê´*²†n>zøñ}4¹{§§J‚ñÃóè÷Ñ„>}žŒ~§ÿ}ô µòM¿_N>~ºûüy2šNÐìážÝÈ›pY"°/nàRŸìjàßy2å¿Réfˆ7g]§½é»¾jl[Æ– N1N(¥'îÕ¶öBê¢Y¬¶Ùôu‘%4}Wí:æ"!/;*Ñ…µ‚@¿2›ú:ÒØÚàü€Ðµ¹ ͧ¾à(©ïïUÒàóhz??=ÈÝ|Ââ?>~ݡԃÊÇ•Efkü¿GŸŸÇÔÉ­& t Æw—X|„‡(Ñ~|û‚F8Ÿ-øýó<ƒŸ$öóݧo(ã,ñ¡_1ý÷ÑÃýˆÝ=ü £@²DÊý|5€ªèØžÿ~BAÿÀ:œã?G“)Ø)ÿx¾jÿÇó—¨øާc´c˜­êké%¶êY #øñüÇãdüü·\¿<#’æëèoêªyM&!*M©ð?ÝMÇ÷ìþñAZÑœÓÝ&Ïã/ã{'>=~ßG’ïSv ’q0'ÎZn&Üæn”LÔ!õµû yÊUO¾±Ïãé3{zÄŒñç?t·3ÀDþ<žÈøðqò7ÊÍI½<}»ûûyô >Ù*‰ 8ù×Ó;¤ë©Ácì¾NA݉cÀ9‰)ÐÙÓOrmAbÃt¿Á)žMÇ0½Cù²Ñ=LêÑýÓ×'PÃÉ‹t4UtŒ­×Ö>º‡ù¥¤}?ÝMžÿÆ,€*ɬ¢W†ˆìøx:ý1š°éh2¾$Ø…ô62nÒß`øëyôðyôYmØéÝï€QÀ•76ѱa¥~d øuòé’Ý=‘w"©czü ð>9¾ÜE¾{¾ÂpŠÏÑê¹ÿctÿuúã;~ôpT¾D‡,[\%Çï1~Aã?¥ð(Ãyþ 2š‡Ñóôþîi”¯]›Ô>gúôõޏ€»‰?«–øGi=£Éè š'¶"Î&SÀ´}¼Ÿ>åyÁÉhúÂ×IA@TU‚OŸïžôœ`ò &ü£ŒG+¹—È*ŽCÿ1šüe>}úô÷3"J+ñ1 a 3þø08ùþÏǯr¯…3¹úSºËo€u$'û é&(Me”ÿmò˜2œ`œ§O£¡~é Cþúù Lì¯÷ÓqÕôW.¬¿Xþýîža\XA0½û2’_Ǥ  lDþIA_ƒ`ÙçñïÕ4G—{‚ÉßOHxu¬ü Ùxo(þ” ¢Ä%Ç/²swŸaºœh2º?1Ìêš3¨ÕQ¥YAŸÀ?>à0ïs s>7è£& ìCT2çOGÆÙQƒ¨±NkÀOÀ½9(`OÒ§>"|’*2údDû¿Ü}áOÿú»8sRv£ÏW¦ 9UþAtÐi%ò¨xN‰<Þ†¯`ç+Ÿ™` ˜&ø¦ ¼€i-`ª¢ã4T2€¤Ž 0ÀOÓ)ÓyŒFN ë“*%>È OÀÅclñØô/ȈjXDŽ÷yª*ØLîKµÿ>ý¿ë«Fh|Œ½486#) ç29.L- ¦D²»*D‚ƒ4’:‚6°ÿyúŒ‡i¾$@hÿÇt4ÉÜé±1úM£»o¿?.Ñm±‡ 9øóódüéÇ3HÝìîÇ_ d½»Ã?ÝQ£z/§ zHqoAŽ«„‡x­á²480ÃSÇG9̹t ÍFÏ@Ô« ž ›£´óÂ<:XEFNTX¤[¢Ã&jQB‡\ ÒÈ"Î-52n ©1dƒÍB‡8Ç¥úkÆs{x‘?÷ís68· Û帾"nVPœ_¯6Ÿqy~…æž]À¿ãü울–g—C \WWƒ ŒYU8n·ÄºZòWÕœñ€‚;´à}À4²ÑUIé¦R¢#z,•àˆ{ùîp†éú«g6wàámlcº’dŽ9ë Uä@{÷mñ½ûJtœKs ôîk²@Ô»o‹›k˜Þ}.ò±—-8¬w_IêÝ·‹ý \ï¾ j”!½ûJtPï¾->αÑ÷î+¡¡Íõ¶,ˆæztLs½’Ø\¯äñ¡Úq‹ø)Ã-}s=o®W§4×SàæwŠÞüN“ ›ßmÍï6€ S ›i÷ÈæzŠÓ\O##›ëå æz8¤§JpÀ¥ pµ©;ð˜y…m®·aÀÔ¦èSº:6L÷¨úÈ <ù‰TŒòe æz94®¹^E:ls½„µƒšëÕ QªAz\s=Žj®·6×ÛPàšëips=Åk®×DÆèæzŠÕ\¯ŽMßl‹i®Wƒ'¿ãßDªÓ\¯„‡4׫¢C–-ds½Ñ\o Žh®§ÐM4׫ñšë5ñ‰›ëÕàékç5<¦¹ž††5×SèÈæz%>¢¹^ Ñ\oK@ß\¯ÄF4×+Á!ÍõªèôÍõ*èæz5|ÌBk®W§o®W5×+PÍõ¶˜æz|Ls=M€i®§ AÍõ h2¨¹ž4×ÛâšëUÀ1Íõ*æz|H Ô\oMÜ\¯„…4×Û¢CšëÕà1Íõªˆ^k[|ps½-ÑÃgÄ.Û¸oË€hÜ×@G4î«SÀ æÙ®¡•˜Ö€äJ×>U‚SR“ÈÀù#¸Ž™QD°B6oÜCÔ¸yã–ø ¡¡Í5¨yãÓ¼Qã›iÞ¸¥B4oÔè ÓpäQ8ðY>_ÒÀ«®< ؼq£{lóÆ vwlóÆ‚€¾yãÕ¼±Ä¹adóÆ>bLÍKXĬycþÕ¼qc/àæäÜÕ¼±‚ Sâ0Ö¼± Ò¬yciÞØ‡iÖ¼Qᣚ7*lL ªycp˜…l޸ŧî®X"cš7Öáé›7nñÉ›7n¡©›7V‘AŽ ×¼±†ŽpYÈæ»ø(G€©{€6o, è›7n¡A;/LóÆ*2r¢Â"]XóÆ 8 yc‰¹t†iÞX"ã’~Cu •çè~H; ÒsF@› |SžÙTh…n ¶‚^¥Z!¯RyKæp'œ6´<ƒÊ¬˜¸£¤DžÇœ^ n xLÜ0CÂ<£Ç ÎDb%Ä×kÐôKÏ>Ö*…ó©ÏÜ„S_—È1Ob—¯è­£mœŠE/-±¤Å ,Ÿ3Û'|¡‹ |"eg‡—ã’;§èWÊSÎænà`€é‘#¼ÿ:᱕„15‚Åh#âüÏë nìU÷bcÒá¶%:n{!^ 1n Ë¢„x*è”Øò$&½-@¥Ç%÷Êᑬ`"ŒN¯]rWœcÊh“zs¦€SâBy‰IîsLŒyE)ut)A§7X‰©bV6O›|éÎ"‡€‰›aW–—Ò›×?<&Þå¯s¨w:–Ô.|µYØQy7E€Ë»5щónMø}+èQøÿ÷m±þËsg Ûfâ7‹ÿçpžÿb?‚L­ýŸ,û%‰-[Úûï÷÷ìü·ó£uSb~ÖÕèÕæQâ†Áùx­—È_äFí…Bþéþªø’Ñÿù<¢9Œmîä¿ „ý'÷_î?]~¶k½O–à´’þ>¡Å?QãåÝ—æÅoC"ÔoV°H­ŸFÜvç®­ÔK+÷„/¤ýOK-®”ÀÏr¯Oo Ë·0á"õI%Õ€,ŒåÏ’ef„mJ<¦TóY3±rÜ!– ÄJ¶X¿]tBsœd~¾™ì]Es©²sšÏ”X‚+ÙbuU™Xz •dbSaÍDfE¥ÅvL 'Èàl[1³-{Iâš$^,f•¯½&€Káþ©øŽNæ&¡*(?Jˆ¼¥Lú[×V™{ù37Ùhî¦;°:Ükâýgpu$bB7 ÙX8<–ñŠHxÌæªi6ɨ4AåÀl"92›ÉHÐà»+Ç.ס.›ÒLP‚%6Õ Y€‘ F¶t+0¢uHB½’iŸûiâ ¦^y•«xÌ… úิj;ôýMÞ<°fgü•Ûi¢+-ì—mô1ìý+™S­Ér_ÃÇ™S# rÄWBÄù\PÅõŠjA»¯r \*,Aˆ•Ì—J÷ M¢%„hi œòc‰àèÆA Zé(­DÂÑŠ¤´ Hl.¯´òJ8 tX^h%Ž›Ì©4§ð1^â:sº¯M\AŠFý­¯„Ò¥õØJC&GÜŽoלôQ#Òõ+•Œê˜,â±Ës“5[•iÜ­>0§‹Í 5Á,ñ?Ð#Løy„Êò¨”å‡Õ÷ù©G—`t9 F—(ÀÈ#Ë (0º¡$;PXT' ‹îd@¢Ñe>¾ ›Þ Œh£*¡ÈÎÅÕ¹˜Â¢; }~ŽEð‰‘Ë•›*™£Qå³£0²C°IWàÑÉ—ÉrH49š E£3· ™h¯d 8ò@x`;ÚЕ3Ƣ㾀Nx‘ÎèB Fw(,ª¸CaÑÅI¬Šÿæ™ )5à+`Jx–:îJo[.Èà¨âæ”p;•aì´-3‡¢} &7J–1·œÿ Üþ&BÍsDan!úøQåCì—¹ëñ£5Ђ%5ñmüéž þvIœÄkJ9+p䢦¥¤[4RA™*nî,`ŽB,XÜN¨ph…ãq„LŽˆ¥JK‰áhEÛAâÑ  Æ/$ ´b-©· H+®\ lfyœ³8î ÚN㘠“èqâ[¯T¸ànw iE%\pÞ}¶iZÁ+…ÇyD‡Tðª3lñî#¬@®ŽßÔah@aÒ"F*0%øÚ‡X¸ l:™FÌíKrЭó \L,Þ ‘“iÎc,:èC2DS»™:,È€rRSÁ„ ;¤+R *¸\­1²—Àhñ³$~ Ÿ8©¡BÇ(©qØ> ôö9 P«ê2f9Ú¡‘k¡H˜. ÙË€ú Õ?…•¸ÈÑu^&±†³ØM8Eƹ¢’êãI@¨Åº}z÷ U"Ñ (8ÁtQ Äb¹ Ë&9.‘h\‘œ¬¯èÖ3‹ >W Äb©IOƒB*XóH) ;’¶@¢E¦Z¶ß€Æ~B*–L¸Ð4™ˆýÈ”`ÙªK ¥XÅqä¥q4…q€²8ŠJ3ò:3ª²VHI+ÁBM½JÏÅ:èºÍÕ¤BÑ•ý¢J~éÊ}A¥¾^,~ú]#ˆ…T0‚Ò4ÑyX % O0?}êùIUÄ×ZÂ×U8‚>’ò=úâ=êÒ½ÈJ;‡;ƒT(‚ô ME" 1¢NëlÂu+ј¬¡ £ ‰¿à‰5Ÿ«Ó¼5 *þ¥Ë¥ç÷i貜MGÙKŠüÝÈÈÑX¤Vì¨ÈP¸HáÝ`Éc7ö’wöMo@#?ADVlù0`¼ø¡çÚ¤n¨ŽŒý€°sAQ+&Th‚ÚçVL¸Ðª·- .<ÀM–¸0á©+gjàÂÌr.Œ,ç¶œ 3˹-çÂÄr.p˹0´œ Ôr.Œ,ç¶œ 3˹,罜 Àr.Ð˹-çÂÄr.@˹/ç3+Ž]N½ío "'( nƒDŠLP+Ñ jAF€ #±´b²@ œ²®‰Þâ¡1}•C G@´ŒÝgTÚÖÁ b†ÔJZŽm‰Z-æñ§¼Éú„—@ü|øõÉD,» .ÜE`y0Ñ xðªC€S_ ‰åß2€>*=Pp@„ЄE¹ËÍòm\^Ù‹‹ ª$´Ëj 2Tû„!M *´™Œ0a2ä‘X 2Dû1u{Œ ržL%CˆÉ¥Û¥Ô° B¾’Íg…_4¯Pùú8·R/‘$0à­~7Ä$äR¤%ftéâòN~d‰ì:(Jì(Õë‰Kåêk˜ ¡ÕÒ4 ÀŠ!S…Öˆ‚ x­]ß°D„À?ÃÎÝ8«PÉ:‚í¢Äu¸ÇIÅÍ!âºUÜ£ P"²0Yò˜å¿#ª ?OÞšJ®B]q¨B­&,ÀW6)è\| òV~ªŽ²^+&Â*sµ“ÝÐæ®ç]ûH¿Ò:aŽÓû¯ŽN˜Àôý«£ œy#æ¡3³äJ/Qqš§é·ØŠ‰š¤EQ$Ld@‚Úeq—DºÙÝd…tÉl@Ã?äeZàAžfË&¡RŤ­ØèO Í·AÃÍ)g© êȨ¸ÎšÓ%8ØŽú§îÅÅZuP =yªu–E-ÂÐR€ 8[à‘ö/€K0³¶AÃÍ ´#K@.ÂÐR@ÓJ{/.‚ÚhW¡"’6onŠM¸Â‚Ú67àI·b…Öy „ä`´ø$݃÷#Å'j—½+:DïˆFÙ Ò¬Ivƒ¡l´¦©³]`°øäɳVlüGÐÆé­Øà  {î ù¦»ÿ0Âîõ÷æ„PÑ5…ð¦US¸ ¨)T¥Óúje·…:(ÈnrÂÝs %4yA¤€D êÚB¬-Dt€7~( b7@‚ü*q9$è˜Þ]ø– ÚHh A¥<%sk\e® ¨ #7 ÞæT!!ÊUø„u‰–p÷[âÁ„¥-Í©BÂD&MŠT'rb^«ßBÄU¹DU;N;T!×ý¤µ \"Ä]»Ü£Ú—j,R3 xK†è9+ÄcVù+7±åvî9­1H…â[N+Z‘ìµHó8ìºåØÀP‹æ‹®# ¥`‚ûŒâU™‡Z8@ ª`šJ5 [U˜à$—c,ŠüþÄ,Gµ†ô£¸XÈÈ}kɤ>d—‰|¼7Tˆyþ‹i/"œÇœS›S>Ï­’ÃëÑÎýÓý@; ¿‰è¶åy3Ë~avSÆ‹%þ’Kð(vWÊ·¾ð5‚#úÜKÅr£zò9Õjï$°Ú)ð8‘QWÃ6ÏhÛ˜ScÃŒ’ï¹5•©&¦ pF˜ˆ™„‰˜©Iƒ…ÀÆ? _\^IÁ¾('Ú˜Šfs,²„ȃ<,<ŹUÂB‘•,A °çËU™CT™Ðq»âðÅMðWigªc“ºcÊí]·C’f©S f9ÒÔWðÝYDƉ—ÒÕa•¨˜ŠÄ3š)#]g A‡ïÉvfª£ÈDŠ(Ž”ë´âÈÀ4An`‘rÓ­COʦ„0&OÛW(D˘ ¹ý%¥P‹Ùn2BabPÊESFêp>á¡Î> \G£{B­rx¤ê’¤¥Ä˜³DûbÅÂm3<±°à4q ÛÖäS KÚ)[}ÊO@¾B@êìnú0À³Ì]E(–Éô®¯Reu" ÖÔn\]½× ;Ð HUiì¥å†´†¤Q¾ëÈ@Ou±YºµŸ,j{gŠèOÎXÄyL¼æVðËbúÂ’* &ƒÐ`@ûUiÈsUpÇáéÃÄ ýñÒ9Šq³Wc³y‚×çûvÍd3 —£«2­·‰V:«œ,Û–‘1±*eS Ûqãâx*ýäv"˜JP&ô»E¦ClžbQ•£EQ5Ÿ© ^Õ¤ ù|ÄGØ–½ä2”£žmÈŠð†×ÙjÝwtó H‚í= ‹ôVâØÔ8`ö:mÇ!b 0Û± 2ûëòì–MŸ'£|âP§=ÀY?§4¨Ü‰eÓÍ“@# H¾Êõ…dKÝÇ€süš8E0MK/вMÖ HJÃoè"æ™jL«nÿZKÝöŽâjòò+îèƒqgîžgP„—E¡à2`œå]Ü ¨ $ §‘ªCy@‹Ä¥.ŸÚવáUF9üv† ¾ð0׎ñ7©À·¨°7¨*èr¯#7 |ÿÊ0KiF¾Ú--¡r?öR%`Y<ÏÅV¼n9Ré­nÙm÷ö€ÂÍ ÷“€î+ „þ„U†êÔÎ$âC¾ÓG…1/3‚8dfÍf1_!ÒŽUÒõSD˜£6â°¨¸±M«vÓOÀr¾ 9?YfÅ#SäðôËö¢ ü’`~ÓMŸ§Á”îðYJðãJJ"ïgæúøþ˜™ Vf.Wá.VÁ/U d®K@r]•;`8dÜí²*IÞ^Žþp•#qíí?‘²%} ÎúõµÜ=71ÜCÁ¢ Á‚JúhðÝpDhì}.ü].÷¸ ÜáBÝß‚ÝÝßÛªÀCy’CyɦûÊÜd‰JCö%¸Ô:s½<ˆ¿8ˆ¿4ˆ¾0hä² ‘‹‚ØK‚.¸¯gâ®æ'³È-žn Ä\ Ïaò x.ªS¾‚Ç*¤œJò§ Þ|S¡Sœ±Á‡¿¡ü!X1C0V1¨Iz‚û‡3tAÏ>¸Ã÷ßÝ8ø#oû$ŽýÿýêyŸ+e0·šê¨÷}4"û߃3Æì×Wk殃+ÆxúùÍ1•Zÿ|6Zýÿqÿ×_wŸÆòã:¾ùüÂiÂ!–ðš1+Ž­µ9¶0‚•ÚˆתíYBÕj“¯Õ&#^«ÑÌܨV›Œx­6ÁZ½•Œ¡ÜDÉ%Θ^[9ÁšmåÄêv(>Oý>¨1åî!Åjw)^½Â5ìi÷âÕÛB V•o\¿{XÁ Þà Öð¹ž5ŽåË]‘å™Óñ^^°–÷ò‚õ\õý¡ÜÉù3ƒ«Ý{ì`¿ÃŽÑü"HYÆþà’}sE"îp¦âš‹e¾Œž¦g¬xrö¯¿ØùopZ‘YÑh"i§³ÌWi ?ye”õ:æ*‹Í ÓÞ$±ˆ9õ#T=ÈÙu£ é¦Ö\Úq¢*ùÂX‹0²ïúVƒŸ&üµñý¿Ýš‘áJÊ`%‰e/å²,<>zz˜²ÍßüWÊ;WÙhÖ›„¯JØ‹¦nKE}XCÆäÊÕ˜Amìµ/îɆë2œo-Äò¼^ÔpS7ÒÔ³â>äªáÕò\Gô(˵¥\Ë ôÃËœ^=2æužµ¿ ® Ø:}bœŸåb¤rEt¸¾_ÊèÖ xü‰Ôƒ@ûMˆH˜‹\UŠäyÜ“ÖÁ“DÝp;—>mçû»œt|€RHÊ–¥`½ÍIe¤-¶œ¡ïÚªÝàèéO×¥ž›2•# COYSh`ÁÂé¯ zÕ˜Kß‹ù†E¸Õ.zîÊ †¥¾aŒ¿ÚK+Xpfމñ¾‰ã†L¬[—ÔÌÒùØž&ƒCnåbËMÄØ.Ô‚ÿò¨¿™ëGs™Î½0;i®^…œ+ÁèÉöNF (U}=‰®ç/á|>òäÙ8Ò¡óÇå¯Ïõ¯#ä NFà(£ir1—?ŽÕŠìÏòâÓdt¢Rß„+ë©áž†@·‘*Ÿ[®w2¥SèèDÜÇý`ôtÃÆìËøÛèDDžœHyN÷$$ô!IÖ”$ë/>h•¥¯ø M˜þâƒ6iÊø ëa5Þ#PœŠD'ìø¤ãƒ6©·ñÁÏÓ¨œŠD½Æmõ´ŠÔo|Ð&R?ñA«$èø`xÍÔ•–Y¨ªÊxì»r:ªY½ÇcòÓß-ïUž¤›Fƒ3I®›ßK›.©Óªä«êæZžûÏNðƒd¾Ò)Û³\ŸÍ¼Ð~‘~ß4½®]/è}Cìƒ~F{°;ÚO_VO«Qoô¿2o°ÉR÷ q“ZïÑÒ}[úp°µôö_øzôÕÿm™h/¾™ôFÑ©Yýˆ ¾¾¾S_®þØQí”uðøušÜ–ôô´úI¼½+Í@K“F¶%%Î{úºš<È—¬øý¢9Áèd{¢^éßb¨…pd¤¤ð´fT!k:c/nà”:›ž³é%Ë5''WñèIuÃÜÈæR@¥3ϵ™ˆí‘'åÔòN‡ -Qã@Ïfß”ær[OXŠ¤Í +I[ù¾:öuEùûy0ûZÔ¡J"v7B«¨½_ (uTþXIí•êMTh¨ñ·F¹ÿöŸ{DÞñ^m"7ýÙ@û³ 6½bù—˜õgíŸò¦KÛ3`7·§Þþ´ídÌÿJCiÿ–S´”·ë×ûö¿µ‚½+6Ò ½çaì[‰Iïƒ}.„µà#%Ö9û¬þ¦îÛ)7iÔE#çI5ˆâêçR¶âAc—{e8f÷)Ôð¬J½q»‘Z´rÑŒËu^Ê’…±ÒyÕ\–"ä¬zâzS\f½2‹d·ª’"cùžjï©æÓ×Ý~ý@żÚèã*?"š°¶è—ú¬˜&Y1µ¥©§–ÊUk%8®ø©¢IuX7ƒKóü&?~¨×EO-Ñá\±ûf•¿Ëß«Òü†¬W LÀ¹fŸ»q_Ð"@¿ôa ŒZ uá±òÌ€•àMv䯄+±ï7Cnx&qµõAØÓtl—¡w!ú˜”»R˜ŒëŠ[èÍ"öÑ¿}ØD‹†Çch5OÆÐŒçx{pÖ9±i-Ç=xK±[šƒæ¼œñ…˜&µUÎÐ8iËðˆ—Ü’f©œt‡Áî…føªs÷ã+¼½÷à fÊÎ+Ú"Ãæ|e·¹)“÷ªõPÎ÷ᕯD:SnÙð RG8=DoŠÖ5¿Æ_oNHš'ƈµ«ê‡Z¥âzújMmذ·Ü½ê<_›L{« 3à±o6ùßÑNöÙµçúnbÚ…ÞØVdÙ®ñ(óF»÷°iQUÜ>–H÷‘³s¯v˜î„ëDØ‚I¼¶W3|ˆ…ÍSuÈqR ý‡4OÈm€!µ± ‘ Œ0@ƒÑØÎ¹µ1<°¡ið€”?ÏO­÷rÑTÛé/fˆÚ™ QÁ¬{— £½Ö3Y£T¦¸`CÕÂQ è¼V Ne…¡³Waè„U ÏQò´Tg¢˜É;ù›ƒFÈtÚ‚ãÐQ>'GǨuì(`‡‹w„(p…z(p‡~z´'ʃ4ˆyWÐð¨y_ÀC4{0jÅÜ‹]ß]‡=Dƒ"‹A‘Å ÈbÐGd1è'²ôY ú‰,ýDƒ~"‹A?‘Å §ÈbÐSd1è-²ôY z‹,½E£‘EÖCÎ"ë!g‘õ‘³ÈúÈYd}ä,²~rY?9‹¬ŸœEÖOÎ"ë'g‘õ“³ÈzÊYd=å,²ÞrYo9‹¬·œEÖ[Î"3³ÈzÈYd=ä,²>rY9‹¬œEÖOÎ"ë'g‘õ“³ÈúÉYdýä,²~rYO9‹¬§œEÖ[Î"ë-g‘õ–³ÈzËYdFr¡™º‘-ÍU»öœ¨žå‰ëó"é“÷…µ|ù—)kçuÔ«–9­=$V¿aœøVñZ0k6‹ùÊ•ï˜"×4hu÷ñéúÅ=9o“e/¯jÈ£4Q7$áÓ×a©¢k°^Ãmê+o6Ùám9¨f³Vgè›ÓÎÛtVƈ›3Öñ>ge‚|¿³2¾ßY™ /U¦:3™qVYÍY™øÊš³2AXwVF/\¸öþÒ_"š!SO˸ù åjq # ô‡ª4<ãÖ ‹’=Í47ì$ÕÆíVŠö)B,¬‚Wt4pQ¨»/Ÿ÷~ô”;P¼L»½ð›㎯ ìy&¼Éoh>*^ =Í„7ùM‚ù™P\©µ¾ãõàŒÿJÝ•åÉ%Ou¨ÝÃuA·Sß’ÁÕB\6.þšdÿ½c”&.Ùvÿ§6уóÚ/‡úál«òwÔEle›÷å³×4_¿/‹½ú>=c_V«Q?üyLŠàͧd¹åouŒ‹ÓSé£üQ¿ü—¼¥“œYzKÞ÷DêÕè¸ZðÄ mC´­Œ&ga+¿AhŽLÎÂvz£³°U“³°=AcdºÁb˜ZÊœƒz ¶È°ÿqN˜ ×*3?WÇC*ú°-Ïk?s¸!⻩~óþýZõ‰Üªµ Òƒ$R·ÛÄi¯r˜Æ5Òƒ‰&‡„'b#”øFú³‘ÊÔȹÜU_,-±OÞ|²gd{£ék,vg!„¦©ÞýÚ ¼ù· 4W4Ãòa㹩³a8(Í»_yŽ¥‡LÁQKøj¾³æG%;ñÖyi«ô¨*§>S÷ B/Ìx3Cx#5©¿OÝ ËÝT[6(Í­ºÈ¤•X|•ý¬ Ÿ $Êrö%­QŒ’§¯ä!Ò_é®2L j;› ¦Â]ú®œ Ë4ØØG&F DU(Ûa°âq"?‘e¾%^F ’òR~¢´þüÛžLP%Ð1ÛñÀ†Ø Žªæ3´®ñe¢+õj¡Ç‡®£î¶¸·6$åcòøÿ¥ *~áZÅêö*Û¶ºÊàÏD¢/Ää.0 ÄÒ'£‰ŒäŸl¹G™4÷)h)”{äücÔ½ÛýÔªEêâ{^å ruËÙò2u3*•»6˯ýh»ôqrà/”\ÉŸ\µ¥ˆ0MNAå² cØJƒ¸5UJĤܑÂܤܡ69)wÈ OÊ&û¤Ì Ì„¦$õI™™œ”MQLNJÏ“œ:›¡cèò™&LÈ^#T-Uj„ù?`Zõªh[Pwcó,ZµCµóÚRP®N&aº6?„×RƾïÖäÀeÍiÚ9×kÓ032†ÙÎ4TÙè4Ìv§!^¹›iˆgº6?„•iˆÿ¾[¤>[ðDŸÆßºes[I·–}æÙrþ*ÇNd,“ŒŽÔÑWþÏdšÜ¸¡P×ÎùDß@Ë_ÉÕR?y>åÏðþßø ÿÿÏHþßøŒ×ÿ7>cýïüŒ«Êg̽ÐJFùÄs¡Ç~¹ü¿|Hè'È6,ôì_(³ó/”™ÿ ežÿ eþù/”ÙûÊ Ù9eFœ™¢e~ýʼ>™UŠõ߸~"÷ -ᇈ}B«ø!bŸÐB~ˆØ'´–"ö -燈}B+ú!bŸÐ¢~ˆØ'´®"ö -퇈 ]ݳ}b·]¼=ÝáDò  ¡¡›(ÌÐHfèö $3tï’ºqÉ Ý5d†n™@2C÷K ™¡›%Ì'´S:<(NîZÂO&Šû„ò“ɃâÄ>¡åüdò 8±OhQ?™<(NìZÚO"¥Eú6üp••*mÖïjª‰ª÷íªðOöô–MÜXµ—p¡nOמU©m\§»Äþ¿Nâ×ÄëÓ—ø¢œxyROO½é•ºÄu}Z3îr«[-êØiÕîi©wGh~úBŸ«÷›>}…mªˆ$„히äƒm“ˆäƒí‡ˆäƒ…âDòÁbn"ù`Q*‘|'ŽêGQ-gd{õ T.ާ´$ª`ÿä}õ>!OÈ]ïñ„<ö>OÈiïñ„üö>OÈuïñ„¼÷>¡<Û'b{µÂn>!«¹ò žO8Pàä2ì.¡›Ä­ù„“–¸5ŸpÒ·æNKâ¶|‚jTpz3îcù„ ¼5ï*tk>á´„n‹ö3pŒJ !4@%È M äƒÆ¥òAƒRù )|'Žnò Y=Ÿ ÖÅSZ÷ö§å«÷ yBîzŸˆ'ä±÷‰xBN{Ÿˆ'ä·÷‰xB®{Ÿˆ'ä½÷‰ˆpà7Œ9<±\oxÆžb×ç,æª!‹Bϵ׃zÅ¿&lö’ŒêÃHö4ß{2è—$8wŠßù>Jõ$¡m‰¤õ%Â["’Íx^Ïå'§1o##¢ò¹Ö‚«4Õà¦Þß^jž¸RåžUxçqèçÌ&êU^]Ó뺮O¼Ð/É+"õ°zÑš¼NÌc5UÚKÛ !b´*ͦjËÌø©&„= ¡zÀÀ„:³½sÿ··Àõ㲪WèïãÍû‹=œh‘™ñYÃ_ô7²½x’ íId©wšU¡ZÜët6ªÅý[§öŽHMõö[ž0DwîpÛõ-O†¹êLÏ—,ÃTX#˜àžOMJߨ(Í~å±Épcl"Üšš™Q’õ'™Y’ö'™a’™÷'™y’ó'™1’ÁýI¢RFGt2>sÔS)aìpÌ£äG 6ÈÃY¦äûÈÍ¥§a‚Ȱv–_ýÿÿÍò¯¹Ü“þåWÂgœ¿8Öúß(¿zÌêTç¦Ê 0? ’¥vhÿBíVû/I/½ù¹wößüŽ“ú†b†þ‹ü²: SrŸT‰Ø¿f$ŠÔË¿zJ •±X¹SoÄ|¬¡—úPíØ©ÎïLNéEóÑ9ÖÂ~ôüI7ÿâ`èæ_ÝœTt`>sÑý‚\t¤ü'cÔGÊÿo5ì“‹î”ßht¨l§Êtè®z2Ñý¡ßp‚ÑýŸðVtŸý{Fâ4£ûÃ>¢stŸÒÇ|(º?ÄÂÑýaŸtZÑý²ÿK¡Ó‰îÉZ²ä›ñé'Äe/zQm\Ú€²w^R’ës¹«F=•¨'¥Ñý÷\`’®,ÏŠck=öGÂýs2x«ê¹-Ï mdA·d®Í¤ÖZgÖàŒ¿Úªïü[¿£òˆÍìÿM¹'#G‹]Xà_¥ñƒD+ýТŽSõ9¾ã„|Îaßq€ÏQ—2‡ v ÓÀ'œÔL8ÌýœªòOŪS“Ù5+ –ò¤Y9{8m]îô¤Ôy[öì­'­ÙšÌƒ¾d>îd¯f YÑ|ïj©ÛîÑÇÿµî•ù¤4û¯pÊJþ€ƒ0!¾7—™R,I®";LQ‰¥dq©Òy(w"Lu±{9zú:eOO+ÄÓ”ÆfL#ÕhMR>(ì×Wk殃kùsÏ‚•ôy¾¶"Ðc®È¯”ó˜aîxWè.5Ý\]ŽvÃÁ'§€=º¨.4äÕ0lÐC ÐCПQÚøŒ‘8ÚF†² hÊ62”mdÛx£s–ôÒSf‡~dÅ|´Ó€ó Í>dwªŽ‹-]‡ÇÒÄžÔ‚? 7†Ë0ìI†ïÌãÖ “8N}‡[Y@ ÓÔNF~/__‘`üpËØ"HUð â†@•õ{ÛPòIEƒ#-^±g6½aZÞi2<›‡q&ÕWþU–X @MüŸòôUþÞS&ż>i1åoM/”6/OOLîGɚň&=orŸkEkÝÂRÈQ|Ï.¿æ†)-ò¤åT›,-çUÏr*…]ö,C¾ã4+ƒXÆnð¢¶ÎÝâeüœR7älò,›3+}Um·ÉoB½)ÀeEaÍUØ¡®6•á¦êÿ”ذuåÃÇÐj6`žóÀp„qÁ&<Òg£—×#ã!FEWDª¥j"Ä|®œP_ƒ é+±ú ïq=ÏPÍ žèX›÷2 . „üÖÌÔÓ½+ÃðªÔB°H–Ì œ­8-àå dX=×úi?k–»Ã!Š–@÷u÷ ðRF—-À­Zc®Ê=}ß¼§œYöËN`·ÄØüÂ(2+Md8n’õrÆn`öK/mOÝH6Ë)7Êkv~oˆÍ;µ³a¯¶á6løq{³«˜ëV-f¼!5ªßký<]´ÎOŸ §ºšäf?[§|ŸŒk[%ZÍš³bõÃïmŒ«ä?»8RûxZáazÁ¶§Ö·F}ûáÒ^oÐðÑÿQ2õò‡Kh<Ê8\Äé¥éC#dÔÿœ¸Œ'±:\nÃ!ËF>ßô–£ÎÜßðÍo;šÜf7vãv&w<+ÃÛ€›(ŒXëqß5˜Y]>Ú¤ ³†ªáab“ܜ³Ÿ&ùɮѡ¾R±ÌÇÚ¨aßúÈ|«Zö¯æK©sZóGöùÍ“>8Í.N³SgËÚ‡’÷ÄimÅ’è`MJÓÃýÈÕ§7ù>|b{°€úfÃ3ËwlæÙsòËȇm« :^P·’úXM†=­&ÃV“a«É°—ÕdØßj2<©Õ¤½æÏjv5žúj2ìu5ö¸š@®¿ÅgØö¬i{/Éj8U&/’ó42¨R£Êv_Íæ¨¢o¦ÍI27'Éyæ$¡W¶£#’ñ2oø\v(jí\a§÷»Ž Ï{ü&ÄZâ|>ƒ BôYMÝZÙ§Õh4™º“çÆJñÆQƒjfŒÉ1ÆÄ1Í1ý4Æäcò1%Ƙ^1­‘Lº‘ò“íÑ;º 2ùcô¤·µñ@~˜PÀ€Uï"âQ(è^HÍ;¾ëÀFÈ|)¤22¿˜G¡«ÖŠþLwËf ÀZ :oºiÍ=Ut»1€)áž·€¨, @–yå.‚0棺Ñ”TÀab»8•¬*YÑ‹-xÄkuš:ugµøCþµ´pÏ 8Æ›UÑ Çu”&ºø€}£|¼}fz͸ÜÛkîÀ…ä\HîÀ…ä\Lî@õ4û"Ï”­ß6çžž!iÞyÈszŽ"ïoZHö }Wì°)XKÞf?‡c`!–‚%oØžÃVHK&£aÉŸÉa ì+vMê‡Cèc±ðrî¥b XÜB½MLíŠ7tø]q¨wňvxáe»‰ŒŠ¿Ââ°º qðC(<$º+ÁA^¨ºÃ!ǵò,ËÓW}þBRËU¢™Ç 7C㙡ñÍмš¡YizM„DAØk¢ „$ BH¢ Ä,%˜5ÄË7Ù!"Q°' Jš>šü+h`ú›n’>O PéÓ •>K Pé“ •>G PéS TJTúB¥Ï(Túô€B¥Ï(Túä€0ð*”Ø}ûI½«ÞG|ÏÎOP.ì[N¢ùbô[y™Éž ý0ÓP=%tÁ ±L>&Ô”XîGr°Ÿõ»¢' ŽŠGΔvý‰ƒ|€Aì<±c¿ûl’¶i.' Ì”iY•÷-²¨/\7ja’Ÿá1ð’‘h{¯ˆ>m-Ú_%²écÑþöP«§Ò!æ!zIH´¾„YàZßBSáÞÿ&^ùfÞò†^ìÆÞåý¼¾ó!ZȧV_ÒѱbaÝ}1GQÜ]ëË8 _{G Þ¹›×lèwäöd€=L#>øÊ‹Ž~ûe‡LKÜC2ù\ŒØ¾Îˆ2+à½TÞYÌÁ*:bTß|ªe'0&¹…\r"vÛgW$¨ß>re¨ås%CÝ¢c õO`†Z¼k‚ë¾¶‘¯&?úÁúV rd|̯ #¦IåùÄ,¯ÂC¦yùB÷°‡>î9-4@#Û×1ì{$Ú7)Ÿ?³Òè1 ±}µªû*ù'|´ûfÇó0=cåá ÿáAœü1R@ÎbŽà³z,†z‰qXt¸ úŸSÄ`$z°p²ú9÷|PLØ @D…Õ÷0c€z…A€ßZÕG ì†rˆ¢ˆ&µŠÀ¯#ˆÊãÑ/`’Mú]\Q;OÉè#±Þ¬FØa ÔÊžº½ÐfVï@­°ùú@·ÿ¢®®ZT‘CWË=³<êűä$ ɰÅÒ¬@º%>ÐĆ`G8:Â!ÊqŽpw„{Zރᾒ2*t„#|¿Q½G84â‡!äJš€\IºW<&zÕ áwÞöàñöõvy IФO»ÐÝØÒæ=×c¹¯±:h,%½v’Á™ôÆ©¯oslʤ?ösƒ§õŸJ²aI¦mm>hÙ.%Û\­: ›{¡•(›ØÞc}²!ªYKÖw1ÝÏë ˆ¡Î€X$ƒ­àõ0\Zž°6[Ò²DK ÎbIìÁYwá¶ÎR–ElEK8‹f<†³D±à5¥g‘ÊX£YÒ(ÂËÕ+Дå²çWîÏå7¶åÈ“ž&8èïsïøøg ŒÇÐÄx ñã1Ä*ª0€‚¡ (òÀ¯óU]'tøÜJ½„EV’ð¸5(¿ äžÕ®0nXmLx¼å½Ùì0ûM¤Wä±ýmv6 /tß¨ÍÆmÿÂèIn˜Ú–ÇY®ïØJ¹Â6rú½ö>vù7¬¢ f[ö’Á˜†ˆ†½j{xÚ"B¹ü]"çß%B.%Ñà}Õ W_5xÏW ŒÌž)_5èÕW ÞóUæ´mÄW Lùª)_50⫲SŒ«²^ãªì½¸*3²Òg¦âª¬×¸*{/®2ªm¼¯ÊLÅU™©¸*3We§We½ÆUÙ{qUfd¥ÏLÅUY¯qUö^\eTÛF|•™¸*3Weи*4p\±å¸šÇœÿà ‚k4:ÓïÊß;×n<,”0þˆDÕrƒ\œÍìêKK×›¬ª±jÿ]º>åQåjo ôÛàÜœL° ^ü»+7¨\¿‹v•wéGì ÔG€^ü˜È;“àZÇ(üe÷¼l”`N¸^ó>*`¿G|{:öÀgf‘{iô#`Ïò> ¨CæG˜{Ûƒáö±ï2÷¦m3;ެɜõ²ãmãv¼­rõ±ãm¤—o«$}íxÛ„Ù¿ãÍz²ä¾w¼­2õ½ãmªÏï~yúÛñ¶ÊdjÇÛFnnÇÛÊÞÃŽ·MŽrÇÛ—C)w¼= Pìxû’àdv¼­ÂÒŽw¯€'µãm“r»ãýÙ•o_Ýñ¶J`tÇÛ&™o+so{03;ÞVæÞ´ Þñæ5]§sÒò®<=ÄoÈd ô{ƒýÚ-:äõÄŸ Ÿˆy½)NÇ6Àú-æá)ËðÔÆ¥7 ^¿ÞbîÍͬ_'“7yWžþæBO©‹7ØM®_{bèÓ1^ׯvo1÷µ~íæÄÆ¥7jfýêaÿõ3TÛî̃3ö]ÓÄ–ŒŸV£Ñd:d“çÆ;.·ýÈ3;-qœÓ‡Ÿ–8óÓççi‰ã–8þi‰“œ–8¯§%κwqÎ<Áy}„=ë‘~"ÿà2ÿ»å Uù·;êÝ…êUU}’÷F]Dê@´/rõÂEÓ^ñù¥:N]ì9LíU$Ïê|Dš„{Þ¢·áIƒgå•»˜7Ê(©^¥søÊµ¹nèn¢˜'q~Õ°qƒíB|•÷+\YÞ†ºùÈ„W?Ë)?؛Ү1µÞ–ZÅ}`$®Ïó÷‹î[,Â34ÃÚÏÔI@[—: f—rQÛ'Ó æã¼­û¡€Wì?B½cÿÌ]²ÿ 4'f  ׇ¨Ý³ÿ 4§64ýùVÐõ!êþ ÒÐb¶¿;KOÓa¿@=ΈÖ#ys‹Yk¡¾ÉÅlß Éé˜H¿‹™ÁãšQ÷¶˜í‘æÔ†¦?ßjh13x|ô!j¬ÂOé ÷ƒ2õ¦ÃG¹”©/u€§c§¹¢†*<<µDÉ2¿@½)>¶|“ÞDlù¦ÆcË÷¤91ûÀ. oS›Ž-ß“æÔ†¦?ߊ]ÌÞ¦îÏ -f§’(ù€@=Έ~%oÒ]ÌN"Qòž4'f†³“H”¼'Í© M¾ÕÐbf~gö65Há¶4#{•°Ù:°|>¶íú¿ÜE!j¬ÞeöÅŒ2°÷hAÆõ­ÃÊz3¬fc†Õd6dX;´f k‡fXž§6öŒ5¥&Òx\8siÁ ¤IdÆ$2ƒ&‘4‰Ì”Id¦L"ƒ™„®ûcê‰âE¨o§7K@‰Ú86‰šŸƒ"Ú±‘)ÕíXQú<–¶çú*œþìŽgKK0‡aì¬ÍúŸ ­+Ø,Tc:{h1_+iÕKÝ ›¤ÄêS™HÖ7©å¡\7PµíÉÚä}ë•9îBþzpÖ$¾@~±"æ¯Qð 1ªjß z!>Wcü+uy¬“ƒ|!'“ˆ¸íZžûÙy|Qæ] Cêû¢:Ðf©/·¾šy¡&5~™¸Á:àBºm>W͘ r_«ïî"†, ›ùel9î«Áa¾Lb+29¶W¹£6ø‰7û–$§ôVüÕ²÷9g„foU¸ÁíËË[ä~è¤^h˜TÍPƒË€è'xý¯¢ŸàUô¼Š¾‚WÑWð*ú ^E_Á«è-xý¯¢¿àUô¼ŠƒWÑcð*z ^…éàU˜^…ñàUô¼Š‚WÑGð*ú^EÁ«õFì ²"ë¸ø•ûbVåþx§Ù7bU܇ö§Zo†©HÒ½!*Žô­ð7®o†¦@Ú·ÂRœŽß Iq´o‡£8-¿Šâxß CaÌm!(lXÛÂOØ—µ†ž°OÛvâøÚCN˜6÷…›P¶PJØf‚gæcÌ™ùsf>ÆœõcÎúˆ1g=Ř³>bÌY1欗sÖOŒ9ë'ÆœõcÎzŠ1g=Ř³ÞbÌ™Ésf2Æœ1g†cÌ™ásf:Æœ™Ž1g¦cLÛ|Œi›1mó1¦ÝCŒi÷cÚ=Řv1¦ÝGŒi÷cÚýĘv?1¦ÝOŒi÷cÚ=Řvo1¦m2Æ´MƘ¶ÑÓ6cÚ†cLÛtŒi›Ž1mÓ1¦c>ÆtÌǘŽùÓé!Ætúˆ1žbL§Óé#Ætz‰1~bL§ŸÓé'ÆtzŠ1žbL§·Ó1c:&cLÇhŒéŽ1Ã1¦c:ÆtLǘŽé“›1¹ù“›1y1&ï#Æä=Ř¼“÷cò^bLÞOŒÉû‰1y?1&ï)Æä=Ř¼·“›Œ1¹É“1¹á“Ž1¹é“›Ž1¹ésn>Æœ›1çæcÌy1æ¼sÞSŒ9ï#Æœ÷cÎ{‰1çýĘó~bÌy?1æ¼§sÞSŒ9ï-Æœ›Œ1ç&c̹Ñsn8ÆœŽ1ç¦c̹ésn:Æ\š1—æcÌ¥ùsÙCŒ¹ì#Æ\öc.ûˆ1—}ĘË^bÌe?1沟sÙOŒ¹ì)Æ\öc.{‹1—&cÌ¥Ési4Æ\Ž1—†cÌ¥ési:Æ\šŽ1ßj²š·Æ¿ÒpŒùf£xœfÍǘ}5ˆ»?<’ÔtŒùN_xܸöc¾×§ã>bÌwûÀã´ÜKŒùþï0fƒ1f{ßwØ—™Œ1÷ö{Çñ1÷÷y‡Œ1÷÷wþ4cþ4cþ4cþì!ÆüÙGŒù³§óg1æÏ>bÌŸ½Ä˜?û‰1öcþì'ÆüÙSŒù³§ógo1æO“1æO“1æO£1æOÃ1æOÃ1æOÓ1æOÓ1æOÓ1¦g>ÆôÌǘžùÓë!Æôúˆ1½žbL¯Óë#Æôz‰1½~bL¯ŸÓë'ÆôzŠ1½žbL¯·Ó3cz&cLÏhŒéŽ1=Ã1¦g:ÆôLǘžéÓ7cúæcLß|Œé÷cú}Ę~O1¦ßGŒé÷cú½Ä˜~?1¦ßOŒé÷cú=Ř~O1¦ß[Œé›Œ1}“1¦o4Æô ǘ¾áÓ7cú¦cLßtŒ¼ùú5Èp‚7ŸA¿~ëþWЬo=‚Tñ›o ?÷Íù½o½€å}ãt ïÛïŸøçÏ‘Ìo¿~Tö;Ÿ™ß{û¨î÷ž>R¿ÿò9޼ýásÜ·¿{Žû¾=Ïžã>pï«ç@Ê}žãÔºÿÍs,gû“çXÎöÏQœa/QjØK”ö¥†ýD©aOQjØS”ö¥†=E©a_QjØ[”ö¥†½E©aQjØ_”ö¥††£ÔÐp”šŽRCóQjh>J {ˆRâ԰‡(U˜?¯æÏë…ùózÑÃy½èã¼^ôt^/ú8¯}œ×‹^ÎëE?çõ¢ŸózÑÏy½èé¼^ôt^/z;¯&Ïë…Éózaô¼^>¯†Ïë…éózaú¼^˜>¯OÌǘ‰ù31c&=ĘI1fÒSŒ™ôc&}ĘI/1fÒOŒ™ôc&ýĘIO1fÒSŒ™ôc&&cÌÄdŒ™1Ã1fb8ÆLLǘ‰é31cfæcÌÌ|Œ™™1³b̬3ë)ÆÌúˆ1³>b̬—3ë'ÆÌú‰1³~b̬§3ë)ÆÌz‹13“1ff2ÆÌŒÆ˜™á33cf¦cÌÌtŒ™™Ž1_Íǘ¯æcÌWó1æk1æk1ækO1æk1æk1æk/1æk?1æk?1æk?1ækO1ækO1æko1æ«ÉóÕdŒùj4Æ|5c¾Ž1_Mǘ¯¦cÌWÓ1æÚ|Œ¹6c®ÍǘëbÌu1溧sÝGŒ¹î#Æ\÷c®û‰1×ýĘë~bÌuO1溧sÝ[Œ¹6c®MƘk£1æÚpŒ¹6c®MǘkÓ1æc†+Ͻ0c<ŽÃø~0š|Š]&r¢¡!¢Ïg£•––aƒå·Á% Ñ%û抄¡ÃÙÌ|pƾ³˜KvÁw8‰>n‡s 9¥+Ä\ÆýOS6=cf˜/–aø¢C¸Ã%2+Mv¿Cw•úãÖÙ亖ãתIØÀ]·›(†ìæ-ÛÄPÞJ¶ ¡Fåzmó(qÀEI<8¯ýrc­êk%õݧ1üvþÛ¹r¹}—Ì_V«Q?ìr…êëÃW}Ð{Õ÷°?}{Ñ÷ç~†ùs?_kMÍ/ÿ%¹¦¬!Âh:4Bp³ôr©[!¿Ûògé|lËߨK+Vá”ÚFØ£Ñà,Jg‚ó—p>yò/ Ù8l*ÇqcùësýëLjrËÛAbF¡M“‹¹üq,#CæÏDb%œ%£Ó‘uȘ°æœ-f©¼Æ }Õ‡(Qï¢\ž,FOöôœÉú%E”KÑŸëÀÆD¦¡¿Ì­Òíß•¤á4¹òBÛòz›§—QÏš žôi Š?“ÁëO‚(•°{å—øÚ£ R•ÇéÏ®„š=Zá•ôÈòÏú4Ã+ð×>gâ•HB!šü683)Ãkïî@ŠÐû|¼Vqf¯ ôõéGã×ÿ’HüZ¤A¿kì0ke¹^"l ú‹tnä¤:™°ï6šYöË\Io ¹Õ»Ù¾×½[± 3ß Ö=N[åòÕ€ôÞª*¶¸ß8,O+{Û•ÞcN*?Æ=ìùۛ秹AçÐãîqÌwά rç)g3ö–5ù³“̹¾)æ‰Ez­²ö“s}S³9×6QŠœkf.çºOŠ(—¢?ŒméÚèMæ\[ù{ ¾[%1˜små7˜sÝËÈÉ`$èo—@ç\³^ùUާG̹¶ñ͹¶ Pì=û£9×vÌæ\[exíÝls®ýÉ`6çÚ*ÁéG㧘sm—ÓdεMÃ9×VÊœëÏÞDè+çÚ&L%çÚ›Bª9×þ|éœk» eε·0ÐtεM“9×=üý}»ÁœëþÞ¾ÝTε•»Ç17•smã6’suƒÅžœïÔÒå—êâD䨉/Té-VïÊ£®Æ”© ÿ†¹÷$<—u#ïãR˜ªzO=\j£òdû~¿’œÈ†åCržÊ®å=aoäðæùÉ'{zÁà™ûwå1T¹ñžÆ*&Þd_ðü›ñ±1¿¾'Hq5û´f’êÄž¢–†'¦%x`ü®è踠%B•d½Eˆûå9•q¯„›q&ÿʀɿ¥…AqLm¼'Ç6TÌÌ„Šû%9­Pñm9O,TÜ+l%TÌ †Šûå1”p~Oc‰Þw1*îÅp¨¸W©Új LÚü‚™³ùÃ3eóJeÈæ” ióQZŸ‰á©øùãÛüÑ‚Amþx©6¼T†l>Û'U/~þxÁÌÙüa‚™²ù¥2dóJ²ù2Ýî¿ÃkžßdB™Y“d7MXÿü+ÆÊ}¤mÙK•^PG‡úçà‹mÜÒN«•jhŒ d­T‹l¥Â¸§]ª¬G“ÌÌ™dfÎ$aù¯V*S& Ë€]¹ÁÊò\‡Yñ"õyà–Ì]*Øš¹C…²‰Aìðà–Í€‹„;Ûîé¹êî·-ÒaDÍÞû0¢f·}"¢kÆTT\_JC6Õ¿ýO(åh}0j0„0ƒ¼{;ƽ·rær;f>·sa<| WÖ›UÂbŽv.cV ‹:Ú¹ŒY%,Y›+&õ‡Œy½’-i-\M"¹`Kõµ/'ïº~‚þmv†ÌÝí§„eåöR¢fÜ^>ЬÛËšy­|óV30o5ÃV30l5“V“™÷5™y_“ö5™a_“ö5™y_“™÷5™a_“ö5Ò×Ü0Va,¶GÚLM%K÷KÚ¾¼AˆÙÃì'í„«}ƒÐ¨Ùz7Ûi³˜6[œ¯}ƒÐ¨Ùšõ¶YïÞ63ím3ÓÞX¾AhÎl¡¡åž½mfÚÛf¦½-4²}ƒÐ¨Ù½mõJe^-ÕO°ƒ1ØèæP¹NO&sín•ëädB¹‘ƒdy–ƒd0çlúm&sD}ôL8TÀÓ“©‡Î ‡ xr2ôC¦[(&ÈÙaà¸úDteÅ®5óøà,w¾f–×ìÿÛ`€§•AŸAÚ‹Lªy4QjO÷Wʙܕ¼Œ§É¥Ÿ&üudL¶×P²Ý“oYË‘> öe·ùtuûß &‰ÁÂÁ‚ Pæö vzBVç…À,Ï YŸ[…èw£p˜H}ì–ð…êa¯p°„§'”Idz»p PžLôAIÌAì…2}\°Ó ët>*Ôé|TƒNç$‚ ŠÔcôq OP¨þ‚ KxzB™ôG=Aä>Ú(,ŠšÉ(¢û%‡I`FmÝDÌ*`¯Ô ô5pKSô\_R1i—|p¶´sxÆ~ÛŽ ­+ªöNë}A ­$|Ác“´ƒX}*ÉÚã&µ-ä¤Zµq«J3“Š1ÜoeƒG ƒ1žã„Ú‘Â`ŒòHa°œÒ/mÀ ƒ5àÄðÂ` ø@ap¥Ål OÀ! ΀hÀGƒ3à#„Áp¶OÓøa°|˜0`>P¬( Ā߯Þt¡‹¦©Öä¸Ò…–áëUpî·.;¡¹ß¸ûCD=³f[T­µ…‡ø‹-<Ƹá¦ÛÙÜ ­dîr¯õÄ káN…HØ.wŽ©tÚ ,çg*L|Ò¹´áEf, cGŒÜr .Å:°Yæ&K&Ç GP¶ký¤¥¾páy3Ë~#UÎ"u³mQµm…:æ é*x\rž¾¬¶ì“)swrJ †jMr\…‚W¾Rd¼%u¨±ž[Q&ÀTIn f|%°ÓÖŽtÇú¾s`]Þù²ùv5AØÞy‹ Å\Œ7Á”.68°‘æ7uðwx|Žñ˹ûÚÞÐŒŽÂ•›EðóÒ[²Ø],Á*Kâ4ÀúÂ+AÏ\ìg\ÍÜTñ¾åàáþâÅ2Èí€-Ç«Œ¤BÈ]’ãºèÝ„%™Ëý,zD4Iuö€‡fv™†¦˜@òìÚUÒ`—¯ëEÂýصX†™Üî`IR93géJr£:·Çi«°eQúÒëHõ(ǧ1ngaèY^´´°4¹¹˜¶ç[š4Šxl£Çàƒc{°{^ÇÝÜ‘ÜßÑÑÉ A‹fhoi ÿ0Èic•dÑUŒQWÀv½§x=ü¨ÎCvªâ¬2 íUÇYcÀØuúQ؉êp=¬7íÝüQ‹Q`1UÝäœ&ƒ+V~vÞ%KþžÍ`¨2»ÉÙ“>1î¤Âr'UŒ;©2€ÝIv*îÄÜe‹&g«ùgXã„… Uãî$ÛïNðú»XtRe»Xt¢ZcžÌ=“£¥ÁXБҀ¬íXi0–y¬4`+>…Ë&GK¶âS¸nr´4`+>… '¹4§rãähi€V|*wNŽ–hŧrëd+Í)\;9Z°ŸÂÅ“£¥[ñI\=©<°it gAX\•ahä;03§Â²¿*ܦÜW„–n“Åwí³Á ÿ ›{Öb0L¸H˜¥žmç‰êm7ô¹ÆkÆ×Z ¢\Ú·bc"د¯ƒÛÛ›>Þçz‹ÝØ]o±ï•®â:’ù«dpò=¯uá‰ñ/v½E¾ÏÖáŸýÎÃ]xàwݪ+pºf¦Uð! _²ì©ò0éýÝP´nCgüÕæ‘z¹YèuC¡þUMÏÌK£\³\$5û ˆs©ï·ÙK^¾"€,­GšóÄår‡Æ‰/æ®ç]°ßãÕEÚêXä2ÿ‹å¦DþõôË~G JøÔ«]š¸çñž±£ŠtOhp®í0ZÏýD©ñÆÈ;ô7§ã¶Š³ÙL ì{¤Ã“RA+;,z“´Á†Nm™¯þ§Viú œZÅé-pj“¦œ’Áyþ÷Šä¦ü»hgÐ&MMeæy÷GSý(¢hªU³ÑT«oDSý ŽÁhª¾§hªM”}ÑT?ã¦ZI÷DS=© åMµ’ö1Ø hªŒ–@šÜâc”¶ÅÇèG½‹·>™RÀãÅœ?-ÈØŽc›G‹ƒ6åS¨<^´)ŸBEàñâ Mùj qN¥(ðxq¦|*eÇ‹ƒ4åS) ¬ˆs •Ç‹ƒ6åS¨ <^´)ŸBuà­¤Ï%8—?`®æ1çÿpDÕ-‰J1Ø®JPêLÇcÄ?t©Ž*%To*e`ú“ÀÆšê[|ð€&c²Ž8sƒyÒÏ£Ÿ->@?U…R¼Ò»_–•…È Î,'Œu,ôÒŠÿŸÎŸóIü5âvÂj{Qk(ûÃK6[Kóxúºòe°#áï>Ùà·óßšÞ+ŽDqut.mšÉÐÀw+áO_V+ê<±$¹`ê…îWl5vF«§¯öä™Mš‡“¯ð;ù-òð“gÞ·<Ê(¶“d—ìK°bKø$ºœ§Iª‰—ú[HŸÙZÝÚí-åÀ+ŠELÀ3©¶ÀñxŒ± ÷÷~ Í sÅ6'ürYÒú[·Ù“Ýz€gö|ÆFÓ+öôuzμºp· ÙÚöM½É–,Õ;›GE«ÛÕ‚<–ß…5kåù¢õö¨²½pÈk=Õ,U]í%Y›ô#ÙvøuA:`ü%‰\ÜùZ½ˆ’Fn°Pí×v: “\LPtvǶ–  'ô-7Àû–©Ø%h&·u'BFåñ`‘,M|T˜&,œç“ËTìKZÕG‘M«Ô¯§5ËÁNèÉx8?&0žÌû}òÃäÛ®µÀ…pKKß©ÚràæÚ°œk2,Ÿ{*†…qo¸ÒÀ“]”ÁD°²å¶ûªt†>Ï(ešíEº7ˆ4Yû6¿’Nq›éˆïätðBœÛn° úŸáM§'š§É…-glðõ°+°ŒÅ1À2Š€óÀñÎ,’t.Æ¡IDˆïN>Sbô¯ 4ÿ.ç^*–ýë¹£wE_f(‡$‘AI"ƒ\Òõ‚'žð6û˜Zo¯„×rEž§lzÉžéoõÐ '†“¯Å¨¥|o®àæ”G DyA¨ãß«îˆ|»´T2ÐæÉX•^èBÄ¢Åÿ·ÙÙh4šáîm¾ÅžgW»B¹ܼoÐuf’úÒV©J³Ÿ[pýÎk[îì•X[iÛŸé² –ô"CÖ« ž'YÍŽxÉjṽÔ?âÒVvÇ´„‡_±èCÂÃ*ç JX}\®Z£³®úFP/´f¿öȇ"zñd½Ì±-Þ{ñdýÌÑ×”û‘ñd­ñè‹…ýÈxRöX–¤ÓÛݦ‚¿¹S|}fÐ{K€A¯d}k ëCÍ{ì™aöí¾½ZÓ_»÷Þ;xÓb”{ø~ˆÿ‘;ù~„<0°1/ä‘M?BÚ²¶«ï‰Ùô<¬íí{b6þÍÇîð{’ò”½ÏÑûüž¤äUB ¬@¨ A€® ôº€"VÄ‚‚XOË b5A,&ˆµ±” VÄB‚XG0ËfA,"ˆ5±„ VÄX?¦NKä²c¦eê¶€^tzâC‚†Ðdp¶}! Rº÷ÚžwN;gµ:·Î®A_à…öKþ&Y#ý7 ãÈ;dµ´Óxaùmý%ñ<™¡ïÉß‚­¸ÑuÒI†"©¼Ï b¨<Ì‹bؾÈÛ~¢A@2T¾=ãÖ‹zXÇR´—:¯a±†¬Ëç0ã­³ ¬wX}ýDQ}ö·1î„,ÕAR}êDQºÝY:GQTž†Eçµçg1_R ¾u"n„¸íK¼¹´fü‹ bã_ìFL°i\¢6H¼iL \ÁÎko6cFî¢9óÆÚd6g­æ­† `/˜ÃÞ´ö í2Ô+"±FCq3¬Í6æ0VÝ5u6yPqç…ö<Ì–T‹0^·Ç!žî¢þd<æc.ó)Pn}ß·CýÁéGJí‹=__4Ek½àß{«Ä¿]¨±sr‡5)/7ýÁá_Ô$‚}Ѧ£wùEÓCº<ê°žÎH¡¢´®©wp6$ÔaýšAB¥ƒ_S®Ü`ey®Ã¬x‘ª¢MÀEÂk[õÝóL‚ÅâZåÊ;"¶åy° àõ6G^Úò¾”<Œ®=3¡Û{ࣃ}ÝMuMß¿•A†m"Ž,n·IÞÔÐ*C?zO@azPWÎòÃKî2cËÎ7Ú£³î¹„}t­1ݹ¤+¶Ôï{g¤ÿÀƾ;}ù]ï}PËf$áRy‹›ã{ÃÊrûœ#ŸnÃÊr»šŸÛ–Àl3Ê«~LTõ9ˆ­¾‡!¨< ‡€ÊËo‚#xèóÈw܀œˆË9öU6ˆ0·ÊçXž¶´È¦/ã̆U8ƒÝ¾UfÑÝ»ýDæc} )͉Lî£ßµÃHƒ­ ½Õž SÜ–Nð-×ĺB¶Üë ÙrI¬+d˱®-WĺB¶Üë ÙrA¬+dËý°®-×úB¶Üë Ùr9¬+$äÔ£õjXWЖ›a]![.†u…l¹Ö²åZXWÈ–[a]![.…u„œÞ ðüœ’ñC Ï»­ç»”ï·W#§|¿A -å;õSÚχ;õ_³~¨S-ë‡;õßPÒЩ¯c¹ð´c§¾‹®¦Õ½SßÅ-L„nu(Eèҩﲫw!êÔ×YŽi—æuÝÚ8O?Ô¼®ë|ÿhóºn÷Á§­-ª:ŽNk‡ªÎ˜-{ÅΘ-›ÅΘ-»ÅΘ-ÛÅΘ-ûÅΘ-ÆÎ˜-;ÆÎ˜-[ÆÎ˜-{ÆÎ˜-[±Î˜-{±Î˜-›±Î˜-»±Î˜-۱Θ-û±®˜m=ž:B¶µxêÙÖá©#d[ƒ§Žmý:B¶µwêÙÖÝ©#d[s§Žm½:B¶µvêÙÖÙ©#d[³¤Žm½’:B¶µJêÙÖ)©#d[£¤Žm}’ºA¶¶IêŠÙÖ%©+fÛÙQWÌ÷z$ .»¼Ý#‰€àÍIïõH¢àx»GÁ;=’ºn1wyöÔöÓò쿲@΃ûž7{$Àû=’SWM’Öâ0 ’·{$u="™¾Û#‰€áÝÆBs×;-ÚK;fŒwXÚë XÞi,D¡®÷ Q°¼ÓXˆ‚âÆBï4"¡x·±Ë»…º&wwûû|°z𼻟<®±!ñaÝCè‰ñ…èˆlCAünc!‚™ó^c!Ž# u=kma6ÓªÊl¶U…ùÐÆBfƒß|xc¡®U-¬¸çFÃúÆBÝwKk,DÀó¡ÆBݽéû…HŽm,Ôõ½ú£Ó’úˆÆB]kZÚø¹îMÁÿ±ÆBÝ3‰l,D@ô±ÆB"Ø‘7ºê¾7¢o,D&ec!„P/ÌPõÆB݃›5êîÄêÂÓ}¥<¨ „nJEûº®]xºVTtá!¡sžËs:Žïƒ’Á¬êÂÓ}Ô…‡€®Kž‹Îg]ºðt§« Ï óžô­.<ÝÑêÂÓ9ûvP ¶7ºð :–ò½×…‡Ÿ¬ Ïew]’uá!’…äÖ<¡,·Ýey« OwOñfžîèowáé^ñN‚·»ðP ¾€° O炲 ‘04.‡P˜î>§³0ovátΔÞ…§ë-Ûcºðp¾Y“Ð]„]x®:ï…(»ðIC2¹I¥éžTì.Í›5ŠÝÍòÍ.<ðouáéßr‘§cÔr§#bË5žŽˆ-·x:"¶\âéˆØr‡§#bËžŽˆ-7x:"¶\àéˆØr§#bËõŽˆ-·w:"¶\ÞéˆØrw§#bËÕŽˆ-7w:"¶\Ü醸Œxßü¹õæNÇzïçÖ«;Aß»ùÒñýøçw/%W)zÓ-i!þ``OG|`¥(±W)J@|d…%uYaIÈlöéÆ ó¡–tß|h…%s×f‚iÝõ„™@„Î'Ì#Ñù„™N†ãO˜Q2˜ÕÛ{õŽæöçám¯ºåÄþ<¢ 9åû½ßnºÚìR¾ßF𺛥üyTARÒ·$з$Ó·¤¥=  ­–n#ØÙ´ˆè :¼+ÈGÓ¶Ý™î´Ð°©®´P¿h¶Î»$¹ùÒÆ:d.R/1L{H¿Àîìïö 츴ÿùÑ~]¿¥5¿2èX3ügk‚¥k8Òš`é ú^s”Î ~/ƒCñïõ.¡øˆ´œu\Vv‰Ú+–©‰öVbˆ€_ôf&ÀÐÞo/ÒÕï5IZ«^(HÞn/B0aÞi/BÂÀüµuÞ­³’d¨¼cÆ­%@–÷Û˜ÜvK›í²ì)®í‡MßïcB¡¯÷û˜P°¼ÓÇ„‚â>&ïõ1¡ò÷™|É»Lh8ŽhdB¡Ãã:™P2–Mï%{BEÈ|àA qÜñ{FfÏ‘Ç`_wä1!󡇎F|ä9ÝGzFÁ|x§‘®YÆÖÜå¡a}¿ÓHÇóÔ6Ä›½šç#FºæF§é4BàëŽí4B±bÛj„–ûˆ^#9s$àCÝFæËǺP}¨ÛÁÌüX· "òn#k}·2¡(»P8Wòn#B½ßm„€å#ÝF(h.·ìµýôö”róö&A¦ñZmÚË“oÛò$R%”¡ª8LÓ:Ù›Ï4®“ý’u²]¥ß[a|ËêŒà ÔzUAGÊîBew¡²‡PÙC¨ìµ;ZÐï¨3¿)4öM¡©oê)¦;P£:0Ö(¼U¾nFoJ`D¦ÃÛ%Àêà#÷`%|H³ZèÁ>$‚-ô8!úÚñíŠðæ3Zx[³ZèÏÞ«…Þ÷ÿGËb^/FsGË‚ÕËa…w`Å(LšéËdƈf>X¤hF3¦Íôl3ªl¾±•‡þ{ë 9ù*åÂd‡k)DêFàÑËìeÚÎN»"b%ÎÈ%Π3+ }•Ïñ¬›‡1³'æB´ÞO%#ʤÇaü5ò\ÛMè©ìW+¯«Q%²xàð ÙsÝ犘¯•…†c[£ˆ@ÞôA#Çæ WÝ~JìÝw5:ƒ«KU, ¤-q;áéí4ŽkÆ£õDÏãp«;i+7NRËC˜¨Ã}+XxáåC ð<æÆæ°æÎ_uûukGº©Vå#ˆŸ"YxáÌòvK¡gsˆ'Z¤Vì0kÆ8pûWêÆ€iÃÇr&ëRojøHµýjñ4è1×=°„åªÐ5á¯nmL»&#€Èí3[ŽdF%öówF4KWÜf¶„1½Üº!8-8Lì|"ÁÏ‘à l˜¾ž”-‘Aš–È´ÀŽºÞ-w&ô‘õâõ•E<a`yn²f«3Zü0°9‹âðµ½PìêfMù’¶[«2%\$Ì’±¤àïmãû¿oËù_ž;{õ½áo"ümøÛm‘ýŸ£¸þëÇó—›çðÄ—kµü€¿¾²¡ü‚ó³.*+`]zV2 E–3!´gŸùÜJ½dz÷×r$<wÄ\J 0Ÿ¬Xðû0Hä® #\1êìõÛ 'CsB¹k!C#SYG°Ðs¤åý¯ÏvèGVâÎ\åâ:bJé>¥ó9ïT6ej/¹ßu8^KóË‘§î?td]ƒü¦I! dÌ®Hxü:¼ øÓòR „ªN=rÌï—Ü~qƒ-þ(ŽG:¸;Øï<à±kTç"Z4í^»z šü/+Ô ­"×Ûõqà&ßS)êg¹ÆÆ!ÁDmàJ£}!ýx$°ãG9X0:õsþ˜&QJ0êêK]9þáŸ]›ï+çÑ'Ï ^þöÞm¹qY}•ºÚ}±c:Ä“(­Øë¢Ê%w{\åîéÝ0h –9¦H Iù0¬wßHJ$EJ‚)Q2*fª]¶õ%‰ÌDæ—À‹èµvÏ7?$?–¬Mô#w:zK¿¦Sx\ƒ, lÙdÑ=ƒSr턱KabÍ·¸â¯äa9…)]·$½ Ѧe‡Ð¹ù“®i?’µÒ™ºtнbÊ!—óë'h/ßQã'šàäfÊ•®÷œ-¬¿XÄZÅ„7}&î ùæ‹ôýÞl‚‰?_Pïd’ÆKuˆ˜â‚Y<“åCBÕ=ç uûšØ9Øžø"‡øè‡¾›57¥Ïñ°daF@·…ú•x°¡ oê¦îfÁÁÂ>¹Œ§ŒêZ`XêÆü GB²p=Ø)f-é8™),&=Òˆ3÷Ãx)wä4†}û7]?T'7 aæ/謀°™_Ê„)ûÑÛ¢ ÚÿUÏiÛäŠø…„Ó¯‘·_w”M0,UÓïðsûF÷rèòó€ÀŽø1Šü)=À_ÝŒ¤WQ°œ‡™+:jŠÍOÄwhԵ댣7)0µ€)4] 832^>¾w3…ÆðžPи<8‚3ÕOn2ÂÛ‡ý&ÄCOçÁgjŰ ñ+©Ì¹õ«.½L£+v1@}ðq¯½ÑÌ×»Jßà''òÌ£ø½YŒ%—‹Q’2^&O˜BAïˆËÎͪB‡ƒ¾ž¢!ûÁ¾ù‰…œ­ôš*€þ#!?y’]N­ŸhJ@â_7£Ðfw£p³›K‰¼ü:öër¾¸Žâ¹›f1IdQxB:îæ®‚GÏ^BÍð•Ê;á2rß"?n'1>rs ¬‡ý2A–·1ø[ÈŒÕoQô¼„_@8’!I¸Ž ¦9òI¿“Ô-®wÁñ3-÷sî§)áŽ0¸¦@Wf!ñb‘~F U2 ?ÈkÍö„ý}M¿b`7ï&ªåÍn~¿qPÀu«|ó˜‚iŠBá³SúÌòçžÜøŽ<‚;_†°‘ÿ4†(€áñ+tŒ ìœ›hoE yò8^<–ã½ãyîÔDÛ„6Êjc÷ö¨ÀÔ¢EÃF:$'ȶø½;CpRüYÅîC@þùä§ÑpvU_ÎòÌ#(×KàÌäìû*#eÿ`“Œ”¦Ìh`!ÔÊGÀ«‰ƒ.“'`T´ ?¡6a8uƒ(^÷YYÉ}ĪL@‘³ÒgÍCjÒ:~èÆïŽR¯ˆC'Q,—SúsyL– ½Ø8&ôZ ‹;AðËy6™àSÀ0Á§ ¢n]Ià3ÐXçÒ¦?4H¿ˆ#$ =o„gÛqúÀ‡ˆÉ#‰I|LƄꋂp5O5fáŠåÕ0Ðð8×èIêÆ)ŠÉ‘1Èe¸`÷t„“ÝóÂâÔÐ$…V!o>ÿFW^fÂ|%)ñ`çº&ÃBâ"n’o>pì…ãNÐ'g‚;9óàó•›RÃiöy [/AƒGcKØwÔ¥ÕYt®Ð‘᳤+d!Y²?înÀ%L§ŸÑ2²3ü«'?€_ü9î7?V ›ž©fFŽNѰGH É9z¶ùø.ì-v†{–þ oéħ*8Ü”£cùü8&/xƒ‡ŽÞg¨Xãe5úåªCtE)ðFa øð©Ÿ8+ï½Kó”¥j8^йŽKY¦ÑœJWÔ=…Žm—à©ÑÊ’Ø]$šŒ›„Y•ñÜ1Î\ÈòJ_ÿ}ì†ð s-â*Z²Bq*D¯¾oMвµU ö£éqÄÀo Ø2Z$~¾©JøAf±ªhñ3ôúò] Aœ+T…Eñùø}fpTfJ6Ÿ¾MÖ“P·ûÚg—˜ÓÅ„²ÓŒ"(Š‚ûèž§&fäCÔ^‚Aù]–bi…ôM’ø)j6G _\_Ú&£8_\ïù>ÊŒ1¸+ê«CÀÀ lCÉ\Œ˜WÝ€IÓcUÀ˜+æÀQ»Ðõž €–óL%J„YŠ@!®¢ú@€…}ÏÒ/09N8…ß\£Ø•äÌpXB=L4SÔ£ûœõ, o€jo…š¹Ô0GáX ,šöü-Ž^`nÂÇF ß$P‚Z ³Bg~'ñŒ€-»¦tu˜wÉ« ù⃃9 '(ÛlRÚfWKˆ÷2yŠkW†0oåj è?c?%W¿¾Ãzr!&‘cýc¥d À9´fC…¿«\37 |Íá ›.³’À,|œ±ãožd€àÜêÆÄfî*>÷ 3ÖW2¢ =ƒF¸ðϹ1€ÍlRäßx; ä̦ÁÁÎN|ì#IÐÆ)‡½:t1áé9Œ_>šáÅøÁô,­8Ìïu0üŒ“¾d†>B&Ë—÷”9nÉrNjµXÒ—žWšùGa-€ß BßGà£7âAW^3h7ŒBFI[UÀ–\Ê +#o̲ˆÁóArø«¢Ùz¾ÜbDÌUÌ¡™9íëNšbŽŸ“Ðù»EÊmpB¡æÔâ¦Ô#£ö µèù´¹žWþ°·úÊð\y© ºx•G-ïQèqÖð:×5þµ'œ‡$¼ y"N2ä³ÿ\—=WІzÞ¹á ”œ!G¦îâÁºËChâ= .PÀ¿¿óE>Ýü}KwFà“Ï9‹ƒb€æ_ZîN›†‚M^…2!)|¬Â¶XÚj,T¢€åœÄ.F29‡gtIÐV!ÅÅ¡k¨ƒc¯rTËcáâ¹”è‰!`³B”pQ&…g(|-*QÎT.W¬E´ô‚€”‚§k°ûf¬dÜüD—¦$a+øm}?ठöýXÉÀçÀßZš¥%PÈßHºê  }8â4D)!Ã2©–ÉTKа|ª%`xJÕ8p/”2.îâKÈ{"õ °qú¸0ðe3GÁ÷ûúóû?cwñy-ÒºÝGÕ þ#lÀ—ÎÆÈñÙí}ƒ6„>«ÇÆC¿#^zT½¬,ûz±4œ$vwŒòžÙu%,7ñÉÑ & äŠR6ðmPÇ0ÇW¾Þƒ_¬±1¨üš`¤á¯„`ÅGW0üÛ 8êú¹©HAñqòM«ÈàÑyšAžUÜ–-SÂÞú¬Ix糊mT¥3t*Õ×W“Ýb„ßGäT½9ÑÁ»X5 :¸1/—ĸ)ËšàóåSüͬOˆè8‡Þ¨ã0y×À“åð¥"ýї[3³4éäw†\¯Tš ê”ÿ‘¸Õ”€òD½ÙòhÌ?_Á]!û´ß5OaOXGë¹]Ρk'Ĉ#ªìü©Ÿ¾s£žj¥6s¼²™87%èº]â– 4Þ\Ãf}TpªFD@·„YKA}ÌÁgÓƒôŠ©R¿‹"¢ôLÀW@XUÊSÇoø˜pUV tL Ü hìÝb膬ãïjéƒtð~Cm$¼~Gè¢]x­“‰™,ˆç»<1þAâåædô¶`aäWwò|˜+pfé` ××9,C&±ÿRIC`oúb`° ÷Ðüî5Ë(ÇAŸ°Î,Ð7É?ê:ü»ûv=“š1,§Ñi‘06Ú·¡, º–4 Ì3!pkäö@¨YpM߱Ĝ噥>À7Ï¿»©N’€.x"ýC¸üºöÃiCM ¼˜8)œÁ¾*Õ9­,=2rŠër 9í36RŃFH«ÏaqÓê¹ø´z‹›V_’€¶Q=úLZª+ƒ¿ùŠ6r^ÊFOQâ‚÷3øïTżacD¶ \Œtƒ 1r€{î*Ö„àe ¯Ñ[üdBRÖ•¨ªÎAÎýyóŽ¡ü¢ÀÅZ.whÚ„:'h›2S®›ž+Ì™Ïú`0gu3tN:ÌÀòù,¿g­O7@í÷oÞw2ÿÔ`¥S8설Õûw`R·ØÛHüñ!ÊàÜ0lQáP2òËrÆE"?/i‰¡‘““ :‚ Z“Rg „Í1I’ïf×o¼Û7¾œ.Ÿ ;åM[¿’ÜwÌÐWªh§f}‰5úàÎþ?p§5µ“á¿em3³wü-°¨˜kâ¦ËcëæÈ(^…ϘbPZŸ±v(àÕ ¼Ç RÉh^©ˆÒ"± ’Aû,aÌ?¢IÝY²äëBóÖ6u>]¨Acm–͹¦Î:µ\¨¦B;Šj„A8"Pæ†z§CFltƒ±ÑËFu%…þ§‡ô´LPÓg3[güî& g%ĵ"EÆÙŸ ö‰·±OãwÜÀÇÀf Ö(¸(-bÖÈ,y:ÊÅÐ1º•0ܬðeíeÐ(+o³\ ù `Ÿ•  ¡ø ß 2‡ÅH¾»Ipæsޝ¢ùƒ"0Œ” ±ÆþÕŸÁ“áä°XcfW™!Âõåkäð×€sJ¢Yì.žà{UÀ±æäISŒwùÝõÃì|FÀößÈ©úÿ&/ü)Ž\A;©ûÐü2­¾Œ€Z}̨ÿúýþû7hØ[BüK¨®Pà\RñÛt¼Ú£­—õH$öñ»úåüºYHo`SÒ+ðÃg–$„PçÄ.ð?/ôTÂ@æÝaP€n®8.ÊÍCþJ‚„ IÃ`Qººr`œµvGð‡%¾ „ÖÈ ù;‰g(Kb-¾¸¸_–C£Í4#øF÷’Ýï" <»û )³ç5ÀxðìÆA!1|н=¡G |è½$àŸn€²"ñŽqÇq#=ˆ2Ñ;ýŒÞdØøÐàqF†=zc¹æ¸Öj&¦” Žñ ¬%àd¹ 1Ú‹ðž¿ù± áñ-á-V1›ß$žñï.+cj^+>Z˘|ªÑ¥¢0 û[TƒÂLÈê/ðW?Y.øY#×Í[þúˆ‚cäùmVm¡nÙyrÀw y£Î ÷)zÅ€mï½.¥ dœMýGBÀýè삃3CÆérÿ=š.˜® ˜á3èM>B(äznòä}þàØŒ™FàïÿЫöLKéþ¼LŸ~Gá€*$ héÿ+ðŒ·ò gi½K­t»ÔBHS«1€´þš 1àX ˜W_ô)BÙ¸kô;2õÑVþwNîßÐí  x,E_`£Î –Nΰkœô;’.ãð !_H˜¸/xØhÇyÅ"mfÖK’ú‚F à8WM ŸÁ-—‚@É‘¨|n4ÇÈ¥È Ü*êqÙ½3×±;Ã{ŒËÉ5òÈMQc\Àø¦6áò¡‡ ô$C¾s_ñæû¾ù‚ÅBÁá¹ë)*.u=°‘FpºÂE$g§2²"=xÎp }ówèý:Žæ¬>ÚèQh¬).’FÁUß(ë‡kŒ7cpJlŠV ÍÀq&‡ë7µ¤ÂκQá*¤ÃÁbù xVû}œ2!ΆGcد`×|*€ø¦ù~”¢ ¬a“z®î7RV ð±šüàj¾TŒáæÆùÄj‘s€êÅÑãP_3ëèótŠåbTÐ1”(ðeù˜]Uo†.@ð1ÒÖ Ü-´@’è¬O„‹p-•A#®—¼å-ô„g:Å„ªI„7cJPLœ¼¯Ë—psC Qž€ Þ²œ .Ë5:’›à­{ âðeÐÈ[j!Ï9ãÒw7„õ+üúá4zMPd$YEvqbÈâe(Y#!”ô…Š^ü¾ÙÄ®ÿ«.m(mʹ÷d Ä횥`ømí’ø,ú¿jÒÌîí7*Wâd*$6åÝüÄœÄë€ú^˜š-®¡¼}[R/ð–À]HÌyâF‰çÖ3^4x186÷à?§[JhÀ³ÞÙ¸è7‰Î\P•RÏm“ðÅ ÜÐ#Ó«§eøŒÃOÚ&çŽxÑ ¼§ÏÅ]} dÿgÐY ÆÑ˜á?¹1SÑ ¼) TBŠL޽„çÊÌqrNrl_-ÃNßR\ª,Æè 73ÃÐÔ'BŽRË2渗h뉱ŒÍo¨bæKmžªy#Øb°ñ9i%ú³„Fˆ¤Àæ âà§÷.ι…¨=3hÄIaðXgn†Žg¥Bªébê¹NÑLÜB„…x2Þ2&{ÆqŽ%û”/DÀ“ WàqZ¢rh6ùMÈbÀ Ô©Ç-Ýc”KøîÆÏËš’@ôì¾ûðý–3¬sjÅ€ƒ>O£gø«“ {Õ¤iÐåx„–Ù•áƒgæå°÷nÝG5_:TÒT¥˜lYùî]s%äðY6qçõª@½¥ŠyVÐMnä~Øá,sølæÝ‡ nÍ@ß‹æ ¿Ž.?÷dêR/Ð+¼B”ÞdBp>Œ£?ÊÀ!ǽrƒàÁÝd°—“?Z&¨%büÈEQÓ eÚïÐHžïYž™™¶Q ‚Zõw¡@7Ô lÕÛE©‰ÍKž£Í¢a8h”7—!ã¼>Žò92â‹ÜdÔ‚„Fz‘ ëErz,dÜÉÚqdèXÐ(͉r\„ö,u<ôüÀwSÏL“'¦#dæÈÙ'ÑãŽÌFoÄ£~=ŠÑ#GgdÜÀ®Û©P˜Å—]‚ëe E¯,H/€ñë3!A9<ýyç ¨Œ* oètÌW›Ž&8:òMò•P?yî‡ø™î>!@Ó“ø´«…¨Üowh„eµpèÒ]ð8Jðgò8çÇfPÆ‚0T6$lDd 1r†K&ýýîÛßrÖ~–r—TŸD:µ4—PgvE®S%Y¿Jóõçèõ¾apãfÈÍ|{°2ZŸ DüFÒRÚJmõH·è\ á)ƒ57ØØM6süœ(¸åØ…jc¯«VªHPÈ+—?ôdÛ¦Bíý¥—.cÒ°?ú¿êPªp²e>—±ã‘¤oŸrq\uà¿Ö{ C=O!àz Upû¾4ŽÇ‘CýÌ«z8ŽÄçÉ÷I¯·Ö‘GšþŽÌ£_É”ábéfÈe|wd¸JSó;’t#ë$"™0–°|òù/}E¬QO‡Âon£N½n×£þI‚¾I…„ÜRF …N›ÊæáÐ4!8øŒ7Ú\ ÞZÕ $€SBË9«‰x¿úÈ%lVÕÂaóC‚9vzŒºsEÄ|ˆñò!ð½èkÄ=+”BAÿÝMЗ(•q"˸™…QÌ2µþùä§›Õ«PR¨žÖè?"ºr"ïáX²~OçÁqda/ƒd’ÒÑ»Ab¼ÿ¶úb xj7{$Ixó…„;™µt[ 9=`ØI¼4ð…áS¨°c¾Ež›¢˜¿¼ìÑ\âøxSÅdú#\lh¦Sq±™tƒÅܵ‚†O( qHN tŒì‹2ö?ýô ƒÀ¯“âQEG|†?XQ â{Xá£ÍÒ–u_ÈEu_¾7ÃÝH-AEy9î(„×.9ô=xG®s#CM2c]OѦz…Ž5á+8Óþ#Íéû½;ƒg`øÔc±B®å\ø}„ÃFŸa׳ŠAÖ;…mlS^Ï)†ÝhûGìƒoÏ 1xµ&Þ™»WOÄ{¾v=R»/’Ÿ ¾5QJ@î"i <‡`(dÌ©oA6]Ÿ¢$áŸOi²¨= ˜œÅ&1$üfÒðfV 0Þêß–²(¢Îü ŽÕÿ®"¡žˆþO?˜zn<ÅQ ¬•ÙÒg9®¬©ÀÄŸ/þ:nR2¯¿ ©¨2®Ü0 ÕEEDƒÖÓÎ8*‡ïq.çsòÇ·hã¤Î_YIjËc‚“)yôÃM ^°½“¥6¬/éüÁ2~SvÜL5¦(‚ÍÐMRÚ„‡ÜN¼IøDáìmY–}ù´®•¼Cv{'œ?ï?ßßüü¨·¤‰ÂIøÇf>,À•㸅k—4äº!³ m°œáÌ=‹¥† <ømiºPó³g–®|@¤ך¤ ÷D\ÄÏ»;­uÒÙÆU!؉À™4**3AØÑWOS›¸ )?"ÖÐÇVXéj˜ ¾©² fmoÜL¬E5¥ký ,[íp¯Hh ŒY£+9ÜPº³ð„³ô©É\„\ÈUAG˜¸ªû‹h †Mm‘€·)˨Çwµ Q,¯¾!ÐérCNCž ¼NU†5cÔ“_,HˆäqTAN¾D‹ac‹iŠ_CKù±Ñ JÏpäͶóÒ…Úž”®>ÉĤqÖCÁpFMÞê Ëiô``Åìðîa%µzáà’Ž$æ/hÃÏ„…ßÏ+0€,&±Åäy,âÆÞ\“W?õž >sð‡á蜂»IĹÁ%ÜGXOÀT:]RšŒ!'ñ ÜcfÀYç”ãßU´„wš×rXH¡p³$à=C˜,ç¤^‡$m#¯¥l0з—ÐéøÓ†™Ø5!Í[M“>"kbX TPùÀ?Íq$pv1ô73ŽÉ£ÿ†+£) ZFCe´ˆ¿æÁ7û9¨Fbн’ù—)ÄÏ’‰ØÌ#”±Ñ“VÃÞn5€ry ÿ[FiÁC´)* ùGL‚)†Ô Ìtå9y:Z+å©|úcƒ¸6ŽRaõ,è7uGæ®Në¯ PÈïn²ZuàA¬Š˜vGD –çVÁ zÒë¡å¬L—M¾>È3¬¡‚T=7š’°s•'ìs¼ÚXT›åbš• °¤èy¹X-´ÿ=bBø§gMâZ—„w†f’ûI€K¹öãäFN&ŒUBàËÂÕmn°Þy© ÞÐÔQb^E½r xŠ_^àÿÇ­S#ƒ.¦Mßö)(>5ô^ðÜâBÀØMYúuUŽôUëZÎ?–QJ0®C×"Øß¸è+åÔÚ,LÔM’ø¯y€*ä'}t!“ÔEÔæ™„zp XDÑÔ++¨AS¼µ®QÇ’S¯¥@N^µø´–Ê&§¡< P—MŽĘÅÑo\×À/g£´¢±s„tÊŠÄe· ðR§­w¤{Œ±h…C àYØñ(œ6ó@æËJÈÕ×Ï÷ŸQ45òQÇ+µîÐO@áé«jÙOäºu)ÜðRZ† ÁéèQ‘ÓÕ£"b|ƒ†ÞÀÒ‰ÎâO=%nÂé†%^“Ðt +§Ñà) aÝbðuzUÌ ® Üã#|€dMˆB@ã!‚ }ßr0zOÕÅ`%ˆ-¢š…`ïHÄS‹ÿ¯Áªbç‹ÿÍnŸú&² ?ü`ä•dàjâLJOÞšLM\ÀÖÄ…l½²’ƒ«‰Wb*#G——™&hŽK!¶hžy¤§,z]â :ÊJÄ?áøßY/§#C5aÇy¶#èò\Ð14z& ]¯¯ÄE»¯¤eg­¤S9eBø|GÕØvr&åÎ}=†´ó’$ì CŸ**àA>gñ"þ<êX—†½;ÿ<ÚøçÏÀ?tþyÜSðÏマäüóˆáŸG= ÿ<ÎQøç‘ÎÂ?1çø+y,±žnž0gRòdøLØÄÿ–”˜Ì¨†ÈÒ ðá$E<³„9ñ¬3'çßh®ŸùIÿéÆ!ÕZ« &+»¢bÄ”?—éb‰3‡·„d4jøÏ³N”?‚¬ÈŽÞÒ¯é]Tör²Mu“¼1kLаö!z;db³¤¯äa9kâi{¼L¯ë?þ3’©KŸÍ+žùMÞIomiì 'c;ó1¤|~Þ\ÔÞt`OÇ”o[¦„-ð ´W\Mn’ÏdFܼزÎf/û™€`ñä>¶QYÞz˜ž™Ñ^=˜É‹Ýœª¹½ñŸ)ì ’0jùû.8¯TG¯8/û‹›øÞ7:;8#ÿBÂ5"q°©9ÿŒ‡œ;sHÓ-¢yô¡‚³›8ªþÀëCr!o_c÷((ƒ]?Š ¤—°|ª÷²…ÑØ_Þÿà «|_ÒÝå“÷ùCà<ÄÕßoY' ºƒü TA‚wøÔ%ÝLI4‹ÝÅÓ±ÅM–‹NÕy!øÎ²ÅqIùúsÃé˜ZérãæRØ¡ÿè“)þ‹ÛÄõ£ Á±'¶ŠÄ±*9¸WhÀ8¦#CBÆ9ˆ2ÒòwÓohÀàë+ä92Ú ü†¶¿w=)¿££ííïàU_+d¤“ÎM ã˜ì moÿ@Ûc4`´Õ»dþê»^ì§Ì ÿîÆÏHÒ&í1ŠCP1¨•ØßÝàñO·å‘……icŸß‡!Éà °Þ;ês¼/b?J'ïAà>¸ñ;Êûý @ºÇ)À›CWPð•±4ÿë+yqCwæÂ–eðtG<¸H—£ÐcüêS~1.çìWÒÕßo¿‰g1Äït"EõFé“--¿°wìèo$š“”¾’É“»@RRTF<úmü-¢oéÄ„àØ’õ‹Kp3Ê"õ= }÷Ûò_nL&Îð—ñ|ùü„ÎlŒWšRu4e4ük¼K¢ßÝp¶ *7wç8& >³$mAe,Ã(ÂX²¿“‡¸Ú@ nÔþìiû/nJþHÈ„šeÑÌE`Ì^ CS{#tQÀoÆŸWWQ8Ã_ÝyùµË¨#³`'(£^q½”À·æBoÝða‰sÊQèÙ›_ÜÁb‰Ý)Î ¿uS÷k5àã§(dygÍK J‡Ü>Íữ‘}ìo.ΡÀó±4ä¼.¤°˜pnÌ«"¦SŸ© øΛ²pnã3(ðŸ fpà›?X¢¬V?$nü%Wäsœ‘É@l|‹^‘êïnà¾Óÿã§¿»)cåÀ² ¹¨Ê2.¨œFHGöw?ñ}û!‰–±ùã}ÆX»„~AŠúòQGk3+åÉî‰÷²¹Äy¶(œEV(ãù—ßßÝpÏðα³¢ZHïgì¿ãXÚ?“¹¾»›ø8ÆûÚCG™Ÿ5ü瘠LÓÝ2DZ¥“'÷¥¦Ø =ñÃ'jŸà {îÓ9º1>ÒÆdázìÖ0š²ŒÚ8¿]@E<ËǧN7‡°3™ÑeÿÀ’–»„ÔtäÇ?Š9µ)Å€*‹Ùi "ß«ê{.ëòp&õîZ…vïÎÜ šaŒšB?¸á+І¯·ÿàŒØÿk醧 1zuïÎ}£þžËNvóý“‹õ¤Ð8·c÷þI‘<œ?X Ò}d^írE'|J-ÏQìÏüÐͯ«°’¸ÝÁlù ˆ‡ulJÁMfù?¸w ÿÇǽCü?þ¿X.ysYìI+Ý݌υo·ž¤ðŽúÝÍ!)Ð1Êaï¯ÌÓõæµvHCäMž"Ø4¼ÆË‘#xû&C§KøLÙ zÁoÌ 9©½BHèå8røá3ã€A@޼çoþC\»x€OHú#©7%ƒF^P]=%?ƒéD‹S}YúÁ4gô¦ž;·¹ÖÇ®hdJÚ»O‚Éc­å#öH> )Ò'Œá5W!ˆÿ‹Y‚ƒsæÜRÇzÛt!¨ÒÔ´ÿÚG¸_ IÁ³KШCo`êD€Ç\§?®ê}¶­_M0ðï÷Ñ3 ±ÐN¡Q7.o?Ž+až²¹?† äÉÛV î‚\ÂP!âgØÜÐX²F¢øÒ]¸ÚSŒ£EÃSôÒ] X&OW_ÝÔEÄÇ}‚ ê¾»(_>Ý„^°œ’ë˜nŒo´}†’ðƒ¼â  ^GpC¸ÔnbUM"껀N”tÃÚœºß ÿ.i&p@¨AÂ^ÉJLýµØòÛ»5!)Ê“ŒÝôéótÊMøÝÁпDQ@ܱÉb¤ÍpWn’ærî£,— _Nv%‡m@úÖï£\ ¾ ä‰[É9ÂÄåaðŸ„?ÃV@.ùq2xüÇ)ä /ü9Â#`¾râWñÏl'âœ\¼ì3&ˆg#“àà.Y{:z¤mhÜ Vi&)ôÜw!QïÃõÃ]uqè!xåzOuóZº_}!ã…Ä)ªjÊD`ê¦L¦rŠ–!òŠJßÒ†ýÝÿæ=ó†!_—ó“1z[༈•”Ÿÿ"|€ËðY7‡¦rø$õC´±gà“(NáÙ r/ˆ'ÐèßK7ÀÄãêê‚Å:Ô0Ún*ÀI’`i&b–ÿ°^IX²pi!åŽ$µ;`²®Ý !¨Zú:ˆ²N7xxðQG·DgAñsßÿ[­!%¨ Ä#ŒÁg½­P_D¾L¿EÑ3|öXƒˆj{I0!¿»ÉÄ<ÇífŠº£oBçó¦¥ Ayr‚“ïæÈ?\p–ê™ÅÚÞá“u9ü79DñÍMpoÄb¹I96¢yû-ò܀݋¢ÎÑ÷óŠã{Ñ»þÇçæ%ÓP.¾ùq„\düqwƒúbWÌP»—FŒB4_{CÂSû¾³KŽi®áÑŒB*ßh£BpW<õ»t@oéçÐ#Iáx/e?ã pì.+‘k%'u£¡36<²NºGü.®£ ˆ0zúmJ˜ø¦ ´Ìº•ª¥’×ð1ñš Y‘€ý.ðÖ,=‹êAÇá¯Òí±WؘF| ÑÏOëÏSløHVöJÀ¡ÿoøÄè²â¶UoïŽ)á+|YVžÇQ§è;‰g¨3tGæÑ ª¶¡ÑðïYk\L­T@UKy•®¥Ø7iTî#$ˆqåœ_süYxÿ*Z€Wäfðñ”Ä_#UT^°õkDÀ-ÃÜÍŠ1°©ÉðÑУf„‡•­¼±ÎßHÊ3LÂàñòp(:bðb%œIU-Ü‘™ŸÐ÷û9 98ú¹Ĥ  @TÕe1H€…$뮀çÄ;Hé•u!Gx#…(ä·BøíirÅT.òêÌGN1w¸â0jð2àeˆ{§;¥,œU+ü‚ŠrLR7N“úë$œáç Õ ž‹™#<Ç7ΰ'lù€èµ0šRþ$ŸSd`%ê yŒb\o% YÊÕ¿?‚oOE„Iসïú>^â àÛï:ð†%ÝH©Š@2Qþ» Ìûx†ê 2˜î ÃGœÇ×Àiüyúâ†O „€ãôaüÚ%w qòÏ3Ü;7œÄî4f‘u–w•‘’¢LP åF¨"몣"å¶£"é:¢"ëF"y.S¸‹„LùF‚”¬ÃÑKS…¦§›!Xß\ æ›àØlðX™õU)ãÈÇH‚¨ A}ü 0I7„ <‡¿ðlá4föËΓé ÿ»å3ÿ[ò/¿yÕ0IÊú‘pqÿw‡¸_œß~üáL~þqw5âøEûeëG6äýIbV–}ØüuðKå~'î”þ®±ü2u_ü·_Ÿ þ›½-ï!ûUçшã‡ÑêCúžJß$Y}jÛ+Ï?õD‚õŒÝ¢ÙŒÄ¿>ñß7Û~½:“,“éÎ2ò—«ÿ÷ÿ­ÎcN×Ëßà’§òB’tú’ÿ»ò» ˆõ–!û,“_¾ra{ìì7ÿë¿îÈ¿—$á¤?|lGiäEÈG'©›.“«=Mð_Ç{{sü—½Âƒô×gá’}d¯ß¦“¾s¯WßþäÙ_T¶Êæëoló7r¶ù}öý/Îÿü°øÌiÖSš.<:oŒëŸ±îú{©Â°@¸ø7ØKùw·“d¢9ãñ‰£õøFÌ ›¿ÓíwÃ@øWN³™ìIYiÍh<уamöÕñˆÿB`‘r¾¦ÉèxPÐÃ2t”¤­ØÛ 7—ûpóúâkë†êÛ}ô…ÖÓúÖ^çOùSÙägz‹-©8{<®yæ_XsÕ Å0m¡O~gÁZÅnÝ#"°«­›á~ÝPÝ»ÆnìÎEç³ Ñ“úøÇ fÅY/ò-háj²Ùì²Ã=·côÁvKfçŸmf×–O‰¼Ø;’.ã°0Ý3"žk('lYÿr¸I¦…~±5Á-ÌÍßxÉ:Õˆ .k &3ó0-¤ í”V%d_Ó±0 Ì m©:¹ÒFô”í9ç¯K º$}òP]2Ô5CV™:ž_´ŽÏöBƒÕÛšÞ³»¯¹kÊwco íÉû§8z ìÖÚº1ÖÚ%Í«k=Cè!6”§-Þ%Ô¦àiØ¢6‡¹K²xw'J[®Ñµ¥A­¥-+hxÚ²§›z÷µeÞÐUÜ"«ÈF¯/c!GyÃÜÿ´õ!£e ³'´¾êZ–Ù§:ÖÖ!t¬Mÿf Þ‹éè¨Êd-¢¾,1ÞŸÄoYÄÂ(¢L£&Å7é'o~Ò_º Ët4®|ïç’}oÞARWƒ›ƒáPið ZIƒó {bz§;1õŽÏ·ÏTƒóB<؃Ӵ4óds.|f´à Íy´LQfÝê[Òa¹ƒgÝìø¬{ŒÖ~ÎûƒþŽKÝŸsák€¬9'q ¬ÊMé£ó¸qgSÊÕM&¨}mËØ×æP0ŠÑ™øñM¸2Ӆư6î5]È×lµîïÈ"ð=WE›ËhˆÖ·môN§¯»n}G±?Ž7ò᪣Ǜó= ¨h ]<uÉghbWdQÒ¥Thõ`uðcâè½â_EBÏíeŠXWŠ˜£!*b¶),¥‰+hˆ÷~†%íŸìÞïô×}†Ñ?•þÚ™Ù¨ú[Ó‹±ß¤z[Wz{†©·5£/B ôö6¸rž©Á dwõ¶)€¯ÙÎbá›Îè^ùÇ@ìÔiK¬«¨iå(£áצ2®«h¸aû ¢[Ô4ÿ ÎµÄ«ªö®XÒÆé\»«sw“§Ì0V:7CÃ5Œ‡*´\EÃÔ¹ºiœÁe`‹Îe;Rçö¥Ò‘­¾&–û¦sy] ëxœFÏ$”1˜ ×qšù;oÁ|Ϥ”g Qy CéÎ*®î쟟½ZÝšÚÓ–Šhƒ¡Ø |-®àÚ´ŸÆ¦8O%ÖLwšƒ_û$˜Žx͹ °fhˆªPïT|µŠ¶žíG¶a§ÛîIGX/6=˜5ô†­‡˜nü“§œÂg‹éÖÚ¡UU¢ ‡–Tîžaêb—r_ `”Å˘Ú$N< $o’˜jñÜ$ýÚ“?Ÿι.!áðY…§O±rdœÃ†LÄ5—¾Lù„ùÜÆÒ´QÈ©ý‚ðNeªi¢NcY™û"áü…¸îr˜Bñ1ÚBd{w 9t•²Ü ¯L0Ö—,oA߯ Þì‹„ê[9_R"–Ô{_4ß@¢ºZ"£)aÂÃkœ¾ˆãÖ”oR4‚ ©”›ˆp‡„>ïhPvÚ‚Ä©°W2ùeLFD)Ãþ Ó¥Êìz¥ÆêR¦@C õ¾ºÆ®¢už¤õè3•­ w7£=©¨×‰i¯‡ ´×šVâ@la»~™ŠÇºMñXoÇù`*òbÕ–À«[ñWWÐjLʰIƒ½Ói’®óVG îþ )PeµðŸ³¥¬†4‰M)“X¸Ó!hµËI9Etú†‰²53r]ÝþIÜgà«bͰ¤Jªú¦&FBpAÌ5ChW3)¯ªÝ(£avâT$ u4Lô¥Ÿ=æÕ´A!ÏùZ›+¢Ý£í*‚ôš"ÚÝ£ˆvw} @š› ¨·â@z{h˜JooÓÛŒkN¤WÑP+ ªr•ÞÞW1¢åo¡>´ÞÈ„<YïÞܬW]—ÐYïœó‰u(²ÞB†¦™=©bYjï~XkÁ\f¬tîÄÿ /«²[ކk[çë_³e©4)ÎÅÖÝÆÖ­¬§šbëÞŽsNÆ“bë.¤0í)å²v€­[ëÁ¸Žºî~BÒüëï$}Š2Ân¥ ?áªBÅÖ½¶ží9_ˆ°óýÁø£ë»R‘Д\1H×”ðŠAZ’¬`@ KÑ …è¢@ä‹t´¥•™e–fv†;ùØ.…yºüLÂ#WUÜÓœ{Z¹¥%4Å=½GqOïú”„Î垦êQ*_\˜{>º’R®¿u'Jé­Ñ}ôvE½ãS‡™ša QmhLj]Æ.µÇþPoöåOÅ=½âžàöµUÈåŸ:¬ªë–øzª®}¿ |1¦/òfñ»J+Ð0ë‘uí| d£5ÀHò× MÎBV„œí„œš"ä\£)BÎí8Œmî躉S7L©¼'&äÔz š¯`ää ÷Ñõ´™ŒÓWLœÍhЉs;ÎÓÏ7<§Ô‚¶žïGØ|?M¶-Îq*®BI®Âü$ƒ´,ÉvÔ½Ó\m>T£ IñöY¾çʲæ0Bœ„º1PÄ—ÆþЈ/%S}å"DëèôÉ—æPªŽÙ6[èvei–¯IÀi{š)0G#(¶ÕÓ+´áénBDWÜÝ„ 0Lµ-Uu7R a¦ô ]²ÞG&>ÒÍžT“2Åõ¼÷ŸžU­D Mq=oÇ9Ÿ~Åõ\—ÅWå\[C0øÓÿA^`ÒZ*ÌÎPÿà"ÑOF®ˆe÷#–U„à%4E,»GËîúÔeøW¢Qž²æÕuÅÛ :Ù{”èÛ­ ußPššö# ¯¢Å»û¬RD;Ê+G ݺW¡5c9ÿAöŽøP­¤±æ@%VÉÓç }(ðn~Çþ‹› ›ÖÕ¢]èÆLº^rU*~§ dk=C‚å£ÙÀŒT5W¨¢¡VÑYštØ[ÙÀÛàJ“möµó#žì’ ,Uw¡ˆ¾÷þà~DßÂEˆJAï ¨ˆ¾d0KRŠè¢Tµb1ö½¨j„då$%qB-§†:µQ?ánTE\»V+à«8iC·ÎŒBš½v½ÑA«󚢮­P×J²u„ºV7â)=ˆÔµ Y2†Q¦yú1a‹ðÝ ü$õÙC—å¥pØ6>¤ÎHcÂd¶À|´¦X þ>ZEÍXFS|´ÛqÎ&Çê<i+W fß³CðÉõþP*+K˜œ€NOš—QÒœºÝ fT¤z%4Ìh“9ì™g¶é?,©ž> ‡K\cV» åsîì5ÑŸ¢èY"¥/tÝ}þNGQÄ×¢$½O°Šq£½×&¢šðòÚ½º†¢-•P«¦‹”ÿh]$ÎÚö¢MöVøýô ü~bÂ^ÏhÄ™[X‰–ЋWÙHûà•Τ¾-YYž'S3B…V~…{ôïýŠJ]k;]«hDðÂèZ áâ@ Keh‹dptÊR± °¦sK°0e›¡’‚eæ=É0}C¬ˆXíð½v¸ÖÑt]2Æ=I-œ7¯£2Dó!œ^åp{Q6`YªÖ)ÖÒƒ›øžãG‡¯#Ý–Lö™¤ÃÕ(n^'©¦yOn줱ë§ô#ñŵÑ'#G?ù*1tq&JÅ#Þaq•“–£)ñ®óˆ†}\q<*p˜¤¶jÊšºV-£)*ðí8X³í퉸³ÎXÓ¬¾&•”‚p«j˜š”ujq¡à¸,ƒø\Qˆ7£) ñí8ŠB|¿a( qÁ?—K!žøÿ!NL ØÄ·Þ锉ðEP Ž"mßõ©C ´®‘¶¦d,EÚ¾ï'w‘¶KÆi!mï Ÿ¶!Y.¬¨Þ÷ý Õ»diÌ…P½¦5ZšŠê]„꨿À¹®µ¾xŽ"ˆ?+‚xué•£)‚ø®’·’%ÆC;O§õÈ«Rv5|ïäá?ÂkF?"‹Mõ%)Ð0ÍèŸÁ…awÔ±£Hñ÷ýà~¤ø@®ÿΩs­ž=N“azú¥%”•¿ÇÒbÄùP¦Ã4,ídÞ·"›Ý“lV5\(¡)²Ù8Šlv×§.Âp´ ñÊ€r ¤hÒÔéÎx*=×{"iôLB‚$Í«™Œ©òŠ èž Hö˜®¢AÔ¦OK¸E5S•[Ô$oÄ[¦$ÿ÷Hå6£)fÑí8*ýg×§ÎÏÖÅŒüšB­îoH…jIµ3æÅàɃ(xA-/ˆB1²¥0÷,%_õ3ÛÃV_°ô»^rÍVèÞçÿ@¤~Ù†ºVfG?Oýø’è^W¹ úR40æÐ8a„jùi}˜êÆ’Í,ë­‘à^¶ÙÓ¥rÒöP,wêeû†Ð3òÀ[iÎ)‚øs \k˜šdö¶"aY“°œŽ÷©$,¦fIÑ Ë6É\êΰ˜’żtËZbGØ=Là΀á¢×,ª>~8ÍyÖEñÇÄ)üϬ1c¬WQ¼4ÌË/‹E˜U¯Œ¶žnO¼çI f)”×;á„Ã×ÃNø2öa' [ÀÁ“Ýõªà¤®ÙµÃ ÐseåÑR‘æÓ’0ݧJd ×Ë h&¹›¤ýÞèÆ›¸7ÞH™-hŠd;Ž"Ùo]7–öxÒ†zÿt®Œá?gGXÁ8HB“ãV„û~ra…dLë¬ +LëÈ„8Û‚é(û“GÔnEY¨ûžÃïx“Ãvoå¾'ªo騍D3Q«—„ZÌËÄÂá›^e°¶ß´³÷ü¢D°FU5gÚ ¯ÜœÉ’Œ±¢7gjè_’­ °¾%tÃ*:ŸãÑùqH«‘Ø—ºRXzFgjå•!ˆeÚ¼.Ù]ëíDì.]Y¦û–,SÃìxÁ±Sົ§wß hÑîå½ iš+£#°–°pµ „£ÿŠûè<¸å^ަ¸ºZÂNÕâ>:°*ƒûÈoí÷‘i w‡¯öå5Lem9d QÙé{¿¢²h„׌²hD›bs,Ð0- Mö[4ýžÔ±£(÷öýà~”{@~:§Ü;µEÓ×¥è*èét¦\{òkË‚áªÐòÑãH¬VGûVŽ#K:Ä«¢é[Ð@{¸ìàgЉnH"áBTtt_$ÑGâð‡OŒJªkÓ°&Ë}à¶ÿ}UT†DI:z#ž°¿Ù”Y—SÑWü‹ §jQÒf«ñ/žÜj3¥jºÀÚ¨ÃÄ«¬ Ió¯¿DÓw•š°BS<ÛqÐÊŒè2ü€Ù åDc[l£×ouGCZcçÏÓØ n<šMçzB’ÄBvÔùálô ´ç'\í AÚØ!í Aæ^¢ÇÈ–!°óß?ƒ~v  ´º©Auh§ø2A<]/ÓKÒ¯.’K"Ì\?èB#Ï3NÙszû2þ*£§’½÷¦¯T.á^‘ ¶‘ JF"J$¨§ŽBØ¢ÖP@s`ˆÇu* Ù©ôkŠc æY5E1kˆ"hÂËk÷êN"† — ÝwjuYB%°m«kP^ 1á‹KLim[\ài×–ÕÍ­– YcP+„¹0¾X:J¹LÄ8n¤eeòùU»äbXáœx hº\ËKü ÅÀÛ âoK—Ë€&þæ0rKŠó[Öw¹-‘~[ÓÈñ“QúªB†ŸÓW´a_ºÅa‡b†B,Ð-hëév!•Ò‚·žm{`õ.ˆEO(–Ø‚VžlK® ¯Ü½SÓ¤)ôð£³ý ª-Ìúb!ËzXiÜ“ŸŸ–)eG)û6{MÑØ‹¡)û8ŠÆ~Ïat½VÑØ7à(æÚ]Ÿ’°5Ðhì-Ɇ©šaèçm?1‡_I@VmUQ4Lë¡oË'(ëa'¦²¶ )ëa+޲v}J&i¡|4Ú}MÖv°Å"0°å«oVoèÅd*c=À8›Ñ¡\Ñ¡0õÝ@±"h¨VÁ@;?V„êBÝË¢üß(Iõ0Hö ‰YÎí)³Fy©ˆÄ›ÎòëROÍ-ö@ 9…¹§—5j’Y`0»ÚáL6w´ùÆ-©7~êu‚iÉ;zÔ Ëô:Žæ×Óæ.uþ\ùæÍhª+ÝvÕ•n¿atý>ýq \ëtº<‘®ûå‰ÿâ¼Æ~*Ä*Ù Êwrð” cµà¨PÈ®Ožñ!fÎÔ¬´•ýi¡ 嚸t£ûL?¾†îkƒI¯‚(Tí×r4Õ~ ¤ýZ_´\u³ý_–€šÀî·’&©ØÛ«%“êÌXEÃŒ•ö ýÌÊö¡,–ß)ò)„~]µ d”‰ê×µ÷ÅúuiŠk…¦úumÇ9†Ñó`Ä:j¿.ËÖÅ;0©~]¢ýºNÛ‘pµ˜²àjµìîjr!ÝÝèj'†Q½P΢Šêî–£©^(]í…bÙråªʾܯ Ô…^(–Ý—JVÑz†užkëH†ë§ØÞíä!.á†`†øRS–ÈUùϦ%dXÚÄô»k õ¥HWU뮽?¸_ë.MµîÊÐTë®8çXW­»rTÕÚR©ª+SKW&Iï±[]™,{ DŽԮL@yt[»2o_ÔAÉÑTW¦í8h]™–6y80/¨ªvº:lÊ?žuÒý>X–=7tOß¾Ntg,Ä…§Ìƽ/·‡ìt;N t¿ÙX¶ÒmKº´óbã#ŽóKÈxÚéî:óƒã¼5 kC,W'†gà„Bµ­à«KÆ}éBߊ¾%ºN«=àzB½ö$r'àÛj M({¬«ß}ìúi"˜8.o±, *Ú\©0EZ’êå í" \š:>fkcßqïÞ°ÂÙ¹P Aû§h÷²Ó…èfÚvºÉ^&Ï’lê;+\ÙÔ´TD>ß ²/œH´²4M¨uÁ%/­†¦³Â©â+ l‘Ø¢eoª1^?b¸f×]èGÜ?¤”@õ@ÙÙEuPDS=Pvà¨({£ë17Õ¥Gîú”Ì¥N”¾mËõ@1M¡xP÷lAÚÁöœe:4Õ=í@4LËÁÚ§K®U–ÃA”å°OY[ДåP W¬&@»a ªÙªVÃ@(þ~„-­ÃvòˆÿB²±Hï«î¶öÂ+*iºäáŽ~·U¹ü6ûB!{iR_Œpãà€VkªmâmZަÚ&©mb Km«žzí=õ$3ø«=õNî4UùPwÜFïlÓ'„rÚ›ÊlØ–÷Ú<¸KîpV\§ú5ʦäWû5¦,d˺¸6¶kT¡Àf4Õ¬q;ŽjÖ¸ß0ºü˜±)Àvv…z´†‡šTノô°‚©BÝ«‡•êoWCSM¬PÚÔæþˆ| â·?Ô¥eÂ}TΦ%^½Šj…WEC-]5úgÿêN+<@u`JÄ«F9{5ʹ¶Jý¡%ÅÏ¬Ú ì×Nà´}•Nn¡ôÅÃÿª Áy4!P·‰9šjBÐÕ&ý¡mËrÂÌØ8ìÖ0 O5vkwÂzíöµ‡?áîáj¶[G+Ý ]·ÀU0È'9J=4ä‚XÑ‚Ä.µYþ2P= Tw‚+^LsÄïŠ*ž£)ªøí8ëÙÚ-hëÙ~œ«ÏÓ±Îuý>5z|¤»tºû½Ó]/­Ä:¦´à)B~`B~jH… … ù1˜õAÂ~+b}ˉ»*UŘ;Ñ03°†ºÊÀª¢]hi`×Í•~eôùÕkGXE­Bž`4‘Pýêý$¯A;Ð?€.©à°pÿ¼‚ù {ô°<•u·FC´Xl£/Ý1ö¸zÝ4,±z¦º^çw`ÛØî 3V8.…â„Põ?ìýûb7d¥ý>q¡6wû$2ùünZ’ªp…sÚ’aÛ’c:ç>Éž¨å>Zo9‰ç†¬ÛGšµûP'À'ä;þ kö!TäÖ‚Vn‡ tÅÒ‚W:oVO9­´‹í¬Òõw7;«à[“êô‘v§öEmÛ–ºp×û‚•ÍPA‰7ñ=Ç·`tY畚³«QÜx“TÓ¼'7vRÞßáF¼ÀÆ2Y¡Ÿ|• -ñvvPé´ºn‰YšPK ˆ‡Ó€áá´¨òZ<úaAy&H–°±¸jpBPÛöPN)¾Ö&¾VÅô.ˆ¦øZwà(¾Ö=‡Ñu—ë¢.e»îp}ÌKÙcðµÚÃTñ©fY§ªÖ²z0$o½ñ2U4ï¢aš CmpIQZe6l†2„ÿ(³a;Þ™› ës Îjô4¹EÛJ+™ Õ)zØAÏ”Z'§&þ´Aòî âOÍœ»Ïä* â)þOQ4Åÿ¹Gñî7Œ®[ˆÓhäÿ¬*Y@£GëI±X÷MMÌ`è ñ’<­Í„ £™lTö"¯ óÔ·yM“ZjaˆD œ­3D*¢Ùš¢ˆìÑ, BÐE³åå8"Ï26ãyT”±U4L} «.„2v ™rÝ™ è^$ §åŒ=¹jJQFÐ3çÃòx î®¶Ðpe=²keEüW ážk–tmçÅÆ£ØŸN·Þ³LéÒž£_«•w&dŒIŽÝ[˜ø  Œ/UÐUÛ¬ˆl&LÕ jµåw~, G9 “úîè3cóäyrŽÁz‰AꃈØ;FèiÂ\“o%ô_ã—±7Í'š28š¢öÜŽƒv_G/>ÛC 7Ô†¡ªŸ«h¦œ¼Ø”ºåÔM]àä‹ó²ºÉï9`¹JR™Và÷¹hç÷œ$*·ªM1{nÇÁË` 3»wºÀU×Í•XÕQfOzv‰Ó#È0{½ H=%/°n׬žÃI'iì‡3ÝÊÐp£[öõ”7>?ä¢[Ùò‚Üôr­j„Y\¡6=ù«4à&ûk¦Øø”ÈÐpõÀà î­*ép‚ÈMj€­.@5`Šj*¹‘%¢× X`½·7÷Áw£Ø#S!­òm—ÈößÜýZÏq²q¼hšåäƒq–á«N™³~Çþ µì„'¥¶>j£A©‹¤À§àiöT]ÂH;”LZ©0ÒjI_¥Š’¶Œ¦(iwà(JÚ=†Ñõh‹¢¤mÄQ”´»?%tJtŒ’–žv'Oˆ.V ®ÑJÂoÿ-²dß§(zår(“ÙŠìÆ¶›'ów:žG>d_eýQ’ŽÞˆ'œN¾ÁÿE1E>Ž` ÷ZYš¦ yK¼´å¥“|e ú{Ý[YC[ІNñhoãÑ–,cé ö°gHÿ½³=Ú„ŠpZ³/íLíxÄ!ÙtNï´ h¨IÅ!û¡Y†?dDRgv2ü« §Ù@¬ª•áEp@½.èøMùFÁJ¦oäq 8\U§Éì YeÒµ´(û^¸ БbEÎn)rW«2Š’äqi:OÖ`ûî¢}Ö‡8ñ‚jÝ‘¥aµîì #Óº£3ÕÙC퀆P Ó0„üñÎ-LÁÑ·2w~%Y%ÄÉQUÀ„€P–×@ŠpFñÂ7ð«v2‚hŠ~Žâ…ßs]¿.U¼ð 8ª`×§d¬`^ø¡6”+WïÛöY[ ú¤†MëýFT7™CÑPs~ e5ÔДհGY { CY ÂŽo5¬Ï%@«A×Eïuëá([¬x–iðÍê ½˜Um¤¾*BêÑ¡\Ñ¡0õÝ@1–Ñ0ƒ ý¦qªh˜ŒZ_“®s?ºê¬îMHõiH‘ 7ãÂk¨£« •4#!édòíê³÷D¼çу҆Ÿpµaß蟮.^ Ý´ •|¤'‘TË6¼2Ym_Ú?ÂW… JëÍ ©DûRJôÔê WíE§:“¹·´§ã?S¡§f4Õ¤n;ŽjR·ß0ºxKPh+bö £ª*î$üç¼² ÐR0zR ª à¾k(™(ݰ;™†.Û·¥ ½ÂP›f½ÂTóÀšjv‰Í醖¢Zïv†Ý³Ž_ª{` S!–vf‘«Óv<¹YaJÙ½ªÜÞܯœ¦.w×hªÜœó¹ÜUíà Tç W§n*¾ šÍH,HS醳 ãê°QCˆ—óÒ ÅŸÜpô*ïS¶%СJ H'aMö2!1H—À&5G­Ëº`Ý 2ã:#!)ÓN±n÷„ÛG¡Iñüœu˾dEaKK½Ç ìŸÓ;2õcâ¥~*6CSm.Û\n¬4PsÇ– Tu Û¥ ä^Ý.õ2óâ‘•ʽhFS /·ã¨ûé]Ÿ:ÑýtywC*S[ªª¢ m†UG@3k`E¿9Žª<•‰ÄÑ:Þýï¸{Y×lÁhmc“´bAîç\šÿyvI³`œ&V0Í.÷Æô]©}Ÿ¡©i€‡x¾¶@÷»”3$Ü ±Ó \¹ÑY²jtÆ¡ìë«hJLö—òˆ8â·þ%݉ -дR6:DÉP©½~÷a°>À]憶\³IíTôò~”8nBf—åÓi`—ƒM±-pNžg¥d©¥ D÷Ý¡å Ë2_––ƒýèúÁ2–^9ŒÄAíqÓP—sËηa ¡IÖkWö¦‘“FËłģWe¿}BNjº°N°œãx°³mjšt1!¾ ÕL?­Ä‰°Ö'6ô^Ï’£A64íD¦…!®PÃË2‡à5qƒ ™«¾A|$7¯õÖD¯Â«Ú[‰?,Æj9$»E5 È®›°šH6¿º„flaž®‹…jÐÔ,@RñÞ, C‹ò„,LS;á:¶(…úÑmK3¢Cê_Q‚‚AYZ’Ý+õ&µê^!ˆ¦x¨wà(ê=‡Ñu: ÅCÝ€£ò-w}JÂØ@à¡Ö{Ì&” ö(êfjUª\BS<Ô;pΧTYñP¯¥Põ©Ë5ÿô/!Õç‚eëÊÐUIÌsrš"oøJËÞ–RŸ=*º—•GUE[OwV ›ÕÖ?>°zØ:­ŸjMCª"Z˜½*­Œô_2Aí¶…õ–…_qÖ•òÏÑ0¨nÎ,O•sçËåü¯—¤J+ƒ>5ýÄ*¸è5}“G’zOŒ_gÌ©Y4p§/~BeehŠv~;šGùø˜Ø8³>Ð¥ §.6Μøÿ!NLµ¬%Ú;Ý ‡6ÃfBRE Ù×Ìó2äŠYÊg¤… WÁ 8è÷ý ½d®ÙÅpÐë=KΫí å4* }F9­HèkhŠsºC$ô'×#–äÂéÁú0‰ÍeF°!³¿‘÷<{s•ÕŒ¦Á¶ã`ÍöÃòñ€ë¶…°Oç¢uÝ)ž»osŒ•O\ÃQ X»>u¨Qbjb^TÍ&Y^€±eHv,Ù ì5;–¦1 £ÜóT¾H†¦(²*ÜxvO쮹#+_` ;_ª/0OÔ·£×ºA/ókÑWE¿øžÌ”&ÈÐp5Á¹Ýœh‚lyê[táT˧-¡Ž%‡Ä+ŠÀ{{s|ç1Š=–·-2‚’ R º¹ýµžãdãxÑ4ËÉã,ÃW?œ †´Çþ‹› Gèëë£6 ‘D $ΰ{=2‚™Ð•âcœc’W*ᣫa ÈTœcÎ1ÉeqÖœcºÖÍ«,%­'â½CuÙ¥ÜS=‹f‹Vl]©£®0t§£¸ç$4‚Eï5ï+ ¨Iôå¥xûÏ™PN¨kœ¡Üøu|«Hå8š"•Ûƒ5ÝŽD°~£i Ow ÕõkÇy‚-J×¶u;(?þ´&VwHü4MôFI‚f¨ji ™¾²´„º!´YZ&³xÒÓ€}UTèÄdôF¼ÑH4¸Ð`|‰|ÞÇ×tQ-µ²L!oð’W–­,ø/$+]XòV=œ=¯’¬ŠBt+…¨d( [¢š.𨠥QÄ(å:¥QL¨À¦"8Ÿ*x'>¬LQ ì°ŠX’ÝZZrw+«ŽÍtNóu%FþÙ´®Ö`'^TÖ )³l³¬äyx̲tQžŽîX1Ën2ËJ’Ê,Û¡yBªcË,¥êÖ‚Ô+8Z/}ÆËˆéx$„‚±°ú=¹VV”…(¬ƒ0dÅ5ÖAw¢X×hŠupŽbÜý©ƒÓ¡`z}MãF »ô@úo¸|A:‹rñŠ®°DW¨)ºÂM4EW¸GÑîñ)_œ®PëË‘¼ Ó¢ñ%sšií„ÕÛûÔ½"qÊ Ò¬QFÝ8U’£!jÈ>kƦd­Ô!#ð.Ðn˜Jw*¯îuH=+|¸y÷D³‰ËJÜp–a\x½/t×#­Ù€(Zi£ÑWàÌÝD$O¥³äoë’–ß¡z H­jµ2B"ïh—§Ù–4øžf˜ÔÊÒ£üM“|’C>-ðø‡ëä¬Ã’âƒKá± ©”ü¡!”¡pIt{Lh·Â™&¾/c<€o[rDy ¸²¡n  ®î&iÿ…°½pãMÜo4R„W-hŠðj;Î^iC½ßWµ4EyµGQ^íúÔ¡‘‚îQ^ÑsW.{¦”W’e‰òÊž‘ô÷(IÇM†¦Ø®€9nØâ‚Üð’w¢LWx”U@—/eƪdÅXuw;Z¼jCï ¸ÞжїŽõ_¬C‰¬hO¦ŠÎJyJ_¬@Óƒ±¤p©@‹0€¹À½#ÙÀà¶|Ç|}r•Í”£aÚL¦9”Îñ9î¶gw&ûž-,¡Ïw‡“I×-©Lìs¦í¼Ý؇¶'ˆ^IùÚf1ª¶Øî‰\=uª·¤P[ßö /kyÏW@_É H¾§$kI%±"IJ|d’z„JKB¨Xa¯ì –Ù[îÌ»°Û½‘Tš ií…™!t¡¬Ý^¶0!çÚè™ÖySw#Íõ2@çÙ”í‰sð<ÃäaÍ3DFhBz8¼nJ¬ ¸ó@øn ª¹óS§lLÂÆäíËo˜µ`oô´vaš¬ÎÛ›CQSjaõÕÂÊ–YmjOW•X sãª\ â•0Šl!['d ’äçN¶`’è¦ÈrµO¶ Y˜u ÙB‡–£%EK,Þƒ´P ¹ ³¦j-"eI<ªh€9bCKêú]¼q2àû–î›,yQPë›,ûŽá¼C¹« 5xyU5â]_5}üÍüpLü5Ч<¥z¢+Ž¦ÚºnÇÁší€-ÉÎeU_lÅ"ßü›ñƒ>~ê&º} y ‰’… ‡Béè]Šî˜=ˆ{ÈZPGÐoo é¬ÁN24{rÅ¥ŠzjM=¥)ê©5š¢žÚŽ£¨§v|J,—¬£ÔSfÏ–R¯ŠzjßîG=%p?ê)z\KEEº@=TT^N.0æŽûèz:òéT3š"ÚŽƒÕºãÖ+×ôÓ•ít= ¢øø˜…4 †r­BÏ”üHlÐÛÈ4+'¨ùNÿ±$±XÅ¿:ÐöT,HëEª¤ú] ³!Ai(%½'ÃÜÒ9¡Â¢4+±()…ÀÑpÂÙ5LWð´>,O_ðd3ªD³‰©yÜp–a\˜f*k®–çŠe¨Öksù#Ó—ÁÛ È Ù;ƒf÷Û°„ŽWʾ\)¢¡ª çJ¡kMŠ3ýœ¹R€\)ƒiä¼úSŽ„:‚ªSoÀË%IÚ@-hx=iÍ30°:Ô–+“kõ~Oªó•¥Ÿ(‰ˆ¯Ã´$‹Jr¾ŽÅ2çëˆÎ„¯ƒøôkï€Î³Š+‚+æt¶mG¸b¬ž-î9©Ê§lá"T>Iæœ{å“¥õäR©Ê§æÊ'ÉŠ:¬Ê'KÓ¤Ž>UùTª|’|ǫʧSIÔ[• °œ{ƒjM6¸¹Cµ®Ïš ­Ô­ GSmª«·.¦àue[›j¤*K³ŽÛ«:ç_LIíÈùw'*ç¦rþ·ã¨œÿŸ‹ ˜ó_S·©[îh‘:þPÃê²´'OÑÖ{’7VÛS´Ucà4•£½GåhïE×s´™P]›pTVü®O]LV¼¥KrÛœgV¼  aYñê'«løšÊ†N~Nƒ§[þBšë‘f)½—З·È\ñxÒs‹÷&|ÔWÑ”˜ì¯ÑÄTÁŽÖí¾C®ÂGèÜ!wÖ3£k›m{Ð ïkÒá±Kv¾'³Î­ïãZÒu¨ÙPÈÏG@3Á£?ÓjDIG»T8œ‘4+TR刚*G,oyVq"±åW« tÏË¥1v¨$$Z-GôâÆ¥rDµ©?©SÐù_¯¯Ó×õûÂ=yJŠ@×z†À3ÈôßÔ!^´xTåÅB-}ZôÆÿ}Er¥î~L›>aJÞÒј‡Ô«qx‘à‚¼R# ZÚ2(+‘žÖ—S"‡º]@Q¬‰–¯[©Ì²ih–a‚ X³œ]ýNõ '» ù´Àûi¸Δ!X²¾-z±[‰`k=g[⦿¡OÝS=‹^—o‚…ÚÆµšµ¿ÓQÜódTÁËþú»]‰€_öï^¹¤w`öÊá×!å…H’Â^w!WZÕháy,¤ÑpÓ¯l<ÛEþNäRm—la* ¦ ƒ4×Ë8gÖíõ4ó s ‚5ÏÑÐàɱÍÄÒg(E™DC¦ŠEa„,µ.Ù˜b­‰[ “Y†7ÌZ°ÙWwÄ#þ ÉÆ*\ýÔdužØÞêr¹¥çË¡3”í\¿‡Îøö•;‰Õ¨}€»bÒiÂ9›ê{`©ôÑ*bùÿIg»ë)7ŽóB`©‹´Þ`(éBuœ†»ˆ/K‰kB`î¢þÐÖ×Â]dÈ›2+î¢!}/¡ÇÑëèUhc)»eoÀË¥-‚%È…f¥ËZÓ_ŽáÍ8}t—|8²’Ÿ}=¸tL1-¼yfj÷äå¦CSê æÒ?HSOìà*¨ …»šÒ™tútÐO&†s7I~”ð`Âëƒ:„?áÂCvmz9g0ô©=ÙÕ@¬ŠVžl6Rcöú—;€^Ú~ +XžïÁ@>}ÿàù6;?ßB$-xåV„ýËÔTkzCM–«± lyCá„l ›Ì¾ºÉÌo2ùWNWטڙ_cÚÂE~ /)ˆf3 …á~ù憳 ãê‰Ì<“ø”Nú œ¹›È³@6¬EO 9¸ôfCÅóuœ”­e' /$KA±MCŽo£4§–Xyòa4§£ïÍ©b:mESL§;pð™NcÿÅy&ï°ÌŠé´ŽÖ0õ—E0ÛõË#˜…÷ôU uó§v× fGßáÒ$¨'•ð)N0 LÛ¡]‘ÄšŒª¡¹œ™ÙpcþseÃ5£a¡h}í’# O4r\ØzÜ 6Ü’öÍJ'yå.6§×qR`!ùë¶+—§|+Ë™~ÝàñôgÎãw¨½¨›‚7G`ñ¢™R&æÞ€ŠÅo šbñÛŠ£XüöF÷ÍKÅâׄƒØq8-ä×\kÊÙ– ðèrLPCúGè§âC±.µž$Gtn\ÎHzã1ãÒo0.½ºqé„yú¤Ömméå>ùÚ³¨S"±öÄYÈ RõÈËÓz[k#kìeö“›°*5U ™¡!ú(Fo`JþãwÙäùâ¼³rD„§f°±AjW 6v´ áԷبÈF4E_³GÑ×ì7Œ®$ z_+úš­hªÂ·œ<¬‡ÝÌf'¤Í0”«AåUÁ#HÑ$‹vùQŒ^RðU|‹f~8Î3 âŠÑøÚ¿ÜqC›$ñ£ð&|ŒFw“db9þ¦…1R5l9fZ°Ñ¿¤´`ØÙöòµ ›éÑÓMuñQE+Ù ‰§nêÂÆ‡¥çû¸§Ÿ\Ñàv= x"ö‡Rå1] ÒaŽÂ yPZù׊;¨MqmÇQžÅ®OŒ”º?[ïm@EjPU}þÜACÙ–ãë nòoÅ´FS¼A;pÐŒWˆªÄs.ã–½é)ª¸ÿû¿AµëPJ»v‡<È”¼½Ý$ÒõÅÈ8&þ™VI„ØåÒªŸ>)"¡Ý8ŒHèbc0 ® :wÝsN1˜f­zz§¡Þ“"|>cJA¿OÒD+êµÃ(Uœ&e4Åi²Gqšì1Œ®™ŠÓ¤ çlª¯§Ië'18Mè çßu]*zzÖEªò6 p‘ªÐ™£Œž½U‘ê4U¤ºG©î3 U¤zÈU¤º¯¤J΀¹\©®©a)Z'XÉnêk"ŒsªË2æî.ßÈ‹dC5¥j5}ÏÉGÑh: V Ö×FE€Žð Ù½@ [ªú`h‹åmt¬ŠÙôÛª˜™÷áµy]¬bî‚r2RU̪‚þà úÞG¯ Ú†d×ЗÏÊfžÕËgé™òòY­ÏâÐ8On8 ˆJnFS…³;p°¦›Åf®ðJ=")£©|ërJ TF`®Z¯ lSÊp®ã„J¶†+ÿ”eBo©ÿœm¯ÿTÔ0 óàcýÙÎK;ÚÐÛN5ý°}Ѫ!uËØ‰b7ÉßTìÖ§/às˜¼’˜ê¹”¾µÏ3´ŽW¸Ù tmnòʃÜÖ¦«ƒhét •dd]B¥é$ñÜ™¤±ÎF*ï¿@«´ÅüàIцiˆ!õêÉÒ;y2´ÑÓDï Ë[_×zB×%ܸááZËï‚j£¤5,‘›é6¥1ä_Ñ\i£»ÇæÚù-mf‘‘(­K€T ¨&¶*1M’¹ìÐ P¸ k¢…ºr5ƒ•gÙ´N4Ë0a.¬Yââ¥â;è`x?õ“m¥ ÷öîÓI8­µr:1^§ó<„­^ª5&ñcÏÝÐ#_ÝÔ½ÒÅÒÔ´^¹X½'{:ö–­-¸kˆŠ•@‘&Ô{{só9OQô, .‡‰„ôFkùït÷üÖܦîû=]'jÿaî?­oÉZ'ØûïÐ"”j(É;Ø6CIl-nvC*ìŒ jMùŽº[ j{ÓÈI£åbAâ‘X#¼‰R•´M8x™÷ò~d­Úð²sÁÁª źof‘ç ì¾€ª{ëÃvÄt®#¦G‰:öTņ[ÐT±áVUl¸Ï0T±á!T±áv¼ÒÕ²9ŒtÜļ¸rCjZö¥RQú=ëĦeê ùIå édC³ÛR9Ïk[9O«mI?ÅlËšyI¿Ötç†þ‹þ?uSr÷ ìÍO¸ö¦ÖÊଢ•O‰"”7Ó‚X™oý’lNèù&áô‚æ»û¼^—dãwßæ„®NÒ,Ý:/ÜŒ¦ç\l|­g?Nã{MJ[ù§¯6zÂñã_>Ç©ÿè{¾_œVøH„¦Š&%Ahä-) &ËH¸a™©ü« =Ú³ —ô×Wƒ;) ]Uº”礼Hf"9-Dâ¶èÒ«¦; U´¨,9v€úᣈ¡Y®žµä²o'é'<°!h&µxgù!]dÎBeHafHé¦.Ynƒž!%ÑK§®ª+ëÄÇÓ@îÖüô„1 ev+˜D QŒ1BhŠ1fcŒâ‹ÙÀQ|1»>u°Ÿ/ן³Ð¬€)_ƒ¾Ôá%LƒÇüÔí¸ZÙ© I?¿&Ÿ—)}þÜÔÂ[òžðrÕ'GÃLÞe7Çêô*£•Šö‰“Ôy&ï°ŠÕìõ¥‹÷/ös=$ ü¤[Zï ÒZàÚȵhVÀÃmhJ•¯Ó$±!0í§«tHÆŠªfâÿG¬âM}û–TµÏ¤]·ãªSKvj#Cb+ RXÂÖ]bBb'€qË©Ìe¨ÈÑRu‘žI3-)ŠÃ3.eíK:Æû—²Ž_Ç·ªœ•£©rÖí8gÓ«T3zº éVÑT³Ò”Ë6+/ÖÌþ‡íU UâW>,œRçðÞ€ª|x š*ÞŠ£J ö†*>äÏ%—rÀ–ö\³¨êá5"µ,åzQž¾zøðV€¶<ÙЇ…Ô¡²6÷TÅÃÛÐTñð.U<¼ß8Tñ°øŸK¶8UñpιXøZ_ï âa®9åŒük}9²aá2ÏQi=A7mkY¬È³%€ì)> ކiÒ›§<ºo҃϶ªÍ©¡]ªùCÈ;@/È¢‡žp` “Õ/Ó2ã§ÝŒ"uaG¨S…Úš&F¿«R{-H8õãÅ¢¹«!Ë VÛÍhª`{ÖtõãƒmÈwÁ†á2†µS Rá;dª ùæO\wÀ$lÕ™˜Ø84lÃA¸H 2\[/›ÞØ\\¯ÏŠÐjm½ª,äh˜6†n¤‹Ž«tÛ4¤¼æÅ§&ôž&¥&„Ë1ê†Aê «eÃ/ nœ•uò.êaªvx††¹Ãûéhçq7¸›Àæ"ƒÜÙÂíª;V>,y~¯Ë‡-Ç}µs4ÄýkõÍ38 Ç±ÿâ¦D.¾(·ñù‚ÜëÖ‡íykË1í,¢WÕó¶@SEÂÛqTÏÛ]Ÿ:ÒmP‡zÞr©îE¯.ËÊ^·ú§è;°Jí‘]2‡"ÖhŸ¼fQ­î{Îj _5©Î5"Hð,ÏtH1¾¸Y";M3eéÄÀË›…’Ï•±7 *oÞ‚¦Ê›·â¨Ü´}†ñsÓTyóbjšfõÏ ò Wü IÝw#7M·¬¡ŒyyÎÎɬ¶ãT8‹-epî ¨*œ·¡© ç]8ªÂy¿qt=õí²ŒüîªÂ¹ çlŒ|}¨} ”˨pÖû©²=ºmèZ#Û¡,Iæ$µøÝò'zµÙ™–áäKÉÖ¤j™N_,8ת`ºÈJåûGS¥ò;pÎå6B•Êo¢]ª§ò¯#.­T¾Û®Šù˜˜¸Þ<ÿˈ¨R¨”±ô5ÊR¨œ¨Üˆ;,#j(Ò"§1!ÊȲ•òQ4§CõÒ¡xL„d¨áðÌ™tIVÝ:“}'ÓœI¡¡é½É®“B3šbR؃5ݬ‘8älg¥ÛÊk(£•[ ÂÚ°ö ƺ~—¤h4]ì|­Ù«ã .ÑÞèõŽK¢€Ç†`ˆ ¤­HºF†`Ó)¿"qê?úž›’¼/vú>vÓ'Õ¤u…†Y3eô/©f šw) Ù·žsO\¹:Õ-ÛRËŽÛòƒB¶Ø¤‰ƒÂœ‘4ÿú*šªÞõ9šâŸ¨ØL²ô2¥¸¥-[ØÞ–¨Q”¯4,ofK¶}Ѿµ†–OD˜”ö³‹fµÃ?áîpƒ®,e.UЪ}¨a‹Ì­Áð²‹ÌáL-® N}‹B )½}ÆD"Cùžu{‰Œ_Ç·ŠL„£)2‘í8˜š8=¡§«8z­<ÝO>4y‹töM§ÏU0ò©3ƒ¼ÅèkÂÚárH9ßÇH9”ÏÅÑ)ÇvœsIƒU¤h* v;ÎeÁ^)‡PÒa^¬Õ³/Ûʼ@R£¯K]¦5)‡|ç¤ÿRç'\ƒS‘rl¢)RŽ]8Š”c¿qt=‘ò²ŒüîW^)RŽ&œs©tÓ,zX~$#ÿH9 Û6ê)G3)‡XÛÅ‘r¶ýqI9Ä6ÁH9Dj$•o¸? "娆¦H9¶ã(OeŸa|ÀëEʱ‰†çª| TÒ !å0†Á5Z)`¥mû?AfY°rðÂK/Z¼ •lK¡jËÖj kLâÇ(ž»¡G¾º©{%Ø›HÚ>2A5 ´qX.0{’)£iSßæµ²ïàwn\³'êV6nßâ¦éÐÆÕåHuòk—ÞËw7~&ñ•®¶.êÖèç»u³%¹y¥¢ƒ§g:‚éè¾b:Òz^%¤ëH±5¢)–£8h,GŠãhGñîìúÔÁΦܕØZ·ÂIÐ#Lªµ”0ñÀ­0_äxÛLØ3ü$meìQ  óÜÓítYâqÕ+X’ª¢Ú¶äU†¦ 5R,2*Š|F,Tت+*ì3ÖŒ¤ŸÃä•ÄÙˆ9×bôÊÐ0)*¨½¦Lã*ÚzºŸøbtø7@3³×ÅÚÈ/n ÆMÑ‚XöIΡ€¹j%÷¥è)kêðàÓE÷¬Ä±«=üè+|¡û¡}H×®ôÑ݉cÓÇLÉ[Ê=©ðŠäî…ÉÁv¨:û°&ÚË–$hÔ¼gJ6ä;x®aŽ<¬¹^Æò‰" ÆÅÁó “•ƒ5ÏÁ7ÐØÛ±oJGÜý)JZ]14C¨ÊAnpÅ`ïÏERáÊ‘2KÄ,kLârÎ.6Ír?q—¡—úQè,Ô­-êYoê²z{¿J¸õ½^[Z"Hðíp̾!U'~Z†Ö¡Pjèá ­ý„¤ôg£ñ«j—ÉÑ5ëv4&{ˆ\èò\Ë_R^l´k!tuØW:äƒ3¸J\6ô¾TÞr¦oO·löûRwIçKƒk f~‰Ñ঑óêOI8cTÇé¾€Ë ] ËsnžÁ~ØXÅÌöÍš®<¯Nú¶T¦ìys±ö%(x.Öñ­Ê@âhŠu;ιÔ?+6Ö 4Uþ¼çŒÊŸ/ŒµãÕσ3H˜Q\¬%Dj^„Wé¥p±ÊFèÃŪøv8šâbÝ£¸X÷‡âb=äO—ŒNeâ·£û&§âbmÂ9_³Më²ÉÈÅj RU’hDèF$Rï7ëT¶ê T¹ W¾€ìRÈYàuozšö# ¯¢Å»û1>iËÆn‡TDÀ6{ùˆ•´gÑ@û럃µO]{”Óž»‡*ÐD3oåh™;ãïk½ž|ÞÀŠ“9ï–»\,H¬224L½o™Š·Š†—* kzÿãäƒeO+gäåšàô†žña™Ò€m[a˜ÒßÔ±ð ùXPLéhŠ)};ŽŠ#î3Œ˜* ˜Ò7Ñð‰ôÀ–¬ë>#óB¸Ò©%¬Êæåþ9×\TK¶¡S9[ÀkËhµ/÷ÍxP6ç'd›Ó2liÍuÁ6'x¶€eÈ#:duv>[à¤ó­²Äÿ\²Ñ©²špÎÅÈ×zöGêÜÚ·„ºu4[Àê %YjOÝ›Á”4Õk½¬ùóÔGã[ƱW%«æä{ÿRÍšÑTs†8hô|qÂÒq z§£>ézì‚‹¯3L¿ð&¸ÐÍ\ Úz²cö$O1YYÛ–uºéîº ®šH6áÖ!€¥õ„©¾#x DL1k¹¹Ö?¤—ô* CÂIìîý9‰–éh®Zµ¥:¶4mrH%Û—J¤:ãN-B\µûvj±ÉgÙºr½'r=“P5rÊкޥå¸:ahX"Ým7´ÂÆ2T ýþù²Ñö{b6ßÁl´vBÈsôø8 VWÓújÓüß?$œGS¡f-jÿï x±lµ°§Àlµ¶=Ð.(<±f«5{úé®ðº[Ÿ-påИl«›3ºÀëL)öÇüì;ù^_î…ú‚N <¾õ&º3~U&Ì'äPÒe1Cgk°¹Hš­Ê;ªhåÉ~ò/f²»Ÿe—¯l£§_¶Ã­ Ö¢Ó_[vo(cËœ5?¡lÏì£ðª*Wަø wàœQÅâ'Ü@Sü„»pTÅÁ>Ãèz¶“ª8hÆ9›ŠƒAß”¾ôè´¡ü„Ö@—2òÏ™”L—¼˜m%%{ã[•ëÆÑ1Ùœ³‰Pê†%ŸæÖ!Ó¼ã1J]7õÃö›=­ÜiÚ"8k`J%+5QÜ»:†?!ÊnMÁmÇQ›}†¡ˆàúsÉ2؈ ›ÒÙX˜Âg ,)ëòôxžaBÝXó z¼ÛÏ*=pãz–ð° Ý´Ä‚?‡'.4æ'{l,äðe[¶Iý$ÕL/ 7%ÎÃ;[®7¯£¯bA©TšÚ*©ŽåäI1}[Ø$éN'Ùîfûv2&OÑëÜ ßU;ƒMµ3*Ó–¼¬[-ÌÓ+’¡T(ðœIiížX¥ý‰Hi…òé•êÚP‘ÒnCS¤´»pΨ†F‘Òn ©ší8ª†f¿q|´]ר†æ2Hi¶&×ý¤¤´CùPÒ^¤´ý„¤ôg£±'yV&÷Þ€Šv Z©° ,ϵ®Š*ªh¥¹JSn+,0ôQNGË0Åú6üŠ (‡£è­$ohBYº‡Å¿*ç)[l~ø(â³”óÚûr ¬·“tÈÛx²!h=Ç¡Žç¦ÞÓh|;qÆãÊ•™±^I½˜ú©n±»™á8éµåØDN÷@Ö±¼ÐÜŒl¶£!z§fÐRKZiëîdhÈç|Vf;Z¦b|¾Í¥˜‰lY3z’†D¾gÝÌXŸQ" –ÆnCc —vn-n•Ù!$¿ÜšÀlM0 ËàÕŸ’p¤zp4Õ“`Þl³ùþËgãsêô0e5âJàänç@.&{Þôø}ɘ.<=þøVåˆq4E¿Gäï3Ž®~/ëÚ_äôç’ó,`ïý‡EßþéNÒãºT¼áœéñesŽC?Wç'd‹SÑão )zü]8g”Ú«èñ7Ð.ÕÆï¾É©R{›pÎÅÄ×lÓú8ä ¡Çö ©JàÓÓ¨ÅÂØ;iÔ©™>ü»Îãtü2WÌéÍhŠ9}Öt?Âwðåݰ“M]öG€ì™Š¨ªéªheФe(OTžlûtÉë]·¸mºaÉqÌX€ã¤Æ˜-cŒ ³¦ãÑŸ÷%¹ÙÏ =!é}ì†  Ó;2õcjËûQ8Y.ôÍŒ”iö ×4ë}i/¯C–l„.^¯HXßš¥°ž•fµÅ(ž7K{¶îs@kÉuªPTkÍTk=Eµö)[_¦T€Å0,Sì}€õå)*¿‘®/k(³¾`¨ü$’9MÉý}ÙüúoÉŒ¤áhüªÊó9ZÇÉü:d#Bß»@O¶¼×}±Ñ;Ç5Ä?T¾,Me¦qOBÚ}™ò¬9* ±€Ð‰8*Ŭ(u"ï ¨8*·¡)ŽÊ]8g”Ȧ8*7ÐT"Ûv•ȶß8>Z"›nò³}6Fþ…pT­¡TË”“rTö{’fú¾•vBÈsôø8 V6ø„~gêÇôßÿ÷Ï çÑT™äMqXnÇÁ²9,5½G·÷å˜ã°MAI,Íž~º… oŠϵb\)økÉ7»=S¥7´Åé´~úÜVé‹v•”ûá@ˆÎìðûàŠ’W©%ãFä•5™6Ãwê¸Ay‚·¾õ׿ÂÁ¸Š£Wᙃ§ö‡R‰‘þm(Ùå½™þm|ëMtg¬Xà8šbÛƒö`ƒzš­è~ªhåÉ~ò/f²»®NaW¶nXCéÛó1“™ý:Êp8´{R™¹gÍ?#YÔzþ™7e}B¶€ÿÌšâŸÙ…sF×öŠfM]ÛoÇQ×öûã£]Ûkƒ¾ùqZÈ_ ÿÌ`(¬…;Å?£k •Î+þk±I@(šf4Å@³G1Ðì1Ž®ÇMŽb Ùc]·¹£ÇÇDÌi,Wh0û¤ë6·bü‘eüYSþ {Âg½å@˜)H(!ª!ÔÝB4ÛE¤úõp4LZ·gÀ+Ñ+rC=ìZu`šÃìC)Ía˜–-¦ ‰E$/É´ÁPŒw§1i>\ÎËÐKKÌ5§c© æÄ±³gJR#)êšFêEÄéú2¥èa¨k-ÙH^ÑïË[3\†tÐAôª,– ­ãÄ5gs…`±¦\Údµ0O¯H¬Ëða¦ á1|Œ•îâhŠâcÎå )Š 4Eñ± Gå í3Œ®ß[¨\¡fœóÉúPAñAÍ|ûŒ)>41_KŽâc%£Ij>ÒÿÞhšã̸îPc]ñ|4¡)ží8çÂóÁ.Ç&ï4Ï‡âžØúéî ªŽO~ˆZ}©CôÒhºäÑ]¦R[*tã8z ÆüÔÙ»/àå2@Çh„V` ^9gZWÕs5´òlOÝe›íhžA~ Ð lŠZlº°™Ú=ýlÔ²v]–æò8eíïêXþ„|,«²ö 4UÖ¾ 献ªTYûšºªÚŽ£®ªöLJ»ªtýÃù—QÖnölaŠ×Ž•µë’¦z­¬½¿x©…^®k¿U…í­hª°}Ž*lßc°°¥4+»»Œ¦*Û·â¨Êöý†Ñu³[U¶KW¶s °@ÕîK•w —¶#Ö¨KVš6–¨k:U$$þ<#a:º»ˆ%(ãw_Àõ®î}é ³‹µ}—t-:.[Œ°Ç–Ý;ƒøEY“ÚReqå] ©ME•i¥TVŠÜžBõŒÉ¯çD$—Ûwˆ0ƒ4&ÌYÂl>ŒÆ*6é–2%"8à bLM7¥¨!D !Äéêõ;F¡éru¶ÔBdËü+ÌS”#"]ar¤6'¥„°{’T°ûRBXKE±FSt¡ƒè„fhg\#¦#pÊ4¥Ã™É{è)ý‘¡u¼ôëlô‡¦KÕ˜²%yríA·¿ŒöøˆÅ1–¤ÑÓR“5ÙôT—Í MÕÈìÀ9›.›ºnê§‹Aw=%¼Ïæi§>%àCÔ$]lVxgSÓ>ƒ[j 3ÛÊr¹¡Ý¨ÓL]8Ÿ¢[5`‡öb‰­'*óá•ݹ/ *Û†¦ŠÀvá¨"°ýÆÑõdTUÖ„£ŠÀöG׳Q¡‹Àt­×û@|…}«/kèw L“dz8}˜!iª×ŠÀ¼yÖŸÄ«”± 0ƒþóæ'ýÉM¸X¦£qå{?—ì{sU+ÖŒ¦jÅvà¨Z±=ÆÑõÀ°ÏƒóB`«4ÓÒTÁX­TôLQ&Ýê[§Ó*]7Õy•øœ[½Ó©–®ëªtÌÔä{¢RC ®ÚA³Rò h‹*öFöl‹ª±¶¨ëš3•ÆÑT ÔÊ5›-HÓ·Ù¡þIïYÂ&ªª=Ø£ö@U·dˆt… ¤ª[N[{ ËQ½w;ÊŃë=?º~0ú—:=>ážõ ¿t›½ÚàŽ9›»l±ÇJ œ\k³2aOᤦ¤•¿oÁÇ0yŠ^çnø®ª>r4Uõ””Ç‚Ö2eÅÂ<¹"Ñ )ÊÆsÎÉ“®\=NNžÐ}‹R]{ªœ¼mh*'oŽÊÉÛo]¿ïS9yM8*'o¿qtýš<'O×Çοœ<Ý#¥<}NžlÈ –“g5ñ²«T»f4•j·G¥Úí1Ž®§Ú Æ3[ð'{;šâdߊ£½v}êP+N–#˜"\7l©+÷Q„ dOŠp-!)3à#/ FÌ&³ŠŸç߬~ª,´O¸Ú…q‡ ]ÿ¶ …¥ÐšÙÂìk7¼ØÌ€VðL®’† pg×YåËmje‡-Au|™Y%ÃN@؆þÖ´Qx-Þ݇€\ úJkc] ©‰õpY-èr^ò!*a…pp´­® J‹iÏÇÝ­ ¦T-L~£Ì-5B²LSŠcÿ-Y,Óp4¾}KoRVÕ¾€›â}edìÉ÷’½Ø¸—ã„°³ d<›û!Ù<°Lçžüzh`IQ6Àd“Jœ‘¦$cþ ¥ôŒœvFzêˆähÏ'UGäV¼òdë§³GÔ )üç#Lãžü„ŠæùT|HÁ¦n@}èxPÉ£þ´`„¿t°Z"ñý¶ðþÿÍ{ɶs+ ø–sFO“j×tÖ9ó†äÏqræÅÊj•y¶/ Ê™ß†¦ræw᨜ùýÆÑõ•3ß„£ræ÷LJ˙7 ùÙ>ïBræžhL´âòBsÐ!—Ïë?žgtYc?FñÜ =òÕMݯº”çWCÛw/í~É‚†ä/\ºl¢óQ–Iž„'˜ïQª‰I¼i}Q½ ÌU4%ßtíó2}"aê?úž›úQ(Zñ 1YP/³ä±ÿ×­e@Uˆ;DZàÔOãC ÀýéËs*T^‚¡ég^’Ó»óÙY’$„<—Jr_ä4£©‚œ8ª gqtýÚ%z|LÄÌÀÈòÍ‹~:¯Þ§‡Mf~ ÜpŒP2kñ’}zU•Ã7£„›Èí¸œqC3¤ ²ó'_¶e[¶TóÌJÕ<Ї£)îå²&è‹!l*‚F ‰¡É„ ³'òHe$ áÑÈáÑSÄ©kóélú÷5Æ•>º£œMŸ.%oéèŽu=2þˆ}?N^ éP­ÊW)ƒ¡¤%p¨Õä¿aM´x¥ƒg¨ËNåÛpNs¥­Bx­ã¥og£G†CSªñÚjaž\‘Øý[bJê¡ã”…Œ•îâhª.dŽª Ùoª.ä?]Ê!Qu!íÃèz‰ª iÆ9—ºm@ècè_J]ˆ-â­¤mk†HCãÃlüŠ‰Ï–›>ЍåJGvþѮ²8lšæ8ô%.ž›¤£ñí­ç8ÞÛ›ûà¿hšM¿få¬~42ØÕ…Í^x¥T!S–íB3'ucA]ÓŒY"R¶LÉ´¬ Mpœèá_Î"•·dª³-iÇ ßEVÎF½/tK_;KjõÄÔ(êIÄÀN_ÕÃh¿®jò‚(©4R5Mhª¦iŽªiÚc]¯iRU¬&HÂäê0Ë{`Ë1Ÿv¨‹döNsñ†žô–ÅçÀ!£uV}Â=«.¬Ý l4ÿ™.DÇe+ÑaÅŠ°±8ö$Ï®ñÊjcÃ)TÓ0:@%}è-vO,>yp6µT™4k4•IÓ‘Lš.dјìJä¬#É2ÚZÁ~t§/~%†ÌLœAöm'Uަ;pTaqt=€€@ŠÒïi*Ÿ¥‚¶žî€ÀRÿ[½Ó-mølXþvžyBÄÝ-åâѽ ÛÚþœ•O—› €î\¿'uŸsþ¤(I–»R}VŽ«)G£)V‰;á&ZŒO_¦Š6òŽ hqC"â×–ë«äèP&éðÁ:nDÞמî Gãþ)¦½èÌÁ§X=Sª4æ´QA]ìL>¼ÆnñàzÏ®Œ|u |ê~d°C.}· £yd²ó‡oG°+-pêP¬¥Μ¢zr'¾ Åj?LIº-H8õãÅ‚¥1OœšyO¿éÝÝN’‰í¨|¯f4®Ýƒ5Ý™K œ…ÔSÝC«hëùN<ª+`SléD…‹ Ø>DS‘îm€%eb÷N×;¾ëˆ\™ì®W~ÌÜÑq쿸)‘3ÉÞ@ ¢f“oÚ}p5K—Ëx¸€»d€eKŒ~9g݇TŒ=GS1ö²b0¥‰Ç‹õ¨ú–d ¥®‹)„ãìÛØ„žU–P·ô怫îñ*â‡w¶Þo^G‚Ç¥‚Aõ’…ÒHNÒé„Íœ ›°a Õ¯ƒ¯-^!N_\}ÙÐ$µ½(èŽ?ñªÊqòeëýÓßìÈ0—‰q®|¹ÓKË4d‘A±À®²Dö¼ØËh`³ÏÈRô_pøÏq`3u€ìس¹Jã+qHf:÷äg¤°_á„ׇ§è$óoÈ$dÁ7ªFv¨æÃh䑗Ψ) 8-mFßЕËîò‰-KuùúÌ’Y[zOSÂ[[¦þÜgmy*œÀéÚ²„í/Nh'œPcu#œ@”T½a²jʨ-ЏE­¾)™<}ì-JÜö´†rެpl.¿EÖ‡µ…\¦æü–r\DëO#gJ<îÎ"òÃTuÒÍÐ0³\¬¾-M~ÐÇO”®iˆ-ÚÍt€Ê =yÔÃÊÑP¨@Z5öác³V¯'¹¤ÎøHqÝíy¤¥OÑ2qÃiâ$d¡Ž´ Mi:Ò*+ôäúGëÉÕö iÝÑ?°&µ§LêV4LýÓgQ—£ôžt†m—Lj«g D£ã—cÿh’=êëöFßî,Ž– ?œ)Õ“¡)ÓHõ¦ Φæ)Öæé•ÎP.ÇêŒX§ËSNW+š2z:dôtËé’ª/Ò†ñŒ© ƈô,7—JójR5Ãwê¸U~æë“+æP©ÛŽðÖj…kýŽß.V¨ m¡ëöšR`ËIäã÷Oqô*¼ÀëÑ,­'Ù±æœ=&¡D…==¦4^¶§”Ý’¡) În‘ç‹óÔ& Õ:RýÖÏÚeÓx*NÓ„¦¼%§©!Zš582EV‡”Ž)YW7uóä£$ÊÖ)¡)[§C¶Îjuv@ïÈ]J³±êbyÊÅjBSƘڱ‡²ý*ºâbé½áÇu±@­OY;hJítHítÆÚ1 ™ŽÕ¦&D¼ Ep–u{~X>v1¥ ñÜ6å±kVÖwz5~SóžÜ˜qLûiBÕ(UDsk냞þâÁ°¤ˆð>dgs9Äît6·¬¾h$F†š×RîºÎki²Ñ”èí&†ó¯1gðèñßÅq+Ä‹j£§É^T8šŽx$Ñ2ö„,ŠfDPF¶C§ºÛÌwSz@ù¡›úQx!ó ÓFµ4ßBÁf°õ|‡Ù1ªG4mp¢¹†i¢Šµ¶ ;Á@WõÀì:µHÙ¿³… †šÕƬ(Ê˲Eµ`Å9ØBÌ Œ$9ÓÚ‚Ù6ÉáÆ[‚BH3rV'ni%Цäª}Ög¬çÝÞîµM[Yp»W¸Î@†;š^(Ëx_øþr1uS’¹Oš]úéw7~&ÊoBõ›LÙÞ«ê7ù 6ü@·eÙÂÏÆÚɶ3˜Æìk¢^0š¦ƒô½0×ì±ÿIÇt¾l†À' ×+wDQú±Ì>/ߩ鼨ç+õB½‰ë·º@á6°.s›¤˜¡«ÌКb†nSÌÐí0ŠzÛ‡W—ÌÐVßÈwݬb„þ„ª?4ݬeË%<èšÐöJx oY^JÁUlOÒáj’¹/=HGŠtYÙ‰ÐÊ©.ôðe³©Ó¶ñ#õ¿Ü„«Å# »œ‰% lc½QË8 YN†û¯BQýƒsë µ4‚=UÏÎå£õdZF¨”¼­)y9YÝHÉëæ1Cge‰$«ïÎÊÒõ„¤¥ë„+7\ïy4¾~É.êW£ñËhb:Ê€T‰Zí0XÝIóÕ :ÙöP¥j­ÁJaâ)ë 8Ó¦lÚÐÙ\ï4ëT(«oXR•ÞҜޢÂ"*½?½¥o—Iˤ·ÈóØA$ÅÈ9)·-Y1ZÏ}HF»HÈTí]̽;ÐéyØí½[>¼û¦—TÛöëE·ç‡2…@†Ù:ï€Btã?ú9|Û •'·ö±Ì{ŋũ°;Î÷ÍžpÊMÙŠ@m0‡½UÇ#ÑW{Pز®K¾h[wdøž«’?¡j}ÛèÙ}s¾0àv¹&*N¬Ù0šAqõD¼ç¬ÊrW'W©2íšÀºœiw™qAäº+Mï Zõ\ä²j€ÓœRM¡Ï»»ïþÎþí:Uדžºpév÷ËT¬hÁ0%©mNæ[N)šÂ•mÚ)IÝt™H§]ë}¹˜\¦¤ô~æQÒ8Œœ4rVÿ¤–¤OõV2Ñecr¤ :×^4e¯ÐôSøw[&^´hÝîéêîy¶žéy"D£Ý ׉y§缎>´ï$uÍß~öÁY –“ÅÐ ºQ@†ŠÂCV6?2*áFÉ„òŠ &ûk4Ñ•£…QîŸJ+ÓBðOwL h{ù Ø^îk²×$—i]ЩþÞ9CîÈ!„õ±fˆ÷YPVå +¹R†³®°ÚRy(}±Þ‘@KÇ—a#¬ÖØ\9>õÏþömÑú(U_·×ÇvÔ× -Ÿ××Ùú@Æ=ÏÄU¹j«ÖÄUÍ}™ÝÇn˜<’Xå0©ÌÕU<Šî1¡óªžºº^VP榭KÑ1ªÜU_ô hÍ]=©ñ ¥ŠŽTÂë>Ü•ðªJ”Ó<áÕ6 ™´v«¯ ±¹AÑy®÷DÒ虄æÉX¯®ØpîÙpT–ú'\ µâ:«M[]€{W&.(J" d¨ÁpHBä2U8$%«xïlÔq¿UFí:£VSµ˜Ê¨m‡QµíêLF­ÍØ<•"^F-A§ÞË\Vžà¼Y½¡‹V·Ë¦Ì–R†)f7¦HUîå[R=XÏ— "#Š3Áf™Pê ì4ìe„t0B@?üà "€Ü»6»b“‰ÑªlцlQMe‹nSÙ¢í0*[tç T¶¨è•-ºñœølQÛÒYÕ¥²Eå³vdEåî[oË™¢æë“›ªËÌ#~hi]ߢª ±ØÚîfËé ³†í¡.s±ôA³†!ó»5<Ð ©v¼‚S |ï$“ü)YsP§ÚWD.˜bÎo‡Ašè…Ho“´ADO7»~lcÿ…õØU"M9Û¾P9Õ§ÂÌXŠÍ]¦O=D ›nÎHúù5ùL‡Åþ\f1_û$˜ŽrÞú¿NôôáÁòûhâÏ@ûnŸ0öÓq™i發_È|w›ôÅõ<’$œîcz˜’÷ím:ðô’ižu ½GlV÷µÞ#Ê7ÈÁ:ÝäBϹ¬¿ ¬`É29òŽÒëe Û®dÖꢹɬ>õUÍìLÕÌÂÔÌ–×àÆ—1“TÑ,+š•‹ w¡hv`h2±ó¾© )ÓK)šB”áé=öúoèø¥FäEÁ=Upªïî}îÙã5­°cÀÐeŽUNÛTN«jàq¿³ÛÁ8å´td§T9m¥œVŽ¥\N{Z{N¼ƒD .B­ŸUµŽÖ¨ e¦êhÛaTmû‡½#ê‰9Ú5m-HìÒƒæ¿áŽÊ.UáÊÅóÃkX.\õ#çaùøxE¸ù³À½z¹ª7¯/S‡¨ªÁm‡Q5¸{|èp Xƒ;èK…|Ìž.d¢¹ìå±Pïg®X˜º]ë=¸SÎôìO¥ù¶  3,µj–”%âþ ^¢6äaÄhJî£<‰vJTOÀ* RÕªjXƒQuØ;ÑíÜPN9Iwv)óÝùblкœÔ°á؃2.©y l\~ŽSÿÑ÷|76oJv©­ÐQ?<¡d£‚ðÂØÅmñM˜’ø‘Z *s·CL*Ð5ÙðìeÚÀU}šÞ;³¬Ýíx Ï¥Ÿu©ûAU+½ª•V½9˜ª•n‡9­ªj¥#Õ§–L; UmÖRm¦´k¦ªÍÚaTµÙ®®)QªÍ†ú@F[žgµ™œzl­6ë§QêEY0»Ò–ûà}ÔŠ³úÚTÂÔ2Ug ¥cD­@Q:¦qnš È»£%£ñ-»n¬ZA£»IjMÙwnè‹{£‰{3±œÑHî†R)€}ðJy®ƒ¡Ês]ƒašKÆ w*¿¿ÛwŒ/4©X3LÍR—‹+0u¹˜«:‘æò?ëƒ ÎrJµÒù¨Ý}uˆdóUw_u•˜ƒuºÃïeÚQìƒ&kš!}½pô  h/å¡¡ ëT d CºŽëˆ:.e Bðˆ V—ÃÔ‘kfƒ2«Úø`ê\­gè§2„»­t¡ó7 «ëQ´–ü§mú@ÂúU4=û|NŒ¦G‘|àfÔÉ&MÏPŽÖš[Bý¥ìÿHj‚^¼YöCå`¨æ˜©Ì±5ªlËNHÍòWñªÅ¤ÔƤ$ÇŠÙ&¥¡Ñ^x”!By/m†¬^¦Ù`•õ 7ND©Š;ʲ~8¥0P½ªAê¬Ë½ª•ù”ƒ©¦Ôí0X·º°¦“iž™‡ ß»w(šý^íÜ+àžIèÇ—”½FÁ”÷ ›ˆÀÇ6”¢¦ýˆBVƒà>¹;) ¥µ!Œ2„Ü¢Àª°œ³%É q „QƒHS,ѯÐn˜ry퇨ÀýßÊeCu½YÚ¯{>ìN½©8˜v}p“l÷âsæ`êK?›–yŠp…ÜêÑÄB, «gÀÞ¹çJS=0]\8[~¯²¨~™¼Ï¢àO'~”2ÿ·é’]Ëì—Àà&Õ¯IôkïWýWÑkÊÔ—?®¯GwÎäæFäoæ!}ÙšYt"}ž,?åŒ^Ôçœÿ ¦ÞË0/š/ܘ8!]9˜o=)lÛOºñŸ|)”áÓÜõœäÉÕ ž·!* õ¼€¸qVÄ0£HHHº\”$°Gáõ+a$8&'€›˜ðÒ5*~5a¡ªŒLZ‚¹ˆ£…;£ÆNéYc`Aº¾4ŽÉ£ÿF¦UOgyAªµq‡ÙkùžÌP^ ƒÏVרq¥AË[UM£à¶ì^œŽôúQƒ[¨Ð˜¦¹j¼‚ûIó!¶Y)\Þß ¡ÿbÕMÅpвõÓɆ[K%L°µTÂ[KìðOâý\$z/¦^ÄØSß ¾,ILPLÒ_¿ùIÿ}.–éh\ùÞÏ%ûÞëõ”†¨ñ«§ïË õéWÅlðõR¹íÖ¨ÍÄŸ/z’óÏgàvÓŠèòØÇËÓi°’ì£k°µl8 VÂÓ`%L( ¦±ØÇ©^zEø±ßzY8Øk¯€B½÷ (Ü‹_«­GÂéJ aMwIž6õϧ_¢éûq2UÆ„¿C.a™èIZ ”ã‘ / ýÙ2ÎÖ&Â3Ë«ÈÄqÄ*"ð±­âÀ±mRàÜŠmRÀ±²4G¬"$&S?¦àJ)cuÛ«=;12‚DŒg³C2‹R??µŽöpˆ>gEÌ"Ž<’$wù ô£Ï;* Öû!‰Bç®{ÇËÏ¡Cyñ§$q.ò(îf]²X÷ï;Â’mà—Épá{ÏNB×É1Öþq\Ù’ÀÜÍÒì{ú”t\»ÌŸ}/y%ðbõ“ˆ…óAÊ `>HÔÉg˜«<¦g/ð=§ÎcÈ4ަ‡„/qú;N2¾ßj&ûN8SVÙá$r žMcÑb,ADmxgá&Éë4Эç=¨DɲÔý–{ãý æf¬Ž®!,p²íµOO<ºÍ¬‚)@AL ¦`þIXŠþ?–$~Ò/¾’€¤¤…p=ÎUL}7Á Ð1xOnì<𬣼Na ÉÊõ‰óâK"Yú°ÁY4ñÿCÀ}jÕWQ¡–½Î†7?³ô0M_Ä䑤Þ“3 ætY Ü鋟h]Tä™Ñ‚à9+UQÌ"¥g2–1Zf !Ï£à(Of-ŠG Ž"î5ö¹^<ÎTökyGy¾ŸÎN¤ÎVƵå -ͦ:€öËžã N?WPÁôsL?ÿõýÛäó_cÎÙ£õf$ýæ&¬Ÿ'h_=-™ã~ Á©Š02ú¡«©›ºWTù㈱rÒ¦p: È<•žUeg¢&ì£*lŒ"ð lÅVPQV,Üž­ ¢ÌÜž}¢V”“䱨ÌR•Ædõ„À˜Fæãœ*M¢&þعUñ` µ µRk°PKµzhóÜ‚˜—'“YÅÏóoV?ůSñ·„,>þ JWkñÝìŸgì:ìV°&…%BO&ß®>{O„¥(OÂ’þ®Ÿ>Ɖӿ¬Þ0™ì뫘Lé|çM±šÝŸ »LÝûs1ÛxÒ¯’‘«Æo©³ÒtªÂLG¦¾šão,º;fÁÝ(†Íõ®‰dKçókòy™>E±ÿ>Á·ä=Á”iU–Ò•®÷Ì—ÔøÚ¿dëJËCn<60nZi›šz•BP±íN§l¬¬ÉŠ›’|¶Ò÷±›>aíj£×¼Šùj«;úâ,§!€4;[¶¼-)#ÊÓÒÍðd¹XDÔLÅÐH,›¬š¹¥Ñ9 4ÆQÊ0±F Yø¿1pÆUçÕ!W ÅþÆ”<ºË u\nÇÀØÀMRÞ‡€Ý–B.˜Åè$¹âÉ@uÙÀ½“$ZÆáôdPþÐ2ö¯¸ÁƵ3ºb²ˆ>5¨ì #pš¨Ž µžk¸`Û¯Ž 6Þj è!²‰3fH]¿‰2f0m_ÇEšc¬õªðÍï$u?|΃ŽÏ λ¢ ¿&-R[„«­ ;B´¶&r0ãA•Ò{bjm’ZSfk°‰EÚÑĽ¡O4*×vñsÌ^õS S?ºá¿: ¿Š4>œçÖ;þÜ`j¥Š §^k¸Hï N½V£ šDîô:ŽæÜ|Ðô"B‚e­m?ú^ˆ?Ú`í™ l”—kÏl`£ŒncÔp‘Æ kw8Þ2ŽóÜþE~­ÿ·a_–ue¢®Õoôhdn!p²´™uv¾/³Š»©·EÅ$Ö­j*)S«ë+ðŒºB:?½Bº| Î `¨õ¾ µà-žjýI¼¬­,³Òýðd|T8öh}pk¬ ¶ÆêÀ`kŒi(/š’›äOjÍLG0µ‹±Í£)°jêÓÿ°™øëû·"•‡_=:,a$ËÝ.Es N¯žè?á2†6åèÙÓdjñyÐ|ÞMQföHt-‡mn¼‡¢§aÄÓÉ«C¨Ç ´A6å úñ›âúŒ ~™áÁŽ3Ø:ÈÖ‡Ÿ8Ùí«UÁ[#ÃL'w`åSS—'Ý"‹ãtø>™â‰ÓseX”©$œ¥Oˆò´4ög³•aËÇgXëÌYÛD†:M7Á,‹Md´Ù³-úë²÷ÌÕj›ë¾XzA^S8pFË_¿Ð¿'šÓXëÈ~f¸Ó<Ý}¼*ïnJ¿ ‚‰áÐÿÁ-FhK‰ù±Ù ÁâÆ$YDa»µÛ: ÐP{§jóØ+w’nÏÜ +ÿm8Ô%ÁÜñFã~@­ÅM‘ºA÷—™‹ö˜¦_K†17å+¹™IRˆçl;õgƒ=ÿdòÍaA&gLæÎ+7âÁNëWÔæ¦3C€7TC 0µÅ3R«\¡Ü7É(l9fµi,ÙLWS4œj\º±bóÞ½€Löv ÍÏ÷•7Y?ÿ“NRYX3ìš°¡ôq6Ø Õ„8'`gÔ`ÊþCWÏÔvhÇÚzyUѯ.ÀeUA_Æ~:Â@_¦€Ð’¦(noJ²›‚EÓ²ÀÚ(½™/ÂN)v…sMÇþñʹª“Ô\¸~|3Ÿ$«TÖÃÀ†2 ²+ï²QÍwC‡@få²ï¯ž–ásVÛˆÄq¤!¹¹»pžÉ{â<ÆÑÜùãî[z ÿè&_¾ùÞGÌXÍ{oÚx.d>Œ|1–›]g4âõªâRÛ* ª¶nú‰ãfáhç!Z†S7~竊Å'Ð*›…ÜGþ„0ªÂjÐDù=2€ ½óÅNà')51–"Ìœñ( WI¾çö2ØvcÑŸoþþÏw0…Õz?[îTd­ÃD|ؾ´]z%Wf”}“kVóŠÍà2¹'k–>X¥GN˜ã“EÁŠÞµXGÛú“Aæ‚sMÍÜËŪ¦o4æ)¹yЩZï"ßÈüÌ4¦‡$=6Nëqú¶7ÀøÞB0‡iÀ¯×Öd‘;Ä•‰Îà KÃäú#ñ™ÝÄu ‹,êkXÛ&ý>оEá iõým²¿äç¢aôýLlÅ»OÕçþüqФ†MÀ¾³‘é2šo=¤‘òªSD¥×g5SŸ[›hF5°¦“ÄsÔà‹Ùä@цphs¢Cþ¬ñ ‡£_`½ÐîQ" *±_T”ƒaA–&ñ2CÍœæ¼hDˆÔóq1‡+V%Ú"ãj/kýL~ÔQÏÝgrA4íÊl™uñÊ)ËW‡[Óa†7~”™·™‹Ä½ôêíâŠç&p6Æz{jÌ‘ëõ‘gycòÔ æ… q´™ý÷SÓ™r½ FŒG7^ˆc48$eòxRˆž.°3¢o†Í‹œñz m6wÌ^öÝ cQFtÑr¡ÙõdEh¨¿óÑñe\YÍGtÔm3(v ^ÞFƒ¤zÇc|Á¨­ÄrA'à‰/$Ÿ >— e:p@Ösd@÷+%øƒžZñš´<Ív}É[cÜ.kë¯$2ÆÜ¢åÕlÌ-áÁ,X^…@Åè&¤¯_„# “^Â#”ŠXáÏ!”’(ð =m›þÍBöYoìÜXj±¼Ñ ¶Õ Ð{­$Õ}øf©ÕY·Ðœõõkþzó;AÃv º6’›ÕŘssw—ëˆ%Þže>[ë‚:ŠaZ 7LGƒ”Þ±§päu0àÁÃmœ!]è¹g}’‡ow@¥´:RÀN÷êt/ð N÷ü|{Þêy <¨ç}!1/ùA[U_i=j©'Œ±ùõ§ÿÆ®Êóú>œ·?XÕ²B¥|ͦdzal¤l˜Õ²NŒ­uhH§ÀZ|ÖÂp½ˆÇ)Zàt-±Ýàž(¢°ƒÅWaù±‘åem)×ò°T®%òùöiþ¶üÅæÂBòOÖ2ãùÖgÆŸ÷Ë\?2Z§Î•ÌU“ΊPì‰î/CÆ2{²™¶3·³¼¡à½Ñµ¸ü¬8Ýó²½ÄpôsPœ×§½n[ZÞ§udWƒî0 ް,†ù²h1¥Žq²ÎC?€ùV×à:"8”!¿²ä×€@¦ü`ÅÄ–B¥™ùhÄÃïPD®[E16þ+¸8ýVY`ow«¨7¾UÆ*h® G] m"1WE›L”ÕÑ* c•´ Z-C/Z¼óZ³†b´½Ï`èçÿÅMHßÔŒþ_gJx¦»|^i˜„x|û$Yëf],¾EÞ³пd_MÆÌo@8ùKÉ’ôê+äwè ìéä÷CúzÄŒè_£ñõË‹ä†(a^!G{H˜‰çHÒcæ¯0ëÙS¼P0LS~”°¤ßD Kú]Üf'LùXà=µèWˆ– øÃ þ{"MÜž.—[Îfõ9L^IÌíA ÖJÄïyýyVÿƒ ÊΫJùPOÄHå'­,yÒÊ¢Ž3iY¥újÒØiÁŽ$­Þò~Vjy#BŸ•ÛÚãÉ _ΙÀ”ñGBâϼç,Ž ¶g&“oWŸ³F¬8BìY¹ß9ïsŽ#ˆiåŸ ÆøQjY"Šó{]Ea˜eáÊÒWlÕõxÒÚ®#I³*k£è펷Fô+Òmíe"Óè5O骓=ŽTö"··¥’[+^àJ%ç`™'8R²Èþ9-=˜°*Q§ýä&lÍÁó’e„“ãZühJŸ>‡Ó,IüˆmÑ—ê™®%Pv:üÉSïÔ ·ó nÏ0H…~Cà~É4h©R%ÿ\G뚃ÙFÍä'Ôs&Œ*!I㥗ތ½ÑˆŽûžq8Ñ'`)£“Tï=Fñ«O?eöG;©;“”œjšó•éQ‡E(o~º©ÆçÂ’Ÿo©f;ß?ô™Â¢¶<+?IRœÐ!˜ÎuN„ÆG¡ ›RðÐFŸf9_üpzsÍú¥ÜclèUÒwèÿX“úuJçt¸yŠêlÜ|ó5:©C‡~¡Ø­GŸ%—ÁRt‡ÎçðuIré”_;`à|Ï~Ì’º2‹OúY-ú„¾Ç([èÂyX>ÞxìxO.}›±ë§ {×R#&N:˜#&N:ÞC‘íõÂÉî¦ãŒI¯GÁ^‹†þ&ûmþþ^«fÈ7À 5˜n)-š Fö‘2¢ÀI2I@^H`‹²ˆ]Z¢O'i±Lžfz:îòíæ†NûÑèåëâç½ô4>¿Ÿd ÃE´`|8òNöÞ"!–Ͼ¢À—V¥êfuðLÉ£» R'ëP)ðì’9ä2©2‹²-ÎЈi¹üÈ,ÎaöëwŒßŽ}lb/ªqéWÑ!‘:‰ã¦|ËÏHQ¦R¼q­hü~ïÎ4»Úž~kÅfʧŠÌLsV7½·×`÷÷n Îf|ñ {wãb›»ÖS¢—çãæc&ÇßO6ŽæõÛ­á Ìµ ¨ÐdÛNŽ.ôø"ÿ~Šçü;¦Hˆóय³bsë´ræ6,@“íù?š|зÖ(á ÎOûw‹Gyy)oý(õŽ$èïx‚0líš ‹ZÎ ý:Î,\:Þ='Œâ¹¬íê±Ç_œt×Û ñpV×À¹{pÒ˜¶ÍòÉ2ô«¹Ìkè9ªúµ$½™˜,Baôç7ùê5Ùêµxt-uxüfÒs°Á–/xäÒJ¾ý À}ŽÛ„üéŒÕ ÃhJøoÀ6X 6(RLy?wžbºm¸Á‘FKמã0vÛ݋ž°ÞèÞÉÈÝÝÞÓ±§z?vÃi4w\Þß.ø»Øø–T°Îþ‡/x˜ vüÇý&……å–!ãÉÌMé[Iukñš[ÆNýlÕMÃ÷én¡O3`ÿÃ~–EÐäœ<ÜܳÜS-F'Ù`Áü¾ÜV½¿Ñ´Qx-Þ݇€p¬¿iýƒÑ*ù…2@ëT>i¨ÂCÚHðý¤•ž ÓMyÐñTciR¨õ¦3%+¡–¾àÞ•Vjè ‡Z-„›Ø¬CÀÏœçö¯ïß&ŸÿÊYÜÁ^˜ñ5gY^^M”€/­Î^ \ÍÁÍ„•_½Åà†lsÂdð··Ù6 º!Ü6! ŸÁÀ[*¢ æ¥¥1#Üð[:Ý X3ÿ€åüš`xÕ_À¯ý˜"^Ýî@pÝjˆ[ËHÁ6Â^eˆòÒ¸ýOâ>;1IX€ƒ5&¹Ù•XÂ2麾!ÝaívĆ ±LöϦÉ$R¯¥5/Â^åEÈÎ̤ɫ9­êÕ ÆÙpjvÛ&íNºéÔ€n:5ò MN€ºáÔ@ n:5P¨U§µÑ©1äa›œØ§Ø©Yã695¸ÍNnÉ7;5òÀ-N~ðy´Fnqjä‘[[ºÕ©Ñí8¹Ænwjôô}œCZËowj im·Ã©1¤5IÙ©‘ƒrj ¼ºS#½ŒkN `Í©‘¬;5šôöÚÇ©1`¥ìpjÌÀSÓ?|SB95ý× ¦S38xXVÝÃõÞŸu?DªÝÝðC @7üÐ?uÃ@ÝôC P«~j“b¬G×° ~Ähüë`=üçZï4ø!ÃmôCp›ýàF?`†[ü€!·ø!Èm~Àt´ú![¯Ý‘Ÿ“­~ˆüرüþ?DZ@É‘«ú!òx5?°ê‡VýyÀº€¸‡"¿„üC¥ÉÝ$º»ÝXº†¨öe>ÏÊ”%>ï­z09 —mëÜ8 Œ5Æ£PSŠÄàdñ¦l†I š9y!Ä£fhi–û20!¡3öLÞå/É//í•Y4]tÚ=¦ùÂ4 á,}‚x¡3p“tMýGŸL! ŸbòS*÷ü‡·¹ÌÔÑçYÿ!¡ZÌv²~“ãÉqò"Oy ¶#½e̸p²Öž©+£ƒPc’,¢0xh¶Š1{L†e®[ –%í.R†ƒóö‚ã¯î»ì£M§tõ-¨yâœxòhô•¾½;î2}’ÇÊ–ÀƶZÑô݉Py%G óÈ1Œ.àH„ÅÖpý8‘Ô"'¤¶: }‰Qð"©€ ¤e ;¤Äó}V0ŸZÒH©?gÇS,«^3¶oI 2óÃbJBñ¨ÕWôØ%S,^åÄ•Ü&Rz²çm`YäP %Çb>Q"©år¨Y½‚…€sõoÀu•„‹ØÓG°ÿ@ Ìsƒ ò$1XÛ$¶ÒsZPI4€Ã::È!LÉÃR¦ «€uùW8s7ÉïìËñYÑOܹ¤§Ã[ÚJŸxŒ:Æ} ;ædzôƒ ·X—±L´§ÀÊmAy°(f^—¼MIQ¤œ<ÜÀ/ÖåÑìR»á `4…ñH•bÖШê‘>”fWÀ[a€‰÷DæËWúS”¤Œh_ñ€½Ñ ì&œ»TgM™» ‡óä&N’1%KEÑsÉ6€ãVŒšç€“<"ÈÊ刋hí\!k¸DÚn̰b•¦‹üBÚËõ¹ïÍ01ÎÜ}Á›î„@Å®¤¿–ÃÖäј9IúW~ ú= b¾¹6I9€?“ÁxÅ$~!Q' z‘5b8”üvå01¡@² Ž´LüpædmÀàX¨s{Oš¤QÌ£žPPPË+C[cKŸzx—vÂÊ€Ò!ð5˜||“™Ÿ¤[ªÀ›G²±õ9@˜i>µ ÐK%¯ËVaªÁ€-0@Y85»CCÙ"Ž8Qуü¡V{O‰¤aËàØÍÌs2¶ªk“ÂI#ñìE2™ BZDÑœa $Ò‚›%—N¢Ë¡pK1÷â?”œ¢…›Ò-ûäSYK6CŠæÌ@"‰çÊFû8‹10^²€Y4IàÊš[ÂÐâ@ËäA#Yó€»i  ‹<Ü¡} „aø­ÁV¹JÁµ*ˆ5¹Bc1;¾ç¡ÞG)N „ºsÙ{õV––ô:ØÀ$•6ƒ¡;Õ“Õ,ÓŒ>ZƼðh<›Ó %#ÌØŒ'@æëÅ –²ÃZJ®ó§¬¸Aƒ›Œëü/y³¶ H¶GÉHåý¦8ïÈ\:Ù†Qe8?³8Þ Î DÙ¯Àü@×Ôîì`tNüèi=£¨dPšn°ž2@Hƒ*îÙ ÖF²6Ö€ÑTÂâ- €ïtsÎaSžÉZÈÊ#åyBNš5–ÈÈÊ0¨[ÊS*ŒX›]Y͘'ÃϨê<¸s$ì,—žžs`ï¯P´<;Ëm•=†7éd¾øÒÞXšj’@§š$댘e—„‘@'a0À%}Xw&BHž\ÙYˆJÖþˆw “¿ÊŽº¼` ÈIÉÐ&p8Žç/ž¤Õbù38Ù© ‡4á°ÖÔ%7‚°+8Λl0‡‘>Ä8È2Øé õû S½Â’éU€Ég\s˜!š€Â@,¢ELä‚ IÞ!Èò$@– -YÀÉßÀp(n`@<"”“’ŽÇÚ0I§·­¦þLÞ&(ÀÈ›|Îè L>™gE õ0õSÙ5¿‚›>¦Ÿ$KiýP€ìÈ*ñg!™>@ÍY²|ø—¼õQ ½¸?…{¡œ#Ÿ;½Â„8Vàgû”xñ»´µ\$!”½!*CíØÝÁ¡E¯!È.ËádµÙrD ´ŒüÆ.áÁÄLK€Ïä5ȃdG,@X¡†øBbÿð±Óx™ðPªã¹<Õš-%yÈ)Û{0FÏŠ |v36¶ón’¼Ò)|€ËâxÅ6”dû˜u‹È&QÌ¡¹¤Ùz#°K9Û0ša c=W1=7!ò[‚âÄ•¼€¥(t_Ic@x$iBMLñLá¿¥Qò Ò(ˆ^YÔ<Ž]É­¶ !x;–!h-^X—C‚ÖãÕ0A*òrL¸š¼2 |)]R—· åƒáËØ—·$8ˆtCÉyžÉ;<  M‚Á€0 1 e0"VÎÇîææò‰3[Ó¬RTÓ`ð¨Rðe3õ^`îÃÞæˆËÆq²ìYù(ñû8PžC£Ø9bä± F4•~‰ íÑõÙXÃáüi*iVHƒš» Ù06ƒP + Η5žä½Z&O¼®9Z®.|ÙbM†q‡MS¢²i~R^' ‚•¤tæZì€Ì–¯Æ€óÃþ@¶£E´X¼èPÎ3¥Ø£ÿ&5’8Z@0Õ®V°Šrä¬ÁŽ<+õ*O`lYÎ{ Iè·Èþ%ð8‘ó¯IôkïWã×Ì8ù¿‡ŒÖùͪíÐñ­Lê7´76ª4ä°a¿Ê‚Ÿæ®Ç§´»ÛI2é9Rh«=_ÜÄ÷Æ)5Óżñ×<üˆ¦„3ËS1é€#n@Ýõ›‰Îû/ÝL’ÑH3x­øÕ“ë‡wÄý:Î,\:ÞÛ›f;NÅsú¡,;ŠoÆ·“¾3Iû/„µ¡¸aÿpÙ߬YÓdäÜM¾87ãü»×E_©=Ú•6¢¬;l–éÿ›=–9IØ?éû¿Ò»>Iúé'é«6:é|Õ¡ä¯[Ži=NûšµÁÔPY5ã–‹’¶ÈX“Þ„ŸUWôÉMö×hbÂKרtúÕÄ‹èÜ2ÉàLfZ¸3z$”žq¢?Š®¯¹YE¦UOg&¯îbt‡°.,/ˆB¿¢‡Ù ÿžÌP^7ƒÏÖí¨q CËËNøéÏp[ö¡/NGz ý¨ñµ¿`᎕&ÂQáN _áºA%[‰ôý­ºXÝݲ3‘u-ù{­7È„”­ŸN6ÜZ*a‚­¥&ØZú=Šžïc×O“+°q–0Æ ÷ŽJ˜Ï÷ŽÖ=^¿/K²¾/ײáÞy ì—0ÁÞ9×qVPkm”p!ÿrËà£/ÒŠðc¯Ò²p°eZ…Z§P¨…ªe3y”JÓfì„âm%þ43ÿÑêu¬ãì-M-Y@Ä JU‡Ä3 ¯ãh~=m’/ËÖ"UgAv’zO¬“d³Ø`N¿;p§/>£è@xrsš7ZÎãÍ£@ËX†¯V "$Öp§ÓX¨¤ŒlF ÒòR-8›…±¼Ífaãøuj !Ï-ëþé¬ÅÖÇ“)ãlÈ7‹À[„ µ9gãÍÏ#­ú÷D¼çd9oS¶ X¸¥"–¿Ç?‰×6³ì»ýÜÍOúK7ábI¿YùÞÏ%ûüüØÀ®—AÐ:!ǹ:ð ¦üâ ꎪ*ˆ¼oÉÎÂã­s¶¾Ta—o‹ÅLV"²~Œ_èæÍ¡nÛ·‹uâÚ¤ÀžÛmRüáQút |“W_e}1Aý$ô{ЦH36ày1ØcÓ)»ÜÏ%Ðòo²oTþ¿]íd/¹2ÕÆÍ‚¹ÿøÍÉ‘N͵¿êWÚ1nÈÄ}akGšÍ’ÀÍXÃ1@].Dû1úù£8Þ0¤û^g›ðIr ±úQföø7fÛ„efaAø‹º(˜3ȼËÀŸY„¤#u¥!ãæ£$î8W%‹™—GvœðqYâñCV%ép!«2(Æ6…ÓRePŒÇ‡ÓR¥£Në­™ÐÎ¢Š¼#„ÈÊòޱ*Ë??¨&º ü+§ßÝÅ"S@\ ¯:‹oÇ·šY¡‹M€ÒVËÃ1 zÖ ¢¾SÁûú²Ýzþ؃*’.Kmx7ÞÈcîÇbD­âSvŸ  û¤Û'9 ‹ÁE²Ê `#eUÙ«@_Ó CÓÂÁˆÿ1‹”d c3Ä¿™’:‹‡³Nüÿ°…XE…z¿UT¨¬gù£_¸ ¬i^4Ÿûé7Ö½1ã²*ôDu6µA0Ãè&dÜNmu…QŒ^™R•†AS‘w„Ú”ª¼cÔŠT$¡X¤"츨¢¢¨8…ZAE™h…Êîú‰®q‚³ïË õ¥øö¦W²ÿÝ!’IV·™øsNTȇ>>§¡ÛLDZûn½[úƒs}·n˜+CƒÞÍ9*ðnÎQÁvó_ß¿M>ÿ5æD Zïæ«§% ŸÜÅѪ"4~6 Èüê]B¤&ëms³‹7Ðcw¼gøÑ ™íO´3ã!«WÞ‰ñÀY^TM§«+¨(3¦«¯y¡âirMkâY¶j°P+  ¶*A(ÎQ9Ž£4ò¢€gä[ÅÏóoV?ůSñ·„,>þ ÊùoñÝDŸY«y¸¤…šVM6™|»úÌ«cqžÄÌÞÕÛû„Ä/ô¼¾™©I³¨´"õí;Ë“a«C/§ú/”A°b‘+ÞÐŽÝüeõ†yÞd__Å„÷šuq'ãÛü¹`禅÷YËäÑxÀÚ–& "GÁÝ,Rg„µWY‹ö£ÉÔWsüÝûŒÙµOÃÖÖD²Ýòù5ù¼LŸ¢ØÿŸà[òž`Ê´*KéÊ ‚×{æKj|í_²uU¾"ÈÜÆúJÛ<œFPI]µÛîtÊÆê?úž›’|¶Ò÷±›>a)2£×¼Šùj«;úâ,§!yiv ¶lïc—5ü`xJ)$“å‚uœBQÂÀ¤ÄUðáªJq#°:&0>¼ h8ª½ h û‡•a’wpc2à,â*,ΫC²ˆA©†,³ÿ·ØŸŽÂ¨ñNÙŠV¹=T"¼#Ÿ6Š~®.7³ûäÃZÔ@鸯¸ÌOt§ÏÌß<²`gƒ¦§QIÄq„2•{,Ap‹·—î¼.R?Ö¼AêêFì£Î˜"¯ãBiò:.”*7Yu‘Ìj&pFCl¼UâØí»3fЭ³2f¸ýQÃEšc¸ýQŵuÌ"„}ùU„zýUv„ °šH½Wýw–eçW?pq€šØË#ÊׇP¿ 8þà4E LSÔpÁ4E5ê¥YAäN9½8; 5½P`Ùg[žâ6Ø£yå¥ÁÍØ(c†Û5\¤ñ¡¬)õ…#é˜0/xÌy®+œì’ fB¬B=¿-‚(¦ç••‡…¯]¦ªßÙ®-S^Ø ™Ÿ…ô"/tŸn€Cn¨:8ØQ³ µ¥6€¡ö”ÅÓ¢?‰ç$¼Y",óØXoÙSå;l àØõÀ­±:0Ø«ƒ­1÷•$ÑœÇb9¥ì]KIÎf)$C“tð¸ ùýÒÍõËDs&†Ã²¨Øµ¸]xaFʵ3~ÒZÇ‘¹SÃmª»z0F;ؼhJn’?é 4*ܰüÐOWÂz‚ßÇLo0c“½Rº™‡lõéØJÿëû·Â]žñäŽ<Âô$ b°¼òMQ¨~ù¦¸#xæBÁ,÷Md(½· vl"£ÍØ)Ð_—dFê¨Vj½«Ø—e?äÅÐ_œÑdàŒéa0`-‹´ÙoÀ |š/ŒW4M…wAÀÎ%N(=!¸Mæ0çê-ŽÈˆ³?±xŽõEIùˆ­VÇ6–zÐ?<ðsßsÖwþ;£Iß¹š…=F´ 0hž 5<»(zåfù£ëÁUé6@Cmñh¨=nk¼F—É›Mh° Ù„†›Âa£j5;,ûTO½Í‡„SÌïa4~á§%æØ©³´.3Í+;Ö’a¬M¹ÆJnfâyQýÙÇ`Ï?™|sX¤È“¹sÇKŠYÄRã'Ž=ogÉ&|ýdK jýdÇÀÂMŸ’xî‚ÀÝ:Ø~þœJ[¡½9» J<yìŠ÷Í(“Sqi5¤üÐzÉ““©³H㺂€®"Ç“S…æöJ³‘ÂWšåü m+Ò9–ÞÀ¸íjó‚'8¡ÿ!Œ1§Å|CÚZMcÉ·[y0-ocä9Ý`YyBNoãzO~Õ`¡IØ ´OýPókÌ–Á¹^-ø_4møP«¦ jÙèUÿ¬À×z¼‡Ã=9 Iu‹&3_OmÓèÙÒæŽY‘¼Œ!ô; üšb0Ù>£_ÿ\$€­‚¾ÊzCA__7¡%õV4,I©Á ¤&Øiv]ú#Joæ‹€0óÌ5šŒÄ;ÆàYbbÌéëæ“„Wô0S±ÍŒ€™‘Æ*@?ÍÙ¶’h{Dhý#Ùyë±ÍÝgrAq Ù±ñÕ]Žå<å¼%›Áœ<«txõ´ Ÿ³àR½¸¥*Öy&ï‰óGsç»oÅí;ÈUnò½ž?à}Ä<ᬲ»Á Ç çÃÈUsa»ê¬Q^¥éÚ'A9—FŸ8n–‘á°ñxPãË0°÷QàA=oõ¼/$æE£ h«²h–À%Œ†`±ù}ŽÿÆnkóÂ{¶?Xåî± â|Ív–ÇïMm¤Ô•ÕL6öq$ãa-žpǃìE: çs6Æ´úaôÀ¦¥Á ñi%ð…67»‡¶á© /_+ljƒ°ÎcHà:"8Ü6ß@Û´ÈP[pS\_´Bãì%6@ãMÔklQÕP“Ò41mð@“cñkÀ  þ"ƒ„šÐ hþú¹`% ‡û¿dÊCžö”$i½#Kõ¥Û¤@í”V| 7ÛŠü®í>‹Ç8‹› ÇhÄk`s¢YÎn—¯7":Þ‡‡þœ Ÿ®ÆsÔ©°§~²ˆ è.©Ð v§<à¼SÞ4cÇÚ„ÔëöþIWþa>Í9h¬ÇÛK ï›î°aw6°ÎlãMßø ¶rÓ »¼ÆÛµ-Ý0Äîlë¦Áufk7 v{¯z#hÿŠóq‡îŒðx¤á<øýF}™ÞÜ9’+nXú ¦3ôù£~3±«Æ?qÇ¿Ug"£¿ÊÂd†c1BMã†ÉÙ°oÆ“ÏügŽáƳ›o¾–ÔlF|“:ª¯1ç ¿™ôù|Ð?ýlļ¶Ysòaóõõ±¿›Œö£W{DV^sbúR;ŒcÏ«?¾öÇ·ùäÖ³Aï‚`2t¯éj¾¬ò|ñf?&_›`4š\;õ™ûÍ¡_ꣽ'ê{‡'*(­7ƒþ+Ÿ±ú‚³IþJ ά.¸AÂ97“/NþÕ|ïÙûy‘³ç N]Œ~þßý§îÇ™L)¶ðnù·7S¼íÍJ°QËožäºB¿:ÅW×ÅWûOøýeNøË<›ÈúVçÿ Îâdé?¹‰Cæ‹ôÝIé#‘tô 9º¶zìèá_ÔT‰žI¬}@á&WΨŸ œÉlz•ôWN8y'>Û6­»&èóyNüñu^³s'ÔEÏ)è!Ô¹™ÒOçÁø9Ô®éà¿2#É{’’¹¦gÿÍnI!s?›¦{6 ¿4‚C…OÁÂÕÕ`¸d˪¾­Goë .?(€%±ÿyJ^ ‹w½™$å[ŸIj$Ièw!â^{K’~‹ý/nBú¦f<ðÿ:S»úÈӟשMɀǷO’ÝíIÿ‘²(_ÊšOŸÂt=Z!^4_¸1qB]ߣƒsé ±Þö“ÉÂõÈÈÃK7y’Å[QºÈ«Ì5”ô>[CIo¤Û\÷”ªËù% ýjš”!à3øïÉ !ñ‹|î@‹¦~¾ç¿3£GŒÍ¹|úJ®Hœþeõ†H‚ØQþ³ˆ£ßûs-‘Vζ=õºÂ¬µ®,}Õ}Õý–¼#©.-{[ߢ™ŽÝ$yâ)’4«²6®Ü xp½g¼5¢X@‰Éò}Ö 9o7Ÿ¾ó>Ž(2^ó”O‹$•½ÈûØ æ„…ô$̺ÓÕ3Y.Q ¶\Í̘.²NLP•Ô±_Ÿ\¬q[ ¤ûb2‹um¡òc#ï·Í‚8R2µÄþ9-½n0aÅY‘5©ejÒ26Ù®¿ŠÉ”.Vß ì'7aûž7nE0¥V¸ÌîàÁ@@\‹ÛLéÓçpú%‰¥Ë8JØ]‹nÑ?¢jóÞò}ÿj€ªy §ÿ$£{„~Cà‰5(o‰ Jþ ¸ŽÖ=g=a†\4ù`.1ˆ.>Œœ ¦ã¡Òí˜pÖ¹#ÊßHN=ú lŒà³°/3ÓÑ'gßuiΚ険3uÍãëÐ n¡iêÌ,n#ðL6Þ ƒø“DÓ # JÒxÉÈ †Ž3 —Ž÷ö¦ÙŽFñÜ ?eÑ úØã[Ý{ŽFcïÞ™ôz¾²Ž“Tï=Fñ«OW¿ë¤î xpco4¢o„JÖ%§šæÜ/A¾¾ÍÑÍ$]%”Ü\¿¬.»ëø{…™+«M±/‹nY %Ǫô]ÓPÿ~>³Š3TˆY5ëUæ›ÍpØåÿ*+y’ZÎ?œÞ\·[ß¶îä9å'Ÿ˜lëç OzéièPtg¸yŠ‚)•Ì“Ÿ&×yêSö…A¿øÂ3YG#­ç|/†É.~†ÎçðÝ™º©K·÷w‡â œïõLdéé²è$ùž“pãaùxã±×í=¹TsÄ®Ÿ&L¯ðF¦ò—åbâ Ö­€8ˆµg¯×^Ö %Þ¾7z›‹¬—ïÊ:¥ +_g¥µÇ2ªÙïï\r£bÉŠ%÷Ùᙉ£!]qEÖÝmyÅ­ÊN‰Þsœeè‡> ùÿ!S‡1SÝ|{èÑo?˾9.&ª÷…½µqÂK挿æÁàG4%¼ÓÀ$¡³À##Nñ¶Ôtœ<iÄÉïù¡xÅQvôÅ늴>¡+‡>'®,—ÙÃ,Wq˵tŸ 9z0º¢ yydÑ€qÌ_ê“ì\£o[ëÓ5¼X&O Ó;îòíæ†çYÒIzùºø)KÃ.3¿Ÿd :µ„çG’5\D ç1Žäor÷ ±T÷¾Œ‹^©ëUcÓU3%î2HVãN¡_Þ¦Ì!—ÉI‡¸¶g‹•–ó•}píá0ׂþÌ>FäqéWH^9 ÓÄqS¾™äg¤H¢i>azÛOƒ>¼Yœ0.?w³9$Ô¦‡mUóØpþH£þ{ÇG=\iÕiç˜ÕÈ'` LïèÀ ”8ü Ô}}PZq{ïÎ4»z9K¿Åeë[õ‰Ž·3å÷wÔÁ@ëSK/àæÒ²”ý÷£Ên^§ÂQgAalÊÜÿ-¾¬ VlÕ øéÇößq†MÇãrñí“•]èñEþýÏùwL‘Û~ ¸Ï7²òuTí#EC7 >Þ!% ÿxϺN ¬Ùùi_ànñ¨ïoŽüúæHoÏËî+ê:ÆŸ¨fAÇ„ «É°HÌê\w]ì{ü­M,èGìÇ$aÙ¸ÐeS\V„"ê$£57Fk²÷a­ß_KÅë0œì‰›^ý Þ‹8ì9¶Ïº 9ëÁj°ãÍpyÖÂ|Ûpƒ#Žv¿l’-7æyv ÿš†¢ …ªyÇyd9û%¢y£{‡žYôw·÷ô•¦zŸªÙi4w\Ï£¯.'lÿ‘­f²ÿo`ã[n?SÁ:û¾àa&Øñ÷›–¬± ÝøÝ ÉÌMé.Jukù!ý5'œìg«¥è?ÐeuÏèÿŽø,t˜Ôjy!qRÒ§{=à¡Oø™ýû É¿©ÝT~ ÍqHȪÐÙCÿ•Ä|üÄa¹B7÷Έ>&ç¶¢G:]bœÿ‘îðüª§ñxX^ /Ë@8IA{Ò•ϦꞚ«tÁ,T2gçþFÓ~DáU´xg³Á±þ¦õF[±šH#­B“k^èoŒ‡ Sä¨nʃþEÏ÷ü•Žt¼„©ÆèPK´zªÙƒAe—U? ðX«31ÖâR v¬%¾À±2Ô¼˜ n¹ê슅Õ\ò2T°)г¥õ%ㄆeô˜/Lÿëû·É翲›U¸7f|åm+À÷mÍÖ[ µbn¸×J¬G\½‡±•WPÞ0c(t¸![,‘YoàË¢OÿÃÀéb†ž»Ð|>g؄؅šøynÀo|Á°%yí²Ü;ø°¬ßRNÉlÊõ^1åE±ýýŠÓ^«èðe®ëÕ-.€;òP`ýìX›Ý¢þl€«\0À"¹ ùã(¡ÇÔñ9XéVZµSF`¯ª"¥eÓH˃Á¥:`0ІºÐR™z&Æ’yÃ;ÊOYÄB:¬ ÿ¸¥úý¨Ò÷-/ïÆ š ·;1¶-åИ㫯DQ{.•SŒ q]œ` í‹n0õ†öpJ¿a¡°Û& _¤ƒé¬k}K ô†6&¯ñí­;ØôÖ ì½;Øy¨óL¨iCŸÕt®Â*?«¤¤?úœ5m¸ÚhÚðµÜ´cô{¶ƒ1[ûåôÖý`J¯Æjx5_œ¢GÅ—U÷’n=’/øDŸó7Ÿö<[ú§4½¢[þíÍž4fsOš¦Úüä×ô]f ¤ØWWÅWÝœ…¼‹ÌþOW_©ü¿ì³=M­ROSP›{ßnå`'x次,ÜèšÈuÀЇu3EbeñDŸ÷™,c]ÉÞlçôhÏØ¨qzì£Á‚üLLR]ßvör3v©)ß:Ez¨-<…’}Áx,†×ü²oeÒtå}8ZýÊûàHÕ¤ýÊ[?ø~ ºyå ºqå ºyå-Útå­ n\yC¡Ö®¼Pág áÊuóÊ µzå €ÚxåmÈÃ6]yƒÁV¯¼`®¼`¯¼'-§nË•·%Üxå Ü|å-Ürå­l¬‘[®¼å‘[¯¼mièÖ+o} Ývå €Ý~å­¥Á·\yÒfÔÖ+oCÚ¢Ø~åmHŸ+;®¼ iåZ¾ò–«^yîuxõ+oé X¿ò–¬]yKÖ¯¼5éͻϕ·+eÇ•·)³0Z¯¼eöòþWÞ†Œ¾ÛÿÊSÌŽ+o™¥ }åݗјXWÞ;ùÊ{xÒ Û}å=”ßëû^y›2çÈ•wãa¹ò¶9»®¼m™CqÇ•·-{>}6qÂp˜¾½ü(«ñJÄ?ûEÏ|,[ø¿>‰}*ãA¡»LŸ„?äe¹w|nñ.ü¡8K£\ð4JáO'©›.“CøÓËØþÌ›Õz1™ ~pÁ2ûD>ó”¦ ¥¦,ýSô“3²ýS5Âê;éÜ©~ù›¶ŸÉ~û‡;'™Zúõ×_ÙOòÁdº ÓØßûeOþï6ø_´žnêCgŸùÌBþ‘ý¦_¾¸ Y?€¦éýÁžÏÍ>éèì³Õ ¶?Æzιõò_ÿÅÿ؇?Ñmž¤ÿKÍŸ¤/ð±õÜ‘Ç}Þݧ}^ßàè¯Ï0Œ¡Èso¼¾•2Þã›æÒÍ¡Ì[g¢¯¨{ñàzÏߢ™ŽÝ$yýÿÛ{×&·‘$[p?ï¯ÈO¥*º ïWVfZI56·TÚ’ºfì¶Á$˜‰àÁLéš­~û"@2Aîáˆ@¤˜mÖ¥#‚áñðp?~N^̪¯Xm(XËŸ–ñ”oµ„ aoö«Ý*r}é«È±Bˆ%Ñá})°,5 z¡ƒ5%h)6éÙ–…4æª\Dõûµò1‚ï£,¿*g“IôWÝs |½] J/L–yÊ~‹? Ýi{ŽØ–«À™°!g¢õÔ8Ev¦l›–/ùõe}ºH4ñÛº?*£Ý ‘ÓÅ1ÍqY˜·èK‰¶ü¸=†ˆ¬é(Ù®¾1.c²¿Ð{Wºòv%¬£ÆÇ}Óº™G›Zæ›ˆÝ £çû9J<ñ‘þV=/ÓdŒ“.ù½“d»C\ll@¼5¦Ú«YxÕ*£X¶/²cóZ1¡Öë´’¹ƒkQ½˜Óÿ×ç'i'±éñsu÷]ýüò—Ÿÿþ÷¿ÿò ài5W½Ñ:Úk/õÏ•×ÿhá·`9Š`[}p›”Ìô´Ý;=Òý[–ù¤í?èêþ矮¢¾õ¿ 6kÏ=zö¶÷<)·ý›¢Lçé4¡‰¾–Ççz&66ЙÏB]¸Á>T¼§EÝWÕŽWÿ:wÍPÁãÍ]l°ø ð<5± êéûVó\m<ìãù†ÅÄ£Ë6Ý"ƒs–oÛ(ëEN=ܶIî—‹¸L6ŽÍüû~þ6ccÏN´ñZ;ˆoçõô..~ÅEÆq›ˆ.0î臀]˃ý¼ŒÅ*‰¦Ìß®ahnZšLXt¹¼ÂG:É ÊP‡o¨¸ÃB/ÄnÃA­øRßûÌ÷Tä©,ׇ¬á½ÙÉ!“‚8çðè Ñw>Îky¸ÓMž/¹WÅÓÀÂD¨Ýže#èÿ­;žV;^ï&ø3©XOË«M; VAÜkÔi„=ŒÎ‚ÞBzÖ“Ï`ú_GgL†™üOu;Dso©¸L3ð!Ço¼´šÆ¤zWzÔi¾igãSk BùyD?p±iÄi­Á0"îØ¾•Éä>^}Ñ× BùBÓ ],ükëR×~°G]›ðõÖµûu2‰¢GfÉú`þ—éý7Æ¢&@±Ž³è›¢ˆ¿Ù34Ñ/]`W lY.©v¼1²tðÀùà6î-^Üæàsˆó È«ô÷äþFÀ`9Ðñt𬶶ZéC\&Ø,ÎS“𳨻¡}v6ú=Zݬç¢#+÷—•x¾ÈÒì¿Æ#€ùµGÒf¨ê1®¡†ÍæqºHftV«Ÿ°"Fô,iÝe[o²Z¶QZ¹q™O7›jUs¤ÅvtAW@žV=hͪ_ ›ñ#sí²õ}´\—O[@óì›QÉ ‹¬Öºf/B<| ¿¨^Z|+îT3•†t˜ÿ6)¹G»Ýêš`-F»å4€azñ8$›F+E… ûÇÏCQ4ýú5¾ILöꮓc[URÐhZvÝ·ª:ªÚ訦HH%PRiïªÍ½«sp3ô¯(‚3Û6Cltúé€;¬Ap“cH‘Í6mV:·¢8¯;[áí+I`! ó'¾Dú˜Zw˜¤1¤cÚ£´#ÊŒ ¬Ó ǵiàƒß"¡]Ìþ” Dú×!$ v,¹;«£h{ÓØO­Ë|´‘ñ¦aÃR$kÊÑ$)IJM†Z׃½2Ÿ|v /4Æ•žÖÿΊ\U¸Y–öÄÉC`ÚELþBìÃ6ÞÓ´ýþ> 7ñÕÒýùåË_~þEKD› DIc&ú϶çD„“½X&›"ÅD•tæó—Ë@/ÓÙ—ºd[ ß*ÝL‘m`bgéÄZÕy"0±àö6ÅaÙâ?ªý¬¢«ÐÇùíèÚrñÒrÚÊòÓ…å{kL&ߦiõu²†œ¸¯îrqm+ǤH¢‡´(×ñÛ~zlÓØ \ùu¿­wîb¾ñüý¾ý¶D«òÔÃP¬Pû.À¶§ôkî×;*Â"yÿ5™öš¨9ºE?4€ŸCf•ÙZÂPÿ5üã\€'úö¦ì>®ë“l*u×L*"[½ÕëÓaÝÕT&ÁaÇXBªU~tδã-.¬3 Ýý§û¬â{HÿIRiý &¨/~Ðõåw4ÔÛÍXßQÒ/{T¨ ”]9»f< UË,9 ôš‚눈üÜ£„¢ ·!ëî$ýÛEšdåÛ¤(ÿË5 ÄöÏ…~Þ´M4ºYd¹#¡þ3Y.Òi,rñƒ°‡¸ùm¼…HŠÜ6±ì:J¨¿µÍ¾“¯8dr˶¨¼ÝCžÎ€×)îZ þcL¹Uˆ‘;[ºdW[m4Kyó2™–¢³Ã˜+ªMf/_¤øZNζFúˆ—À@ v/éڮ暆˜L¾ÃÒê§;4MßOwºÝO¥«h+gîøf_ÝÞ}=É:ã;ëŒpv6Ë£i\NP»f?n¯Q÷³^NcHȦÙÑ©ˆý§2|êLaXÞöT„åCHXpxÿ•ýC½1˜L~GÉK]Hío Õ}ä¾Î.˱F(ݤ³\£i‡è¢3;¢kβã?âÕÖ§ª#£t¿U9Ø/rÏŠþåô§¶CÑãˆíÎα£d¯„B{åP˜]4cø¾(òBëCÏ•â[îgo–¯ÙÃSÞÉRh¿:?a »~?YNϱsSµ®F}›%³«ÊYéûÕ1Gz²ÎN•¯¢N,ðAe¸ÃÓ këØ2ZXùöCŸñ$ I&ˆÊ@b‹t4­-¼ Ä#Œð~ƒm •{â7ÖžŠ§&2CR±±o>Pnãxc?(±± bÓ¸Ÿnè~]>%^H wÉI’}¡e~!Iînh0û÷Ç+iíÉøÌö–ˆé=ÝZ×jz¡Zæš¹P-ï¨å?[ª~Ñ€¯)õ}€†*Ä<FÖšV%X†-?Xì`KJDI;q»§H;óù| ¤£ $XF`I_S–e` ¨DbÅ3\‚,ŠÊœ,U·©ïÂK¥‰„§CnžÅLW÷À2 J ¦múÊÉ;ÿ@{:Ëråa "Sf@%‘FH”G¼+Ë%.oÎmܶͷ,òå<ÍfÛmyõ™·!$`èZÜ!º ÝĘî3$-{N&ßÑnu{’~d¸nû0g¹­Îpd}7þù£WÅóÚ7‘Ƶø>4½Hm¼7„‰ºAOVÍž c¶uù™Õç¾|µUÚNæ§dµJóŒíŠ-¬íÕöo)ÂÛ¢z~ee/^¾:€Á½|ÙŸ ·ºUÇAV¶Oy9"e„Ø„MÆ«Q_ç8ž§ä›ã1GZᾉ˜b2ö›@¸obN8^Ê;v–•ëb(Šß¿­³éÇ’*À(dœ¤´ 6侂ªÊ˜OXÆt౓\^úúȽ+ïe+º{)³¶5üLjŠ9°1¡Œˆ$"}ƒ(IØjF=¤ó#ӑŹÍÅÛSˆU’] X;Ÿt„q%.û55KVÓ@4"2Ⱥþ[AzÌX[aÙ¹¶I3Ç”Ÿ8g”t:XU_¬º\ÉÍ;B*­9\+K*`û°p䔕¥ëévð08± u$ܪ ‚}ïO.Øž®1B#о[8yb ÓUá¹cÛŒÌ"zŸªJ*J]ë÷0(Í4žÞ%eþ%ÉDÍøªµ·¬µÏ¬5™(,æöˆ ’šŽÕÇw<°‘«ØÛïCž±œ5ƒì@­Æ %èm²³Ã& …lAœÿrY`t}t€Ðð­×Þy^ïÓ³i¿´H²²,ï0ݲi¡·÷‰¹éžçY ÁÜ\äUXÁoúõk|“Fó¼˜&3dÐõÂ=*†lðG1”ËLÀ”­œ“•¨l–O´ÎÓ À¡ÜJ‡îÛ”€–,Ì'l3™|ÇZ«Õu7hWJ×J%uMcÿM·õjZ@Í î¾p¶ þ‚ q™ß§Óè1/w€ˆ?´ÞìûÅ1(GÒŸ‡Õ’éïì§ë&Ïûï!ÑGöïÜDuÕhòÞ]L5Åcè¤Z±”y²Yÿ¸­èU ŠÚž5Ÿ¯"§xØ:A°ÂLG-ù¬Pì$˜´ŽñÉãÜÔ”jÓ ðtl2«(-ËnÄ£MiXE™æ+ ¤J9 ¤ð€L\”àãè÷è~uK‡@¶[¨C.…ÖvUN&ó8]Tï<¹ÑžÔPè3­•í6Põô›ªÕÝ ¤!º;!‡ÔÑÝã]$ÛE……ÁpT¸¢†ç:fÊÉä;Þ¼­žOý Úsw<“ëùõçê9w›”ÌʯÀ¾Ýì¾Õ ÐB4‘ ÔMT•Ÿ4=Xô~´©§{ÞÍO¢É Ë iTEôLµ‚•÷ž‡BXÞO+@ÊÖ¢áî¢ôB»hØðÒ+i9k|ÞÑ8ž <²–'“êžy0¢Ìr¢ŸJÓiþ»ëÇêÏÌÍ¿-â´\]?¾ÿÎ|ÿ€£y<}H9FCdŒ^ÐöNî9f«÷éÜÖEo«>?¿ºŠ>×ÝVõ½{ _]m û!>MîÖq9™×@·‘¥~k9nÚß i¤V‹®ÒEæáNŠ»Ìôäœ> Päè\xÌH°]£fà8žï8†oûF躦Zøet/[HÁ~«ÅdÙªCiئ‡Î8Ån¹(³üT5´<¾àP^†Ëj ËÍâ¢Ý¨P7©êP-#?g† _ š5Ú&l‰L["¡Œ‹`¨`…;wÔÉ")“‹\Í‘OêÁí²fõAZ·ÕåÉö0]ö‰Û®Ôú^669Œ¦…±û³S´ª¶Ò{HmÇa¹k`µL¦W@\ƘjílÛ—#«xoþêá´`´X&~HÜ÷R_s®©}$w Z4rÙ®gøcÈuxMéy®€p g}¥Ó㎼c¾dûÿ•L!ûÀó¶ã£CøJhÇõ±ˆ¹hyB~YójbmùáMXÚ5®y¯ ™ĉlgä†Ýð@k=rBôÁŽgŒä"ïù ‘_øÖ8ÕN4Í–x°Ç#Å“Ãö‘"CÄhÌžØkj5ÛwÑDQhàuÍŠŽÙ$Œß\äE®üAȘi§è‘›/êmº(¦©(ºY|™f¥¦rÞ5¹üÀë›P€]Û°g€¯@a:2,lÕ½ñ4M;žé'ô±åC4†›Æ«RáÇ„ÒAÀÅŒg¹¾ ѨPé—i¥_M^2ºÚ¯f»¨Õ„K-“9¦ vÌöY`X‰Žªœ ¼C¸<æ,YM£•ž‰6H㌠Àq¨:>o6Åá¦Ö;üü·Îb ù>B!õ‚Wû€w ªÎ$x×<ñ)ž†¼åOO§Õñ¥²xz¨›ÐràЫ…1Š*è'Cèï!;PA§K5ôîG³jhò*9.UùÔBù¤fµÐœ-©&Ʋ­îN3y’w×§Úä:RZí8:!¹u=C¨$^—wè„cSôS²Z¥yÆÐ«"ÅZŠ‹G 2Z¨~N¼2â­Ø,ƒ}ÿµ,byWîIzÖ¤.0(@ãÆzëQL9üqzÜ´Õ®ÿø+™^g•k«y®Å朩â°­>Ïúiô‰öÐö]*¨í4ûRêùò$¨šU¥XŒyU©¶)·P <ÅqHýã¦ÓÓƒv±:’˜°@àCÑ6\LA…ˆ{?çël•ÞfÉìª:ip9/\u3YÊË5=tŒ@äXó!õ\ûùfÅW/µ½C\ÅsVhbÂi¾ŠnªÆDÊævmÔ¿*«G„žÛ„š–ÖÃâ0/,Ë¥ª–#,—“X/·*Q¼¸ÍÁ‹–­@ýŸ»˜\ÿS§»!ŽEó÷hu³ž‹ŽlµñÀ÷„ÄäPC¡à3ÖfýÏ›î†6›Çé"™ÑY­&é1Ú gIëîÚêÚWË6båüq™à:üÚ~ÈM&šþ%Êÿò‹‚M€ìðüȊÔŒÕ ‚7®íaý·!¹´õÁm<¯›ˆâSèЊš¹P>`vÏE'¶IøÝB(j‡ío“AØižšE- RvW@ÃZñà‚xƒÛÛO†Ðöຎ ;ú.6ÖŽ'j9Èð~,òå<Ívz›5¹ Á?"{írݲs×üº¼p ù¤fC{SN&ß1vmuvÑ@ÝY8±ïG)½PMó£à=jÙ^ZÉôBš^“ž!‡(êMQ¦ótšÆ Á§‚5ÀÝ5Ò€ƒ«†[3W í+Ç3T„0ª~ŬŽd³êGKµaÀ‰ú¦<<%•b–1—ÌïcNyþà@Qc¯D€¯ÚU bûX²äžilk×]ajݘžuá5o›ü×%—˜.eP|0Ÿ šÐqñJ4èëÊ ú^¾|y%h€>[h«Ê^š* Õ´C Ü]MH¬4~øB#4Øì)g/®ê(ÛÛ¯M· oÕt×Á 6pÕ/ö]4P%²®l=“ `À­#Àº³XNþ´r‚°ñF0À‰<¢êf1¨,º|X–ØbÌ]kàÒ¬¬o ’¥Àȶ ²y™LKQ êÆú=ZÉ4]ŽšÎF÷6³‚ ”o³Àè$V Žþ˜„Àf7´-éhôjwÿ`FcwË4Eh:ËBkàL$fîlC›3ò1•t[gƒŠÏG`²½³AíÕ_¸¸³fÙÇ"¾€T:äíå‰l0œ½]úØ ñÜél”³+•m3 è³³ ml¶/.ªëbõ¶0BÛÙ†6·Yå~,nâéºÒq! *”Í€ ’Î6´±óö£ÿÔOg£{›Ù,|-ÛfL{úجvô Þi|Õ°ïšÒFÀ­ÏµVo4–n¤ aYB,ðG1ô| ® XšYÌÃ)pòQÏ’_¯E:òl“V/Ýøsê^NÏ?•Á®yuÔuPVšÌ7ÁšHÇZâjxÄbLU[iQ®wxk¡Æ†<ÇøìÍ–ô“ºà%.™›#­ÑenäÝ{ÕÑ”N£íÂyýÈjP£¯¬º…©iPÙÊ1l'û¢¾ÐÕÂÖßÖ´.ÆÓ½lÚ•ýXý‘¹1H§åêú‘ÑÿÓ;Íý½­züüê*ú\wÊ:7ä««úÃÜøž¶êš€·›üwl£t¶+Á ÇóÇðmß]—A#ЋÃétÚþ†%9á*\l^ßŶ³ÅdRêÁˆ2ˉ>ôÜ;óýv|~ße&2>?¾Î¥€ÊyyëÃ#~D½u (éhK:ˆFðþõf!V/:< Á:[—Pc™&`lC~Œqô+Áãýº|rÅ[™ît(2ìl³¼Š4Îè$‚æÒòQš¥hºˆm£dä–Ï—ByL?åÌé²x–'?[>zl i¶Æ3×Ù ŸuuEXŸ).…Ò^[šH:lƒ© OþCáQ¶ätó!¼žìÈsõ˜Ò-êìAÑ.QçÝg4Š:ŸåÞ/þ£ÁUng X=¤V:ºÓYõðiGb©Ê¢w–f?©—õËE–[Ò*Å0Ñu‘èL}êYž|©'?û‹<»ÅóঙŒ—Çs¡Ad¢â…ØÂòˆ®8îñ4óZï×Q øæû„¶lÖîúiüL8»=viasNœ €¦w§óÆ­ÑVpJnFÁÂBÒXÃYŽW#ÞñÔU'ëû¯Éô×þd¢¦Quœ7&škEžPoAÚbÓØ*Tgx2.Buç¢K2 .z'Rú|½;ÒÐ`öŸ’Ÿš"r©ÒyéE:o×ÌE:¯HRðN¯úUþÄëfÒ–ÎÅË® ˜1 AžŽ$+¢Œ¨^:Ïóa;‘â•ô*K~ëÉæ©§íÓ]ñqè÷}hΦ 5}¬3Á9÷¢e¹X%Ë…î´½}OX¡zXnTB¾KI™<©BÏ÷/R…Èͤ Hîî`Åÿ{r‘*<öIͤ ÷¦œL¾cìÚêì¤T!ug½¤ ÷ý(•*ô€g+ Ï$%9d:üÔª¥íü÷ÇWà¶-^qÎj”˜Æ;µ™ˆ7î~ ‘™ë$Ó×= L´Z €–6[<ã3¢Îj€¢¢íXÍžˆÁj)-á“h#[¤µøB ëîCû]Œi†€¢îŠðM1d ÁÛ|™&3˜3MÈâ!„ÑÌOI6ÛŒ_ý{’`}”Ñ2tÎ⥬¡«e çxõxbB[¯0x·Ý,9|·Ÿ«.n“’ÙWtk·úîñPtXW×>E¦Óìô½Ò2Є¹7›§zZTNb_…?Í{Sˆ á°N¿=`âu5´?CgQš‰±*ó ¾@56ÜDmfRó¹nŒ¯™6Ü1Ô¤Šƒ;¹Iˆ w5ÄOj‘L‰˜H?¯"e²¨y'{àæïjˆŸWáþðÊÅQ³*žQfVë_ͪ+R„vjûšáP˜zs ÷¾O¹’ê ·3Šƒ¹uWˆÙ†&@,‘ø k`=oØ·[ 혤?[•‹âú*´MYvÃΦd±x  c ÔZØz"u`¨9Ô[¤i*Ëêî8ví¿¯9s}ȳ·ùò ô¶ÆTHK3«aW´²‚+?Lí¼®é*ßycœù¸Ä¯”0ŽŽÓFiºo}h+eÍâ2ÆqþÙywÑÙ^tz TF¿Ÿ¾u¶Jo³dv¥-sï(@D ‘»ˆrz­¿ü—iÿ7*Û`@x“ž¾ú›¢ˆ¿ÑlÏÆ—²È#ØP`Æx³mÉzª«%+Ïû¶“¾m µãدêAÑl;FÜ¡Òbšhï`(Âmš~IàÈú;âû™g“|«ö‘͘Qìßw°˜¡áYôÝ&Ž ôžzØ“n0¢LèúÊkõ|4t]«ç<ò¡E Èvø‡¬McC@ŸçË‹LöÞtôR Ê«òY•UͬÎË®¹}ZŠ峇“H= 3µ¢H2(vjiˆn¨&·5»7Õ)*:ÞÐ+°K:™Ì “†Lf 9ŽËðØênCø*&˜‚Zk° ¾L ¹1ÜOŸÁSÔ¸3ÁQt»Ho¦Q‘¬’âAT€ŸéÀuEÔcTª ãLd‹4ÃBnw r¢ D¹H´yž&Èíl©y ç3:Q'Ò‹@Í-‰†Î0s»NEeB8ÜV(_RŠDîf˜©½%œZ'¡RT¨K3ÀÔFÑ2ž êÝ7”Є¤ËQS ¬rílc ›¬Ð=ä@ Õ:ÔܲQ²¹BÊ#ç– ôr¨¹½Y|!^Óõ…¤ÀÀÅ K=¤QQ „ò„xí1âk´bMJ*mÓw¡¦†Ã³6„&@Qa0 ²fŸ¥˜*Àxù®T¾†Ãc³¶a”E^èšÎ Ð|)h„±Rý‰·Ûdòáý>%«Ušg¿ÅÓ2/¾áq_Pš³aȧَ@nC!¢SðVâ@Å€,í© ¨Ø ‰ñV݄ѿ›Új€“·ÁrSu»ª¶\$˜²©²²¼Š üS©®¨O*\ !cq¥’8ËÅY-ÜjÐéWü}y,ŒB¿f|ÒòìPiŽ{a›†HäíÙêÃPš¬z“”ÉWA¹íFŒß³DBzX£ÑÀ41ZT¦÷I.*kßHˆ„²°6£Aèb³Ut³¤AQo2,ƒ&&›E¤×™åš†ØÑ8¨?t|Œ>2§HÞ£yÿùS? É÷Î"“Éw¸qZd£ì¨g[°ëD)³w`x*LìÀÁÆ©ë÷öºHEƒÔÿ,R`רR é+Ð- m@r‡é¶Î·¨ùÞnš¹Ò^v;y„˜àfË‚ý¯™ÎzHD9dÿ‘bføÜü¢ù(°EX–Çž~ýߤÑk™ž½9˜>Â8­ÞN«óP÷ÖGAÕäúQ(…ò–i!ôêŸÉ4I’MÚÆ C o!Q¢Ìtsdº>îCHÇFß4ì1Tä|\—Ï  ‡‰e Š6cùìbéPƒ~UÇÁVe‘f·› Wã~ú¥‚šŠ4ÐXÎùgbß© òÜc†|Ú"D&WÍl¸ÎXÁS/þLÊu±Ý^> dVðJÿmM?–4¡¦Ðò¤¼ Ç(¢µˆ#ÑCÂʺDÂ÷›6«ôÙ‰°ÐvåcX\Bawò4žÞ%eþ%Ʉݪªµ·¬µÏ¬5\&ôU± L[‡È1mÈB I[ר³€7AÉ,;ËÒê+ÄÕYTkß Äæ9™ˆÎ}WÓàÉ–ër?¤2¾Å£€«q»µ(ËmCàv¦©z‡pn «l¢eÎ J6A_ªÞ¶˜YÿYÝåøäÕ¬øcí¼Ø>0ÕÐ\Ò9JKõ‹d‡M.³+º\î Yž·ù2Mfõ0MÔž%˜¬¯ ¸2$ufQ¼¨N}t r¿¿ø¸ME¦H4ôýWMëM&ßá–lõÓ²¢ïǶúôóxà,kõp*ö© ŸzQ˜ ¡Ôñ$OEË4ˆ†Ú É(ªA“Q|Syñ´¬_<{1/£ò¡‰¢AP2cæè°(ƒB¦d ƒ†xå)5‰…Ð!‘˜ÏçÏE"±æO’þ4ú«]ÉZ· êiùš¬çi8e%ýL»±ˆ¯«?27©å®ß¿ÔÇ5û>©TÃoèmÕãçWW[M‚_kùšŽ½õjÈâÆ÷´ë®ÁÁæ(OêÜŒf”În)ŽãùŽcø¶o„®kz†^NgFøoD³AWájóú®¶}Ö¯Õƒe–}è7¸wæûìøü¾ëLd|~|kÅgC°Xq² Y–ÁÛ¨%ÂÏ6`l4A‰i¹í–ÊÑZ.ûÝ›ïyLdi.¾$@§³³½’OÈ¿šf'ó—󼸳iò..c´·¦ª…”E¢Ð7ç®æ.P#:ÁØ™.õ Œ„X´º¢Þ …Dn‡°äž}M_ÂRû¦Ù•ã°%Çž§é.tÐÔy\A£3jY¸æ Õ±Çhà"wsºQ:ÊXSw³PXÅñ˜Žàù*‚X®ã Qm¸ÖÀnÍg7dãsöÍ_×ÿýöµÙH‰y{xÌâ‡ÊžeÙ_¾ªÎýW,X´]ÿýsÃ/q.$0îÕ刼¹E$e6<’ÎRñ%(êkø/áûB_þÙþï_ž\ï=çAÌÒç GE€ÛõÐBdTúQXúd2ÓźHô/-p\´&`á¶Íè‹À¡¢<н#oGÏ5„»¾‹}JÏiVðòsLPyÀÜ[Ù…¶é7'À2¶a|ÒDÀþOÚ•|•Eš­Ò)ÉÊwMC…\€m€2HIu·uï-nÝk¶³x¡íºwM ž5‰{åÙh¦ëÊì M@«ËØÊE¤Ty\ ›ÊAãYm·ì¡)eýoÿ¶¹| ¨HŽR;Ô«‹6]ˆ֡ÎiJ`kËp¹E+r¹2E€È½z< W±ö)ºÉóE¼XÞõÏ(w7ú/ÖOÐ2|Kê° Y™%Sºù°äÏIÈ®1#«»üqÉîoÁ æÆB1,Gzí…I ì˜A`JsÍ ¤/ JLÝ­4§æKº|¤œÇ=3CÁÔœ™u–– Çî6¹© ÌPä¬ÁN ½Pkj–ˤ˜2òÂÃÆ³§ 1¨»•Æìijÿw½*çi²¬oίb[eRº[i:4Õ²¡ž_ÅÂÆ)º[iLÍ|‘ÇäëÆòP…‘»ääP³4'‡½æ÷å|ß®¢$£œ"Ïeé“Dãm®Ÿô«0í“K÷‹ .ñæŒÜ%ý±´ÝÍñ×·ôù ¸¹[›hU$|LŠlܬÜØÍYY$sÑ‚nFlùïI‚[º9#ù”pB<ù ÁÝÜœ"½½#œ1| nN®äÖÓqš2pæ<¥ŒÅ¸òÏXJ»»ƒpÃð눟×:TÀÅÂ$Ùú~C']W¾Úo[_Mvp•º_&2îÈç¹4=YCÉs©%ľFÝbÓͺâuù„s4‡Í£"èYHH<‚@"7ìÞdŽ‘Ç»—H¤Ó°¼ÒCJ§é‰{ åC.k¹ö±™c= ”c€Ž Ðá¬ãçÁ£-I'H ]½`´ õôa\[iQ®ãEÝž)ÔØ‰E!µNŽó°Ù.PÓîÖè ¦²Ñ;ÖÚ}•“ƒþX¤q¹ù¤‰9VA‚‘£K]³™¾ä­»ZØF»ƒ„áóáDßw»èhº‘ßfäz÷ ˜fT<¾BïxczÇ"•Îè¼ãÏÙ\ãn ¤çƒŠ³Ÿìøù¨®C]Lù^°9„¬…ß*ºñôÒÿÔT[¦tÈLÛ äWê¾öª·ßÛÝÎýº|r¶›j~ž.D)_8}ÓÂä¢,?ú®[>J³”NðÖ´<÷R¶ksˆc‘Åêl”ƒÑÛŽˆ”Ð¥&¬«†Í¦ ÌPwƒœ¨tµÉ.a»6‡°W¶¾–kºSÑ7 ùû¡*˜ÅnB‹…B¬¡Ò#º,u¥S4WïB¤K4÷X ÄUHçp¼lÙ oîö}hólhXѸNãÖçmÀú”Ö•Åê@<†c‹;4×Ù*½Í’ÙU½‰û~žCœöþ xwv¶l '!–à‘^;IS´°ç9@¿ŒF@Ú À)<!DÚ´- ýîúO”íH¤=_0ê`ò§ùòhÖyR1(nÁr º»¥½³–f3ažo*íh…ífvš¯E…Ï,Iàx¾Œ›ä6ÍèFº’t 0³‹êÙ ñ:›S;µ$¡Ó¦¶zJd«yRÂ!¢ýüZeëëp‚ß<ÐÑ‹)™`’Ðä€|]ùû1áÕ&:ÉR¢‰ÛWÖǤ˜çÅ}œM“ßãâKÒ%ÛŽ(Ö ¢êWP›XI<ÂGëØ¤D;Üü¬L¾–XOßxúÇô¥ßn†ðþër‘òLc?gÅæ7‹ëÛ„¿›·ÿ]Y.‹ä­+×fþc†üðþnÔ³É `Å¥$ÖC>Ò ¬·5Û?ª–vfCW áNOºú#V˜.?>Yõ`5-ˆ×µ¸žOv´Bl¤rH3¢¬h¯2LÀYI-'€_¤#Ö|—ç_`a掓´jã5÷ëOI6Ûôô«¦"#>Ÿ9ðL£¿_©ˆo— R½3}+…÷p\d‰üŠå/oç3ëM‹ý$m þIDià›žr ºýðá‘®åQ(z³¦¨ÊJ0h—þq¥Æ:ÝLGóê!ZBªK3&ÔÿƒBI3h],¬…ª»-òõ²Ú´¢rI_jŒ 7’$ÐÈp‹G¦8Z±sŽlžý@$àˆžg ]Œ98´Õ˜ì¸ÌïW‘hfŸhßB!²ìLS,i²•ƒy^°ƒX*|EXY‚ži‚1Ý<7§y½J†8¢'9Ï ãá.²X'õͲeBnr–)|ÃnÂÝ?‹› …<Ô<ÏãÅêy,f‚4òà“ü,V3T¥WלêY2MïãE´dÁ6Â5͘)åO5%Ä@îFy—¯Wq6[E«€înYùD1ôÝ µ¦7•\´‘ð¡2l §*ŒX=ßrM™Œõô.³¡ •·”œÕœQ«_¡ Ï †FÞwlà¹HA5¸–a}UV÷Qœ"4ùìó¯¹Èù+î׿£è¨ˆøy«ÀÇ1UFS†™|á $:›y°— I:ÀØÎM7;î¶|êÿ2íÿÆdŒ˜Š"gô¦(âo4Y#猙ìÖ\‡ýËù­±-ìêýY.[bõ6.gÛ(J³¼¿ò& ˆ¬;gPVG'# 8¦ <ZÍÒ"º«^ס܂@þaf›6@9€·b–<¢sç7ñlT×ÈðrÑë—HM ” L>Ÿã4`P¥”y*ð‚‰Àý\0Ç?N‹‰$]AD\}ú§FDçéÁCØ"]ð'›½à!š ]ð'6S¯û%xC.`ˆ£­ª^Ë,ôgXÒûo $„¡ûqºeÅÓL‹‚ æa0"µ½ï3@³îjŠ~¨q²Â¬þ!ôlÆJþAugàÁÖ8N/¾-sŒåIóUtSµ…ËmX.^0{×ód2¿/ç‹ø@IÝ¥’½kÅ-¤%«Ušg×Ù<ßRƾÚþ͹Fø¶¨\ó¬LãÅËWû²ìôëû¢È‹—/yU7ùC_¡ƒÍís¹ë™ù!¯b¶™lÇ.| W“žÞ¢‡åÊìó«e2íM÷.Xe!{?m!Û0€B£$|'6 Ódš?BÌÖeobƒ8J «ÿúº‚SÃ6€E^$œLdD*ʪÿó¶jîš-þ¬º4¤…t Õ*b#òh2~;@¹„-Ø6®¡xÛ°`0q¡¶e¾J¿¢EÚù²Ö–ûÈÆ°Ûqè¸úTÚlÆUaDk¯ÿ•sNkï™XÐDZ­¹Æ! ŒÈéìin@ìIнÿÌ DâY‡‘ÛÓÓm±ñ|m¶éŒ7¨H[]³a‰ÃkAáÔöè* lÃÁ2Y¡ÝOÇ{@ îσý·½QjP&Ez9¨ZIK:‚ÇÁ–~PËwéøTp±~&~‡©7—v:k¶áË~ˆ‡Øw8Ë»¤Ù@  ´H%nÞäÙÌçsÁæÜ(¡– YCZK°Z¶i-X%}wƒ{{¹¶…²’ªúfšWgÇëííE÷7õ4@a…¨C„ï}šk¿QMÚž 1-ćûÛrÄ£3‘mµ¬À‡!CEËð«å¸@¶z°À›Ý¶] ¬õDcdÂaò•æ‹xµym Q<b²Ö²Ÿæ‹;Ýn¾±£Oº 8-…ÀÇøLÔL=ü-[s€)ÿës|³ØìOSþâçê »b/ê¿ÿýï¿üˆ‘·šÛµÚëZÕÑÛÊ4ŸL¾ /÷Ö,Gý¶QácØw>Ë£i~¿Œ ‚~N{í·,âl5Ï‹{‚žPÏwñêN¼ÓÎ>þé*úŸŸ¯?•¦Ó4ëõã{\§ç pÖÍŽh{6Àïi1+—ëfÝÿ‘Üí»=µódëj9Ô¿¨©©#ôãÌhy-y9fÔ¯ÂæR®ù,ˆŒ¬,óé¹õ<ôëW‰Š€ ¡§U¼åBnŸ¢Û<ŸÝ¤~NnbÚ)Ñ]B š’$Ÿ“N‰|jJ$G›S2Ó霈¯ãæ„@#´9'ìÝâF‰(6€ŸÏu…¨/eKND×ÕL\‹Scîo¥*¶å£¤ñÐnÏCÄoCÏ9(mÛ¾ÎWú{Ͷ&¬0¶F-'É;ä<äTcË@UQŠb5Ç4!p ¢ƒÓLú×©Õ C ¤"(+ 0¨‘䢩@‰X( Œ'§uO»Šþ&Ò>obø†46ú›¼ FòMüþ+B½%ô÷*Çi…CxŽÂk`¨IS;ʰ­‰_p ù¨³Wz€öU®å‘ìJ|„fð7€ FQ…Ò€Jæe2-ᇾx»j€%§ÑÎF›ì']!†åŽW?ïŠæŸ6sÏôþ‘Ÿ9ĬÈÌ Ñë"3ˆŒ¿íX14Æv”âd‚c7ooìŽíõ¹ÓàØ:8{¹Ú{6é¿Wóv¹×61>X,p¡·@€‰ò¶ë}Õ v‹¸çÅzâ`§j/û@¾´eÈD0½î„–Ð;Ë´×_i?eël•ÞfÉìju—»þîgë:cÙªU:¥à±s€4M áÀDVéQ­ðIÁÏ8›&ïâ2Ö6cîžzW×4°äòµ·)ó%s5(A7¦|ó¸ú”L‹¤ü䔦W<§@¦Qåh¥àMƒv6_XMú¼–Ÿî…:$Æ®µ+.VÅÖ ¬=/ÆÃ²,ÈhLÓÉåÛ¤1&ÏŒ(+NÜ`·Ž‰E¾;ø×8V݇Øî*õÞìÞ­y3{HWÉ›uÙ_a¦»ÉgTz¸™“Ol7դɗ ÄæÌüg³@1ÞÙ(U¢O¸.(Ûž´q=ýÕ>èüaµeLËoøèµˆ®­Ÿç%ÊÐÕýeˆj¸¿ÀMw{\œ!´´‰3l…:/q†#-HŒ3lM1™|‡¥ÕËÉ8Y/}â Û.TÆ,ÙT86ÓÚÃ_½ë"ÌQþ³Hµ•t€R#âþÏŒ¡/ǵHv'߯˧[L«£Y.2‹Ëx¹XvmrW¼í =¸¥\ñG”dSr@ #)&ÄÊ"àÞxF4g°tò?òbÔÞÝ ÛNî1ï%”véÙÅáú0~:UU ®gTH_ÑaD®T1Ì«Wb‹ÌÀ‡dYZ;$[ß/×Ù´¼p|ã~.EŠý$3´—õ¾˜@|Á·Fq¢¢Aâ(N”5ìúj`ýgÉ4½Ñ’å™­eìì¾¼Ë׫8›­¢U²´ ±³ûÛ"_/™¯-ܳ{~ ¶J;Ö Å½óë®Ñó<^¬ˆº>Såá¶V·âšNx©ä…Ìcó£Y9ç…ÌcÓè…ÌãìGÐþò®nîRî iæRîÛ³‰1Ðx ]àKÞ奤W]Iïo‡ÚR^'€/‘”òº> ÷¡'гü¶®”ZÜßrúGå%J†"Š+[£¯õ¥žiÊ”oj\ïúRׄÁhÔXM$„"ù:M–eš÷sµ½ð§4=D],€¢?”¿UŠ`Aoåîâ™¶T±îÍ{ŸÏ@bA 0eÖ žÌºÄ™6?š%Ü< )ÿÄ™DE8 ºè’¸BÅrÃKO‘ûKØÌ%ÛûGA¶#õ)%ó:H¿—\ë%×:’\k°ë^qŽÕõLà9®qæy6w¼± â¬×Ï Î.™4H3—LZÏ&ƈ5,³&kbžÏ` ·nÏ`Y·Ó>X·h‡G¬[¼·3(yð¬LmÊÑõ€U‹DäHžçbYuPV§É²ãʆy0ÇP¼¢ÆA2AoéxPeFˆJº¬*;áÂòÊ‹aÜ[\ŒM¶8†Õ?@ܰ,S'¿©ÚÂ×öݶ6ô®çÉ$_&ˈTMíÛÓ2“ã2Ð$oóešÌêõ.£%\-N8 FP=§ÈïÑò1/3!TZ¼ `†™Û”vnÇO×Ò:I£ÿ¬¾?€…úao!9FM e! ¾È7­þ¸”6Øa=$Ó2/D|ãM ¯¹ä_ÁÈ¢0B5îJþ{ųÝ1ýô|«x&Ö§ÕÉAñ:"ÏÖAÉðìO»ö¸;Ô „nÑçæ¡Ìéøä,ו?µ¦û©„•:[j:Ù,éÏ9×Ý G®(T"†›\9”¡&·HæÓ|Ñ ¦å:Ú¹×oãÅâ&ž~‰)D߉ÚÍd‡q³m´¸`ä"µ/-2 $¾¿YÏQáK ¾lplmºŠYO&›_°ï&´†Žu gÌ•Í/å˜2jº™øj CüÌÎÕQµÁ­‹(š²UQ/ ¨Ä˜Ê ûjyPföXK\ø@ìµWµõå:^lÒß’Ýœì|º‰=cë. Ô5¢T»ÃåE ®ÝÆA!Œõ{tK›þ´‚ Ô#ý¹lovº©+àr.b1›Ï 3Ľ?H&£gzkäÆ:¼Ù½:Ó_°ížˆÏ47Äæ%ýê*ú\Äi¹bÑšÃóêjãèÕ^zýï6é ûÚ>ÊÅøvá3pÏw÷}#t]Ó3 ´±»ã8ƒ(¥7ìŽÐˆ¯ž!˜Žãt2©º{0¢Ìr¢ŸÒwæûlÇ~ßeÑÙ±ï¸Ó2¨”‰¾£ÈTO $>%‡:ÑtÎVÓÜs(5à˜š×QµÙ6ˆØË_Ô€€wÿóÕeØ$ ÓV5­þe­2Ë/TÇa|X³›šEÂé=wßÀØõvï…BŽ=^€{”Ñ*™Šµ¶Xº"°ZL€ 0Ьf„Óê‰`íÁï·¾vhœDÅzZ^±M¸ZöÿÞ¨â=î¸úTwÛkjÎV *[¸ÃÆÍÕ:[¥·Y2»ZäÙmýˆéêHîgë:c×Cuç“L˜ç(I€¬X]6r­§ˆ¤Îi“:C¬Àž¶k&¡©&Ó‡f¿Èv¥3|ö)Ì:/¬d/‚`¹óÑúîG,ÉàM*˜Žv,(”åXKThvY äxÁ–-ìýͽC¼PûSϯ·•ú“‚©eÅÙ4ù=.¾$òÓ\€õ6¾$×±YÔ(ñE*¿T±Y! ;zÀv1Í—ß@$<† ÇsÀŒQÿçmÕ{cÑì*lÑ{¯Ýº´@*e-d`H¯…´ ä\„œ)‡ ãÏM[õ ·Ò¹ 2‚Ìðù ×Ã6`ÙŸÅÉnpñƒŽ~F©ÕHôm'tpuqV—±¦×˧ÊÊãâwß ßB üÝñƆ¹½ï/™æÈ´8îë“N—UC<Æb`nt© $ÏŸFö"Á“¤›HZ˜®‘ó -&(°`'4.úÚ²Á<]$ØÄù( óA9ò R Š:›Ó‘¯EHùãÓ>!pÝæ„”Eõn§›[þ{«w·ÑÜ2Õåš/“ì>Ÿ%Q’‰’ér³ã¹Œ)B`‚ÀÅÖÖÏ“:0]WSñÇv*äÔ¾ê)¾¯ÆNQ¨|:,•^ïGi;ëÚH˜˜7h‡oð¨²ë*I¾ÌÒþ|Üä’®ªå7«ƒæIV¬XG…KÖ’U…oóešÌ Á…Ž7pšÍsÚ@¡kVËYL§Ê‚C\ôWW6êÙ)ѳ½ùj®h°-[=dÒ&íé$'ö¾§Ç»ëEŸÑ¸2}?(+ îãM¢[”&°üg¥éÈÌSáh r˜Ã€h6ys™ÞZZx$™^½S¼ŽáË«)†®e h0hGŽm„g?Ã/¸+©¤Øàí¶%®*Úƒ(ª-^9d2.iÆ#¯¿Ÿ0ï5 Wæõ'Õk Íj‡/òªzisqüž”%µÍ»ÑCÈçsÙ‘ÕìQÕÝ€Nè¡@®…åÞ ÕQh ¡Ù«xjNÛA…fÈÀAŽ ËluÏFžÊÃÙ²rÜ¢åºä¬©e}§cZ0i(à|ãà l Ðð‚2 È#@!y: ¼yÛ_­Ï®VµŸŠòJAÇ_õA¦< Óse;áºð­Àb‘ÁHâh$ÃôÖ[» fyô˜Î42à…ivt–ÅE‘?â{³:çj¨ÞŽÇu;”Éä;ÿçè~ODyí÷DÌ·crSÀ.iu䀬(ÒQgŒùXG«iœ‰ôÖ­€x²·,GƒPN #vtWæëå2A«$ŸRC ·3¹‹_ï×ï±â’UG ¥Xæ‹üQäkÖ£ho!h=nîÔ=K13--ÁƒFÿ[®/¨×"˜g°3õ)YÞüBm½²hùiÖ´< *Œ‚ȱû‹)Œ5º¿MÞчö¡©»QÅõMàSlˆ²ØëÍ{EÉAŽß÷^g;ˆóaY¢oÐmk{åBÓ4ä#Ÿ)  ä%šl˜ë÷(Í¢›¤·ˆà‘÷&smK>6›¢–aP“Ñí¯Ú`Ó5ÝSb0Šb &ŽeWl0Šrm –¯KýÏDŠz­,¦ý¡HQN£•Å´? ýúX¬zE›ç2Ñ,[$±*§(‹Ëì?½ j"tާµºPÍ!Òš\%¡Þ]yĉ|d{Go+£|~u}.â´\ý:™,™‚á7Óm2ØÍt"}~dël6èÍt"íÝcp}†ñûz}æ\ò HÍfT;„/Ë¢ïÓV~´çqÈó6 O‰wf/[í¢ðïÊ‹Xb‚D€ÊtF€¯­¦3ØÝ‘%€Í¡cÐ%eCÙU^ S Quâ…ß07±ê(ÅS7Þfëhúõ+«3‰‹|º»;OüÍö»¸kuZÉMšUÆÏË»„ý~¹ÝBhè ñˆÐ”zŽh ( rE8œ ]¬ØAkŒ§u{ã¸åWu­VÕÎב;Ô‚Ò)*gòCÈyp´©¶œ)€àO•3AÁtDµL0Øìs)eÎ\ê˜Íõ-¿Ù¾óäÖÞvz¶ðfÛAaÅÙÒ®Î;ð]‰U:œ­¼¡ëêlÕ;+±Êº³7Tjm¦CÖÚì¿‘`åÞÙ:›ƒžPç2‰;oøº…üC¢u/‡õ|Ý ]•MåË*,ÃA‹Pü4t¼x´ÕTè¸11e&p<àjråË*9V`ŒGvw l‚ÈúÊÓ9–‹å&ƒ¤0xcdÉã&ÂÃ"’|<Å^ÅÅøcx½Õ\ú˜󼸳iò{\|øŽ‡N Hwl.5×Q„ù¡•¦¸m%Æúí6MìN Öoþ<~Âþ»öýqpèü–.’ëlž_³Ìóx^JGî>‡óæp´ÇÇ“+¬mÃË‘¼¸ÀËÛ´ž„S‹¦$läû«Àq«áCž½Í—ßX龃 ¦ û{ñg-e 1"BáV ‚¸º×‹Lâ¦#% ¯§T¾)m›)PÒ”(KZÊÅn­ÏGŠ‘Ø®¯€læiŒþ’‹³…`íöSø§3–¥8|H¿‹ËxCÑûÓ+ö¯^öϾ¼ôÛIÜv¾¶ÒõDDVq±$ì)ü·pDø_…©¼ø3)×ÅvÔcDA®¿UnïÇ’äj…²„Ó¸4œŸ‡nèV~É6È倦|½qW<ë(9:¼+$í¾¹Y[äY_N Ä"HôÝF ô§ Fó@`Àæ1'Õýr!ØúãW~݈¾þU/œZÙe€Œ 2v pôǼüÑ“%¶)_WÅò|¤ðN}ÓOóå7Á þÀêzÖ"ÙÀw.>ÓŹi¡L>o¢…ó´zé2W˜ ¹È3@q¯Ëµ[.Òi\¨èã²nIu ¡mcŸÆhÐLùC:`N-?"ù,Xù&N—[ïöu‘b-nú}¦þî…2—µÑäAÛ¨b‹MÊÆšE”Ær=ÛýÓd{ºþ³Hå¨ÈЊæ^Õ{3L&ß!ÆhµÞ]qCÕú©â†nÝ‹]5ÿ^ĸíj{TXMÂúr]•q¹^¡«ƒM\ÿç}Q亾„\ % QÞH„¤ÿÝ©E¥sگΤ*0¦í‚Æ&ƒ«+ ¢žO€ Ç ÇS­€àLšÂöäDð8't HÍYKº©ŸxÔÒì—V²4Í+QX÷wœºãP ~8úg[“€¯Z8;î†m'º ‘i]šSI—©];^H­¦=J—RW?ı|te·Ðã ÀdX²ÞŠ:¿ ÏD¿ ÐÚ”ž ùÞ„À$Þ˜I¶¾¿jÁ“мÌ+7s2Ùý U—ˆ¤4m¨f“Öl_ãÛ¤ºžµ.^—'á­æ«ƒóÍÍVïÿr~ë')ª‡x±NÄ_<ê’CùzâæC#­N¬°1â2JÜ|XZj6惌ۖ´s㹬„gì¿Ú…Øà ¯«™ø´™ Ù¨Aðûjè$:×ASnánø{²Lý°+MÂYoóešÌêaö'Ççïæ;1<îöï(> ¡Ì¢i © Ù@·ÈØ<‘SžY¾¼a¼Z^hÇV/'ÅÈz9)O´ëåñ.Fwpš}0Øu¢.?ï2Ô0òˆ¯êôl[0—$þ<< ÂÓ¾°Ó `¦¤@Ûž 8ìE_˜-|¯·ñbÁ´ô¢Eª«†‡~äKK zP2Ïc-éàCQœ:¼WdBtÔE´QÊF;|Œé¦³å}ÖÑr­çí%6\îÔÎv†ÛGù:8¶å¹ZF˜4³™ÁüÀ“¯#NÔ`ý“jí4 &Äž¾mpo¯ p…°({øÃÚË"´×MŠ}lîšÛ[+ |ù И>¾Çã}¼"¼¾Œ ò9¤D¼9¡0‹<Á§í@(`À=#¬¬ßNµF…ôúF8s*({iA}’êUxN¥Ñ—ûU¹Çç4J(;;§Z³ïë»ÈËí¬¨YGg…Œ³—ô©šýœU1¢ê眎L£ŸÕ4Î:;+btØY–£ãîguŒ½‰iA×2¢ììtFÁ­;¼~D–½óˈèMW2¢ìì„rúÑS]UZ¦N(Àíy¶£&}$1£+v3—Öw-ola}ÜËÓò¨!Bœžz¥'ú+!2©mBïQ|³*‹xZn(Õ”=!,—wÞî3—wÞ¶½j5£åºH¢‡´(×1–ñØãްƒîaÇ}¦îM½­–ïgöÔ":Z:ñØS3 îG!ºƒ„íwºàtíw¿ûèÚï~éѵßý¸£kÿô{Î2;W-ýð ¼ ºŸqí«{»9*ˆ6l×3ä«Þöz»iÊÑàAùýh°‘¡‡­Œ¤7ãóP¼ð€²€ÀHϰŒ®›:ÿ4=ä:™ª6¸ VUf­ŽÈ²Ö–Ò—€ß’R‰SйV€QÖ–· oKMQ¯@ü9ÅÞtm4h¹rÂ’ø^Ô–›VPÌÂÕ'tû]T*bÔ!€è\â©m€:Ä—€ˆø«žà—gGMU¤-$,néôŽºqSÎ&¹÷6Ô¢„l‘³S+Cà@Î9ªÞû):œoõ‹òŠò5[æ^ùœÜ/5ß& Nq¿@.¸ÐRs9÷¦jéÚõ]Íb M€µ|nNñ/!äRÎ’ÇHPÜEÉFÑm¶Ž¦_¿V§•ÅzJóÐ €ÄÕD2+Ú—û=æéI{\ỿ®@ZÛ˳]mWê´è;é"½ií¤ôJà “ÉwœZ=ž”c¤Ç-¦ÝèI¡ZK*` ,/Bë–fº‡X‘–Uí¡\íµZ6˜ê“Å =“)ZasC5ÖkšMÛ$JrÛ0¼®-ƒ™ýy—áïÌÆ3³w˜¿ñʼÏgIÔÛ¦2D¤,äY“¢Ézú±øÇ‚oPþ£m P¬]·KUL …ÏÄègì&GjÑÛ¨}Ǫ»}ÝT㕼_L¥9 ?Z´$4døp£TºÕ‡Ó%Àr¬µç``j×hiÎ][œŠC“ÊžXnª&¶ò–Ø'õ®5^Ø×šZ¹q¦Í­$=Âä\ÈŠâ=µ)êHÌ(­^ÎD•ˆzéIò·]( !…†§"Y³ñ$¶Tœ+áèEÏ9Dô?Í¢›õ|Ž&YصÉ]{o¢1½+v “M®©ƒ2b+ÌzýÇ_Éôõr'ù—œf!}a#´ãq?ûÕá­Øš‹JvgÔ˜µW5óUýWõßô¯%|!øØ'yëS.¸ã…ä|¡“7Å~ ‚—AÃ7ľü³ýÏ¢?“r]dûSV–à·u6ýXÒdvB D£8¾ì®,—Óxz—”ù—$Cã_NÕ±;ãÕHÞ²‘|f#yS‡›s¼Äðòæ°$Z )X{ØÓ<+“¯%M¶õí¦1½³­¡%=ÛêYÈÂ5 6m§oÊUJ5ðÁä¯Ê¸\¯¶ Bt¸ûòH½„»ë6~D<¡o»ã„Ü?tÓ¯ï‹Bž£rÂî­1™|G˜¦Õ×É€/q_}„ƾ•¡_Æý¯øâz>,>}´%Ý$¬‹ðB@!C œ²/½««¬åÀRžI}›1-,t¥t0 «¦ÈÞ7t³ð.iˆˆtaˆ¤½Eû"‹¨¸ þe¹Þç·ú|zßEüdr¥èàoÝ‹øöÙñKòuš,Ë4ï¯*Ò€‘¢/j&GŒèû¢À}®© ÜOÜ dÃ-ÚêïŒ7ygT¹¹þ†“æ6íFWÊUÕñŽ•0ûÞJü9°È³Û«Y¾f ^Zäá:+‹4[¥S ÿÑ…eØ…™ÂÞï‹ÔÞ…t1ä>åp"1,L„N¤…¬”ê+¦Ùæï4슎õs¶J²õý.]ö©nïm>KXúe$ï|ôϼœ³ ‰Ž!/ºÅ;]n±ªÝz8Œ8+p¿.Ÿü(JIâY\ÆËÅšNîÖøi 8:ÑÍúV¦·qÁG_ÓOn…ÂE²ìá)”;ø:§ì @ü™t†;ˆ)õ‹Óû%Vˆa×—K·ÂÀÖãàÜ,È1Ÿ”Cìz`É7èÌñl™4øûã"¼D{®odX@ú±˦«uÔC¤€{_OÃ+Rß"¶ XÊ#¸Fèý |êjØû¹oÀáH;C=“Šd>Í×6^ºk“¿î5`wãnûɤæ‹;½¡ŽÃ”u,”ß0ÊdòfœV?'R¤ýœc}*½Mgn݇:$Xžr'Èrn*&g‡»Ê{ñ^ï»îzÌ`¤!ž¾,%,¼ß4B9ê¯*bg‹]ÊØm±Õ»(7ZÑ9”øÝŠÝÞèþ¾ºŠþX—×eÂHÔ¿·Ö÷««úùFëf=ÒêÖ@Õæ¿ØüfC˾ÛWÕÿðVtþ |ƉáÏòQ ¾[OY—ÁwúŸš ¾[ Z“ÁwËLk2øn kM§åo¿Àõã§Ò ;FWÿ…É êúñý{jõl]¦rLJ²Gq CF¤…" dÁ¶LåX‰á,ª*îZÂU¶5mÏ‘n¬Žœ ®maéá°œ žiñM>çí'h¶§v6†ÛÕ5µ!²œ€>äÍPŸ](ŒlØ¿C‘TA$ƒÙ”d»â¥ÅÄó=t@¦“è#Èó 3­ñb-–-lpPׂÃE}ípHÜE÷7 Ö,; [:{`aKäÐD=ŒìyL—Ž®l=õDʵcb!KCÙNO/ÁÅ¢ƒž[ì’ÁsKï-3Æní×ÛA§ª¿·q’Dez¯eí” SÇáÚJ8ÉM6â£X#QZºØ'¨3,R³þn$[ÚCkRácBV×AV¸ü&ÈTø1)æyqgÓä]\Æ›`×O˜¹?¥oÂ?‰€¶.³ëá1¶ïÁ¸0¶¤fCø¨ð?K<òï•»t°Tßr…ŠPÔA’‡˜Ûyš¥«þ ³»EÅ“K*bD9¹I6‹òyµ~ó"¾¥SuäO¾Ö‹'ú«>ùj$åëÃK÷÷¸øR§wÿTnÖ‰¿î×#抷Põ4tÐL&¤+=¡åxJcBõ^-LtLºOí">5Þ¢ðWò"_&E™&ì!).nSÖËyx ÅÒX6 ˜="'õ"Õî|ÔÒXù|¾B—æìÚäh< SoWuÔÒcb‚?*¥Ç®3%Òc¸û‡Ns¦º~d+3ÒHAdÑŸçås©Ù®Û3¹ÕP’m¹£?g;uºäŸ°— ë¶EÓ"“Éw¤‰Z}ž”¿¨Ï>2N³+…ØL§K.jÅv,±l¥4˜žñ[¶Äb=óë"ÅzFR“ƒ÷ŠÿY¤wé+ãÉGÕ+F¢áÏ›PÓç ÏFØ£:Š,·7™¶ð0¨‚’ø9™%‘ |‘‹RÏæ@>1 =5‹òrÖGÂ'gäšrÅä1_äQ 7øpÔýAˆ…©¡o^¢a#ìd'§¡î*lZ“ë¢É‚úX„> ¬°ô§Æ{V§ÒÒ™¶÷wˆçTÎb‹0Ó|ækÙl×Ädýg^ÌVzzÉ0xˆ¦²x½C 'm­§,^`߬½)Fñ&®lâ«-ðL}킨=‘Aµ³ÈؘÛ—æ@QLBwqà"ãŽôÕr;ãÕ7³®÷3ƒ- z¤~²øJX¿ sÔ3ýª|>×°Ë3,ù85Ý'joŠ’ï£¢-g8k–kº_˜~•j$<ë=Ñæhõ¡ ¸ãH˜M»ˆ{Ÿ,§ïï^hxá?Ñ𚡉*a}âb»M.4¼V.4¼½Z Æž§Y1Ù"~"¼Îö|‚ÜêÞ²¦ÒÉMó4+渚Kµ{ìß[‹²ÑŸá?ùèÏÐzÝœa?÷ØO³—Žzìg¸G=ö3ÔÇ£ûæãQ½ñq5Ì ñqÇèä{&5>9Â1œw˜ą̂[‡‡µâ¡H<€XŠÄB•Õö"™¥M‘O‚ÊG”3Wï›l; 3¾ÌõªHþ×:Y Õ ÁÊÞRÍa»ƒÿñB0/6 «¢1#U¤³ûyøe/Þå™ _,7!E­¸ ¡¨Šã–Æ’]=iž}ȳOëå2/ʤ”ª»u~vDbŒ¸ù¡(mÛÏÏõêC^¾y—5ÏÉ7™‘] ýHwÐÝ73YõmÒ# ùGœÍ*œÝ-óscIŸ˜cÓÝÈ~nÞ,ªûyöíÏu–¥Ù-áÄÈf{za$ø‰Y—wIV¦ÓúÌy_¹hm&?;Bú·¨Ùqu7²Ÿÿ‘ߦÙÇxµzÌ‹õäÕ­¢&–índ?9o‹ÊõÌØý]È¿åkgwÓüäxÒ'VØÝçÙ$Å}ºZU{êÏd¾^‘^á„øÈ¹ec»ÙÏ »¡X2²‹ö_˜”ž Ïf·Fˆ†3-â^ 7)ÿ™Ü¼‹ö¼XÕ‹aUÝàâg1?GÞ n†hŸ Ÿ¾­Êäžøz²¤?€°îFš§Ìû¯)ÿÒÝ"?'ÒŸÖ O„7Åíú>”¾iÎŒô‚Eû@ØÎ̧¤xHŠ?“Õ2ÏâçÝ­óó#ý`Ѿ>}úÔŒôÇEû8`þï»dZ|[ðtcµAÍñë€ÑÍ.(ý^[þCû&xWÍÇíïl[þéBû"ø3¹ÏË„zVä0´2_·9-ÒOñ›š›Fæ1Ä@` á&…ö ðÏìK–?’_BÒÃ0â^ ï´$u¦º¨‰N]~rNÔ̈;/Ṵ̈Lvååæ‹5›˜ßât±.èRp' jjÄ=Þqɳ,™²iùXä7‹¤¿(qgÃÜ´l&Ô´ˆ{/+zV§Xf2If‚Ž?-"úž˜iw]:WËçô>ÉĹ sÓ"[MVÜwéÊbSÏŠ@4S†l’­ïw´cŸjtËÛ|–0â¿Yï㵓>ŽoNR%ÿûê»PTvšÒ%Í}«1€Ì%+ϬËòj°Ù†ÆFK†Z<‰6D—TZVeÅR=Ͳ®o‹è[²Ò7¦ëëM@8"\ß›uÙŸ:©³­ç‚ìcLÃÚBú¨3˜Õ¦Ð6WI¼yó¸úԟ窳1¢d_ðÏ͉X½(Ë|š/j¥§úW‚Na«]Ͱ~õ{Së„ýGÒeL&A…Úò”E®¶+_Å·$-œèš9¦ˆ²{6ÖMÖ§x/4=Ã=Ùâ(•9`سˎڲý1Ín9{í÷²Aà#YKM•ƼL¦Â¾¬YÝHWå"z¨‹]qà}´Ò:›~_õf¥3 ‚´oG÷ü; ù±„Ð#sQn!àÉ>Sáàߣô~Ù;l~¤=NÖ tPý®ŽÀè¯záÔº—ƒPäçr¶›ô ç‡ ‡Î·)˜®4ñ¼ÞæË´ò2Ù0MùÄý•BÏóÊYSµG,ùˆ”J_ÊÓ:wùêÏ"ôkÀ ÔNŶ.êéͰædò]ÈÈ­þO*©K进˸ÕÿëÏ¿N&·IÉ:jûRü ˆY‰Œâí"φF‰yËèêQмç ÁÇØÌö]Y.§ñô.)ó/I†–.Gi›6£¼ ƒ÷–ä3É.Ì+ë¼BÆÜsl´‚`B[YWSD¾ÍqÙX >írpën|·Í@úKCÑ%}Të¾Õj沓>Ž-„P¢‘P×2£ã€¶¸*}·2½h®òQ7Œ°ëMGU7Æì;"kâ5YQöŒ¢Õ·Õ4^,¢Uå®ÝjiZGzâÕD¬éd­kŸ*bȾø&}0ë‚.ö¬« ºêpˆÎU]®ƒåÇÚÑA7òt¦)Î̳¥W@ºr«dÉ£@¹Ül¨½Ò[aÖ’sÐh‘ÚH\àVޝ>’ —Øù6 áñ€Ê­&_AÖ1 ÂtWÒv³ÕÌô<}GÏóÕÄ$æšÆŠQ{‰ ¤ô¼€€€ëJ“”Þa­{婦Ù-N¥)¤÷Úên§+Xnæä!J>)9¹¦|QµrxEñºÀ0ºKgUŠÇ;wü‘aë]ôO6¶J ÌYí#&µ)p8#µµ_PÕ‰:€Ø|= `аbóS.žvÖ8 ÂfS¶ -ëŽlBŒ=Tš‡Ð? Ð5Ìø=h@Š…Ù‰8ü¾ç4â®ûh«•IvFóícVmCy¦‡:¸@[ïÓÀE6 c Í+Ú72™ÜÇ«/øP`†8 B (AÀ5p‘×møŽá„aœ$mD÷–e.¾©õxZn ÝÍ›YרCÄê’„ö<‰û ²hmÏ' êéV…@Nt’(_à#ƒ²T–c·ér]îm§íÆùTùû°÷ž£Êß÷GÚ5ò÷³äAì}ÍŒ*{?¡‡„BI¢cÅlL×ÇáÁ©¶feIéIåÐGF²ãö˜ÕX×7@ðD‚S60ûƒ–«€ð‡-µ·þ¦Ó _‚–Gn¤¨ÀÄŽ+ƒg r ØoM;õw ÓA4U˜ƒ°*P s"¶(L¶5¡ýÙ_^–ïØRj” ÿ™,é4”’ˆÔúûvTûn§Bv¢ø dQ\1F“ H:Ù„P›aÈhn£B ½…1¿ÄwHØ? 6Ž;¤qÜßÇ‚p€Öio‹œö¨ºwLJ´b~Õ̼ð…€Ø™¡8š3³*ãBPO·µ`ùÓB ©Ûš–yš¥+ÀùÑÝ$ݼŒÄmzúK˜SÙ™o£ñÎP™þp§¡ýž$×虡¾ò…ö°åòym¹ëAÕìRV (ëÚcÍ!D`ë bY ‚5ÓÁäXPà‚‹`¡CX=ìäÓ!Øë¬×þ9âÍ(c‚mö´dây©R-·9PÐTyPÌÝ+£{ÐLׂÊÀ-¢;~;ý‹fž€üÏ‘•Ï ý{¦rõŸú÷Lß<Ö`ã5ãiöšÙÝM­åUó·?µ~ ’¼ŠOþàvÑÑyâ[ý¤èkÑv~-1æN}Ãú@®sñ'XýîSä×Yâ¯vì±X5ð{¼Œ–Û—‰Ã/áˆ}yR?%€J÷4ËðÙÎÒ'C!#µÍóÃæ8\ÿþ/™Ó¡sl¦:NAy@¤?ÆáË"Œë€k…V†àùpª«QœòÓT¦©/jù@"š åSmîbá sUAìÝLÔ¡}(·ùô1rOÙ2ämþ0c€ì§–ñí«­½^EŸkÙíÊ[˜o•Ýß¼Üýâ§:LtzŸK؈B+xDᢃE­è‹Q„º»ì$Ã~"m–ƒï#§Ô4 ç«èùþ@]oÓmÑóyý `hÿÕ1Õ»¯äá‘Îu1@l¤îgþ+0ä\Œ1œ ]O‹çv.2 ÏÆw.PGE†8Žö3†c!M{–ñíÂ02ž%##„¦y$„«# Âþøeýÿ—Èó€0;_¢?ã‰~Ô[ò¹„>ê“åÇŒ{*@æ`Mv¤(ûAæÔ$ >øX^Pê•=»«œà’ÓõÄAGZ¥2"ÉrO4öc1"ˆíº±ê [â"‡ûx*ˆ¨KÜUÌ }Q’Í¢|^­š¼ˆoI‹fÄæG­S°ÿ3ŠÒŸc ŠèÅB:t]P).í‘.ê\¤…þ4ëƒ:R(Ëí˜>@™z‰d#º–Q±È(×F¨Æ `r¥¡‹æÍ¼Å¥üë¿%fßEüÌd2 mÕE…cöÒØZ—€Ø‰? ê«ÿd#÷CÇŸyø1Ãc¡á1˜îÁ©Æ.á±3M\Âc\‹£þ{jRõ¼è›ŸQ¸ÃEÉŽÈ@Á2è5s –u®•Ábf«…:Ó4‚Ñ+×o™‹~«–Îuµr®Ùff1½þ ¡µŸëûšD”¾÷ÿúß,Þ³»…ûâçêÔ»úùå/?ÿýïÿå@ µÙšéu5wÌ&“Éw¼Z=[Žªžm««ç(š~£åºH¢‡´(×16ÔÇ"Úƒ¶t5ÿóOWÑÿü|ýÁ­gÐôfëý/˜£ ßpæ³,ØS”ECª¶¢œœsÛ’¼ÍÖ•™¿2=»­[cª_GoØïú½òXŠä&Íú?Ûç[¯^0GûUýehlŽU4ÄÚœŸ œÕM Ð5Ðìâæ˜T4XN+çý𧉠œbåý}’ÏÉýr— Ð ÆE×Ïm¥¢vµ){^{ÿ#¬\•mGìÀˆ=øoWŸ’i‘”ÿ‘|ÓÄ}½Ï®´°:òÈ%´;êÂÝ™=‘ŸÖ©¿Uí÷d'Kp t  /Qô)à€$=éjèÐQá ª§°åÂ5$´MUn3@üT„okÿÕË%/îãlšü_ `î|´ïhgz^ n¹õ޼5VÌ]Y.·[²Ù¹5ãöŽ]Eü\ZΟý´^.ó¢|›geš­ÓÀ`¶-?Ä‹õî‚÷1ùP‚,17/׳ʇÎË$+·g7Ù´XÓýdßyäΰ$[ß·üßñmã7½×y—'‚ki0õßÞûsé}õ¥(DÓmÿéŸÁЀ£KdU‚›æ`/ǤëÞ(nÛD?)€î >“Nm‰ Þ5dâd,™:õ`k…÷_·~ÿ±ÈË|š/ØRÆG̤¼àGb;1•c޹ýP‰´×ŸåY4«¿5Ž^i5 ãèN²uã6)YOƒŒ¢;wdoy6Ì0zdì‚§„݇O‘etuÿþ½ÂžmÂØ%Uxm‘]˜òœ_ Ÿ¤î†80\TÍœXc<Æ_â¯*a#.õΆZ“zC7«Ž=î„cÝß°ã/‰ÊÉ$Îòìoë,­þ»)ÿØb€Ó§–%åÿÉFN‘h„ø–àr:nòò´/~›ûš•sP¤Ù*öùªç¾)èhCõ-I‡þœú-HÑl–ÌQ·„íöÎáòLµ@ƒ¤• A¨ «%AŠBwMÒ¤Ÿ0îÀÕÛñO"`”ԅŽ<[›Æ‘0v± ¬Àã„}oÒ“Õ%LY«®©®ƒ½W@wwÕE?7®‡´H–<¢Á7ñlS²™v=_‡læd›Ë Î` siøtñ‡ÚVk>ËÛ*ù:M–%óE,öÔŠ¶ïwH, {iY+ì{©‰xs|ðÔì[UÀÛ¶²Lo_aGœ'wΊžGÎu1Q1Gc»õ¦±®—š a @¯Ÿöö,÷8”ô%¹3'2µVõSϯ·œ¾x8"„èùX‘B^.ðâ0ñ]4Ͼh×3š4_ÕP½ÕÖJÜ6Q=0ÿ3/f«ý¹”ù¥n¡î—ò9Ã5R)_Ø ½­j(æ<4m@¯×ü*FOÝ?‹œ\ Ày¼}-‹ðÐK¾š°¾|s-Mÿíߪ—Ò<½EEgM`†³5È­¹O1kb˜ènà®Øýš°°$¸ÛXuz3p¥ü€í×Zû®'“ûxõEìHÙ·†9D¾ã@‡Ú›pK¤žA¢ÅÀŸ'ë&Š6¶Žoª $ž–›Âîýµù…ðuºÌ"<Ú‡Zd bð‡d˜@/3ÐzÑ8F á•èJÛÀ(«À˜Üæ×9ù(È•9ž *Jܧ¨÷&®€,ÎxXÔlÿ‚ªDÿ¿ªÇ9æQ_}Lé“>ðeÕ«qtì–Ì€Qm˜l}-×åÓÑô°*Ç‘d/,c¥ínÎvº¦1Ct æ„à3*®åÁü¤£-‘eTú~óFïÕ÷ Î бY™!‚§çëE6?&«­‘–E^&Ó2(¨u·IO`ÿ{4¶Æ™Â<:[.¹à„%DfÚ`Jî¿Hg; ÃÍAuC@oy®tk;é³ÍÊ|½\BtO:›ä-f$kH“ð5èd²Eþ¨½É<'LV×ñ“Ì4,_ºÁ€*ÁmŒù»_—Ol ”÷ác:K²(ên³ä£0²mThílㇵ=™á]C šiy‚‡áiù,.мí@w‹jMìlãÇ5ýxNüc)]À‹×,ð(ç Â|Z&S`"d|àX6Í!c{PÒ«özŸL¾‹ªŽP]Q÷ÒMpuØË, !³¤§Nâª#=‰¼œ_¸=W‚xO^ÏÕPõ$âb¾ðû¯¡~Nq‹}*ݺ¯ëéû_Ðí÷_mBŽÙ‹ ÿbÛv„9dIÒg¾ü:Û0Äf?7¸í4É|>µ±3BmÙnGG Gb$!c…’Pk@CÞ&¥î¬ÀðÑUÊô,-IÿF¬Q\§´n p¥" LPøs˜¶·`ÿS§ƒŽ™í€¹i?6Íl9ñ¢%L;M°`²áΙ ¹Äì6‚ÉçŠ0TE',†˜|­çÙ¹—³<_D±gš/¿ @ÀáýH)Ã~G`™°è/àv=]l " @l€·Ö¾­jiaÌU³Õü݉Hæ^ºÏZ>@5wà­ó..ã­Ÿ§)~±² ,cJ൳w,ä?Íîô#ây«•ßd_^Nˆ-ÂFnNË–…¦b‘v,`áÆÑ–t#bo#€Ú$Z•q!&‡Ú@Vèè ‡brçi–®Ä8µÕÏ. |uˆÙM²Y”Ï«œñ-!Nt–<üz¨“? ¶±"¼üuÿÓêY!XlÞ¯KµªìœŒ' ,ÓvQ•e??‚–Ü ª²0q¥‹šlÇ”öÆù¹@VzµF "+$%F +ÔÿEÇ  ÛuS¨[Ýè²8oñ7zh;uØÓàF÷ì0#zùªÃÞÅ„/SQuXõÏ~â™…Ñzu·¨·øî? ëK±ø®ÈËóy;uÌŠœW2j«¿^NaÂNë\¡Ó&Ô=H|—õ¤ÒKEÑP(ìÎ{’¤WˆÜ³áDü®Y‡gv—ç_V¯ å”HSÌoà݆\°Â«QÑm ð\ÈŠÜvÿ¨¾ôŸˆÙÇ|U¾ÿšô†f ù (—å1`aÔ]8í-tX±ºÄlÛêü¤ë0tç'ýÖM—ÑÑ=ò.ïu•‡ý¡nô^[ÿì}Ž%‡D]Þe:O§i¼ºý$¹4‰Øtq¡G$¹Pýçú¿’éëåZb- !×sµ\°¸6<2Ês,¤ÕïÊr9§wI™I2,0j ±ÞU›oY›ŸY›u5‹zÂ¥l[¶fIä–FÔe FSØÏ9«‰.“¯¥ õÞnZ€—âR*x©íb¹›±Ðúzò™ ûzµ­Á^€Rþ‡?B?üûÿ³udÅQ.çÌèJVèˆåˆ¨3¶qK-½g ëÀ˜¨¬l§Å5°µHÔJ¶Zz&®«ÀÏĺ&À’¿FåQ´ú¶šÆ‹E´ZäÙmTþËFÉßá’"dTùÊxFŠ%ï-Ï †Þ‹2]£R©¶çÿ@°Â†ÜäFÛW=€z¹7) êÞÕP\YÖXÀ _Õ±ŒÝ¾Fç†ã„A]Kw2‰þçç#Ê,'úðiöÎ|ÿ€îÚ<Î!Ô§kC ëÎ÷ŽVh†f:ÁÅÕúFÑÛê+}~u}®ù5 ±ã;¿ºÚÕ‚õ?ÜLÅ1ÀqL#ÜåÓôšîæõúàÝÞj°›¾K|¹œ ë:ºî2ÓÝy'È»Î÷+°í:킆µì¨»ÌÀq<ßqªG“o„®kº¡…^;Ý4]¸È­Ãsks7QxÝ@†¤×Ý¡™2e·$ìÍÃåP|€+6ñÛ×wŒ¶ „XôÎÄhËÁ»È̸"qÔ®TlWË­ä`­ 9‡šTC³Y2ÇYó±zäGå¿,×CIVVÿo;D".@3c­dÔ7ˆX-ËCÉ’w*]s»Tìæm7,m·SB=$xžáŽ@ý¼¡ ­%|"j:SØ®ÖìFÙE¿?úã¢úÍo®qñ3 Õ4fÖa5Pë¡û€ïEò ÔÜ4G.P%ˆ†÷ˆ¨?£ bx¯Ýê}Ê’ÿ±.¯«˜¥Éù•½Íoó©7ëy”Vÿб…ŸIŸãè'@#õ `‰QÏr•c>!U6Þ1סí˜OȧvÌ'°£ó \ÈhÇ|Z Îߎûzú©4ÃŽqÕar#ºžÖDf‚˜­fP剠 ýÂdÊd?rMÓ0ldJÄÑäÄ‘—Cˆ%Á•TÜ,®³Uz›%³+VmÑó+#;Ü]ge‘V½NûÌÓ™Y²Ð¤ÇØzOÏr`­áT)Y«5MÕB;Òê6„·@žºŽ±ÕP~ѼiØØÜô0»ðc‘—ù4_°!j»ñÅóyÐ'zÏÕXøfa‡1^ä;¦´&˜¼ÄL;Zƒ¼&ƒ¼Pÿ2Rƒ|ÍLªA¾ºÑÇÏ _ùr.l”ÇÛ¢ºÓˆKBî0‚¢£`Õ¤5 ®~ÀwÔ#ûùþŠIΑñ¸Àï`sÄ]ü £¶úëågö'ìW°ÎúB݃HÎYO* µAˆÇõ ;^/¢žñ9 ²±º4yD¾˜ž^X*ïZ1Íþ@n¶òt¦«D Ó–‘z7íQÈÙ :BDdÏYÊÇ*mXÈCÌ\$Ó†Kƒ1a `ûF&“ûxõå_&Š™Éîÿõàe ƒ{û`Å2M#Ä–ªÑ3ÙÎ3±jD¥ÄLƒÐ«„Aˆ%:Ä'ÅBsK¼ôN…6Ƈ%\3±Å@OŽ˜ mÚøý¼)[}ê~W¼Z3í-µÇ,$ÕŒkaèÊÑjœ>ò‰‚XN}Ö…æÇÖ¼š¥ eBQæ5ÀûU²W÷Â8¸×”Km‡¡4I½½…ôõ©¼ƒÚÝߨMßC ”UãŽÀ^XóD^7fhâåw£Ö¼ž­\Xóη@\‰qBRp·|Ÿ…®³=ŸÐn]o ƒR‰H§´G;æÓ¬hÝCþÎ }†œpœƒ>ÃM8ÆÅq†šp”C>ÍC6Æ!Ÿ!&ãÏðŽqÈgh Ç8䬄Õè6¬„ã’ËJ8Ê Ôï0èVú”3dŒgÚï±zô_5<Ûÿ™3þ ýôwÿßÿõþ—ŸËÏåçòsù¹ü\~.?—ŸËÏåçòsù¹ü\~.?—ŸËÏåçòsù¹ü\~.?òþŸ¾ýˆ¨*davix-0.8.0/dist/abi/abi_dumps/davix_0.3.6-gcc44-x86_64-redhat-linux.abi.tar.gz0000644000000000000000000037540514121063315024763 0ustar rootroot‹Â‚TÔ]ßsÛ8’žçû+òpUÞ­º¸DI–퇽ڌG7ëJ&qÙÙÜݾ  ”“ Ek¶öþö@J%Ê–É6㪙øç×îÐÝh4ºŒˆTÁ’ ¥ü”΢ŸÀý1™Œí¿çõ=Ï›ŒÎϼŸ¼áx<F£Áð§w6šx?½ iúÈ¥¢âÝ»ŸhÀ–‚Iyè÷žûùúñïß>ÜzïþòîŸÿönóqòáçkrõå·›O×>_MÉÕߦW§·äÛôöîúËç“wùÏw'ÞéååéåÉìþÝ/ÿí¦þ›£Óáί QþèábB&ãúO¯R®U•´¿²Í×ÞÇÉ/¾]ÿùùÓ—«äîúÓçÿä Ôߘְ(Ù ì¤P«ŒÉÓE–Õø;ñsVŽ—““—ƒüëIÂÕè?}ù•|øô©åÐÆ§ó9-¾=ê?ýߟƒÁŸÿüÒ¡=î«Ûë¯×WÚ¾„K Ýƒ‘A å¿@ ¿Lþû¯­e€ÀÎèÇ/ýÑCÿzûáªý´w>ô ‡C׋ìÏ_î:¬yNLGÃ6–´þûÃíçëÏíMÿUDà9Áo0›Ÿ…„o€uKÞäüü|èµÙÍÇ3ùzû¿ÄJ¥…öÇ®=•KÁ~Ï™T-D°=n%V/ò¿ÿnM'¿°ìn•ÌÒøOéÝIÍfi*‘+©Xò>Q§2==ëf4™üãó™…ž”ÐÞ˜ ‘ âSÅæ©Xý2˜.-¯µGÇ{%:CGt.çl­ž 17¤†CjÎ8‘‘ž?$ôž‘J)"¥ƒÍéç;LÌωšº =Q ‘²Ä~ïM:£|Ò2¼^0¢%WÓÛŸïD«sÀ¦hŒ/à"ªØ8Ûý«°2,¤y¬ö4Å×ëJáÞ§ÜO³ÅŒxÞÖW0íoˆmEh8îLèîèQºêî¨Q† };ŠÐyWBaÄ1Ö¥qT Ôçi¯ek[Ö+•vB\lËÞ NýûrÂ÷â8z®£w]o¥Òx¹QÂë ¿.×ëò¡9‚SRÚú½¾k/×Tä{–Y+H1§Öæ7ü˜Qžg$̹o×Üéôf9sÄUÉ€ŸêÝ_¶ÛH^´[Q…Ü+r”r³Re©¿ þ²*•_€©Œ™ ’ÙÑpS°êj4g2+Õ¢ÕcŽæÎ&•HáÈÈá+ÒreÛ{„\™÷„ᬨÙÄ 7ŒmMˆ$Wìa='hB»uzάgŸ’+óÙ§äÊ~έšæq:£q©­JOè¥ë|kFŸ€deº¡ÌÒóÌÞ°˜)&Lª.ÍU' ¹Âñ¼‘ÌRý™#uω33 ®&ÀKxp45vJ)ýóï>Üyšš«±Ì ós!_—¶—þ‘#rò¹›ZuÂÅØì•›x¯KkµSÚ±2W¥Jƒöá^qIklÕäÚ ++»Ü,dnðá—Ö¸ðµ¶ÄÅï.šßKŸÆ±]®oþk¹´õ­&9cW¨0¦ó)¸ØõR¯÷Ì®=¿ügžØ5èæc|3T‰#b—3CëÏ®›—À²:bí~Øt{y#®òAj?̸&C2%QG’ùäps[8åa4ŸÚ{ÎSKz kö›Câìß¹ Õ ܹ ¤² ØÕ¹?"öF$fK~°C~• ò©Ì'ÜÁ’z•z’|éªΕW‰ùn™¨/¯zۯˬ²ùÆ…ýZ3æJ§%3Ã~0³9µphW4Ü™Ó# wVôxhâPX[DÜIk‹\\v$zÅ´§Ágå² î¡°}Åx\,(Ω\¨Ò¹!½Iqfÿ´ß<ž foSõ‰Ëç®&ôO®ÏqÜo)×îôY¸5Fû-ÓzÅ}Ÿ…Zç´wRm*sï™8›Xt%Ç57NvÃu¾Îf?+²fäŽè8¿™^'‡¾¹]G¿09AÛ]…¯­l˜æÊì+‚ò9òðtçåîAã|Û;uAngD Æ®o>.ïÔ8£‘¸6õ»%뢒òÜ}ª™;ëéëIu}wNô·Æ1“òZÿñôŽÚoMõ/ý¦ ^2¡ˆ©›TÞ† ²w¿’Ûú×”A]è1ÙÚ”éY·j²¿Èc;±­°×Öë±YYÍ¡Åã?yß ëÜWüõƒ¿çœä¾r[ó:ûÊdÝ‹ë—MÎÑ«°wô4yKfž™ý`m{ôƒ£šµ¿K ¦í€—Ýk 6¹‹s_ùßÚé†om"üp†£²™©ê*ˆ„‹H>Ó3ÐAwÓ5¦î(¨ÏÔrî‘zAá^Ç—»Ó(Ë'×düH–Y‡D¶VN•Ý †|÷DÑ=D¹{2ˆáð "F—¯@¯CqqÞ þŽ "¼Ð<œE—Ý;Ac™lŒ"._c&´".p}»»G“ÎÅøm˜9*Џpjlm¢ˆs§†Õ*Š8îY]£ˆ rÅ=EiŽ"†¸½íé(ÐZÿELÎ`œ<EŒp³è¹(b„›í£ˆI÷Pæî`3Ô#¢ˆnò=Eàv¤§¢€à𣝻¾Ž"qñ·§¢$þ1QD÷{ÌGÐëEx€WV FôŽÝ¦0¢\6ƽ`ó‰@Â1/Œ$:?ÞÓŠ™£"‰·f­!’xcŽš"‰×gé`$åå@$Üéžöñ„žñ¬Ç8»”æçwI½Ü³Žwϳ>zv„g çaÏÚ ‘=ÏA¥Ù³ /´ È+¸c¸Z·×cVCç€eG]ôsÚg™ºêVïžÕžIÕmSx‡<¾šߺ½·#þz$?' µ±lõHZnzYƒùz[y¹ì“Œb)¡ñbËrù¶—K&Ñ’ü®§ºä}™JózöãÅ-¯Ä2ÒvÑ,»‹[ÜrÚg™:Œ[³Ú3©:[\ñˆ–ã×àõøv´“ý(휳û#È×ek÷üöTÂîÛ8dÔL„ðëGˆ¾žâñõ_BD1„’PqL)£@¾`¦SbÙÌÞ\¿g+nÙâ| לž"€«ÃØL¤FU¬y3O@äFù%b{À=ÍÌIÍü÷ÃSox*Ë~ïÿ|1­2}ˆÔ_ÿúë§ëŸ¯ÈðtxzÖV'äú Hè™@öAßÛ\JÚÆ¸Xs: Å¥Á÷\*â§qžpœt+ذæ±"AJã8õõÆc›ÅJ.ð¸ÙŒú÷¡^ñÐy§öAΙr ½™åPÜ”"‚ÚBi_³<Äa†ÚU‘@à ÍPŠ!K‘£µ>/Œsä¬ µig©œŒáX@$\3B•iE[ö“ ·| ëbç°Àèm£Oqƒi|h0ä÷<É õ½×æžã#¬ƒÁ§K&°›¥…5Î9R2vï2 ‘‹|‰ª°û¤Um¤rÅ}0dÎ'æöf,&Úé Í%)ƒŒ„Ô[<Ñë³HGœi;Õ~ CNU𕉈+ädÒJGºà…Ît4aQžª¡ÁÈ…h‰÷%ÚsT :‹”X9˜î9w ^;µ Ü54šY‡à€6— E#Öá4h$¡âž£K ZÀQdÆæp‡°˜Œa‹ˆ„’³ ÚcF¥éÉsOú‰#Íf£ ÓæÖGH³R‚¹Lo;pËeZêÜ<«€Ûø5².!÷æŸÑhQ™ŽÚ|«¤ãšaW´ßš‰ÔG§•,&xØ9Ò;Àúê‚%é’Á·J“D0˜XDhZÂBÝiX ­fX4ÛB!—мø0I¢—“1#pB¯! $¦ô)G[‰Òý5¡}Êã•h“Í‹2ÐÀøL®AupHk`ñKœu}”9Ǽ% Ôþ‹H™âšÔD©$I ‡ðˆÐˆ“ÂPÀ&)¸INmáãÅ“s/!±Ö–sI7.pÿ¯p 8ðžð]†àýa ßh —U<…«2žÂaOᨧpUÉS¸*å)ðµ<…‹bžÂѹwá蔺ps\88Y-\­NÎA 7é© :K…vä| xs{ýíÃ×uÇçv˜Áws9áÆch’ÆI*˜¯ÿ#‹4mp4Úò*´O” _¡Öl8ÿ£l›EæÌK@'D|…¨¨ŽP¬;°Á#þbKßÍK|8þì»~Àý~ ™•·0ÈÆ3Q‚ÂrÙ€zOfiŒr}÷IˆJn“™ Ll˜ÍEƒüƒ Ôùª¶tæß±H¥’ÞÞ·ªç7shÇžF§ã.œšËU°a³ùÄ×›áj Ržz5ç¡I«Ô¢NÒK9g>l%òÕ*c£!™¡vÅ5 Jµ›Å6Ï20,xðdfÎÕ¶fKWõ”9©ñsíÊP˜oTb»ÐÓ-'ʯ@¼æbÖt¨Ó–ËJ¨"¿ç‘i_»®æ º°iqîþ›E #NãèÜ’¼š›#Ö²n=ç>aæwè@qtGóE^Ë8ðõB €Îü:ß²Ž`¸h>ÑÞ|gCsyfÒ°J'S‡•h#ÇŒ/#‘6d'Z®H:Äà)±9Ö¨ ¶—á,%på}Ž‹ÌäØûW8°„+«£X€Å-À|N5‡Á8«±h°DD ‡3Ãx†c-…Už,…«Z˜¸ l‰šé¥0âs—MÛH·X6Ìr‘)‘6Õf¶h;_bŠ9Πm‹‡ÚÏ;Ã5ÏâθæÉ3踑Æcî~@óÇë9„Ué-rØEÓ¤é4eÌITÓ9äSY»‰SáaÑêüuRG…‡A›ÓˆÈhþ{Îr†Ûæz‰]Ú,ˆŽ-©$Á̶Oý…¦“4ÈcfÛ0¬7ŸQ• &¡È~ôÏ4^Àâ(AMƒ—šJ*Nes.Ò<º¼Ò¤ãá|Æé<â˜SÖ˜eÄI`™sTBç ÐÙÓ—v cà héXš J”°4 (ì”ÕD`ȉØ>‚0“Y8J,Ø'9Mb…›Y¾•Zé¾\nÐM-T…þ( ¾|Ä¢Kóÿžd`‰&zI6,|¯ó2ÃJ4a5šc×ìzf»Ó"HWÙ/׬vÃĨœQ©ƒhX»° 2š»™TRQsÇ—‚·Z¹’Š¡WþÊ\wB8Ø`KeÕÏb=¯ "°³;‰ÁP1´ª\“±µx¦Yê"{ ?À)¯ÑT ë~¤á$·€ÀÒéXíš`]³ÄÏVÈZh›.b!3Í%Ì„J8™àZ÷Pi ç€l¦Üî‘9ìVøáËX- ’SžÊ˜±‡“rV`ë–yLbÊçöéH˜®¹”ööu4ÏÓ;nzÓ¯aœQé:’¦@ZîSÙ–8VÝA#…±)¡´ie-œÖÏvƒ/݈dÉrÃk‰ioÁnßaÀM°l‘Mm ^F¥,7vPÃF2-™XF>s`¾©ö¶¨OÐ7o׸K8pÆ8.b)ÑÈÖ%á.% Àöà ÉñMÂ4mlâÕÕDH.©‚¡a»à‘,•d)ÎÕÍR=˜¢äZ®±SLjÌäWps¬‚ÃÅsÙþUÇnpèÛ¢bÛ6½+û=g܇txnœ.X²Ôî’)iAwaÊ42ÎÊ-LF`+^~˜D© [ÊøÁNBƒfŸÓ#Ò<@Ç1ãs’4£jº¿Ä¢…"MˆóHš†TÕ»ŒN‡`%‰À'ã÷™ÅKèjÆÀÇm—C›äYDôÐåAšà®ãLsæ€u¶9`*«sô ì[.}’á„[Ƕ¥9ÚËÄõÅÜ!€—ÔZbù Ó°"ËwNòº̦½]²«Ìz‰Hw6Í•qí¦Ú¿Y!û6¡ã΋7èv‰|ƒj?Éc\mi‰,!¯"ãæóMr\Ëñ%46(•¸g)V°Õ$öJºŒæÔG^}6€r;Ñ€‹±€‘ÔÒ 8O¢9ŸáÜ“ v3²Âƒ%z4^Fsœ§ñ´~·J‰€¹Ìó˜ãs3ã;BÚL÷~û쎘 ׋P*d@‰†• ¾@crì ùÞ¨»YøToÌÀ ¸AÄ®W˜I¨ˆÐÚ ƒ¨Ãì Ñ.¸ðeƉïÁaMs7ˆ# b€;\Õhå% ¤y‡IÊ¡ÆÚ<Û3tÃã.– ŽŸÕû nwH¬ñd3q.%"rºH–VEZÑ€#4 ì¶¡ÁC/³ðU¾Èª4Øô¤ÃbñB7l†`6ï¡[ŒÅÃÎj•Æn$‰uÌ4ž#Ìі»(Z¢¹#Fs<£Î8ŲºdBb#»‡PÛ¼Hx»g¹’¦ Æ †æÎV2NçÐÁ.m‚g†ÆÅÿ£ñÁ´–e*7TÜ<ö„·91÷†” –7ÛBy„‹Ý.F©ºÜJýq ÌÌ›´ÂC¾u .˜är¯ã—}‰çt kiÈÔ<Óè߯›7U·´\Ì–ÈWL–Ùk‰Ø•EøÝX‰ßqÐëذ]œø,ùìuì:n¼ºÑ>ÏÎbAq§· Øæ½ð÷¸: ÕŸ¾ŽZÌ[¡8@ Ï [L…åý@¬V$4W¯ñð¹ú«´qÛNÉ Ø@c:€t‘%­`±xø,i‹Åçw*X0ž#­#S% +¢%ŠŸ˜’šk\4 3N±¬bS…v`À™t 碩cL§76ŒéŠv|›Z±tD_ìŇ5øNmMtðL×CrÏSXØU¢¡)|ÈæÄtniÎ<¶ÇDWâZ̆B¤n) po7dk7š«ã*òq·‚˜Ð À½Ç¥ñ{ÙGOgj²ë8>ë¸zÝa>*µ©Ñm¯‡íû©Ý³¯Ù¿WÃ-‘xàgïÙ,+ƹ\àžòŽTJIyxTöHjTñ¨ÕJÕXÅäñÑ͉žµÂ®·,í(…Äå°*¾dçJ_'0®ÅÇBšÇJkH:ñje–|­2‹ìké ‡œí ^#'rNlJˆ76·‚•’˜¦¦-’Œ`_4ÜEÏ —èrî=ƒ¢›°Ïì° Š¶ÒdÕË dnÿÏÞ¿57Ž$[¢ð_i;/}ŽUšx%}çØde2«4•µ˜UÕ{^` $‘.¢Tcóß¿ˆH‚$(ÄZf6Ûöî®Kr-€‡‡‡‡»Ç²3Ôòý×B-å%òXLau©˜*t‰ ì¿„”ç­0~V7Ð(¯|‰ˆ…3Ë”¯¢z7ïî/ƒ£tJµ˜U§ýtÕ= 1r,W?_|ÚX„¥“/¥|T]´„/yNTÇß+?ÐéÛÖÅõESÐݽðâÚ[A¥CUý%äåQN•‚ 6H,'ó(;¼‚ÃlÐ;p=$X¿!˜ju¿¡‡½¥|—Ý£Uf ºkw:GY‰"%´üŠ|8 š=èƒ"—ö8ŒA²=¥æÙŽ#¢´ÜhÐð.ÇÂÉ•àÆˆ’Êu‘ýt«G¡:€ ¿•óÅ ` ¶'¶ûhJ4ߎA­Mô#‰\˜¨ß ;3+Ša9Üv<Ôö¬Ã3º:>«:³Ý,¡C”åUxª@VÕÜýhÄ™ðA~ž†ÓGO$^Nc{n³©ŽÄVšÁ£NŒ𪰢²q ÙÜOãëþdèÏ—%ö÷ùþVŸ ‹&O&¸ñJÄ×XDÃ~9ÞÆ[Ž0@ð4ºÂP)ÅSÛ0?E!zA"p»Äu×pêônÃ<…˜¤±L½ Ê›J 7•ƒ¡ŠW—… ´4Ä!y0$”Ë“ÂÚ„«p°z=j¤ Ì©H3‰‹²Íjô6Íï‰ º¼O€mçAÙk¬+8u?<}ÐÁwÖBuÅfƒŒa¾c'Duª»úÖæ¡|.…d¥r'..1P®rT{A.ìøª×Ò‚0QlãÄ…¡Žë 0Ü“…ã¿E zæùŽ»ÂŠ#˜Ü–<'‹R¿ñ€³OŽMQKLbÁ–«c§ÀNåMõ÷…áñqÔcóñ3*¶ìLä8½$(_K†PÀ¹ý b”]êà®ÇI‚ž»=wª—4oæz C›3›øvU¾Ñq`sT¾°3 ¨¥:‹ÃµN}¹Âúlçh¨G–hV¨J}˜²ùAjãÐv;M£ÄDž¬4`´zÕîÏa%`€òU–€P ÒÈøÐôØå†W¤Ô‰à˜™Yãl€…c¢Ãºq ªªÒ‘P07UAá¶d…Vzͱ!ZL`ž%X{BÅEÔQ‹ /á@Çp½œP×ù %,é¶e¨§ÀTİW €·л'KDŒ¤k‹9ê½×~ö½é¬B=ŽÊŸpÕï vÉæ:O_yBÕW]P$ú¥"X ”‹³7™àV…ܵPø½U1ÇÎX®oyÒ")+Í\ÐòwÁjŒ¼8uÕ;|ýk(Êlº¥÷Í#•:bß4Á „k è>ã*ÄvÞêñ…ÇÂ#ƒžÂy"¡tT®í{ê2%\àN hÕvÑfa‚K–xÈld 4vú¢8LC(à‰GNz½P¼éZƒL!EKÓg$œ:0$3ÊúQˆÐ…‘¥O@8dÕ¾Dæ°j49ÒäÜk<ØU¬F›‹•ÿ«ñb¡: UR#Èmê±á"ÚØA8teÀ’+Öàññ±\íÐ.ÚlzücÃ9Ü&Z#ñÇ=>À®Ê€—yg;µ|™Î!çÒi·§b_2ûQáœYåJêžò•7ÖÇX]s±§=ÆQæ?ŽAõ^" õ©P±¶5LÁ5¢òÈÁB•Sãih£ñ°“(Õ<‚ 3ÏE– åD—ãnÇ¿ _@ÉMÞ†âmuºkø$”Ó« Pz¬°PNŒÄ…+5pˆÈ!F%Á:X¨.\“|Qbš N–]kÊ÷t N¤+<ZšÚ¨DÞ 0ƒlM!›sÈr,rÒr,”\¸4† öŠñÄ PâX¤xŒO¤nÙÉsJŸ¸¸Â]\®s޵a0(¬@Õõ)$p®ãx0̱àýƒ °š(ÇBv‚ÚU& ÊI$ÔT¤(Ó¡ Ð“?…^•¬à`ÖWFa‚Jª*à€`¸{œrî€CMª‡»Z¡•g¯)îªi‡ü¸¨2½‹ðy@õ[0ôïIž·ÊýÚó|ʡϱУõØ£9ÊÁÓ`¨ÝV5Ä}T\J»†R§šÄâ\ÿy:O@™è“`n§°ó#lïN˜‚rÂðÁC}OØã¨“ÈN÷4Ò=˜´8‰2˜/¬ Ð&Rb¢6,E¶ãk,†€À Äïø›×'¡ðâ¡Ì‰DR-ü¼`‚òI$¢7Q˜ dg•p¸DÚIžû‚Û÷cÝxr8Øè¶GC¡L»ÂB9qÀ—™'‰¨UA…0¥Ðh0,h$AIä)Ku✪á€``áqÒán0RX~«†Â-)†Â‚_MÒªn´Ç!ÅY°}w „Á=ƒÏ¹©zTÖóݶ*Dàmª„nî 裦ºÈ¶Ài¨½Ð$÷¿ê–©e”lîñ)»9Æ[Ρ@¹ ÏEM×>»šc¡Ïg  c:µ½Õ“¡ DXúÄT¤–ýÍžÕûfSrAª“ÅúvÐõb`›<…ü â@èg.âΟ÷6Â?2ˆâÐãY¸ˆŸ%|zl8BªòÍñ3T‹J˜¨{º%*ì&±”t6 d((È™ ©#ˆ¸N o“Í…9ø˜UY¢sTIÉ÷}]á{ 'zš§ö«Ø°sý(ò…7…?ž(!ÅÕMG¡4*¬ (°€FÃo4\ œµG~P`: MãaÇ*Ñ ÒɵEƒJfÑæcDœùTEdcíì ™ƒ*3ê°³‰I‘” –iv <°„@ˣࠟx-¬Ð¢Ç~f±#ä¶—–ßRí5z)`CÃ}\­­ m×~e`i<ØûéK4 B#{­àò¡rá$–ZiаG ÐÕ 8…jeVˆX)‘Š˜ÃaåÃúÄÞ-v7 Q}çr,ËÜj^Zaàƒ: ©¢hE³#±Ž„vüT€ÈsT4AÙP )r‰ ’Å^ˆk{«Ã4›û&ÐX-Q³ùè n ¢¥Ešÿ% RF tÙØ÷œTLPž¶Î]æ§ñÑ•]Õh@éb‘ 7$ ‡mì{sö¦À 9`Ë¿BD~c‰µú%L¬¤HC“Ãaåýѩð2Õþ‡s{áÄ"EîFª«.x­¬!Ÿ8…~å5$XNäZ)ðªÛÁÅínÃe€en Iè<`לD)(Án`ç‚)¸qÆCº« )]6F~_hZºÃ'®Û• Ðs8ä·EºÒàÞì >ÎÀÑã yk¨À ²AïÏr8¨|s\XQšk4\ ÿª&OЋ à *ç§„V9™ãºà$¹.pP°’ЩŽaቅC²"9FÊ’HLU7-®åÀtŽ«˜Ì±`æ<È,Wî•ùí>z¨j!•¾ }“inËÖÈ{¾•HßKa©xêæ´u*ðŠ” ä‰ˆiŒzDªÌõš’…ëó¬qQµ l+»¯Ñ4—c¹¬óqŒÄJCT'ù8Ù̱lhÙPjÙ/K—9w‡Ž5±=_¸ÖL~k¿Êu´¤O^ª²ªÙQe—иFÖKD]Á:‚-1¡ žPX$Ôy×£S!©îÍÈþsQz|´PAÚô5ÅB!ÁÈ ÌAÉØa$éXÇ—(Å5ªV óªÎOÇ‚U^ÐÙq" £dMÂxnƒV¾z,závaå‘ΜU,Ù*%(6#Ž€­ %V¶{’9ò"QÊ=¾•”B‰ô¦V†(¥•§låÉÿA©mˆ{÷P#ÆóÔE4"ì®R£e/„çADaâ=IŸS§¢œ P,¤rÂí.i‹…¦kÐD”S©*K.GL"UU´&òàeÙŽjØ›¨ƒÈÝê7‹** Ð,è]Á}wc/ .ã¯D¡’±iòkp¹±M|{ŠÚ+wÑ#ÝU”Ÿ83áJuÜKúžÃû‰7uÅÄÎ|’ås;]lãó´?¡*hÂUЄ¯ ‰Mø šðõm7ÝØãÃ/Q »+Šba»0—P¡7ò©Ž/ÉÁ@P¸(kqÁÕm”-ÜÝQ‡ÒOaM¥!“Ò=ªSƒ~˜¢ò1££âuèÉLº¡‰ðaù1‘´X°2¨ù|`”ÎÔ¢±þcYz®Hmg,ÜÚ&ð‚™ˆ½|ã0ÀwèJ|äö¼CÂÂqeh SW†MØZ“е†á×Uâ³´&¡h®5ŽCÛuìröO“–3{°ábïXI˜ÐKd¸ÈÛoMäÕ°pa··7˜¸0\`•Há.lʯ±áb“$¦ËsOVèø=Lü•¡Ý4\¶Æ‘èÖ̳T*ñ3ô%Ö¿2¯¨ˆÀhl¦6ìÂ1¶a™]ªj‡„RX…‚9N²²éQìÌQÓ/‘`†ÆÂrBTËL¥iMì$…à–p#;ME Ja“¸âI€¶w 6¯nÜ×Íåj¼§eÍWUÛcj!$*²Që 8jÕç2SÕº;n Ôä9Hí'¤†³TáK ãRL’=Û€;¾V¹^Œò…Wp0ÛŸBÁ²áºã/Ñ0•n[™C ý˜*‡énŽ…l +ʼnªy‰BšÄ0·L¢Í7B^ Ф5*|&÷¤ó3Ö¢)´ פ×hYæ` Áp%ÞËyUN©ă=}µ®›fyåbúç¼mð$}ó¢G0Óªª×&¹o>Ýh@ßÈÈâž‚Ÿ&pe0Ñp·Y9j `r-`O åX@Ï xú“PÀS¹DÛ8ê¨&'N N+sÜ'ˆË‘.U*ª{ôºG"Oâò¸üˆ+F^Áá”×Ó&V=¿BÔÑ"ÃSá©& ¸dƒš8¶?öAN‹ƒb¦?ŵ%X p80؜̈́NS~\{鳊Âñ°=˜âØöd¢ÒÃ6Òtw+va¾â Õ‰²µœƒæxÀ¨¦þ‹¬²£×ñ¸±.K°äIAĨdÉ:áè@BÑ„ðÍÒ7{ö„òŠ!`Ís,T¬R½•†³ËÀR²DÌaw´ Ö‚Xb… x”„Òiïe¼FKL Nq I 6º®6FÃÉ‹/*°TWª,¦ïÙ ,NŽ3”Ÿ£±&0 )÷r䓪.œÛ^€‹¶HH1õ` —ùª°2 `¨ÆMä¤MäH‘’“5Z˜¡Ú«I8Õ*)žÂ΂ƒ.T/zì'a;BîiÙH5rd%°Ú`q6öR°ÄRÉHó¾Ý¿½1ÜvVÕh¸N&o@×G ÐpXó!-_4qZ¼ŒlÃ4„ήüB¢ÅPŸ"ÐÝVÂ!·Ûê¦Ä¾7÷RX!á‘#,á"™BíÓÍÂdêh<àú_ÂÁ–ì Ö ^BႦ³9êíB …‹¿Î²Ô Q]…ojóÙœëÂÚ„+8?Õï¡à¨|c\§ÝPÓG 'æQúŒ”^ T@Ý–v,ö¦³vcåM½i{Ÿ[÷TIÌS”ˆ ü{É\Ìǰˆ‘7õÃ`Š‹"æX“’ºÿÐ¶Ä cäg>e¢ÐÔã>êÆHâÅ¡]¶e•¯*ÑbeDhi†ªæ“pH-IÀÖ»Ñ&™òq渢ûZCÄGTj­Ä‚ ¦Àpý~O¹&²_²ŠœØR…aYŽª¯ê+h¬È†¥†DþÆk¢MŸÙ :A¾!š`ßMpÍdG€Û A¦†BÝ­$E­òÔN' ,Ž®ÑpXXÑq²¹Õå ÇÔlK°ª»Ñc±Â¬êåÃãÀ`;®d!I#'B£Ó(‚ÅŽv<[áaÞ¤.ð’eÊ?X¨Æ+9V¡L­„C~RØ[}N9 !‰P‡¼4vQ¯©w‡qÛK´òhP„°DÃI7™ÃÑ9LÕ&1NÕ&È­%GƒÓG½½'±ôæ w—¹Ø¡m[€´GRE"\…£ƒ®«hg]5hœ/ñ îB‚sscè)OÂ÷Q¤ç—†¨ã¿Æ‚Ù 4D×5P.Wªàp ]bŽ4Ä)¿Ä~Ø]f†” :e›sÖT¶¿€¢d ø2è'ÈÀß ÃšŽ ÷MEœ µ§IŒŠç`(¥¤?:À×hÚ¤:ç§N÷¨ŸDœª\m”ެðTGWÜt áÌç w­,!UV%ä¤bÿ9ª³Ý xìG_ö Ã;΀[UÖÆ"òË0 àc¶³tæŠÄRw U}œºG~nǖ† ª]á„.ê„—C¡JfÁC¢’mrHøk\€&ÏR“æ•—B PÂ~€~ø‰[tß‚!Æö ™:2s#kœM¨HØc_8¶3âÞ\V‰‰V¨…=†!Eئ0œ Â µ?. 9, dÒÃó׺ºÃt¼LžÔF%‘ò~¨±LKë ÁeÐsbIóï{åG~‹&Ê?u.®/bî..P˜½âQ®hb‰x981ØØ——y”3¶DÃxòÛh= V¿–*îãò»NË@ÆO—Ýcµeº3—cZ ›K#hõR9ZLdžT%Xˆ3Ñ ®Èë9&Ú>'>Ìó×Þ9 ëqçµí&€©ãÆ6ª;FêLüô¢ ÂÊÐá#uTÈu¥áp½'4¬Ž=uT¼Bš9äú(@èäAw¤®ðêB_¾N$K<¾ëk(-Q šVªóMÞë „75oÇ%(¤)jÂ$–nn„ƒ‹+ÁÇ¿x¸Dœæ½ ASP‡UêÍNçÑv³ÉFÒåp00ÜÊ×X¨«û4´ÇóP`ÒAÅÕ 0ÌM^fQ„“Lƒ¡$[8ilW½ÿÐ&ô“. ßtý¨ äW-¤g*ÉgÛ <òiÈ4}Æõ„,À`¶2UGSPX9]Ø>J=þ®ž²Ÿ:ÇÎÒ¿a×à™íۨĎÌw¢… Š~dÀ®o®|<›‡Y‚EÍÁ@X¸E™ê  Ö†»³È±0W+”ºû’È.Ômf—Û»4fä.RTNYJŸËá{ ûI…µÕc÷x7Cõ­ëØF9ö9ÈT>  TÐPAR–ìø» xÎò“l˜RýqpÀWzmh÷…GŠËåQH ¤Ò–Ôa k}[‚NBTÒãúE'ÀÌ†Ç 4ëBÂ!…›ÙÁU¥öt‘ç¸Î-ÐùGÎ>¶¯Ï#ÖH"{šñ¾- Z廞.va̺‚O¸ð©çNhS“z œ<1O<Ù³€¬5r=± Öš¾FY$lú=‘F ®®#'a`û^úl=^¬îŠëk 9ÛÓ” _»>o6|^¬ØçM´Ošèyè’&cžù´ø˜Ä¦ÅÇ$6->V`³ÄfÅÇ6MIX×d štM¦ i×dœ2 Ä”f¡6'ð"‘YW× štu­ iW×oÌ¡ñóÙ±ôŸHWd98é–, #G=\Ã’½€§I¿ç‡.Ç (ð„ NSó%8Kð'Ö¬ðol Ý×½­­"Kí¼bÞ™±ñц–dcš›)±YΠ‚&9ƒ šæ êwӉ˲‚~BÆbág¼|žÌõõé¸ÏB'©2Þ™> ÂØ­Ú’‚PB2ÿ©û¦Ó}“„š°~ÉÈ?­·?[ ïG·_>ÿ¢—Ÿúõ'H'ª…ÓÎÅ.ÜÓ½BM-á@]ÔõNk¶Dƒ5‡Ã5r|;I¼ ¨¾Œˆó 6îÄ›cÔc"+8؈ <Ðpm'ü+$Ð ¨Ý††BŠœwT⪞j®$ê*(¤XÀyGA¥vj§¡P³¥°€CÄ!ˆÒR… 8ï (ÇF5bWH ¹RP°ñÁ6C¸:ÀíÐAî‡rCt€;¢ëH§`³OaãƒmùpÏw€›¾ƒÜõä¶ï÷}·+:ÀmÑî‹rct;£ƒÜǨ~P 5[ 5>ÜÎÜû"r[DîŠÀMQx@$Ô\I(˜T¨ l|Oj|ÞÜFy5 5B……"0’ #C£Èìl…!j|ajè«Pã“P°ñEÏ*‹Eƒ3‡ƒµíãv}ܦÜó[>nÇt j¦$l|qˆ²4 6B‰…b,l$jˆ %.– e#È@2Ž c$ÁŽ¿ 6[áÀ¸@ 0N Ó £4È .FãÆôšBÍ•‚ö™rpH@¡p… %ÓS„:ùj(Ônˆ ;n…„ ê†Â…ŸpÑ'‰4ï¡pœw@CœÀ®·'¸ëí îz{âz ýO!¡Æ'¡Pãº×£Ð­|Q®—¨2,hÞá ‹9©@Îæhpñ4àÄGE±5hfè)„‰˜…¾‹v¬šKc!è‡Nß%—T$`uÌ"×NniáФphJøÄQ¯×h(Ôjˆs„Þ”HO8$Üðž`ãCEl|°0Ûd¢LªD‚/tQã‹aG( …aŒ;FMí9ÊÂh(Ð5hˆ³ç(íÓ 4D¢ç‡Ó1 4Dâ7P0ê*õ †ú c|CÅ0¾¡ß@»ß7ÔÞ÷ µó©chgÐP ñi,Ô[CŽe|u¹Ó`XÙ ŸÀ‡ÉæÇ°çvs,Ô7Ð`¨IóGý 7N…†(.7™šˆÌLTX(3« €C„™Ùp º„RH¸¢.¡`¹¥8èá\\ê,.s¹a ÷ ävÜ- ›r¯˜ÛéLÄ ?«QH@(Ðd¨Ìª–XÀ’ŽaÇãgز^Á¡ºÄƒ ÷)µ'°wºWp°áxÀá¦áÂF½Æ¾Æ88 (/XCÆ©±pC„á†\,涸¨º‚ t…‡î_YˆÄ T‚¡F Û_€^#ÐiúŒH—é1&ŽíƒÎ[ 4D…¢òõ 0è0Q>ŸFCŽ:LØ(½i0µ+2 j#©Ð¼‰çب…^DÍÞ6…(-ñX¥fŽ›³Wψ+ïÂUw‹»€µ]¸Ò.\e°° X×+ëÂUuኺ€5]À’.\EW ¼3M‘·œ)òZR÷B¡Æ¨°@C|…žQñ„gT0á”mòŒÊ6yFe›<ƒ ç3Ên>Wš•š8taÒY,l·a/öϺý¢Þot&žI /§ñ3 ; (Ъc{‚† ƒ@8?f*â8-9vê…˜µ°Âž8¨ØÉ2Œ°ˆ3êÈ…æX¶¯Á…§òôE p²8AªšªÇ)*=þ% ЉoM‘þ®È#›™ ƒÆ°a$‚A+ªÂÄ"FÊ´£Å,v KÕ'YdÅa–zAÉÈõÞô€$Ò,«§tSo¾¢¸»¿ýãí×!˜$á’È1$‘pTÌ…ó=Tq”gûÞßÂ’ Ó+yìè¡<ˆgK5͉íàϳTMôž$¼ÊUr7M*Xþ5iT鉂³wš‡ÜfœÍ‹fÜ&S&aZÿ% k#[$&&‹¼U“ê–ÈùYŽ,þÊ@µAÛÀO…áGéEE ´1€ÆôKèRßóLoÎS1D™^­e!I‚Àž‹ ê ¶zt’”*¼„ÿbóö¹iÁetWø‚„Žz¹½× Uÿ4+ÿ'IÙ"àxòd]¹l•qUn SûmŠÅ…2´ÔïMåóÄ^èÏ÷‚)k,—‡“\¾‰ž™!}Äà„#ÏÎ7’¿K"ŃNr¤x<|ÕZ3…iè”{Sqhx‡‚ ž8g ͺo²ð ü’](Á¯ø¨¬÷0²jŒä5ÕpÒ<VMbhÕÊ‹XÅEüRr!½ g»Ï3R/d󲆴ÿ«î@¶ö”¹—óNDö„ÝÀ ȼU?=ØÊ›X8˜ç×Kx“8„îV sž@;%bŽïq§@ v]ÁʓãígpqÑÛ„ÂDWÄ)Ì(LàrVd¢€åùž+7./€n\ /)¶3‚ƒ/þÀM1ï‘,Í$(¡–X¢Â?ùs’ ¨ÅOWîœÐÙ„7Â@Ϣ‹°iEûÜ™£ðhÊ›$þ›$|Óysñ¦#4Õq-yÿù³êmk%êÍ‚ìE“éИXXãl2±_·¤…“pDçÉœ#GÏòÄž$ÒŽYJá É,KÝp¡ßý8zìH_ÎS©=s‘ÎB¤ä¼˵S»ù§N§Û œ%t"âG©èpøáý½å‡òL7}´¤·ëÓÿåçÿiaÇÎ,WK/RihP…¼~Ò½¦ôFÃÑèöËgüØ ‰Ú¼ÓñycP¨ïnï~Þ«c“{QîB1äJŽ$E*ê:TA·°Uˆ™‡.­DB˜ø/Ÿî,ÛUEó(.¶¸1Z1©ì2Á¿÷’ŠñE¾þ;Ÿ¯|/{÷–„_lñtÇöý±íñUcµbêáZ©bÁPH½¬DœZEo;ÁRã-ßK®m‰Œ3&‘¨$ðj?„®ŽêmÖ'…LÂÕ:&qü•yò¿ ‡2‰Šî…K™ä–éMžÙU°¸"Jg\Šyè2·>&ËJÆO® j,æá£ î— YmŸ6iÅ ì—¡˜-IBŸ¨„>Q‰‰"­1)zÇ*2Qà\7cEÀ·Üš*ZܙĄϔ˜ð™¶ID0ÕoòpˆÂðÁÒ†ª m®ˆ–ªÆ¢qÅÄÎüT.Ê$Y¸y¬,1ÉÏ-ÙéŒdш{¾]ªF «—™Ø~»â˜'S6…z¨ÀÒU<*3W8D³³¦J,Û•ª–z‰ ®¢(yX™:î$*¦"øÏfÊâH'ÑPÐéçDE²^™êj-ÕepˆŸi-xG^î'jÅHÓo%q±Xæ‘åÎØz«X„c†'Nl:MœÑ\À|¦‚ÓJWïòhño”`ñ&õvô¹ÃgÉ, °ÜÞÒçkƒƒ9e›DÄYS'Uâ «dØ Ì+Ó83Û Í“F9Cž+½.U'5ó´,®Å÷/Kè©H/¬H¨'yXø««Sü ¥ÌÂ9mm1°®HÊ4ÔYÊŸó¥ÂãÝÄ%>¿DŽbÞêÕØÖíÕ.áuì”vÂ(±WXÂÕNÞ!fù”˜¬¡°]/.‚âÙø›pÒÄRa‘ŽPdj 6Äæ+•ñUd²ñ-•FO!QuËÌA”ðƒplg&¤S„^Ì< vzíhás¶sTV¾¶FÇ:7´fvà&3û½ƒ¸zë–ˆ¤Ë5ñ…rmKÕUËz.Õ8ölô\Ž#úò S²S´o­±KÁÿ@LÃÔ“SƒVë©òÄ8Ê·.Nžd^aJ½¯^££¯ð虃š@÷YI°Î]&²HÛc$Žå­-ǃׇû8߀sh*![ÿ¾¼¸±F_¿Üu`Ês ”ûPð‚-¶T£dÆ0óÔ+q…¯"rEjÌL«òx†_S?Bá¨ãýôiqѽŒí’á¡cz.´NË«ÖNxXý’ÜLw#ÁƒSLMžP"\}}­üL­CΣR/B›àVÞ4ÀÀrBò.~Do¸ŒÊ:C]«(Åqüjr¥·J¡„.½oé¾rðI+jÁ1î ¸ýÙ‰Št83ò Å¬$XlÇÏEW#,´ªdYŸ6 [‡fÐ'BQ½"ÀßÌIçmL"¸øhzŒ÷Säqz£â![öx‹GF ¬ÌBštÝ7–s=²Í¸)²×!I8>/˜J«ÔIhN…œßÑZE·a8<~«äúЋ|òJ}3E›tWŒ3üÒdEìF”ËL»„\ÿa¦@ÂLq¯0‚^‘0#; %²“ÐBFªCÊ$‰pbF}s™#õœm?™Y“ÃÓ~ZFƒ“vYni¿,ÇDIŽrV)­ ‡\‚S‚§ÄÖJ¨Še\kŸwÀfŸ¯©¥Yü²,~I»ËH)–‘2,n –ò+ÕP&*¡8ת2EÈ?]7€^Øð9(:n#1»=Z{ãž…Ëê@¬á¹“‚eN WOz¤.Ø96IdÖtç¶y}Ç—ø4`îÄðçŸÌî´p(©K=·I½ÎiDâs Ü®Gêªî†–›úIî‹ä¨ðJʶx•c.’Äžâ¥Î«ÆŠÌt+È7£¸n¬„jÅ c·˜#‡¶I3áûÈÒ^úVàbËÓrP^Cï%‘J‚Ê«;ñð!iÍ»a6ömZä¶Ç׿堺’ÆI,u9FXˆëR) 4˶–°™3£ŸãUõaŒM÷_Säv–ÍZ;ª –¸4å÷ŒÓ±°ñÈ^¢…ŽUIšCÓÛr•1#ѨvîÖ<Íà¸ØìÌSjD”¥œ¥œ!ŠCGu âéIþŽÒs ͺ/AOlÏ'h_,ò ñ¿”³9Æ–;,ÒØ’¹—Ž¡p—f˜JÆÚFÔ«œaðXH“½L-IÃ)÷«"}O=ROâY7·ÆßOìò<ˆgiPóÁQ‰à÷Ñ% B9b ]Ÿs¸Ê%mùf* ‡f™ÆÆÖ­‚Ç ¡Ùw 8'Ð2yyÐý`BnBœÚqNÈýÊå`ÿªzþþ¡Ey ?Ç )Yc{]ÖÛ–ºfaœy¾«›æÉ Ôö­.šÀÑg¦¤áÌquÐÎÒ™€Þý.+9Ðq‡®nSì½zÞ$Ø3È VFlý™6žYµŸ…ð©q¬„FÃÊO—Úcu^·åYÉC“SrŠx|©WNnhu¦u}«UÓÌíkÔ° ÉV%^¤æbfÒÖàé4¥~ÒGÛ÷\uŠS?öK¢e ’¾{R;š‘7”ÕŠ­vp±R ‡,þØ¡YÒ˶Úó¹»ÿ„–(Ýþv2‡Åßb帼 §Ÿr£° -WN!Qp.'s‚ ›º‘äØàÚø4£O:¸T~ ?ãäÐèÏ*Ebމ¢µÜÍÁ÷®‘ŸA#dpÖDJ±Öœ™•gî§S\îÎÅHeиX÷ ‰NÓ¸àH‚Æ\Õ¡«@(¡ópABr:ø>ø !±A•’æ·¨¶!)Ã`øC„¾59,ÛË¢Lp,Ò,à=r5öòõdü5S¿Öи¯]4r](ûSîw¾!çhÜ+Þ©p°ù42Ñ-’àc'?nðslכЄP¶"(R‚ ž$‹Ô›Ð+ó•~¯>²]¼±ím<ÊÎø›yà"ì‚BÝ)éqØ+WÄTe(Î)æeZ@dÉ@H¿(ÐÃ0×°÷ÒµÓ½\4–‡Ô ‹´ÓŒŽˆ®ð3ÂT”p)=ÁëãèÞãl!Ü£{tt'{Ë-I¿-åûø˜ÒãURäè!7?pER¼ùA€Î"8ÁõíáC3=e¡l¿ØÏÎüéìùê·“Ôø«àÒÜNRµht;3¥ðu€z2šrèÐ v•üˆì²/î4T´ú~â_õRLföÃ2K‚@Qº”$ G±x$ÂaƒU¸“La›†¬(¼iÀÀÖ7…¼Õ•?@θճBpE©D_cgË]>Š ´KC}’Ç·¡]0´Ú7h‡Ð58þĸ,NSy‡hÛ¨óÅ¥ã\ª#ª^ ô³òà0É'Åïßk:ÁcèñXôíž\†.jlߎçŒ]àSRgT?náÃB ÃX¥¢I×IyøÈ5¶&àÒÿ¦É/ᡇ†ü1Fõcþ¾³ð.g Þ/®0 ï(O®ßÉߺp,'“N‚<Áv¼BJx‰Ú]RÀá¡59䓪\U—¹ê¥YBOŠü9^%㹑âÙr=í…‡ü¡ü,c}Gúj{Ão+xxÒβ¥5)Ñâ öÍÇ^õKp¹Ö£dYí$Ïaqe“Ä#àÿÏË2ýS‘¤®óßþ›â¼¹xÓéi®ÿ}ÔP¢õ¿>w.,Ëyz²ÇÞc§3°¤ÎrÕò‚Iøþbøø?þÇ»ÿûíÏ·VçM¯É‡9Œ°cš°Ë%¼²,;ŽígssZÁHžÔ Fþ¬:¾­Œ“ÁYÝfäÏê6#V£±J$79«ÛŒüYÝf$Ïêd ½@ùYÆæµ’“<³•œÜ¹íÊ¿^†ƒŒMîRîìî!åOoâ¶´{HùÓ[AJžÞŽe=ÎÏïVòïa%ÏpO¯מ‹ •§tcs¼——<Ë{yÉó\¶ý¡5ê]:s³ý ;yÎ_açÌü4Ȭ ŒçKë£J BWXʯéÏÂðax7º°þÇÿøåãíÏ’Ùê½éÓi“… ï%í¨c–yzÈFY¯b¡B Â0íµ~+q"bý…SÝÉÙ]1ΦҥÙ©Ç©Š†±¡Óµ>å ²TmÊr%EYíepú~NÙ±üä—ˆ4•£MzR·õ°YüuÊDRîŒÃz““JI.5i€Â¹ç¨" áÝž‡žÕ™Šî„¡¯Tè°Ô»túAA¯3¤Uf÷pnX„½¸&ž´1\êkkUó›×oð¿÷u’º^h%ÏcÉÊU=¹uFi§£z¦XÒYòÒäÖûê_’?þÁ²¨?AYëGs™Müpq*Ò žÔ‹wÁðÎñOF (Sýv*]%B<„“ÉЗÿ²k݆‰4èâÁõbù÷=ý÷_"ÌuâÐÉ…Ép”ö'òoÕ<ë´+ž¨Ôס<Þé¥á†@7‘ê<±=ÿd$Ry™ñ)™wáݵuûÅúpûqx""uON¤<w’tÚd±-É¢=ÿ R–¶üƒ*aÚóª¤Yù‹vã=þÁ©HtÒþÁ^OÚ?¨’zí|; JþÁ©HÔªP%QËþA¥HíúU"µãTJÂöºW–Ê«ÇcRϽ@U¬í‹~o·æäAšÛã‹á°s¡£°I‡ÏÛãņK6iUüYU{¶ïý½ãü0™:"åø¶7ϳånš^TôsCìv¾vg÷kß}x¼{¶F¿5ð‘y€Mgºížçšœõ5½Ó¶¦w;kM_ÎþƒxÞQçÿfh/>üvЛE§îÒtÙC¿~{%3XýkÕãE=\$#£ôfõ¯îî¿7²W¥éhi²È±“T‰saÝýöxÿYþoçÒ*þ¹RÌÌO‡' Ûz§Uˆ®•’Â×3£R³±õàîjÎF=ktiå3'Wñƒ–¦®›+™zœÍв±ï9V;C_Ê©åu-¶D[©Û-«ý¶4—ëL°•HZ½¸’T%^«k_/YýóîÌ BÅt¨”݉²§¨:{Z (çhõ/È“Tc¼mŠÚúSÃÜ~v ÛÏ="ïX¯*‘·íYGÛ³¾5XùHÌڳ꡼hÒö| ²™Û“)}Úz²GæïRQªÇrŠšòræqÛöw#Õj` ÕËãÖ$Œçv*EÒçà⮡«g½WÒš'SuHC' ÏÛs¡þº/e‹b9uò{ åŽ9m Õ½X %UNìEjÓÊE3.Wo%Ë"ŒÕü˜ŸšË•ò„éÓV„¸Z&—ÙO–/‚iºÎЉX¾&‡:{ õð“¿ë¬ú¼œÍC$P Ö±ýì­‹á=eUŒÆUaê‘­bÕz\/ù¦¼Iu¸©—æùM¾«÷E_mÑáD±ÏÍNþ.«HõëZ­J`úô4ûÄ‹ÛÒ€ Ú•  ØÁø7Èû4û¡£,3a'x‘]9y+ùb'žÏ·]fx&'b°¶AØÒr¬–¡u!ÚX”»R˜þW%³ÐšFì¢})ÚЉ 1 ®½}3Æfì‰`ûî•MÙ·îE¤+€¼DÚcûA´*A"ÿ€y œ0zÞ™^i}×NmÓCä!DÃKiMÛo æ+'6=Ëq ö#ÙMVas^ŽÅÔ L“:*ŠfšTÌ£t; ŠN·c$J¼­·`& fÃçÍiÒè׉ÁK¾½\øAU]–q>Q5“!*švïRqf¯ò Ë(•).Ú§ªà¢L éz+a]b%†®ªCRIqíÄQYÚåR²¼Ë¡(圇ÎZ¹9:gZX7; íþ&áÝÒ$¼»˜„wã’¬î7(*RB'³ÖNO™âuGB¼ÔHˆW ó‚"a^C$̈¤t¥@ˆ´&勃„‰¿{äcPtg#ØNž$mÍ£`Çìnd>¡Æßj”=áÆÒNÄ<í\ŒmW×zn1³wZ#Zîk]¥ŸÍîö–ï-/ÿYàzºdn»B«ƒ"÷ä¦#ÿOØóËØgÆ'’4ª‘K>¨Ê¹Ägâ9RQö[§hUˆiQvF\g&¦9;NÇVò<‡„—ö‘º¡5Ã,RÕŒÆH'±í¨×l½41F*—¦ãÍm?¯O6HZ-(°¢mA‡{r¨vê=ª÷4¦”í¢šVÕk6…Ybnb%œãP%m_µŸiÁV(Þ6Vî@õsheñòÅÛ‚FòõÛ‚R+æVôúÚè>ÔiÁ³è´àYtÚð,:mx6<‹N;žE§Ï¢ÓŽgÑidzè´ãYtÚñ,:-y–<‹NkžE§5Ï¢ÓšgÑiͳèõ,-Ä,-Ä,mÄ,mÄ,mÄ,íÄ,íÄ,íÄ,íÄ,íÄ,íÄ,-Å,-Å,­Å,­Å,­Å,­Å,¦c‹b‹b‹6b‹6b‹6b‹vb‹vb‹vb‹vb‹vb‹vb‹–b‹–b‹Öb‹Öb‹Öb‹Öb #1‹ÐLÞÈšfÑ*XSÕ­7õæ¢úäí¹Í—&Ÿ’4VÍëª÷ÜrÚdxgXýãÄ7zÄωeDZxôäà]Säº=¹žî6†®ßš’ë6µ2x•„e©*w‘„w¿uSJÝëUñ¹Mòz¹MÞ¬>ªÆE¥±"4"©æÝ6Vƈ·W¬â}ÆÊù~ce„}¿±2A¿2V ÕêÆŒ±Zl+£Ü0V&7‡Ñ§ž³?õDÓµÔ£ ^þ6¯Úg¼Ä #Arô»+¯Tz¾TÇ´§’ÐÅ“#ôË)Ô<ôÞzÕãÆÎv‡gHžÕ-*^7"@þi+g€yØ9€~ÏøAí#êŠ@Ÿ‚*0øjh ë ¼"m ¼ø‰½¤ã§6„Z‰¶)B,'X¹yì}³_Lw[6ï~ö’«)L›½CøMㆯ ly%¼Èoè#*ZZ /ò›þæWBQ|*øÓ0~î\ˆ¿2ïÑöå–§êä7*V=RçK2xZˆË­Y3‚ì¯ÐeÍÄ¥µ>ÿYQwzÛÕ«Ú¥?£J–•n¾[=ŠyõuYœÇO£ ëÃãã°þÜ'eðæKruä¯4ŒýiÄis(Ô.ÿ¥ÛÎC«´ü.EÛŸ@?’Ü¢ƒ©HýÐ1$AÕÎhrVòTJïÈä*¬ å/`tV `rVhŒ¬B/˜î±#[ƒ©%\… ûp£Ép]–aÿy‰=µÄ`ª9‘ÏòÂk?¼ù¸Y2[UzrŸ‘T¤žf$<9Pã3ÒžŽ(qFzò”ÛŸÙÉìöþÅwC†Ž? ¬­ ÄAˆDSuéT¯Ž¶Ï!kÂæŠFpXVžKÒtn)N‡Jóê({\zªÂXÍw±=(Pð‘¯—Ž WªDà •)úáBÄÃ;‡“:YÍf‚)‹"ƒãÊÙ¸L=듵ð\X^àÑ:®ùú’/°¥Þ/Ì^Ë™ÔãS¹ÿr»»£NçšJs£Jpô$£r¸Ã*ñ9D¢E®ø‰cKmL†éÝo Ê›„[|+sµà$OV³™`*Ì•¡qål\¦ÎR?‚05¢ *·Ö ƒG§rˆÖbn'ÔIy)‡(µ?Û ª”úÍv,°!6ª¡Ú°À ¶Þà[0ˆêé4_t=WUex”W–$ýÀžsâêøK%80ì•òÕÇôÖqTþ|œ¤º”#7Y̼I:¼—žü#Ï(÷Ûç¶Ê<Š@þkVÅè~jU\¯úÏóîx\ÕçÚþBÕô¡2×fùµ òï.m\_~ø¾Ò€ü‹Q Pfé)ˆ¢LV¡ kiõ>+ '±(w¤0·(w¨M.ÊrËr›¿zQ. ¬„mI6åÂä¢ÜÅä¢ô}É©£Ú‡^=ÄqÙ7U3 ÂüÿÈ´êiÃ4¶ƒDUuæQ"öÔvÕÉkMi`ru0ÑÓ•ùOx%§ÓØønL~¸Åö2$œ77–áÂÈ7\ì,Cý .ÃÅî2äOîrò™®ÌÂÒ2äïÆÄ‡ ²¹5©¾¿ñVy_–—ŠX=Y^™†™GËÅ“ü'N*}™ôöÛP]}åÿw?J¯½0QÓâ^×NßÊ¿“ÿ¯¶úû¯§< ÿÇÆüÇFúc ãéÇÆó÷9ŒAi?´Óá!C`¡-¼ŽØ'´‹×û„6ò:bŸÐ^^GìÚÎëˆ}B;z±OhS¯#ö íëuÄ>¡­½ŽØÔÝ}±OìªBØÓƒ6Æ©ÄAãTâ  ‡q*qІÃ8•8hÃaœJ´æ0N1Zo'% M=D‘d¦ž H2SO$™©g'’ÌÔƒIfꩉ$3õÈD’™z^"ÉL=,‘d>¡“ÒéÄAyrŸÐ~2qPžØ'´‘ŸL”'ö mç'å‰}B›úÉÄAybŸÐÖ~qÐ(+·áÁYV*µY¿©B$*k|î”…¿sF7Ö½wB«ö^¨êé€gYj‡Ài.ñü»“øé»“øùô%î¯^ÔÓKo4PE\W§µâ.×s«E½u+g÷´¦wGhqúB÷ÔKvÛÞýF;T$¤ž@òÑŽI ùhç!|4W$ÍçÉGóRAò;ªŸó´Ý¡ão:¡rs<¥-Q?ê¶zŸ'd®÷‰xB{Ÿˆ'd´÷‰xBv{Ÿˆ'dº÷‰xBÖ{ŸˆT¾Ø'bu¶Ân¡êÙob:{×þ ÏM‘%jÇ*,ÊV¡½Á›·{8ÙöbaÆ^,¶ìE{_¶K²`[é¸EYà¤Ê‹P]Ýu—ÕÕ}‡-3A{:cƒMµ³Ø~bˆ®ç Ǜ۾…êŠÏ—ÎÂ,±7±ñùÔ¢4RþïU±Oή)¿QW¸®l§·ï7è¾y2®pÝ1œ +\s/¹Â‹ïçKœ¦+\o]áÅ æ´\á#dÿN½†Óq…aý-òcÞègFå ^T‡w E¢ó%…Ô"åvýíQ¢žÔŒî/ IúhûvÛÏ·óa?ñþæÜ9ݨLaÛ÷C‡™*,Yϱä¬U®¬Î…xrD”za°FùONB+¼"œ´Â›z4mz‰·¯ÅÛ!öüvˆ§aØŠj]Æ®4j­0/¼™‡x>*1oƒ¼ý8¾ü&¥T 5ŽÎ÷:ŽÒ‹ ãSnÆ5ÂÑboviÿ®f¼–èäI¯›qª6§Ñ8NÈæÔG ›£Êýº­¾ÏÀNj%Ô3?§:ù§b‰Ž¿ÕÙÙ!•Áƒ¥<©‰,Ý=œö\îô¤¦ófÕ\pc<é™Ý¹Ó–ÌÇÝìm¨Â¢(kç›Z”ÀdÝ=úò»™Ö½2ŸÔÌ`Ny’0&Ä—âæ3CŠ+’Aä„+°”>GBNé$”'Kõ¥°Sg6¼ûmdÝÝ=2Þù+1v4c©^’ò³Áyz²ÇÞc§s%ÿÚ·“ÄZýùáå-Ð’@}Ëò’¼XYħz¸Dw©é&ªìÖ Ÿ\Îð]Gõ7gÃ,±IBw‰BwIB¿gÍÆ{ŽÄ ¢n,Xº± êÆ‚¥ –n,8ºñBO&y«2©¬™çŠX~ä;µåvðŸãpº-ÉðÉò…ý`ÉI¸Ð|…{¤ú±I!sÒἕÑ,1Òg+fôÙx‘»§G=ë.t‰üøŸo,kdÊ{PŽC ’àýµ/©ÒA»–ô¯ÍÎQ]9•7«å´,§š°Ë–eÈ]{£2¨ú"©Í¾íËΞ†óù^ñ¢—%{"¤ª¤Æ¤ ][Ú“„=¶ž}ë^DúæÅÒ‚†ÏCãæ³$‚—Dª`‹"Äb¢V^[AÒ»vj·Aßâ&–  ÞJDªýÑÊ2¸,$H䟰Ç>![çUºåÏ`%r+´§¢"róS¯K–d°úÁ4Yvà®'fÓ*¾¹425/ døC]é÷ ìqn¬ {ZÝÙƒÂ^ݨ´7ÊM‰…Jk›ÏÍÛìØüf™,ìhx/ýR“¬—c1õ³#½t|Ui–Szþróíü’_NV0Ãç•B¶¹ÑÕ?°£H->BÉô´­ Wš8³+ƒ¸O,ÿýÀ ¼Ô³}ïo[¾—¨¾˜›Û§cH³GÐ$Þ40¯æ+Zß<çmAÍKĦÕ<§>5Ï¥1¬æù-ò¡ûÛiÌT-™Oy>[ÑìäP^³ë{IlÞ¨m0¶jKnÊ·pRÄB·J0;ÁKR£ó{¥ŠžóK Ã!˜mr³ÃÖAÑ;ã³­B‘fÕY±ÎÃGÑÚ7.“vqÓsø!ûó¨o­/3oŒÚöúÒÞoÐððQ2µòõ%4îeÔqti:X}„ŒúÿN\Æ“8՗۰˲”onúȱÉ܎ݘ›?vls›=x”Øë™<ñ<>¨üe°n±5`º³¶MnvØó,ÍïýÌNx”%3kl;fã&*³ó7ó‰…9­ù«Õ<º N³ÆrÉiV‰×¬mLò¿eW¾ó"¥i![—’Šÿ"ßíaÎÙpøÕ’g°&D£5û öœü²òn;v½Û’]ï¶`×»-Øõn+v½Ûž]ïž”]ï¶b× ×þ¼ëžº]ï¶j×»-ÚuJÙK|†uÏ™NJ‘ŒÆÍ¸ä<(›Äèd{OfãÑGÓê$«“ä< u’‚à'ÛUÁÉx™7å\u‘¨ì.CaÇ[@W9Ê-މaÕÝ÷TÊüSö5o£ÑßÝãpx?òî¿ny©ˆw(¶¨ÆÆ˜\cLÂÓÄÓ7cL¾1¦¹1¦ÔÓ“1¦g&“nvyçøxC·D†7/ ï[ÛkòÓ&€LØõú‘Œd2¯/gÞå(p?y†Ì—‰œŒ©ôÇû“(LnUû«ùXw4µR‚¶tþhÙ>u¤^õbS*|J™², iæÀ›a,†› „¹À.ÓÄöxSòÈœ’G¼Ø‰ÒøYÝ0޼1aZ ü. ÿJj¸ï‚cÍÊè„ã*ÊRš@À¾V6> 礙i5vàQb^«±;ð(±;ð8±Õéƒ4>#‹ðÑ ðuÕÑ“æ•ÇÖF=y{ËB²ßã;—渄ýHÁºXx+ävÂ%¸X ÞT7‡%ì '£aá-ÜsØ”ûÄ}†Ã†º¹;Þ /'~–Ì›[¨©‘©Sñ’Ž*õ©˜ÑT,¼\Ä^*½âßnqX>N…<ø.žâÝ­ÀN^¨:[1¿k©uþÝoúþ)¤„–ËDc34®a†Æ7C37Cód†æ™HÓj  ¤ ÂV!%PR!g+áì!~~È‚%89P°¢i#P É#}˜ö–›dÇÇ *>L PñQ…Š(T|Œ@¡âC •àTJT|€@¡âã P¨øè€BÅ’Ý—;Ôkzê}:W—ÌÅ}‰#Ù~oƒ:nKòdç¥çÕ×3œQ"wÜ>>s¹¾0#KËBÈ¢®EœPÄQÁ$‡Åà©xÐLªŸ­pð;CÂyœ"!=A‘T>4Á±•J°©xG$&ž‡HÌ<‘zê!1ö CbøÙ†¤Ç¢¥Lmù¡µˆ)ûÝîƒ ŠŠ`^+N Ù&Ò ÉòüÁ$¡½uÐ^4H|@;Ží²S–ï‚dÝðŸà©•À‰¢3žhßDgN|e½¤C©—\q2¼òuK}.8åS¬šãSiÎQ¤úëÓ©è¢ÏøÖövÏÍ­ÉA׬í‰a~™9g—ÐˤÔ,ž±ÊËð”e¾j8Ϙ{Z[ù„×<~ M˜‘u/vgGAǽm Æò¦î¤ù!µnOÖ=Ò©s_¦€áЦÁËCÃçÑ…µ }šG×—ˆbä‘‚rpŒ V[ ÎîU[ õ'㪢¾ úÿNAƒžhmá(;d¹û7Ÿ¹öæ$Ÿp‹€á–»s¾«çwRn®íl Úå·)C véNJ½¸ W·¾æ¥äð¼Ø{Þ㙉M0 0CYVÐÌYÙ³ËUQ¢6;Õšª¥„Ì ©õÖ¬›wö-âèÔ™B³t¹,9I‡HÒåZ«.ÙZu‰ÖªË²V]žµêÒ­Õž†ÍdkÕ¥Z+Fr@›e3ÖªkÄZu X+JGB)ãHt§c‚™÷3&˜¥}M‹IKZÒf‡Ò€8Ñm† ÒæÍ„ ßr_Ç`Ò·”tøÙI;Òdfs]¦ÔéX#KÍybyAUvÚ5’¬»" ³ªúu,Û¥d›¨­!µ&~h§J'ÖZwejǶk¥Ï‘ð8m}7f{“aÂ%ƒ£àõg¸´}ùÁªt¡aZä6K4³é,NÆ>Åõ¦^åê²Lc;šÑYüp!b:K{Æ¢,pø,I¤¨l–,ŠøßeðDTe¹-Çy-iOþÇŒ­9òð¡ |¡â‰qЇÑ5ð=º&¾G—ÿ=ºüïÁr†J $g¨Ä@r†æa žs—õZº¬®˜Ø™ŸZ‘¦"®tÊû@N]¨²ªÞ\±:÷xÍ{½< pΚHïÈ·ÎÇñÅpØíë†(˃›µþÃ;yT°üб}aåÓ@²;B)SXEŽ?kïc—ÿâÚ*M†åØÎLÀ˜†ˆº­Îv÷4f»kˆˆeòw‰H–—ˆ¹¬ˆ:§h«:­ÚªÎk¶ªcdõtLÙªN«¶ªóš­27ÛFlUÇ”­ê˜²U#¶jqŠ~Õ¢U¿jñš_µ0²Ó/LùU‹VýªÅk~•ÑÙæÛª…)¿jaʯZ˜ò«§èW-Zõ«¯ùU #;ý”_µhÕ¯Z¼æWm#¶ÊŒ_µ0åW-¨~UhàºbÍ1˜ÄBü-/7ht¤ß“ÿ¬§»É‰D0]| ËmRòì逹ñaѵXCzŒ>dÇè;–•zsQ°†ÝÞ¦±úw{ _“Dµü§W¥º Pv˜]z,]† ê6ç—ã'l±ìÎ6 Çöl³°?‹“²?‹öìÏâû³àkîˆýY´g/Ø3ókÀþ,ŒØŸ…û³ ÙŸÍ6ü]ñ×ðþ7g»”Sûw`‹‚jad`løùáÔs,Ça̪Ýb!Õum²°k™‚´RˤeÛÁTÐ?z™…÷ÑK,¬^¦à|ô®eåÏšL<_9íÝ £ë.O_ýïöc墔 ®0ºÙáNDÿH{ò8FæôÒñUëpTƒ§d*Ò€”—YÁeiÀÊfݦ»R¯L†“‰w&wɯ“çÄÊöÚºýb}¸Õ%]ôHÞ~9ŒwèóOnå)ÌÒ1ñáo’Y¸˜ÛÁ³™õšŸK£t ÛUOÄ“Å8ïðvÛá5´…‘|—nQòØóå×ãœqw˜º¦˜H~Ì I¶iL(˜",Œ)-ä°CcBhA‡®Îm/`g6ihç™ Ö÷ßà }üâ¥öWÙ á}•2 ë«lp¾J˜¥V8±ô‰–øU6hx_¥LÃú*¤¯²º—gZ^Ç 3³c“(©üÖµL¥Ú«aq*!7©öžMœÒvD‰ÂDOûù¿·*Ö?'ª£•š9´–åQ!ÙêÕJÊÌ•T¯,Rÿ]pΦ|ᣈ'~¸ @Rmî!Ì­uxçÅW™[›m3'ËÅ6󢕓e¥mœ,+iådY)I['Ë*aöŸ,-iLÛ'ËJ™Ú>YV ÕæÉr¿<í,+e2u²¬"7w²¬doádY%ÇêdÙ–AY,[ 8Y¶%ÁÉœ,+…;¥“å^OêdY%åúdù­J'˶$0z²¬”ÀèɲJ3'ËJæÖÎ:fN–•Ì­Í6ùd™ß¿ŸÎÆ«ò´àw¾ “×ïö+¯(©l‰?O<õ(ŠNG7Èú%æî)}—î©}—Ö,*yÿz‰¹5]4³LÜäUyÚ[ -….^`7¹íñ¡OG=ZÝ¿Z8a¼ÄÜÖþµG˜û.­YT3ûW 篗˜©³í½Àܹ°>©{šØvÒÛ»Çáð~Ôµî¿nuj»iGžñi‰ãž–8â´Ä™œ–8ßNKÿ´Ä™Ÿ–8éi‰ótZâ<·.No*Rî•×!ì‹éï忸Ìÿ쪚Hþ饞°¹P­NU›ä-¹QýH]ˆ¶E®Z¢µ·<éi/‘_ªëÔéžËÔVE2чñiRáûÓÖ>O´¸*Þ4c±•®ˆê;]K€V‡O¼A?„ÿ±íélgø‰ÒøY…ܤ÷ÆhTCˆn›B\Ià{ho*KÐ’{re©În‰ÿZy I8oñ+‹œ’Í?¿ÈÜ=½Éh- É ú¾ÈÜš´ô“áݵŒzm©Z!BzíIYþq1ê·-ÊMñGå1B¯ÁÑe›˜i"Ýßµ§®÷-y.ŠÚmšxùõ¤=jb)ékÔ-”uK>™¢f´ž<šÑèö@jb…ÂkÔOíQ?ó¨Ã—‚³ª,‘xòy‰ûrâgÉŒél½È® >ŒG(É`„òEiT„2jíó,b/ärª—Ø µ+C·}¸ç±C Ë^@5hn[oô¸‰ˆÓۻߊt î½óÒŒOH÷„d'$‹B²ÌOH–§’å¹mYZ ¿"RK&¿¥ ð+"µ4Ü ð‹Ì­)@{Þ†o&|€¦‚À‡ˆb6üšD¿µ¨'f–¤HÄð+ÌÄð+ÌÄð+ÌÄð+ÌÄøï+ÌÄðï+Ì-÷$31øû 31öû 31ôû 31òû 3%ðgAêÍûÝÂ-Úy›<,t“„äzn’p¼Ì~á,LƒÃ2XmyˆPÄéCè©5Ò‡`®Hú@iNL?HŠƒ¨ÕI(Í©}šöl+iƒ:ˆº=…4´™íï®ÑÒrØ/P‹+¢òJÕÜfV™hmr3Ûá>iw33n?ˆºµÍl4§öiÚ³­†63ƒáÿƒ¨¹~JqÊÔÚt¾Š;P¦¶¦ƒ¼[¸;ˆš:áá©JÈüõ¢P|ßòEz¾å‹÷-_“æÄôƒ»¼LmÚ·|MšSû4íÙVîfö2u{ ih3;•@ɵ¸"Ú ”¼Hot3;‰@ÉkÒœ˜~ÚÌN"Pòš4§öiÚ³­†63ó'³—©IîH5rSküØsqë8›Z¹‰bäȼÊÜm‹™¥`¯Ñ’”ë5Z3еhM±v˜)Ö6³!ÅÚ¡5£X;´4Åò}ŰÔg®*ms1•g‹‹§.ÛD4Ù&2£ ƒ*±0¨ S*±0¥ šJÙ\ÄÒ©ò½¹ò Þ{ÃÎÅÌN,Wa<nyÎÍúSŸB+™ãP½eçî¡åŒVÒªÇu§"6IÛ‰ÕP­$}ö…ÉYîªë/ðÒg“îÎí'KdÒŽ™´ãC&-ùI[>dÒ–™´åC&­ùI{>dÒž™´çC&-úI‹>dÒª™˜ö!Ó>db܇LZð!“|Ȥ 2iÇLZð!í\H’Ù/¸ÄQîsy”ûÝFÞ̾à2òú‚»Hé~W‘Gú’›È›ß]D"íKî!oŽ_t y´/»…¼Y~Ù%äñ¾æÒ˜«\AÚg­ri#«tiCÛãþñøª]?Úlîsû¨„U.•°ÊÝ#ŽÍûzcó¾Þؼ¯7nÁ×·áëÛðõÆmøzãV|½q;¾Þ¸_oÜŽ¯7nÉ×·äë[óõÆ&}½±I_olÔ×öõƆ}½±i_olÚ×›öõó¾žcÞ×sÌûzN ¾žÓ†¯ç´áë9møzN+¾žÓޝç´ãë9íøzNK¾žÓ’¯ç´æë9&}=Ǥ¯çõõþžcØ×sLûzŽi_Ï1íë¹æ}=×¼¯çš÷õÜ|=· _ÏmÃ×sÛðõÜV|=·_ÏmÇ×sÛñõÜ–|=·%_ÏmÍ×sMúz®I_Ï5ê빆}=×°¯çšöõ\Ó¾žkÚ׿}=aÞ׿}=Ñ‚¯'ÚðõD¾žhÃ×­øz¢_O´ãë‰v|=Ñ’¯'ZòõDk¾ž0éë “¾ž0êë þž0ìë Ó¾ž0íë Ó¾Þļ¯71ïëMÌûz“|½I¾Þ¤ _oÒ†¯7iÅ×›´ãëMÚñõ&íøz“–|½IK¾Þ¤5_obÒ×›˜ôõ&F}½‰a_obØ×›˜öõ&¦}½‰i_ofÞ×›™÷õfæ}½Y ¾Þ¬ _oÖ†¯7kÃ×›µâëÍÚñõfíøz³v|½YK¾Þ¬%_oÖš¯73éëÍLúz3£¾Þ̰¯73ìëÍLûz3Ó¾ÞÌ´¯÷Rëg’Ö¼Ôö™8Jþދížy3kÞ×{¹Í3q¤Æ}½WÚ;óæ· _ﵶμ9nÃ×{µ3o–[ñõhãLc6èëU·o¦Ì¤¯··m3Ϩ¯·¿]3•Р¯·¿M3‰ð›y_ï›y_ï›y_ï[ ¾Þ·6|½omøzßÚðõ¾µâë}kÇ×ûÖŽ¯÷­_ï[K¾Þ·–|½o­ùzßLúzßLúzߌúzß ûzß ûzßLûzßLûzßLûz¾y_Ï7ïëùæ}=¿_ÏoÃ×óÛðõü6|=¿_ÏoÇ×óÛñõüv|=¿%_ÏoÉ×ó[óõ|“¾žoÒ×óúz¾a_Ï7ìëù¦}=ß´¯ç›öõææ}½¹y_onÞ×›·àëÍÛðõæmøzó6|½y+¾Þ¼_oÞŽ¯7oÇ×›·äëÍ[òõæ­ùzs“¾Þܤ¯77êëÍ ûzsþÞÜ´¯77íëÍMûz/=³KÒš—žØ%ŽÒ°¯÷âÓº¼™5ïë½ü¤.q¤Æ}½WžÒåÍo¾ÞkOèòæ¸ _ïÕ§sy³ÜНwÀ“¹4fƒ¾^õS¹´‘™ôõö>‘Ëã3êëí—JhÐ×Ûÿ$.‰05ïë¥æ}½Ô¼¯—¶àë¥møzi¾^Ú†¯—¶âë¥íøzi;¾^ÚŽ¯—¶äë¥-ùzik¾^jÒ×KMúz©Q_/5ì륆}½Ô´¯—šöõRÓ¾Þ¼¯·0ïë-Ìûz‹|½E¾Þ¢ _oц¯·hÅ×[´ãë-Úñõíøz‹–|½EK¾Þ¢5_oaÒ×[˜ôõF}½…a_oaØ×[˜öõ¦}½…i_ïɼ¯÷dÞ×{2ïë=µàë=µáë=µáë=µáë=µâë=µãë=µãë=µãë=µäë=µäë=µæë=™ôõžLúzOF}½'þޓa_ïÉ´¯÷dÚ×{2íë=›÷õžÍûzÏæ}½ç|½ç6|½ç6|½ç6|½çV|½çv|½çv|½çv|½ç–|½ç–|½çÖ|½g“¾Þ³I_ïÙ¨¯÷lØ×{6ìë=›öõžMûzÏt_/|ñÄ–ˆã0~×Þÿ6Jv™àD]CDï/†X:–K룗¤VºÂÛ‰èÏÂðax7²Lp% ;ެх ºAèÁ™˜Æ«Xȯ—#d×rw ’‰Ûa—f¦­?¶AÛmu¾»íÍw·•ù~ßÎg~ßÎh푹ï+þ’\ŸGÖ–ÃQ×} ÌÒ˽Bú}‰·=g“[GþÃŽ3³cKN»òá°seãDˆ‡p2úòt­Û0±FòŸ¸^,ÿ¾§ÿþK$é¤ ÆVSKÌ(L†£´?‘ÿ{ÛéXÖ|œ¤v*¬tx2²ö‘N‡wΨgÉÿkSŠ(—¢=ž‡ãB9góhèµÆïÉ¥–ü(ø¡cû­iäeÔòL$S‘¶© Š?‹ÁoO‚(“3à´Ê/gà·§ S‡Ûö”`¨EТ¤E–ÿ®M5$xjs%’4L’mÞt.LÊðÔº9"´¾¯”GÕê}uú~çÕwâs^%YÐî{í–ýh{~‹",#¨íy:×rQŒÛwmça¢¾Ikr£Ïmmï{7É,\Ìíà¹År£L¾ú -º7*ù%n×˨ÝÖN¥ïH+qw[{·½±“®Íãnñ›¿oqÎóàª}[ló/N2ºø¢˜'æéUÉZD梋û¤ˆr)ÚÁØá¥ŠÞdt±’¿7³RƒÑÅJ~ƒÑŽüò,¿0âÞVK £‹‹VùU4£Å)0]¬â7]¬ 8eµ÷ ŒF«0]¬”á©us°Ž.¶'ƒÙèb¥§ïwžbt±ZN“ÑÅ* G+EXE¿µ&B[ÑÅ*aJÑÅÖ&¤]lÏÖ™Ž.V˰Š.¶æšŽ.VÉ`2º¸‡¿½±Œ.îáom즢‹•Ü-~sSÑÅ*n#ÑE/˜î‰nŽlxi}²²ÈU.“˜ªtJî|¼*Ï•”gõç,UkØ‘{Mžü3¬R™Ã¥0• óšús©ƒÊ3Ÿ·+ɉX’óTN-¯ k*'à59ŒÝÅ¿*È>gõÍÀ¸(¦üÅ×)jOKs¥P'&P÷g©{b³DwD_€íTx„R€EkÙ~yNÅ#Û+áÒ#Ë?Ò±¤G]Q˜mPSW ¯É±vÍf\³ý’œ–kö²œ'æšíÖT@õ59Œ2_ĸk¶_îÙ^Ar×lmOK…ÛòÑö Ô=ééjÉYÛ+)gm¿$gm.’ÄžŠÄ?ö\H¿PªêÝoe­ ë$c}Ä &c_‹ÖÝfZ˜Ô‹…I½XÓ‹…1½XÐô"ÈæQ8©{QAÆÓ‹]2–^T0‘ô¢‚É^PíE™9½àÙ‹ &CzÁ³©7ÖT¬5PþÃou]hy©ˆí4Œ+«˜:ÔP0ž¾5Œ¥› ¥"éqC© éübŸTUwå&u¾¦`æt¾ž`¦t¾¦T†t¾¦TL²Í•žŠ?^0²Î-Uç—Š©óÇKeHçû¤jÅÎ/˜9¯'˜)¯)•!¯)IçWá~vÓæ&Z׿m&–šmÓpôf`Y«Óc;3uè¿¶>åM.¨â–Â0%•T]cT$©¤2§'$£±KµhQ%æTraN%iQ©J*S*I‹K ¼àÑö=ײãi6AÊÛÈv©h;ÙK'vx8 qeYÊ Ú4R®5Òÿøï0ÕO§tºf’ݨæâŽJ.’–TsÔ’í¨àZ´¦•´Ý¬šË˜VÒö³j.cZIÛÑ®æRñž7oû>Ž/˜q†ý”´Â^J–¶ìå#iÌ^>“ZÓ1¯5óZÓ1¬5ÃZÓ1©5 ó¶faÞÖ, Ûš…a[³0lkæmͼ­Y¶5 öfÁ´5×–Ub,\{­¦¦BHû% ¹Þ/rüïý„$¥}£µ/UÛNëjÛ1­¶Ój˳µ/U[³ÖvѺµ]˜¶¶ ÓÖ–êX¾@hNm©®å–­í´µ]˜¶¶TÏöB£jK´¶åò¯<³£n<µ1Ø£®\§'“¹Vuå:9™Xf¤– $ËRKsƦÝFµ$j£¾»®€§'S UÞu<9™ Ú!ÓåÞõd Ù!' \O¿iýhÇž=öEç"SoòlÙþvßæ7ŸV:}iû 9ÍÃ{5íYàý• KžJnGéåT2ÚÈnòåêµ@¨'‰ÁBmÁNP(sg„Ú‚žP¤Ý¹¦œí¹¦œý¹Rˆv õDjã¤P[ª…³Bm OO(“öÈôq¡¦T{žŒt $æ Ã;A¡Œ;A‡ vzBqΡBPΡB4:'á(R‹NÐáž Pí9A‡KxzB™´G-9A‡ A²G‡65Š¢í`Ôe˜™€ªÎf'`¯è èvtq¬ˆ¥*úÞ\RYR/Eçbf'–+‚0žWõY´žü‹Pu4p+k݈´^Š©ˆMÒvb5T+IŸ}ar–»êãzÁD½DðlrÀݹýd‰§( DñÜ Z!î©©þ+óDj}¶?›œë¾Ôé$ŽgûÞßf—S¿ü™;&ç»_þÐf©/×&ÓòäºX—ÅzÁs ù·bƕքÅ}¥ÆxÓ@*Z05¬æ—±ízO?ó¥Ü#“ßvàzSùׇx3]=×ÒZ‰'Û©4Τ™½Q»¾p./o “ʳU懆IÕ %mÝÝËkËžiy{ Y7æûiù{ Y#쥱ÊSvEj{~§kYQ¬úÄùòp²8r‘kM·ß¿hHzé¤Ï‘î½r‘ê&ÒS©ÒÐkQÏñíD»5!ãL½âêz•« 6UÞÚ¹´¬¼ö@%_eNz÷[:&déo²)ºmŒ«K'˜µ†§„©Öð”T¿vn¬Oúe¼ü¸béNeä.ÏEõòäé«aϾjY’ ™ðÔåÈjý³†§,GÕ)O_ågþ(7~ù×®Ðþc†ûÑÅæSëon¸¬ÉÂŽ†÷’uÔ1J<È=àG“¤W±xq²“1Ìe½–ÇÙ ™ˆX]Ö<;³8 ÂN7yNR1·•˜Üéê“P¦aà9ÕÙÉ&•̽`çUA”=˜&¾çˆkë6pÅ“P}Œçª@ôúÑöí8¶ŸoçÃQß"¬Ümâ®)â|?ètTAl(ÿ*qtM¬Ò%ÂCã<玴BÞ‚Ši?3ž6/{ª†€)àû* ⫆qDüKëvùöâ’TNVQ}÷Ûç‘u9±‘nmço®ß§B€œT  œ½²$45)‰‹È—d+1¤}]ÉÂæ¿)ñ¯G!‚)!º]!<‘äbðjNNëý´Ír¯Fc€‡NÁê\µÍbfÂ(g‡ Žƒ¿IÁqò ŠüˆMÜ´áëôäN­žr,ÕÔ‹ó°ô&ãåŠ1ÿÇÌI̯$£t-±æ¼ß=,³¥¸VRÄB=µþ’r™º·9)œSþ&ÕäLC0˜úáØöµÓN#¹*âîÄq\9¡ïKå'š´«ânHq½|s—Ê!MUjÇ•¹? ŽÜ£}l¯Üy½Oò<ÙÜÁã-‹_ÎÏ!.8¨çñ«^(x—«J]3ªÔ%«R×€*u ¨s¯£îÕÔ]Ú±Ô'IŸÑ•ŽÙ'é’Ùqjåÿ@•\$3;®¥ñ­\" ½FtàxÈé'QHÓÿz+F›S T®ƒ3#‘HgÄÎczë8ŽeÍÇrj¥_ž²®÷ò™º†|I£t†®)_À$瀳ŸŽb@÷ÓQLêŠnaxqnó_œ¥3½8+0IG^œ;tÜŹCÇZœú¿/ÃóýJ”dsK DÉ% ©ùŠ€¥Ø+®*›ËÛ¤$˜VeVNX‰€¬Ê¬¼°2G•ƒl®.UtiîÁ5»,B®×†¬À5…á*pMa( l¼>òzl»–c'¤,–5<åÛ­á9_à —Ý[&~h§Oø•ÑÛ¦ %¢ÄñDzNÈš¨c»ß²ÄÄzÖ'k‡ kÆn2ôÆÌu™<޵ðÒ™•¤®©lWú‰.ˆîûcÛyH†êš_<î´€e!–¨c1•–AÄ+îá݇Ç5ûýÈòµ + ºrð®—Da"Jã§$_®I½€ª¬=;ŠÈœì±5ÁXL¹NVÙÁ Gà ®í뉀kòz³í·0Ðau AÆ%èß^ÊIéÚâàzšƒäÜlrÇá‹ ÷‹_N¼§êæ08 O:îäç2×d±7‘§,³€k Òƒ{Üa Æ^@Ê^sˆpBGòàE JÖôšãIzR!%‡}ÅqUôÁà’Lä)–ýE4IùÇ„Æù»L]SL¤ù wïZÑp·¯«iÒíØU2 ò¸Ã%ÉäÊg*ɵêD6¥Ü|Í¢æK'ò2YT“kÁcÜŒÃзýhfsiró8-d×4Y‰Øa²ƒOöíɘlyIwY;¶¿;£Â{‹–ÍPÝŽ>0ÊÍO™¤ÑeŽR—Èz½'‘ŽýùYÉt mè5+£®ÌÀÖkVNÝG¯ƒle“ªn¡Ý͈ËU¡\ALeªnsŽÒÎÀZ ;ï$ÿŸ™Í`(Kv›³¥ù䘓Éœ”8æ¤Ì@6'‹S1'æß·9+ÕÁUNš›Pf0nNûÍ >Éæ„æ”Èæ„樖'“ó´4 :R’¶+ G3•†¬Å§ø´4d->…Ôÿ£¥!kñ)$ÿçÒœJöÿÑÒµøTòÿ–†¨Å§R°–æJŽ–†¬Å§Pp´4d->‰2€RKõe`: CãÊ ]#ãଜIÿÊ tòž³tcYÎÓSçææúà×=ŠJ&óþ>øä{^ùàï{éƒÏüÊk(TáΔãlN%|Êr/áS{ñò»&•ÎWçB<9"Roÿ%ª _׺ õÿªíŽyiTÿD¤šýĹÔU=ÎL¬zJ3Š_‘¦—zB.¥Ð8qâùþÐõ5^šª‚Á—ù\¹bòw,B÷ÔWºt|aÇí륉ìö×Dˆ]•šxBçÊ £çÉ6É›ZyK¤™\ãs&mÏ™õJÒóÉ$@/åÖåhqHÊv´8Ýa~þÐRÒ@Î=ç¢ÓÉÿšøö´ÓME’Zvàª{朋y?[aìŠx+W ñNä~YJ‘x® ’áÂvÃ(U×B•ø?5&pÅDÄL‚,O‘pRá¢õEí¡©œþ4$Êß“úfÉm{îv*î><>¢c¸’¤oYN< õÂkh=ÞºÃǻߜû¯Öýv@ÿþ7z•p…<âÄä™´-Rеb“´âR±baͤÝóEL£yNR1·9}SiίîŽt…ráËí#‘_²ò8w¿{ïüÕúza Gëî·QÏò7…»!ÉV執&[:S]à—-û Vt0ˆå¸¸*p¥Vqô¼¾«NPñ+oÏVS½)Ú5K²* hG²õç׉τï/I¤mõ&Ïê½,ò‚©jn´Ó¯’„®èœ,ŽEZ«["9&Éñöç[«ó¦÷¦‡a‰E>s+–ÏêëYë¿Wo§wz;$rmÝ¥ a¹Â‰Å\Ž\š‹ò?_à?m¹yn/hqàkrsÜ¥E«NLÃ÷½ÎÇΦ³Íu„f¹YŽEõG,šÒJë@$òé´¯"ŽÃ˜KÛÁTðˆº+]û¶ó ·˜lÿ Ø®øK‡úehÕ­~Ï2¸Ç×j ŠÉvùíÔÙ^ê¦éÌS˜¥V8ÉõˆËT¸èzLÃ9ëv¶UE·é7ª+/Ìáäñ~LpÅ÷Éw„§H“o½í÷„5Q, šªÿæ­µîj­Iuâ+wŽÆÕ[reK'ë¯öÕàÑö=éÜÇÓ,w‘lë5‹±íÛ#¬IËñÉÕ¼w‘ÖøMÉ-S'mÒ]É4Þ#Š47iÕ'ÐÒIßÛ>éS„x%ÜÀ¢çxÁ.èOÝëFï$ŽÒ¾#WPðU·)°t9ÀrW§‹Àõk½à_:£n|‹"Æ«‹Ï”íÏÆ‚´þ.'~–ÌÚŸçBŽÖ'úrÁ2H™d‘$2É$]MEê{¨Ò‘ýòNx%wäñí¨o.­¯øÂ¬pò¯xòU(µ”ïÅÜÜä„£L^jï·B«"ßÌl§rDz«nŸu.VÑÛùãøb8Žy¥k/±/Œ³«Sš<œ-[·F½0I}é¨x«ÙáœFÇyåȳ‘ó(?¬£f{>Ö·ßVÚŠ ‹Veð}Éjö‹¯XÍ~ó ›Q·Ò†„õÊLKX?˼ ë%”°üªP+´FW]ùqˆVhÍŽöÈá­ˆx²VæØÞ¾­ˆx²væèJÍvdæcOø-IyÊÖçès~KRž²ý9þ´ß–˜§¬™ÇŸùÛóÄtÓOnKšq¾ZÃÑ¥u÷›}2àSGëË0k]†ö¿Dûßòêæ‘TuöH¤^˜¨Î ɉÈÔS2E±p¼Ä +òîZªoÝ‹äÔ¦êRͺûö‘²\+Y({Ç‹£º“ߎz„ ®j™vß¶»R{"5³LÊå:YyþØ@oÔWN8|ñ$EåHuhr©Q©ÄIΕ8ɹšœä\MNr®ŽjPq‚P|£ºbœÈl˜pމï !”©¾T<©¾,TéHq¨R]™LYž {ã^ZTYi–{’YË¡ˆõ¶ …!”Ú*‚f]·'sö*‡¹pÌp´ˆ_‹›x[ñ+|ð¨¶øØM]îÛŸ…{Ê,Ô-÷¾c8ŠGÈq"rÐÖãd";¬Ç ÅvX’Šä°% Ïa=^žÃZ-Sëu¶ñ뽕Hë9¿ÏkE¨×ÂyíuŠ3õZ0¯¡Nq¦ê6a¹$uå`¹$uå0á’!ß%9B(.I}©x.I}Y¨.É‘âP]’Óë^ñõö½Wц÷§Î !jÂ@ýܹ°,çéÉ{Õ^xÆŽp­,Xx»ÙO¸Ë X–PùÅ«—968‹N1}$ã•eÙql?›¥t|;IÌRFʤ¼ÑÚ#¼i°nßh@ƒ$mzA*bscU­M'*ÿY5Þ6Êšx¦UIõË|œ›§íé)vmÕUÒö —*´æb>f«–dœ™’ ÓKR× -¹i Õsµ2ɵª™O„ÊV²×¹Ésà´:Ur›Uvð¥Î7®âhlI¥¦:£«âªhÎË]µOÔkÔNÁV:Ea#‰ûK^{×(53@¨Ë Ð tÆõ ß >tÎM )ô‘º`€>1@Ÿ   Í0Ñ Í0Ð ûÌ0Ï ëÌ0Î ÛÌ0Í ËÌ0Ì »Ì0Ë «Ì0Ê›¿*ÞÏ#ü¤¨×yó§T6Voô"8òBbâ,íôçbh~U.>ÏÂÐxÌñ„d-ÞjÎe€dÁ")½°Gb(=­Çaè­«ˆ+¾[ÞçÀž Úßda}ònùù=EùÝ=EùÁ=ÅÊŠŒ³ ‹¢ô˜mCìm<ÇI‘ðÒý‚⪠.ñ2UÝøˆ bã#öêë­Ò)ƒÄËvdĽ¥·ñr"çËõ‹/g^Y·™Íië’¹¦ÖüÏ‚9lm¶Ãf{å„>ÒVQ3¬ÛÍKi¬ºW(ÛÜæay„}my,GRMÃø¹ÚXºþæÃ­œÁì¼´{àêŒo‡úÀå¥ö‚éžQçå%ìY/ø÷æ’’ø×5wMî±åå²+(}DÛD´-ûx®F4ªÓÛÑPõ:92…Š²Í™:¸o£!¡êui$ µõ>7‡e°ý07‡æj]}ø}áX]uT–C·7ØL££îº¼î÷û™{p•†·á›u„ µi¨”¡yO`ÂçAe»ç1m[ÉbÛÉcôÕ®Lóƒ÷>ºJ‡@דtÅùsk|¯C™ôœ‚›Ó¯^ia¢“\ѽo®pÙŒD'J/¨pñYßæ¸÷P¸²œÀ¡àÈ×M¸²œÀàZ]n9vÂñÉW”°MùŠ-?§Â!(½šÂù¥ÇQ8G¾Â™Î#Ÿ:! s"&çØ‡K(ÂÜ(›cû~XÑE_Ü\™»:*q»4ºy)'¡¹u=úÎ`},†)͉,~áHÃͼіŒæSܬЫ ðe7M!+ªnšBVÝ4…¬¨¹i YQrÓ²¢â¦)dEÁMSÈŠz›¦å6M!+ªmšBVÛ4…¬¨µi YQjÓ²¢Ò¦)dE¡MSÈŠ:›¦e6 !Gõ;þôzHƃ:þôší’»”¯÷KS¾ÞñKy`ëRn½Ó»³ÔzËzpëÞ5’¶F놫£†­wúMU«yëþ M„CHš´Þ¹lj]@­wËqHë¦+îÐÖ;Íj\G•ÍaÎOeo˜Æ˜g Æ˜‡ Æ˜§ Æ˜ǠƘç Æ˜¡Æ˜'¡Æ˜G¡Æ˜g¡Æ˜‡¡Æ˜§¡Æ˜ǡƘç¡Æ˜¢Æ˜'¢¦˜U½`BVµ‚iYÕ ¦!dU#˜†U}`BVµiYÕ¦!dU˜†U=`BVµ€iYÕ¦!dU˜†Uý_BVµiYÕý¥!dUó—†U½_šAV¶~iŠYÕù¥)fÕHSÌ×ú¾t.›¼Ü÷@ðbßÁk}_/÷}A¼Ò÷¥éóо/`žý©øpÞx^ìûP€×û¾têû‚ y¹ïKÓKŠ×û¾^íûÒ0z|`ß—†1Ûû¾X^éû‚˜®Wú¾ (^éû‚ x¥ï „âÕ¾/–Wû¾4 »Ý÷¥×Ü‚×÷H\¯¹žØøˆkö}Á×ìà ~µï `å¼Ö÷Àqdß—¦÷Ç÷}2›íTb®Û÷…ÀlpÌõû¾4Í`8®ï †õ€¾/ÍÏ1‡õ}ðÔ÷¥¹5}½ï €äؾ/ýfÔURºüÔGô}išïÑ´ï ‚ÿ°¾/Íc|ö}Ö÷…@D¼ïË ùÙß÷&²ï C¨Æ%¡èûÒܹ9¨ïKs#^«ïKó²Vß Ýþ`3‹Ž6º¦}_šfú¾DhÜ÷å²ùbmÜ÷'Ãñ}_X2˜‡Z}_š/ÂZ}_tMú¾ôßB5êûÒœþ¥¾/ÆgÒ—ú¾4G¯Õ÷¥qô­VßÛ }_: “ì^ëûÀ‡õ}¹l>—°¾/ Y uÚ@YšËòRß—æ–âž/ÍÑ_îûÒ¢ŸE€:÷:êèX/‡ut@ÔѰ2ëè€ ‚wtì]øŽ0¡ÆÞÑ!Ôë,‡ttÐÔé耈5Öié@â£më4u@ð5͹Aœ?š&Ý dhœu0¡³np2ŸuÃ’Áì<Ôêëpk5v@ð5éìÐüHÚ¨³Csú—:;4¿ºx¹³Ccáë´vh>UuZ;@Ø^híÐü„òrk>¬µ`OÃõv@ )Æl¾@qÍšËòRs‡æîùKÍšßf¿ÒÜ¡ùrz¥¹€àåæÍ¯4wàš;4÷š€ÍPÂ@L`!âš;4æÅæøºÍ/ƒ#š;4çäæ ›;ô{fÈæ0i0‹)MóÕÝ\š›;4÷ä^l¿Ð0é|tÖç‘ûþbø¸‹Þ¬ÿì »CÃ>(†8¶Ãø Ž¿JëMŽ¿’Ÿ9þC²8¨p̨P¦NE=ILÏÉÞx¦ñ9Ù/ qNÖ»s¼%ÂX/¬ ÛgíW%t¦ìUv*{H•=¤Ê¾QŸCÇ&yL¡±1…¦ÆÔ’OWS£s`Ê­©)‘9x)×Û̼(‘90íÞÖ”€;‡d§“'á ÌÎB ªpff¡ÅÑÖ‰oW„ ÌÌÂË"˜…ötáe¸³ÐúùÿhYÌÏ‹ÑÀѲpç¥^âybj ÓÂÌ´¥25…123&)š™™C…iafZÖ™C…¡Î 7ÞXɃkß1 ï“ra:‹Ã…U‘ˆÔŒÀÇËì“eªîN›"r%^À%^P%¶ì4œ«xŽoO­I[¶ëÆ"I*‹9aD iq,ñùžã¥x*çÉÎójTŠl);äÝfo´ÆëœAò²'[L½@Uí:»÷ƒ;rÞ­,ßV8© Hïdq,‚týYõ<áy\1·ƒ©O@ËšýI,¨ ¯j×¥q™â hå*’©Žm÷ù$¸5¡,ÝifÇ®eØîü•y1A5søXøBç*£á£,Ö£§™½ûúEcôXèL‚}Žå8i“ åG ²ˆNÛ•Ê—Š.¼Ç'aÓæ; ÒdKdÒLKd,°«*|¥sŠwæ¦OOV$â$ lßKŸ­Ç ,~8Šâð©ºýJ첿®lILsØËL©HRË–R"^;!Ç÷^–óŸ¾7~šûÝ7Iø¦ûæêÍ@sýþùû××_Ã_Ó¹Üíäþýéc×êÊô.šLYë%¡o§(²\ ¡3~/&væ§£·ÿþU~ _Ä 1gr˜wvœˆwaÊó@C¸ÐwåþùÞ ç‘zcO-Ö†˜R~Î&¿UGÑ‘3sѲ˜Èyäýƒ„}› ÈêB cypMR]QüaûbÂ?TùÍßÍ„óàS,þ0އº¸9Ø/"±ç UÏ,š^KOM×’Mÿ´ã@E›±ù‹>ºÝ^ú)“¢¾—»Eê®TÚ8èï½ý"?&p¥Ýü ñ%K£ ðÕ"úÙ·ƒðGÿ(½2¶ôñ9S& e mwø”¾O]<®ˆ!<ÿÌùÆñ.v*>x¾P­m˜Ø yÐ{}ü^Œ³é0H½Ô ô6 MË+йùCê´8áÚrŠå”#ÕùÞöZË÷…;ðÎöý±í<ä ñÓ‘•o›˜xcd?ŠÏáp¥Ï_í)@yGÞ<òQs9JãÌI³X¸@˜g1ÊÆ‰\þr?]šìgRûa¾3Žômy3ĉxÍ$@³Y³S9Žq¦SÀƒâ õ½p°‡[ǵSûgå)aag¶jn$m$V>KSžD¶ƒbyÍÛ1Õé~½åþ]úÄ"¹Ë’‘dçÜZÉðS·{ì–PI¢üyøPôépeÒàð¤U#~ˆ<3Ëìš]A¿W2HÀe‘itµÆàÈRis²Ä† .|¡¦¾YåN Ÿ¢2èàM·h=~d ‡ŠÀ¥(†Ä憕Vã?·Or· líq ¬Ä“0{®t²àŸn*Òw¡ŸÍƒü•ZbkýŒF]%ÐÈÏDK3!¡¥‚pfä.ûžsë¢qGú]#4®óq¦zf'CÞ:”è·=ûoå9A],ÄÆœ_¾é6‡ÎÒð&B§árÓä5É'1ãçjšË7W ¢+®I$è½°Ý-¯dðýÁ¥!o¹;HìÛ/,ä\o8è[¦ü{"¾èÔÁ.½ŸÒù G>YV’ÀO–š%tŠ+ò÷Ù<úÆs;Í£õd*‰Bgáî®*ßÑ;`J·ã{1‹MŠÓ¯ €§_¡3‚²kpíо&Å NòœS<ëÏ9½óN¡26EÛTf Xz´4lÒ&9"ûâ_í)áâMƒ0¶Ç¾øs楄h¸J†)ç+”ø+žÃ š°ljÂR•ã&‘^Ö]Ö& š%30*íÂÃK¤O¸¶`½ÏK}¾†ªòЬ²PÑßMc¢?[°¼^ƒßsÒ—‡O„OA(O^Àg ²ø©:â}l¼;ŠCG$‰ÜÊnƒD§†êþÀAÄb"b€wœXÈ¥÷(·ÜÒø,O5E‰žs#¤vœRÎc™qË‚H9¯î“(ó¨B¾h ’ƒ¢MÈ“ï¿HÍ˽÷"v®·Ά¦¸M>zà0†ÆÑ'gÄœ¹ÿöJdúÖņ©KÐðÀf û^žŽ±6k]t2|ž¿D&É“™È$¿ßßÂ\÷-­| Ç7ó|¼ò¸½l4¶ÜS nFº4ì!)··@/" o}ÏÆ^çø·Ø{¥ô³xJGž4àÈMÎ:äðw±xä „ç¨,yUã†ri+`™Ž Þ©>…‹/ÍøHÄží{‹¯Oi‘ý³Ù4fÉÒp.7¥wòxŠ—à¥ÓªòÔµã6Q^e<÷ÆR| ùù¿Æv€7˜kŠwa¦ºH’îæ÷î4jJº—…=áš¡Á/Âö@†QâùàðÍ&Ãg1ÝĪ8Cñ%p]}W$Ĺ¢,‰¯å÷”ñ1SMSÓ÷‘°F"Ý<÷gN—"ñ›V÷«¾Qaè ¿ p–ߺ#>4°þUØ,ðu-ltzÅðîø.wLÞõ¹€àºv„‰­:˜QñÕY šÉ²"`ÁrdÝ%„­rˆ9È¿è&¹ ä"˜¦à@øû^$4 ”»ÁÛ¼ ½Ü×^°[͉f1<¾Äþ3öRñî×·÷Lø™ w‹KðÿÊBéÞçý\ð4žïþK]µ# |/|©<;QØAæ«+|Bt÷ççTõäL²¹ØJõkx×éæ•é¬ TnúkÈ> د í T/°M|Ùìé‘™uKµFV7ëðiÿnÙ_ƒ"†»uÄû»Z9Ìi_ß-ÃÕkÎýÝŸsuWàß&ÿ±@×ß–t‹ZAAØ¡¨÷ÌÜkf·Ì&.™éwÌεgp¯¯ ¯mÑN?£ÓàMžô¼‡£‹áiÔkü^œè67lüÛ†à×·q>¾dø¤õý6¸·ƒ)´¦@–(—àïäÈZ8Ë^»ð_¿~½Ó÷«ðé–àåwÌì©À§(hxx.ù¸hDŒÇ–Ö"ÙD_t• ®š½¥¢ñs¾X¡:é¤HÐÃ[Ýœj#·Üî`ÍòËò)µòéí®•Õ€™4‚ªz¹Kvž|ÁAž‰Á…+&rós)3ÖD_g±°] ºn¸}L‘ø‹‚Oꛡàó“úè—O  Ï=¯2&¿ªú:#»Äý$}WOEè‚×5ìj·©Hkê47¡Š$ÅG¿$ì~ÁÁ 4m\š2"A6±ÍH9Ððª>íJ\NQÏ68#ÅYH+ÏÂåÉœ§ÛÒ4ñ.וp)“¢/Öß/óK){ª¦àÚ€5Åžæ›Hž­a7*]qÜ~¡3)¡*{ÿR£U ±Ñꊃ0-€?îm‰Õ˜ABþ"ÒÕc^è͑Ӷ„Œm]Sw¯)AcØ”€ñ=lVààæ³e\®ò%b§]…<' °9sxÇê @8û½ÿòéÏØŽÞºa”nû}Òœ ðß©nøó |uŸ]a Q⫬}ú½pÂÀ‘æeåÙo§Ôã˜Ôm*å;« <X®ê: XãP fP)ðÞ›Ûà w|Eðþ+ü¢`ÍhøPEÀÈ_‘°â£+Æùvœª@_v )Ÿ“¹Ùú¾õÜv%A“Êz¯ù*x«ù ’—ÚüÔë6¡ð©á•oŒoÞœq8tÛð*¢£_BÒLªƒIùB>_žÄß̓DDÇ5ôNù Àå]²1øRQaŸäÇÝr³:ÓÁòvíh2ä¡ü÷Äž6{<µÀÚm* òË~öQ°ÿ¢ |_Õ „=Ro†Í> »ÄÚÚÓ"†Òœy®—>k·]Ú}V³ªgG8w %èmÏ rð ¼e²†Í[Ór*%*(Ð]v×,Ô!0…ϧ‡ô‰¥Ù¾CJüœ`Ä%(ŽÄ´6P”+$}¤äu?*ÁóÄg^±­ð= tf+¤2>ezÔ·eØâ#J;è÷BjglãÍCN3Š„ãÙ:G?8¦\b Ÿ"Ñý<~·®oÞÀd®\ú¶B‚`²ˆ½Çíè0{÷Xƒ­Í# õ5hžÜÍA©VºèÛä³çûÛÆþÉ~ú>ˆ€­Zb¥áœƒLRÕ>(æàVTˆ  ·òwAÀ:)€»Õ„šÇ¹iöNåÈds8²ÊBÀ?œW²SÞÁC‰<§JáÞî¡>x[Q^‚§‰“å©m§. Pfo ™&±jÊ=­i†¢O›”ü¯  î,7Ã]“à3Ü,7ýÄ@ÓEêÑ;' e*øÛ÷4ÉuU™ÜE… ¯oÚBéU¯Þ9 èÇSHÕ›EÑ åM/bA¢‚öTF=AæÏáçdû°tÙ¼DS#»b»Ù+JhÖbÙ °<¬KÏEZ*ÚV´Õ»‡CA™y:el y¡[ÆBW Ï…ŽúO;än™Pó\s_£'¿ÚIÅ^‰¸V”Èœõ)I°3ýî`?w™à=&8[eBSp)Œ¬‘U–;:Ê¥ÐOi(ܼ$¢{94Eóv )PÈÿª˜€V‚îñ  Èy©5Ï@•ð)šRÂgÀ; È­€Y¸2ß§ ­À)Ø„—sîï‘›·f")x Ÿ2ç%|4üí—_ï(YZ™’¦¥‘yZ˜‘¨uûE5v&M³‚&ͳ‚æLôùO4ç#ê»vBWŒÛÀU‰AÒýË»ÃOzª:ßDjÅÃi­9e{ ™Ø,XÁsº5¯‘¹% ÔŸYAçO|“R×İ÷š„ß/û6ùÙN(¯Ú­‘‰ÃêÓÅOM…H|߯?%XÀ2òãnÎ<3çø]8{¡G š%û{oŠoSÀ²dV·á†qÌ’S'1]Nc;šáߎÚgÍÉG‘¦ŒoùÉö‚| %`{OÂ%UÒß&wÙØs9fpm¥ö¸úc^šl•`a¤þ÷¯_?}DÃþ&D¤·±¤¢1…€s¤/¼yåA/Þ§ÿtÝ ÷N_§gó±< ‘¾À.éxÁƒÊã!”"©;ö·‘<ªÃ­˜BÖo©P€ —K—r¹¤ß _ñ÷( –ò*¨æèÚ‡8Äo– ø6HOë*äO"žRTâ.Œ~¶ø¹¬€¦Í´j‡M“;SW°$Áó;ª·ø{“5¸.ÓåÁ«m˜ƒþ(b|\¼=’[ >:^"øÓö)ÉœqÓ¦qCޤÌph»oIH…͇†ÇöðI¥ƒs½Õœ¦”°Íˆz@o”E"¦}çá£7ŽmüÄÇD?HÊo~LH]¹?ÙªÒ¨ZWœÑrXÕlg3º´¬Ca ·ào0ò³%#³¸€V¥ÌYÉË~¿‡'2(|•uý6Kg¿RÚ4-ˆN-Cž·–ü(‚iºý¦kãÇE—$UsÊÄ–ð¡Î` Î2Àº@B¤³²p×è÷ÂõhšÿÉ›‹¯Ïúi¥%<ËÐ/±©sòÉ9ö–àÀI¿iïÁø%ÃÈ~äaÓ¶+±`õUVÞ’J’ú™Fàœ«&…Ìo²V°(52¡ÛŽÂ çŒX‰Lh’£REæ6àÎ9>Äö”7Æåäyh§”À˜&¸»Ýšð桇—З$G¾·¼ùþº¯a&ù#Ác‘àøöò•Û]^ì¤Q.BW¸Äþé’#/Ò÷õ–з_¸¢kôq8WO|°ðiÒS:MK\’EášoŠþq:U­€y³qïZ­@iÕÊ œ3Ñœvì ¸ê=gvþ`×x6wË:+ð¼^ƒú pµËœOk‚¿½u¦<ó°_5?è!PÞøÜ`P…»-#Ðsõu'eÏz—à³6 øR1…[8ç#oìoEÎÕ‹ŸÃÏfºS+ïè­ë²Žè #* ~Î&ùUõnè‚ÏH[[â¾Ð¹§!ºzÊÁ&\KåÐD})^¥%At¦S,¤™$ĸUC „ââOo©| »pÔˆ<‚O-GTµ\£“ÌØˆ§÷šràË¡ÉK*žëvI¿ßß2¯ðÿô7\$Ž$/§^šû¦x9JþP%÷`ƒ@W®ï>7xÓmìåìò|€à*8A·jÆ¡k?SE3ŠÁ›NãÎéû wÊüVtMÊvùn¿0'ñƒ/NL}p¢ ÇÞÎóèài8ž>·¾M_(€ç:sÑó޼^“e;£Æð³íÛ#Üw³,xà4ÎÜÇs/œð¾ÕtïÞ9ï9tžºÁØSrü™3úó¬À«Rÿ „Ä;ÃwˆÌ‘9™6å„’c§O)·@žÕÊ8ÇÍýšù$dæ,q•AfÊÑô‘Ô °Œ­ïebªO›§Íl 6 _·j¤%p%¶ÞXˆÂ»_mξE´ž94qR—æâ.)¼0àq<å-ÖUgo{—_Rà[ÿnÀsÞêÔ4Ÿü6P‘ÏŠ§½å‰»ñã—šá“?dÍHOvŸ<üCÀyí;kŸZÕ¿sÐçiø€¿0ȱW¯G“ôdI@3”wCZ>SŽÏG+`¿Úñ”d¶t«ë*×Âæ|Õe¡Ü`‰<î7½§éû(µã”åSŽž“TÌ™V]<Óææ÷{ÎZ’¸÷öbsmþÜë šªŠˆ8‘æQ½ÄÄÿœÁ315¼Ä£©KüÖu—ï#qÞ‹q6}ñéœ&Í&sŽò8ñ?xy‚Ê ê­0x:rN£È{±pR–Kç…‹l_¡ !“èìjî÷>"Öq¨šŠq÷ý éüVÎ-øRüUø"yD4ĤžYó¶ò»ñ\¿Äø;$w„L‚FÛ‚ y¢ÈÒfòTùŒ?ÙOïE´Ý„åjÜIÁSeS*âJ¸1¬Xxn‡Îå÷Òg¢ï´¤øÓŽÏ×$¹ó]íY6¶ì4ÑÓÙ×pë¬&TtJ`°UE«÷aïPÀç©Çžoׂ9v=”°¬ «,Nr/¨€G–5|>óöØßöfPò;á<ò¶Ñ›Ï½pmy t–§BÊ‹\•$œgîÂHoeð!¸ïlßÛ»}Û›ÄâÑ ³„Z¥70F,Jºn”i¿§µ6¾'ö6VnÚNÕ%uó¼‹Ý1+ØÍÓ”R Zú†»¥²8hÊ—Ë‘9ŸOcS¾¡F&~ÈÝ>RHhÒ‡TȬ©›²°¹R=B/ÏÑYД'y \£*u †ÝªZöG/LÙå6jÏU‘9ˆ»lì{Î-ú±@Ï ¥(è¿Ú ]E%Çm@æ¸a¬2µþœyénõ*ŠEËÀšüÛŠˆ.’'tƦ¸~Mç¾.¶$£TJoûaÀøþûê‹AðÒovD’è'}ÈÜJ·ñTVôÀ°“Ьè—硥ó1tì”âþê²W¢»¤ñySžâ2ýDËn4×iy±›tŽÁguîZAãÓ#–М&'KtFöEûO/1ø-98)›èÄ1ü®ŠRˆßa…O›'Ò’µÅNoçAó1îNj!•ò Üa€·.ôWx”FÞn*ŒšdÕ®<¥Mõ 5á+δ‡ó(}þjOñ¾tÇT¬Ók¹ à 9mÜsìí¬bˆ¾KØÊÇ™@àÛ9ÅØ'’ °¿Ç|É8vÀè«5rfbn¿› çáƒíˆ­û¢æ³‘ÃïM”A„¾oGIEËsDW%Ç\ž-Än¢+p%†?gimÆí6†ÄÁï&-€w³Š€À<í)e H±Ýù Îzõmƒa;ˆþ§ç»Ž»Ó ðÊ<•ãªyóÈןã6óíÏÂ`¥r¼³ƒ0 š‹ Š «×íq’G¯qÍó6ùýc¸³S4Î_Y1íËcÂ’ÄÂ/ØmÁ [;y a…~5Î,ãWeGáfª2E6C·Iiîl"¸•x›è‰â¬—²,ÍÓºV$¼Möå NÉç/_ß~½ýò™h_HÅ1üësu?, FåÎ8w¢¸~IE®+YmýlÊ™{K "üKiº¨ù90K·y@dI·7I7"Mñ%Rw§Û[]ãlãMv"pÎ&©rDm}Ûiа‰Ûaùª— 9¾ÂÊžHÇ„ú¥ÊDÕÖþ p3±¦ªJׯ} <[›¶¹o0TF@ÞèŠg§7Êv.>Š`šÎªÜE¤"o˜¸Íã/Ñ^~ ªžE/S•QÏ?j-©òÞ^, yô"Κ@Z´·ÉÏa¨‚¾lšª€/šåóÎÓ!(¨ßd.rý·”¸q¹FN“Æa°;ÅyKô½§G0O¥Ë¥yå8ŒeÚ{l…3¢1ðvfXøÃÜèh«VŒ{|4Ȱ„;3|³%îÏÏ¿Æøâ§‘(z(¿Uˆtn«ž-ü¨*S˜G±H’O„J«<+”̰zI.OžýRBÄÖ{¥CÕÖŠ@óAØjɈ=G¯eÒéG¥ ù•"e,` ʨˆTÁì–AÞþˆˆd>‘ª¤Î7Ì¢â¹0ÞMïpÌ„$Fƒþl'ø%©€ßÙð&G÷½Ç™Ý÷ö#¡Tâ»øk`ÝŸŠQœ¼Fÿ·ê‘NiN¿Åq/B'êœdÁ™~•gF^º¢ð?c€üàE?ûvð ê«ñÛd)=™l¾Y g‰|/Õ—r]to3ªÔ<ø·BÆËlbÎÓ°ØñÈñð¯ ÿv ÄÕFk‚özÒø_;cpÿ¨¸ùÉ9é‘8s¼—™#')C)‚³#QgY)sëf TaÏïB|¶l¼S‚DV5 <ôm÷ rc®Ñÿ´ƒ4y<“¼`ZÑÏÒܺ@ÏâXí,Òc è£$x/95/>zÙ˜C]NHÊÙA|Áþq`ö‡œ…>’¯ûÞéúéý9{âI?u.øøÉ%jÀÛ=Î&§`?‹­×‡·ÓÀœiàìt¿$ÉÆÔr¨®Êp4´âeøŠ—ø®Šn¶X²q" _–® éѪ½Dœ‡«F /ufËàðÁhtݳºŠ±oh†¯!kʤK•"X2…üIÄSø‰YçO¬Zä½ 3ü¡yÍ£B„JÇÁ³Cds±]¸ÓØG^³ì”îú—Ð¥üiÅLÁIõRë4Þ"·hTo;äƒÝŽ‹þeîb1ñž¸U‰PhŽŠT~4Å¿çþG›=IRÙ ºVòóåNÎ-r,9Ånâ5cçS¬…>Eöf." Gñþ—¼„Þ iST&ùš¡I˜4Ú¡®hµèï½ÁS¤£ííÚ<ý±‚n_SO ÙvúKÝ‹¹íîög’üj'+­ƒ±6höt ·¬“[™Bw´©ÈGGó¬\—ÝwÈ=¬¢äjž+]Iì\µ¾ù1Ôš4ÕÆÌ>dÑJh ÿS¨šîðwÏ-âºÍÄÛCs¦Êà,¼81àäädª‚ÏŵûŽ}`ªh¼âÉvèAI*¶KÀS¤ÌùÞßöv/a¨2íž½±£øÒÑ{ä‹—wvªÒ¯7y_µ®yþ•…©`\‡®)ÔsÑWÆiïë‚0ªÛ ñ¿ç>•ä‹ d”ÚDkž3l§ÀËW°ò‚šáÝzf‰Æ³Yº•^œ¸MžŠ’- } ,ŒŒ¾+u üqvÊ*Ÿ?hüÐâc¶Ý| xѲïä‘•E¨O£tft< ÜJäR¬HÞ½ûõ-• ê5*ˆ‰\QlµÈG@ÂËOáoe$:Än³T60À³T¼{&á£öƒí'ç,÷ö -»ÄÄž0úTI‚‚¼ÏšøÝ·ÙØ«óc[à÷À? m‚˜Ýÿ0» þÑÊ>ø‡Áð£;áf¶Â? í…07ÃYü^LJMBwûƒgç,EîxN6òþf±Äb*-Dž}W‘¯Žc uÒ‡:Ä«—u»Šêrcå/"ýÓŽIµ·´Æ•ß©>Ž_²4Ê8sø›y×1þxÖyå¸BÛ>¥ïS—N•œ|Q½‹Eñð‚zA¶B÷oä´yzÐ{1ΦUmM`ÃËyt¼ù1 ×–cs–c%É{Cvë…‡£q/7 FòðÛÙTw—€Nß}—ø’à!]¢~7ºMÞŠ©°‹ÚÄíæïMGøÑÌ µPUšwž•Ó/¶Ëùb{ìÁ;— w†ñÖ$ÙÏ$2éù{6¼ S‡ ÎÇþÙN<磜Žä?‹`*H¶tçxÈÅaŽ4íaÎÃIHW7qÒüÁË) ’§÷±½ ôÕÉácÛóýeA é#d³í·R1ûçç¿•cˆO™\]¶?zžCŸ3ˆwÿó7ý$|ê=+¨B#ám>ÛL·®§±ÍLÓ²(âi/‰ïmW)‡¦BÿìÀ½“ÞcšíÜ\#É~¼‰'\þ‡Û!ÒöNuláø/Rr¼ »KÜw4`Žë¨á­9±B&©¿~¤Ã;’¯ç4dÚüH[á„,‘?Ñ€ikû¼ k…LÚéìô3 ˜ã²+dÚÚþL[w4`š6ßÑ>àmÜÑv×;Îù_!󔎶ohÀ4uqÂ, ™æŒhªñ¿hÀ4ãü¿à]ÆWȤu2qø HÆ.œ=uÉüÞ³ØKÕ)ü“?†²mÆ!T jEû«íO Œî…!É‚4ý;O߇‘8tÃTç™:Žç(öÂtôìûöØŽŸ)ßÿ9ö|Ÿt³¯]¡†ð^55œó×{ñhöÔÆ÷÷ÊáåŠۤ˃aà¨v䮾 ²¹º†æ2½ûŸ¿}*¯bˆŸä*$Eõ†éÌ #’Òê {Ûg‡@á\¤ò“ŒfvD2R’#ž²n åW }‚XŽ/©‘©^šÁVMK¢Ôsöî—ì›KÅ䈟ÅóìaÆW>ÆÂsSiŽ\ÕaBÿ5ï’èW;˜fþÆÅÍÿ´ç‡?ç"Ã瞀O²’# ¡²¿Šq¼ùÞNjo:»‹½G;¿'b$ݲpjL¯Èè±ô7›~{÷vuÅuçå9Ò/“™Hí ª¤í¤ÿ¢®&ýÍÆg—“ÐÓ'oyË¢l—óÁ³Sû¥MKð»Y¨¼³jÕBÙßfsüãºkdâû£ÍÙt>V‡œ I–çÆ|“Âu=e2ðïrqnãó#ï=fpà£7gmõaÇ?†|ÎY95²ñ1\·êO¶o?Ëÿç§?Ù©j ªå# HZ:šÙ[† %ôÈ fÒ?áˆ=·}_Ùœ?ìXŠOºÃE¶£n CWeÔÆÅí‰J8ëŒ/iRnQ{²*¢Ëÿ†ÅV ¥ë¨·Š;µKCq Ê4¯:¨ÒøyÓ¼°çr›3©ÏrÕr ÚW{jûá”!µ„ÛÁ‚bá·‹€óá}‰½gvð?¥$F¯¾ÚsãÔ~6åd7Ù¬¨§„æÜŽ}õÆ"%p~W) ¤ûÈ¢ÚåœpWzoÇaìM½À.®«XIÚïP¾üHøÂaí»,Üd–ÿâÞ5ü—ǽCü/ï›Ê%O¶Š’¬Òýí0qlü{r+àQŠ?¨ßßþˆ%:£öë‡kuÒuæ[/Ý wûa`ÓØx‹W ‡xÿ&GÜ Ÿ)›CG!~aæÈÉÖ'DBgc8rà{ÁÃö{ô äÐyøèã­‹ x"ÒÏÉö{a0h p$mµ+¾øîç¤)–nösæùnÑÑ[žÜÜ{Ô,ꉹ廟bÿc0>õ{¨†ä©¢aŒ·\K"ý¿¬ÎÜäÌÙ¥¶_§P‡Rõh ÿƒG¸_‘¤ðìÇ4UôŠNx¦ž~~·ý,õå›> üÓ×ðA,t¢àšºpõkÝ\†yªæÞy ųÔUPpî„–_‚êÀd‹$Vͳ8î¨b€gnWY2{÷ÞNm">wÿ"Ú¾û0„«Ï¿oÇÏ\ñ!B;ã;/2£>‹—@žz‘Àá-øþÖ VUE±½ äD5~ðp‹gûÜŒÿªi&8 TÁ`à“¬h¶?ËUó彤‰”2’;;½u]í àW‡Bÿ9 }aª›,#mFs¼³“´àùæ¹L|NvÅ£ üê_ÂODž¸‰32þHô h@ÁCNÏÎ’‡¬üó“ Ï—Ø\Ã?ÔJäì\ºì3ĽQ1x>üHVÆv‡ø@ÚAåZ€x¥9SàØ)W‘äéÃö‚„N"8r|g;³m÷ºñSòKŽG§TÓ”S0mSÎÀ4Na5*}J+Ö÷à æ;ëCÞgóHq Ÿ"·X±|>À 9<õ‰ð¡©>I½€&{> ãß ¢ x$î@ÿ2ÛgâÇñ¦öƒ`Y›š¦­¦%¸H–ÕQw±Pù_ø€õŠ!SáÒ%˽H¶Øq}°ýDP­ô?Ì_ºá1èà)ÑFï‰ÎBñ‹³;ÿãÖƒ”Pâ¦àó·­¨¢PÓaø€Ï« Ø|^Fò«Œì¹àÜn]ꊾ <ÎÖ–&‚(yrÀ›ïÈŸmx—ê%²Šµ=ã“u5üG›¢øh'܃ÆGa»¬cRMto?†Ží«{Qê} ™WŸ–o×qà?¿­^YM”Ëo? !/³ ~¿¿¥~ØÏbÁ u¨{ib¢úÚ /ý[üË.Kp¦W¸†§9…’‚ï´I®ió}—$xJߎHÒsz)|‰GÂçø'š†•ȵbÐIÝ4tÕ Oê%]äoñ!ôýñ¦ß.ÃÈûL"ZfÝŠAZ)Brà>Ž ¹ ìoÁÓY¹1í>ÑÙ.vÔ·.þ3É^üxá“—Ë$ËA*‡~‚Éð_:U†×±;ê}ñ”:C÷b>RÔ‚¦áUÏ×2­Ò’€j–ŠJ2îQ1LÙ·]’‚;„„û-zÀ1åÏCðïÂ^5›ÃÇ®ˆß‡ŽÊâßøÀ—o‚;ZÀDDw«º`S“ãÓÐÈ…Q¥%OêunÒ¥¯Äg†2q~D3.RÓø­ûhŽNªCÀé\úR‚rûžÆœ î÷Þ¦‚˜Æ*î­2—ò¶ž” *ÁSîk6X$”»ˆ ÒeÁë¾ u6ïÛQ"\­Â4Rº‹F/MÍNW¼oMÃü[ ÏÊMßd¹ =FÁ& õ;è0ZzîP†¡á¿†<_8•ÿòêÎtÃÿyá7ÿ§,ò?qia’T½è¡éþ÷+tÿ´~ùü»5úòûý»¡þÁ?;ÿ|mþi}¼ôÿÓÖÏ·¿ü2}µÞ~¼ýåó§á篖UüzpÈÏßýúö¾3°¾þ×ÝpùÃd&ÏeÿÈ‚Dž9„û©3‡õº@Ç@Èñ¬Fp}ÈÞÿüÑz?üüåþ“õéöóò§ý77ý‹Áå yÝïtûƒË¾ø©×í xûËj/ýÑðntûñËJ„î›n÷¢ß\ôoº—½N¯#~:ì›(°_ߎ–òjhÃò§·Ÿ?Ü~¾ýú_Gýø_¿ß¿ZŸß~®ýëOo¥þ•&ï²wø/ÿmu.¬á¿ï–¿í]üýÕK¿ì\þ¥ÕO—?{sus5¸‘_ª=èö:—Wâ¿ÕBjßæþïŸzWÿOßoüX£Së×%Å»¼¸ê]_^Ëÿé^t”î8Žá»N÷z[“;ßz½÷klëAï°ï±üñÆ×tú‡-Áõ¯‹_Þ¼¹yí?C‰Þ¯7´íÏ$º‡}¦5Àzbå¯ëMíè÷Ÿ•Ux»ñÉ/Þ\¼òŸºTÒ”ïjÁàý‡Ã¾­Wu~º¡75ºõù‡7õäÞþÀ7ýC?oñëõ„Ý\Öa~éÓÖô+¾^çòýûÿýùܺŠßn|?i‰êývßúö®ûµÆ°ý){×/Õâç%xÝ«Ã}Ð:­ {«à~¾}o}PÈ_ëmÏÅÏKŸ´{è­ájï¿~y¿úña¿½»¾{ûuø¾†¤Ãjløïwû¯·_>jüH»GC©m_µ¾|þ¸r”.úñǯ>gçMÿ¢Ó½¹îÄOý˃–ªZƒ–˜úÍöâ~Ó¹é^Üto.ÄOWW|ÔƒG¤{ºüéQîéòÇǹ§ê×Û6í071ÿåŽ{zCµümÙ;íÖúå’N*W÷ºÛë+§ôúào\锿“.¾é“v/kýx­ W—ý›~ïRº¢‡Kÿöýí¿kœ_Þ½“:òÇÐzÿçÛû]ë݇[ëíèS =Y!Œþëó;ëÝ—Owoï‡ÖÛÏï­ÑŸoשׁ‹ƒª0xêºÔçßßéÇíç·Ÿ‡µÖ£þ­T‘/÷«3ûÁ?»{ûõݯ‡ ?Ör.õoïµî‡‡oGkq—·¦¤¿ÔûÁ¿ÿm½ýùÖúcx?’»Ùò,{q˜âËßýz[ç ÈŸü9|û[­Ïvûù«²Je/­Ûíõä1³7¸¾ì_]]^_\tÈ(Ê#? ¦‡‹äÏËRt;ý«þuoÐ?H>VGzoýËÎÍÍe¯s}Ý•€ƒ‹îeOîæ7—ƒÆôq;xt©ÿX=ê¼¹¸îw/º«nÿúòò¢ßïIïBüÔ¹9\#7é‚H›E‘>V…‘­ŸÕq¤þMï ô±*’4'ŽZ?^ox×7W½ŽÔœÞåU·×¹\^tÅSÂþ«vo‰pXTècuPIލæïW‹£7èv.ä˜zŽô6{—ƒ®ruÒ—Ï¿äÿõŠõ8 `†T¸½–†~úôïZþó—c¶Ç»¯÷ïo?|8Ú<Žt0½¬‘݃,ãè×ûM¿³{58쇷ÿkøåƒõþËï?\I|ù+~ùáã—õ‘ö EWüðöóQ?Ó ´)îa1Žòïõ1Øcw÷EŽvxÔO—uÌG¿~¹_ýð sºü¡üŸã(ÿÔ|Ô§ýS©Dý_î.¶º7X£Ñ°›Çê¬uý«š?8Š¥ÞŸÿú^¾Œ¾ß×ÿ]ü¾Ï¬;û…ã¼Äø¿úoúo®þѽ»U¯ÓûÇÿ}/¡~µÓèþS§óÿü_‡ þ¹mI빚…—Ævàhr%npjÏÝZ7ÉúÏ×úrNäg‰úÿ¿™™å{AöT‹é¡Î±ôẶ–¦îŸ¯Å^õÇká?]¬ZŸ:ÿA ŽzsTï‹v'Á⫲…áVëtƒíŸ¿ Û•DÿûÒ/þéÚÞÓ›Yé?yñ‚Äùµ&ž/,/˜„«uüQú‰dõ«—²\Š_ÍÂðaýƒÞ?°& wõ£þ¡?òæ‘¿úÕåë¿òÃéTÄ«_ ^ÿE:aô¼úÅÕ¾l~jÕ0³§yJï?ßý·ÿ¶ù™‹'ˆU]oþ'4WåŸÙИ$u‹¿ßø³ h¤ZÙ’¸óÏ÷šìµ¯¹ú“ÿý¿©­Þdþt`’òòw÷â¯L$ú¤#~v‡©œ|¿ÎOG©fÉ»Cå”&þéÉ{ÿ¸²îò'ýiù±ýsÿý¿§q! vSÅF^´a.vÿõ¶Zìþ‰Ñó|ú¥{ýÓú_Ÿ/õ4w.gi9r’o“ü¹bï–n–_CýÔz÷¿’QǺ»û<²:ú_ UÞý°&|ÿWinˆþ«‘Ü|¦†Ã«©HUOÒáݨk {¥þê^8Â{Xäë¹Xbø$ôM:LÒØ~r? ï+(z¿ÇÞðUí­P_Å[­šZ-oåvuˆ=ë\\ôÑàòoÞùvR¸uWW¯_ß—©r$ãÌIÃø é*ÿ6ו’É_í-5@>zA±k\¾~ô+ýîS0õ×;Ni5߉x¢:¹ŽP/á½ëëàÞÙ±=¯9ÿ›M~½†±ýipè9üU°`5SéÌKšã)7jyÓ½yÙm|í?/åôîÿQO:R)²k]ÙRC……Qå1öjúòʽî^½~£¿ñÛã×îÎâ¤pÁ뀬ï –’î[½×ò¿U¯'¹jÕ¶yU‰ k7^¨5Œ]ÄðU¼µŒ{¯ÿ^ýO5¹%Gçħ{f®/ Þ½Ö¢á|õó:_iÛt.—çÁ‚`4ûµ?~Ùhö;ÝzFó½ÙLÅBvºµ­æm°²›µèK®ÒëWåîó•®>x¾P~©~òa"VïëyK; ²X ìOa?¼îy—ÿs€~ ®é×àêõZù·;Nq¢ñq~Ri°Ãv®![lù$j†òzaw×pw×Áàâò¼¹n ­g»¯ÊÕØ‘áo¬÷"Íâ`yÙßëÔ9ûîXÝ0±-w´ÿ¸/÷//kÛÍ·qêM<dzŠrnþ¶ls¯¸¬+ÿµ§«0Þ±†ºù¦Þë¿~U_þå>ß{/|¡ÄÓyÑlGß«ô‡§õçƒáôõ}L._ö¨ª,ÿöÑåÒæË¿Ü§Ë5¤¥&wšir ê»Õãú¾,H$^—ûƒèñIfå_îuºï²t©Æ Xk¤ÖÏVýëú>BI§:ÝA󕓇›œª:7ˆ¼ Tv:S‘ª›)Õ°ªæw>¬,yûW7ßAí.öíôC´yJè^×s· GI3ç„A纑 ¸¼©7¨Pl‘Z=IKЭç¨íu¿——ÒZ ÎU"Òw¾'‚ôˆÓ_^Ü ïÓ—ùê¯ßÅ•ÿJîÎç+F´Ý‹~ï„Ù@[϶ã{–#:ãýŽ<Òž¼u.Ùz§–-»³Ò‘föò¦™«u]ïšdË̪ÜÉF±ëzñ­}^–üouÃpíª „Ã;mJ7MîÙ’j4¦×5èž-é&š+&væçq‚3¼¸þ|¹gƒý€ÝAãø楹@Úã«ú¹>´«Á^¯NÎß^óÚíäIâ‰Fš?¸^l%ª—q-ðUšî*e`+ü5€ògï5¼©T êæjnlËÝÁU=ņe/èyÉb¯IÊ$4¦Òm›Fv%Ä‘]¤&4:÷z7-iB›y,~½à>¿ð^D¾çØMïº ˜ïôv`PW7ÒÆhÛXúåñÚ·¡|Ê#Qe\Ç%Œ×ŠíêÎ(½QüºŽ¬¦æl+Î §Fm+ôº \]42Bý^¯­ äV­æ’§{±Ì~[Öz©Šw]•cUË}?ŸI,¥XunÇš~°3éz¶±SÝëu¿ƒK—=™©åµ <\uZK—º¼¼¨çEýV{9ó^¯2–U ±»ü;õ'‡ÃwuÏ%gÃ}(àÚš\]÷µhMjiÇ×Y.Ð^ÿU§ÑÅ@ÿúº^Äqî¼€M{ÑôôYÆj=œqÕíµµŸ ºõb~çýìÕýìW;™Éý¬nêÙy?;p½Ÿ]_]ÎûÙq2*ÃÓ¬ˆZ:Ãõó?Ä~vÞΔ¹h”/cµ¿õ»M´JnIõ¼¤cKÂdm¬Õjäý­âaóóôòt}qu†m Ñ‚a*‰ý{ÝîÕ‚DÁ. ¯¾»½»”„)$èôMÓèíÌÄ×ðAM«E6ÑßzÐhGí]ðÊ\ù·§POT Ô«PÝ_ß&Å• pß¹Óí6Š/›•šuÎMvÑÎM^Á975:àW ì&¾©Q§Û¯Ÿ¸›ž·ÕØpH¡žÙÞ—™¥Æð‹Ho?Ò^w®'Å£ã·ïU„²¼êD ùÿéàQ(û;Jû‘íÉÿMFÉpdߎn¬áЪÿÜÿöÕR׫bK³IªÿæØ§œ«òÅ“· —½~Í¢÷-ËR(ÿÿo»´PÍv•âþõâ­Í•¦ueEÙ;¼†ŸûÈï}øÏ1äÍnWÏÝé^ÿaît ôqÝéN&ÓW=UO)Ï ¢_h]O©Î ¢Â;7ˆÞaéH¢Áº½®usJë¶^iÁÞí ôY>ÙñƒˆÏ­ÝÿÁ]¹Ý«ïwåæ*‚[»ý«ö|Ï=äùåA=äæè}÷=ä:ýëÖz!ž{ÈôËCzÈ5<ÙCî”´¸½NˆW5o´~-¾À´ÇºøE :!®‘j¡Pôñ¦Q—ù“脈é¶ê„Øsba¯:çMÏôÛZ¢#ïä‹P@›Äö4«×=b^ù´ÅÉ®”³‡Öì?ޱéwƒ›þ÷u«Ô¿©Y®¹µëm˜Uàõ vT¹Y#O jœâƒìÿÙÐMÿmOÐéNÐsŽF£fþ šFÛ…NÍ÷vÛû²ºOvG< pBÝ'A¹,‡uŸ<»·Õhç~”/ã°fûDÛGž=Üñ¾g·Û¬eã²Yg­Ô(B)ªÜõê'ÿ{|BŠñºÝrKLù×_¢äGjò¹Òý¹jäþœ»|æ]>Þ½@—ÏÎÕE£ª§~½$Ž$p©•ÚèlQÝko8D½_Ûú…ÂÕEÓRÊs'Ç×Y¯“cçÜÉq…vîäø2ÎwR¼~îä¸Å%-o§½Ô‚sç«~xTç«s'ÇíÜùêD;_u®ºN™çÎWüð°ÎW FާÐùJjUky˃›šoZœ·³W·3Õ±çÜÈqFÜÎn®›hý'og½FÛÙ¹åÞ!?<¬å^çÜr/G;·Ü{ç;‰Zœ[îÊÊ6kPpn¹·Ûr¯aqÍV˽Öýú€s£¾mÙhÔPfåW0íèv¯ë¿vbª0]ú:jïÅDâ»U=n¶ªR̦ͫ[üxt'Ø®ê‡õçÔRÁN·nµuò>ìEêµ­97;ò?­7ëvoêçhœØÞy ‰UÖïòxîḉó´)šµÒþeM?´‡ãHîl¦—ÃûþÍtï¢Ñ‹BçŽü°FGÐåêwÞñÛë4{ª[夷–SŽ*jèÔ¬Þ{v_WÛ5Í^#ᢴÝË#5;7]jb¿M—Z®ï½é’ÔâúçsÓ¥FZLhºÔ0x}dÓ¥Òâ~£ÊŠÓhÕ„9¶ïmÕ4JÎUìÕhç&M/ãðš4ù'WùpôdŸKØkÿçܤ)ß¼štþ\Õê ~¼ …n ^Oî=»ÝþïwRšGÄÊ¢Â5—î®…¨j÷Þ"6ѤälöÔév“es£áÔ îäÈaìjOeÔ­w—~vM,·4ìŸìl¢­gÛW*yvN¶qxýŒòÅr3þ¥T›S ŸrÕiÔ'£å†qÝ høNn?ˆw¡ï g߸ó&öòùúÜ%nÍ;óóÀÜ?kéüÀ“o;÷éM£4ÎÝúÆ™Ø× âî^”»€)á~¤®fËñ@• þÅMzš¡Ú=7lgVói_“gÕÏìf*ÒQ{Áô\Œ›£17ïˋﭡ³>S40+õB®úË^£¬“sÿº×بè…ÛïônöjÐH=//kFíÏêùZ¿ õ'mªÒä&äü–êÎ[ªçWñÌù-Õ*µvë›ùsO¢F{„žDç{Ú¹'щö$ê^]7kß}î–±Û-£é‹Ê'Õ-£«ZX6Ðs·ŒÝn9‘n½ÞM£^*×Ý–²ØåÁ# ï©É;ëq-ÿûNI(ÓÑ8¸e¯Q¿ñó‰•s@åÇ´B97:ÙÂùªéþÁ®Å™Nt=úÉ{ðFœ+èúOëô½þO"œØÎX3ŸìØF'[9];¥ü'êòxx‰ó´[š5ßË«ëz§ºC; ÜgÁl¾‹ÑýÖ»Y‹ØºýOà«KLƒÇÝ^$êiv}ï~\k4bàúòº÷änÞe±8.bÃâÞtëÃw°oZõú½fi?çf3{šÍ4L×)5›i;´9è´öNLç¢_³¡J¿–î»]«¸ñPe¯i"j~é\m×ZÃrlßoª“;€Ç^Ûµ®ÑG$“ÛÕ4ÑjF»š†·Gß{»šÞ1П\»È­âª]M?ï®°¼:{ï9Ú‰·¦1õèvkuØÓÁƒpÍ8¨¹º¹ ;—5­,.ƒ­i·”Æ éη ›žßÃ[¢1@ÿúò;èÑ{råÖWõí¼“B·€Kÿúˆ3V“6/¨š;Xw˜^Ãøo{ÚÃL«ÛÜm‚FcÚ„Îà{+Ëë :—îCª• i&ú ]þ–›g@öözÍ3Îí*«ÑÎí4^Æá5):ÉîGÏ÷©7…:w¬ì6:ínõi»P£w}YßSæµ(é`. /™pJ{TÃ]ëœþ³íl@é›[‹tr/9¹ßmÿ™†ï»—úϨì•;ùµÎÇÜíÜ}窅\ï×b_çÎ3ü°Qçл\ßé5ëõu³$É^ï?ð‘¸N¢ŸÕ*‰ê9SƬ…GQ³›F]÷Î ŽøáQ ŽÚí»…T°Fvlн8o³¯ý°ž‚ýj'³Sì Õ»¹hÔê@ªJ½’ð£“æÅìÍæ9ﺪ‚úâüŽ…F#žã®¯/·Ïùaï,ÂØ›¢oˆúßA±ÜK«&ÒÚvjÿF­‡àUXýzžçíƒìÑÙô­Ñˆ¦oÐí\ŸMßZ麶–nï+wi»n<×f£…ÊT7ªY #ÛÒ³û¡&³Ña¹v/.B?­šOÒO«Ó·]7õƒ'üó#hhD Úïõ_ýý°t¢T{Óz~mm=ݶŸÕŠfîAü}mÓ†â6­~í‡ÏÎ/´V¼ÐZ³ùÞZk`Ԏƾ® ½º{dY®®jµz?]¸„´¨¿,õo§vÃG{·Ð`½Ìûý&߸fª6ò!‚#²¼Ëó:…¯¥x«ðç瑵¬ï”í²IV’ó‹‡à!ó·u¯@Î,k¢›w Û(iêV=Ë–5ËY\«±D5\ù…ê¦ʦß×(Œn'º¼jôˆü¹9õº9uó¶>yÕxËÙýËëú—'Ö¸Ôüí–Ö5›wž{]¯qþƒºwþ°!<|¯kÝyô?'¦ôR¯ës¯ÔþÓz¯Ô¾ê°Ðä–¾õ^©HŸëŠ^©×ºì= ÎÍR ´s³TH³ÔÞ V¼°ºƒTK`pÑ,UçÜ-uO·Ô†%&§Ó-µuU?5áÜ-õ»¥6ÔÉ¥[j¿iÓ™s[ºŠ¶tç'Q ´s[ºÓmK׿¹n”gW»-±¿&X¸Õ^î2Yvüz'âôCaíÿ}yq£¯*·ƒ‰ž¾¿ìtF"IÔ?§¨<–ØW?y W"I/@ÅÏÖá\ëн蟻Tm¢•¢«Ò_Û8êw}yùõJhõÛkpúò¢vVÙIuÄ”‰/ÓE®ÕW[ÕÊV€úVf´ü#gû²ûun¸vnøk¾½š%ø{Ëï{׃ïk3ËEn²¡¶¹uõ¼ÿn›}5<Ž”š}u:ª%SÑÊäUÈÑο6nRz5/+z~ †\ú—²Òj÷ý:™F œ´Czwß±ÜDc–Qß ¾3³€zò¸ Š:¿"4Ü’æ§QlóÜ×í_Öëëjµut_·SRÎë&ÊyîwÀê×n/L ‚ Å ÏÝàøáQÝà~vƒRÁì77õŽÈg{MÁTÛ*`»ÁÖ·È«F¹xç&…‡üð°&…s§®5Ú¹IáË8ç&…¯ÿ `Ÿ±M ¥µmÔ¶v“BDœÒÛ°á»å¿U77ìô¦"-’›TÙà9<§Ñ¨U÷ûßA2àÆCªr½Y|n­bH[pDíð‰uß«yrP÷½A"Òâ¯?‰tæý÷Î ûÜ…}n¾·ƒ¶ží¹VDè|ÿ‡µƒÛ^Ô@;zuÕkbGÏm9Öm9š×D[ŽË«›FQ³Ú†Ä"AÈ. ^:ç"ã5ó&{pqù}Yø~§fuûöc–Ø:áúÍuέ>+Z}Ö3ê'Úêó²öóq›ùùƒ:ÙRiƒîºØ d-Ù÷%÷ÍßÕlóyîúx^9@ò½õÉ+Ö'oЩ럻òîïÊÛ¬Q3«+ï Ó,ñ¡vI+*áV Ûôµžßö”ÂN÷–ž=vÆ nK­þÞ’Ou1h³è6»ºrйién»º² ­®ì«Ø@ueåþwwwê_•NìçKv®±|ç\cy˜§^c)ýì¦vÝÞÅNíÈüÖ\‹¸V«³=x¥[ÁMãÉ6|;^ï¹¢”è(t/Õ²}¯e¬× ;–ÊXU¥Ú¯a’žO 9Ú¹‚\Áª” ¹â›„øÏ¯ûè×}:ç×}ö_÷Ùs~ÝçE!ίûÔúÏ÷þºÏ [{+úAú(\5ÌÍ®ÑGáÜã~ íÜHÑ©þ¸ô³:¿"TâItî¤pàïLuR•©ÿÝf ÆjwR8#tÚî†pî.´‰FܯTþïjSl·»ЀÔ~«ûÜ)ÃH§Œ¤‹T°FîÓ¹SÆ?<ªSF»­XZwœúZP}¿ß _zÙSñݽP§<õ·î½p=)§ÊW:{N9Ú¹ð\ø½£iÈ«¯ËË&–á$ê¿1Õiõß½Däùp"q’ßfm'ÊWû?¸«ý\ ¾ƒ¶•§µ]þŸô˜óÆ2Ǚի‹N£s@írppI÷5Æ#_–b¿m¬Újœ3Ž_B£–t{ݩ۞SŽwpx)Çà4X@s“6çøGÊ﮽ÕîÁ9çw¿ö«!¿ûê¢×¨UOí¾,¨ünT;—nÍ'œ÷FÅJ¾ÚÍT¤#-ß9 –£1ݶ›þ÷vH»¼hôXÙJ»€f 7hù:¡÷1üò»âY]~÷Á»{¬xÿø®êýãÝsÝpÔ9÷—Öhç'‘_Æù®žDî]]6nµõÃî²DÄ®jþœñדּîê²5Fn‰7ÒcÚn‘Ї4^=@íÌ„ódó=ËQrn ¼D;wExç¢6 ùB­X²nÖŠõÅ“p²T_‘ðrvÈÿÁuÈÏ•b;hçôcTúñæòT¯š¼&Vóe9ôópu|·×Ÿ‡ë+iJ=cG=ë[#3zî${ÞzQßÜ4Ì(þAÉ&a&Ý6äLºœ;Õ§ÝMÖ•ÖÕ lÝààǘoLvEi¾kícÕ`ëùVmÈ"}¨<Ù— ëIžkLK·…ÚÀÝÜ £÷J>6õu'yE½û ;Ä^× ŸŸpÝpÚVO¸Ö£œ²ðÎO¸®ÐåÔíöÚ > »T›”v•ìM[ëºÎO/ÿƒºn›×]™^·ê[½×ëF¹m·À¹Á$}-[à Tõö ÿBùϯU‘k^IyŽ!W¢›á¼‚s®49LŒS¯4A<­sn†ó"­N¿Ó<Áôè¹>7éýŸïê6*÷#p·P×›Fíp:—W5ßœjpÒbvŹ©W°ï´ÕÏ}¶'GD*’-[Ê»ÓÞ\ÞÂä]芾ú¯á¨{nƒ¡Ñ¸½r:g¯n­´ñ9a½¤Þ=ˆ'âgàºæ.ØW)7º_\4NBÿa=ºy2=9µæ{»¯S–v¢Z[M)ççitëî>e?ãêªN :ßå²NÞà^ßàòNÄ“0žÛ#ÞÛ©=È"×NEÑ^þªôo?Ùñƒ8g¼P/X:MK‚Д›~14ܦ¾›‹ê|5ã"èÝ‹FÏÖnTJì8ŠI».7MV G+ÏVçƒÕ?¸«Áࢽ¶5øsÖÑj-¼=påôöëÓw>‘îÐÍ^¯{MR­;ƒn­tgH…]¹j¥^ª÷ëÙÿ5 tíæú«å d˜¤Ã'áY?~ö:Â+¹C½ëSOëiP7Þ¼lœP·vݯ­øçÛ8õ&žãÙ~í\ ²Ýè×+d•`orŽ«é=ºµü^?¯Ê@Õ¬ìÝÖÄ Dœ£~9hôÚSíVâ¨^h¸ä Û›ü¶§ùto òs“F͇|o=Óº‹~½•TÕ(‰Ûdùúòº®/zZM–!]ê5Y>gÃU£Û.¿ŒsN†;LŒSO†;·]Þƒó×vùœ÷"ÞnZܪÃuë·Ü—7ê¾×ÆØ5_¹©1v§#ýðßëRˆóIO£»cƒ»c/ x´S>sƒ¥ÿý¶·¥vÈÎÛÛž;do¡ûÛþ€²¯ÕUcR·Áíɘj‡ì¼Ií¹Cö&Ñ‚Ü\ ¾³jÛí]çW„V³×ƒ^£—ÿÎ Œøáa ŒëµUÁ50>%]lÔãýÚÌöëIpX›ÙD¤Å_ÿºÏÃóë“K´scÙ—qX³=–jxrb³^CÓDÇÒ‚ÆÅ!n:M²¯úµ mŽ ?nØ\õý½zo?ÝÒ»"î8Jo”–¡Ó·,/±¢Ð R[Ñ9’ZsÙé~O¹ƒëZý¸v^(kV»)‘7ý‹Fþ~ÛÍ™:˜‚’Uw¦«0ëÅ/´g:§ T¢2½‚sÎA9LŒSÏA97dªÀ9gC¼ö«ãSYo:õª7·ÜbGž*úÍWÏ‚þ¿—u΂^E;7 zçÜ(è 1΂êýçÇõ4΂þ¿“ktÓð™ðÚ/P)”0£¦ë··ž®Ü0c*RùŸ’é9ý!Gã:Ýï,ÿQ™«ðÄq}Ñ(ªv]-¯@ö’ ¹˜ì]$ËzÅáÔ îäÈaì. ‡w¼»Ç¼¹Xg$’DwR}?JF—–·ÓŽ:瓆F#‡æ/DüÀ §Ð]°SÖilOè¬l&"víÔÆ9¾¯Í¯é5þ F¹öj¯ÞSª¿¬7˯TŽwºQ,&"ufzKóçêýÛ}ôa¥çË9v®‡5Ûád"v¾¯[œïSßÂïoaÅÒZa½õØã7ÃF(¥¥Å:Å×7ßYÉQ#Ÿ¡¼wA=„F©ÓßmíqÃtërí±ê9ug§³·û¯LÄÏçhYŽv®?GËÊJ†4u;]lzu†…êXè<=Ùcï§I;ªç¸Dàz½wl@ç²r9;KËÊ…±²`áîû‹š™À±÷¨Z×””Ñ )êHPº—i7ÓôzÐ(käû-h¥ÖÄç­çšø-´sEëéÔÄ×ù¡Œðæúªö±õ\ÒJ)i­·yþ€%­R½äq %­— û;RÒz÷Ûc½^çìPÀsIë h¥’Öl2ØÜóÁå”çˆn_–šò“‹Û~G¡DRq÷¢v'¢ ÷©Þ›%àçú®ëäÏíÛ«nô¿“‚t»r’K¯ó•lŠôší—ý†wÃQ¿N.͹zø ¼Òì¦áyì}¾–A³QxÙðöñèÉÆla¬ÉÎ ™3¸Ä™ïæ­ÄjƒŠz’¥{ѯ»H$Ž6)TÃæœ–ïÄjõ*8,áô]½æTç-í ù\ ‚Á›_Ãðay¼ “tø$œšï‰n«Ub4x?n§ÓitÆ=‰RJL‘í‹¥”ž®¤ÔhçJÊ—qX Â&ØflÝöfúÔ©„nƒup>¦–Ñ6ŠVÏõªÇ{ª¬zÕN§IîPçº_gWyŽ%§ ^½ìŸ ¯ü5Ý)èºì¹ÅB9nÃá•<%|•zw΢f]]|WÏÚÞtk>vžJ¥Z>tëªê¬:èÕ*5ÿþϪZ1±½‡— ûô¾ ;ªæ€¸|Œ›N£‰Z¯GëBNœ«z´kÇq.H«…v.H{‡Vv.GÛÁ9_á½ö«£³…ê…·6±¥a‹nš=¦÷ã<ÛÛ°Iøžg{»ç$¡=hçÇz_Á9á×~ÕÀ’n½i ´§uã“%j}Ã%jê+zꑉã{ýZÅ5»ù£ôFI`)TWu/±&Yà¨ObEç0µ^å²ó]…¡×µJ!wZåo¨VËᨛ~£þ5§Ô ^ìZt:yáðH=)î°B;wx‡öx˜ÒÃs€FzËåŒs³º^³ck§ß«—J‹êß/V>çq&·Vap…Å•.×J„šÙ_;Ÿö¸±õöÌûðZÔë6{2õt^oª•‘Ýž\¼oÉÛ,•ÞûÛVßú7ñœè}yÔ=?®ÑοŒCÛš…‹ôÿÏÞ¿7·$éÂøWñ_ãyg'p¿(z'£¦wôºÛ­#ºût¼'IS%{qú³ÿª^ ‘UY¸P¥˜é¶ÝfV±.YyyòIïkø» Gqd¿"­ÔÙ3Â4Å_tÛQ¹}ZVQ“bE´t“ËBšjMŽ ËŸ.ÊqÃlž»Ê²*§&«rÊÀTx ÿ‹Ó…yëùjüÇPÿ`Á‚[l­¤>.o_nƒçÙó\•Vl.MVBœ–#¬h?‰_¢vW)?Æt±&ìú[Ó±ÊÔÜ!ÕÄN€§ ÐMuΠÕ2½›ÇwŸ> v ­É¥•B$Yú RÏ‘%OÝT ™.ªJ;,¸·AŽÿ¹ËǃCåÅë0ñ³8ùáDugò rTMá\Êz2øöÍ¿þý!NZÁ†³1øŠ¿TÅóŠy¼¨eSLÆÛ¬^£ÕBÕqßLÅ žšS£KªjüN&rM&®²È_^«¸¤Šé"¯lYœAÔ¾Ù‘«çíêê W‹G …ĽºA¼ÊÂoÐj#ªUo#J½.¦!ÉãwÂD¼fþ…’Çóók–u£Ë›bî[7n¯ žRÔ4®ôÐà•Ê: Þx_©ìgsµˆ’õº…þùÓ<•õ[ÍÒdÁò9’å¹Û4Æž.Ú$ËÑá¿/6]ô6‹+ÔœA€/€Z¼ixñS]ÓÁGV‰w¯We•x‹4Y%~FŽTÄç>Å¡JEU‰ëšÉå‡+@±À¹hŠD*w¢ƒW¥rô±T9*»¹4±úS³Ç¥‘iôñkuCÖ2vúàéZFåm×2ÂË=¦Þ–¡éÞ[õ_¿$þ*}™¬”ͱ$néXáô-¨)»cuÇVe‚³&»c·‹‘ݱO~ˆ]-bwÇ&*±_R‡ÑuǶ8“¤Íݱ5íqW³\傞v.MvÅ®òµ©¦Íéj76D¯Û²¸HØ&[¯Â" §êãM¢ü%Øz’J »@äúø‹MWl@ñðqS®»dÇ¿èUÆT¯ŽÃ£^Ç@D`ãpjUˆ´ûð1Zm'³¾-Ò$Ái92é{îSÌè®þ å˨Km®êE” òa´½³ ®x;½0mþô%ñ£,•õGï‡ô‰aìg/eCm´~s V^—Ðod¤oŒÙÔ$}6Cè=‡w¸pÊéph­§¸4—`ëóÓt¦€p…SÝ ·!Òð{èœ=5E1‡±)÷›V7˜.h@±¨æ½ŸF·ŸÊÍ+ùC5xò/ËŸ¦›W¢„8Ùºkc€D‰¬¸à†Ì²)ëèš²ÂÎd‡¦¬ƒj1ô§ÝÉÕD©O8ÔG]±ØÖG6´r5(Xưš¥ÉúÈ3r„5tpƒX²¥ë±´2ÃòÑv† ÏÊâHðOßY. “P³7öÏ^pÖ0]®D׈š¹é0ÀF—fnJJ6o]˜··sÅ£Œ ¹½P0Ÿ_NjРÿ˜Í !È¥ûº_¬Õ0Î>o#2@žE‹´ÊÙ¦×uÁi;i:”¥UÖûç”iü¶ûn_2˜òÎErìÌà*û˜\—i¾èUµË´ây‹Ø ü,xšÝ~š{··/ÿ’ áQ÷™¾ÌÊÏËž/_(Äå6y‰œ˜WÇâ»Úñ=ä®·-½€.o<ójãØ¨æ]eµãM†ÐÒ¦Bl˃›V»úÝ5p>ÄvÀךš¡J‚›•€3 ò©LK`¼>ù™,‘*¤‰l”k›.w¾_oÄ_éz°&ÊUa¸®Í¥VÆÓwÛæ4—ZÚþbqh? ·mb³ï·~ö”“ÒJ}òN°>‘·ëÒÊ ´Ä0iøfCI'n7^bÊT4®:øé¸òÚo‡×ð¿eqëAš,n=#GXq+ÈÈh÷–‹[w=åþã?0õ«¾¦c«p’2w©pÍ!ƒÿXÆÁ×Ùmð,ÁÍÒdëi9¢Vû~óð€Üj[׆[Ÿýo^ý2®B¶Û®K7f¨_[A·@\¦ÁüýB44“kHG-Žâ¤ÿYq”©Y|åtªæÂÜà‹>1AýÄWNgZкlU[scê­jµmÔEžlU[D3mž«k xsùÜŒ6µnþÏk2Ù¨v'LÜ¥‰[¾+{™`¾5?ý`ÅõǮo“èÅÏàEéM –èåÅS¦˜V@öýþ{SßoI‹¿&û~·‹‘}¿Û?Ä®±û~›îÄy-x;EÕx-T%XÆiØÎl!ÓVÒ$§Å9Â8-$£Å‘™B9÷)Ö  îAµ"fP\ÎB„‹i@ÃÑPo@ ÈW®»@Ùsú”4äfX•‡Î± @ÝNwf¬ñ@Ô½|Õ#b¸1`éÄp,C?)1ÜHúNšSxµ‡ã5<í„¥@Ûñ]ö7Ù{„Óňpjƾ¹ØÓ¾»ØÇ(\.òÚª¹ê‘ÿAÆ¡cÌ×~PÖß2lZæL¢Õã—x=‚ž³f¹˜eC>]ÙïkøýBÖ{Üì~„i:Âå·®/u„DhkøXÓÉhApKáj£«9ÆÍ ò”+—Ãè hƒº+KØÅN˜@¨w5ò¥>tùDVº¼—ž“…•Ûˆ§- …+e8ý6ÚÀ2‚®m´e”f­ä’)&—&›iWò1®jpÕ¿ž:rxIËи¨°ÁŒèÔç•?0¨Z˜þ:œç®¯älÙK«DÞ8‰Ðc:îÙ\:b#ˆWž` ñ ø"¸ þnžY/!u o‚¹O‹d|‹4Y Z΄ äUÍV9]ª FÉù692!yîSÌvÇøJä- zQ+Œö ïƒÀhPý‚4·GÌÛ0yˆ“g„?ú™¯j‹èááKâ¯R¢Èe«ØfççÍï—”ÚÑ@g®vëËç /ÌH™½xb’èà,ÑÁeQcX|~ˆ/ÇÜý·\Ê@¶¢×h×Ý/ùñï?ÎÄ*ÏgOÅ»à¼;V£o »€Fß6ŸQYhƒ‚—rË ºã4£ºÁÌ9MG òqü¶6Ljt"CžÈS<{"zГ©ñH¼³6O°´¢.¸€³åò5†ÛÚC G h27¨ªÀõ ;W\,CÙèf/Œàè¬ ±‹í Âè%,æ:›Ùaö…˜mÒiëÆè‰*ñ—+^²=RC_}(Š é9ÒÔ7g|ÃZ¾µ=GÇê Á¼©Èóu Ú‡v\´"6J5õžVÄ|þºˆ’Ùí'úÌTa9è_2Ûß,MòŠœ‘#®“ ~ºšîçmA{ÁÙþM²æmD‰~þ&´åÅN¢Ç'P‹Ä‰%èj ‡d?µ-r$®âܧ˜qÚ\hÎÜxÀCTØØë—”9'ìò:eœSpÝJÊœSÒ$eθ)slC»Ê§E\™2ÇX'ñÚô³°D›£Üxªt¾ÎFhS]®.].°×ÛP­ (S4²¢êž$Éæê¬a=£Šé¹‰V1cžÌ䃇}šg.G§ ªž·ˆ½Í:ðÓŒF4UÅó‚oßüûèEUmòkºNÞþï%.Sg"™âMU“ {a‡…ö¼ÌOCþ8Où•ty{z^(Ï‘çÅ÷ÿòÖ…»ÕÕ;ãG/êúYR«g†•+y&øÇÔáÀ²ˆÝx4% 3ò¦¯Â€ú”_¢ç0Þ§ÐÉȯÒ5Óó&ÜôÈ?ëÑ;+9™^VJäx›«q¢t&å³4ÝrÄ(¼£ñÕ7 Ή¢s–)•8QŒÍJ²¢4J“¬(x¬(ÕC6‚ „crõ®/Цàó¢¨*-#Ÿ‡ÏኘU¤Bi‘&©PNË™ŠÎW¸`h”$Bi“#;ç>Ålj ¡l_0<—Á±mðC4*TµóXΡª­Íj­¾¶Ãª¥áÐ,M¢ªÏÈ‘¨ênÓ»é QÕ r¤ÕpîSÃÀ|‹× Ó\p¡çcÅšYèíÙŒôÕ_Ïî$Nw+M I`YŠ)-‚Š4qJ“š_Óš|IrñT¦ËÕ È‚ñ 6⣜t0ºç¹ù?¯ÉDJ $î«“¼ÃE§½W¹¤](ìk 2š¥•Ä6gKá¤Û¢¥X…4JÐË‹FàÂ&Ê("˜ÑפWYø jv–”¢Aªh_ÓðçR%ÂBamWvý<+A‚0W™ÜëIqõ¨$è]W‹ñ:L|b¡ý¦Zì^9ºþi„<©{ÿ4å± –)û¦åÒdß´ŠR0\X&ì˜ÁK 4ÐU-®"Ñá¡ î:‡ZIü|.ý,z óNˆ¹%‚;iålG„ ³æµ§.8p—„˼IâØÒK=g< ª¦¦Hë—{xP&±n¹ÚÛŽ”©âƒ2Šhù\Ì"‰ªh–&ᘧåˆbózXà¾z‰Y•&3ü¸¸@ªE+Ê &àæ¬x eoCÁ ¯Ed k'L`î2Î ×"Á«žÅØKékš²rñ‚¯.¶œd7IД»w“´²8ó—»¶I¸dGI¬Ž’õ³…yÿ®Ðªjë°€VWÉUøÊàOÎ3÷Þ_xþrÀ_ -#·‚@BJLŒá÷˜Ô…§±ªIÐZ_ø/Ñ2äxC D¹­HòÏdœM+¶R°4‚®¨*Jzð¢*B:Ô¡UEò|²U…Œþ5K“5UgäÈšªnÓ{PÖT5È‘×sŸbÎ0rÕTåZ°• <æ0YŠle€t”¬ “/ŠpÀs\­?'è"¯¬M]Îb«¾}äP óX£óµ6Árï‘;› øõÎ&@Ïmä½Èa1¸è·FT ê¥Ý©>VÓö”í·Iø} Õž €·“&û2œ“óÆú2\¬ë·Î5Á輿~œ>¥:8êQWÀvR7hÕzsÝ Aõù®õnÑÆ¹ˆÓÆi6û³Ù wkhÈÇÑYèɉ„Ò#cHÇ'òÔÏžH§|"“p{ a™ÃH Á9šúæT$¬‘F›;c5¸G8„yCŸH‹³‘ëxuà,ªùJÕMÃì—¼€Wöéh•&ûtœ–#Ìy]§²M‚KÕpÇ>†ÍU¬?‚R\X½Â‰ÔéE«HÔo¥ T›ü9œ>.0#ïâÍÏÏ#æ]w¹Ì©1T~j(·½­òSvâh‘&K?OË‘¥Ÿç&1öÐ?U² G£‰ý:÷)Vë`tÕ¶ºîØUñlà Ǖ½•²‡@oþ«y¸ZÍìÇ0ûBœÄx Åx9oËo–O3ׂ¹\µ`Û#5p¨Õ„‰`ÿ T|s Á”rþšnâ¬:ª CÃ+ªšÁ…W|ó到,÷Å•#ªºÉÅ8tñš¦¢÷ÅkF¼Wíµk’ºªEš,^;#G¯u›ÆØÃ²x­AްèÜÒDN( §[äÈhѹO1G‹ˆ1ñ•š¸ÞWx¡"U·¸ˆDe-ÒÉZ$N"œZ¤¡Í Rª¸ŽÀã(Em@4¬b8¥[\¡ÂìèªêçxE»ãø÷ËVÃÊí5àø ˜²¿P~ul>_åÉéþ༿Mâ, ²p=‡5íS:L¿îy]`YPÀü…µq…´QÝÇ©AåÒdWä®"〉år… Ç€nΠ3º‰1» $¼©Eš„7–#jµï7 "“6‘eÄÄ8U¥–ûÙÿ&!NrdÐêܧ†„8å/$š¡ zϹžG:šÓ¦øTÎG¯O¾t¶ÒDVH¦9±'Dý{tÏéÁšh”R3Á ÇRÀ)ª8€¨ÎžÝ:ùŸz‹Ûéx´H“¸„3rD-7raE‘š“~GYšP7»~ðb]Ž Þ¬ ® N4¶D%œ‘7eO3,®"Wj, :w¦$HJà„#_(AwØ©0V£„Ê‘ýÍTÜ á©°BáÉVßÉD®ÉDÂUùËkMö",„ ì¯eZœÙÆ íE'Ñ#æBÜæRßåÕˈVû£á•(« "ŸFî%@ÛIytOÁm[¹ËÃP¿Ú¶X %Q½Y=IJÁ;¡jU·Î Kß·}w2ðî¹ .-Ýs f!7u0¿¹ù?s¼Û\2…0q7Îuyý^¦³•6K+gõm^sQ´^cäçª&­ˆ¿ÏQ5çh¶8ùÅêqåä&ž+dZ— | Ù)NªÉ¶ì”ìÏ}&³S²?w®nh…NŸÙ©ñ¤pÒƒ7¤¨” åÕ’Z'—&ÉP*Èšâ‹Ç H±˜ŽÅU°N± h¤ÌŒÉ .ÿÔ”šÑ÷aóyô?³•&Òþ°m“ÛÃîYpbä*G OXS¯5°:w g¯Z."#òíÒdDþŒ‘ï0‘gø‘ùseÅÈ i²b䜒?÷©Á*F¶V¦!¬sÂ𠼸èºÊ‰9j®«Z—Ì_i7Ki»†* âª4©U‘ÐÜå˨Vmè-­(UÛ±} ’B~37HxˆçPˆ!Uãw2‘k2‘p•EþòZ¥4Š-‰"»È+ϘoûwÆÙ iYQ 'Ñ#æBÜH©¾9«—Ó̲¡E/p¼iCL>dò\ÚÐÄ£{ MÒò³A9 ª¿¶àïœÞ7«‡XòᆰVuËá4_û¾í»“wÏȯÊ-×—œãŽ7\ñUÄëï°ëÍv»ËTo€ÌÒñÝVÕÏñêšÌÚ¿_†°›Í}±qî5æµF¾Õ•\,ßf¹ÒÝoôûÛ$ΠÐsXÓ¥ÃÔñëvÐ ØÚ)m€ŠRUX©i˜Ñý#Êg9£Ñ&sO“\ü¡³ÿ¯2öôNlìéÂø@¡Úi‡Õ^Ócˆ|r-“{½'}*ÝtÄà“£ríÇ@%Š!u¤p‚eè'’L Aš$ÀºÑÇg óbk\ünºj{5c‘ D\dªÂË&á´œbùJlMåìàèZ0ª¬s@ÕBD ŒÁåd˜™gªrï/ò°]´à?;I­‘±Áú¤ÚKÚ…_ñzIGߪ[¿AMŒÒQ²A--ÚJ_Óàl²•‚m³»úþG?ó¹£e8Ž2Š‚ioZ5Ï's/Ÿ4õÃ&{¢‰‹‡(ð)¤ŠÛxO‡˜¯ý`;N>ÆÕÕa €¨Jqž05ꇦñKÄýæ/7ûº}¬ØŽmZ\”ƒãêßÇÕSŽßß ‚«§1üöæò_nVëM6»­üÙ/úgÏkÔ,M‚ïÏÈ‘àûó;ø>¢ŠÁ{ Ô5wl…»˜ôbøñ&±æ®å ×&cì(ü¼è}É-|@|ðÏÔ€ø[³/¶gƒ gŽœ(.Š'Z‰ò:¡wK¦^k³[ }'ßÄŸ#½PØhq#0—ZÕ,Þ¥fù4”¬rñ"\¶þÆÉ}T¤F7uìÉc {"“£¹4ÉíSéw£BÚn7zà#lÛ±!,”Ècñ`ÕÞþúZ6°ÚK“h‡ M(çu.0ÔÍU—ü–¡(FupT“ËГP‡-ÔûPLêà¨ê\×Ô‰$›“tž9t÷?Í03TÎdÏôMªÂe@\¼ˆpZ©È—³ Ts­HòÏd@=T?@[) àspþhPM‚KzRFË1SÍ*ÊÝÂ$YÅ^{û߯É,¢}+çªÇFhDÐL<&Ë_KQMÉ@;Á6‹,…e9‘ ʦA¼F]gþö—Ì+aµÒÏ)*i€댃[µÎ«ðu†ÑEMè O3°lÔ-Šö—-YáèP@@Ål¤Àl ×IøjABÅí`ÞÆñ×/‰e)ЩoöAÐÀ¤¡óòh†‹a9£áŽÑåwFUz‘ûy`¸¤l_jD~)¸Ó Gò ;ž7)÷™Å`©$M®µÙñtv¥³; ×ÖM">êÇ1z0£F•ðgR.ÔÙ–>¡ÂJT锄Öz“,q‘R®taÂp©Óò_ê–éáÂó; Ê®7®b, ³ô¹b,³©ç¸¬±j–&k¬ÎÈ‘5Væ1ö«ûÍêjËî&ui²ßøi9²ÆçܧØm|ý¯‘Û_;&ô‚¾ÿäåý”ph)ó§ $ÜðdnzdÕÆˆ;4Z|C­C›þê. Âè%,¾âl†‰8m[ G[%läy¬ŸÇüWópµØF>þ™ü0â+p0MÏJp®@r{§êqâ„hU… ­ãl.:šQ jw¤6Ó0û9Ìüe´úú3­¡êE+ÿIõw28’K“„çåˆ"~Æ€ÈU±X®3-·†—o¸|½‹/Ö ®ÀC(ÈÅ*ÜãlÅý©©rÏÜ7>ßÚx…{7é©; ,÷u°Íá¢JcN?å‡ÑËÿ7JÍ›€¾à õKÎÔˆúì¹*7!U¿¯žJßއ¯¦Nñ>WÕ9Éö¡Š/wm"'ŠïSµ8Ñx}ò%ÿVšÈâtUåíDÖ÷½7@5sÇ1|r°& êtUC¬vùäÉ‚U„²ç ¬º4õÃu†$Î|‡3G8ISÇ™»†ÉÕwbp@/§BP¶LÃðk P¶Œ$œ¬Yš„“‘#ádæ1vO=~xHCdŒ“£ —À‡”áæ–þ#rú…ä$e'åMQ–ßE07COëáôIPÛÑ••&_*YošÊ¥I"ÔJh*ÏóŤÅ$c]Ëê·ìx’±6gÉPc2ÖªeÒÙÝ<³^B渙gÆÚÈ¿Óy:›û7sÝ›I§/—&Ó´gäˆW¤j‘¥e”–¦5"xyÃÎ ög•´¡¨Ã-8¾?‚ġی¦Äá>¶/³†%i"³†šfLìÒ¿Ù¬¡¡è§Vf|´ o²A«Ô²=R·”¤ Õ-†9± ÐÖ-ÔièôŸÎË­_KÿÙy<Ï2d°ƒ4™<#G&;Ìcì À5ÈiW¦“p‡ rÈäøG&ÿNË›ròÏ‚fËš’V÷/}Þ³,.4Ö˜Š[QpYõ4ž–†Ù§0\XF/áì^ÚaïÄÚaVº rZ¤Vû+9ˆžOO¢G.\3Á²¸«§úU¦¼E¬ûk©N°Ås)ISØvtKšÚá·,ñƒìÚžÂ/ñ×p%ãi…´±§EûU¶¢À^ÿš68:fˆ*ÁqùJp ×µiGJÛål.=ÏTcÛF2.fróJþL žüÄËò 7¯`­¶N•ñ(ZUŠkó¥^LÅ„ÅGÇqZø[–æÙ—RÓQ‘‡egEÕ¡lÏÍÁœŽ·o¦â OkR_ÕÎ<õ;™È5™H¸Ê"éÏ)Í…âAD˶ ]䕜4ÓâÄY^h[…8‰PÛ•Üì´½öÐ25 Ôfª¦]ãu˜øä!ú,A²|W¤Á³*'*¡^l,ã´Â^/3Òd¦ñŒ™iì0±geBFƒ…ÛjV®MñBª î ]¦®5mˆulÐ{´ÅwΦÍà °Ð‚ü¿ÖwnžùÙÍê!Võ‡$~Ο<úGÄ#0h³léˆó t‹—èB}ñK³´Ã2›·ëÕ§GÀÓU·r…ñ\›Îæ ^y‰×Z2ååL¹LÓäÒdµ+2£€¤­J{Iô™´}uPPÉÕ䫾IÃRâõöSÑ6‚üÒŸÊkþNì5çoa{ÁÑ‚,ÏÕ¢jUÇÒ¹HýjU.LåŽ#êTWç˜Ce½YÁ¥VâhiLñ9¼U—“£T$N$¸I'Ç §…¯G„é×ýRNËâ²2šî…(‘2¤ ŽÖËYá,h7U`"ë¬,ãÀ_†^@çBÃò¬yd›3<Ϭb*惄X•Ü&qY¸€/G=*HÇü@©Ðb%„¨Y lV“Aêâñ* ¿Ac 凴m 4Ø×Å48 n¥@$ ÷44Ãå (Ž1av:T´?ø‹—¨‚2Y>ž{NñÇ^&cF¹4 19#GBL:ÌcìlÖVÐŽ»ÞKäx¨Nm•¡¿ —=€¾hnW5Íq­7~ÞÚ xgÍ„Žä~‘ÛÇ2Íyü•tÑ­þZÝʪŠwBTü¥ïŠ *næRœw©Y> AQÕeå6¢¡4[¿úÅ‹­©=×_,J½“çDJßµ»À‹%Á]í¯áwdßU¶L®I«´LÝbOÈ´ß«NDãÞ[÷ãCêq6—h@êÙi˜}\ú3 ÐS·Hÿ òI^UH“X½ÓrDR-â®¶iν^¸\aäõÚà†¦rôöÛy¿¶Jñõr-^è’ÄD ¬ŒÜäròȽa”ÛEÁu \ªM@}ØJÕê1ZEÌ/á«ÞÖ¦ÙäŸÉ^\PýÉØÛ¥cx[£Ylp™a‹Ù åܧ`ð‡è…xpðCP¥º* â[³Åí><еç@òú(«¸ôúÚ?xÖëË5''bïòñ±…Àå³5.¦ùé÷žÐ‘º„×zO(aVL:•' i²óD¥È0¹Šç ñi² ‹GŒ¢š‚»ëXÍúØ©šUÞòwbo¹,f=’6öbÖ~u*B7ÜKÃâcb› ¨£+›j¤av›Äß¾ÏÃä%ç´Ù9¤6}'V›JZ›#i¥¨9=“v¼‹^0µzõÒÝFÔª6¸Dmtf*P¯wk–lV·Ix·YÑÀ‚t; i#7H'RåR•s‰§LKë—+ptÁ+ƒÓÙm ^U«Lj’\š `U-Õ…tÞhò¶„˜Äo<'›‹ãmUÌ‹¨á»ð1J³0¡ŠX¦·Ò¤…0 ¡r4ñ´e*\Ú`úF°©¤»:ùåó<#GGª’Bš4Ê*FÕ`쎦:p¸N4ÛµJÃ#8ÙÓ€1s›hüÜ&î~7Aò.ÀjL¤M[bY<5¼š # ;¦¡”e½ûà¶ü tªDOïíÍê!VÕ,ÎÑôôfw¥†’e™¹L,‡ ¡e™)jE¦éX¼”1,Ÿf¥˜Ë§ËT+]a´ê7 Ì=‹MÑDL{Œâtƒúü¿&у…¬[“›aîÒõ$Ùé‘Uúöy5ô(×®oõ€âÝ`l%UÍ$EÑal4Nà8õˆ­2›Ò¶ÃmJ;»IðÍ;9ƒÛÌŽÍåZª¢ÀB£9oåié8Ø~´Ü$ÜÇb+$âËS¿Â×RÀa²á,JcEN™"ú€é«¿žÝÁ ÊÀ[w(uBšÐòb롤ÈEÆ‹oÚ˜Ÿ_Æ7»Ç7±Z9 m«Ù&TW»8€ÎZ%!}·ìZý  …V6Ñ-û'çË5˜*L@  mÙ\RéÆn§n‹GŽWS(éÆUÝ8Îc1q7ÎåêsâÄ5°WAýYºypþœòúËö²ý)1‚ÚE3š¥Ux\ì Ó-¾~Kñ:L|òXýZ Ý1t®ºkø“‹RãmuÎ6ŒŸž[ãõÉÏ$­&Øê:6g¼ï(j=xtíéÁš¨æ˜\ €=Q»/:`¤]óEU} ³m»‡´…ÉSrÈ gŸ©–&í³ƒ0ô°:*iç…RÈ¿=jóŠ-¬<È’’>ų†M0-º¸¤(íKÜrÏÎ(öî7Ñtû]ð¶žv-»EF´;Žì)Ôh‘Ý"+Âd·H‘Ý"á˜:Ù-ÃcÜu‹¼J]ÚEžì¹—n8`†8žn‘ø-AÃwhùHÉ6¿ó!ïÐĘåpr; ¿w·›$<ÄB}ÕÕ@àÇî-=‹h—ÝUÁþä~+÷ûÄÛ}™ PåUΓˆ±Ÿ¦7{ñú;ì8±¦ 0ØÑQRÕÏñêšÌÚ¿_†?‚ú¿¿Mâ, È‚N¾vÜJ3è¨ÍΞb{põ0L˜ÆŠ-ãÀ_†Þƒ„;ÜXÕ4NúµyfôM¾y…3'°Œã£‘Oa`Ô!9Lõ¼¥˜0,ç¥âÖ_ë¸õ×Ëáå05ì-áPíÀü¶")&(KÐæÚÙ4ñN‰@nhO%ªr¯5 |,„‰óïLG—‰õƒ°Rbdq4K+•ª™ÖÄÂWG·r Kˆ&,'DÓÀ, åð—mƒ”f!Ò7Sqƒ„'x+¢j¥ùLäšL$\e䑃ùGç£* +ðajÀ¸Gƒã·ŒÃèøýä¯ !×OÞ@@û‘Ây£05g¹¿Ì“¿Z,Cn¬LI{Ú _•ñ‰Ây¡-ó& “…ŸùˆËÌ¹È î¾1¬eÔ- ”0£jÂÛU¤@‡fØ\ý&d £è€ÖÃ]X C3\®¨™ tœ t\H¾©™à@:;Šÿ¯“I\?…Á×M ÇãCÚKº¼&ac¦Ë»ÌxÂÛF.ÖµmE5àùšŽÃÕHw-`ûq™kä®rÓثͳ÷f9 Ž‘¯úÏ÷›/ÊŠâ×Fzœ!³XÛ ýnëŠËE¦÷Jy±ÜÞ¡ŸJ~‚¹ˆ½(e¯²”÷~ª PU—³|Tw £EZ‰)Á{F]m]SøÛx0¯6N)ž¸.ÖžàžmͰ&ÐÄšãÄì«ÜÁ_PÕäc0T ãjù)Ü[:Œ  Î4Ø^ªYD!öSiŒt˜ùO!ͤgVñ~ˇò؇RÓ]õ’Jd&XþÌzåTlgí®47ƒl® WÛ¿Wq{4T‹¯bo×Y®·P"¥&9Kë‡hµØ2’PœÔç¹·£E ^zèK庼µ2—û Àìµ-"ËM¹‹}Y×zÜ,%—Ï·uh#ãù§>Ä“¯=BhQyÝàŒÊ;6ÈD]TÞ08û€l£òëÍ6*O$*O&<¸q .v“)!¬”ÐpxŸ±¤„LÏÚkA@ÃB­cËx%‹û…:,ª=­Þ†ŠÎCÇœ(<3Åָ̔Iço-ÎØuCþööÓë\ónaJX§» ¼Ü,.îr{Þ2Æ]nS±/)‹½ÜOüáŠñ,7NÈBär¿„¸ysÃqÎÀÅ„²/Åéš|âÜv¸* Nœ[Ü5&ÝçVfä¿Ín_—Ò(y'3æçåL$cn© g1ú[$k T`™M_}CèÕq€ñê=ns•;üérõ×TÍ…=R£G–5…l%²¬YšÈwÒÔ,ùNV¥Id™D–Q‰¦¡j\€`™9fÏ›¼AæØÐùÊõ'6Ì;™P•E쥿ʫºŠ´€´+ÞɤÀy9²´«Ë<Æî_X fü91¦`&c6c¤¶¯Ýà&ŒarAÎ €zºqäì4 ¿Æ³%ùšw§ÞœüÉ"JÈïõü÷¿¬ÃÕs¼ñ\šÌœ‘sXnŒ†°xˆªšüñ™-¸éȉr² î¾é#2Z²nWZlÍR¬7c²¨šêåÛ¥ÉÀáípØ1¥iDàš‚s{C q ¹4™Ÿ9#g*ùy6"kDš?5ÀIY˜r%ŒÁ°xZ£úõz¢‡h²—¹F)ù'mc¡)äy\çŒv*øÇæá!L~ ƒÙ-¥IPõmýjþÚ¥»?$Ÿ¼ù…ü¥›Õz“Ín+öˆþÙ³äV8&°TÉÒdŸšƒ°’¢ÏÏ-êRkÖPK=nj…ˆ*}iµ[á|X/”`!Š7™€õv-‡3¬Â¼Þ`¾×f1ÂHZ6+ôÕV‹×b^np.£YŒä9õ!€ÉS¶°uËõƒ¯Ù×MöZe¯aAOÎq-}šùÙ&å' ÅéÚì`MÛv½ âuH{=xÄhHÃV\ÏÛH¡²ýº bBknâSû:xÀ¶ùZÌ‚q„èP®,©ñ2˜KõCos1¢­EL?5›ëÞÝ–ÈÕáä[ä•ãbo*.¯‚ìÆ&¬ÝJÀ••BÆ‚t æa»Þê)»žÖô8ÆA¼üB®Ñ5° ² Üw‘W.6w'Úù¼|JÐ|KSqÞnÛ'^nÉJ™ºN¯âLÖ •¥É:¡3rdP—yŒßO”uB rdÐùOM¹Nˆ=¢q™‡ôHŽ@}pÑ4 ŒÂQ…Ҋ“U(@iŠwFÎD x9†çr‡ã†âItØ©³ÅRMð1•¹à–\ðp]G‘ &g©çÜ£ ׯœóáç‚AdÒ”ë,Pæ‚OI“¹àÓrd.¸Ó#g:û«ï2 ¿•&“ðhDV*0ü\O"ìŽæðºÄâJ# ›Œ‚åiŠÕJ,OIÚØsì“Q#ÓÇòXŽvSø²ãñåÝUï¶­RÏtXÙZöp)‰±'€±<†ãð/öd”zñm/ÃÑtt>¾)ã@n{Á@Ú¶Êg¡»@‰ 8%MâNË‘¸€Nó¸øÄœ–Wbnµ¹[LÆÀ¼`€cð¹– ‹þ¨[» tZ­ËÇpk]Fë’|ŠZ—5ónO÷MþOËŒîd÷\šH‹“ø2Q•V~&îÃG\›SÕíK*,Â^ïpµ¸ õo¾‹²ñÇoubÐ’VC›ê€ÇŒi‘3+_5të Ùù¹êä³ó‰¡7´o«|l!¦®ß *t.!{(ÙA)A¼\ÒÂÿûïôzݼÊ_[™ËðçËáB°L`n`vf/RÐËøUrí¤Ipù9’kìܧ†À:£påŠ`pí®™\)h$¬3G¨ÏàŒôu…;[ßRbí­f·¯’K<—6v´óˆt7¶Û‡»Ú–ªp3(d‡½Ø+\;‡¶¿•—’È_(Ýá_INFÎaQü"*‚šr_²"¨.MBùÇ¢HFSd›*—.™4¤_C+دAúoƒÛOÖŸK“°þ3r¦S°¯hüäl™#ì®ù†øoŠo{uäI}»½öN¾lü:Šïò~'ø–uGÒdÅi9cÕi²ŽþsɈ6\„•a¾!J¨ )¤°M«ŸÊ )˜­KÕ²¦PG!3²¹4YGqFެ£è6YGÁò3&£SÚø'æ1~«SÖQ4əޕ¯˜úÛ1ó/¤ŽhäWðà}c¯Ÿ¨Xø ÿ%úæ­â ^ÿÛÓz ˜ÀÍjoâ/åq!ßöÈ%PÕÏñêšÌÚ¿_†°2 æ#[?r¥t¼§çÏcsÕIÈ:œæ:œ{‡«DZ¹šˆ™º ¹·oã|²Îk+‘œ/‡«€ÖyÁ6h\ u`CÃñÒTÏËÑIžO¾šdy¼jØjÂÆ) ØÜ·[Th¡ñÚÖŠ eך½4YXxFÎt@p²kÍ‘4ÙµfT]kÆQÉéª\]kŒœ0nºö›¦¸œÅú¥Tåk[ª²©2tHën;áá_‡ë[&YÚœ4¶LڬȤˆ¾R…´±Oæ%SÓ†a˜kšd4‡×%£(¶%AFfOIHL.mìå–ìõá®¶®IÀuUšd$I!ñ8 M}»Át4V¶ @•Ĺ4YA|FŽl vîShvœÆ`£ˆåíÎËAA+»÷¤ª¼|5ø%­ °±|: ”%­§¤É’ÖÓr$ܽÓÍb:<;x—/8;iúÞÜn+ýÌmpûIfÞri’‚挜éðw+?¡4órŸj™¿ÛpMûíd;‹oË—í ç«qEì&Îù£Ãrµ=pþÀpMò%î*Prþœ’&9NË‘õÀæ!9à?cª¾VAIôqI ›3Þ4!#óRH\ƒ &=mÒNPJ?¤?ÿ’&ç;Á&§$ý9’&IÎÉ‘¤?Ýæ!I~ÆdvJÒŸSóxs¤?ŽªqŸîé˜ù—Aúãê*Wû,IÐB0h]˜ÈÈ ãJþ›¦Œö¿…HzŠDrÂt°)ÉG0šP…Ž@OÜN`’7*Jg™ìŸKh°-}8Ï?Р![ªÏ¨«­kŠvI ì0(/ß"¯â¨íÜn’ðð¬±:ªÅ×i0×Õ׹ˣÊ0™2MŠ„Æt¤I¹ýÌ5ïV¾¦¹4É–rFÎd0›Æ€°œñE°›.öøö âúãªÇRß@Öá iŽ‚ ÈÕ NÛE’±’ ËÇ2àŒ«»\d©Ãò±Ø B°² ‹»¾÷ƒ¯~´œIK.mìœ,#2ˆGMXP¼“›g¯F ¸¹Xˆ&ÁA¤ÕQ”DZei’g,8c ¿q-ómº³5BªÈK2OÈKNêš4YFÎd²ho) å€Z7eY\ຉiHU4xEÚ·Ÿ¤ÙšK“eÚgäÈ2í.óöí¢*8d™6üç’ëepë7,“[mOÆÄ¼"mײßn‘¶Ã}î¡H„\•gg²Hû”4Y¤}NŽ,Òî6ñc¾.ÊÄ¿Ñ)‹´›äLÅÈ7\Óâ.}™Ž™!EÚ.´½\ͨ‚Èh=5ž²lÍÝLCåC[›i˜ä@­¢Õ⮘е:»û<÷lò]³ð[6»ûD~§ÿšD³ÛÛ¼ÍÆ}_¶×è"¯¯v]ηöBÛkÅÁÄ\kU½œ¨k½IøK4*!yw¨u}w ÌuÖ-—ÓíﻵFíÂê¯a) _ÿYI±ÑB±!I\ ‰ä„AÓŠj¶@MÈÙjµ@õÃe˜…;ûS“ögwaÛ»Ù&'ÄVÚŸ§EJû³E˜´?[ÅHûóÔ‡ØíÏÊ„h}šo–~‹×îìB¿uûé•Ò†À¢2‘ÜUàå’pœ6„»\Pyä¼!ƒ®öø“È/!6é™ãpƒRFgÃa=Ë%_‚‘õŒÚ2\5À“f=Óù™=ë™K6få'Iü:{•¥x¹4IxvFfÿtü¦fXÙ‰ãÇ¿-üÍ—…ë-?ò6¨-´îð Ëæ{H¡\c*}TlX@ãdé#Œ€«¥ôñõ^>Âï‡\‡¿‚fDð¸ UǑლ´‹EE¿ÅÂGÖô¡Ð±×¹A-å^+f¡9ùŒÌák-EU¹j‘x69ÌD¤óÙ©6­o)Ù/Ê?ÿ #Ù“V`W—Kµ‰m—à®¶Ì!I+/6ˆ©E^é•ÔÔ·ôLæß–ã™,´îžI.JÂaYM…ÐQ7Õô—è¨AyWùFvˆÌl:¢7rÔtÔ9±ê[QÚ¼,²c!£¶Ýæê"ð&™d]N‡ª™IvÛ¶Kf±si’PöŒœÉàïdÛ®º4ٶ뤜)µíR4ûí¸ª—Ѷ‹Ø<f`Úlvü-G{`³û& w‚ Éfw$M²Ù“#ÙìºÍcü¦ÐEá6$›Ëd³;-¯jæ¿àæe°ÙYŠmqe¤&\/l(°Œ"¬^XUȧ¿¢UÃYQ6,íõw‚íõ +Ö>ˆÿ¼E^ ï¡)w\gDÖúÈCIJhøHÚÈK´GmÌŒ¦dxûH"Ö Û67Êdë†Mþ>oMuÃ…ÈÄk!M–Ÿ‘3™WÕ4þäÔ1ÈÏê°Ë=þÒ¥QÖk_pÈ=Ù­k—Í4S6þŠËÌgý¤BÞ¶9©f¯gÎvÏwäúxY•K“õñgäÈúø.ó¿‘yQyÖñ™²>¾IÎTò¬š¡½ óRÊãÆeÅÌ[ÐîÞ2~| Xç„÷?ù«ÇBÈ5äS‡) j…Û Ã1Â0‰ëJ—˜,¿÷ì§_¹E–ï1×5fT˜8¶¦²,­òsÊ'D„ù³®0нUúÿÎ÷¶²hûî_½¢®gáHQ—´\ǯÛAíª.WÄJÂZnmpòÖu¥$qâ—0yXƯ³I¿ûX¿ûÒIF]m­*¦Í½ØÓ±•óoËa+ïÔÀðÖ²ÆUnÄ’122©¦r¡™T C¦¹4I”qFÎTȤdAt]šä’’\R‰ä•äéCoÂÐïléÊã0–¿ÉžØ»r6ÿü´íþ©ÎÃ4âÕÍê!VõÇ0»#Óôï—áŸA-feƒÏNòzƶ±7é++ ÛÖ!ËYW•ƒ…×àÏåiþ«š.¤¦€£µôñÝß6ÿ]ÓK“²+Ê4Ë£v-€·ó;œþ¨Án~m«+²Ð¶ZU$íT§ÏU쟤*៮ ô¯º ¼\Æ)ì¬=zO¼W{ìT kŒÊ;Ù2éüGÇ U‡ïí2ýÈFŒþè»|‘ß ~‘%ýÑ‘4ItNޤ?ê6ñ—T_,wü0QIÔ$g*°\Sq nôdÌü ¡?R lÕ] ý‘ÆOÐ~‚þHÝ1;¬âLò•¥Iþ£3r$ÿQ—yŒ¤ ùŽåL†¨Aòµ~Rÿy%ñTƒ¢j ûz¢÷!Z†<Ù]Èr¶ewmòÏdªšÉK"‹üåìöÓç¹WKüÎn_ž—··ô?(ùGgI'3‰‡Q-MçD0ÎÉBµÐ2u©5k¨¥Æ1OD-õýæT–Ó,¯äü´Ê8f‰¨UâÍŠŸ]§bq[œ!æ•Æ ŠZéøá!…ESš%–:R¤Ø0K9µÔQÚò‘¶Ü)a"uˆ$øëænÉÃÉWª~ÚÜMüæÈÜM ‹Œòu(¹›NI“ÜM§åÈ$q§yHî&–ŸKNÊã&‰í·½ê&ÕTÆPŒ>&‘&äæC”†ö_g—[ˆ>jËvßNS³üËr¨ì±0ˆ¨&ô”—+Rù&Ý-²'´tƒ¯h¹HhiZÁ•ñ:ô¾=/½µŸ¤a«Z¤‚çk?ØJÏ%C>_ é*¤Ò®™î«þuðbB&4ˆXy³-KÂ*“õ6IÄQ"ªêo9mú¯It­Íî>ÍfKfB;É+Å~uw¨ÄѸ3¡ä `®³¦ð¾áÂcì5õH. ž.´ ·ªRȦ»ÃèÂp„OL¨2d«"/cPt †û.\/£À—Št'Lœ"5{¨då¸iœDü%jåø•£ðJzÖ¤Û[ˆ§Mmƒ«aò›$å7u'å¸ýȦ„i’›ãŒœÉ@Ý ×äÏ\pÎë>ìr=縥ZÄÉv„­Òd;B,ê™üóeGÂ>c›\¬GÀ>ÃNžm ‹¢Ÿ¥d¥ÑÙU ¤Ÿ9%MÒÏœ“#égºÍcü­…,¿í)égšäLYhª¦óvúB^ ýŒÕÂï?$Yô´€šá*×¼8½qY=P—󶤞C«Êi߀›ÏsOSv¿£§:âårg³"㢻‘¿NòJ°%hM£«¦¼3ÓÄツq÷Um·«ô?JØÕN˜H#Ì‘øÕƒ0‘°+“³àg(›ÿ šb¥ì`i±)³µ°ZJ [«²ˆ½,Þ¬×a2ƒe?eb««ÀË¥iuF}û¨ã¢8D–ù2ñT· ÇRSuNvî 3û¡,=0û@jåÃÐ] dö9%M2ûœ–#óïæ1v”­döi–3•ü»c_¶•yÔ>ļt¸ÌKËÒëŒekÚü’÷(Û×6”m«}Ùe{/mÎwbmNS1yI•/ÚæDGÙ*ê€fÐDÙºÞeËðsÉV§DÙ6əЕ¯:ÿc9;¿P“GÙjà¬a ‹jI4<£D>‡yUfÙúÚžÂ/ñ×p%ÑTïÄ¢*4•óí;Ù_=ˆé~›‹z×Th§)ˆòù1d½º"r@ªbókdïuˆ‹¾Þ¬â£Ï~„]\®g¤vBv³ü)Р'ªRV­èƒTM<‘ûÅMDª*D¤ªJ/û¶…y î>Ï=›|Ï,ü–QÀ]*{é H|¦¼Ýƒ.Gs­UUãe‘d]ëq7ÓÛ$üy« +ê`ë<îvzo¯óXƒ¹}zðŒLCá”N›jÅA‰¥Z„e¨³@IµrJš¤Z9'gBI Iµr$M&ÎÈ‘I nóxkI SÓÞ«â…P­h¶ÁYK0ÝÚ1‹³ \÷Ú±Û×ÛO²~,—&ëÇÎÈ™ ·¥*ÜÌZ#²ÕGNÆM$\ôãŠS¯—/ß«Œ_¯g›o·^ÏAb-Æ«×û.âw‚bY¯w$MÖë–#ƒ8æ!ëõX~.9h†Ä1L›“Ùpäfæ%ìÙ¦Ëe__°Çl_ª?Põz (mÎÎe½Þ)i²^ ¥je½Þ‘´‹µòÇouÊTm“œéXùŠÉÙ°xBfþ¥ÔëÙ®¬ûÁ¬ûQÞ|Ý®¨|]»§ŒòµU{ (ßPºŽï§+$Ê÷HšDùž“3!×Q¢|¤I×ñŒé:v›Ç[sMÍyK®ãe |uغ<®£«¹°<ËÈ\GSáÄúR³¼úÞ§—kXÞˆòL†?[:ؤªœ-rà Kt.!ûá²Á¥†³eñrIœ½OU1‰á”ÁçšrI‚ÍáêR’°Œ_e;›4YŽpFŽlgsæS“‚Ç£´³É<^×M.bðxö ´ªj£kh#y%ri FŽÈw™‡È3üŒ)Ü,ò§¦1þx32յ㼒ƒ ÈëºV ·aÿ@yØ‘6gW JšÈŸ“3!”ƒÈI»X+üV§D94əЕoX¦ÎMn33ÿBòºîrqÃò£1óUÛáLBª‚ãUj¼/ zö—Þ:ŽV4--MôŽK&ºC™§ßŠÖAÈEUèàêÇ7Ôº b ò\N ˜âV*±\š¬¦8#gBqYMq$MVSœ“#ã æ!ã ,?2ÎpZ^¹ßuÞßÖ¥TS8ÄÙæ‰3ÈjІjŠáªñGUMá¸\©jKQ4XYûÈΖár­@Vêä-ÝU¸x¨e¥NµRg@5’JWá++4t[¨íVMå@©œ¥Ó-ýš„¥_²Í^š,ÿ:#Gv£é2ñcüe7šÉv£Á.·sU>¶ði—ÛéüÖÈåv’à-—&ËíÎÈ‘åv]æ1þ§ø¢d²ÜŽågL Id¡´ˆXog\¸¥y‰õv®~ô.§Þn iþ%ÎwbNYow,MÖÛ“3!œ¬·;’v±f¾ÄÁ±üHÜiy•ÕÖ¸O÷dÌüK©·s->æ× ×Û9 _ó£z»ì)Þ¤þj‘zi¸–õv…4Yo7žz»ÊZý†Í…>’PÉ&¨¤„ágËáŠ`Á¡’xO7¨M3ø#X˜d= â絟„³ÛO¯sÍ+þ'Ÿ·wbŸ7¢à îV#Š@á#p9¨1@1# @áC.h¹ÇZÆ Šü‰#YîñÇŸž¢ñ-÷d\ Åqì˜l틘| D² ¢Rñæ+l êãñdÒ§[aªüÚ "¢4^£E¸šÁ ¤Òé*ðr+!ÆÝ粚£iƒ“+uQ€‰Ëgù¹ä.`ÇâWÜ£¶3/•o˜ mÕ¤QùÎ$ºà’ÂÑu•÷²;›Ã+ƒ“ZVu`k12,¾crÊŠgP*ÐÝ,†>R¦¢ƒíÛ‹àüÕee¾Fkw•>ÄÉó„/³wb3 ¿?–&T¢ï¤IPCÍRlX¡`CåäNûŽàYåk^†(èYŬl ê•m¬l«Hú´Ú•Å{e›á\R‡Á±¶ ¹ÚãÏà`×µ ¹ÚãOà`—µ!¬ödÌÆK©j3ƒÎsÂEHºÈ®,‡"¤Âz¼•]Yri²錜Ée¤áX—&0&#íÆº´òb/”Óh‰ÛqhÔ¶ V­oË_äR;S1¹KÓÆAÙᠿI;è`¤…ÄAI“8èsr$ºÛ<Æo Itƒ‰ƒî6·†ƒ6µGmê_ ÚTì·‹ƒÖøÃ–G8è,Ù„ôŽIt!Mâ Ç¯)Îæ”Ws]‰ƒ®á ‡c Ú„CUöuá¿Dß‚x•…ß²¿=­!¬ýå}åÁŽwÕü‘NÃ~ “4ŠW =}OÍ×ä\ÒrIÏWK.4H4²~&¶ó滋Ïï­¥¾]šy“¿V«„q·É+ðä§OÝ^’&ÑígäL&‘*ÑíGÒ$º ¦‚x5XßTïn&Y*Ÿ»?e\;f¹Xp\.Èu+MbÚÏș̃*‘IuiãF&Mç9Õ.Ù˜‹Å,•2pÂÈ_“³“ÅIä¯Kvyå'Iü:{• riô{FÎT IÃ;~ ËâÁß,q¨²åCË'+0TX7™ãG¹P׈0TK{»t¼.,ä0 õ»|™ß NtKê‘4 C='GÂP»ÍCÂP~$ õœD C=%M$ Õ5¸ËQ›ú—CµŒ· CÕa-éÎÂPibêÁ_¦‡Z’&q¨ãÁ¡îçÔ͈:µc;ü¡û2U¥1ƒEDÏþÒ[ÇÑ*“ª§&2®ÒÐoEõpG'+Çspåã@kYõ¨¶ Ñ<ÇhçoÄP’pÁw¶ ï@ÚY5~'¹& WYä/Usû‹Iüü1Z†·ª6»û4O)íÏíç¹§*ù‡fI'3ÈèÜÊI· ªlÍRÉp÷4aõX‘â¢úœÊµŸ=ykUóèýÁ\õx?̪ãDE­úšè½×8¹”ÅÆ 9ŠZlŒøWy-×à\g–O6‡°ncÔÞ.´K™jÔ†¤ '…­\îØÎ IÂMš„ÿ½ SžÚ*×Ùjm”ì‡k57-r«bžOò:^„ýÇ å•ÖE'y%·ÅR8½– µ.Ò ^ƒ¢"ÍGñÈ¡[ HK³°Ê#Go:æZ› g9ÌåÚ?§üzÜS-Ú¤¨‡gÏ&Ð8Ëb§\˃Y”ËbeÏNš¬â9#GVñt˜…¬âÿL' E±ä!åL¹~Çá‡wªß)ø&‚[YÆ“K“e¬¼õé2§Ô.nR9¥Ja­eCèžêfÄöÅBËE¹š µD5BÕAc«Õfåsòò†“Þs˜ù0³Šœ¯‰ó»EQaÏsQùµ/‚·é:¨Y6Dà6Ýõ6IÄ~ÄLŒF1GE‹]EöÒh} {é„üÒ3(ƒ\@D]èpèBrF‡Ñ…á: ? Pex³Ú«CÈàe#¸bß…ëeøR‘S¤†csÒq_¨"“µ{³í(¼~uÏšt{ ñ´©E¶½ÿdÑCDþ¬”ʘ8”)»ElüÈ=ìÐ8èÍê!¾ù<÷4e÷;šU‰ƒxù…œíÙ¬PÒ öÑRIw’WJ·¹g~ÿB•ôšçUQÑ:ï2÷¬¢wWrù¾<Ñp¸I#{ Ínš (ç#5{ƒfWµÝïèß$]“½&°PÊ1¤F?¥ÑÛ{ü¤ÝቃL½µ¬* £-AQQÅ2þ±&Ò´vd ù Ldüƒ›4d Uœÿ šbuy8ˆ½ ª¿ÅêâêÕúéSaàJ½*ÖÀ•!‹’0qzÕ±]kšz•^E,½j+@ðXz`?>† LÁ½ÿÉ_=B®!ŸÚ«70«‚Òz±<òfô;{Ëð%\v܈³û ;PVŸÒa¼­§ÑDyí},h•… -í!ï#%߯.òJÅíŽ>±TàÑ6î:†5yl^ãäR‡ÁBœüc!Ä<2ìjš;nºàü’¨) Öt¤ ebTn7P7QøTÍÛ$^?D«¥Ý@/°v²jÒ ’þwèÅõ,Å≺K¶Ý*Û®äá“l»íb$Ûn‡IŒÛ·_ÁÑezoÏÈ϶kC)¸*¥®ªÆa4dªVq¯¿C3U¥*-ÀÇŽ Uý¯®Éøþý2,Ré€L:÷#óÆcÞRä¾|Im>\FUˆóº Zb~€hi]‹üÅ¢»o ñ¡¢?ƒú†uÅYº®XY^Kåa³uÔ>Ž?¥|Á6J¹Ýd²y ƒ0qî”cªÒ:“îÔI1Ò:3 éN~úv§ïž7ÅÉi¬‚#·h«¦8$ŒÚºÝ;®*4¹òs¼Ø,È!ßn‘ö`znÜo7”s¸YjºÏä(ˆ€§!7Z\_4 i`tl9EaoC@\©Zó7Ù¹ŠÓ¤ÎÃ4â…"Jê;±ÞÅÛ€IøEg ÝóÒ¡B¼è< gI³ÞB³®\ͺm;`ÆŒÑЬeiÖŸeìX˜äYo#yÖÏOBò¬wÿ¹ÐðWýOè%äY@õ 5n“Q”[ÅM*Ø8^V{ÛvÁ>¸8V{P|¢Å”ÒŒ2°Â§æ>Oö“Ÿ^‡ °¼G^ú.òJºŠfòâƒEßú²y¡òlÏ–±îè*Wy˪ŠXݧ:(%îÞ ¶Y¯uV*bFV®œÜÖ½›T‡kˆ¦# w JÙ%éÜ;wIº^x]’¤D€¡·VrLe¨N_¶ñæÎ0¤[ø R­Ãe˜…8}¾*² rE•'™&Y髬ô²É@˜d¥o#Yé;LB²Òƒ~.”–ëíE g¥wL«Wm’¥Â± `M«UðŸ¡ìUÃ"LœUàŽä»?“VÁI1Ò*83 i€~ú¶ ïžU O½W uä¾W†Ù–Ÿ¢œ£Õãì^¾ß²_M»˜ÃB#T¬—Þïâô¡®5MŒ[ßaµ¬9ºÅxúˆ”’ë’UÙ)YvJn–";%7pWFÚ)Ù±Là£ìøUîø%QÎb3M²ãó,éâq9”ÀŽ_âÚv¡ dªmœTÚ¥óŸ®?OaðUz–"o±¦Ó ׳|â.;{Ã^åþö¢)L[áÉË ÛÏÄ`ø(·Àû¸Y.›[àÝÍ3ë%¤ÝM0÷o‚™Ì´5“-ñÚÅÈ–xç'1îDÛýæá!DÍ©š­ò’TÉd[«¸I%Ûp{µÑ— ÏFPGÔ« ãÍ×õrk³E”ä/ûwo¥Y´zôÒ,¹ˆ¦mß ïXh<Ôrºî‚¬a¬îÚv*20p`ö]¸^FÏY0°•2l©€ Ë"U­8Ždì?õ¹.ŒýÍ=³ræ~!Yër³E‹6fFI'ïØO»QÙ[ïÜa½õ$¯üV˜ì­×.f2Lª²·Þa(ÇÔWK=–*L‰ £dsa” Eéæÿ¤Ø‡zGcLZ‚˜„€˜\—/$w‰ ¦q}¹ 9X%º, %†ÆÇŒâ †Š5ѺP͇…ø²¡oP=>B|]@pJÁ0õ«mY9CTeQx¦‰ÎwË&‘£ 95‰”m·Âd“Èv1²Iä‰M?ª'µEÒè.,ƒ%5úINÛ^ɶ¿ai lk(ÔÉ[Òèªbë2QŸ mÝÇ“¨‘ý)Ï|®[JYç#Ö¬–ý)ó«®òTæÉþ”õþ”2«º&ûS¶‹™LVUö§|—+IMö§ìöÁNý)UÙŸ²A˜ìOÙ.Fö§<õ!>}‰Ì)æj|(?Ùò¦©å4+·ÂdË›v1²å͉±+Iü–7®aÕ.D¶¼9óÁÎ-o”·Ýò†œá¡Š‡dË›3ìØò†¯isË›±œ_hõÒ´ @"–ýVÎ}C#Pn¨t€ ¼JÇÇgž¹tt;5õC³q8/Ý>Òaçjömê0>¸KÐ\C³ªÒïƒÓª«$iÐê[×°ž,«lÉQiÉ!u„É–íbdKŽ“7SlÉQ#Y‚N}ˆÝ–ÀoÉAô' Ú’#· øçü<8 ‚OõNG<$šJ$? j¸cÇZ–IžrÞRö{tºÐ®¿|YÙ;Là·‰€ŽŸnáÏe›Ù&¢YŠlÑüÀ]akQÖŸ.¤¥®=ãu˜øYœüR±1Qš\6uÉfBãª=dm–ÓYýã–îú:'«—Æ“Pã‰à7e<íOžáÄE80,‘: òt†HÝ]o²IüüqÑL[=ˈè±0IÞ.FR§ŸŸz@ovXê‡jŸú£ ¦ñp”ï-<ëËç²ÅQÔ£àýœ2‘{ò|1œôÅWÁÛx—§á›fÙƒÐçë±I"öSfa2ŠOàD³ ˆ{ÉH‘ Î|ð\C>8&CC‘1mxôNv! PkÉ_!4¬ »0MR…¤nLS¦´ñ’ÔM•áT6;)„‰S3¶cH5Ÿ Q3ÐúI€ŒÊ¡• ó™Ôd&»í0™<žyx@Þêô“‹{–(Ù1™6…æ°34T’Ô«#4e¶Ô«’L{+LR¯¶‹‘Ô«§>4y³ÑjtÙº©ÞºI•­›ÎÈ’­›¥ÈÖM­S­› ?#oÝtâ¯Ufñ~þýù>^þ&´Ð¥8M!=w8Þ/£ûü™ø[ÿMù›þ7hd¤$ÊûÿT“ìxz´Ý[_àöSµë«íB`”ÆŽ¥¨("ÝBdšù«…Ÿ,Pæé>=û—>ù*qRÊÇ#m_Cÿ?‚Û, Cê”è¿?/Ïñ"̳8d˜Ì!/§¿ô²ø†ø&³¹îÝÌÓÙLÕ=J_týäG«»0˜}v=ïqµñ‚oßTÛóVqòL>eÒÿæöÓÜòæ™õR{ã†þƧÿœ‘ŸùÌ»›ÿû¹ÝþéGò§C~µFW™ü¿iÒ·/ÃOÐtÿw}BÆ»HÚð‹”LJ_Ãÿ€W•`úI¿½ESCåÒ0Û¬K#ÐC–CÖç9Dìš|sƒþc67ðGWÉèäWsŠ–¢G(EÁX'ñÚ$OBé;ÎUô¯¢iûn“ð!ú.ªŠøvFúê¯gwÎ…,ãUˆ¢ÝbÃN…l7_œÛYãÆoÏ+DnË=Ôð‡Ó} ­×¯‘ÓDbËD{VJ2<E7Ö2r=a­ 76ÞY*ÉD;K%™hgéŸqüõKâGYz6Ï’LóÄÛ£’Lßon7ÃÝËÒØ½ßËÃØx{^’‰¶ç%™h{NÖuK"€7Ï’L¬y–Y#{?œ•Áû>¾L¬ãYеïGÌž8B³l}óKRÕGú2åèø4ßÕØþ§ývât—¶…Ô3È0°‚QÕ)åe‚Û*íÆ)EÏø£w0|³à‰æ9›‡]>“?uüÅK”†^&à›‹-mto’ lž…€aŸý¯áu¼\’]ŽâUOÃêþb1C ‘”%ñ:lùþ` ¹¢ÍƒÝ¾àŸSs™†á×–ó‰ÿíÌõɯÆI0¿ü-~° v¦avóKO§Þ (±GºynS¶)Z˜¥2l¾¿…AÛÊæ8ò¹›_È_ºY­7Yчlÿg¿lèŸá¯¿C'öq³\¶.HÿCî¼€¼r€7.ŸÁ—¸Ç÷Í¡ÄíOýCg¾û+裣9¨¡" "D{°$TÄ×ǵ3ÿ—uÚ· ²¶_d;lßÊx7ì0wq;:î]Ü qqïâN¨ˆ¯{·Ÿª„ûHâ\áÒxê"J?Yü#^|ïg@ú ÎÃÇçpE¾aÐĽ…>¦v>RTF˪'›ÕmÞmV4Â(â èĂ͡˜Ds'i@9BuâºIÃC?á­ Ykù-`XƒøÆöc.y +7U(ü›}§^ΊñxH¦Ð¤›€Ãb¤û!Š‹þqyûB.ßì+Ë~z8T'®mÜw»m”h)à«Xä|X¥¯a’D3 8Öá›'ì)^Z1'ÇÈþ:”ÐþãÒÌ1êöéT~ƒ]í´Ó¸÷èçþ#-èéÕ<ø«Q¿£õñå\:Ü?–qðµ§Õ, xkècÍMæŒÒw^çÔàó´aµ^V¶ÿŒÙ©Á{YY\g?QWŠæ Rïr­¾ÒÉHu¥)õ‘ù( ×O*¢4àÈbæå™õ>.ØȪ4:^Ȫ,TÄ5ÅÓRe¡"¾>ž–*=uª£™…^þ·°·¨2^!²òx}E¬Êcö±ªŒø„ùæ# 8&Q'IÖçWÒƒxõ=n’âl øN}…‹*cŠ U†.:9Z¸èÔ(xÁS£ …‹Êƒ UIÂE”ÛÒ£ñœÕf-v¤Ç+dïÃ\/ª¥E|7{>ÆY´}ûûr«0^yOqüÕ[çš/˜ÝªÚj? /%wù“»Ê‹q³€; 0X¦úESb4|SúEï7!˜h©Ã ÖI„iz·=Ä4‹-,XVX³ò¯~OŒ L– ~‰a2Ë55ú½Dëã ŽV‡ûï; pPÝu|%Ç3Mû¸ÿýD6Kn£n•pH[¨ pmÀÁñ¿²P4ǯ,ÕñÛvzÕT“=}&šèz]‡Iö³¿^ (×Âiñ׈þtûI5蟤KoA‰J¼ ¶Z™Î"Ji¯ÔýÀI¸IQíãÝHúVÙz˘xiÞÚOÓ×…÷°¢_ýSÝXeØåQÛC빑77£ÖôP3½‘;¡¨7r'íFnÒ(^̬,m¦EÝ÷>¤Ø”Ëh:8""Ôö ½¹Ùœÿ»Á)²B^‰v«R±ö·*kƒµ©úÜÚVÕ ~~޲ŸâÀo] t ŠžÚ$¨ vCFKVm_+YRXx Lu4ñ© Êx=TÁTÇë£*¥2be)•ñО‹ªT!êO¡V¤ Yl…J³ŠëTSs µŸ7Ë,Z—"éÇþO÷,¥ “¬:o#ž7KòÜæS¿ÒÔmªãèŒ#Yì-ùS™ý¸rÙ•©aßæ­TäÛ¼•Šv›ÿù§ù‡ßoé-NT%¿Í×O›ÕW²H»êjžq›-Ãçë{šîÈŒµ%7ç˜ Ê”67½Y €™êùb$× ?óÉ\#A Re&³Õb»(t ,yu¨‚B3™—v`;Ø­í`»v ûŒ?—Úþá*Í|Âý–b>x–WEªM…§«+R…¬š®ÖÜ–Dƒj­ ß7ô³:<Ú¨‰Å:5±hG „ÊY0w s쿹ûïÛ?töÿUÄðþS®?,£—©º aˆ_É%úðH¶hðˆÚ(´nm>ÿéúC^‡+æ›Å^}û>“òÞ#ç€j£™d´ÈîgŠÈ¡§C+ÿIõwB&AËR®—}sÃ$ûÝTÜmÞ ¿¾NÂùOÄ‹28eôüeMßÍ(^}‰žÃ˜ºNF~•®C>’ïæ!5J‰KôáªÈº÷3¦¶_ãŸhÞç–¦}â·±6$½-^Ó›ì)N¢ÿÉøSø=9¦Y9J×þryï_ó#uû1º})ÎU9EP¸õ“vü8Ͱàc'güq³ÊÅöÌ3çaû'7£†Éß5MÉÍ©MÔö :EÚqÌÏÂí¶fßoýìI”ÆÕ•æc»ÛØÖM½#'Ìôð,‚¶Q§÷ëKâ¯Râ;‘Ù–P5óÍzGJÄkÌÏ\îî —ÞXZÚ…F+{$±öH´CVc‰š1&ó‘h‹gºWÅŠÙ:A¦;*ë²^;üg-f«¬ù.迼MyÁózk¸•ø?Ñx¸õEøào–™çç6~‘øvx…’y_çÆ|þ:÷NBà· \Ó·AÕ²¸4D?ƒR•Û×@x‡·Q¶Xæ÷úZ_놩«e÷ºnhм.K“×åb©ò· îu8’-fΨGñH¶9ã·š\Ak,꼡ÚÆ. $:ëUHhÞ«>X™¯ÚšRý}½²·9<¿º6ìQV ‡Züúê™þ§€§)jrÑ4EM.š¦¨FŒTsû‹œÁœ,ù­ªí~QöÎÉág?ï†ïm¸Oó‘l!›†û4É2g¼‹Q“+h¾¸O(mrJ|Ëÿ ³[DÎìÏ[]áÙ)œ1wêùÛz'ä½2·aÖ>UÕßé­-³jبÏÝè;@2šÂ>Œu0cL3ÇuÅ¿…—æÝ ‘ÄÞ&ñš6 .p4¾õ ౺`´3VŒvÆü×0ŸóaÎýz×RÑr\³˜ïP%]õ2W½¹îQÍ*Û»°#ÎLs'>tf¢›¹k[&wõ'ÎPôyâEx“þFôø©îÁŒVQ潆´i÷—$DÓÔd£[JÎâµÓñ•¿EþEOúï?ÿ´s:slÄšf!C,Þƒ†aDù¶ÇC õn‡ëÁ¿=Íþ=–Œ¥÷Ž$£½Ç’…­Ú+`F SoV«‰>W+KsòÛZâx³¹ãÝ’ÇÀ¡=Š«©éßÀ™øb‹ý¿ÝóI4Õ Ü-—ô]Òñ%/Dn“yÔÇÚ…9?ËišhTļã´üÄV‹K+%ÈO>ù¢x‡‡{ûwfsËû‚´ f»l›à²mzÖôì]Íhn–?ø^‘kƒh¬+Þ ëŽÛ»z¯¼Ä•Žƒ· Ç¢ÑäX4Þ‚ì6¢V‹ÇÒ"zêÛóÒ W‹pùì÷³Û—üµDÒÇCj4™ž¹:/Œ8ŒŒc…«ïÇ-ìƒÝðy Ný»ß¢}ÿùü'Æ[¼ÛðÙ»Ë+riÜOÍ_ 1ö¼]@ òóS%¬óS<k?{òÂ4ð×!^ìÞŽ¶æUúÿt¦ @l ä”h ¶ ¼ÁE™E*w‘öSÚ¾ª’>ùI¸ðÖYrCNR@¿q>[NÏ­½Òl¤ä'Íôþ%l{v8št§$tµu7pJþRj›óMÐÕjšËöº•'Ó²‡ Ïp“¥èþ-;Œ ‰¾H—àÉ_-ÈrÔn†¨‰ ùëM²±ÌµÙhl“lk‚fÂ:… ’„ÏñKè­ã”hÌÜC¤v^þ»Û²ÕÐl+³~/Jç–=åä™X—XÆ—CƒáÞSŽU÷¶¤¨”@ðù‡e¿`ëÌb¯ø4H;‹Ž‚"ÂÚJ8”'M—¹È-QÀáÜÒ}˨û³@»\±nW£p¬ëåÖªl¾e‰ŸG¤½oÔ‡‰òLcÙÚ-yA ‹W¯išÒ™·­Ë(w9f1utnÉãÙ¬°}·¬,¢8§ÁÅÚHºgϔυꊬ¼sÕ´–¸¶‹–}I¾ïz¤Œ:¼×qÂFøÜ$üïm–‹Ò çéÑmk£ ˘ Ýf5ÿ]ã$âÓ”]ÈoWýåû-4×"Iû¶HGR¿šBw–2zÏù èÑti5ÒbÑì“èTŒù¤öZ*ŸšQS•MŸâ¶-Ðd‡kâñ/páù÷‘øË%R>USÃ-§ïüÕcX¦³ç»cuÝ-皇T®JÇÍ()f´ _'x ½<-}{ëx7¿xo~t÷5e—·ÿR.剶¡ÌA½k,ï¸Ãyš5…RsÃ7o*shp¬k_ž—¢¾~f›µ?<_œšÂ§åí§g”°¹¦VôÊ.†Ž‰mèÙ2Ú Ó"ë‰iõƨþ*ݹ‘÷ßiˆŒª0œRCM­$Š¿.¢ñ±P©ù#jæZµ®ýдÉÇ:5mò±ŽV7M ;thãD+\îíì Á›d â=¿C‚í&Sœ~òë_Ö)âñ¯H߃õ„H?dI‘¤ë%¥³kˆ’ËéòÒÔn‘åýg7ÏëeHŸm4KRßG­[&«4Þ$A:e‚¬„ÃÜžý¯áu¼\î2”#˜[~†Êaˆ§-ÕÆqb 9usÂÍ" ¨S¶ËEæ} ¿§ÞC?{¿Þý´KÍ£ä4#¿QÛ/ø%¦Žca­6Øpâ"Ûil/6µ¨q{j´Ý]éc.Ë@œêîÀ®–yïà ¥ž_ B¼ûx³ZøÉ÷üðÒh»À}2ËvÙn܇|!q”¤Ù ƒ—áê1{ ÒÎÑ{ˆo¥1N<Κå9‹Ü/¤›±5OÈ™ên‘dÈU|Hš„}¸ÅviKªµÜ*ƒw'ý÷*ïDóªÙsõ§å+:û: 9õ‹œÐŽœ\ÔkµMÝíÍÈCª-ݱC©^éË#YzA4íåͲå6FÑ)%ßy•ï<Ë‚3láȒͪ‘ ëеSN{ 4lúò§u§¾5}i(­êH{ýr\÷qÖ›h-ñv‘aº^q4r\GL^ ªm£Õ#žÏ¡Íw¢bÂ#>¾º‘+ô4¢&|þˆÐ÷~°¤´nž:–_âø§xõ(HéÖ©±ÿ±5ŽºU»þ’¢vмØþDŒîjXÑŠhRªÉˆK´K’íì\™SÌ[ƒr£rTo2{¾ýZ_77Æw9íƒÉG‘£ &,OKwKÕŠÌö´ùíäaÍok¡íÇNÖ÷ÝÉÃú¾/a’—/¢HÛ—þª q¦SZç¾^ÏnódNô¦G·ÅåbØaxgÅ£µ¬Ûi4xAž4µADöS2èDÚ‹ Y-‡áóèí­SlÄÂ8Z¢Gl7YsE ÙºŸƒ™ŸÂò×<Þ2 ï¥ñ–¢÷ÕÌ‘ýíËü/Ñ㯖 þ0fò|ò;‹>O¼”¿ò'á—ÉZ7 *z¡-zE-ãÄJWl`ѳ٬r˜ÃPûn?a¢òõƆËu ]ýþ´‰½}-‡[ã\T¾t Ŧƒæ_»wKÅÙÙICŒ/vû*©•a^¥Éå¯zzÐy‡Kànc‹é܇áD{ö}F&Ø>× ÇrÜ‘<·ƒ@$×ÍÙÓµÒ£ í~—Ctgy˜ò;VÛ†“C9´g2ZêôäXh»{r¬?9ˆˆSÐ̉!ô4´ )òT´)ät´&â”´†uZv(,ÁA Ö )wÔ~æ«Jó„ä}×»¶¢ÇŸ,†™„ÄëïyfC…fg# ÝJØrë.ãàkQa…påŽeòŸÍc™üdz,óqã' zaÍç ±aP´ÁiùhóÏ+U¶¼ÈéÌLÂ4Ì(eŠtu³ŠÈõè—È_="?Ø$iôBkqWªËXX«fäyW²lEÕùM]UÌf³—[nj±b,3{JâW/ÜÕÔæß;÷ÞŽÊ(WItÈ»OHcZûÑÈ7Ìüh™ðW¡wï§¹©.£`‹Ó£`ˆÖQhÁÙ2ÅSÝ¢ –òý‘ük_mÓ¼™Ö‹°© ßö©‰ÛPÐLîlâ¶ 6´}!ê–džˆýÝÛ$£­Ý‘d¬Õ8^jK¾U´¸Y£mbƒhq ‚µšº= É–¾טn´0mâ‘G÷î#‡6•ðC-ÌœPáævkuU9]ónºŸ<Þü©ôEÐ}Íëi&eû¯—Yè°Y|žÛù¥VLH0!£2¡O»ªù¦t&šwCž…¹ã-”!`^&ï¼>ÏÝÒÒ™HS4¼ç‡H~Ðo–‡ùŽÎ§©¾nFÔüÏsÝû¸œ›ÞÜòžQµycÕ¦UÌäÛTu2y͈V~.^9¢ì-:¾—Ý|¡ï°:óÞÅû¢z_4ï‹î}1òŽÐ?z.¥žðüϼùbz_,ï‹í}q¼/®73rv‡Y¤ï#ùüüÿõ柼ùOÞügo6¿õæÿË›ßyó¹7Ç ¸0¬ÜKÓ‚˜çVC¿™ÿ£²Å˶_ ã†,Ï~5Jë0#ëð.Åzó’EØ-Çüóp+°l^‚åÙñ¦áv;µ• 'd¶_‰ù/9ìGÔp ¢óÇáÃÑqp:‡É"|ðÈZë0+_Œ¯_ű<”­4$‡ÄÚÆ?´mKÁ Þ¬0*HOGž¹™® Ádµaš%ñw±£`¹³­ò‘·àH>ò.Ø%ù4Þé­wy„¼œd–èn3 9Ë]æÒû—Üúœ‡½ˆÒ5ÅM÷úí±OËÙñOÏÙñz;M¥xÀðGª4™¾ÏUièþWyÐÞNXyPÜc¦YdÐpåß/CoûBå¬hÙS”Îþq }ŸÕÌ•ÓÇ®üÇ0O1” š»Ý—ÞÏKŽvCœ„ÏÄ(<² Ìc ŠüUjÿèžIí[Ó÷!#bíGÓ<Õ¦äI¸ Bï5Éémoˆ?5+~¬bÆ9P„læ>v|_´~¾#¶"ý/ºRûŠ´J))(GTì}¯ktû1j”Ý-—Ä^¦Ü€ûõ2ËëEŒÈÂÉʃi‚iÿ¹¦u[¨ŸG¼PËŠAÝj²ÛÍ‘³ÃÕç4¸™G}—í¯ž;¯Þ/¹zpñÈaŒ¶ÿî¾tŸ'²t'‚@MïSþÇÇq»! ÖrÅ›ù†œÐ½Ý¯>î~Õ}Á¿\æ‚¿Q‰î Y¿êù¿—“xY¬'?õÂçuöÝËÈW 31–¦î¿v|ÿ/bþÄ_ÃDŒ}@××ÞÌ*&¾êm%ù+.ÞÀoÛ’.ë¹ú0Í⾦µ:Óx¡.zMQ¡Ñ­”6œmE[Žüoa¬ˆ½.07š¹ýEqö¶hnŠÆ 7t )ȰÊnj³ò½N†ôÍ*mµëöHs>/`Ä68þ7_îFï绞éÛ¹èÅľ»¹ýøò’ƒð‰¦péŸxKÿqÆ› ¶>,—õÚÌHÞÌÓryžË0MiáÂv‰{í¬øihª~ŸÿÛ[„yû~žåº`bxSÁ·Ÿž8ÇÙó,ù5£øôŒö𜯗Q†Ó^e/Yâ絟„Þ* “/|Ihàˆ·£t¾öƒp¡ÉK—~úÄ+oÏÀï?ˆâ¾gQÜéÓVÁ•JúòùÕœ>cä»…øŸÓGA·‘„— %U2ð®Ò×0É‹®E aî‡øç¶¡fÑ"FÀPVm¨ ó*QØk?¢5}DeSú`»Oã$ìm—œCc´eý<ûå³à+!xçÊC ¶s¥IÝA÷KJ Fw“ÁZÝRet¾wD>Íþøkˆ*‹ªÐ¾ ¸_¢6U®»R|AChdˆOa¸þ°Œ^ÐNzÃä—ÏT׊ã×4L><†+î.-cÐS5ŸÿtýášÖã Ä(öüÛ÷y˜¼ð÷Ýn…ªŸŸ·­Û~¦F«˜a윇#"[r&Å ˆ>å¿ì’ _¢ç0Þ:½öĵ[òbÇÒö=•÷-•?…ß©›|´b·~Š£Õ­Ÿ¦¯qÂÝ<½e4³r6®·<âÎHmÀ[Ï]à€ óѱ¢‡ˆöVݶÆÎ¾çꄌ©+Í{¸[^A£Ò“ó%ñW)õúVäé-z‘’åoÖë8A»Fa½ï*[QwÕe¿>ù¢æm¦˜þ’AMäƒIœ¿SÛî½4š"f”BÒß.JÛ6Øîq*ÚoÒwÓ¯‘æØO~Jï)’ø¼%¥Ûm/—:y8Q®™iÙÓ‡Õâm„]’m’³è/1ÈñKBí¼«G³šHDÕ¼‰§ÿ¨HÊm†½C葃мÙ+žÐð¿ÏÑ¡»ÛãQw7œ)ï:PEqK!=SÇüLûT/uã·‹3›­ÑÆÂgcÁé¡'n~væìJH3laBÀ9‡Æ`»'“cÚ›Ú³a+R½ÙÌHÞå9qà½9ívfÉ&Èn>»ž÷¸ÚxÁ·oªíy«8yö—^”Q¬ñí§€æ†f³Ûà -)%*¶~šgšò'¯~²Øÿ]/ó{žÜvnsÍ#“3zžÜm@FVèȪð‘]ïç¼¼OÎ-¯ðic»ó«SoØEîæ)M ßE£«7wè7p½yF¾ž÷à/)Åù÷uÈ9åLU½é±ÎK¬Îžm2ÿŸÉÅŽ¨HN¹÷ì¯gœ=x¡SàOGäεŒXé/Øïò -lYGÂXNÃû¸÷ÁTÝ£©çpø@A²G#ÑÛtÀFGµ:ÌkŠZÇŒ¢OÉ…ª@\BU=B¼•Š-T…ìñvž4ïàzVß½™QN¿Ðûíx?×Ñ¢׋Fw{c]1( Š¡YïØ½C>xP:sÝË;ËÒ²ÿ½Bq åÚ+h£N(73 Üã§ò)d Y–S:B9ÖJ¡#f5C ›BM”TÕ ôïŸÕ³Æ˜í4Æ/ÇÊžXÝ€üK"€@¯Y,Æ5AœWÉ’c̲,av}5Õ"‡e½IŸ<š ðüÍ·›rhèš½ü¸þ…=Ø}"vî9½‰ib¤°üî{Ü]ÇkZGÌŸ'î<$Æ‘é:úq:¶Ûõ\ç¤ddz†¨Î2·¦ðÞÍ£Þ'ùÿ-ýÀs~ÆDOÊ “zˆ–ËíÌF2«úÑ ÝŸUøê…Ëð™¼Õ©çgùç÷®Îl4Œ\\5î¡wAƒÝPþAÍ¥Û, Ã<§ÿþ¼t>Ç‹0oZATkæäy/‹sTy s@q>YûøçªÐÎUá¹FAFî†ÊDÿ^6eÕO^Â.9†ÄŸ‚ÆDŸ”?§æoùÎñÄÔ]bõ‹ÿ¨ÚÕ,+ù£||­århÝ.Gnw º]§/ìì:máÍÍÖœ:»Lª—c-E,ÓÑ$Ü»ã1¯Ñ-Ê=rZαÓmƒr6Oä Âûbø'|?7{ߊö±~ ¥­jaH¥ÐeÂÃ,S¡½ ´oJ΃ŸoÓqN;m@Z\RÌõoŸÕæ„©òBuÜò~t¯Iã Q×µqkü<Ö%Þf@®uÐeNþj›ÑÐó©»÷ݦBœ|Ϊã™à½(Žwwïå}ï‹“ú‰VÂîÀ8å] ŒSÄ•ó(±â͉“djšåC©fvïà*‡=œÝ~Ê“GÛÉz-ŠÄåü?½Üïû—1ÉÆÒZR„˜è©:dÙ‹ÙÞ’è•5Ïÿ† /p«j«ÐK‹¼—ÍÖ8š­Ñù”üè¡4¨3?½Îæ:/÷“ÝQ ¸³eø\ôÈ<5Ýe³=d¤y<”Ggx„'¿œgK×ÑÆ ¹w8†©h£™ òÙ`žï™gšæy›ÕpDùÎ×ß=ÿ<Ú°Ùk×N{í&ÑÖÎk?˜¤®G5‚›Ó²Ýn™|¾ä€½ÊðGþë•Sœø®T÷<Ç/¥¤HKLB=ýí¨Ž3·ß.§rv_ãšf¦…}|î>1Ç+¾ƒæíÌûbf¼üÂi+œ¿)»TÏŠÜ‘iÑÈ]¨]d ˜žã3azµˆÆ¥­Y›æ÷…ìŠNfDÃI}ÏuÞñ-Øä«¹!ù6o¦ÑÿÝ}"_“,ž•ø«EüìùA@^<ì)}™,šÀ6böò…A1ù·ö¢‡nP`Šéجüä»· ýŒ¼ö™f®ãˆ†È]òŠÿ¶W‘Ñ=¹QÅ!q<Ñ Yú.dšV¾„IZ^ÊNXgÆoøÁ+‚ý†ëe;j~O.EÑ‘„š¾:½œÇã˪~ŽW×DÛRö\Ö¿«³´= ·¤½š?0 Ìð„þ'e\(žíB¨fð ýgý’oâLo7ø3U)„©%–ÅBª¡àH¥©³_Ö)ò\«+€1×]Šw®%fĹ– ¥ÐŽ«¶Ë2äõ¯hK GëU$¶XÊ–Š¹aÚï?ÿ4ÿð{‘çÅÛ1ýǼ7 ú½­y6hg¡VEŽ7áZm7⌫)z¼›ÛÒÍ<÷¶ò—xS6)¨ŽÚDèÇÂ"ÿ¢ÂÉaÆ^ކ\$Ú‚Ø;5ñSøË<ç&Û)éÌ>u¿ã wË ù[®ámÉ5e·ä»*ÿ/{Š{ ñjE‡ sM«^yôò° –0«xVÐVwWø6Á=MàÎwÅHýˆÛ8%ÏÖóéìu-y®Ú)3´­ªŒÒréPF;ª¬ÇÚZJNS+;,ªb};7SÄÜ`SÁ›È¶h>Ä´¢ Ñ Ç’ÝRë&ÒÂÄð•‘§»?Ï‹V·Ê¡ÖK©via¢o[˜`]”Z½ÚÙ2Yã¸LÖh.“mþ¦fÃ7­ú ùbçÚX4z˜³YžóvÊŠv×Gí~=ûŽNŒÖN0Ê¡ÓÉ™ø‡·ë¾ð}_Žq}¥ø>l{·|èíûœè Ò´EÅ:î¶b4w[i:¡Íßü£w³mDu½ûÕ8WaÛ¥û·«ŸÔüßKÜïÖÖŽ}€skÑž6PS´Qݺ}Á±ryUòÿý¯ôõß,³œ åæ4uA{*½F]°«žÕ ‘ùW¢±Aª¦-Faáö³"\Ùw‚{ª-Uä»g»ø…^äí?xü{=oÊy±K«ç¼˜]Õy{ÎKcNð„缄å¼0„ç¼ø…6å¼4©G9/,©µœ’TühÈy!H=ÎyaI­æ¼¤6æ¼t~±M9/4±Õœ‚؆œ‚Xäœ×¼åC“Û’ó2ù7æ¼07ç¼ø·ä¼4fƒä ¹%çÅ/¹5çes‹nÍyi¿ì¶œ‚ìöœ—ær ?‘óҹͨ“9/Û¢8óҹߕ39/[¹–s^ܪ9/v¯c'¯žóâ¾€õœ¿ÀZ΋[`=ç¥r_Þ.9/w”39/ƒç`´æ¼xîr÷œ—Σïç¼\uƒ™ó²y4É™œÏ ;—óâ¹r^\ÏÁär^ü‡`¬I/÷›õõâ2‘Gšö2¸ÕÂÈò^z9‰/—[%8óÅ ™wK}q¹,©/ƒÛ:bI}™Üwå8õÅþE†L}©œónË}±.Ãç¾8z#O~©ìÿ·Z¾ŠÝ4ý­=_…!ô(_…!ô(_ÅŽ,==ÊW!Ì´!_…"õ(_¥ZÌmUl5a…& Ž3V(“=NYaLö8e… µ)eeð/ASÊ ci›rV(r’V¿ØÆ¤®5&­ä6'­ØMÔƒàÆ¤ÆŒ“V[×’´B˜rKÒ Ar[Ò a9Z“VÊ¢5i…°$íI+á§’VÜÒO&­øW]TÒj/ÿLÒŠ{€RÒŠ_X=i޼µ¬ÿ kY+Õ¬¿ÀzÖ Ab‡¬ÿMe­xFkËZq9ݳVs–µRu5mÅsjO§­ö¹5mÅ/ûtÚŠ_þ™0%—‘ɦìcÀ†0%÷¨GaJ={"ÜǾáO+ÕòÄi î^Â'ÈKà1̼eüè-×pÉ-Hz n1«lÞ×ðû6¢Á!)Ý~½m›LH˵N‡èÛöûüß¶OüßòdÞñ²½ù ï—Ñjóí}æ ‡0Ió¿õÿ;7º ÄgúÛÓzÝñÛ þíÿ=Â?G§—+ÆÒte ÿìSeý˜÷ðº`ý(Õ‰ðÏ÷þ¹ULzáŸc\ÔM?äo²'ð‡‚"€Ãð9†ÕHŠXÜ:Å?f~¶I·2ÀŸþF|” ¡ÇmMC= Ï„DÃÑn’ ‘ž²l}ôÍNª¦ñ(ò‚Üý³Úìý¿«Ý4^ñ·?ûÏEÅèû¿ýíoï»iü|2ŇnV´_vï;|òÿžÿ^U0sò‰ËÇ¢ûzçwô=mD˜½fh¿2ùhñœÌ¢gòRtÿìOÑj;¤muÿÔaoèx^Öý“4¶X|Òéþ¡ÃºÐ_-‡.{z~WUÈy,ïê{•ms*·ša‹ —e‹Ò,Ùٻ܀¾ºÚ‘wù˜ÄùÚ¶bsy,{8Ï烳…š©öåjÖ寧jV÷ptjBw9‡ÝnesýŽ<¨iö—üŸ©,²¼›×ùxÝ>x~7mÖÝ;¶Ÿd\ȧö³dj±ìfù~1á¿ô¸·;Ú:Ì;Èu§˜öà YÉÁÃÙ:¦=€hÄó[`ÁŒ¤KD”¢1à’/Ͳ»CšŒþK2cÎï¸ 3dA€ÁذßÇ>ÇKx@Å¯àŸ˜öR…|¡ÃRÜ¡m¤î2[3ÌÚs¸X‚å{§Ò9s¨Î4[\]e‰zuåýº"W‚^xÁÒOS Ô’eº“9¼.64³7] ¨:QÕÐmF<œâ (±õ§5äzâ#Ý×ì:^GáOƽ:6Û£u¸3ǹå>/ ·ë¼æ¿}Ù³ˆ1žÓ÷…iôþ߈ÍûîßþòçûÛßþöç?v¡&޼çväêêŽ]ª§ýާk¥ñö)««×'`.Õ„:M{ðoz—³$Î3|¯¦œâŸ™ÔIGrV‘Ûì/3»QmÙ QÖMõ°.‡qu¨š®_jêìN«euO»&z) C?B²•'B˜¤‡ó>,—qpu•„´(—ýQ(ä0»8ù„6Ðf u¯ß«áMÖ­/õ”cÜy]…Œ]³ JÃÿðZüæïWWä>åN6§Ð$œI/@¢\g fö2iõÚ©² “1µCDÐ$;[€ yU0‘Ð]óæk@ZüìfYÌ:€9ΡsÆú9cÃD†—’-ð²wSìÛÀTŽùdè:«ùTË¥sXOMå{É£BÝLÍÂÖæø2úfþPûý?ýôé º>Äžº.sâMøžÒíùût=[wH ØÚÈ7”#=À¶«xÙÛdÞQ¾G”9σ¶¥ÕR×i?ŸN¨£š#«±–ªT×£Ô¸qå}cq>»vnÓ€‰9~¨ÜÙ+ÁÄØÁ£„œçß¾ù÷Ñ MÉ™8oï82ƒÅRFŒ©ŠÑ?B%Í–^Džv?‹“¼&sç2…†ìî(À¶„kD SÊüG® ›*<=«-¡åY®¶Ž‚¾Q•|PU…y.!<ËîîŠï?ÏcZßÂiFòˆŸÀ®„Y£y¬šQå:xàÏáó=˜¨jâ³,W³¨Õ!«ä‘5ä—UÒ+²ºC=*ã‘ÍB|“ YTmyïñÖ×Tu“káŸÀoJÉJïùž¢‰Utuå¯âÕ¿oVùçöÂþ;èòÙ{Ù=æ¨~¥óG²Q´¾K@Õ M¯Û¡¬ýÛ²;uÔ°ùø,q𳦀ÆÕ4€I‚P”Ôl“ä…ES®@ÉÏþ16Ë„€hû-(šj¨,…„bMŠ–EÄJnÃä!NžýUR¦8 yÂ6ÁËA¨: ý„èR5§;‚¦¾{{Ò†8'èÔ4f€û jòú˜Œð2FMÍ_;³/&`z^AÕžãŠÇ–¹YT)`ô²ÎÇÍâñ"‡(˜ „‹ªµ(ýç­d­Sµè†½¨‰®”5áŠî½‚i^"²dI5Ü`šipí,ÑÃöðáô)QTSé˜yì׸îXžirìrŸéuzÉfå_ïµÖmÕ~ú {™Ópµ@^gÍå*dg\g`¹i³Ç9 BÜuÖ\•/Ü“ù¹C¤íøSzV¸üÌò«ä2Æ‘réYrú7. œˆøå˜¬,'­å˜ñÃèÊ1GÀd¤ZÀø$ŽÍjuÕ5JÇÔ²j¥Ò3êÌWZÒê`üuESÞS–VEÈ!¨P xíg6Ü´´ÈžŽ céô‘.àY쪰½\n"†—ˆgU—Œê4óá §¸ôÏt8li&—Ã3µ´Ñª{åJ³¸’Ÿbñ¸)ŒK;ÞàYÝ{ÚpÛnYÊC(Zï÷{(AA³QKìgÑ3Þ«ŽÛèˆØÙc^áçKXa`¨¸YЍ.a…ˆÂf)bÂrÞfµIC@N³YbÙˆ ŽqïKŒ %D™+ÚÍ0ž¸2Ûâ"(¼Ò¢šŽ€PX£¼ÒÚÚý¯-‚jµ¶›ˆS-”—–¸ÿ}/-7±¨¥}Ä\Z® ÛÒ‘½2D,­ç­ý3Xe+®äµõh\u2=dÉÔc À r£ AkKÙúÐÖVWú_[`¦Q† µ½_~E]^W±x–üÑÎÒˆf%ª! š:©\ñ:NyÈY@‰§Zž˜luè?ÃNø°¨VÔìo^ÃÚ÷Aq4fŠuôÂÙ©Véiš3D> àØ bãd„ó  j@n|¶L!KÉHÄ“ˆýûCœ49Ï”g£]fž¡d­b¤û©ÊgWœo³z…ôEÀ`³ã­#Õð—àVì‹GNìÆÕÕ¬ûSlWNÒË`»:˜ï­7Iè½DI¶4…ªJ<ÙGUßJ5kß­GN·{xöæFl€‘–ˆO³û f0é\̺›Æ5ò³ø9 ¼×8a´t&ŠTïÃa\ÍÏäŠck&ë3c÷ …»ÇXÿÏÄ“z‚a±B pí/—÷~Ð= Øú/IïÍ~À=EÆ,IºæB˜àú©-œ¬Ï$ºâ‡‡²³Ã1ÑêH®Uš7N4ÂtÛfvD/~Æ›²Wù}e®]ßÊ+ažl¾Ü{/þvUKò=”L &– q¯«‹Oœ\è6Ôäî×ée ¡_&*‡³º•”£²ÍØY%èDí—½§=„,«):QNäÉfµi@ é‡Í»ž3EéFП\³Õþ[^«ºc²¯L¯jÛûH Ä¿C’i"²bvïŒÉ†hò%X=oâd9“)}qïQnÞc`SÉw›4àn(`¯æ^©–:~8Ù!;%’ñË ooÿêêè6ÔäÖÂÛhr»„··C ÞÖ‡™œ åçŠÇmŸ«*ö<5Ët7ÊÝtãMVo§û×—8ZÔþ‰tÑc—7Dƒ£©Ö|\eÎH#ãÃ…Â[ùšôt ô]0HYÆò]0èOÆò]‚ý¨ß…åÓŽ]!Lµºevˆ ¦ÃÑŽq_›ôðÊÍB¹Kã&á]„´P©Èå²a”°Y!ÑÝÐéÏ訬AÏ P}ü·ÑË"GʶYlñK¼½2mæª@X3¢\[lm;Ýe‹Sõøoes#KhÕȯ«Eø@LÇ…ÐQ®®ˆ5ÿgÀwa¶I¾wYÀÏaö/n3$¸¨n±¢yši6syîÃfÐ&,Bœº¹Ÿ‚{áí„y¿\N™‘9í³n$D rÁÈBÙšŠÀDQy@=ˆn_€¢aC>œLíôåѳ¥ 0s³™,-Ÿ‘©½ëäÑnÎüomá<<ó—îïú{Î…Ó¬¨ ·yˆlíT"’kûF+Ž7 ú‘Ø ¸s×dŠÃ]à:§sˆ• !RnÛÝC+?Id‡º£CX6”rv;ûÈk×lqàZõŽMï1—††N€BzY°%˜W€+v©à„Ÿs¾ ¼”·ÃGðþ(±Û½ßòƒ“§ß†.Kò‰ŸéA)Þ­ïÇÌÄç{ÂØM„lè@ÖÖp’8<€ÃÍ8šw®_Œo¯IPrm–Óç37sÇKF¦Ÿa3;ÑOån–†ÀLþ1D+ÒÖâæFdìZXöŸdšjÜÓœ;¢eor‘ù÷bÙ—èKw.uœf³oaÐ?°dÊ_(°µa#®®þàÙžÚx5À«ðñv䈥ñ~hûïWWaöTf^¯ðVuF…k˜°½ Nf]a†´pó^oMçýõMnŒùËÉRjå ¯þwRsyv²¬YŸP3D¨ÙOæ›ÉîΘ¶Aüô²ópµ˜:tаaE©ÖÁb²ÉáÞei –ñêñÝ"ÞÜCjŒx3D'Ñ*œÐm Ñû]5]“5 ~ Â5…y±ã[ö"¦ ËQwCØ$†©Íé í7Y{„º ý‡ãòÝûhË1é«$ù@à°lÀëQÞ¿,z!™å#€ H×a0eº9SÑúow¥Z*¨‹Ìñ­Û$ïuû5‰¶7áûfÛ”óß7Úe™íºÑê!f»pô½#<*iÛÆÃòa‚Ü4np›êtveª-JÂU@·éÇBBg½È‰WƒhÅs;Äì|’eÇZÍßdO¬ H¯¨¶ÐÖÔXË€›SíIš€Ñ:¾ÉÅ ý0¤9Çù ³×ŽrÚÝî2"9zÄÅáÅø•ÑŽ±‘„þóýæaÏÂ̈Ý0 šÃîy_?ÊÒ««øá!§£fÏAoE1ʼnè¯òIá‹ì¡?8eåcfº.,·—*+¯`½1•4¶ÊÊ”ÕOéÅD iȲÑ¥v,pQ޽œþÅÖlvÄ(ëÛuïEâØÖžŒ*¤J¿ôl}X.cbÐ&á}´¢ ²§0¹ºZo³´ìoX“ܼh9ª¥ý=âgÒXóWý i¿x:{1); õ2=~iF×|„ïœg~F³ÃŒ­¾Ù'ZVÑó­ ¼x–¦00óú}&†1¯ a ÀéX:s­„ ÌþôYìl`Vå:€î€å] ¾}ó“€n$‹ëçy…õêÊó IÞfõJLÉ"¥l›µ9$W÷7Sqƒ„=?ŸŒ!=ò+Œ5g2—ßÉi¼&§1\eQÜy¼:­3¢=@è[S4ž6¿¸­K=ÚY¶Ï¶ÝnÕXÑ&i -Ôþó€â·øðØH£œJ÷ù4óΚú2øŠ¶ÞæpXæÃ %bm¢U”‚ì^\Í"fqÃÕ‹Èùÿ‘×ÉÆ[ä^œÙ<Ùâý–k¾¼_ùÇžNÑþGÍ1fS0b÷1n·¾ºˆb€.‹aÎ×î¡Ä¹Þy¥¸Þ9„g-ÞU wE«îMM…•¢]G°‹E#¼ob5~xÀZTÙý.*ÿ»VZT@¨IPyQ“0X†Ì<Ø…¼òºZ=¯+°’·I·Qe]aÊ&i¥U5û>­À&)M"„¬jþk¤U5TžU…~²ë6´õLêüž–Ì•î M6⟳æJßä¤çQÙÔÙÇ)ån˶À,<ìn³î->…!v€X_”^Xpê‘Ù€”.”2ˆ/Ø¿Dz§ˆ}±()LßA ŸD2ÑL2¸%˜`Ñ­Èu§àò_dðSRâ YWlúz—‡C´÷r^`©•ä®G.ãÝUÍýÁ°5é e»ˆÒweºjè{ëMz/Q’m ýæ«»Tâ*‡‰X ƒ40NkŽˆÖù±k€3¬b(©¤>Ç«kòizq&ØgÊ"Ù½èÏ¥S–a÷ÚŒü霹ז?‚gÉíÕIZGn¯=×FÔ^8ƒEä@ìÕD'2$¯eê;Z£©@ cSV1EXw€@¹¼÷ƒÝÃz4|ÐÖdïÅ^ç: W}ª¿ÉžxK㨌›U@+û¯—Q¸Ê®Ã$£…pc•§yù`ï£Øæð…§E‹=Ö+¢R¹;;«4Oa¾ë8•€—jæ Œ%¥cð߽ᷛ?2mH9žÝ<(ê¥x_¡­2Ù¶.ŠÓÇé°“ÁV±¯ Mî8Ú {f²RÔõ~x…tgªíמe¥à ûá5xò/ûûtU&s©[‹‹koî!yZNÛ—ŸË³ì–§îÆwÃm„n4ÜáIÒuÈoÑŒù¯2PMu#y'é¢B–_Øó¬ãe!Òã Ë’iêŠ|Ú…a…fEw¬—'ùËǘãÚ >šQtþÄf@@ËQ×+ŸÈ›Í;³2í458¤ ÚMTàžu×7Í‚ªU>qŽ;”愤<›&T—Ô^Áø˜’vosr=ˆm„ J·kð;yRViñ‘g:êRÔ¸{~T€3DÞìÅK™‰ÝwâJØ(Õæ±†F:Ã]ÛêâÚèqg5†÷þpcˆPg·÷ªËd¬J ‡#Z=t/%¬¿àT€G%pP±m‘k¨ýS:jŠe±fó˜:lÒ¤H8òfIòÍvÜÔS&ut `™Òf:ôD›™$q2}ŽNJ˜Ù7 AÕX)†³tN²Š$OÏ÷Ÿ³44ƒ«mC¨€á/—ÓÏÖIëým.¹ó@q!î.Ù„!rúš ë† &§™=§ÿãÍÝðY × A j¼Åê8á˜M5#\ "ÄobžQS Ë6Š„‰€ìi#^mãˆ2qþ@L>Š¢ø¢Ô1©Yj)½¡©œù Æ­Ã)r±yx»WÛ¾×8áŸ[‰cÆPLîžwì{‡qï&¶wôÍYÆÀµÉ-]Ãd1È`§¤8_£EÆÉ²9¥ÉÏœ%|Û Ô\þÒd­žÞK,óòYÆÛÆOÍ5­mchìØ,µ‚1¸4%ãÖaT Oiëø ˆ²YöðA6 ™ÐKlKçÕ¦®º6O¢›uë€a…f!Ú:êxÿ&|<´uÓàáªfÝ: Lï”¶.÷ 0ü»òµ³g ¬9m2¡'/¿v) ©â];>ª~£ u\èPþj4!2#Ä¢V¸ò|/j‚wôè‚Oq/Ì3g'Ÿ‰_¡ëy?›‡0ûiÌUXb8œŸq%!x™2 Ñ$D싉ºg?{ÑÊ»ñöÍR•!<Œ·%Ûl¯Û@Û60(ö¶…+DÏb m›@uÛâMvZr1Pô}»5ùÖBŸtß.AON î‰lNÒ|Jr3·Þk¦(¦ÿ°Œ"¯µ¾å±‡³°B 먚ËA‰…J¯Dw~²ÜJók rk±´* Pra¬ÒÃ3÷ãxqq67~÷þÅ_n¶B¹¸g†Œ?UÖåÞG^ކ˜ÃFw*ËÆ¸Ë2ÙèIeY(å îºðåÏ OTÖ…êÖ-†cRZË4õI·ájóü®è }CVã›­GF¶™=ÒÛ®²³•öGÇæØš†q rao–Ž ’ÖƒE4f:¶çM¶ÏÞ£Ò„Ij·½1S» ÛN *Ç’®óìúŒ4E’"®$f²a#Äšybœ¨ÀW_rÅî&fœH®ØIpű\iPìEJ®Ø–0M\±yý-[tÞ¤  1ƒ([Xo¾™Š$ìmÆ ³X3gÑÕ%º&sWYä/g߲ć eo6&‚-“l%,ðÁñfÛÝ;¬ŸhëÜn°Û0yˆ“g„?ú™$+ 'ЉEììîÁl\¶‹È×M×±5\ôNNå¦/’¦·nÝ¿o'ŒÜÙ6`ÿk¦@1îù¯×~´ýUJÛÙ<þµôë¿¿cï½ ± FØC÷üÚL¢™.ê;ÃL,Ïc2xOqü5õ¢çõ’ÕjÐäÎmVÑøYø-»ÉÛSùËi[ :«ñÇʯ­jÏŠÅç´¶[8IX²g0X6JCa]am(LW|ËǼ¦ªFrYº»O_á¯é‡ÜÞø~ïëÆŽ§¡°ejÄ93*#û3ï™iÓÜ»®à¹Èþž¨ö¯åWÜd;y7Êv6í#”wý=“Ù[ïÍßÓt £Ñ+ëË)ó—´,Ù'sº£ë.Ù~äŽ#?ûÉ×§årÅJmE¦ì¿µ­â$¼6@À9ucYý°$Ô‹\@k/a=ª†@µKKý÷…e0ÝbÚ§ÿVM`¡÷܇gº{é±ì8{©j6ËØsžÉî¦Ûw´EÓ-ÆVŽEÄm“Dœ¶ú¯I4Õ~fd¿X[ÞóxÍÌ µ’Äû4§ÚöHþ3Ž¿BŸÂ1¹Èªb0ëN¶­žÉ¡™FŒஎ¢…ÍyˆH?§fq\Ž¡ Â=‹¦Â_Ý4$ºödNó”'ðˆr¡v/q´øË_·jn¦inôïoþµ²ÿÀÁùË_þü×\Ö›Ná/*g„ˆñt£\ÚÊÊäKò1e*°OŽáä°Æ§¹ §’Å´‹MÇi6û“Nç]íX=Ïá[B,©––†‹(ñžüÕBM#ê>1·Á†£ÏÅEuúî\gÙz{®ÿôçîò8ß*µ¬·¾B=æ qY³Mß2NuA{ªÞfHî–²ë|Žt–¡`PCL$u¯£pó PÆ4Ñé^uÄçÑbh <–³’HAkœÂÊ:Lã©7yÚZ¬¡ Œ^Âí¡êw£ C¬4óü,ó¸$ó{Žù¶m¸ºúƒ}kjcíhçûK׎Æú¡mÜ¿_]=†Y¾¥Œ£â½ÿlæãªöѸ3&ßµÛµ<ûþºý¤ýÞ< ¾lÅ[_r೉,õûáìöo’ŸEäл&ðYD½k’ŸIæÐÛ&ùï™d½m’þžIæÐÛ6ö{Ôm“Ü÷,Þ}åÒ/ˆø~JÜ%ˆ¬÷9û^߯:s#ÖËìŽò+_ïKâGYzu­²cšYHØ8©Õª C"`ë[0òÀ{‡P‘ØýæÝ:—½í {­™ãh½10Ÿ¡àz¥‘U/ƒ*Ï‘m¢ÁÌ ª­@¬NQUÈÕC0¨”<š{>¤¾®YÞ‹¿Üìñ áTׄŸ*¦´&C„µP(¢+kr*›å•Öd²Ì•5A]¾GlK‚Ân\Y’xÃ.«“!Z€¢pW…¸‹+nf¦Ò²èC¨nÞêõ!ï®(ƒ·´B–iê“`S W›çw¹=çÝåø£FµÇÊÔ™>šé¼xEͦ®°rpšhàÖ¢æ4 ¿."¶ê"kšuw€ÀµÍ\¼#"î’„“îZ ±DÀŸ ¾TZvòÉ®‚_Ò²Þ¬h¦¸÷]–öÜÂ'ÑÝQu¨ÒdwÇS2J1  º:„ïË Üú¯åàÆ ;î¶Ç3B¿ °Îœ@ÇÅS 󖈬c5t\6Öè:.yºöóÜkj½8°ù¢¡À²ƒ4?¶U åi›$ù<žQn~ (\fyß›n~<W Ùùø¤áïða¶o!æÔFixŒræí= ÐO«c£:èO-È…gçùŠ”Jš`¯:7@d‰ °zúgXgvõJ‡¯¬´ÌËÀÌpd^é³KÍŒ”e†í±öج¢4cdxÓ ¼¥uJöj¢ýL…=ÁŒ#Ò,Ãä WåÂÅ„èOL±bÙ1Eÿï°"ÿ&#Yq×”Ú£²!ºçq.Þu"3鎗þrýäK|Vme!&šb²Cì(2Y•ô)~]ÇõÒ*¶|`¾ŽÂÌ „RÕÕ´@œTµ³£\¸-æåÁøÕ—çk´~E]Cq¹@8Ì«ƒõ«­1£3þæŠUÄŸêréæåÁ€ýÕ—‡2ü I‹Ø üOw†Ñ>(éè¨xñ¯Mš=Dá’èV]#{˜+†¬<äø ¯=ÌÚÊ-b*Ë“ÇKÐ×G³ørA¬ „’Ñ:Æ“>`Ö9\ ?pðµÈ+«Ü! Æ»]]”$z|B­‰Ñ†P.ÏuÍÝ "Úºç!Bå˜CèqžâW ¿YhiiL•OÉÀ?‹QóqkϽ½‚˜œ€5àÎÁE (º=.‚+ØQ)BM£†cß, ÄJˆYÊd@îJk)SøBÞ/ð—Ë{?€Ïð+šØNjE“©YýÓY»orÜ}T:‹¼i×”¹,òÒ‰%LU5Ô3¦agÜV›¼’ÁÄM®4Øpïž?Æ€áÖšỠಠšc[L,kñs×cŽPZ=MÏÂ9´àFgÐþÐ…'[JmÚ}ò—éäô­Ñ2ôh¥{KDõ2ku(Ú­VG׬þ›ëŒµ ×j­ðÊ tËæj­Ã´´¸¸OS£¤ÃÒÂXn…•š©´ŽkÛ-?‹žñ–VUG貚m=Oir¡B–6ÕÒ‚?ÊQq:ÏüŒ6^è¿ÖÔ`³TÑÿ˜6ÐTE •Ûš© ¨5äâ‰q.ŠNZSŽkZŒ7€úÈêv£‰¥XgëTtþl) Ú=V阭âîEoœ…£dù 5`v#Õ`;*kª³íyƒ þðšÎà ³Oá÷mÿ›/'Z1œehÌ©GæÔµó­o$SGcãúõ2 üß²qB¶À$ûk;foDôeM yG› Oû¯²­¢&x- æä Y]—µå½dA¼þÎ`-5ºüÑÏüBÓN6ÎJvübLð5 Ñzè”è,H‘z+ÐãÓ5}ÒZË‚!pQ4@÷“#Z­n¡Ö·÷Úù¥?¿{ÌMk‡‚w Å1.xG˜ïíå1‰ñ¨´ó|¾ßà/Ì=¨º"O úÒL F]XNïÑÅ6äÙ>œ³Ã>Ð^²”š­u?þZùü¹îŸ#„θÄõ˜?Œ<âãô.çG‚ÜGVö„³šáÃ¥uf›„á’ñ†Ý>nVÁm†„ú·ì¾y]QºÇÝêÆ<…Ýpšòä_‰ž­w2šo‹§ðChW}°ÞMàˆ€NÝËrJ Õ—uƉe.éDGï1‚s ‚0ݲx¯“è…»W¡€Zx˜;¥ëŽ;•\þ¯IÔŸ±ýEQF“…¿ºú²ü5y5rhny¸™u"~@>fËé›ÃVW9_q-³¾$~”¥ÓÍ;8¬ð|Ž&ó–P2Âv®ÚĤÒpþïÓì8o3·çb¿„«ß z+‹vЪÏñÜLÚ°ÿ›©³fu¶!œè]ì¿‹¤®èŒÜûOY¶Þ‚ x÷HÚîßýxhs$Ùàþ\z'Ô‡¥ž-#÷îF’hìnXj­3ÚhôÅúÇ'Û‰ìkˆ7и+:Ö;, ÙÎ0¯lè#ÃY}Ë ?Eª¨è1q„Je!Û8F§Ùç½·"SK¡íE¿Þ²C ÕoðöD¶é2—L±k8®ÁZ0~ ÂuÅ+öK¾ÁUñT^õ2€~ÖVõÜG±Íd÷r€º)We¦h²•ò|ä´ë¦òâ™~v’ÝA Ó„Õ^žVŠ#ð!#si/Q’müeáòsŠ‹D*|2»;åãR#%ù‘ñx€ŒÞ€µ%²Êm[AU9ú26ÞÐRl¨‚Ð& ×wóhß™XÎ?7P=>Ès“Aã?7oáy0¦VgSE•ÅYdü=bD¼9?{YÄÍŠ_–©¶:Ùž˜b7­sê¦EÐó&ÛGÄyeUÀC´äîHS¢ã¡d´Òé o¿­"î’®R¥‡Å…0”ÄwBš{Osc}ÿ[‡ÒkkB[dìÙ´½ÄÒ³k:ö]ŒPMhÛV›go½AÔ”ºåèCÔL£ô*›ØÆ=†˜gS®½iÅWˆ6XlÅÕ*ËØÊþCÇVȻ €à¡@Àã’2iæg›”ÍÙ\˜}›Us¦li' -/ã0W¨pà©m›+°Á$áÔ9h ÿ\·j«ž3á`…©â’—µ Ý`¿=í MðFP%}x¯?,^¢4ü°Éºó@7‹Db7®Â¹¾&sú,æzoeúoqч¡¾2wþj4…"1õSfÓèlßH?_ƒîŒËˆ¼é,Okw£3šÙUûèïS³pmPPq¬×Ÿâøkê=¼2ÃFMžzŽCqÚ]„ :Ú™ØÒ‚ £®ÊÎWÊá ¬Lùè¤ÙÒ{ ƒ,Nx ~ÈfI´zü;Ø%àÛä8¾þ­cMљٺ{€N ê2— 2qkœL®ÄQøÆ[7z]H™,”«±>¤°mcw1È6Uv›¤)Ô–é¾4Ñ×í_&«âÀÀ—õ³ÐÎÂÊmy8ûqª}ÄÉÁ)²WWÞZ"æ=E<5C-Òû£©@k»äÌ%gŒTßÈòûKmué"Cø-ʇ!ÙÙ;Ï+†ö~æ³,û<—ƒ´îÀ…g5ùX ðQ‰ÆM’>«¥]]¿Æ wŽù †‡«á`­o„»¾š1 vï‘´÷¿É" ÚN`È Jüº4Îð&”«HP^¶r]ï îÚ|·ÿõë Ú,®¤\M@ý/0Ú«vý[-Âîå‰XT-p>ñ†¿H .Î{Œ²väÞ2EZÑ­­ªµÀÞ½ )¿ú[?4 _Ò˜¶Šn€ ²FñôcÓ•‹BÜFÏk̪"EáëÒ«Ž(Žfÿ([ÆÄ ¦€åàPRéºÎH¥ÌE;ûË©úÿaÊÛâ;¥û$þwœPš©°wއèÐzÚMѺ3gUw//¡û}µ«zruõì§_9Ò¦là^Ì´)Ê ãö‘ 1úk‚;I„/m'Ú÷:<[\ S&Ù°|åy©¾÷OÕœî”C¢ÛVõ‡Y@Ü4ZkÒG ³¶o¦ ¸yCÔ¸ôYâ‚÷ ’ýd¾„€ÄhÝu{nçQ"5÷¿ʹ^Fÿ[ôáÆÌ;áô®zöOxû)Z·Ø6å ëùu%Ô"žß=î¯ôö²¿O½½ÝË(&4Ea¥˜àe6bè¦ÛI‡5¿f¹ƒu(ŽÁ¦.·ô`?[J= îÒöz^üðÐfˆeG“ŒçvÔe9ƒ5+‡¡ªªR{l¼¬Ä;Ñ\þ22z¢Õ€/®|\HCdž®«ùèÐ73|»²— jÜý“ÜaYä¸ì!0[Û·««?X6±&|•"|×îùHøë“Ï\Ìs2Ð;ÏTå0S„·«Ò8£¹U[zŒ²!aEÚÛkHØo$…AßpÀxׄ:<¢gªœÍ|„^÷æF7’ ²e³ƒò‡ØmJ$3H‹Ò:ï–<ž¼U±L‚uºy̱2ž¸§æ¬8~œíÛ·u™|¸3' é ®æ-ä®Al£˜îU„²a]EZ€5ÆÄT7RƒV´a‘*+Ìà(¡É´°ÖW"ôjžÐD¯ZãJ$MóYÔ”aUºª ¨:ÜÂ˰or¶ÆÔ˜·‘9™ËȰÀضý 1—_ÇæÒ3Pãùã3·ÿ¤xøóhüÇ¢uZMÿqÈ´…Ä/4U&¨9~.;AmC2 êÀç$¹“éé¢ÓÓt×¶ùcØÖ¥¦±¥¥ Á“ÒÎn”!3Ò¨Vf®Fgw IKMöÎN$èqvc v&4ù†Žý eéH{xDyßPÖ~¸ò!=+BôCºßºí£Ç°•µ!ŽžTü!Ž×Ò"a_ze¬aßYÖVr¯KE¿¬ÂWϧݑ|Xynz T,£ªW/øöíêª2‡Í %i»!Îà }(ˆ:ù  ÕRMíÇb©FlqC#p%`DëböLÙ©ÐòJ×€@Eþ6+ÕVÞ/—«: ?HéB’½”œzHCeΚ=LB5Íf­fîÁi¹SÉæÿ"6æ÷©¶à,À(CdÞsØTQ 3Ù„»Ó‹UÙ³‡Í* –ßâ¿R6fší^(ñ×Ï^¾ˆ1£”eÙn/),Ö˜=%YÞB@_1V*}•À½äu<ãy Ù2Þ#€-¹0íÂe«Ýc| ŽÆSM=²…¬Î'›óŽGv®”RŠùÞ3óõÀE¹.´QP5À•or^ˆ ù H¤z´ý×…”érñk.3ñ»Ý¢Ô-¤"M´¬K_Œ¿åV®ÛX4[÷äÑ«vˆf{Äs$OØr'—èä®›^L‚±eP<¬y®„|-zŽ2Ë£pnWTŽÎd|àça«òÁÏSkå«9€'¦j£!%ãôdžwÇt•µ¿kF@ÓFgŒÓT”Ö·½¹ eDé"¹ÿsºÈ†$Ê<.“=±úè<Õ‘“FÞ•yþ?F«[bÀ¼ÆÉâTaôï¯t4Ö0ÇÑ$ ¸õJ£†àH12íV†Q×ú¾èª¡±w8Œ¾m{Ô¬©‡„´Æ×rY“MÓ†É}ÇÇ4×`|Êñ»4÷vç0»kézœìu=i3¶EÇÛ9˜'ÜÐW×M›™™PFu,À]kJbж° ©ŠÂüðÛÍïÞǧë±:ÌIžD€·I"V³”5Àš«Èí ÷kÝ;p¡õç3Á¹xŽ=ãnÐqÍü^JÈ|ŽòÞÑKßçÝ= 'ú06f—ÎÑx¢<[wسɶl¢í«Çžwul Cn•%‚ÏóbF·Ç”îÒ[P§–-Njéÿ ö^åÃþ°w¬ó6ä=evÇ—n­.Ã$¯˜ÖšËZ¤Õ+ꙵ×_ ù¬Ià³ìx,he‰ ƒ¶®šesu'fZX„¦nB–Xk@5s£´RÇoÿêêè6ÔäÖš=£ÉíÐäÙÞ1`gCáèïÌE~É…E&þßq²H'ˆ5TVã=–`Œ¡ô¥_W:CCãzã‰3@Šv”Ì£ª²­=õöždTÏ ª›30e^ko¶)GÓRþºc±–Ra^¼¼ª¸u“U›¦ÉŒžeokš.«³ _ùn\^ðñnò„ÏÆ@iȼßÝxÒ“5=w˜ÏqFR?<éËçÉ4brÔMÅÄéà…™bí·§›àeo¶ÿ6<³ügM'»»í·P¼»¶%@(Ýï@7„Ýï¶k÷àÁ5Ñ}ruK1r…0Ù'WöÉe$ûä ‘}rÙe Ø'wHcaê­rß°± ªÌÞ1ÀX@ê wx²hù“|³ä›µR}³`¥m"wûep zÞd{ˆBwúþfY•×/ Ðß?ƒ‡}²ßç¯Ð#WW”º›¯©ÑNÓë(½àî •Í¸ºú¸)5Ñ•® ¸¢Oâ]æ™UŒf惰^šä ÓâÖŠ;ŽDíTó ¦fÑnY· ä…"övãšrª!O•‘(2]-°íd/]¿þ÷MSm•\ sß&zÙ,…9HÍ¥%M›UK²öýªmÝ^̤u¥e÷•c(ož¥sq"¤™ŸmÒ-— ;+B©ÏÈl·™Ó‡¹ÀÐI,Å£h])÷Ü"9Ái×Ï3º–VúfEŸ(¹W—ž]k{,˜åh¬Ö6f—{E°]SkïK ÃÌá=XãiK0Ý­ãÀÉù›LËdÃØ’ ý'ZG€Ê²!€`™h­|hèD« ¤ÓÈJ hB»0Dè'#5Ñã?¢oâÑòÂ~H+^i*K¸é;„…®)ŠdmöÆ”‹éè0 ‹Z(*’—褆 É"nøK™ëÄUù@‘£¡o q×,J8è!ZvïëÛ"ðp Gå2á†é&øðnšÐàE«fq¢£øñŸdý½o8„¸wþ÷¿yÀÔ|³Im^žâ@T½ºÂÕœuã0ê?§µq«Í³·Þ êKÃPlm€­â›…LnëÙQ¡;™¥­3O]ö ¦™¹ƒÓ°æv# ¶¼Ýà´¥8’^o‘þ—óØJ@¸ŠÃ÷ÿ$þw¤Ô  ­qðtš:0ZlX|^£exCöý†®#EM“H/G’qã c4ÖÉÞ; ²<ìéü*|- Û~'ŒÝl™Ú•zÞãjãßȵ«Ì˜‘«Ûˆ{±,7Ðld|=¸r}uvX‡g/‹>H]Œá|í=Yõ¬PChnp5v‚·1,iN›©£ØKS²k^d£˜ ™- <ôdfÜæiXy|WçäâSs²T±9PkÛ N/L:Ö5pRNc9úRd!¨-!;¸ £_B‘‡¤ŽÅ`ܶìîwðX‹ñú;§úÌÿuMäëK¹[£#*P`E0Æãgñô·g·UÛLÕ$‰“¿L3²b+ìÅ¥ ­ÎJe€‚¡ãƒµá'ñ££ÆNw4`òÆá&g “8S™4ÚöÍ£N0â3†@D€zë?x /àÊ @zßèo·MÓ5ƒ«ž`B?ïæy À.cú 6[p Xbî¼Ô|Õél¨5„íV1Ôç,íûçxE=MŠ€†EëXü&WóìVÁžö³&|¯kHÍ<hÒwxE¢lýŠÉb<2ïð*¸D6._߇Í* É,¿»®-wA7 áFÐûèŠi¬þ³­^â¯!^wuÃÖx,î~ZUçov–¨WW»SùÃßþö7v€ÂNKüK¤*EäÛ¡ ‰…Š‹÷I1T ~;­IL”(\pàøT­©òªMwÊûÙÿ~z›•Ÿ|÷âÄ»ò_ uÕn·ê¶žl"!÷³ÿþǹɑ[Šã¯©÷ð Än2Õkg$ÆmÞmV´+óaËö§Ô16Ò€íØÖ>Ze”ßü%ŽùëAL rá)8¢Hîýé¯ùõM)·ácí7DÀ_RJ\t>ôN†ã` ™Sõ—¾‚¡S|—LRWb/P‚Àƒ ”h)D8ÄyB©--E§i¾¤QÎ÷wa¶IVûÅî+!ÿ‘w·RB¾ÿ2Í@HŽì“=±Z:€ffÇ–øÚ_.ïýàëõ2 WÙu˜d¿ƒ-x “gpªmÂØ‘P e]e„OfOn"3{[… vÜÔÀ¸Sj£¢`ËéŽÐ®îÙS–­‘þÿ$¢¶~Êô¹ÜmV΋¡°-Àáå"‚/oÞ¶dZ1*´]÷sé8\1]S xævaÃÓ‚ÂÛ^¶ ›"s;Øû`(Y€Âš1‚GÝÙ8ðv€T\6!Ýqaš™*ûÚ"Dd߈wmì{¨w.‹7ë5oæµ!Rm}²®ImÜ2~½„›YîÆåÔ—xۦ؊¤Ê«=Mék´W %Ø"´LÝ&)÷ÊB§q0•÷<§Dðoõ¬ü$‰Q›E}0º¦¼í0¦g@h(¦ó€«ì¡®„ù: €Û?J®Ïé5VéþÉß¾ì/)ßz¿ÿ·h•½£(¢¿ýíoþ3sï@ÊÐxÚ¯®þàŠoÑ„ºÁºÖ&xó h…‘@áÎIá\ž2m„(N¸Õº™D8—‘øÞ>µ|¢¦«òozçý_næ™™vÌºÃæŽ8uZøL§÷Ωò•ͤç°Ò˜0¨-’c+öD=±è0½î&a¹hvžTP­²²¤¢nácxDH¶ÍŒy¯ëŒ0.DÁ¾·|ú';”‡­ˆÊÃLÿÇŽ½24Pš¶côá2þÃ’Ua=rŽ )tÒH¾ÚPyÒˆ+×ꇳª¾‹®Æjª íâemâ LÇŽ«³" 9hËZØ7r»gâÇŽ»Œ¥m ‡«»h²š+¼€DyK8°ëE¥`1é1^°òbðêŽÖ?Û§fAö츰s“Dœt‘¿&Ñ4 'GÀÄÕ!%<íSJŒ¡¶ù6‰×a’Ez)´› ™¸ «mô_³­ +é=V«ZkýCé×waF/a1Öß'zí-V-Í\Û <¥~6r®»]œjµ‘4¶‘î$€È@ØV¶oªwÊ(†ä(Y.kTWh©Ødý$ºž죢³ö™¹M°äÙª¾6‘U ‹®0Š®4Haüé¤bÿP#Ø]‘¨¡ý‡ØQCHFä™p-—µ=°À$îTŸ GL᪬-‰p2—”fÊ“vl¢á2s4ˆJNÖæv¬!z­ë. œŒb sU:é[è) Q MæÐwðr® « s]ÕžA»‚ûÝ›<ÉM}`MehàÌåÜC}0bˆ!Þbªží 4À6æpn# íâè.¤Í €b6l4]cÕ§ÁÿóÿëÏM3!žimã½=GOÿ4¶£J¨Ÿ?*Î ž¨ëvïVÔÏ¥Ÿ² åj½7Ê5…•í£ÕIÑê!fɽ‹idïÈýöÍ¿^ÔüþÒƒwœ÷¢=#ú4²PS˜»»¢xHÿœË~¢d™Ì/«Áª,M@Óˆpá6Ϻ¦y˜”9Û®6Ïïê â,âeŽJËÅaÿB^1:Ôr†@ŠåBL!Ù‘RÉ褟Ašh’)tÖŸi¥ÐUÀÆ~:(Sèżùº …­b…º\w$‰»â‘˜jd$Ý“26{~œ2˜ð€°sðÄku ™vP³†·´iìGæ hÌi¢—ÐP@ËöÕ6¯;IýQ° °]•ÆÈ£Ù¥-ö¼Õ2Z}í^wÉÙ >»¥ ú)ý£Ø¬yü[éÝ<¯—Ó½•4”0ÄÚ GExc²ûGy¯{ÏÛ¹¦ÂZ“/ºGÌXæ®iër)WWÏ~úuÚÕ8dYª èîÛÝÙ„C‰†ªÀLœ¡B‰ªj@Á7í¦J$^\• qTÈf¯ûQÑ‚½ó7hÉrr›EUè ŸÓG^y¥–G´%$‡°^© w§’úyÑr“ðKòz…–]_ñÑ–\]ýÞœÚÞbTø‹x}òlMø)ÊÛÏóÌÙgo‡›ýy8YfS±0AÕíb³³UŒrÐ;_ÔJÈá1Z0º¯Œ€ƒªÉ-1¼CÓ V4¹ÔÈ]ä@¥h1ùæ´†ÊLÎÖ«t¯£p‘¨s£dº&@zÄebX‡Xý½ÊfÜË:ãlÉV2âÝæ°áà&\g î˜Wâc´ oÈm¿¡‘êànƒµ~‡™müV®Ñ¶·ÙÚvUì;Skg¾õ1ÖÎ’£ØUß[sÊ{‰’lã³6Ý·ŸÀ“xÒ 4óURí£a3 »ÝåsoÑ;‰˜Èc1¿™Š$ÜäS¿1×DL¸Ê"‹ºüSoæ‡Íì+Ú¹3”–ݦç2êË„Lý°ÑÏñ"„°·Ž‡•l++I#ë¥ÔLVÆú‚}õ¨4o»Å\÷ržùÕ“·ªÉZE™;Þò—ŒtàˆŒtÞpkÉL_Dñ‹w¿yxàíŸ\2Öy:ï15_Äh//nuSzS±ÖV·l®åíÅÚ–[m•ù×Í/¿…Á/›õf^q@»¤çùW@R}gY6+K5]ä ^ç|Ïò]9LÆ%ÛŽ¡Y—ÀN¾—ÂÑ; yãfIO“™–lžË Fc®³³˜1ö‚êì~3ŸÂ &Î@õw.´3T›.„v‰vÒêät°NA ‡Ø(ÏËâÜNæL&dö˜yÀd-( N}¡s*íGÖQr² 9Õ6‡@ší@>-ž‹tÒ)@Ð6°k.¯¾yl5`®‚Ò~Ñ-ú/Í´þ<½N>O¯Hÿ;JrÝen°a¹ó³i¶ô6« ‹â[xU#¥ã£•Ÿ|ßOà‡cFù?ý5ÿ‹ÄŽVÛ8û_)ø‚±d¸ìLLrÞzaœráRü¤aa¹¦LÑ%œøRå{ŽA¾ —@ékÑÎ÷EX‚̹n ‡SSŒAì]é^ÙöNtUé”m Ø=ƒ½ {ò o˜‚pUñú"ãÈý^Ê]1M@8±±oÞC´ZlŸŸ©„¯/ ÌSÛ„««?X·¥6N È#lœ.³6Ö€ð˜ë:„“­¬õ 0¶S ‘ä«8@Kq-VB2üÝ›¨1¢±Ç'Ù¡íºÆÜgãßJoÊ›¤(tRØì‰‚‘åÒG©Íx‘B8 ¤Pë?2_‡pÇAáæ[› Knñh8JÔ0X™ºÂoA¸¦D>-ºsªÔ€ñ‘°9å‡5$Ö5Ës‚á¿î0™aš’żÙSCÿé¯(êýJ؉¿ü¹û,8UNq8x1‰^-Cá«øfûÑÔÒ·ÐÇà[¿f!e¼¢;Úêû÷wa¶I¶zC@æ8O7«à6Ã>o• À²9·U6ì­ÃØ*ˆfCÛ(éœî&Û„j;¬A˜¢^Ó " ±¿…Awà6ûü8ƒJŽ®åôd£Ðº2@/1ƒ’è ½£äEf0ƒîá¨H³§»{Ìí½úÃ6IâðÖîâ, ²pÚÄN 2A¡‘/ä»Ç #0’­ð<¿;Ÿ;<äãÃ_z÷Clßñï[×ñEô¡*‚¥$ó ˆÉ/´¬ÜûÙ‹ž×¬„2;yå®Ã£~û*{¦}aËN^&%!ÏT„u‘R£sœŽ;,ùa !2]cܤ…”¦ Ë:ìÝ4“ѺÎ\ÕŸå@[#µIš‚»3zOHK¨ µñÖÛæ½hF'Sû ,Ÿ»Æ_ åõœYÄÛ-{?ìüË’‚sûW¢ídÚÖÚˆ-,¡GÜq…ÖF¬»!å¡þ~uõf<ƒîèDÁƒ^/ãó¨**4¥iìË*t½Tî;§¿ùgnTDÖ,ÓÀaÇÃî#†oÏÃÜ+K#FÞDìZ"íOá—økØH,ËmŠê·qSj£ÔìA£t)Q4ªC ú”²BÞ˜Iú\ÕG©an#Ôü<ûåó¶Htš,}:°@e÷ኻwÌb¬Íàní€Ë«\†@&k³_AÕ5“ CÓ•" m¬È,1;8Ñ`4p÷؃Ñ%± hv‰âëÎ8þúCé×ópµ( ³FõÚó5d'3µ³g:2åä+av(œl¸¶ƒ¦Ò½ÕQt Íð<—w“ _ƒÉ…9 vßÃ3;˜C†0iLE#T™éª:ˆ¸EÈM$ûÈŒ`œ“] ³ïe@Î Uè>Z¬÷‘©—ø¹ÎÏS~]wQªRUÅeì°†¹Gfh/½oþ}ô¢Rºõ€†5ó‚,/ÚÓ ë¸ö¤ºm_ŽS)§š¼½ Bƒ‰³¹Ê?kì×]?§æ)-ìÍŠrè¦QÐeqÏ­,µÇú¹!ìŒ|š ¹0,¬—Xš,½PoÙH$W^‰ EDqV×çð?ð¶{ÀzŽ4‹.ÁÃ×Ö§ÊN#vÿ:£ÀZUöoå'IüêÅ_ñ¶NµwªŒ<“Û9¼m3Ý,‘Ø}ëÞ,¬YPeß^£sâ~/±´m®ª ±mtÁÛ¦anÛ}ÄJ½—WÞ4G·Ø4Œâë)Y'¯Ï~Šø²™ŠÉ…èl9ŸŒ÷}jÆ"DŽ81œ¡x©z±|ì¶ ÞwAÍ;ÐQaEå!Àòqy4h´žú««EÌ÷âæÅ?'ÅóbïUM+ß:!þ.·mV![?³ìàÔÖDgVœG´sZtø+ùæ©ÝÜÉ_Å̶Ê{ëÌeÊâÍzÍÞ?þ½}f[y埂¶Î33ñæuÖ³÷h€3‡'‹—ñ+Ï8s‚xå»gNP¡-™Þœ 78æ9DhV×`¥ð aûЬÊšeôÁÍÝ+'Íìæî­Gu¯ zþ}š%~”"4Ã+zãf8MûÞz“„ÞK”dŸ¹hü`{cÊÜÙÛ˜2­ÎW™ØÅÇïyl{ üÝÙÙäˆ"wf8¢H ÿúØøÛsÚ¼ÖÔÆó…boc~ üᶈAMifnk.tk±¶Ç‹“ìÁ‚R€8hWšÁ.R<×e ]iþ ÷}Ô VrexO€òþ-ãÕ#„Xžw§ÐèèslðZSUEÇ}`’'{Í,ö6íÝSýõbòÍ1ŠŽÛ*u¶eÇ—þcå7•ƒ×{˜–=¢ÙtlÖME®Ú¹<³ÍÚ¿ŠÚ™«©Íf•F«pñŽ>dù?z«=!ϯ:µÆûzÏxBê2Í„Öh7M4§IÆ;Š™xÜG»»ìM€xìfË1Æé§N5Úà:Ìï³­Iáù¨yàI:©– {*1¨ATÛfì.˜3|37H¸ÙAª ™ÙûL®d™zÿìzwF Ô{¶·¥Ó§8ÉØ.$Š%äÂõÕ^«¤5#+F—Èr÷]À]?ìt1ðšÚe©×ß½Äì°k±wØeeNÊí!"¦×–€ÞÆ—Éß»ˆâï~óðÀÛÊ,¡þ§Éá+ju㇇4䬅)óîš.ï.Ó#„Ä-pJU!ÖòêšÅ*ì«—V™ñ”üëæ—ßÂàfµÞ^,rcPó¬ý:Ïó¯€óþ°· çy˜ Ã*H 0…Ë|‚$…<•ñ&)äM—§ð½W ùü_³$‰»}IHXÿ««?6£&½F,½ ]¼rf@ªxËaªðÄ m‹™ðX¿ã”óÄyD_f,Y¦•±T]=“x‘ËŽbdÆ’hmÐZ–tLwãÓìüJ‘VîWùvé/WéjyÞs¼»Ço9é!ÑÛs[ªõ‘«f©I´YÑ^¹JÊÊ úaõÝ[ø™_$¨þô×ã¾ úkþ×SŠõÙ‚óþÔ½Lâ=§&Áaª+EI]}Ö/¾¶Ã·Ðle2%î²roUˈi@¼¿ ³M¿rœ ¢›Up›á´s° XUÍ=¢uEC=¢Qz8•ú`J&B+á2Ì­’—Ñ• b£+å- !¦-©Q±ˆ£K¤E¯Œ4`°Å¶†(KstgpPþé2ëÉãôóhÖQ´ñuI™l ”m±—òl¡c(£k‘2é«è¶‘­¹ÆQ2ØßdO¬Ö“ 0@N`¢oô{ôA½9­(!ù|Xï7øYÇxvÃóšD¸W÷­d̃¶±6B‹8BG—Ñ›«pL´‹ jå1‡ô€ L~L)BMŽÕ=¥ÝŠ*ý<ûåóÏ\;Ãn‘¨ª3xåL•Ó‡'¾R7!ßNV_aðê6²Ÿì}êÙ/¦©èƒÓo5vÛœ²‘™›íýG¨é¸¬›)Ò]˜®†µ)lS…55$pÙÌ¡ë»MAƒgö;/•I·º³>ñ ø|%ÔÝ/Ÿ¸0wï_üåf+ŠáÉÂÙŒÀ;]Z‡[?¡½ldÇmE–„£ëÛ‚`@;KGc&9õÛçx5߬×q’…€þ Ò˫Ãf[Œ®Z‡õ¹I?ÇÙ‡£$„ᘚå–W†«] ÓÊ`tc,­ÌŠ|›hA±vÿôW‹%/®·¼6}wª|¯)Bkóa™ÇçûÝfµŠVˆ £÷¾0ìæå…ÙdO´¡xëžfY;ÙåÕáBƒ3­0õÐ(ä°:?ÅÑêÖOÓ×8Y`/NßíuwHj¬Å9ô¢'ùc¼Ya>SVï‹ôC…”,›0yŽrÀí]ø°IQŸð¾c¾‡²–4 9¬ }¡žþ%lË 7 )[6B̮Μ,ËÂoÕ”å‡÷?ú/·ILÌâ, Sâ1¤äç×Åå5â°nØV×e˜O³ðùyâj¤Ã¶*¸ŽÕ2³osKŠÄòšôî"›z5 9r>$›gòt#®Lë lWf&/ar¦ëx•":PZï~‚†ë'Ìç?a+˜Þ ×9 öïa|_ p´Þ½ Ù;ðWA¸Ä´{õþu ®Ophë€|Xôþµ ®Gp>ÇYˆ½*ý+\‡ÍÖ­.Kïš…ÿ¥.-ʯI$Äà¸Bl‹‚ëlí—ÆñWÄ£Ò{FÇõ~]}]ůèOsïËÂoË•M¹¢œ˜/HoQyq8t.ÓÊð›t¥•¡é}bûÇËM–WÊç9}´¥áлLKÃoϕ͹xµ º,·I|¿ ŸÑ–…ã21- ¿MW1\yÈŽækÃpÁiî–—…#ÈË´,ü]ãiù=‡ñ†/ÒP^Ž /Ó²ð[tM¹}ìUáˆñ‚I—º.c ,®6Ï; ‹yŽù¹ŽáÕýggôNEY\gA|œþ3ò]ýMÅ‚F°˜A¬ìG˜8 *J¡†ÅJ'¶O;>!§jéÚ4.¢9nå÷~+±˜þ:!¾yÀB*ñ×u?¿Í‚ÕûÙ[ø™Ï;³…©™&O4EðÑ<ƃ¯7«àbY«D­L¸U ÔCŒ—9‰:¼|„v%¹$²…Cö•ÍΙÏï@è×|‚¯®þØýó;B?q#ìýÚFXÄÞ" ¢gé­)Оy ™ß‰²§x“ú«Eê¥awzª£œ³=&ñfÍŸ£ ’Ï~™dòp’¾·Îì=ãÁ_¦|ƒœ"=œgÎnØ›W6²Ã®ê䜉é²w³ç¨“Ñ â¤™n q^6ȸi¥4ÌDB(²ê@ª}EŽ\öP]tÇ “»ž)·ÿúWCWÆÂut1Õ’0P©\áf6«5Üœ#(ú¶{L]ž7Óóv¬øÁS8ùæ#t/‡ÈFÑÝd¥óçŒL9u 9\JÕ°!¬vÈ4Ò< #šK¢+=*²Ç…ÉDm¡»6a|h@QY!«5bs¥¿ãåÒÏBïþ;ÎK$ TŒDvþŠl9ÇWWTÿ *Pøh„àVf†ÄÏÄÿc¡ l!KüUú'ÌÅZUT`ãO~ Pz5ñ§qtªQÝ‹át¹‡Áú&C»;p¼É²f#@`Zp5,`³¨J/ìw'4+¸N úóNT Ën‰½”ZShë¬<”)ÌëŒb˜•Ž3@w¶Èª,¶ŸÅÏ©­¸¥îÚ±5ÝâƺÒGº´Ò*î:/©"毫œhËáá3d^iŒ÷m«Ë¼IC*šw¡×#– ì!ä­MÙ =¬²nÛ<\"¬«Œ@ 'ê%Ü­ñE¼„|s¢Ö™»j'uðÃŒ@['|‘/â4#áaZuµ*pŒjË䬚¦î©ØõD™(Õ¦;Ƀ/4aŸ¸3]8*¼<1˜ŽJ¯ä­Ùô¾R2GQùKŽSê¦WàÑ“E”èªÓ*ZÆÐßIÞ#˜·Ë{dª6_P¾OÓ`¯óÕêÐQÌáüÐu›Š qa8‡êÙGw„&¾™ëh+^0ÑÑa‘,G‡QQ•¾†~£Ãý‘â1€xVöâfMò^W ¥œm’°LH¸Ö+æãS–­ú:—­G]ìÓQm̶¤&¥^™ÏRW@3¿süÏî+·äŽ7€›ù¨ªZ‡Mûu»€çtt-}èýÏİá–af“>ô9A:ðv{TM“¡ŽkO‡G¸Žì•uG1“ Ì_˜S} MÿƒóJ7– `Ê—ÄŸöEíí€CØP æ@Åz†nËb½1ëÉð5DŒ _wÑc™Þ.ÊÜCòPïï!Ž*äñ-Ç…¼¼‡ú¬Ë6l(° + ”¥8Ýy ˆüMöÄIÞµíâx³zˆßå¼Óãï2ünˆ¾¦!ÕØT‚"Ñ °Íë+'Àxò–—Øu®@†Á‚¿ãxu-%KŠER zYŽÅÕ‰\àA<¥?ûO1©ÝÂDQ¼ªÒ»L IiØ&+P§¯o§æxÝûixQš%¡ÿ\˜I“oaè°Âh ¸¼×e»° ÇøÀ”Žé«Ô˜“,Al?2Ðßý§ô\qOí?áÂéŽ'{ ²ŒñFz ªfí˜ œë€§$ôdÿ3±L‡„žB%ôäüG¸¡'2#SaEô:©%¦p'XÂeº«]vG”ÉÀi.ƒ½p–й£~ùó!p׃¶³³X{Ö°ö²T£»¾«'l¢eÈ™¨$ÿúH¤¼c ·r‡Ì»oܹ}³M ÑVÈÜbm ',d>UêÚ o €®»€ÏVn_¸Nœ?‘óÞ…ëeøÓ앟ÿþï®ÚÊØîÛ‹ês$æÉs`Në“Çžî·T '?5¹:Í4[z/aÅ À<+ƒa=xGÉÀ‰äT9iæ'œ ]e±óy ,óÀ`Ƴ¶Ñ*b÷ë¶^\„8´˜Å W /~ ç7NüG^lÞ" Ô|u‚¹ßrÍç‘7üak,QW…b‚n¨C׿üýð£çuçÆìÍþ:Ù}Û-²ŒÑ™ç‘Í#E2˜òj¨RØv æÁu¼ŽÂð@a8.¥ÄÀª8rwvש~½è_\,>¨﵄ø]¼I œœDémiXøžÊó~©'ïÁÕÕ»ß#ñqˆn—¿è6Üc˜}õã­¶Ëftìz¯˜GëÀ<âì„ÏsOÕʘÍd"1½¿þ°èÚÑva„Œ‚*þ12áßQDŸàÓ:Å¢Pä)ö`’Ö0ÀÅÓ:ãL‡E;˜Š9H‰’iœO4Ìe·–ÎS®U2•¾r¯i XIÞ*IÆyNÈ8”. †~DÙ#Äò[ØÚVX ø««Ï!¯¬—±Çvñ–·—ÄF-BñOÈù8æÉ“Џ´ Ý·RÐ ´µZâtˆ#t ÍÑ!z Íš;Dã蘃ÆâlæX°4«b0; xp@•t©.¯øù³wÓ,æ=YúßQdž´í²£G½ßrOxÊ9zØt@ð¿°û“öauƒù:‚fXÁ—8ZÐwçÏ€Oß…Ù&a•w¥?’]¾Í°n ‘‰ÕÖ FN·rU±‚ vmõø_úÿaAg³YÌ’ÄÿŽÞ±ÍþhJjÍ2 V!ô ÝeDç완ʵeŠ ùt¿ÑÖÉö0}R-c|¡óéÛ¶3еYë_€Ü±óüû4K|𙢍ÙËз;l`¨íªfXœúV¸³Î´¡ƒ—õÂ’•,W´¶•Ý o*»H×°{eðÞy‘K;îy‹ðÅ뼩,w´´¡ôW‹ŽäÄg7”ã…4LG» l3-ˆ?1 ¦#!¤D¼8™ÐCÒŒrÈbÊI¢$%E/±—RU‡¶Îª¡ ±Î8¥û•îœ6l“TYj?‹ŸS/Zq®ri™[Óma¬ëŒDB/h—T ó3­UγE,äVã-E[çê2oÒP€‚æ]hÆuƨ·¤¡y±œ;¡C?‚X6ÁK| 0>Ó,DÌ:s£†wR‡>ËÀìi³Ák|‡èô6 óþ¡$ì$—´9À2±íÍBÄ,3JEÆNòÀË ²6 ³Ì…soðN2¯sÒ+ío3À§¯r@Y×wøKä|N ¸-tä»X^Óéfœa’”º­ècÉ8ï3ZSf§…®à`Ó:5­Ù9Ç|”ÅŠ\õ-˳ÊѾsfç{Ç™ž‚ܹseèƒAÛª>@é%•Gæˆ6©A'޼²ŒaH¢mµ»"¾‹“‡\å8¶Aî¢ ôˆŸ›î}´‡ 6LEçÔªÂÁs“ÝR“½È‹‡Ÿö=Éåœ~ŒÜŒdy!ÊÍש^I[5€ð$«Çáµzð7sòÆOnJJý:e«Ç֠ݶ‘±V‚ã¶Ì¨Dâ&}a.cÎê9JÍ:Ù;IïÆ wRg5xDÞÉén£>Dh@7“5ì*pÙœá93]÷ 2U`ÿ+;Hó´ï¶Ü8ÿ̲õ5M¶‰¿†«y¯ä8Ée§‡bËŸÛJ•&€µ"ñ Ý „4t;n2Õ®ŠŽB¶²p¾îÐ꬯>g¥îqµñ‚od÷*sØ+Tæ[¸—̲ýu6¾6Û¥›Pk ”+c šÄ(y2uÕXÞ¶ê”±L÷¸@éÂû›ì©{õ)·b„ÔŸžÝgKe65Ù¹¿F] >Y·Á&ù­Uuºs¸Õ:Búäe<26©€?1=FÑÚ…c±±_8×P8“¾ˆ(Ä‹ œÑF%ý^8Ët»¬£\¸È6Åkçjn˜v 4Oê£TáRao–hÁp!D M†A=mÚWÉ@éÂè€C>¸˜Ë:Îú wK¶ˆS£~øKVñ"ö^£EÈLnð~ÇÓ*~å'IüÊ._SÄʷΩ†««?ÊÎ<’v´¢FÒÏlI8Ñ5ÑÆ™ÝàíœþŠG¾y´Ó òW1{“*ëÌEËâÍzv”×åÛg¶•Wþ™ÖNZùlÞ¼ÎdÂõ΢,^Ư<_äÌIâ•ïž9I…Fez£PüØM%¸g¹€[Ù"| Nc¯|`SôâÓ›ù転'Q¯®¼«ïÞÂÏ|_¦»u)•1€ÍÌ‘’üªÛ›¯çÂT#v.+Ÿcw’Äò6²mc Owç°à N;¶†Õ#¸æ¥ÅY ô}ÄDŠô÷N³¥÷B¾=+ˆÚ±yä=ãþP½C=¹Oãó„ªË0 ‡Ñ0S m*]KSœÁ ×k±¦`Ìc¶ýsVíÆŠ§ñWÍÈ[,Mµ9áØ­&ñWa‘£œØ È¢Ö*ijØN*7ENí˜ÜZ9ùz²Çn·©˜Cq!p­‹? +/,®º}x,â¿¥Á¼%nhLŒ:¹É–‡h ?6ÈÍP¡®F›¤)<4×ñ: @½ŠKú hVÒ~=ê/Ô?ýô‰ýmæ"x_§I§h~BïÒ¥àOÞƒ««?v¿G,ŠnWfÒm¸Ç0Ë÷•q°]ÙIçÁ®—ñŠy´àLgoê}ž{ªVžÀl6 Z3† ¸ÉÙóF…›jèFSú¢`a7Ä,h)x«$iˆQŠ| )Y4K£¤ƒ-“Ò;Š…SÔ5‹ƒŸ£'œbí›C``«Y–¥T÷­dv¶±6B‹¥‡8BGãŽÑ›qwL´qw°ç蘃Zs.°š)§j«ƒ'pŽ ä§œ¿_pºe ×!èTç<:¾ò—Ó„YåÉÍ<,ÃpÆC®w©qMí›ÅÊV€=$$UQ½ˆÓMRãÿ{§2¶U@¨K7™òÃ¥-ÿG¼ø~›Ä/ÑÀq‚Vœ>t £ÂœÀŒÊ©ÖÆgFMUc› K¿óõ+ot¦Nã+(mÙK-€t–=bÜ¡sû2qY®ØÑu¶o+;D¯DH}ÔïT~¥"pS`„éý<·QkŽÿ¢š•NÓÿ N£'9XÓ` °j0rÒµŒ¦Õ7ZÊÖ¤*=ÝCš}¦ËˆUÌhPNeì‘ÀÜõè>–:šNµTŽ®bÏ:t¨þ³M›6´Úc.áf¿8÷!egK`슈k1{‡ôjÆpMžåGÕ&Ï^üð0ÍÏd‡™;yóhCz/6)gh ƒ#ÿ×,Iâä2¬Jw€ÞMô rºoê4MKé»e·¡ZŒ¡n¼½<ÚÄɦ*È2¡dêX#MåÉ}/9ÌœwÉfvç‹·g]¹¯‡ð. èýìmV›”—õ£L[hèe »ÊË  Bh”TYÞu¼È¹!ÑØÕ]kôxËÖ~ÌVáN“bd‚PþJ¿ŽftûÐŒõN ö;ö·}x› Êô0åäŽ,À ^¿üî‘XOZY徬3æ4…°Òc¦ÛÓk=‰Í½,b—â.¹.OƒPè':a–=±kr±A9sÖÈw¦RAÀ]@€Z?P/Ø/üÕÕàM¨‰®Õ `Šî€ªw÷c0!ê;ö³¯!s¤“Ù˜14et½K' ³MñMjÙrÚ~{à­û1\†Y8õ¦³¶ÝWÊ=Î![gñ´Î‚Ä£Žù†²uÖ BkëOL†Í¨I¯ÙÈÒ;µÎ: 3`ùžÍ t0˜SçlïUA–øl^Føz<AÔƒïZw’½Íóø|!·#Á,ú ~™žw˜Ñº¬ 7¹÷Ò!ÝMN¡¡ºø@»à6å#d•z›v²7"VÓy«D¬œêº×“œ b€þ‘Êdÿ™a• ;«3;Ö´Y«y»ˆUZ¥fbÓ†h¹ „Vi;›–ˆ]¥˜åƒ'ÛŠâÃ&c¥,ÜÊzñ—›ûU*CVbõŒÒ<¨€µ<‰(–ÅàïTZŒ~´üåPÝÞ(¯´ZÏ«{EVã÷y–„äÇZ }Ü9ÊpµyÞ½*?‡™¿ŒV_Žaõw\™KFQ a„Ò#5#ß £Þ×µXáÌ™Gg­Sî3¬Óˆ•YÚ¡”RãI¨PÖûÞ3™ºÎ Jµ?M£Ñé×o;æX:%Ðÿ0Ý«伕èÏ…ó é3^ö••j»Ó E]Jú ók_°†{Û$º-rFÝ;$ä$Œý^Änïã-æœQ¼ÝU-êO)ݼ—Ñ#N©ÙþòWš¦øË_óÿ”ÿ—?X¾GåÍ+!ÏMžŽ©Ô ¥Ö­JßÏS®Çú%0:˜ãõ `15º[wa¶I¶—H·l€‘Ë©8>nVÁm†¤8ó3y#«üeAt_®0¶ŒŽu§ª@©ØÅQÕÄfeL\ß_AE”¾€áðøÞâïŠvè^/ÈÇW Q gô‚nôͶŽÓ-;SÑ¿:­šäZ>a,ñÃZ…;9T¥¸[¨¤”_¯”«:\ï›À¨f `ö@”Ç[ç=ßçëÐÌl|!»ã¥˜DÄè+W5ýF2˜™ùø>‡‘>˜Üš4B@4<shV¿œé·÷ 1M;#ÅX£ž^žÑ6håèÊpÜ›`èJ˜Ž ü@¶Ý[„i0MNÛИñÃspòo¯íçÿü_=W€ y’a%Ë&Ö/,„§E ƒ÷ŽÕ‚vþ`[h¶w )/Ý L†FYKJ£úØè”Fq'e¡}òò_#mWIJÄpµ+2àHF£ú¢_]ýÞ€šàž]ð¹QìyQê­‹œ¶×ÝVª ß!5…ï Ù¥;mÒ±G¬ÐK®"ØlÙÅ\ðfø¬Œ'Á$óÌÝ5k” 15À1.»¬Â]™F«pñn¯»~î•Tñ°“ˆŒtÙ–sK¬±‚r8|]ÂYÈÝléìeÆ/éÇ–¸'߈üþgå?•ÄO™Ñ ’þ´ÙH»ý¢ôrLJ]Ø$q^–ÒwcfÇTçy£R'Îòf[Fß½ò>ÓÎ!0oçÖq:,ã‘=lý7£°x µ¿ «ÍÔéóRCÛÖû†Àp2´˜L4cÞ—üJ0]†ðy½ô³°Èã¬9³­;К3):ïeÄË’÷nR07„+¯9" tùGÅïÐ}b;eÖ€tl£¨F>èWËQŒ'‹Û©˜5ƒ¸Dcº×!©Õ#Ju4©æ»ZíÃÞœüŠØPÕd‹Yø­øÄñ½Šæªp´ÑéOnE`ëE8Ñ>>]P$îiñöŒ5 q¨ ÔÅÁ£‡ºÆy|¥kF}¹þ}¤ºè üÚ¨k5ž¬IOºÐèVM´EŸ7ßH‘¹C¯ÿŒ'Õ„ò+zÐE‘è©°Ö€S¥ã}”þf<€‘kc;%蹘ÅP”}¦àmþëÞMò„¿¦Cä5½š'-3aC[ýÑñ‘eò|j»Zçš“sÅ…D±âÐÓB¸¹©ÏýÜ\é|Þ-7Wˆƒa€6ÜÈLø$\ÅÓñ†Å98Í\v¶Œ~ü1‹&qR(0Ío×íw ¹Vå§ãÐ#ž«fðQO/pa)éƒ;1•ú+«õ§¿ñÎ`(zœ–~·öïÓ8!´Ÿ6«ÅLm«ÿ!¦ÒÇÔßœwm<Î…ˆdÛ3¾‰gvø¨CCÒ$GÍß= àÆh0ðFxx/þ)›}¹L«2ÛŠ£×«a Oûº‡•r'¨‡ÓŸdðÂÆ6–Ä„Ê+¬€2×­6D-Þ‡%æ@‡?<4w¿ê´~ø–jv‡‘ªïËÒkŽüªçâòó×hz™,×¹ÎGÐ@D%8פ<1‰2Ž…Z ÈrTÊŽÄž6hVÇf€81ñÖË”mÜW㻥|%Ú kIÄB½Í"î ãñ×Rïå¼™ >^†q)Ÿ×Qó+yÜLÎ È™ :ï`çgå£:Ìõ ¤{ª–0XÀp!Ê`‘®ôˆøùá­:¼zC´ý!]ÆÑ¬[¿ _©ÛC¿°ÊÃŒXÿÙ(˜ó?еԧY»'ñ 9ΰڲ{ɰ”5$%³q:/Þœ4 ¯©TI¬ê1¨¸¨ž€A±½rè/‡`L<\Â} ÞŸ‰ª ¤Yœûa×ۈ·x‰/ÅH›Óþ³x•6ç­É¹þ¢/ MQ¼Ð‹,ög.K‡‹Ÿ¶n¤ÙQKš¦Þ¶NáRPe¼aT>ÐKb7ëÏ¥€ù)Þ ­V0 -n-ß#é’é nzú!Ç}ˆžµtõ±Æ‘ÜiFp}ù¢T·wh"Ñ™|—Dç%ôô_Yœ=Ó5±o·Ñ«'À) Žyœ'öA.üx£0Ðú‹…m$錜’a{H#ÎE·tšmÁ€óæ_oýùÌDq¸¢8È—Åt>ó­^wôµ8,ß3_ëìeÆÜl XMõx“Vÿö@·RÏ´UÅŽb´•ñO¢x¡VˆßLä³tˆü›’ ¶·) jlÙ½dLIг´‚Ú+ÿÁƒ’¶âݦ´ÿ™Ç5ç¾–Õøz‚Èœ«ùU_Xn*õQËÀòúc½3ó–W›X~hËåQBË%ùp,Ò WQ¡jyk€ÜÑ' [?0ÂDâB/‚;è’7Á¡~àqÁ|Á}ÁŸ}„´‡½¡°£%Ðígȳ€îÇê·RüN(Cm[K½¥î§"¼’¨ÍÿÔPÕ'ÌÃëóŠÏóñ¯%quÅ…ýø“³Çÿxý¢äób<•‚½UŸJ¡ÞÎKÝÑã(2Þ§'jé!öûíê¡mv¾µBT׫ŒªøEú)ñ‚ìqR⟕ÿ4îéôÝC4Çø¦­OÄî›Ê#y*Ž©´,/Ó+a§ áI¬ƒv†Z´Ì¢i˜G3"òCOÇ+4 ²Û5²3PQûÕTœØò¤ùMÍ-Òi¸ˆÆóƒ†AÕu÷€ÿøSa£óû, ¿³5Uå25•A0·Â„¾´Õ–ƒ†Ñ ·cÃ( [Aü»­?_eižNÓ…ø°Ú’Ç{ «ZÈyi­ëTüÅ M¹ã}dàc§ ªÑ#t,Q™\ócý@Åøð3 wܪ*Åð 7ûÑžØ 8„SØÕmŸÂáêæBß¹*#õç°p€¸Ue åiê GêÏ ×D#Ô‚^)Ï m~×ç°h®/ÖS(A[c€À'ÆTîΑš¦ËïÙ7øµ¥¢Ô1d;ª²oäæÞªÐnœÌ¢{ÚfU-Pa1Ða¢Ý ¹•6d:M× ­:¯K™Òs<5™Uû6ªd:‰®ã„K¦¶e dQR¥'˜Úê¢ðYDúºnÅJOuµ!Ö< “Õ<Ê2âØƒºlg X¶ÀzŒ}[´(Û÷ߤîß²SÙÒ^·)ÛË †|.Œ(_蓲 Ù…ßWQ6O³»0™F¿„Ù­üùíRšr?é‡1ySTµðóÀ}…‰îÍ—#4n@~`V½JË“Fyµ×c<ž,nÝþXúL‡œŠÿšIÞ¤hÕ`†¼¦Wdº­ÌDãæÎ˜£i]9Åglw‡FEÔ˜~}àº?àJ8*ÞZí·p±&ö¾Ôýšm“Z_à5QÒúØ=ßM ¯žl9¦)Å:bÅœv"ýl8vWJòè>‡…õj£wôÐDó›ð¯ûå"Íä! “´¥Å!6¨‹Ï£Ø–ø­øW3¾z É€ê Øüââ)*—•Wè8¦é:ñ9¯èj®†šß•ù¦@Y·]Åe{òu\ä 5 Œëˆ’\BþOµHsþö쇷?H?ú%Ê×YÍE÷¿×Éô*—K>“®®§B`ëp°¶nç½Ùõk4…–n´Œ¹¾ú̽g J¸Éóe&ÆG¬€c7”±Î¿l6Ò2q?rAg‡!a[ž´ûØ FÄÉO‡“E¬cªƒl„u”-b:¦ª@ý s=Û>V*l/" l†/Š]~.Àà¥èÇÅóâŠÑ%:ŠŽus®=Ķ»´ªÈÏëB‘ššÎF@IW¢ãù¤Ó¸Îb¢¿û-‹QÕŸ¸ØSõçÈöor J{kc/ÿ¬·“ x;V¡«¾E°ïídº^D_‰ò(ŠcõµÝsÓÌ¢¥ ô‡ªqLaX¾4²ìU¤ž½eŸIöµ/ª¬š[t¼Nøžêî–â=ÑÝö1zѶ9°lêÀ9öªWIO_äÝf9„îõö1Ï—ÂéMôkz%Ú^/F ïÇ‘ ²åï‡ôÈõsa˜ø^DE/Ë¢…p!}öˆ#ÈÉ;¦;󣇰m[Úó1´'•õ5Ãwð/5ôøæ÷4›Õ?ÓÓÏþþéŸÿ0Ë,³Ì2Ë,³Ì2Ë,³Ì2Ë,³Ì2Ë,³Ì2Ë,³Ì2Ë,³Ì2ë”×ÿ)0„¶%davix-0.8.0/dist/abi/abi_checker_std_version_32.xml0000644000000000000000000000125314121063315020707 0ustar rootroot stdversion /usr/include/davix/ /usr/lib/ _ZN5Davix19httpcodeToDavixCodeEiRKSsS1_PPNS_10DavixErrorE _ZN5Davix15httpcodeIsValidEi _ZN5Davix4HookINS_17HookReceiveHeaderEE7getTypeEPS2_ _ZN5Davix4HookINS_19HookRequestPostExecEE7getTypeEPS2_ _ZN5Davix4HookINS_18HookRequestPreExecEE7getTypeEPS2_ _ZN5Davix4HookINS_14HookSendHeaderEE7getTypeEPS2_ _ZlsRSoRKN5Davix3UriE davix-0.8.0/dist/abi/abi_checker_std_version.xml0000644000000000000000000000127314121063315020405 0ustar rootroot stdversion /usr/include/davix/ /usr/lib/ /usr/lib64/ _ZN5Davix19httpcodeToDavixCodeEiRKSsS1_PPNS_10DavixErrorE _ZN5Davix15httpcodeIsValidEi _ZN5Davix4HookINS_17HookReceiveHeaderEE7getTypeEPS2_ _ZN5Davix4HookINS_19HookRequestPostExecEE7getTypeEPS2_ _ZN5Davix4HookINS_18HookRequestPreExecEE7getTypeEPS2_ _ZN5Davix4HookINS_14HookSendHeaderEE7getTypeEPS2_ _ZlsRSoRKN5Davix3UriE davix-0.8.0/dist/new-release.sh0000755000000000000000000000675114121063315015046 0ustar rootroot#!/usr/bin/env bash set -e function cleanup { rm -f $release_notes rm -rf $tempbuild rm -f $merged } function confirm { read -p "$@ [y/N] " choice case "$choice" in y|Y ) ;; * ) echo "Aborting. "; exit 1 esac } function get_version_number { read -p "Give me the new version number of your release - format x.y.z: " version_number major=$(echo $version_number | cut -d "." -f 1) minor=$(echo $version_number | cut -d "." -f 2) patch=$(echo $version_number | cut -d "." -f 3) confirm "Releasing davix $major.$minor.$patch - is this OK?" } function get_author { author_name=$(git config user.name) author_email="$(echo $(git config user.email) | sed 's/@/ at /g')" confirm "Author's name and email: $author_name <$author_email> - is this OK?" } function edit_rpm_spec { echo "Patching specfile.." line1="* $(LC_ALL=POSIX date '+%a %b %d %Y') $author_name <$author_email> - $major.$minor.$patch-1" line2=" - davix $major.$minor.$patch release, see RELEASE-NOTES.md for changes" sed -i "s/%changelog/%changelog\n$line1\n$line2\n/g" packaging/davix.spec.in # now run cmake, necessary to re-generate davix.spec from davix.spec.in tempbuild=$(mktemp -d) src=$PWD pushd $tempbuild cmake $src popd } function edit_deb_changelog { echo "Patching debian package changelog.." line1="davix ($major.$minor.$patch-1) unstable; urgency=low" line2="\n * Update to version $major.$minor.$patch" line3="\n -- $author_name <$author_email> $(date -R)\n" sed -i "1i $line1\n$line2\n$line3" packaging/debian/changelog } function update_release_cmakefile { ./genversion.py --template version.cmake.in --out release.cmake --custom-version "R_${major}_${minor}_${patch}" } function git_commit { echo "Creating commit.." git add . git add --force release.cmake git commit -e -m "RELEASE: $major.$minor.$patch" } function git_tag { echo "Creating tag.." git tag -a R_${major}_${minor}_${patch} -m "Tag for version $major.$minor.$patch" } function ensure_git_root { gitroot=$(git rev-parse --show-toplevel) if [[ $PWD != $gitroot ]]; then echo "Error: This script can only be run when you're in the root git directory: $gitroot" echo "Please go there and try again." exit 1 fi } function ensure_git_clean { if [[ -n $(git status --porcelain) ]]; then echo "WARNING: git directory not clean! ALL uncommited changes (including untracked files) will be commited if you continue." confirm "Are you sure you want to continue? (NOT RECOMMENDED) " fi } function patch_release_notes { if ! grep "## Unreleased" RELEASE-NOTES.md > /dev/null; then echo "RELEASE-NOTES.md does not contain an ## Unreleased entry! Add it, populate it with the changes contained in this release, and re-run this script." exit 1 fi TODAY_DATE=$(date +%Y-%m-%d) sed -i "s/## Unreleased/## $major.$minor.$patch ($TODAY_DATE)/" RELEASE-NOTES.md } ensure_git_root ensure_git_clean trap cleanup EXIT get_version_number patch_release_notes get_author edit_rpm_spec edit_deb_changelog update_release_cmakefile git_commit git_tag printf "All done! You still need to take the following actions in this order:\n\n" printf "1. Push the newly created commit, as well as the tag: git push --follow-tags\n" printf "2. Mark this version on jira as released, create new one\n" printf "3. Push the package to EPEL\n" printf "4. After the package is available on EPEL stable, create the binary tarballs, copy to AFS\n" printf "5. Create a release announcement on http://dmc.web.cern.ch/\n" davix-0.8.0/dist/produce-artifacts.py0000755000000000000000000000654314121063315016273 0ustar rootroot#!/usr/bin/env python3 import argparse import subprocess import os import shutil import sys import re args = None def sh(command): subprocess.call(command, shell=True) def parseargs(): parser = argparse.ArgumentParser(description="Creates all necessary artifacts for a davix release.\n") parser.add_argument('--name', default='davix', help="The program name") parser.add_argument('--tag', required=True, help="The tag number for which to create a release. (example: R_0_6_3)") parser.add_argument('--tmpdir', default='/tmp/davix-tmp', help="Temporary location where to store files") parser.add_argument('--koji', default="https://kojipkgs.fedoraproject.org/packages", help="The koji build repository to use") parser.add_argument('--git', default="https://github.com/cern-fts/davix", help="The git repository to use (can even be local)") parser.add_argument('--build', type=int, default=1, help="The build number to use") parser.add_argument('--archs', type=str, nargs="+", default=["el6.x86_64", "el7.x86_64", "el8.x86_64"]) parser.add_argument('--packages', type=str, nargs="+", default=["default", "devel", "libs", "doc.noarch"]) args = parser.parse_args() if os.path.exists(args.tmpdir): parser.error("tmpdir '{}' already exists".format(args.tmpdir)) args.release = args.tag m = re.match(r"R_(\d+)_(\d+)_(\d+)", args.tag) if m.groups(): args.release = ".".join(m.groups()) return args def extract_rpms(packages, fullname): for url in packages: sh("wget {}".format(url)) os.mkdir(fullname) os.chdir(fullname) for url in packages: filename = url.split("/")[-1] sh("rpm2cpio ../{} | cpio -idmv".format(filename)) sh("""sed -i "s|prefix=/usr|prefix=/|" usr/lib64/pkgconfig/*.pc""") os.chdir("..") sh("tar -cvzf {0}.tar.gz {0} --transform 's|{0}/usr|{0}|'".format(fullname)) shutil.copy("{0}.tar.gz".format(fullname), args.release) def create_binary_releases(): for arch in args.archs: sarch = arch.split(".") base = "{0}/{1}/{2}/{3}.{4}".format(args.koji, args.name, args.release, args.build, sarch[0]) packages = [] for pkg in args.packages: if pkg == "default": pkg = "" myarch = arch.split(".")[1] if pkg.endswith(".noarch"): pkg = pkg.split(".")[0] myarch = "noarch" if pkg != "": pkg = "-" + pkg packages.append("{0}/{1}/{2}{3}-{4}-{5}.{6}.{7}.rpm".format(base, myarch, args.name, pkg, args.release, args.build, sarch[0], myarch)) extract_rpms(packages, "{name}-{version}-{arch}".format(name=args.name, version=args.release, arch=arch)) def create_source_releases(): foldername = args.git.split("/")[-1] sh("git clone {}".format(args.git)) os.chdir(foldername) sh("git checkout {}".format(args.tag)) sh("git submodule update --init") sh("./packaging/make-dist.sh") os.chdir("..") shutil.copy("davix/build/{0}-{1}.tar.gz".format(args.name, args.release), args.release) def main(): global args args = parseargs() os.mkdir(args.tmpdir) os.chdir(args.tmpdir) os.mkdir(args.release) create_binary_releases() create_source_releases() print("\n\nDone! You can find all artifacts under {0}/{1}".format(args.tmpdir, args.release)) if __name__ == '__main__': main() davix-0.8.0/dist/installDavix.sh0000755000000000000000000002501514121063315015273 0ustar rootroot#!/bin/bash # # Script to install a given version of Davix # created from the xrootd similar script # # Syntax: # ./installDavix.sh [] [-h|--help] [-d|--debug] [-o|--optimized] # [-v |--version=] # [-t |--tarball=] # [-b |--builddir=] # [--dvxopts=""] # [--vers-subdir[=]] [--no-vers-subdir] # [-j |--jobs=] # [-k|--keep] [--bzip2] # # See printhelp for a description of the options. # printhelp() { echo " " echo " Script to install a given version of Davix" echo " " echo " Syntax:" echo " ./installDavix.sh [] [-h|--help] [-d|--debug] [-o|--optimized]" echo " [-v |--version=]" echo " [-t |--tarball=]" echo " [-b |--builddir=]" echo " [--dvxopts=\"\"]" echo " [-j |--jobs=]" echo " [--vers-subdir[=]] [--no-vers-subdir]" echo " [-k|--keep] [--bzip2]" echo " " echo " where" echo " : the directory where the bin, lib, include/davix, share and" echo " man directories will appear (see also --vers-subdir)" echo " The default is ." echo " -b , --builddir=" echo " directory where to build; default /tmp/davix-" echo " -d,--debug build in debug mode (no optimization)" echo " -h, --help print this help screen" echo " -o,--optimized build in optimized mode without any debug symbol" echo " -t , --tarball=" echo " full local path to source tarball" echo " -v , --version=" echo " version in the form x.j.w[-hash-or-tag] ;" echo " current default 0.2.7-3" echo " --dvxopts=" echo " additional configuration options to davix" echo " (see davix web site)" echo " --no-vers-subdir install in instead of /davix-" echo " (or /, see --vers-subdir" echo " --vers-subdir[=]" echo " install in / instead of" echo " /davix- or . Has priority" echo " over --no-vers-subdir. Default =davix-." echo " This option is on by default." echo " -j , --jobs=" echo " number of build jobs to run simultaneously when bulding;" echo " default is + 1." echo " -k, --keep" echo " keep the build directory" echo " --bzip2" echo " use bzip2 to manage the tarball (when extension is .b2z)" echo " " echo " When relevant, the script uses 'wget' ('curl' on MacOS X) to retrieve" echo " the tarball" } cleanbuilddir() { if test ! "x$KEEP" = "xyes"; then if test ! "x$BUILDDIR" = "x" && test -d $BUILDDIR ; then rm -rf $BUILDDIR fi fi } DBGOPT="-DCMAKE_BUILD_TYPE=RelWithDebInfo" TGTDIR="." VERS="" TARBALL="" BUILDDIR="" XRDOPTS="" VSUBDIR="davix-" MAKEMJ="" KEEP="" UNZIP="gunzip" TUNZIP="xzf" # # Parse long options first other_args= short_opts= is_short="no" for i in $@ ; do opt="" case $i in --*) opt=`echo "$i" | sed 's/--//'` ;; -*) if test "x$short_opts" = "x" ; then short_opts="$i" ; else short_opts="$short_opts $i" ; fi; is_short="yes" ;; *) if test "x$is_short" = "xyes" ; then if test "x$short_opts" = "x" ; then short_opts="$i" ; else short_opts="$short_opts $i" ; fi; is_short="no" else if test "x$other_args" = "x" ; then other_args="$i"; else other_args="$other_args $i"; fi; fi; esac if test ! "x$opt" = "x" ; then case "$opt" in *=*) oarg=`echo "$opt" | sed 's/[-_a-zA-Z0-9]*=//'`;; *) oarg= ;; esac ; case $opt in builddir=*) BUILDDIR="$oarg" ;; debug) DBGOPT="-DCMAKE_BUILD_TYPE=Debug" ;; help) printhelp ; exit ;; jobs) MAKEMJ="-j$OPTARG" ;; no-vers-subdir) VSUBDIR="" ;; optimized) DBGOPT="-DCMAKE_BUILD_TYPE=Release" ;; tarball=*) TARBALL="$oarg" ;; version=*) VERS="$oarg" ;; vers-subdir) VSUBDIR="davix-" ;; vers-subdir=*) VSUBDIR="$oarg" ;; xrdopts=*) XRDOPTS="$oarg" ;; keep) KEEP="yes" ;; bzip2) UNZIP="bunzip2" ; TUNZIP="xjf" ;; esac fi done if test ! "x$short_opts" = "x" ; then while getopts b:j:t:v:dhok i $short_opts ; do case $i in b) BUILDDIR="$OPTARG" ;; d) DBGOPT="-DCMAKE_BUILD_TYPE=Debug" ;; h) printhelp ; exit ;; j) MAKEMJ="-j$OPTARG" ;; o) DBGOPT="-DCMAKE_BUILD_TYPE=Release" ;; t) TARBALL="$OPTARG" ;; v) VERS="$OPTARG" ;; k) KEEP="yes" ;; \?) printhelp; exit 1 ;; esac if test ! "x$OPTARG" = "x" ; then noa= for a in $other_args ; do if test ! "x$OPTARG" = "x$a" ; then if test "x$noa" = "x" ; then noa="$a" else noa="$noa $a" fi fi done other_args=$noa fi done fi # Fill empty fields with any non-prefixed argument if test ! "x$other_args" = "x" ; then TGTDIR="$other_args" fi XMK=make WRKDIR=$PWD if test "x$TGTDIR" = "x" ; then echo " Install dir undefined!" printhelp exit 1 else tgtd="$TGTDIR" TGTDIR=`(cd $tgtd && pwd)` if [ "$?" -ne "0" ]; then echo "Install dir $tgtd does not exist, please create it first." exit 1 fi fi if test "x$VERS" = "x" ; then VERS="0.2.10" fi echo "Version: $VERS" if test ! "x$VSUBDIR" = "x" ; then TGTDIR="$TGTDIR/$VSUBDIR$VERS" fi echo "Installing in: $TGTDIR" retrieve="yes" if test ! "x$TARBALL" = "x" && test -f $TARBALL ; then retrieve="no" TGTBALL=$TARBALL fi if test "x$retrieve" = "xyes" ; then if test "x$TARBALL" = "x" ; then TARBALL="http://grid-deployment.web.cern.ch/grid-deployment/dms/lcgutil/tar/davix/davix-$VERS.tar.gz" TGTBALL="davix-$VERS.tar.gz" else TGTBALL=`basename $TARBALL` fi fi if test "x$retrieve" = "xyes" ; then echo "Retrieving source from tarball $TARBALL" else echo "Building tarball $TARBALL" fi # Build dir if test "x$BUILDDIR" = "x"; then BUILDDIR="/tmp/davix-$VERS-$RANDOM" fi if test ! -d $BUILDDIR ; then mkdir -p $BUILDDIR if test ! -d $BUILDDIR ; then echo "Could not create build dir $BUILDDIR, exiting..." exit 1 fi else # Builddir already exists, exit echo "Build dir $BUILDDIR already exists, exiting..." exit 1 fi echo "Build dir: $BUILDDIR" cd $BUILDDIR # Retrieving source ARCH=`uname -s` if test "x$retrieve" = "xyes" ; then if test "x$ARCH" = "xDarwin" ; then curl $TARBALL -o $TGTBALL else wget $TARBALL -O $TGTBALL fi if test ! -f $TGTBALL ; then echo "Tarball retrieval failed!" cd $WRKDIR cleanbuilddir exit 1 fi fi # Untar tarball if test "x$ARCH" = "xSunOS" ; then XMK="gmake" $UNZIP -c $TGTBALL > "$TGTBALL.tar" tar xf "$TGTBALL.tar" rm -f "$TGTBALL.tar" else tar $TUNZIP $TGTBALL fi if test ! -d davix-$VERS ; then echo "Could not find source sub-directory davix-$VERS" cd $WRKDIR cleanbuilddir exit 1 fi cd davix-$VERS # CMake or old {make,configure} ? if test -f CMakeLists.txt ; then # CMake: check if there XCMK=`which cmake 2> /dev/null` echo "XCMK = '$XCMK'" if test "x$XCMK" = "x" || test ! -f $XCMK ; then echo " " echo "To build davix cmake is required: " echo "you can get it from http://cmake.org/cmake/resources/software.html" echo "or from the software manager of your system" echo " " cd $WRKDIR cleanbuilddir exit 1 fi # Check that we can build this version #if test ! -r VERSION_INFO ; then # echo "VERSION_INFO file not found: this davix version is probably too old and cannot be built by this script" # cd $WRKDIR # cleanbuilddir # exit 1 #fi # Create build directory mkdir build cd build # Configure $XCMK -DCMAKE_INSTALL_PREFIX=$TGTDIR $DBGOPT $XRDOPTS .. # Get the '-j' setting if not specified if test "x$MAKEMJ" = "x" ; then MJ=`grep -c bogomips /proc/cpuinfo 2> /dev/null` [ "$?" != 0 ] && MJ=`sysctl hw.ncpu | cut -b10 2> /dev/null` let MJ++ MAKEMJ="-j$MJ" fi # Build $XMK $MAKEMJ if [ "$?" != "0" ] ; then echo "Problems running $XMK $MAKEMJ ..." cd $WRKDIR cleanbuilddir exit "$?" fi # Install $XMK install if [ "$?" != "0" ] ; then echo "Problems running $XMK install ..." cd $WRKDIR cleanbuilddir exit "$?" fi else # Old {configure,make} # Check that we can build this version if test ! -r configure.classic ; then echo "configure.classic file not found: this davix version cannot be built by this script" cd $WRKDIR cleanbuilddir exit 1 fi # Configure options if test "x$DBGOPT" = "xRelease" ; then DBGOPT="" else DBGOPT="--build=debug" fi CFGOPT="--disable-krb4 --no-arch-subdirs --disable-mon --enable-krb5" # Configure ./configure.classic --prefix=$TGTDIR $DBGOPT $CFGOPT $XRDOPTS if [ "$?" != "0" ] ; then echo "Problems running configure.classic ..." cd $WRKDIR cleanbuilddir exit "$?" fi # Make $XMK if [ "$?" != "0" ] ; then echo "Problems running $XMK ..." cd $WRKDIR cleanbuilddir exit "$?" fi # Install $XMK install fi # Go back where we started cd $WRKDIR cleanbuilddir exit davix-0.8.0/ci/0000755000000000000000000000000014121063315011717 5ustar rootrootdavix-0.8.0/ci/debian/0000755000000000000000000000000014121063315013141 5ustar rootrootdavix-0.8.0/ci/debian/packages.sh0000755000000000000000000000040214121063315015252 0ustar rootroot#!/usr/bin/env bash set -e apt-get update apt-get install -y git g++ cmake pbuilder devscripts equivs autoconf automake mk-build-deps --install --remove "packaging/debian/control" --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" davix-0.8.0/ci/common-rpm-build.sh0000755000000000000000000000051714121063315015442 0ustar rootroot#!/usr/bin/env bash set -e git submodule update --init --recursive ./packaging/make-srpm.sh cd build if which dnf; then dnf install -y epel-release || true dnf builddep -y SRPMS/* else yum-builddep -y SRPMS/* fi rpmbuild --rebuild --with server --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" SRPMS/* davix-0.8.0/ci/fedora/0000755000000000000000000000000014121063315013157 5ustar rootrootdavix-0.8.0/ci/fedora/packages.sh0000755000000000000000000000034314121063315015274 0ustar rootroot#!/usr/bin/env bash set -e if [[ -f /usr/bin/dnf ]]; then dnf install -y dnf-plugins-core cmake cmake3 git rpm-build make which python2 else yum install -y yum-utils cmake cmake3 git rpm-build make which python2 fi davix-0.8.0/ci/replace-directory.sh0000755000000000000000000000035014121063315015671 0ustar rootroot#!/usr/bin/env bash set -e STAGING_AREA="$1" TARGET="$2" OLD_CONTENTS="${TARGET}-old" test ! -d "$TARGET" || mv "$TARGET" "$OLD_CONTENTS" sleep 30 mv "$STAGING_AREA" "$TARGET" test ! -d "$OLD_CONTENTS" || rm -rf "$OLD_CONTENTS" davix-0.8.0/cmake/0000755000000000000000000000000014121063315012404 5ustar rootrootdavix-0.8.0/cmake/modules/0000755000000000000000000000000014121063315014054 5ustar rootrootdavix-0.8.0/cmake/modules/CMakeMacroParseArguments.cmake0000644000000000000000000000206514121063315021704 0ustar rootroot MACRO(PARSE_ARGUMENTS prefix arg_names option_names) SET(DEFAULT_ARGS) FOREACH(arg_name ${arg_names}) SET(${prefix}_${arg_name}) ENDFOREACH(arg_name) FOREACH(option ${option_names}) SET(${prefix}_${option} FALSE) ENDFOREACH(option) SET(current_arg_name DEFAULT_ARGS) SET(current_arg_list) FOREACH(arg ${ARGN}) SET(larg_names ${arg_names}) LIST(FIND larg_names "${arg}" is_arg_name) IF (is_arg_name GREATER -1) SET(${prefix}_${current_arg_name} ${current_arg_list}) SET(current_arg_name ${arg}) SET(current_arg_list) ELSE (is_arg_name GREATER -1) SET(loption_names ${option_names}) LIST(FIND loption_names "${arg}" is_option) IF (is_option GREATER -1) SET(${prefix}_${arg} TRUE) ELSE (is_option GREATER -1) SET(current_arg_list ${current_arg_list} ${arg}) ENDIF (is_option GREATER -1) ENDIF (is_arg_name GREATER -1) ENDFOREACH(arg) SET(${prefix}_${current_arg_name} ${current_arg_list}) ENDMACRO(PARSE_ARGUMENTS) davix-0.8.0/cmake/modules/buildCurl.cmake0000644000000000000000000000247014121063315017006 0ustar rootrootmacro(buildCurl) include(ExternalProject) set(SECURE_TRANSPORT_FLAGS "") if(APPLE) set(SECURE_TRANSPORT_FLAGS "-DCMAKE_USE_SECTRANSP=ON -DCMAKE_USE_OPENSSL=OFF -DCURL_CA_PATH=none") endif() ExternalProject_Add(BuildCurlBundled SOURCE_DIR "${CMAKE_SOURCE_DIR}/deps/curl" BINARY_DIR "${CMAKE_BINARY_DIR}/deps/curl" PREFIX "${CMAKE_BINARY_DIR}/deps/curl" CONFIGURE_COMMAND bash -c "${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=/usr/ -DCMAKE_INSTALL_LIBDIR=lib -DHTTP_ONLY=ON -DBUILD_CURL_EXE=OFF -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_USE_LIBSSH2=OFF ${SECURE_TRANSPORT_FLAGS} ${CMAKE_SOURCE_DIR}/deps/curl && ${CMAKE_SOURCE_DIR}/patch-curl-clock-gettime.sh" BUILD_COMMAND make INSTALL_COMMAND make DESTDIR=${CMAKE_BINARY_DIR}/deps/curl-install install ) add_library(libcurl STATIC IMPORTED) set_property(TARGET libcurl PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/deps/curl-install/usr/lib/libcurl.a) add_dependencies(libcurl BuildCurlBundled) # Replace with the following when possible: # target_include_directories(libcurl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/deps/curl/include) set_property(TARGET libcurl APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/deps/curl/include) endmacro() davix-0.8.0/cmake/modules/PortabilityGNUCheck.cmake0000644000000000000000000000466314121063315020701 0ustar rootroot# # This module setup common portability variables INCLUDE (CheckIncludeFiles) include(CheckIncludeFileCXX) INCLUDE (CheckFunctionExists) INCLUDE (CheckSymbolExists) INCLUDE (CheckLibraryExists) INCLUDE (CheckTypeSize) ## C func CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H) CHECK_INCLUDE_FILES (string.h HAVE_STRING_H) CHECK_INCLUDE_FILES (strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILES (locale.h HAVE_LOCALE_H) CHECK_INCLUDE_FILES(errno.h HAVE_ERRNO_H) CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H) ## C++ header files CHECK_INCLUDE_FILE_CXX(ext/algorithm HAVE_EXT_ALGORITHM) CHECK_INCLUDE_FILE_CXX(atomic HAVE_ATOMIC "-std=c++11") ## SYSTEM CHECK_INCLUDE_FILES(sys/poll.h HAVE_SYS_POLL_H) CHECK_INCLUDE_FILES(sys/select.h HAVE_SYS_SELECT_H) CHECK_INCLUDE_FILES(sys/socket.h HAVE_SYS_SOCKET_H) CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H) CHECK_INCLUDE_FILES(sys/uio.h HAVE_SYS_UIO_H) CHECK_FUNCTION_EXISTS(setsockopt HAVE_SETSOCKOPT) ## size type CHECK_TYPE_SIZE(int DEF_SIZEOF_INT) CHECK_TYPE_SIZE(long DEF_SIZEOF_LONG) CHECK_TYPE_SIZE(size_t DEF_SIZEOF_SIZE_T) CHECK_TYPE_SIZE(ssize_t DEF_SIZEOF_SSIZE_T) CHECK_TYPE_SIZE(off_t DEF_SIZEOF_OFF_T) ## POSIX CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) CHECK_INCLUDE_FILES(signal.h HAVE_SIGNAL_H) CHECK_INCLUDE_FILES(fcntl.h HAVE_FCNTL_H) CHECK_INCLUDE_FILES(termios.h HAVE_TERMIOS_H) CHECK_FUNCTION_EXISTS(getpass HAVE_GETPASS) CHECK_FUNCTION_EXISTS(gmtime_r HAVE_GMTIME_R) CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY) ## Windows SET(CMAKE_EXTRA_INCLUDE_FILES "windows.h") CHECK_SYMBOL_EXISTS(SetConsoleMode "windows.h" HAVE_SETCONSOLEMODE) SET(CMAKE_EXTRA_INCLUDE_FILES) ## BSD ##GNU EXT #CHECK_FUNCTION_EXISTS(mempcpy HAVE_MEMPCPY_H) CHECK_FUNCTION_EXISTS(strptime HAVE_STRPTIME_H) #NET CHECK_INCLUDE_FILES(netdb.h HAVE_NETDB_H) CHECK_INCLUDE_FILES(arpa/inet.h HAVE_ARPA_INET_H) CHECK_INCLUDE_FILES(netinet/in.h HAVE_NETINET_IN_H) CHECK_INCLUDE_FILES(netinet/tcp.h HAVE_NETINET_TCP_H) SET(CMAKE_EXTRA_INCLUDE_FILES "arpa/inet.h") CHECK_TYPE_SIZE(in_addr_t DEF_SIZEOF_IN_ADDR_T) if(DEF_SIZEOF_IN_ADDR_T) set(HAVE_IN_ADDR_T 1) endif(DEF_SIZEOF_IN_ADDR_T) CHECK_TYPE_SIZE(socklen_t DEF_SIZEOF_SOCKLEN_T) if(DEF_SIZEOF_SOCKLEN_T) set(HAVE_SOCKLEN_T 1) endif(DEF_SIZEOF_SOCKLEN_T) CHECK_FUNCTION_EXISTS(getaddrinfo HAVE_GETADDRINFO_H) SET(CMAKE_EXTRA_INCLUDE_FILES) davix-0.8.0/cmake/modules/CMakeStringHelpers.cmake0000644000000000000000000000237414121063315020556 0ustar rootroot##convenience function for string manipulation function(replace_occurence output input pattern replacer) string(REGEX REPLACE ${pattern} ${replacer} tmp_str ${input}) set(${output} ${tmp_str} PARENT_SCOPE) endfunction(replace_occurence output input pattern replacer) function(replace_all_occurence) PARSE_ARGUMENTS(REPLACE_ALL "LIST_PATTERN;LIST_REPLACER" "" ${ARGN} ) LIST(APPEND list_pattern ${REPLACE_ALL_LIST_PATTERN}) LIST(APPEND list_replacer ${REPLACE_ALL_LIST_REPLACER}) LIST(LENGTH list_pattern list_size ) LIST(LENGTH list_replacer list2_size ) math(EXPR list_size ${list_size}-1) LIST(GET REPLACE_ALL_DEFAULT_ARGS 0 output_var) LIST(GET REPLACE_ALL_DEFAULT_ARGS 1 intput_content ) SET(tmp_str ${intput_content}) SET(tmp_str2 "") foreach(i RANGE ${list_size}) list(GET list_pattern ${i} current_pattern ) list(GET list_replacer ${i} current_replacer ) replace_occurence(tmp_str2 ${tmp_str} ${current_pattern} ${current_replacer} ) SET(tmp_str ${tmp_str2}) endforeach(i RANGE ${list_size}) SET(${output_var} ${tmp_str} PARENT_SCOPE) endfunction(replace_all_occurence) function(STRING_APPEND var_name content) SET(${var_name} "${${var_name}}${content}" PARENT_SCOPE) endfunction(STRING_APPEND var_name content) davix-0.8.0/cmake/modules/FindgSOAP.cmake0000644000000000000000000000650414121063315016575 0ustar rootroot# # This module detects if gsoap is installed and determines where the # include files and libraries are. # # This code sets the following variables: # # GSOAP_LIBRARIES = full path to the gsoap libraries # GSOAP_SSL_LIBRARIES = full path to the gsoap ssl libraries # GSOAP_INCLUDE_DIR = include dir to be used when using the gsoap library # GSOAP_WSDL2H = wsdl2h binary # GSOAP_SOAPCPP2 = soapcpp2 binary # GSOAP_FOUND = set to true if gsoap was found successfully # # GSOAP_LOCATION # setting this enables search for gsoap libraries / headers in this location # ----------------------------------------------------- # GSOAP Libraries # ----------------------------------------------------- find_library(GSOAP_LIBRARIES NAMES gsoap HINTS ${GSOAP_LOCATION}/lib ${GSOAP_LOCATION}/lib64 ${GSOAP_LOCATION}/lib32 DOC "The main gsoap library" ) find_library(GSOAP_SSL_LIBRARIES NAMES gsoapssl HINTS ${GSOAP_LOCATION}/lib ${GSOAP_LOCATION}/lib64 ${GSOAP_LOCATION}/lib32 DOC "The ssl gsoap library" ) # ----------------------------------------------------- # GSOAP Include Directories # ----------------------------------------------------- find_path(GSOAP_INCLUDE_DIR NAMES stdsoap2.h HINTS ${GSOAP_LOCATION} ${GSOAP_LOCATION}/include ${GSOAP_LOCATION}/include/* DOC "The gsoap include directory" ) # ----------------------------------------------------- # GSOAP Binaries # ----------------------------------------------------- find_program(GSOAP_WSDL2H NAMES wsdl2h HINTS ${GSOAP_LOCATION}/bin DOC "The gsoap bin directory" ) find_program(GSOAP_SOAPCPP2 NAMES soapcpp2 HINTS ${GSOAP_LOCATION}/bin DOC "The gsoap bin directory" ) # ----------------------------------------------------- # GSOAP_276_COMPAT_FLAGS and GSOAPVERSION # try to determine the flagfor the 2.7.6 compatiblity, break with 2.7.13 and re-break with 2.7.16 # ---------------------------------------------------- message(STATUS " - wsdlh : ${GSOAP_WSDL2H}") message(STATUS " - SOAPCPP2 : ${GSOAP_SOAPCPP2}") execute_process(COMMAND ${GSOAP_SOAPCPP2} "-help" OUTPUT_VARIABLE GSOAP_STRING_VERSION ERROR_VARIABLE GSOAP_STRING_VERSION ) string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" GSOAP_VERSION ${GSOAP_STRING_VERSION}) if( "${GSOAP_VERSION}" STREQUAL "..") execute_process(COMMAND ${GSOAP_SOAPCPP2} "-v" TIMEOUT 1 OUTPUT_VARIABLE GSOAP_STRING_VERSION ERROR_VARIABLE GSOAP_STRING_VERSION ) string(REGEX MATCH "[0-9]*\\.[0-9]*\\.[0-9]*" GSOAP_VERSION ${GSOAP_STRING_VERSION}) endif() message(STATUS " - GSOAP VERSION : ${GSOAP_VERSION}") if( "${GSOAP_VERSION}" VERSION_LESS "2.7.6") set(GSOAP_276_COMPAT_FLAGS "") elseif ( "${GSOAP_VERSION}" VERSION_LESS "2.7.14") set(GSOAP_276_COMPAT_FLAGS "-z") else ( "${GSOAP_VERSION}" VERSION_LESS "2.7.14") set(GSOAP_276_COMPAT_FLAGS "-z1 -z2") endif ( "${GSOAP_VERSION}" VERSION_LESS "2.7.6") # ----------------------------------------------------- # handle the QUIETLY and REQUIRED arguments and set GSOAP_FOUND to TRUE if # all listed variables are TRUE # ----------------------------------------------------- include(FindPackageHandleStandardArgs) find_package_handle_standard_args(gsoap DEFAULT_MSG GSOAP_LIBRARIES GSOAP_INCLUDE_DIR GSOAP_WSDL2H GSOAP_SOAPCPP2) mark_as_advanced(GSOAP_INCLUDE_DIR GSOAP_LIBRARIES GSOAP_WSDL2H GSOAP_SOAPCPP2) davix-0.8.0/cmake/modules/FindROOT.cmake0000644000000000000000000001471614121063315016453 0ustar rootroot# - Finds ROOT instalation # This module sets up ROOT information # It defines: # ROOT_FOUND If the ROOT is found # ROOT_INCLUDE_DIR PATH to the include directory # ROOT_INCLUDE_DIRS PATH to the include directories (not cached) # ROOT_LIBRARIES Most common libraries # ROOT__LIBRARY Full path to the library # ROOT_LIBRARY_DIR PATH to the library directory # # Updated by K. Smith (ksmith37@nd.edu) to properly handle # dependencies in ROOT_GENERATE_DICTIONARY find_program(ROOT_CONFIG_EXECUTABLE root-config PATHS $ENV{ROOTSYS}/bin) execute_process( COMMAND ${ROOT_CONFIG_EXECUTABLE} --prefix OUTPUT_VARIABLE ROOTSYS OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( COMMAND ${ROOT_CONFIG_EXECUTABLE} --version OUTPUT_VARIABLE ROOT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( COMMAND ${ROOT_CONFIG_EXECUTABLE} --incdir OUTPUT_VARIABLE ROOT_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) set(ROOT_INCLUDE_DIRS ${ROOT_INCLUDE_DIR}) execute_process( COMMAND ${ROOT_CONFIG_EXECUTABLE} --libdir OUTPUT_VARIABLE ROOT_LIBRARY_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) set(ROOT_LIBRARY_DIRS ${ROOT_LIBRARY_DIR}) set(rootlibs Core Cint RIO Net Hist Graf Graf3d Gpad Tree Rint Postscript Matrix Physics MathCore Thread) set(ROOT_LIBRARIES) foreach(_cpt ${rootlibs} ${ROOT_FIND_COMPONENTS}) find_library(ROOT_${_cpt}_LIBRARY ${_cpt} HINTS ${ROOT_LIBRARY_DIR}) if(ROOT_${_cpt}_LIBRARY) mark_as_advanced(ROOT_${_cpt}_LIBRARY) list(APPEND ROOT_LIBRARIES ${ROOT_${_cpt}_LIBRARY}) list(REMOVE_ITEM ROOT_FIND_COMPONENTS ${_cpt}) endif() endforeach() list(REMOVE_DUPLICATES ROOT_LIBRARIES) execute_process( COMMAND ${ROOT_CONFIG_EXECUTABLE} --features OUTPUT_VARIABLE _root_options OUTPUT_STRIP_TRAILING_WHITESPACE) foreach(_opt ${_root_options}) set(ROOT_${_opt}_FOUND TRUE) endforeach() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ROOT DEFAULT_MSG ROOT_CONFIG_EXECUTABLE ROOTSYS ROOT_VERSION ROOT_INCLUDE_DIR ROOT_LIBRARIES ROOT_LIBRARY_DIR) mark_as_advanced(ROOT_CONFIG_EXECUTABLE) include(CMakeParseArguments) find_program(ROOTCINT_EXECUTABLE rootcint PATHS $ENV{ROOTSYS}/bin) find_program(GENREFLEX_EXECUTABLE genreflex PATHS $ENV{ROOTSYS}/bin) find_package(GCCXML) #---------------------------------------------------------------------------- # function ROOT_GENERATE_DICTIONARY( dictionary # header1 header2 ... # LINKDEF linkdef1 ... # OPTIONS opt1...) function(ROOT_GENERATE_DICTIONARY dictionary) CMAKE_PARSE_ARGUMENTS(ARG "" "" "LINKDEF;OPTIONS" "" ${ARGN}) #---Get the list of include directories------------------ get_directory_property(incdirs INCLUDE_DIRECTORIES) set(includedirs) foreach( d ${incdirs}) set(includedirs ${includedirs} -I${d}) endforeach() #---Get the list of header files------------------------- set(headerfiles) foreach(fp ${ARG_UNPARSED_ARGUMENTS}) if(${fp} MATCHES "[*?]") # Is this header a globbing expression? file(GLOB files ${fp}) foreach(f ${files}) if(NOT f MATCHES LinkDef) # skip LinkDefs from globbing result set(headerfiles ${headerfiles} ${f}) endif() endforeach() else() find_file(headerFile ${fp} PATHS ${incdirs}) set(headerfiles ${headerfiles} ${headerFile}) unset(headerFile CACHE) endif() endforeach() #---Get LinkDef.h file------------------------------------ set(linkdefs) foreach( f ${ARG_LINKDEF}) find_file(linkFile ${f} PATHS ${incdirs}) set(linkdefs ${linkdefs} ${linkFile}) unset(linkFile CACHE) endforeach() #---call rootcint------------------------------------------ add_custom_command(OUTPUT ${dictionary}.cxx ${dictionary}.h COMMAND ${ROOTCINT_EXECUTABLE} -cint -f ${dictionary}.cxx -c ${ARG_OPTIONS} ${includedirs} ${headerfiles} ${linkdefs} DEPENDS ${headerfiles} ${linkdefs} VERBATIM) endfunction() #---------------------------------------------------------------------------- # function REFLEX_GENERATE_DICTIONARY(dictionary # header1 header2 ... # SELECTION selectionfile ... # OPTIONS opt1...) function(REFLEX_GENERATE_DICTIONARY dictionary) CMAKE_PARSE_ARGUMENTS(ARG "" "" "SELECTION;OPTIONS" "" ${ARGN}) #---Get the list of header files------------------------- set(headerfiles) foreach(fp ${ARG_UNPARSED_ARGUMENTS}) file(GLOB files ${fp}) if(files) foreach(f ${files}) set(headerfiles ${headerfiles} ${f}) endforeach() else() set(headerfiles ${headerfiles} ${fp}) endif() endforeach() #---Get Selection file------------------------------------ if(IS_ABSOLUTE ${ARG_SELECTION}) set(selectionfile ${ARG_SELECTION}) else() set(selectionfile ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_SELECTION}) endif() #---Get the list of include directories------------------ get_directory_property(incdirs INCLUDE_DIRECTORIES) set(includedirs) foreach( d ${incdirs}) set(includedirs ${includedirs} -I${d}) endforeach() #---Get preprocessor definitions-------------------------- get_directory_property(defs COMPILE_DEFINITIONS) foreach( d ${defs}) set(definitions ${definitions} -D${d}) endforeach() #---Nanes and others--------------------------------------- set(gensrcdict ${dictionary}.cpp) if(MSVC) set(gccxmlopts "--gccxmlopt=\"--gccxml-compiler cl\"") else() #set(gccxmlopts "--gccxmlopt=\'--gccxml-cxxflags -m64 \'") set(gccxmlopts) endif() #set(rootmapname ${dictionary}Dict.rootmap) #set(rootmapopts --rootmap=${rootmapname} --rootmap-lib=${libprefix}${dictionary}Dict) #---Check GCCXML and get path----------------------------- if(GCCXML) get_filename_component(gccxmlpath ${GCCXML} PATH) else() message(WARNING "GCCXML not found. Install and setup your environment to find 'gccxml' executable") endif() #---Actual command---------------------------------------- add_custom_command(OUTPUT ${gensrcdict} ${rootmapname} COMMAND ${GENREFLEX_EXECUTABLE} ${headerfiles} -o ${gensrcdict} ${gccxmlopts} ${rootmapopts} --select=${selectionfile} --gccxmlpath=${gccxmlpath} ${ARG_OPTIONS} ${includedirs} ${definitions} DEPENDS ${headerfiles} ${selectionfile}) endfunction() davix-0.8.0/cmake/modules/DefineInstallationPaths.cmake0000644000000000000000000001171314121063315021635 0ustar rootrootif (UNIX) IF (NOT APPLICATION_NAME) MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME") SET(APPLICATION_NAME ${PROJECT_NAME}) ENDIF (NOT APPLICATION_NAME) # detect lib suffix IF(EXISTS "/usr/lib64") SET(LIB_SUFFIX "64" CACHE STRING "Suffix of the lib") SET (PKG_ARCH "x86_64") ELSE(EXISTS "/usr/lib64" ) SET(LIB_SUFFIX "" CACHE STRING "Suffix of the lib") SET (PKG_ARCH "i386") ENDIF(EXISTS "/usr/lib64" ) # correct cmake netpath issue with cmake 2.8 IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/") SET(INTERNAL_BASE_PREFIX "") ELSE("${CMAKE_INSTALL_PREFIX}" STREQUAL "/") SET(INTERNAL_BASE_PREFIX "${CMAKE_INSTALL_PREFIX}") ENDIF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/") SET(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" ) SET(SHARE_INSTALL_PREFIX "${INTERNAL_BASE_PREFIX}/share" CACHE PATH "Base directory for files which go to share/" ) SET(DATA_INSTALL_PREFIX "${INTERNAL_BASE_PREFIX}/${APPLICATION_NAME}" CACHE PATH "The parent directory where applications can install their data") # The following are directories where stuff will be installed to SET(BIN_INSTALL_DIR "${INTERNAL_BASE_PREFIX}/bin" CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)" ) SET(SBIN_INSTALL_DIR "${INTERNAL_BASE_PREFIX}/sbin" CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)" ) SET(LIB_INSTALL_DIR "${INTERNAL_BASE_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)" ) SET(LIBEXEC_INSTALL_DIR "${INTERNAL_BASE_PREFIX}/libexec" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)" ) SET(PKGCONFIG_FILES_DIR "${LIB_INSTALL_DIR}/pkgconfig/" CACHE PATH "subdirectory relative to the install prefix where pkgconfig files (.pc) will be installed" ) SET(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/${APPLICATION_NAME}" CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})" ) SET(INCLUDE_INSTALL_DIR "${INTERNAL_BASE_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix (default prefix/include)" ) SET(DATA_INSTALL_DIR "${DATA_INSTALL_PREFIX}" CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})" ) SET(DOC_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/doc/${APPLICATION_NAME}" CACHE PATH "The parent directory where applications can install their documentation (default prefix/share/doc/${APPLICATION_NAME})" ) SET(HTML_INSTALL_DIR "${DATA_INSTALL_PREFIX}/doc/HTML" CACHE PATH "The HTML install dir for documentation (default data/doc/html)" ) SET(ICON_INSTALL_DIR "${DATA_INSTALL_PREFIX}/icons" CACHE PATH "The icon install dir (default data/icons/)" ) SET(SOUND_INSTALL_DIR "${DATA_INSTALL_PREFIX}/sounds" CACHE PATH "The install dir for sound files (default data/sounds)" ) SET(LOCALE_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/locale" CACHE PATH "The install dir for translations (default prefix/share/locale)" ) SET(XDG_APPS_DIR "${SHARE_INSTALL_PREFIX}/applications/" CACHE PATH "The XDG apps dir" ) SET(XDG_DIRECTORY_DIR "${SHARE_INSTALL_PREFIX}/desktop-directories" CACHE PATH "The XDG directory" ) SET(SYSCONF_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/etc" CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)" ) SET(MAN_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/man" CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)" ) SET(INFO_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/info" CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)" ) endif (UNIX) if (WIN32) # Same same SET(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" ) set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "-") set(SBIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "-") set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "-") set(INCLUDE_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/include" CACHE PATH "-") SET(SYSCONF_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/etc" CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)" ) SET(PKGCONFIG_FILES_DIR "${EXEC_INSTALL_PREFIX}/lib/pkgconfig/" CACHE PATH "subdirectory relative to the install prefix where pkgconfig files (.pc) will be installed" ) set(PLUGIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin/plugins" CACHE PATH "-") set(HTML_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/doc/HTML" CACHE PATH "-") set(ICON_INSTALL_DIR "." CACHE PATH "-") set(SOUND_INSTALL_DIR "." CACHE PATH "-") set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-") endif (WIN32) davix-0.8.0/cmake/modules/MacroAddDoxygen.cmake0000644000000000000000000000106514121063315020070 0ustar rootroot## ## Doxygen macro, allow Doxygen generation from cmake ## do a ""make doc" for the generation macro(addDoxyGeneration DOXYFILE_LOCATION) find_package(Doxygen) if(DOXYGEN_FOUND) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${DOXYFILE_LOCATION} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) endif(DOXYGEN_FOUND) endmacro(addDoxyGeneration DOXYFILE_LOCATION) davix-0.8.0/cmake/modules/ReleaseDebugAutoFlags.cmake0000644000000000000000000000143114121063315021212 0ustar rootroot## debug / release autoManagement if(MSVC) set(CMAKE_C_FLAGS_RELEASE "-O2") set(CMAKE_C_FLAGS_DEBUG "-Wall") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -Wall") set(CMAKE_CXX_FLAGS_RELEASE "-O2") set(CMAKE_CXX_FLAGS_DEBUG "-Wall") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -Wall") else() set(CMAKE_C_FLAGS_RELEASE "-O2 -Wno-unused-parameter") set(CMAKE_C_FLAGS_DEBUG "-g -Wall -Wextra -pedantic -fstack-protector-all -Wno-unused-parameter") set(CMAKE_C_FLAGS_RELWITHDEBINFO " -Wall -g -O2") set(CMAKE_CXX_FLAGS_RELEASE "-Wall -Wextra -Wno-unused-parameter -O2") set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra -Wno-unused-parameter -fstack-protector-all") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO " -Wall -Wextra -Wno-unused-parameter -g -O2") endif()davix-0.8.0/cmake/modules/Finduuid.cmake0000644000000000000000000000277014121063315016633 0ustar rootroot#.rst: # Finduuid # ----------- # # Find libuuid, DCE compatible Universally Unique Identifier library. # # Result Variables # ^^^^^^^^^^^^^^^^ # # This module will set the following variables in your project: # # ``UUID_FOUND`` # True if libuuid has been found. # ``UUID_INCLUDE_DIRS`` # Where to find uuid/uuid.h. # ``UUID_LIBRARIES`` # The libraries to link against to use libuuid. # # Obsolete variables # ^^^^^^^^^^^^^^^^^^ # # The following variables may also be set, for backwards compatibility: # # ``UUID_LIBRARY`` # where to find the libuuid library (same as UUID_LIBRARIES). # ``UUID_INCLUDE_DIR`` # where to find the uuid/uuid.h header (same as UUID_INCLUDE_DIRS). include(CheckCXXSymbolExists) include(CheckLibraryExists) include(FindPackageHandleStandardArgs) if(NOT UUID_INCLUDE_DIR) find_path(UUID_INCLUDE_DIR uuid/uuid.h) endif() if(EXISTS "${UUID_INCLUDE_DIR}") set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR}) set(CMAKE_REQUIRED_INCLUDES ${UUID_INCLUDE_DIRS}) check_cxx_symbol_exists("uuid_generate_random" "uuid/uuid.h" _uuid_header_only) endif() if(NOT _uuid_header_only AND NOT UUID_LIBRARY) check_library_exists("uuid" "uuid_generate_random" "" _have_libuuid) if(_have_libuuid) set(UUID_LIBRARY "uuid") endif() endif() if(UUID_LIBRARY) set(UUID_LIBRARIES ${UUID_LIBRARY}) endif() unset(CMAKE_REQUIRED_INCLUDES) unset(_uuid_header_only) unset(_have_libuuid) find_package_handle_standard_args(uuid DEFAULT_MSG UUID_INCLUDE_DIR) mark_as_advanced(UUID_INCLUDE_DIR UUID_LIBRARY) davix-0.8.0/cmake/modules/CMakeGeneratePkgConfig.cmake0000644000000000000000000000763014121063315021307 0ustar rootroot# @title cmake macro for pkgconfig files generation # @brief generate a .pc package config file with a given name # @author Adrien Devresse include(DefineInstallationPaths REQUIRED) include(CMakeMacroParseArguments REQUIRED) include(CMakeStringHelpers REQUIRED) SET(CMAKE_PKGCONFIG_TEMPLATE "prefix=@PREFIX@ exec_prefix=@PREFIX@ libdir=@LIBDIR_VAR includedir=@INCLUDE_VAR@ Name: @NAME_PROJECT@ Description: @DESCRIPTION_PROJECT@ Version: @VERSION_PROJECT@ URL: @URL_PROJECT@ Requires: @REQUIRES_PROJECT@ Conflicts: @CONFLICTS_PROJECT@ Libs: @LIBS_PROJECT@ Libs.private: @LIBS_PRIVATE_PROJECT@ Cflags: @CFLAGS_PROJECT@ ") SET(CMAKE_PKGCONFIG_TEMPLATE_BASE " prefix=@PREFIX@ exec_prefix= \\\${prefix} libdir= @LIBDIR_VAR@ includedir=@INCLUDE_VAR@ Name: @NAME_PROJECT@ Description: @DESCRIPTION_PROJECT@ Version: @VERSION_PROJECT@ Requires: @REQUIRES_PROJECT@ Libs: @LIBS_PROJECT@ Cflags: @CFLAGS_PROJECT@ " ) LIST(APPEND CMAKE_PKGCONFIG_TEMPLATE_BASE_PATTERN "@PREFIX@" "@LIBDIR_VAR@" "@INCLUDE_VAR@" "@NAME_PROJECT@" "@DESCRIPTION_PROJECT@" "@VERSION_PROJECT@" "@REQUIRES_PROJECT@" "@LIBS_PROJECT@" "@CFLAGS_PROJECT@") # main function to use # FORMAT : add_PkgConfigFile_for_Library("string_filename.pc" target_library # [DESCRIPTION] "description of the pkgconfig files" # [HEADER_DIRS] dir1, dir2 # [REQUIRES] req1 req 2 ) # list of dir to include in $prefix/include/, ex : $prefix/include/dir1 # the pc file is produced in the ${CMAKE_CURRENT_BINARY_DIR} directory function(add_PkgConfigFile_for_Library) PARSE_ARGUMENTS(PKGCONFIGFILE "HEADER_DIRS;DESCRIPTION;REQUIRES;CFLAGS" "" ${ARGN} ) LIST(GET PKGCONFIGFILE_DEFAULT_ARGS 0 pkgconfig_filename) LIST(GET PKGCONFIGFILE_DEFAULT_ARGS 1 lib_target) LIST(GET PKGCONFIGFILE_DESCRIPTION 0 description) get_target_property(library_name ${lib_target} OUTPUT_NAME) get_target_property(library_version ${lib_target} VERSION) set(pkgconfig_prefix "${CMAKE_INSTALL_PREFIX}") set(pkgconfig_libdir_var "\\\${prefix}/lib${LIB_SUFFIX}") set(pkgconfig_include_var "\\\${prefix}/include") set(pkgconfig_linkflags "-l${library_name} -L\\\${libdir}") set(pkgconfig_name "${pkgconfig_filename}") set(pkgconfig_version "${library_version}") set(pkgconfig_description "pkgconfig file for ${library_name}") set(pkgconfig_requires " ") set(pkgconfig_cflags "") IF(PKGCONFIGFILE_REQUIRES) FOREACH(req ${PKGCONFIGFILE_REQUIRES}) set(pkgconfig_requires "${pkgconfig_requires} ${req}") ENDFOREACH(req PKGCONFIGFILE_REQUIRES) ENDIF(PKGCONFIGFILE_REQUIRES) IF(PKGCONFIGFILE_CFLAGS) FOREACH(req ${PKGCONFIGFILE_CFLAGS}) set(pkgconfig_cflags "${pkgconfig_cflags} ${req}") ENDFOREACH(req PKGCONFIGFILE_CFLAGS) ENDIF(PKGCONFIGFILE_CFLAGS) IF(PKGCONFIGFILE_HEADER_DIRS) FOREACH(dir ${PKGCONFIGFILE_HEADER_DIRS}) set(pkgconfig_includedir "${pkgconfig_includedir} -I\\\${includedir}/${dir}") ENDFOREACH(dir PKGCONFIGFILE_HEADER_DIRS) ELSE(PKGCONFIGFILE_HEADER_DIRS) set(pkgconfig_includedir " -I\\\${includedir}") ENDIF(PKGCONFIGFILE_HEADER_DIRS) IF(description) set(pkgconfig_description "${description}") ENDIF(description) set(pkgconfig_cflags "${pkgconfig_cflags} ${pkgconfig_includedir} ") LIST(APPEND pkgconfig_list_var ${pkgconfig_prefix} ${pkgconfig_libdir_var} ${pkgconfig_include_var} ${pkgconfig_name} ${pkgconfig_description} ${pkgconfig_version} ${pkgconfig_requires} ${pkgconfig_linkflags} ${pkgconfig_cflags}) replace_all_occurence(pc_file_content ${CMAKE_PKGCONFIG_TEMPLATE_BASE} LIST_PATTERN ${CMAKE_PKGCONFIG_TEMPLATE_BASE_PATTERN} LIST_REPLACER ${pkgconfig_list_var}) SET(filename "${CMAKE_CURRENT_BINARY_DIR}/${pkgconfig_filename}") FILE(WRITE ${filename} "${pc_file_content}" ) message(STATUS "generate pkgconfig file for ${lib_target} under ${filename}") endfunction(add_PkgConfigFile_for_Library) davix-0.8.0/cmake/modules/CMakeCXX11Support.cmake0000644000000000000000000000217014121063315020160 0ustar rootrootinclude(CheckCXXSourceCompiles REQUIRED) if(CMAKE_COMPILER_IS_GNUCXX) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7) SET(HAVE_CXX011_FULL_SUPPORT TRUE) SET(HAVE_CXX011_PARTIAL_SUPPORT TRUE) SET(CXX11_FLAG_ENABLE "-std=c++11") elseif(GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3) message(STATUS "C++11 partial support") SET(HAVE_CXX011_PARTIAL_SUPPORT TRUE) SET(CXX11_FLAG_ENABLE "-std=c++0x") else () message(STATUS "C++11 no support ") SET(CXX11_FLAG_ENABLE "") endif() else(CMAKE_COMPILER_IS_GNUCXX) message(STATUS "C++11 activated full") SET(HAVE_CXX011_FULL_SUPPORT TRUE) SET(HAVE_CXX011_PARTIAL_SUPPORT TRUE) SET(CXX11_FLAG_ENABLE "-std=c++0x") endif(CMAKE_COMPILER_IS_GNUCXX) ## Check TR1 CHECK_CXX_SOURCE_COMPILES(" #include int main() { return 0; }" HAVE_TR1_SUPPORT) if(HAVE_TR1_SUPPORT) message(STATUS "TR1 support detected") else(HAVE_TR1_SUPPORT) message(STATUS "no TR1 support") endif(HAVE_TR1_SUPPORT) davix-0.8.0/RELEASE-NOTES.md0000644000000000000000000005123414121063315013621 0ustar rootroot# davix release history ## 0.8.0 (2021-09-17) ### Epic * [DMC-1267] - Davix with libcurl backend * Huge refactoring to accommodate both libneon and libcurl backends, as well as improved testing Many thanks to Georgios Bitzes for the great work. ### Bug fixes * [DMC-1209] - Davix Redirection Cache causes Segfault when encountering relative path * [DMC-1243] - Davix hangs if url starts with 'https' is used with S3/Swift credentials in command * [davix/pull/70] - Fix return value of HttpIO::readFull (Thanks to Max Orok) * [davix/pull/66] - Initialize session factory members (Thanks to Petr Vokac) * [davix/pull/54] - Really add '\0' after printed X.509 data (Thanks to Petr Vokac) ### New Features * [DMC-1221] - Introduce a filter to avoid exposing sensitive information (such as bearer tokens) in Davix debug output * [DMC-1238] - Add SWIFT support in Davix * [DMC-1268] - Add CS3API support in Davix Many thanks to Shiting Long for the Swift support. Many thanks to Rahul Chauhan for the CS3API support. ### Tasks * [DMC-1250] - Packages for Centos8 * [DMC-1264] - Packages for Fedora >= 33 ### Improvements * [DMC-1245] - Add leading 0 to Adler32 checksum format in Davix ## 0.7.6 (2020-04-29) ### Bug fixes * Ensure multi-range simulation thread exceptions are propagated * Fix memory leak in S3 detect region function * Recognize OpenSSL 'bad decrypt' error message as CredDecryptionError * Fix error handling for proxy delegation ### Improvements * Add protection in case server sends an unreasonable number of stripes during TPC * Refactoring and improvements to davix-tester Many thanks to Petr Vokac for fixing error handling during proxy delegation. ## 0.7.5 (2019-08-28) ### Bug fixes * Enable use of dav:// and davs:// in third party copies. * Fix third party copies when the server presents multiple certificate delegation endpoints. (Thanks to Thomas Hartmann for reporting) * Prevent davix from infinite-looping when the server abruptly terminates the connection during TPC. (Thanks to Frank Berghaus for reporting) ### Improvements * Add ability to cancel ongoing TPC transfers through user-supplied callback. * Continued refactoring to eventually allow the use of libcurl as HTTP backend in davix. * In-source builds are no longer supported, and explicitly prevented by CMake. ## 0.7.4 (2019-07-04) ### Bug fixes * Correctly handle URL-encoded paths in PROPFIND responses (Thanks to Matthew Skinner for reporting) * Prevent genversion.py from getting confused with non-davix git repositories (Thanks to Chris Burr) ### Improvements * Fix cryptic cmake errors encountered sometimes when building from a tarball. ## 0.7.3 (2019-05-08) ### Bug fixes * Use poll instead of select during async SSL connect - fixes a crash in certain cases of overload. (Thanks to Petr Vokac) ### Improvements * Addition of davix docker image (Thanks to Emmanuel Frecon) * Minor improvements to some error messages ## 0.7.2 (2019-02-15) ### Bug fixes * produce-artifacts script was producing wonky release artifacts * [DMC-1127] - davix should not segfault when calling DavPosix::close twice * [DMC-1135] - davix misuses data provider function in S3 multi-part upload * [DMC-1138] - Error from performance markers sometimes is not correctly reported by Davix * [DMC-1140] - Fix parsing of the Digest to be complaint to RFC 3230 ### Improvements * Some refactoring and splitting of redirection caching logic into its own separate class. ## 0.7.1 (2018-10-24) ### Bug fixes * [DMC-1114] - DAVIX adds cert chain multiple times * Fixes to cmake related to linking of libuuid ## 0.7.0 (2018-10-22) ### Bug fixes * [DMC-1089] - Implement S3 heuristic in davix to avoid STAT on pre-signed URLs * [DMC-1090] - Add support for multi-part S3 uploads in davix * [DMC-1094] - davix-put consumes too much memory during S3 and Azure multi-part uploads * [DMC-1096] - Error when parsing iso8601 dates on FreeBSD * [DMC-1097] - Davix AWS signature v2 and URL query * [DMC-1101] - NEONRequest::readSegment always stops at line boundaries ### Improvements * Improvements to release script and release procedure * [DMC-1065] - Davix should read (and log) the response body even if it's an error * [DMC-1098] - Implement the workflow for multipart S3 uploads through presigned URLs (dynafed) ## 0.6.9 (2018-09-25) ### Bug fixes * [DMC-1063] - Incorrect handling of "Digest" header in response * [DMC-1071] - Davix bug for push-mode third party COPY ### Improvements * [DMC-1079] - force http/s as protocol scheme for COPY verb ## 0.6.8 ### Bug fixes * [DMC-1005] - davix buffers TPC performance markers in a weird way * [DMC-1047] - Gridsite Delegation to dCache is broken ( starting from v 3.0) ### Improvements * [DMC-1042] - Add gcloud support to davix * [DMC-1013] - Add support for 3rd party copy transfers to S3 gCloud ## 0.6.7 ### Bug fixes * [DMC-950] - davix calculates invalid v4 s3 signature when using a non-default port * [DMC-957] - davix appends an extra space with --header * [DMC-961] - A neon session never retries after DNS lookup failure * [DMC-969] - davix increments the refcount for OpenSSL structures in a non-atomic way * [DMC-993] - Use-after-free in the davix cache ### Improvements * [DMC-958] - Resume on xfer with metalinks creates file with a wrong filesize ## 0.6.6 ### Bug fixes * [DMC-937] - davix unable to upload files to Azure larger than a certain size * [DMC-939] - Use SHA512 for 3rd party copy delegated proxy * [DMC-944] - Remove the buggy davix fork-handler ### Improvements * [DMC-938] - Remove boost from davix ## 0.6.5 ### Bug fixes * [DMC-877] - Davix seems to ignore the port number in a S3 URL * [DMC-889] - davix should clear any old cached sessions after a fork * [DMC-903] - davix does not always respect the option to disable transparent redirects * [DMC-904] - davix does not properly escape URLs in recursive / parallel operations * [DMC-912] - Davix seems not to honour the timeouts ### Improvements * [DMC-867] - Honour 202-accepted and retry a request * [DMC-876] - Setting log level and log scope should be thread-safe * [DMC-887] - Switch over to using header parameters for the S3 signature * [DMC-888] - Add support for openssl-1.1.0 ## 0.6.4 ### Bug fixes * [DMC-824] - Impossible to upload directory if authentication method requires entering credentials manually * [DMC-835] - Segfault in libneon when downloading large file with a bad network connection ### New features * [DMC-871] - Add option to suppress 100-Continue when uploading files * [DMC-874] - Need to report quota free space as well * [DMC-816] - davix: Support for .netrc and .davixrc to store user credentials * [DMC-850] - davix does not report used space in directories * [DMC-854] - Expose davix version through its public headers ### Improvements * [DMC-826] - Fix the clock_gettime / -lrt mess * [DMC-828] - davix: Improve error message when receiving 507 Insufficient Storage ## 0.6.3 ### Bug fixes * [DMC-823] - The davix ROOT plugin does not build because of librt ## 0.6.2 ### Bug fixes * [DMC-821] - Code for multi-range requests allocates potentially huge buffer on the stack ## 0.6.1 ### Bug fixes * [DMC-815] - davix: Stray "\n" at the beginning of output when manually specifying a proxy * [DMC-817] - gfal-copy output when copying to davs is quite odd ### Improvements * [DMC-819] - davix: Script for 1-step release ## 0.6.0 ### Bug fixes * [DMC-194] - Davix has performance issues in case of fast small little chunk of data * [DMC-207] - DAVIX : add option in order to report result of failing request * [DMC-654] - Depending if the bucket is in the URL or not, the result is different * [DMC-729] - Custom --header option in davix-get is sent twice on a redirect * [DMC-732] - Davix: 120-second timeout with a large TCP buffer and a slow connection * [DMC-735] - Davix trunk claims to be version 0.5.1, RPM says 0.5.0 * [DMC-736] - Davix parallel compilation has race condition * [DMC-748] - Wrong filesize displayed when recursively listing directories * [DMC-749] - davix-cp segfaults * [DMC-752] - Cached redirects should expire after a DELETE * [DMC-761] - Object-based interface returns an extra entry with empty filename in S3 * [DMC-762] - Race condition in libneon sometimes triggers erroneous timeout during SSL handshake * [DMC-766] - Statting an S3 directory with a trailing slash returns wrong mode * [DMC-770] - Fragment identifier not copied over when copying a Davix::Uri object * [DMC-772] - TLS session persistence not working with Amazon S3 servers * [DMC-773] - Davix crashes with an error when doing a vectored read on CEPH * [DMC-778] - Davix static library crash on CentOS7 * [DMC-784] - Davix does not respect number of retries set by the user in case of 401 / 403 * [DMC-786] - Davix does not set DavixError nor throw an exception for uncommon server errors * [DMC-789] - davix-mv does not filter out dav(s) protocol * [DMC-799] - davix build on MacOS hangs if third party copy is enabled * [DMC-805] - davix leaks file descriptors ### Improvements * [DMC-739] - Support both S3 URL syntaxes * [DMC-745] - Parse owner and group ids * [DMC-760] - Create a robust functional test suite for davix * [DMC-764] - Use a heuristic to find if the special Azure header needs to be added * [DMC-765] - Make it possible to build davix using clang * [DMC-780] - Add support for short-term S3 credentials * [DMC-785] - Add explicit limit in maximum number of redirects, throw descriptive error if exceeded * [DMC-683] - Davix 0.4.0 static library missing objects * [DMC-728] - Add gtest as a git submodule in davix * [DMC-753] - Make sure that a davix build fails if there are backwards-incompatible ABI chagnes * [DMC-787] - Azure tests are flaky ### New Features * [DMC-755] - Add Azure compatibility to Davix * [DMC-774] - davix vectored reads - implement range coalescing * [DMC-777] - Vectored reads using multiple connections and threads * [DMC-611] - S3: Support for Signature Version 4 needed for new AWS regions * [DMC-746] - Davix cannot create S3 directory * [DMC-788] - Add support for S3 to davix-mv * [DMC-791] - Create a consolidated and complete place for davix documentation * [DMC-794] - Overwrite sensitive command line parameters ## 0.5.0 ### Bug fixes * [DMC-629] - Bulk davs deletion seems to fail every 18 operations as a clock * [DMC-630] - Davix: davposix and davfile stat on S3 objects defaults to HTTP head request, bypasses signing * [DMC-660] - Davix-put does not recognize the --verbose option ? * [DMC-671] - Davix: S3 Uri transformer incorrectly assumes all operations are done without SSL * [DMC-675] - Found a host that hangs Davix indefinitely * [DMC-447] - Davix SSL Error needs to be clarified * [DMC-569] - Davix: libneon has problems with the handling of corrupted or invalid ceritificate * [DMC-691] - davix-put returns 0 ( =OK ) in case of permission denied * [DMC-699] - Bad regression bugs * [DMC-707] - Davix: xml parser does not handle multi-status response correctly for delete * [DMC-193] - DAVIX: Transform and simply the rety mechanism on davix * [DMC-633] - Connection timeout is sometimes triggered before the deadline when the global timeout is default. ### Improvements * [DMC-614] - Davix: Add hierarchical file listing support for S3 bucket * [DMC-621] - Davix: Add last modified date/time to S3 long listing * [DMC-631] - Davix: Add virtual S3 directory stats request handling * [DMC-634] - Davix: Add configurable max-keys param for S3 list object request * [DMC-658] - Davix: Add functionality to support uploading and downloading collections * [DMC-700] - Davix-get should not retry 10 times on err 403 (and maybe others) * [DMC-702] - Davix: Implement Content-Type and Content-MD5 signing for S3 requests * [DMC-715] - Davix: Implement multi-threaded crawler for recursive directory listing * [DMC-716] - Davix: Allow user to specify the number of threads for recursive operations * [DMC-718] - Davix can't copy a 0-sized file * [DMC-624] - No decent error message if certificate or key are not readable * [DMC-695] - Makes recursive operations on directory optional rather than default (davix-get/put) * [DMC-703] - Davix: Remove gridsite dependency * [DMC-708] - Davix: Add new parser for S3 multi-objects deletion response * [DMC-711] - Davix: Update banner in source files with correct copyright info * [DMC-713] - Shall the davix recursive crawler ignore more common errors and continue ? ### New Features * [DMC-665] - Add support for 3rd party copy FROM dav TO s3 * [DMC-693] - Add support for pulling http 3rd party copies * [DMC-668] - Davix-rm: bulk/folder remove ## 0.4.0 ### Bug fixes * [DMC-443] - Wrong section in .TH tag for libdavix.3 * [DMC-444] - Fix SSL Error related to too big digest (reported by Martin) * [DMC-472] - Fix Davix follows redirection automatically even though redirectionSupport is switched off * [DMC-501] - Fix SIGPIPE error with OpenSSL in Davix * [DMC-518] - Fix POODLE vulnerability CVE-2014-3566 affects libneon, then davix * [DMC-538] - Fix davix cmd line tool print an error in case of double authentication x509 -> login/password * [DMC-547] - Update the functional tests * [DMC-554] - Fix Thread-safety issue in the new davix logger system * [DMC-564] - Fix issue: Libneon does not set OpenSSL thread callback for some plateforms ( Ubuntu ) * [DMC-571] - Fix compilation warnings on the libneon part * [DMC-573] - Reinforce auto retry mechanism (dCache Door problem) * [DMC-581] - Solve portability problem under OSX/BSD due to the new hard timeout support * [DMC-586] - Fix ### Improvements * [DMC-474] - Log response body on http 3rd party copies * [DMC-476] - Delegation v2 support needed * [DMC-503] - Implement checksum support for S3 interface via Davix::File::checksum * [DMC-534] - Davix: re-design the logger to be more user friendly and easier to tune ### New features * [DMC-498] - S3 bucket creation support * [DMC-499] - S3 checksum support * [DMC-182] - Implement a list bucket feature for davix on the opendir/readdir model * [DMC-505] - Hard timeout support * [DMC-535] - Implement move operation in the File API * [DMC-552] - DAVIX: improve PUT operation support in the file API ## 0.3.6 ### Bug fixes * [LCGUTIL-418] - DAVIX: Solve OpenSSL issue with davix cmd line tools and password shell * [LCGUTIL-475] - davfile.getToFd does not return the number of bytes read, but 0 on success * [LCGUTIL-478] - Davix 32 bits ABI break problem * [LCGUTIL-480] - Davix maps badly http statuses to errno ## 0.3.4 ### Bug fixes * [LCGUTIL-410] - davix-cp help is not up to date and confusing * [LCGUTIL-411] - davix-cp does not support the profile features of the davix command line tool * [LCGUTIL-454] - Davix: libneon ignores connexion timeout * [LCGUTIL-455] - DAVIX: bug reported by johannes concerning dCache and very long connexion re-use * [LCGUTIL-456] - LCGUTIL: davix under heavy I/O usage for vector query send sometimes empty vector query ## 0.3.1 ### New features * Support for transparent fail-over based on Metalink, supported by all read I/O with HTTP * Multi-Range support compatible with TDavixFile/ROOT 5/6 * tested and working for dCache, DPM, Apache2, EOS, DynaFed, Owncloud, S3 * Implement SOCKS5 support based on libneon * Add support for POSIX write operations, davix can now be used to write remotely on top of POSIX layer. * Add getReplicas call, allowing to list replica of a resources using Metalink * Introduce Checksum calculation feature * Extend the command line tool with davix-mkdir, davix-rm * Add long listing option to davix-ls -l * Add the -P options to all command line tools, can be used to enable the usage of pre-defined profile * For instance "davix-ls -P grid davs://grid-storage.com/" enable all grid extensions for davix-ls * Introduce a callback mechanism, allowing to intercept event inside davix based on std::function * Drop internal library for boost ( dependency optional, git submodule ) * The "davix" http query tool is renamed "davix-http" * First port on cygwin * Add --headers options for OAuth spport to all command line tools * Add --trace-headers options to all command line tools for query debugging * create man pages for each cmd line tool * Reduce default connextion timeout from 180s to 30s ### Improvements / bug fixes * [LCGUTIL-170] - Davix : Correct important coverity warnings * [LCGUTIL-275] - Double HEAD coming from gfal-copy/gfal2/davix (?) relies on KeepAlive * [LCGUTIL-301] - Create Davix MetalinkParser and test it * [LCGUTIL-302] - Implement replicas selector from Metalink parsers * [LCGUTIL-103] - DAVIX: Evaluate performance of Http based IO and compare with other protocols ( gsiftp, xrootd ) * [LCGUTIL-154] - Davix: koji build hangs forever on rawhide * [LCGUTIL-162] - DAVIX: portability issue seen on Win32 plateform * [LCGUTIL-172] - Davix posix write does not handle failures correctly * [LCGUTIL-174] - DAVIX : Add a request parameter flag in order to disable completely any session reuse * [LCGUTIL-188] - Davix: prefixed install problem with cmake 2.8.7 * [LCGUTIL-196] - Davix & TDavixFile : map the main option to the ROOT Open file * [LCGUTIL-318] - DAVIX: storm webdav parsing problem * [LCGUTIL-341] - DAVIX: redirection caching problem with dCache instance * [LCGUTIL-348] - gfal-copy produces misleading error * [LCGUTIL-357] - gfal2-http fails to create the directories on 3rd party copies * [LCGUTIL-383] - Merge fixes for 405 error mapping and discard body after a request is done * [LCGUTIL-73] - DAVIX: design an API for advanced meta-link file management. * [LCGUTIL-119] - DAVIX: implement a simple transparent failover case using meta-link. * [LCGUTIL-344] - DAVIX : simplify davix code using boost, internal boost version is needed for ROOT usage * [LCGUTIL-370] - DAVIX : rename davix cmd line tool to davix-http in order to avoid confusion * [LCGUTIL-407] - DAVIX: Implement basic SOCKS5 support for Davix * [LCGUTIL-408] - DAVIX: Add a "load module" feature to davix * [LCGUTIL-113] - Davix misses a getReplicas function * [LCGUTIL-115] - DAVIX: split clearly the C API and the C++ API * [LCGUTIL-116] - DAVIX: export the IO buff map functions to the Object API * [LCGUTIL-339] - DAVIX: add support for login/password HTTP auth when URL contains login/password * [LCGUTIL-19] - add third party transfer support inside davix ( gfal 2.0 need ) * [LCGUTIL-175] - DAVIX: add options in order to display only request headers to the logging system * [LCGUTIL-246] - DAVIX : Add support for davix command line tools for plain encrypted PEM credential * [LCGUTIL-336] - DAVIX : error in case of separated cred and key usage * [LCGUTIL-337] - Davix: Support 303 redirection code for GET Operation too * [LCGUTIL-338] - Davix : Support for file request parameter level personalized header * [LCGUTIL-369] - Davix: add cmd line tool for simple collection creation ( mkdir ) * [LCGUTIL-371] - DAVIX : abi break between 0.2.8, and 0.3 : an ABI break has been detected on davix, this need to be fixed * [LCGUTIL-372] - DAVIX: add simple stupid option --headers to display request headers of any operations with davix * [LCGUTIL-373] - DAVIX : fix compilation problems and warning on OSX with clang compilation * [LCGUTIL-375] - DAVIX: prepare internal IO stack for Metalink usage, Rucio parsing and s3 bucket parsing * [LCGUTIL-379] - DAVIX: Fix misleading Connexion timeout debug message * [LCGUTIL-381] - DAVIX: include man page for the software distribution * [LCGUTIL-394] - DAVIX: bad_alloc throw by davix in some case with dCache endpoints * [LCGUTIL-409] - DAVIX: implement POSIX partial write support with davix ## 0.2.8 ### Bug fixes * [LCGUTIL-197] - Davix : bug inside the vector request system : vector request split to "one" range can trigger parsing problem ### Improvements * [LCGUTIL-333] - Improve Davix setup on OSX * [LCGUTIL-327] - DAVIX: add long listing support to davix-ls * [LCGUTIL-274] - add an error code "redirection needed" to davix status errors ## 0.2.7 ### Improvements * remove several GNU ext dependency * first version stable for TDavixFile/TDavixSystem * include prefetching support * several minor bug fixes * fix a problem related to stat() mode flag in plain http mode * clean of old C error code system ## 0.2.7 ### Improvements * support for S3 auth tokens * add external gtest support * simplify build system * remove strlcpy dependency * add several Meta-data operation support * support for very large Vector IO query ( > 1000 chunks ) * support for IO prefecthing * add initial tools * bug fixe in the session reuse system * bug fixe in the redirection system * add stream support for Davix Uri * clean and re-organize headers * add support for dav:// davs:// s3:// and s3s:// schemes * several warnings correction from coverity scan * resolve several packaging issues * Inclusion of the prototype davix_copy feature: third party copy based on HTTP ## 0.2.0 ### Improvements * Initial Stable version * Support POSIX and FILE API * Remote I/O read only * support for S3 * support for X509 / VOMS / Proxy credential * support for Vector IO * support for session reuse davix-0.8.0/patch-curl-clock-gettime.sh0000755000000000000000000000142314121063315016452 0ustar rootroot#!/usr/bin/env bash # An important user of davix (ROOT project) does not want to depend on librt. # This means we can only use clock_gettime on CC7, not SLC6. # # (clock_gettime was moved from librt onto glibc proper, starting from CC7) # # This script patches out libcurl support for clock_gettime entirely when building on SLC6. set -x if [ -f lib/curl_config.h ]; then echo '#include int main() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return 0; }' &> test.c gcc test.c -o /dev/null if [ $? -ne 0 ]; then grep "HAVE_CLOCK_GETTIME" lib/curl_config.h sed -i 's|^#define HAVE_CLOCK_GETTIME_MONOTONIC 1|// #define HAVE_CLOCK_GETTIME_MONOTONIC 1|g' lib/curl_config.h grep "HAVE_CLOCK_GETTIME" lib/curl_config.h fi rm test.c fi davix-0.8.0/deps/0000755000000000000000000000000014121063315012257 5ustar rootrootdavix-0.8.0/deps/CMakeLists.txt0000644000000000000000000000010114121063315015007 0ustar rootroot### ## compile dependencies of davix add_subdirectory(libneon) davix-0.8.0/deps/curl/0000755000000000000000000000000014121063461013226 5ustar rootrootdavix-0.8.0/deps/curl/README0000644000000000000000000000342514121063461014112 0ustar rootroot _ _ ____ _ ___| | | | _ \| | / __| | | | |_) | | | (__| |_| | _ <| |___ \___|\___/|_| \_\_____| README Curl is a command line tool for transferring data specified with URL syntax. Find out how to use curl by reading the curl.1 man page or the MANUAL document. Find out how to install Curl by reading the INSTALL document. libcurl is the library curl is using to do its job. It is readily available to be used by your software. Read the libcurl.3 man page to learn how! You find answers to the most frequent questions we get in the FAQ document. Study the COPYING file for distribution terms and similar. If you distribute curl binaries or other binaries that involve libcurl, you might enjoy the LICENSE-MIXING document. All of those documents and more can be found in the docs/ directory. CONTACT If you have problems, questions, ideas or suggestions, please contact us by posting to a suitable mailing list. See https://curl.haxx.se/mail/ All contributors to the project are listed in the THANKS document. WEB SITE Visit the curl web site for the latest news and downloads: https://curl.haxx.se/ GIT To download the very latest source off the GIT server do this: git clone https://github.com/curl/curl.git (you'll get a directory named curl created, filled with the source code) SECURITY PROBLEMS Report suspected security problems via our HackerOne page and not in public! https://hackerone.com/curl NOTICE Curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan. This notice is included here to comply with the distribution terms. davix-0.8.0/deps/curl/Makefile.am0000644000000000000000000006754414121063461015302 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 CMAKE_DIST = CMakeLists.txt CMake/CMakeConfigurableFile.in \ CMake/CurlTests.c CMake/FindGSS.cmake CMake/OtherTests.cmake \ CMake/Platforms/WindowsCache.cmake CMake/Utilities.cmake \ CMake/Macros.cmake \ CMake/CurlSymbolHiding.cmake CMake/FindCARES.cmake \ CMake/FindLibSSH2.cmake CMake/FindNGHTTP2.cmake \ CMake/FindMbedTLS.cmake CMake/FindBearSSL.cmake \ CMake/cmake_uninstall.cmake.in CMake/curl-config.cmake.in VC6_LIBTMPL = projects/Windows/VC6/lib/libcurl.tmpl VC6_LIBDSP = projects/Windows/VC6/lib/libcurl.dsp.dist VC6_LIBDSP_DEPS = $(VC6_LIBTMPL) Makefile.am lib/Makefile.inc VC6_SRCTMPL = projects/Windows/VC6/src/curl.tmpl VC6_SRCDSP = projects/Windows/VC6/src/curl.dsp.dist VC6_SRCDSP_DEPS = $(VC6_SRCTMPL) Makefile.am src/Makefile.inc VC7_LIBTMPL = projects/Windows/VC7/lib/libcurl.tmpl VC7_LIBVCPROJ = projects/Windows/VC7/lib/libcurl.vcproj.dist VC7_LIBVCPROJ_DEPS = $(VC7_LIBTMPL) Makefile.am lib/Makefile.inc VC7_SRCTMPL = projects/Windows/VC7/src/curl.tmpl VC7_SRCVCPROJ = projects/Windows/VC7/src/curl.vcproj.dist VC7_SRCVCPROJ_DEPS = $(VC7_SRCTMPL) Makefile.am src/Makefile.inc VC71_LIBTMPL = projects/Windows/VC7.1/lib/libcurl.tmpl VC71_LIBVCPROJ = projects/Windows/VC7.1/lib/libcurl.vcproj.dist VC71_LIBVCPROJ_DEPS = $(VC71_LIBTMPL) Makefile.am lib/Makefile.inc VC71_SRCTMPL = projects/Windows/VC7.1/src/curl.tmpl VC71_SRCVCPROJ = projects/Windows/VC7.1/src/curl.vcproj.dist VC71_SRCVCPROJ_DEPS = $(VC71_SRCTMPL) Makefile.am src/Makefile.inc VC8_LIBTMPL = projects/Windows/VC8/lib/libcurl.tmpl VC8_LIBVCPROJ = projects/Windows/VC8/lib/libcurl.vcproj.dist VC8_LIBVCPROJ_DEPS = $(VC8_LIBTMPL) Makefile.am lib/Makefile.inc VC8_SRCTMPL = projects/Windows/VC8/src/curl.tmpl VC8_SRCVCPROJ = projects/Windows/VC8/src/curl.vcproj.dist VC8_SRCVCPROJ_DEPS = $(VC8_SRCTMPL) Makefile.am src/Makefile.inc VC9_LIBTMPL = projects/Windows/VC9/lib/libcurl.tmpl VC9_LIBVCPROJ = projects/Windows/VC9/lib/libcurl.vcproj.dist VC9_LIBVCPROJ_DEPS = $(VC9_LIBTMPL) Makefile.am lib/Makefile.inc VC9_SRCTMPL = projects/Windows/VC9/src/curl.tmpl VC9_SRCVCPROJ = projects/Windows/VC9/src/curl.vcproj.dist VC9_SRCVCPROJ_DEPS = $(VC9_SRCTMPL) Makefile.am src/Makefile.inc VC10_LIBTMPL = projects/Windows/VC10/lib/libcurl.tmpl VC10_LIBVCXPROJ = projects/Windows/VC10/lib/libcurl.vcxproj.dist VC10_LIBVCXPROJ_DEPS = $(VC10_LIBTMPL) Makefile.am lib/Makefile.inc VC10_SRCTMPL = projects/Windows/VC10/src/curl.tmpl VC10_SRCVCXPROJ = projects/Windows/VC10/src/curl.vcxproj.dist VC10_SRCVCXPROJ_DEPS = $(VC10_SRCTMPL) Makefile.am src/Makefile.inc VC11_LIBTMPL = projects/Windows/VC11/lib/libcurl.tmpl VC11_LIBVCXPROJ = projects/Windows/VC11/lib/libcurl.vcxproj.dist VC11_LIBVCXPROJ_DEPS = $(VC11_LIBTMPL) Makefile.am lib/Makefile.inc VC11_SRCTMPL = projects/Windows/VC11/src/curl.tmpl VC11_SRCVCXPROJ = projects/Windows/VC11/src/curl.vcxproj.dist VC11_SRCVCXPROJ_DEPS = $(VC11_SRCTMPL) Makefile.am src/Makefile.inc VC12_LIBTMPL = projects/Windows/VC12/lib/libcurl.tmpl VC12_LIBVCXPROJ = projects/Windows/VC12/lib/libcurl.vcxproj.dist VC12_LIBVCXPROJ_DEPS = $(VC12_LIBTMPL) Makefile.am lib/Makefile.inc VC12_SRCTMPL = projects/Windows/VC12/src/curl.tmpl VC12_SRCVCXPROJ = projects/Windows/VC12/src/curl.vcxproj.dist VC12_SRCVCXPROJ_DEPS = $(VC12_SRCTMPL) Makefile.am src/Makefile.inc VC14_LIBTMPL = projects/Windows/VC14/lib/libcurl.tmpl VC14_LIBVCXPROJ = projects/Windows/VC14/lib/libcurl.vcxproj.dist VC14_LIBVCXPROJ_DEPS = $(VC14_LIBTMPL) Makefile.am lib/Makefile.inc VC14_SRCTMPL = projects/Windows/VC14/src/curl.tmpl VC14_SRCVCXPROJ = projects/Windows/VC14/src/curl.vcxproj.dist VC14_SRCVCXPROJ_DEPS = $(VC14_SRCTMPL) Makefile.am src/Makefile.inc VC15_LIBTMPL = projects/Windows/VC15/lib/libcurl.tmpl VC15_LIBVCXPROJ = projects/Windows/VC15/lib/libcurl.vcxproj.dist VC15_LIBVCXPROJ_DEPS = $(VC15_LIBTMPL) Makefile.am lib/Makefile.inc VC15_SRCTMPL = projects/Windows/VC15/src/curl.tmpl VC15_SRCVCXPROJ = projects/Windows/VC15/src/curl.vcxproj.dist VC15_SRCVCXPROJ_DEPS = $(VC15_SRCTMPL) Makefile.am src/Makefile.inc VC_DIST = projects/README \ projects/build-openssl.bat \ projects/build-wolfssl.bat \ projects/checksrc.bat \ projects/Windows/VC6/curl-all.dsw \ projects/Windows/VC6/lib/libcurl.dsw \ projects/Windows/VC6/src/curl.dsw \ projects/Windows/VC7/curl-all.sln \ projects/Windows/VC7/lib/libcurl.sln \ projects/Windows/VC7/src/curl.sln \ projects/Windows/VC7.1/curl-all.sln \ projects/Windows/VC7.1/lib/libcurl.sln \ projects/Windows/VC7.1/src/curl.sln \ projects/Windows/VC8/curl-all.sln \ projects/Windows/VC8/lib/libcurl.sln \ projects/Windows/VC8/src/curl.sln \ projects/Windows/VC9/curl-all.sln \ projects/Windows/VC9/lib/libcurl.sln \ projects/Windows/VC9/src/curl.sln \ projects/Windows/VC10/curl-all.sln \ projects/Windows/VC10/lib/libcurl.sln \ projects/Windows/VC10/lib/libcurl.vcxproj.filters \ projects/Windows/VC10/src/curl.sln \ projects/Windows/VC10/src/curl.vcxproj.filters \ projects/Windows/VC11/curl-all.sln \ projects/Windows/VC11/lib/libcurl.sln \ projects/Windows/VC11/lib/libcurl.vcxproj.filters \ projects/Windows/VC11/src/curl.sln \ projects/Windows/VC11/src/curl.vcxproj.filters \ projects/Windows/VC12/curl-all.sln \ projects/Windows/VC12/lib/libcurl.sln \ projects/Windows/VC12/lib/libcurl.vcxproj.filters \ projects/Windows/VC12/src/curl.sln \ projects/Windows/VC12/src/curl.vcxproj.filters \ projects/Windows/VC14/curl-all.sln \ projects/Windows/VC14/lib/libcurl.sln \ projects/Windows/VC14/lib/libcurl.vcxproj.filters \ projects/Windows/VC14/src/curl.sln \ projects/Windows/VC14/src/curl.vcxproj.filters \ projects/Windows/VC15/curl-all.sln \ projects/Windows/VC15/lib/libcurl.sln \ projects/Windows/VC15/lib/libcurl.vcxproj.filters \ projects/Windows/VC15/src/curl.sln \ projects/Windows/VC15/src/curl.vcxproj.filters \ projects/generate.bat \ projects/wolfssl_options.h \ projects/wolfssl_override.props WINBUILD_DIST = winbuild/BUILD.WINDOWS.txt winbuild/gen_resp_file.bat \ winbuild/MakefileBuild.vc winbuild/Makefile.vc PLAN9_DIST = plan9/include/mkfile \ plan9/include/mkfile \ plan9/mkfile.proto \ plan9/mkfile \ plan9/BUILD.PLAN9.txt \ plan9/lib/mkfile.inc \ plan9/lib/mkfile \ plan9/src/mkfile.inc \ plan9/src/mkfile EXTRA_DIST = CHANGES COPYING maketgz Makefile.dist curl-config.in \ RELEASE-NOTES buildconf libcurl.pc.in MacOSX-Framework \ scripts/updatemanpages.pl $(CMAKE_DIST) \ $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) \ lib/libcurl.vers.in buildconf.bat scripts/coverage.sh scripts/completion.pl CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP) $(VC7_LIBVCPROJ) $(VC7_SRCVCPROJ) \ $(VC71_LIBVCPROJ) $(VC71_SRCVCPROJ) $(VC8_LIBVCPROJ) $(VC8_SRCVCPROJ) \ $(VC9_LIBVCPROJ) $(VC9_SRCVCPROJ) $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) \ $(VC11_LIBVCXPROJ) $(VC11_SRCVCXPROJ) $(VC12_LIBVCXPROJ) $(VC12_SRCVCXPROJ) \ $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) $(VC15_LIBVCXPROJ) $(VC15_SRCVCXPROJ) bin_SCRIPTS = curl-config SUBDIRS = lib src DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libcurl.pc # List of files required to generate VC IDE .dsp, .vcproj and .vcxproj files include lib/Makefile.inc include src/Makefile.inc dist-hook: rm -rf $(top_builddir)/tests/log find $(distdir) -name "*.dist" -exec rm {} \; (distit=`find $(srcdir) -name "*.dist" | grep -v ./ares/`; \ for file in $$distit; do \ strip=`echo $$file | sed -e s/^$(srcdir)// -e s/\.dist//`; \ cp -p $$file $(distdir)$$strip; \ done) html: cd docs && $(MAKE) html pdf: cd docs && $(MAKE) pdf check: test examples check-docs if CROSSCOMPILING test-full: test test-torture: test test: @echo "NOTICE: we can't run the tests when cross-compiling!" else test: @(cd tests; $(MAKE) all quiet-test) test-full: @(cd tests; $(MAKE) all full-test) test-nonflaky: @(cd tests; $(MAKE) all nonflaky-test) test-torture: @(cd tests; $(MAKE) all torture-test) test-event: @(cd tests; $(MAKE) all event-test) test-am: @(cd tests; $(MAKE) all am-test) endif examples: @(cd docs/examples; $(MAKE) check) check-docs: @(cd docs/libcurl; $(MAKE) check) # Build source and binary rpms. For rpm-3.0 and above, the ~/.rpmmacros # must contain the following line: # %_topdir /home/loic/local/rpm # and that /home/loic/local/rpm contains the directory SOURCES, BUILD etc. # # cd /home/loic/local/rpm ; mkdir -p SOURCES BUILD RPMS/i386 SPECS SRPMS # # If additional configure flags are needed to build the package, add the # following in ~/.rpmmacros # %configure CFLAGS="%{optflags}" ./configure %{_target_platform} --prefix=%{_prefix} ${AM_CONFIGFLAGS} # and run make rpm in the following way: # AM_CONFIGFLAGS='--with-uri=/home/users/loic/local/RedHat-6.2' make rpm # rpms: $(MAKE) RPMDIST=curl rpm $(MAKE) RPMDIST=curl-ssl rpm rpm: RPM_TOPDIR=`rpm --showrc | $(PERL) -n -e 'print if(s/.*_topdir\s+(.*)/$$1/)'` ; \ cp $(srcdir)/packages/Linux/RPM/$(RPMDIST).spec $$RPM_TOPDIR/SPECS ; \ cp $(PACKAGE)-$(VERSION).tar.gz $$RPM_TOPDIR/SOURCES ; \ rpm -ba --clean --rmsource $$RPM_TOPDIR/SPECS/$(RPMDIST).spec ; \ mv $$RPM_TOPDIR/RPMS/i386/$(RPMDIST)-*.rpm . ; \ mv $$RPM_TOPDIR/SRPMS/$(RPMDIST)-*.src.rpm . # # Build a Solaris pkgadd format file # run 'make pkgadd' once you've done './configure' and 'make' to make a Solaris pkgadd format # file (which ends up back in this directory). # The pkgadd file is in 'pkgtrans' format, so to install on Solaris, do # pkgadd -d ./HAXXcurl-* # # gak - libtool requires an absolute directory, hence the pwd below... pkgadd: umask 022 ; \ $(MAKE) install DESTDIR=`/bin/pwd`/packages/Solaris/root ; \ cat COPYING > $(srcdir)/packages/Solaris/copyright ; \ cd $(srcdir)/packages/Solaris && $(MAKE) package # # Build a cygwin binary tarball installation file # resulting .tar.bz2 file will end up at packages/Win32/cygwin cygwinbin: $(MAKE) -C packages/Win32/cygwin cygwinbin # We extend the standard install with a custom hook: install-data-hook: cd include && $(MAKE) install cd docs && $(MAKE) install cd docs/libcurl && $(MAKE) install # We extend the standard uninstall with a custom hook: uninstall-hook: cd include && $(MAKE) uninstall cd docs && $(MAKE) uninstall cd docs/libcurl && $(MAKE) uninstall ca-bundle: lib/mk-ca-bundle.pl @echo "generating a fresh ca-bundle.crt" @perl $< -b -l -u lib/ca-bundle.crt ca-firefox: lib/firefox-db2pem.sh @echo "generating a fresh ca-bundle.crt" ./lib/firefox-db2pem.sh lib/ca-bundle.crt checksrc: cd lib && $(MAKE) checksrc cd src && $(MAKE) checksrc cd tests && $(MAKE) checksrc cd include/curl && $(MAKE) checksrc cd docs/examples && $(MAKE) checksrc .PHONY: vc-ide vc-ide: $(VC6_LIBDSP_DEPS) $(VC6_SRCDSP_DEPS) $(VC7_LIBVCPROJ_DEPS) \ $(VC7_SRCVCPROJ_DEPS) $(VC71_LIBVCPROJ_DEPS) $(VC71_SRCVCPROJ_DEPS) \ $(VC8_LIBVCPROJ_DEPS) $(VC8_SRCVCPROJ_DEPS) $(VC9_LIBVCPROJ_DEPS) \ $(VC9_SRCVCPROJ_DEPS) $(VC10_LIBVCXPROJ_DEPS) $(VC10_SRCVCXPROJ_DEPS) \ $(VC11_LIBVCXPROJ_DEPS) $(VC11_SRCVCXPROJ_DEPS) $(VC12_LIBVCXPROJ_DEPS) \ $(VC12_SRCVCXPROJ_DEPS) $(VC14_LIBVCXPROJ_DEPS) $(VC14_SRCVCXPROJ_DEPS) \ $(VC15_LIBVCXPROJ_DEPS) $(VC15_SRCVCXPROJ_DEPS) @(win32_lib_srcs='$(LIB_CFILES)'; \ win32_lib_hdrs='$(LIB_HFILES) config-win32.h'; \ win32_lib_rc='$(LIB_RCFILES)'; \ win32_lib_vauth_srcs='$(LIB_VAUTH_CFILES)'; \ win32_lib_vauth_hdrs='$(LIB_VAUTH_HFILES)'; \ win32_lib_vquic_srcs='$(LIB_VQUIC_CFILES)'; \ win32_lib_vquic_hdrs='$(LIB_VQUIC_HFILES)'; \ win32_lib_vssh_srcs='$(LIB_VSSH_CFILES)'; \ win32_lib_vssh_hdrs='$(LIB_VSSH_HFILES)'; \ win32_lib_vtls_srcs='$(LIB_VTLS_CFILES)'; \ win32_lib_vtls_hdrs='$(LIB_VTLS_HFILES)'; \ win32_src_srcs='$(CURL_CFILES)'; \ win32_src_hdrs='$(CURL_HFILES)'; \ win32_src_rc='$(CURL_RCFILES)'; \ win32_src_x_srcs='$(CURLX_CFILES)'; \ win32_src_x_hdrs='$(CURLX_HFILES) ../lib/config-win32.h'; \ \ sorted_lib_srcs=`for file in $$win32_lib_srcs; do echo $$file; done | sort`; \ sorted_lib_hdrs=`for file in $$win32_lib_hdrs; do echo $$file; done | sort`; \ sorted_lib_vauth_srcs=`for file in $$win32_lib_vauth_srcs; do echo $$file; done | sort`; \ sorted_lib_vauth_hdrs=`for file in $$win32_lib_vauth_hdrs; do echo $$file; done | sort`; \ sorted_lib_vquic_srcs=`for file in $$win32_lib_vquic_srcs; do echo $$file; done | sort`; \ sorted_lib_vquic_hdrs=`for file in $$win32_lib_vquic_hdrs; do echo $$file; done | sort`; \ sorted_lib_vssh_srcs=`for file in $$win32_lib_vssh_srcs; do echo $$file; done | sort`; \ sorted_lib_vssh_hdrs=`for file in $$win32_lib_vssh_hdrs; do echo $$file; done | sort`; \ sorted_lib_vtls_srcs=`for file in $$win32_lib_vtls_srcs; do echo $$file; done | sort`; \ sorted_lib_vtls_hdrs=`for file in $$win32_lib_vtls_hdrs; do echo $$file; done | sort`; \ sorted_src_srcs=`for file in $$win32_src_srcs; do echo $$file; done | sort`; \ sorted_src_hdrs=`for file in $$win32_src_hdrs; do echo $$file; done | sort`; \ sorted_src_x_srcs=`for file in $$win32_src_x_srcs; do echo $$file; done | sort`; \ sorted_src_x_hdrs=`for file in $$win32_src_x_hdrs; do echo $$file; done | sort`; \ \ awk_code='\ function gen_element(type, dir, file)\ {\ sub(/vauth\//, "", file);\ sub(/vquic\//, "", file);\ sub(/vssh\//, "", file);\ sub(/vtls\//, "", file);\ \ spaces=" ";\ if(dir == "lib\\vauth" ||\ dir == "lib\\vquic" ||\ dir == "lib\\vssh" ||\ dir == "lib\\vtls")\ tabs=" ";\ else\ tabs=" ";\ \ if(type == "dsp") {\ printf("# Begin Source File\r\n");\ printf("\r\n");\ printf("SOURCE=..\\..\\..\\..\\%s\\%s\r\n", dir, file);\ printf("# End Source File\r\n");\ }\ else if(type == "vcproj1") {\ printf("%s\r\n",\ tabs, dir, file);\ printf("%s
\r\n", tabs);\ }\ else if(type == "vcproj2") {\ printf("%s\r\n", tabs);\ printf("%s
\r\n", tabs);\ }\ else if(type == "vcxproj") {\ i = index(file, ".");\ ext = substr(file, i == 0 ? 0 : i + 1);\ \ if(ext == "c")\ printf("%s\r\n",\ spaces, dir, file);\ else if(ext == "h")\ printf("%s\r\n",\ spaces, dir, file);\ else if(ext == "rc")\ printf("%s\r\n",\ spaces, dir, file);\ }\ }\ \ {\ \ if($$0 == "CURL_LIB_C_FILES") {\ split(lib_srcs, arr);\ for(val in arr) gen_element(proj_type, "lib", arr[val]);\ }\ else if($$0 == "CURL_LIB_H_FILES") {\ split(lib_hdrs, arr);\ for(val in arr) gen_element(proj_type, "lib", arr[val]);\ }\ else if($$0 == "CURL_LIB_RC_FILES") {\ split(lib_rc, arr);\ for(val in arr) gen_element(proj_type, "lib", arr[val]);\ }\ else if($$0 == "CURL_LIB_VAUTH_C_FILES") {\ split(lib_vauth_srcs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ }\ else if($$0 == "CURL_LIB_VAUTH_H_FILES") {\ split(lib_vauth_hdrs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vauth", arr[val]);\ }\ else if($$0 == "CURL_LIB_VQUIC_C_FILES") {\ split(lib_vquic_srcs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ }\ else if($$0 == "CURL_LIB_VQUIC_H_FILES") {\ split(lib_vquic_hdrs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vquic", arr[val]);\ }\ else if($$0 == "CURL_LIB_VSSH_C_FILES") {\ split(lib_vssh_srcs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ }\ else if($$0 == "CURL_LIB_VSSH_H_FILES") {\ split(lib_vssh_hdrs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vssh", arr[val]);\ }\ else if($$0 == "CURL_LIB_VTLS_C_FILES") {\ split(lib_vtls_srcs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ }\ else if($$0 == "CURL_LIB_VTLS_H_FILES") {\ split(lib_vtls_hdrs, arr);\ for(val in arr) gen_element(proj_type, "lib\\vtls", arr[val]);\ }\ else if($$0 == "CURL_SRC_C_FILES") {\ split(src_srcs, arr);\ for(val in arr) gen_element(proj_type, "src", arr[val]);\ }\ else if($$0 == "CURL_SRC_H_FILES") {\ split(src_hdrs, arr);\ for(val in arr) gen_element(proj_type, "src", arr[val]);\ }\ else if($$0 == "CURL_SRC_RC_FILES") {\ split(src_rc, arr);\ for(val in arr) gen_element(proj_type, "src", arr[val]);\ }\ else if($$0 == "CURL_SRC_X_C_FILES") {\ split(src_x_srcs, arr);\ for(val in arr) {\ sub(/..\/lib\//, "", arr[val]);\ gen_element(proj_type, "lib", arr[val]);\ }\ }\ else if($$0 == "CURL_SRC_X_H_FILES") {\ split(src_x_hdrs, arr);\ for(val in arr) {\ sub(/..\/lib\//, "", arr[val]);\ gen_element(proj_type, "lib", arr[val]);\ }\ }\ else\ printf("%s\r\n", $$0);\ }';\ \ echo "generating '$(VC6_LIBDSP)'"; \ awk -v proj_type=dsp \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC6_LIBTMPL) > $(VC6_LIBDSP) || { exit 1; }; \ \ echo "generating '$(VC6_SRCDSP)'"; \ awk -v proj_type=dsp \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC6_SRCTMPL) > $(VC6_SRCDSP) || { exit 1; }; \ \ echo "generating '$(VC7_LIBVCPROJ)'"; \ awk -v proj_type=vcproj1 \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC7_LIBTMPL) > $(VC7_LIBVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC7_SRCVCPROJ)'"; \ awk -v proj_type=vcproj1 \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC7_SRCTMPL) > $(VC7_SRCVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC71_LIBVCPROJ)'"; \ awk -v proj_type=vcproj1 \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC71_LIBTMPL) > $(VC71_LIBVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC71_SRCVCPROJ)'"; \ awk -v proj_type=vcproj1 \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC71_SRCTMPL) > $(VC71_SRCVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC8_LIBVCPROJ)'"; \ awk -v proj_type=vcproj2 \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC8_LIBTMPL) > $(VC8_LIBVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC8_SRCVCPROJ)'"; \ awk -v proj_type=vcproj2 \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC8_SRCTMPL) > $(VC8_SRCVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC9_LIBVCPROJ)'"; \ awk -v proj_type=vcproj2 \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC9_LIBTMPL) > $(VC9_LIBVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC9_SRCVCPROJ)'"; \ awk -v proj_type=vcproj2 \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC9_SRCTMPL) > $(VC9_SRCVCPROJ) || { exit 1; }; \ \ echo "generating '$(VC10_LIBVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC10_LIBTMPL) > $(VC10_LIBVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC10_SRCVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC10_SRCTMPL) > $(VC10_SRCVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC11_LIBVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC11_LIBTMPL) > $(VC11_LIBVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC11_SRCVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC11_SRCTMPL) > $(VC11_SRCVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC12_LIBVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC12_LIBTMPL) > $(VC12_LIBVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC12_SRCVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC12_SRCTMPL) > $(VC12_SRCVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC14_LIBVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC14_LIBTMPL) > $(VC14_LIBVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC14_SRCVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC14_SRCTMPL) > $(VC14_SRCVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC15_LIBVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v lib_srcs="$$sorted_lib_srcs" \ -v lib_hdrs="$$sorted_lib_hdrs" \ -v lib_rc="$$win32_lib_rc" \ -v lib_vauth_srcs="$$sorted_lib_vauth_srcs" \ -v lib_vauth_hdrs="$$sorted_lib_vauth_hdrs" \ -v lib_vquic_srcs="$$sorted_lib_vquic_srcs" \ -v lib_vquic_hdrs="$$sorted_lib_vquic_hdrs" \ -v lib_vssh_srcs="$$sorted_lib_vssh_srcs" \ -v lib_vssh_hdrs="$$sorted_lib_vssh_hdrs" \ -v lib_vtls_srcs="$$sorted_lib_vtls_srcs" \ -v lib_vtls_hdrs="$$sorted_lib_vtls_hdrs" \ "$$awk_code" $(srcdir)/$(VC15_LIBTMPL) > $(VC15_LIBVCXPROJ) || { exit 1; }; \ \ echo "generating '$(VC15_SRCVCXPROJ)'"; \ awk -v proj_type=vcxproj \ -v src_srcs="$$sorted_src_srcs" \ -v src_hdrs="$$sorted_src_hdrs" \ -v src_rc="$$win32_src_rc" \ -v src_x_srcs="$$sorted_src_x_srcs" \ -v src_x_hdrs="$$sorted_src_x_hdrs" \ "$$awk_code" $(srcdir)/$(VC15_SRCTMPL) > $(VC15_SRCVCXPROJ) || { exit 1; };) tidy: (cd src && $(MAKE) tidy) (cd lib && $(MAKE) tidy) davix-0.8.0/deps/curl/CMakeLists.txt0000644000000000000000000014651714121063461016004 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # curl/libcurl CMake script # by Tetetest and Sukender (Benoit Neil) # TODO: # The output .so file lacks the soname number which we currently have within the lib/Makefile.am file # Add full (4 or 5 libs) SSL support # Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include). # Add CTests(?) # Check on all possible platforms # Test with as many configurations possible (With or without any option) # Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest: # - lists of headers that 'configure' checks for; # - curl-specific tests (the ones that are in m4/curl-*.m4 files); # - (most obvious thing:) curl version numbers. # Add documentation subproject # # To check: # (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not. # (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options. cmake_minimum_required(VERSION 3.0...3.16 FATAL_ERROR) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") include(Utilities) include(Macros) include(CMakeDependentOption) include(CheckCCompilerFlag) project(CURL C) message(WARNING "the curl cmake build system is poorly maintained. Be aware") file(STRINGS ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS REGEX "#define LIBCURL_VERSION( |_NUM )") string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" CURL_VERSION ${CURL_VERSION_H_CONTENTS}) string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION}) string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS}) string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM}) # Setup package meta-data # SET(PACKAGE "curl") message(STATUS "curl version=[${CURL_VERSION}]") # SET(PACKAGE_TARNAME "curl") # SET(PACKAGE_NAME "curl") # SET(PACKAGE_VERSION "-") # SET(PACKAGE_STRING "curl-") # SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/") set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}") set(OS "\"${CMAKE_SYSTEM_NAME}\"") include_directories(${CURL_SOURCE_DIR}/include) option(CURL_WERROR "Turn compiler warnings into errors" OFF) option(PICKY_COMPILER "Enable picky compiler options" ON) option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) if(WIN32) option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF) option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON) set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string") if(CURL_TARGET_WINDOWS_VERSION) add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}) elseif(ENABLE_INET_PTON) # _WIN32_WINNT_VISTA (0x0600) add_definitions(-D_WIN32_WINNT=0x0600) else() # _WIN32_WINNT_WINXP (0x0501) add_definitions(-D_WIN32_WINNT=0x0501) endif() endif() option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF) cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup" ON "NOT ENABLE_ARES" OFF) option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) if(PICKY_COMPILER) foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers -Wno-pedantic-ms-format) # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new # test result in. string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname) check_c_compiler_flag(${_CCOPT} ${_optvarname}) if(${_optvarname}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}") endif() endforeach() endif() endif() if(ENABLE_DEBUG) # DEBUGBUILD will be defined only for Debug builds set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:DEBUGBUILD>) set(ENABLE_CURLDEBUG ON) endif() if(ENABLE_CURLDEBUG) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG) endif() # For debug libs and exes, add "-d" postfix if(NOT DEFINED CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX "-d") endif() # initialize CURL_LIBS set(CURL_LIBS "") if(ENABLE_ARES) set(USE_ARES 1) find_package(CARES REQUIRED) list(APPEND CURL_LIBS ${CARES_LIBRARY}) endif() include(CurlSymbolHiding) option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) mark_as_advanced(HTTP_ONLY) option(CURL_DISABLE_FTP "disables FTP" OFF) mark_as_advanced(CURL_DISABLE_FTP) option(CURL_DISABLE_LDAP "disables LDAP" OFF) mark_as_advanced(CURL_DISABLE_LDAP) option(CURL_DISABLE_TELNET "disables Telnet" OFF) mark_as_advanced(CURL_DISABLE_TELNET) option(CURL_DISABLE_DICT "disables DICT" OFF) mark_as_advanced(CURL_DISABLE_DICT) option(CURL_DISABLE_FILE "disables FILE" OFF) mark_as_advanced(CURL_DISABLE_FILE) option(CURL_DISABLE_TFTP "disables TFTP" OFF) mark_as_advanced(CURL_DISABLE_TFTP) option(CURL_DISABLE_HTTP "disables HTTP" OFF) mark_as_advanced(CURL_DISABLE_HTTP) option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF) mark_as_advanced(CURL_DISABLE_LDAPS) option(CURL_DISABLE_RTSP "to disable RTSP" OFF) mark_as_advanced(CURL_DISABLE_RTSP) option(CURL_DISABLE_PROXY "to disable proxy" OFF) mark_as_advanced(CURL_DISABLE_PROXY) option(CURL_DISABLE_POP3 "to disable POP3" OFF) mark_as_advanced(CURL_DISABLE_POP3) option(CURL_DISABLE_IMAP "to disable IMAP" OFF) mark_as_advanced(CURL_DISABLE_IMAP) option(CURL_DISABLE_SMTP "to disable SMTP" OFF) mark_as_advanced(CURL_DISABLE_SMTP) option(CURL_DISABLE_GOPHER "to disable Gopher" OFF) mark_as_advanced(CURL_DISABLE_GOPHER) if(HTTP_ONLY) set(CURL_DISABLE_FTP ON) set(CURL_DISABLE_LDAP ON) set(CURL_DISABLE_LDAPS ON) set(CURL_DISABLE_TELNET ON) set(CURL_DISABLE_DICT ON) set(CURL_DISABLE_FILE ON) set(CURL_DISABLE_TFTP ON) set(CURL_DISABLE_RTSP ON) set(CURL_DISABLE_POP3 ON) set(CURL_DISABLE_IMAP ON) set(CURL_DISABLE_SMB ON) set(CURL_DISABLE_SMTP ON) set(CURL_DISABLE_GOPHER ON) endif() option(CURL_DISABLE_COOKIES "to disable cookies support" OFF) mark_as_advanced(CURL_DISABLE_COOKIES) option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF) mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH) option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF) mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS) option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON) mark_as_advanced(ENABLE_IPV6) if(ENABLE_IPV6 AND NOT WIN32) include(CheckStructHasMember) check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_ADDR) check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR) message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support") # Force the feature off as this name is used as guard macro... set(ENABLE_IPV6 OFF CACHE BOOL "Define if you want to enable IPv6 support" FORCE) endif() endif() curl_nroff_check() find_package(Perl) cmake_dependent_option(ENABLE_MANUAL "to provide the built-in manual" ON "NROFF_USEFUL;PERL_FOUND" OFF) if(NOT PERL_FOUND) message(STATUS "Perl not found, testing disabled.") set(BUILD_TESTING OFF) endif() if(ENABLE_MANUAL) set(USE_MANUAL ON) endif() # We need ansi c-flags, especially on HP set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS}) if(CURL_STATIC_CRT) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") endif() # Disable warnings on Borland to avoid changing 3rd party code. if(BORLAND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") endif() # If we are on AIX, do the _ALL_SOURCE magic if(${CMAKE_SYSTEM_NAME} MATCHES AIX) set(_ALL_SOURCE 1) endif() # Include all the necessary files for macros include(CMakePushCheckState) include(CheckFunctionExists) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckTypeSize) include(CheckCSourceCompiles) # On windows preload settings if(WIN32) set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_=") include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake) endif() if(ENABLE_THREADED_RESOLVER) find_package(Threads REQUIRED) if(WIN32) set(USE_THREADS_WIN32 ON) else() set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT}) set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT}) endif() set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) endif() # Check for all needed libraries check_library_exists_concat("${CMAKE_DL_LIBS}" dlopen HAVE_LIBDL) check_library_exists_concat("socket" connect HAVE_LIBSOCKET) check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL) # Yellowtab Zeta needs different libraries than BeOS 5. if(BEOS) set(NOT_NEED_LIBNSL 1) check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND) check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI) endif() if(NOT NOT_NEED_LIBNSL) check_library_exists_concat("nsl" gethostbyname HAVE_LIBNSL) endif() check_function_exists(gethostname HAVE_GETHOSTNAME) if(WIN32) check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32) check_library_exists_concat("winmm" getch HAVE_LIBWINMM) list(APPEND CURL_LIBS "advapi32") endif() # check SSL libraries # TODO support GnuTLS and WolfSSL if(APPLE) option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF) endif() if(WIN32) option(CMAKE_USE_WINSSL "enable Windows native SSL/TLS" OFF) cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON CMAKE_USE_WINSSL OFF) endif() option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF) option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF) option(CMAKE_USE_NSS "Enable NSS for SSL/TLS" OFF) set(openssl_default ON) if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS) set(openssl_default OFF) endif() option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default}) count_true(enabled_ssl_options_count CMAKE_USE_WINSSL CMAKE_USE_SECTRANSP CMAKE_USE_OPENSSL CMAKE_USE_MBEDTLS CMAKE_USE_BEARSSL CMAKE_USE_NSS ) if(enabled_ssl_options_count GREATER "1") set(CURL_WITH_MULTI_SSL ON) endif() if(CMAKE_USE_WINSSL) set(SSL_ENABLED ON) set(USE_SCHANNEL ON) # Windows native SSL/TLS support set(USE_WINDOWS_SSPI ON) # CMAKE_USE_WINSSL implies CURL_WINDOWS_SSPI list(APPEND CURL_LIBS "crypt32") endif() if(CURL_WINDOWS_SSPI) set(USE_WINDOWS_SSPI ON) set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32") endif() if(CMAKE_USE_DARWINSSL) message(FATAL_ERROR "The cmake option CMAKE_USE_DARWINSSL was renamed to CMAKE_USE_SECTRANSP.") endif() if(CMAKE_USE_SECTRANSP) find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation") if(NOT COREFOUNDATION_FRAMEWORK) message(FATAL_ERROR "CoreFoundation framework not found") endif() find_library(SECURITY_FRAMEWORK "Security") if(NOT SECURITY_FRAMEWORK) message(FATAL_ERROR "Security framework not found") endif() set(SSL_ENABLED ON) set(USE_SECTRANSP ON) list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}") endif() if(CMAKE_USE_OPENSSL) find_package(OpenSSL REQUIRED) set(SSL_ENABLED ON) set(USE_OPENSSL ON) # Depend on OpenSSL via imported targets if supported by the running # version of CMake. This allows our dependents to get our dependencies # transitively. if(NOT CMAKE_VERSION VERSION_LESS 3.4) list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto) else() list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES}) include_directories(${OPENSSL_INCLUDE_DIR}) endif() set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H) check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H) check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H) check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H) check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H) check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H) check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS) check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN) check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD) endif() if(CMAKE_USE_MBEDTLS) find_package(MbedTLS REQUIRED) set(SSL_ENABLED ON) set(USE_MBEDTLS ON) list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES}) include_directories(${MBEDTLS_INCLUDE_DIRS}) endif() if(CMAKE_USE_BEARSSL) find_package(BearSSL REQUIRED) set(SSL_ENABLED ON) set(USE_BEARSSL ON) list(APPEND CURL_LIBS ${BEARSSL_LIBRARY}) include_directories(${BEARSSL_INCLUDE_DIRS}) endif() if(CMAKE_USE_NSS) find_package(NSS REQUIRED) include_directories(${NSS_INCLUDE_DIRS}) list(APPEND CURL_LIBS ${NSS_LIBRARIES}) set(SSL_ENABLED ON) set(USE_NSS ON) cmake_push_check_state() set(CMAKE_REQUIRED_INCLUDES ${NSS_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${NSS_LIBRARIES}) check_symbol_exists(PK11_CreateManagedGenericObject "pk11pub.h" HAVE_PK11_CREATEMANAGEDGENERICOBJECT) cmake_pop_check_state() endif() option(USE_NGHTTP2 "Use Nghttp2 library" OFF) if(USE_NGHTTP2) find_package(NGHTTP2 REQUIRED) include_directories(${NGHTTP2_INCLUDE_DIRS}) list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) endif() if(WIN32) set(USE_WIN32_CRYPTO ON) endif() if(NOT CURL_DISABLE_LDAP) if(WIN32) option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) if(USE_WIN32_LDAP) check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32) if(NOT HAVE_WLDAP32) set(USE_WIN32_LDAP OFF) endif() endif() endif() option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF) mark_as_advanced(CMAKE_USE_OPENLDAP) set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library") set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library") if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP) message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time") endif() # Now that we know, we're not using windows LDAP... if(USE_WIN32_LDAP) check_include_file_concat("winldap.h" HAVE_WINLDAP_H) check_include_file_concat("winber.h" HAVE_WINBER_H) else() # Check for LDAP set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP) check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER) set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES}) set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory") if(CMAKE_LDAP_INCLUDE_DIR) list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR}) endif() check_include_file_concat("ldap.h" HAVE_LDAP_H) check_include_file_concat("lber.h" HAVE_LBER_H) if(NOT HAVE_LDAP_H) message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON") set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used elseif(NOT HAVE_LIBLDAP) message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON") set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used else() if(CMAKE_USE_OPENLDAP) set(USE_OPENLDAP ON) endif() if(CMAKE_LDAP_INCLUDE_DIR) include_directories(${CMAKE_LDAP_INCLUDE_DIR}) endif() set(NEED_LBER_H ON) set(_HEADER_LIST) if(HAVE_WINDOWS_H) list(APPEND _HEADER_LIST "windows.h") endif() if(HAVE_SYS_TYPES_H) list(APPEND _HEADER_LIST "sys/types.h") endif() list(APPEND _HEADER_LIST "ldap.h") set(_SRC_STRING "") foreach(_HEADER ${_HEADER_LIST}) set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n") endforeach() set(_SRC_STRING " ${_INCLUDE_STRING} int main(int argc, char ** argv) { BerValue *bvp = NULL; BerElement *bep = ber_init(bvp); ber_free(bep, 1); return 0; }" ) set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1") list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB}) if(HAVE_LIBLBER) list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB}) endif() check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H) unset(CMAKE_REQUIRED_LIBRARIES) if(NOT_NEED_LBER_H) set(NEED_LBER_H OFF) else() set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H") endif() endif() endif() endif() # No ldap, no ldaps. if(CURL_DISABLE_LDAP) if(NOT CURL_DISABLE_LDAPS) message(STATUS "LDAP needs to be enabled to support LDAPS") set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) endif() endif() if(NOT CURL_DISABLE_LDAPS) check_include_file_concat("ldap_ssl.h" HAVE_LDAP_SSL_H) check_include_file_concat("ldapssl.h" HAVE_LDAPSSL_H) endif() # Check for idn check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2) # Check for symbol dlopen (same as HAVE_LIBDL) check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON) set(HAVE_LIBZ OFF) set(HAVE_ZLIB_H OFF) set(USE_ZLIB OFF) if(CURL_ZLIB) find_package(ZLIB QUIET) if(ZLIB_FOUND) set(HAVE_ZLIB_H ON) set(HAVE_LIBZ ON) set(USE_ZLIB ON) # Depend on ZLIB via imported targets if supported by the running # version of CMake. This allows our dependents to get our dependencies # transitively. if(NOT CMAKE_VERSION VERSION_LESS 3.4) list(APPEND CURL_LIBS ZLIB::ZLIB) else() list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) include_directories(${ZLIB_INCLUDE_DIRS}) endif() list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) endif() endif() option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF) set(HAVE_BROTLI OFF) if(CURL_BROTLI) find_package(Brotli QUIET) if(BROTLI_FOUND) set(HAVE_BROTLI ON) list(APPEND CURL_LIBS ${BROTLI_LIBRARIES}) include_directories(${BROTLI_INCLUDE_DIRS}) list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS}) endif() endif() #libSSH2 option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON) mark_as_advanced(CMAKE_USE_LIBSSH2) set(USE_LIBSSH2 OFF) set(HAVE_LIBSSH2 OFF) set(HAVE_LIBSSH2_H OFF) if(CMAKE_USE_LIBSSH2) find_package(LibSSH2) if(LIBSSH2_FOUND) list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY}) set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY}) list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}") include_directories("${LIBSSH2_INCLUDE_DIR}") set(HAVE_LIBSSH2 ON) set(USE_LIBSSH2 ON) # find_package has already found the headers set(HAVE_LIBSSH2_H ON) set(CURL_INCLUDES ${CURL_INCLUDES} "${LIBSSH2_INCLUDE_DIR}/libssh2.h") set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DHAVE_LIBSSH2_H") # now check for specific libssh2 symbols as they were added in different versions set(CMAKE_EXTRA_INCLUDE_FILES "libssh2.h") check_function_exists(libssh2_version HAVE_LIBSSH2_VERSION) check_function_exists(libssh2_init HAVE_LIBSSH2_INIT) check_function_exists(libssh2_exit HAVE_LIBSSH2_EXIT) check_function_exists(libssh2_scp_send64 HAVE_LIBSSH2_SCP_SEND64) check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE) set(CMAKE_EXTRA_INCLUDE_FILES "") unset(CMAKE_REQUIRED_LIBRARIES) endif() endif() option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF) mark_as_advanced(CMAKE_USE_GSSAPI) if(CMAKE_USE_GSSAPI) find_package(GSS) set(HAVE_GSSAPI ${GSS_FOUND}) if(GSS_FOUND) message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"") list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR}) check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H) if(GSS_FLAVOUR STREQUAL "Heimdal") set(HAVE_GSSHEIMDAL ON) else() # MIT set(HAVE_GSSMIT ON) set(_INCLUDE_LIST "") if(HAVE_GSSAPI_GSSAPI_H) list(APPEND _INCLUDE_LIST "gssapi/gssapi.h") endif() if(HAVE_GSSAPI_GSSAPI_GENERIC_H) list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h") endif() if(HAVE_GSSAPI_GSSAPI_KRB5_H) list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h") endif() string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}") string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}") foreach(_dir ${GSS_LINK_DIRECTORIES}) set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"") endforeach() set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}") set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES}) check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE) if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) set(HAVE_OLD_GSSMIT ON) endif() unset(CMAKE_REQUIRED_LIBRARIES) endif() include_directories(${GSS_INCLUDE_DIR}) link_directories(${GSS_LINK_DIRECTORIES}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}") list(APPEND CURL_LIBS ${GSS_LIBRARIES}) else() message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.") endif() endif() option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON) if(ENABLE_UNIX_SOCKETS) include(CheckStructHasMember) check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) else() unset(USE_UNIX_SOCKETS CACHE) endif() # # CA handling # set(CURL_CA_BUNDLE "auto" CACHE STRING "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") set(CURL_CA_FALLBACK OFF CACHE BOOL "Set ON to use built-in CA store of TLS backend. Defaults to OFF") set(CURL_CA_PATH "auto" CACHE STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.") if("${CURL_CA_BUNDLE}" STREQUAL "") message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.") elseif("${CURL_CA_BUNDLE}" STREQUAL "none") unset(CURL_CA_BUNDLE CACHE) elseif("${CURL_CA_BUNDLE}" STREQUAL "auto") unset(CURL_CA_BUNDLE CACHE) set(CURL_CA_BUNDLE_AUTODETECT TRUE) else() set(CURL_CA_BUNDLE_SET TRUE) endif() if("${CURL_CA_PATH}" STREQUAL "") message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.") elseif("${CURL_CA_PATH}" STREQUAL "none") unset(CURL_CA_PATH CACHE) elseif("${CURL_CA_PATH}" STREQUAL "auto") unset(CURL_CA_PATH CACHE) if(NOT USE_NSS) set(CURL_CA_PATH_AUTODETECT TRUE) endif() else() set(CURL_CA_PATH_SET TRUE) endif() if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT) # Skip autodetection of unset CA path because CA bundle is set explicitly elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT) # Skip autodetection of unset CA bundle because CA path is set explicitly elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT) # first try autodetecting a CA bundle, then a CA path if(CURL_CA_BUNDLE_AUTODETECT) set(SEARCH_CA_BUNDLE_PATHS /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt /usr/share/ssl/certs/ca-bundle.crt /usr/local/share/certs/ca-root-nss.crt /etc/ssl/cert.pem) foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS}) if(EXISTS "${SEARCH_CA_BUNDLE_PATH}") message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}") set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}") set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set") break() endif() endforeach() endif() if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET)) if(EXISTS "/etc/ssl/certs") set(CURL_CA_PATH "/etc/ssl/certs") set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set") endif() endif() endif() if(CURL_CA_PATH_SET AND NOT USE_OPENSSL AND NOT USE_MBEDTLS) message(FATAL_ERROR "CA path only supported by OpenSSL, GnuTLS or mbed TLS. " "Set CURL_CA_PATH=none or enable one of those TLS backends.") endif() # Check for header files if(NOT UNIX) check_include_file_concat("windows.h" HAVE_WINDOWS_H) check_include_file_concat("winsock.h" HAVE_WINSOCK_H) check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H) if(NOT CURL_WINDOWS_SSPI AND USE_OPENSSL) set(CURL_LIBS ${CURL_LIBS} "crypt32") endif() endif() check_include_file_concat("stdio.h" HAVE_STDIO_H) check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H) check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H) check_include_file_concat("alloca.h" HAVE_ALLOCA_H) check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) check_include_file_concat("assert.h" HAVE_ASSERT_H) check_include_file_concat("crypto.h" HAVE_CRYPTO_H) check_include_file_concat("des.h" HAVE_DES_H) check_include_file_concat("err.h" HAVE_ERR_H) check_include_file_concat("errno.h" HAVE_ERRNO_H) check_include_file_concat("fcntl.h" HAVE_FCNTL_H) check_include_file_concat("idn2.h" HAVE_IDN2_H) check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) check_include_file_concat("io.h" HAVE_IO_H) check_include_file_concat("krb.h" HAVE_KRB_H) check_include_file_concat("libgen.h" HAVE_LIBGEN_H) check_include_file_concat("locale.h" HAVE_LOCALE_H) check_include_file_concat("net/if.h" HAVE_NET_IF_H) check_include_file_concat("netdb.h" HAVE_NETDB_H) check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) check_include_file_concat("pem.h" HAVE_PEM_H) check_include_file_concat("poll.h" HAVE_POLL_H) check_include_file_concat("pwd.h" HAVE_PWD_H) check_include_file_concat("rsa.h" HAVE_RSA_H) check_include_file_concat("setjmp.h" HAVE_SETJMP_H) check_include_file_concat("sgtty.h" HAVE_SGTTY_H) check_include_file_concat("signal.h" HAVE_SIGNAL_H) check_include_file_concat("ssl.h" HAVE_SSL_H) check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) check_include_file_concat("stdint.h" HAVE_STDINT_H) check_include_file_concat("stdio.h" HAVE_STDIO_H) check_include_file_concat("stdlib.h" HAVE_STDLIB_H) check_include_file_concat("string.h" HAVE_STRING_H) check_include_file_concat("strings.h" HAVE_STRINGS_H) check_include_file_concat("stropts.h" HAVE_STROPTS_H) check_include_file_concat("termio.h" HAVE_TERMIO_H) check_include_file_concat("termios.h" HAVE_TERMIOS_H) check_include_file_concat("time.h" HAVE_TIME_H) check_include_file_concat("unistd.h" HAVE_UNISTD_H) check_include_file_concat("utime.h" HAVE_UTIME_H) check_include_file_concat("x509.h" HAVE_X509_H) check_include_file_concat("process.h" HAVE_PROCESS_H) check_include_file_concat("stddef.h" HAVE_STDDEF_H) check_include_file_concat("dlfcn.h" HAVE_DLFCN_H) check_include_file_concat("malloc.h" HAVE_MALLOC_H) check_include_file_concat("memory.h" HAVE_MEMORY_H) check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) check_include_file_concat("stdint.h" HAVE_STDINT_H) check_include_file_concat("sockio.h" HAVE_SOCKIO_H) check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) check_type_size(size_t SIZEOF_SIZE_T) check_type_size(ssize_t SIZEOF_SSIZE_T) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("long" SIZEOF_LONG) check_type_size("short" SIZEOF_SHORT) check_type_size("int" SIZEOF_INT) check_type_size("__int64" SIZEOF___INT64) check_type_size("long double" SIZEOF_LONG_DOUBLE) check_type_size("time_t" SIZEOF_TIME_T) if(NOT HAVE_SIZEOF_SSIZE_T) if(SIZEOF_LONG EQUAL SIZEOF_SIZE_T) set(ssize_t long) endif() if(NOT ssize_t AND SIZEOF___INT64 EQUAL SIZEOF_SIZE_T) set(ssize_t __int64) endif() endif() # off_t is sized later, after the HAVE_FILE_OFFSET_BITS test if(HAVE_SIZEOF_LONG_LONG) set(HAVE_LONGLONG 1) set(HAVE_LL 1) endif() find_file(RANDOM_FILE urandom /dev) mark_as_advanced(RANDOM_FILE) # Check for some functions that are used if(HAVE_LIBWS2_32) set(CMAKE_REQUIRED_LIBRARIES ws2_32) elseif(HAVE_LIBSOCKET) set(CMAKE_REQUIRED_LIBRARIES socket) endif() check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP) check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR) check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R) check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME) check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP) check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP) check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI) check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI) check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) if(NOT HAVE_STRNCMPI) set(HAVE_STRCMPI) endif() check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR) check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R) check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR) check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA) check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R) check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR) check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR) check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF) check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP) check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT) check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) check_symbol_exists(getpwuid_r "${CURL_INCLUDES}" HAVE_GETPWUID_R) check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) check_symbol_exists(usleep "${CURL_INCLUDES}" HAVE_USLEEP) check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R) check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME) check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC) check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO) if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) set(HAVE_SIGNAL 1) endif() check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME) check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME) check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX) check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE) check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) check_symbol_exists(inet_pton "${CURL_INCLUDES}" HAVE_INET_PTON) check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR) if(HAVE_FSETXATTR) foreach(CURL_TEST HAVE_FSETXATTR_5 HAVE_FSETXATTR_6) curl_internal_test(${CURL_TEST}) endforeach() endif() # sigaction and sigsetjmp are special. Use special mechanism for # detecting those, but only if previous attempt failed. if(HAVE_SIGNAL_H) check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION) endif() if(NOT HAVE_SIGSETJMP) if(HAVE_SETJMP_H) check_symbol_exists(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP) if(HAVE_MACRO_SIGSETJMP) set(HAVE_SIGSETJMP 1) endif() endif() endif() # If there is no stricmp(), do not allow LDAP to parse URLs if(NOT HAVE_STRICMP) set(HAVE_LDAP_URL_PARSE 1) endif() # Do curl specific tests foreach(CURL_TEST HAVE_FCNTL_O_NONBLOCK HAVE_IOCTLSOCKET HAVE_IOCTLSOCKET_CAMEL HAVE_IOCTLSOCKET_CAMEL_FIONBIO HAVE_IOCTLSOCKET_FIONBIO HAVE_IOCTL_FIONBIO HAVE_IOCTL_SIOCGIFADDR HAVE_SETSOCKOPT_SO_NONBLOCK HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID TIME_WITH_SYS_TIME HAVE_O_NONBLOCK HAVE_GETHOSTBYADDR_R_5 HAVE_GETHOSTBYADDR_R_7 HAVE_GETHOSTBYADDR_R_8 HAVE_GETHOSTBYADDR_R_5_REENTRANT HAVE_GETHOSTBYADDR_R_7_REENTRANT HAVE_GETHOSTBYADDR_R_8_REENTRANT HAVE_GETHOSTBYNAME_R_3 HAVE_GETHOSTBYNAME_R_5 HAVE_GETHOSTBYNAME_R_6 HAVE_GETHOSTBYNAME_R_3_REENTRANT HAVE_GETHOSTBYNAME_R_5_REENTRANT HAVE_GETHOSTBYNAME_R_6_REENTRANT HAVE_IN_ADDR_T HAVE_BOOL_T STDC_HEADERS RETSIGTYPE_TEST HAVE_INET_NTOA_R_DECL HAVE_INET_NTOA_R_DECL_REENTRANT HAVE_GETADDRINFO HAVE_FILE_OFFSET_BITS HAVE_VARIADIC_MACROS_C99 HAVE_VARIADIC_MACROS_GCC ) curl_internal_test(${CURL_TEST}) endforeach() if(HAVE_FILE_OFFSET_BITS) set(_FILE_OFFSET_BITS 64) set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") endif() check_type_size("off_t" SIZEOF_OFF_T) # include this header to get the type set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include") set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) set(CMAKE_EXTRA_INCLUDE_FILES "") set(CMAKE_REQUIRED_FLAGS) foreach(CURL_TEST HAVE_GLIBC_STRERROR_R HAVE_POSIX_STRERROR_R ) curl_internal_test(${CURL_TEST}) endforeach() # Check for reentrant foreach(CURL_TEST HAVE_GETHOSTBYADDR_R_5 HAVE_GETHOSTBYADDR_R_7 HAVE_GETHOSTBYADDR_R_8 HAVE_GETHOSTBYNAME_R_3 HAVE_GETHOSTBYNAME_R_5 HAVE_GETHOSTBYNAME_R_6 HAVE_INET_NTOA_R_DECL_REENTRANT) if(NOT ${CURL_TEST}) if(${CURL_TEST}_REENTRANT) set(NEED_REENTRANT 1) endif() endif() endforeach() if(NEED_REENTRANT) foreach(CURL_TEST HAVE_GETHOSTBYADDR_R_5 HAVE_GETHOSTBYADDR_R_7 HAVE_GETHOSTBYADDR_R_8 HAVE_GETHOSTBYNAME_R_3 HAVE_GETHOSTBYNAME_R_5 HAVE_GETHOSTBYNAME_R_6) set(${CURL_TEST} 0) if(${CURL_TEST}_REENTRANT) set(${CURL_TEST} 1) endif() endforeach() endif() if(HAVE_INET_NTOA_R_DECL_REENTRANT) set(HAVE_INET_NTOA_R_DECL 1) set(NEED_REENTRANT 1) endif() # Check clock_gettime(CLOCK_MONOTONIC, x) support curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC) # Check compiler support of __builtin_available() curl_internal_test(HAVE_BUILTIN_AVAILABLE) # Some other minor tests if(NOT HAVE_IN_ADDR_T) set(in_addr_t "unsigned long") endif() # Fix libz / zlib.h if(NOT CURL_SPECIAL_LIBZ) if(NOT HAVE_LIBZ) set(HAVE_ZLIB_H 0) endif() if(NOT HAVE_ZLIB_H) set(HAVE_LIBZ 0) endif() endif() # Check for nonblocking set(HAVE_DISABLED_NONBLOCKING 1) if(HAVE_FIONBIO OR HAVE_IOCTLSOCKET OR HAVE_IOCTLSOCKET_CASE OR HAVE_O_NONBLOCK) set(HAVE_DISABLED_NONBLOCKING) endif() if(RETSIGTYPE_TEST) set(RETSIGTYPE void) else() set(RETSIGTYPE int) endif() if(CMAKE_COMPILER_IS_GNUCC AND APPLE) include(CheckCCompilerFlag) check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double) if(HAVE_C_FLAG_Wno_long_double) # The Mac version of GCC warns about use of long double. Disable it. get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS) if(MPRINTF_COMPILE_FLAGS) set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double") else() set(MPRINTF_COMPILE_FLAGS "-Wno-long-double") endif() set_source_files_properties(mprintf.c PROPERTIES COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS}) endif() endif() # TODO test which of these headers are required if(WIN32) set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H}) else() set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H}) set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}) set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H}) endif() set(CURL_PULL_STDINT_H ${HAVE_STDINT_H}) set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H}) include(CMake/OtherTests.cmake) add_definitions(-DHAVE_CONFIG_H) # For Windows, all compilers used by CMake should support large files if(WIN32) set(USE_WIN32_LARGE_FILES ON) # Use the manifest embedded in the Windows Resource set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DCURL_EMBED_MANIFEST") endif() if(MSVC) # Disable default manifest added by CMake set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) if(CMAKE_C_FLAGS MATCHES "/W[0-4]") string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") endif() endif() if(CURL_WERROR) if(MSVC_VERSION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") else() # this assumes clang or gcc style options set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") endif() endif() if(CURL_LTO) if(CMAKE_VERSION VERSION_LESS 3.9) message(FATAL_ERROR "Requested LTO but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9") endif() cmake_policy(SET CMP0069 NEW) include(CheckIPOSupported) check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT CURL_LTO_ERROR LANGUAGES C) if(CURL_HAS_LTO) message(STATUS "LTO supported and enabled") else() message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}") endif() endif() # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it). function(transform_makefile_inc INPUT_FILE OUTPUT_FILE) file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT) string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) string(REGEX REPLACE "\\\\\n" "!Ï€!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) string(REPLACE "!Ï€!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${} string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts. file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT}) endfunction() include(GNUInstallDirs) set(CURL_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") if(USE_MANUAL) add_subdirectory(docs) endif() add_subdirectory(lib) if(BUILD_CURL_EXE) add_subdirectory(src) endif() include(CTest) if(BUILD_TESTING) add_subdirectory(tests) endif() # NTLM support requires crypto function adaptions from various SSL libs # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO)) set(use_ntlm ON) else() set(use_ntlm OFF) endif() # Helper to populate a list (_items) with a label when conditions (the remaining # args) are satisfied macro(_add_if label) # needs to be a macro to allow this indirection if(${ARGN}) set(_items ${_items} "${label}") endif() endmacro() # Clear list and try to detect available features set(_items) _add_if("SSL" SSL_ENABLED) _add_if("IPv6" ENABLE_IPV6) _add_if("unix-sockets" USE_UNIX_SOCKETS) _add_if("libz" HAVE_LIBZ) _add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) _add_if("IDN" HAVE_LIBIDN2) _add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES)) # TODO SSP1 (WinSSL) check is missing _add_if("SSPI" USE_WINDOWS_SSPI) _add_if("GSS-API" HAVE_GSSAPI) # TODO SSP1 missing for SPNEGO _add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) _add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND (HAVE_GSSAPI OR USE_WINDOWS_SSPI)) # NTLM support requires crypto function adaptions from various SSL libs # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS _add_if("NTLM" use_ntlm) # TODO missing option (autoconf: --enable-ntlm-wb) _add_if("NTLM_WB" use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED) # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP _add_if("TLS-SRP" USE_TLS_SRP) # TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header _add_if("HTTP2" USE_NGHTTP2) _add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS)) string(REPLACE ";" " " SUPPORT_FEATURES "${_items}") message(STATUS "Enabled features: ${SUPPORT_FEATURES}") # Clear list and try to detect available protocols set(_items) _add_if("HTTP" NOT CURL_DISABLE_HTTP) _add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED) _add_if("FTP" NOT CURL_DISABLE_FTP) _add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED) _add_if("FILE" NOT CURL_DISABLE_FILE) _add_if("TELNET" NOT CURL_DISABLE_TELNET) _add_if("LDAP" NOT CURL_DISABLE_LDAP) # CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS # TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps) _add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND ((USE_OPENLDAP AND SSL_ENABLED) OR (NOT USE_OPENLDAP AND HAVE_LDAP_SSL))) _add_if("DICT" NOT CURL_DISABLE_DICT) _add_if("TFTP" NOT CURL_DISABLE_TFTP) _add_if("GOPHER" NOT CURL_DISABLE_GOPHER) _add_if("POP3" NOT CURL_DISABLE_POP3) _add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED) _add_if("IMAP" NOT CURL_DISABLE_IMAP) _add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED) _add_if("SMB" NOT CURL_DISABLE_SMB AND use_ntlm) _add_if("SMBS" NOT CURL_DISABLE_SMB AND SSL_ENABLED AND use_ntlm) _add_if("SMTP" NOT CURL_DISABLE_SMTP) _add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED) _add_if("SCP" USE_LIBSSH2) _add_if("SFTP" USE_LIBSSH2) _add_if("RTSP" NOT CURL_DISABLE_RTSP) _add_if("RTMP" USE_LIBRTMP) if(_items) list(SORT _items) endif() string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}") message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}") # Clear list and collect SSL backends set(_items) _add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI) _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP) _add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS) _add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL) _add_if("NSS" SSL_ENABLED AND USE_NSS) if(_items) list(SORT _items) endif() string(REPLACE ";" " " SSL_BACKENDS "${_items}") message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}") # curl-config needs the following options to be set. set(CC "${CMAKE_C_COMPILER}") # TODO probably put a -D... options here? set(CONFIGURE_OPTIONS "") # TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB? set(CPPFLAG_CURL_STATICLIB "") set(CURLVERSION "${CURL_VERSION}") if(BUILD_SHARED_LIBS) set(ENABLE_SHARED "yes") set(ENABLE_STATIC "no") else() set(ENABLE_SHARED "no") set(ENABLE_STATIC "yes") endif() set(exec_prefix "\${prefix}") set(includedir "\${prefix}/include") set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") set(LIBCURL_LIBS "") set(libdir "${CMAKE_INSTALL_PREFIX}/lib") foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-") set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") else() set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") endif() endforeach() # "a" (Linux) or "lib" (Windows) string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") set(prefix "${CMAKE_INSTALL_PREFIX}") # Set this to "yes" to append all libraries on which -lcurl is dependent set(REQUIRE_LIB_DEPS "no") # SUPPORT_FEATURES # SUPPORT_PROTOCOLS set(VERSIONNUM "${CURL_VERSION_NUM}") # Finally generate a "curl-config" matching this config # Use: # * ENABLE_SHARED # * ENABLE_STATIC configure_file("${CURL_SOURCE_DIR}/curl-config.in" "${CURL_BINARY_DIR}/curl-config" @ONLY) install(FILES "${CURL_BINARY_DIR}/curl-config" DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # Finally generate a pkg-config file matching this config configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in" "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) install(FILES "${CURL_BINARY_DIR}/libcurl.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) # install headers install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h") include(CMakePackageConfigHelpers) write_basic_package_version_file( "${version_config}" VERSION ${CURL_VERSION} COMPATIBILITY SameMajorVersion ) # Use: # * TARGETS_EXPORT_NAME # * PROJECT_NAME configure_package_config_file(CMake/curl-config.cmake.in "${project_config}" INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR} ) install( EXPORT "${TARGETS_EXPORT_NAME}" NAMESPACE "${PROJECT_NAME}::" DESTINATION ${CURL_INSTALL_CMAKE_DIR} ) install( FILES ${version_config} ${project_config} DESTINATION ${CURL_INSTALL_CMAKE_DIR} ) # Workaround for MSVS10 to avoid the Dialog Hell # FIXME: This could be removed with future version of CMake. if(MSVC_VERSION EQUAL 1600) set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln") if(EXISTS "${CURL_SLN_FILENAME}") file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n") endif() endif() if(NOT TARGET uninstall) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake) endif() davix-0.8.0/deps/curl/libcurl.pc.in0000644000000000000000000000273714121063461015624 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # This should most probably benefit from getting a "Requires:" field added # dynamically by configure. # prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ supported_protocols="@SUPPORT_PROTOCOLS@" supported_features="@SUPPORT_FEATURES@" Name: libcurl URL: https://curl.haxx.se/ Description: Library to transfer files with ftp, http, etc. Version: @CURLVERSION@ Libs: -L${libdir} -lcurl Libs.private: @LIBCURL_LIBS@ Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ davix-0.8.0/deps/curl/MacOSX-Framework0000755000000000000000000001220114121063461016175 0ustar rootroot#!/bin/bash # This script performs all of the steps needed to build a # universal binary libcurl.framework for Mac OS X 10.4 or greater. # # Hendrik Visage: # Generalizations added since Snowleopard (10.6) do not include # the 10.4u SDK. # # Also note: # 10.5 is the *ONLY* SDK that support PPC64 :( -- 10.6 do not have ppc64 support #If you need to have PPC64 support then change below to 1 PPC64_NEEDED=0 # Apple does not support building for PPC anymore in Xcode 4 and later. # If you're using Xcode 3 or earlier and need PPC support, then change # the setting below to 1 PPC_NEEDED=0 # For me the default is to develop for the platform I am on, and if you #desire compatibility with older versions then change USE_OLD to 1 :) USE_OLD=0 VERSION=`/usr/bin/sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' include/curl/curlver.h` FRAMEWORK_VERSION=Versions/Release-$VERSION #I also wanted to "copy over" the system, and thus the reason I added the # version to Versions/Release-7.20.1 etc. # now a simple rsync -vaP libcurl.framework /Library/Frameworks will install it # and setup the right paths to this version, leaving the system version # "intact", so you can "fix" it later with the links to Versions/A/... DEVELOPER_PATH=`xcode-select --print-path` # Around Xcode 4.3, SDKs were moved from the Developer folder into the # MacOSX.platform folder if test -d "$DEVELOPER_PATH/Platforms/MacOSX.platform/Developer/SDKs"; then SDK_PATH="$DEVELOPER_PATH/Platforms/MacOSX.platform/Developer/SDKs" else SDK_PATH="$DEVELOPER_PATH/SDKs"; fi OLD_SDK=`ls $SDK_PATH|head -1` NEW_SDK=`ls -r $SDK_PATH|head -1` if test "0"$USE_OLD -gt 0 then SDK32=$OLD_SDK else SDK32=$NEW_SDK fi MACVER=`echo $SDK32|sed -e s/[a-zA-Z]//g -e s/.\$//` SDK32_DIR=$SDK_PATH/$SDK32 MINVER32='-mmacosx-version-min='$MACVER if test $PPC_NEEDED -gt 0; then ARCHES32='-arch i386 -arch ppc' else ARCHES32='-arch i386' fi if test $PPC64_NEEDED -gt 0 then SDK64=10.5 ARCHES64='-arch x86_64 -arch ppc64' SDK64=`ls $SDK_PATH|grep 10.5|head -1` else ARCHES64='-arch x86_64' #We "know" that 10.4 and earlier do not support 64bit OLD_SDK64=`ls $SDK_PATH|egrep -v "10.[0-4]"|head -1` NEW_SDK64=`ls -r $SDK_PATH|egrep -v "10.[0-4][^0-9]" | head -1` if test $USE_OLD -gt 0 then SDK64=$OLD_SDK64 else SDK64=$NEW_SDK64 fi fi SDK64_DIR=$SDK_PATH/$SDK64 MACVER64=`echo $SDK64|sed -e s/[a-zA-Z]//g -e s/.\$//` MINVER64='-mmacosx-version-min='$MACVER64 if test ! -z $SDK32; then echo "----Configuring libcurl for 32 bit universal framework..." make clean ./configure --disable-dependency-tracking --disable-static --with-gssapi --with-darwinssl \ CFLAGS="-Os -isysroot $SDK32_DIR $ARCHES32" \ LDFLAGS="-Wl,-syslibroot,$SDK32_DIR $ARCHES32 -Wl,-headerpad_max_install_names" \ CC=$CC echo "----Building 32 bit libcurl..." make -j `sysctl -n hw.logicalcpu_max` echo "----Creating 32 bit framework..." rm -r libcurl.framework mkdir -p libcurl.framework/${FRAMEWORK_VERSION}/Resources cp lib/.libs/libcurl.dylib libcurl.framework/${FRAMEWORK_VERSION}/libcurl install_name_tool -id @rpath/libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl /usr/bin/sed -e "s/7\.12\.3/$VERSION/" lib/libcurl.plist >libcurl.framework/${FRAMEWORK_VERSION}/Resources/Info.plist mkdir -p libcurl.framework/${FRAMEWORK_VERSION}/Headers/curl cp include/curl/*.h libcurl.framework/${FRAMEWORK_VERSION}/Headers/curl pushd libcurl.framework ln -fs ${FRAMEWORK_VERSION}/libcurl libcurl ln -fs ${FRAMEWORK_VERSION}/Resources Resources ln -fs ${FRAMEWORK_VERSION}/Headers Headers cd Versions ln -fs $(basename "${FRAMEWORK_VERSION}") Current echo Testing for SDK64 if test -d $SDK64_DIR; then echo entering... popd make clean echo "----Configuring libcurl for 64 bit universal framework..." ./configure --disable-dependency-tracking --disable-static --with-gssapi --with-darwinssl \ CFLAGS="-Os -isysroot $SDK64_DIR $ARCHES64" \ LDFLAGS="-Wl,-syslibroot,$SDK64_DIR $ARCHES64 -Wl,-headerpad_max_install_names" \ CC=$CC echo "----Building 64 bit libcurl..." make -j `sysctl -n hw.logicalcpu_max` echo "----Appending 64 bit framework to 32 bit framework..." cp lib/.libs/libcurl.dylib libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 install_name_tool -id @rpath/libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 cp libcurl.framework/${FRAMEWORK_VERSION}/libcurl libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 pwd lipo libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 -create -output libcurl.framework/${FRAMEWORK_VERSION}/libcurl rm libcurl.framework/${FRAMEWORK_VERSION}/libcurl32 libcurl.framework/${FRAMEWORK_VERSION}/libcurl64 fi pwd lipo -info libcurl.framework/${FRAMEWORK_VERSION}/libcurl echo "libcurl.framework is built and can now be included in other projects." echo "Copy libcurl.framework to your bundle's Contents/Frameworks folder, ~/Library/Frameworks or /Library/Frameworks." else echo "Building libcurl.framework requires Mac OS X 10.4 or later with the MacOSX10.4/5/6 SDK installed." fi davix-0.8.0/deps/curl/.github/0000755000000000000000000000000014121063461014566 5ustar rootrootdavix-0.8.0/deps/curl/.github/ISSUE_TEMPLATE0000644000000000000000000000073514121063461016701 0ustar rootroot ### I did this ### I expected the following ### curl/libcurl version [curl -V output] ### operating system davix-0.8.0/deps/curl/.github/lock.yml0000644000000000000000000000045714121063461016247 0ustar rootroot# Configuration for lock-threads - https://github.com/dessant/lock-threads # Number of days of inactivity before a closed issue or pull request is locked daysUntilLock: 90 # Comment to post before locking. Set to `false` to disable lockComment: false # Limit to only `issues` or `pulls` # only: issues davix-0.8.0/deps/curl/.github/CONTRIBUTING.md0000644000000000000000000000105514121063461017020 0ustar rootrootHow to contribute to curl ========================= Join the community ------------------ 1. Click 'watch' on the github repo 2. Subscribe to the suitable [mailing lists](https://curl.haxx.se/mail/) Read [CONTRIBUTE](../docs/CONTRIBUTE.md) --------------------------------------- Send your suggestions using one of these methods: ------------------------------------------------- 1. in a mail to the mailing list 2. as a [pull request](https://github.com/curl/curl/pulls) 3. as an [issue](https://github.com/curl/curl/issues) / The curl team! davix-0.8.0/deps/curl/.github/FUNDING.yml0000644000000000000000000000002614121063461016401 0ustar rootrootopen_collective: curl davix-0.8.0/deps/curl/.github/stale.yml0000644000000000000000000000125414121063461016423 0ustar rootroot# Number of days of inactivity before an issue becomes stale daysUntilStale: 180 # Number of days of inactivity before a stale issue is closed daysUntilClose: 14 # Issues with these labels will never be considered stale exemptLabels: - pinned - security # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false davix-0.8.0/deps/curl/.github/workflows/0000755000000000000000000000000014121063461016623 5ustar rootrootdavix-0.8.0/deps/curl/.github/workflows/fuzz.yml0000644000000000000000000000112514121063461020343 0ustar rootrootname: CIFuzz on: [pull_request] jobs: Fuzzing: runs-on: ubuntu-latest steps: - name: Build Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'curl' dry-run: false - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'curl' fuzz-seconds: 600 dry-run: false - name: Upload Crash uses: actions/upload-artifact@v1 if: failure() with: name: artifacts path: ./out/artifacts davix-0.8.0/deps/curl/.github/workflows/cpp.yml0000644000000000000000000000044514121063461020133 0ustar rootrootname: Build on Ubuntu with default options on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: configure run: ./buildconf && ./configure - name: make run: make - name: make check run: make test-nonflaky davix-0.8.0/deps/curl/README.md0000644000000000000000000001227414121063461014513 0ustar rootroot![curl logo](https://curl.haxx.se/logo/curl-logo.svg) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/63/badge)](https://bestpractices.coreinfrastructure.org/projects/63) [![Coverity passed](https://scan.coverity.com/projects/curl/badge.svg)](https://scan.coverity.com/projects/curl) [![Travis-CI Build Status](https://travis-ci.org/curl/curl.svg?branch=master)](https://travis-ci.org/curl/curl) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/l1vv31029huhf4g4?svg=true)](https://ci.appveyor.com/project/curlorg/curl) [![Azure DevOps Build Status](https://dev.azure.com/daniel0244/curl/_apis/build/status/curl.curl?branchName=master)](https://dev.azure.com/daniel0244/curl/_build/latest?definitionId=1&branchName=master) [![Cirrus Build Status](https://api.cirrus-ci.com/github/curl/curl.svg?branch=master)](https://cirrus-ci.com/github/curl/curl) [![Backers on Open Collective](https://opencollective.com/curl/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/curl/sponsors/badge.svg)](#sponsors) [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/curl/curl.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/curl/curl/context:cpp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d11483a0cc5c4ebd9da4ff9f7cd56690)](https://www.codacy.com/app/curl/curl?utm_source=github.com&utm_medium=referral&utm_content=curl/curl&utm_campaign=Badge_Grade) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/curl.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:curl) Curl is a command-line tool for transferring data specified with URL syntax. Find out how to use curl by reading [the curl.1 man page](https://curl.haxx.se/docs/manpage.html) or [the MANUAL document](https://curl.haxx.se/docs/manual.html). Find out how to install Curl by reading [the INSTALL document](https://curl.haxx.se/docs/install.html). libcurl is the library curl is using to do its job. It is readily available to be used by your software. Read [the libcurl.3 man page](https://curl.haxx.se/libcurl/c/libcurl.html) to learn how! You can find answers to the most frequent questions we get in [the FAQ document](https://curl.haxx.se/docs/faq.html). Study [the COPYING file](https://curl.haxx.se/docs/copyright.html) for distribution terms and similar. If you distribute curl binaries or other binaries that involve libcurl, you might enjoy [the LICENSE-MIXING document](https://curl.haxx.se/legal/licmix.html). ## Contact If you have problems, questions, ideas or suggestions, please contact us by posting to a suitable [mailing list](https://curl.haxx.se/mail/). All contributors to the project are listed in [the THANKS document](https://curl.haxx.se/docs/thanks.html). ## Website Visit the [curl web site](https://curl.haxx.se/) for the latest news and downloads. ## Git To download the very latest source from the Git server do this: git clone https://github.com/curl/curl.git (you'll get a directory named curl created, filled with the source code) ## Security problems Report suspected security problems via [our HackerOne page](https://hackerone.com/curl) and not in public! ## Notice Curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan. This notice is included here to comply with the distribution terms. ## Backers Thank you to all our backers! 🙠[[Become a backer](https://opencollective.com/curl#backer)] ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/curl#sponsor)] davix-0.8.0/deps/curl/m4/0000755000000000000000000000000014121063461013546 5ustar rootrootdavix-0.8.0/deps/curl/m4/xc-val-flgs.m40000644000000000000000000001551514121063461016142 0ustar rootroot#--------------------------------------------------------------------------- # # xc-val-flgs.m4 # # Copyright (c) 2013 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl _XC_CHECK_VAR_LIBS dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CHECK_VAR_LIBS], [ xc_bad_var_libs=no for xc_word in $LIBS; do case "$xc_word" in -l* | --library=*) : ;; *) xc_bad_var_libs=yes ;; esac done if test $xc_bad_var_libs = yes; then AC_MSG_NOTICE([using LIBS: $LIBS]) AC_MSG_NOTICE([LIBS note: LIBS should only be used to specify libraries (-lname).]) fi ]) dnl _XC_CHECK_VAR_LDFLAGS dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CHECK_VAR_LDFLAGS], [ xc_bad_var_ldflags=no for xc_word in $LDFLAGS; do case "$xc_word" in -D*) xc_bad_var_ldflags=yes ;; -U*) xc_bad_var_ldflags=yes ;; -I*) xc_bad_var_ldflags=yes ;; -l* | --library=*) xc_bad_var_ldflags=yes ;; esac done if test $xc_bad_var_ldflags = yes; then AC_MSG_NOTICE([using LDFLAGS: $LDFLAGS]) xc_bad_var_msg="LDFLAGS note: LDFLAGS should only be used to specify linker flags, not" for xc_word in $LDFLAGS; do case "$xc_word" in -D*) AC_MSG_NOTICE([$xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word]) ;; -U*) AC_MSG_NOTICE([$xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word]) ;; -I*) AC_MSG_NOTICE([$xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word]) ;; -l* | --library=*) AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) ;; esac done fi ]) dnl _XC_CHECK_VAR_CPPFLAGS dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CHECK_VAR_CPPFLAGS], [ xc_bad_var_cppflags=no for xc_word in $CPPFLAGS; do case "$xc_word" in -rpath*) xc_bad_var_cppflags=yes ;; -L* | --library-path=*) xc_bad_var_cppflags=yes ;; -l* | --library=*) xc_bad_var_cppflags=yes ;; esac done if test $xc_bad_var_cppflags = yes; then AC_MSG_NOTICE([using CPPFLAGS: $CPPFLAGS]) xc_bad_var_msg="CPPFLAGS note: CPPFLAGS should only be used to specify C preprocessor flags, not" for xc_word in $CPPFLAGS; do case "$xc_word" in -rpath*) AC_MSG_NOTICE([$xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word]) ;; -L* | --library-path=*) AC_MSG_NOTICE([$xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word]) ;; -l* | --library=*) AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) ;; esac done fi ]) dnl _XC_CHECK_VAR_CFLAGS dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CHECK_VAR_CFLAGS], [ xc_bad_var_cflags=no for xc_word in $CFLAGS; do case "$xc_word" in -D*) xc_bad_var_cflags=yes ;; -U*) xc_bad_var_cflags=yes ;; -I*) xc_bad_var_cflags=yes ;; -rpath*) xc_bad_var_cflags=yes ;; -L* | --library-path=*) xc_bad_var_cflags=yes ;; -l* | --library=*) xc_bad_var_cflags=yes ;; esac done if test $xc_bad_var_cflags = yes; then AC_MSG_NOTICE([using CFLAGS: $CFLAGS]) xc_bad_var_msg="CFLAGS note: CFLAGS should only be used to specify C compiler flags, not" for xc_word in $CFLAGS; do case "$xc_word" in -D*) AC_MSG_NOTICE([$xc_bad_var_msg macro definitions. Use CPPFLAGS for: $xc_word]) ;; -U*) AC_MSG_NOTICE([$xc_bad_var_msg macro suppressions. Use CPPFLAGS for: $xc_word]) ;; -I*) AC_MSG_NOTICE([$xc_bad_var_msg include directories. Use CPPFLAGS for: $xc_word]) ;; -rpath*) AC_MSG_NOTICE([$xc_bad_var_msg library runtime directories. Use LDFLAGS for: $xc_word]) ;; -L* | --library-path=*) AC_MSG_NOTICE([$xc_bad_var_msg library directories. Use LDFLAGS for: $xc_word]) ;; -l* | --library=*) AC_MSG_NOTICE([$xc_bad_var_msg libraries. Use LIBS for: $xc_word]) ;; esac done fi ]) dnl XC_CHECK_USER_FLAGS dnl ------------------------------------------------- dnl Public macro. dnl dnl Performs some sanity checks for LIBS, LDFLAGS, dnl CPPFLAGS and CFLAGS values that the user might dnl have set. When checks fails, user is noticed dnl about errors detected in all of them and script dnl execution is halted. dnl dnl Intended to be used early in configure script. AC_DEFUN([XC_CHECK_USER_FLAGS], [ AC_PREREQ([2.50])dnl AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl dnl check order below matters _XC_CHECK_VAR_LIBS _XC_CHECK_VAR_LDFLAGS _XC_CHECK_VAR_CPPFLAGS _XC_CHECK_VAR_CFLAGS if test $xc_bad_var_libs = yes || test $xc_bad_var_cflags = yes || test $xc_bad_var_ldflags = yes || test $xc_bad_var_cppflags = yes; then AC_MSG_ERROR([Can not continue. Fix errors mentioned immediately above this line.]) fi ]) dnl XC_CHECK_BUILD_FLAGS dnl ------------------------------------------------- dnl Public macro. dnl dnl Performs some sanity checks for LIBS, LDFLAGS, dnl CPPFLAGS and CFLAGS values that the configure dnl script might have set. When checks fails, user dnl is noticed about errors detected in all of them dnl but script continues execution. dnl dnl Intended to be used very late in configure script. AC_DEFUN([XC_CHECK_BUILD_FLAGS], [ AC_PREREQ([2.50])dnl dnl check order below matters _XC_CHECK_VAR_LIBS _XC_CHECK_VAR_LDFLAGS _XC_CHECK_VAR_CPPFLAGS _XC_CHECK_VAR_CFLAGS if test $xc_bad_var_libs = yes || test $xc_bad_var_cflags = yes || test $xc_bad_var_ldflags = yes || test $xc_bad_var_cppflags = yes; then AC_MSG_WARN([Continuing even with errors mentioned immediately above this line.]) fi ]) davix-0.8.0/deps/curl/m4/curl-openssl.m40000644000000000000000000002025314121063461016440 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 5 dnl CURL_CHECK_OPENSSL_API_HEADERS dnl ------------------------------------------------- dnl Find out OpenSSL headers API version, as reported dnl by OPENSSL_VERSION_NUMBER. No runtime checks dnl allowed here for cross-compilation support. dnl HAVE_OPENSSL_API_HEADERS is defined as appropriate dnl only for systems which actually run the configure dnl script. Config files generated manually or in any dnl other way shall not define this. AC_DEFUN([CURL_CHECK_OPENSSL_API_HEADERS], [ # tst_api="unknown" # AC_MSG_CHECKING([for OpenSSL headers version]) CURL_CHECK_DEF([OPENSSL_VERSION_NUMBER], [ # ifdef USE_OPENSSL # include # else # include # endif ], [silent]) if test "$curl_cv_have_def_OPENSSL_VERSION_NUMBER" = "yes"; then tst_verlen=`expr "$curl_cv_def_OPENSSL_VERSION_NUMBER" : '.*'` case "x$tst_verlen" in x6) tst_vermaj=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 3` tst_vermin=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 4` tst_verfix=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 5` tst_api=0x$tst_vermaj$tst_vermin$tst_verfix ;; x11|x10) tst_vermaj=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 3` tst_vermin=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 5` tst_verfix=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 7` tst_api=0x$tst_vermaj$tst_vermin$tst_verfix ;; *) tst_api="unknown" ;; esac case $tst_api in 0x111) tst_show="1.1.1" ;; 0x110) tst_show="1.1.0" ;; 0x102) tst_show="1.0.2" ;; 0x101) tst_show="1.0.1" ;; 0x100) tst_show="1.0.0" ;; 0x099) tst_show="0.9.9" ;; 0x098) tst_show="0.9.8" ;; 0x097) tst_show="0.9.7" ;; 0x096) tst_show="0.9.6" ;; 0x095) tst_show="0.9.5" ;; 0x094) tst_show="0.9.4" ;; 0x093) tst_show="0.9.3" ;; 0x092) tst_show="0.9.2" ;; 0x091) tst_show="0.9.1" ;; *) tst_show="unknown" ;; esac tst_show="$tst_show - $curl_cv_def_OPENSSL_VERSION_NUMBER" else tst_show="unknown" fi AC_MSG_RESULT([$tst_show]) # dnl if test "$tst_api" != "unknown"; then dnl AC_DEFINE_UNQUOTED(HAVE_OPENSSL_API_HEADERS, $tst_api, dnl [OpenSSL headers configure time API. Defined only by configure script. dnl No matter what, do not ever define this manually or by any other means.]) dnl fi curl_openssl_api_headers=$tst_api ]) dnl CURL_CHECK_OPENSSL_API_LIBRARY dnl ------------------------------------------------- dnl Find out OpenSSL library API version, performing dnl only link tests in order to avoid getting fooled dnl by mismatched OpenSSL headers. No runtime checks dnl allowed here for cross-compilation support. dnl HAVE_OPENSSL_API_LIBRARY is defined as appropriate dnl only for systems which actually run the configure dnl script. Config files generated manually or in any dnl other way shall not define this. dnl dnl Most probably we should not bother attempting to dnl detect OpenSSL library development API versions dnl 0.9.9 and 1.1.0. For our intended use, detecting dnl released versions should be good enough. dnl dnl Given that currently we are not using the result dnl of this check, except for informative purposes, dnl lets try to figure out everything. AC_DEFUN([CURL_CHECK_OPENSSL_API_LIBRARY], [ # tst_api="unknown" # AC_MSG_CHECKING([for OpenSSL library version]) if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([ERR_clear_last_mark]) ],[ tst_api="0x111" ]) fi if test "$tst_api" = "unknown"; then case $host in *-*-vms*) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_CTX_set_not_resumbl_sess_cb]) ],[ tst_api="0x110" ]) ;; *) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_CTX_set_not_resumable_session_callback]) ],[ tst_api="0x110" ]) ;; esac fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_CONF_CTX_new]) ],[ tst_api="0x102" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_renegotiate_abbreviated]) ],[ tst_api="0x101" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([OBJ_add_sigid]) ],[ tst_api="0x100" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([ERR_set_mark]) ],[ tst_api="0x098" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([ERR_peek_last_error]) ],[ tst_api="0x097" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([c2i_ASN1_OBJECT]) ],[ tst_api="0x096" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_CTX_set_purpose]) ],[ tst_api="0x095" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([OBJ_obj2txt]) ],[ tst_api="0x094" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_get_verify_depth]) ],[ tst_api="0x093" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_library_init]) ],[ tst_api="0x092" ]) fi if test "$tst_api" = "unknown"; then AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([SSL_CTX_set_cipher_list]) ],[ tst_api="0x091" ]) fi case $tst_api in 0x111) tst_show="1.1.1" ;; 0x110) tst_show="1.1.0" ;; 0x102) tst_show="1.0.2" ;; 0x101) tst_show="1.0.1" ;; 0x100) tst_show="1.0.0" ;; 0x099) tst_show="0.9.9" ;; 0x098) tst_show="0.9.8" ;; 0x097) tst_show="0.9.7" ;; 0x096) tst_show="0.9.6" ;; 0x095) tst_show="0.9.5" ;; 0x094) tst_show="0.9.4" ;; 0x093) tst_show="0.9.3" ;; 0x092) tst_show="0.9.2" ;; 0x091) tst_show="0.9.1" ;; *) tst_show="unknown" ;; esac AC_MSG_RESULT([$tst_show]) # dnl if test "$tst_api" != "unknown"; then dnl AC_DEFINE_UNQUOTED(HAVE_OPENSSL_API_LIBRARY, $tst_api, dnl [OpenSSL library link time API. Defined only by configure script. dnl No matter what, do not ever define this manually or by any other means.]) dnl fi curl_openssl_api_library=$tst_api ]) dnl CURL_CHECK_OPENSSL_API dnl ------------------------------------------------- AC_DEFUN([CURL_CHECK_OPENSSL_API], [ # CURL_CHECK_OPENSSL_API_HEADERS CURL_CHECK_OPENSSL_API_LIBRARY # tst_match="yes" # AC_MSG_CHECKING([for OpenSSL headers and library versions matching]) if test "$curl_openssl_api_headers" = "unknown" || test "$curl_openssl_api_library" = "unknown"; then tst_match="fail" tst_warns="Can not compare OpenSSL headers and library versions." elif test "$curl_openssl_api_headers" != "$curl_openssl_api_library"; then tst_match="no" tst_warns="OpenSSL headers and library versions do not match." fi AC_MSG_RESULT([$tst_match]) if test "$tst_match" != "yes"; then AC_MSG_WARN([$tst_warns]) fi ]) davix-0.8.0/deps/curl/m4/zz50-xc-ovr.m40000644000000000000000000000434514121063461016042 0ustar rootroot#--------------------------------------------------------------------------- # # zz50-xc-ovr.m4 # # Copyright (c) 2011 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl The funny name of this file is intentional in order to make it dnl sort alphabetically after any libtool, autoconf or automake dnl provided .m4 macro file that might get copied into this same dnl subdirectory. This allows that macro (re)definitions from this dnl file may override those provided in other files. dnl Override some language related macros dnl ------------------------------------------------- dnl This is done to prevent Libtool 1.5.X from doing dnl unnecessary C++, Fortran and Java tests when only dnl using C language and reduce resulting configure dnl script by nearly 300 Kb. m4_ifdef([AC_LIBTOOL_LANG_CXX_CONFIG], [m4_undefine([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_define([AC_LIBTOOL_LANG_CXX_CONFIG],[:]) m4_ifdef([AC_LIBTOOL_LANG_F77_CONFIG], [m4_undefine([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_define([AC_LIBTOOL_LANG_F77_CONFIG],[:]) m4_ifdef([AC_LIBTOOL_LANG_GCJ_CONFIG], [m4_undefine([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_define([AC_LIBTOOL_LANG_GCJ_CONFIG],[:]) dnl XC_OVR_ZZ50 dnl ------------------------------------------------- dnl Placing a call to this macro in configure.ac will dnl make macros in this file visible to other macros dnl used for same configure script, overriding those dnl provided elsewhere. AC_DEFUN([XC_OVR_ZZ50], [AC_BEFORE([$0],[AC_PROG_LIBTOOL])]) davix-0.8.0/deps/curl/m4/zz40-xc-ovr.m40000644000000000000000000004357314121063461016047 0ustar rootroot#--------------------------------------------------------------------------- # # zz40-xc-ovr.m4 # # Copyright (c) 2013 - 2018 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- dnl The funny name of this file is intentional in order to make it dnl sort alphabetically after any libtool, autoconf or automake dnl provided .m4 macro file that might get copied into this same dnl subdirectory. This allows that macro (re)definitions from this dnl file may override those provided in other files. dnl Version macros dnl ------------------------------------------------- dnl Public macros. m4_define([XC_CONFIGURE_PREAMBLE_VER_MAJOR],[1])dnl m4_define([XC_CONFIGURE_PREAMBLE_VER_MINOR],[0])dnl dnl _XC_CFG_PRE_PREAMBLE dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CFG_PRE_PREAMBLE], [ ## -------------------------------- ## @%:@@%:@ [XC_CONFIGURE_PREAMBLE] ver: []dnl XC_CONFIGURE_PREAMBLE_VER_MAJOR.[]dnl XC_CONFIGURE_PREAMBLE_VER_MINOR ## ## -------------------------------- ## xc_configure_preamble_ver_major='XC_CONFIGURE_PREAMBLE_VER_MAJOR' xc_configure_preamble_ver_minor='XC_CONFIGURE_PREAMBLE_VER_MINOR' # # Set IFS to space, tab and newline. # xc_space=' ' xc_tab=' ' xc_newline=' ' IFS="$xc_space$xc_tab$xc_newline" # # Set internationalization behavior variables. # LANG='C' LC_ALL='C' LANGUAGE='C' export LANG export LC_ALL export LANGUAGE # # Some useful variables. # xc_msg_warn='configure: WARNING:' xc_msg_abrt='Can not continue.' xc_msg_err='configure: error:' ]) dnl _XC_CFG_PRE_BASIC_CHK_CMD_ECHO dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'echo' command dnl is available, otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO], [dnl AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl # # Verify that 'echo' command is available, otherwise abort. # xc_tst_str='unknown' (`echo "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) # Try built-in echo, and fail. echo "$xc_msg_err 'echo' command not found. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_CMD_TEST dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'test' command dnl is available, otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_TEST], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl # # Verify that 'test' command is available, otherwise abort. # xc_tst_str='unknown' (`test -n "$xc_tst_str" >/dev/null 2>&1`) && xc_tst_str='success' case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) echo "$xc_msg_err 'test' command not found. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_VAR_PATH dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'PATH' variable dnl is set, otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_VAR_PATH], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl # # Verify that 'PATH' variable is set, otherwise abort. # xc_tst_str='unknown' (`test -n "$PATH" >/dev/null 2>&1`) && xc_tst_str='success' case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) echo "$xc_msg_err 'PATH' variable not set. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_CMD_EXPR dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'expr' command dnl is available, otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl # # Verify that 'expr' command is available, otherwise abort. # xc_tst_str='unknown' xc_tst_str=`expr "$xc_tst_str" : '.*' 2>/dev/null` case "x$xc_tst_str" in @%:@ (( x7) : ;; *) echo "$xc_msg_err 'expr' command not found. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_UTIL_SED dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'sed' utility dnl is found within 'PATH', otherwise aborts execution. dnl dnl This 'sed' is required in order to allow configure dnl script bootstrapping itself. No fancy testing for a dnl proper 'sed' this early, that should be done later. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_SED], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl # # Verify that 'sed' utility is found within 'PATH', otherwise abort. # xc_tst_str='unknown' xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ | sed -e 's:unknown:success:' 2>/dev/null` case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) echo "$xc_msg_err 'sed' utility not found in 'PATH'. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_UTIL_GREP dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'grep' utility dnl is found within 'PATH', otherwise aborts execution. dnl dnl This 'grep' is required in order to allow configure dnl script bootstrapping itself. No fancy testing for a dnl proper 'grep' this early, that should be done later. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl # # Verify that 'grep' utility is found within 'PATH', otherwise abort. # xc_tst_str='unknown' (`echo "$xc_tst_str" 2>/dev/null \ | grep 'unknown' >/dev/null 2>&1`) && xc_tst_str='success' case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) echo "$xc_msg_err 'grep' utility not found in 'PATH'. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_UTIL_TR dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'tr' utility dnl is found within 'PATH', otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_TR], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl # # Verify that 'tr' utility is found within 'PATH', otherwise abort. # xc_tst_str="${xc_tab}98s7u6c5c4e3s2s10" xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ | tr -d "0123456789$xc_tab" 2>/dev/null` case "x$xc_tst_str" in @%:@ (( xsuccess) : ;; *) echo "$xc_msg_err 'tr' utility not found in 'PATH'. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_UTIL_WC dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'wc' utility dnl is found within 'PATH', otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_WC], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl # # Verify that 'wc' utility is found within 'PATH', otherwise abort. # xc_tst_str='unknown unknown unknown unknown' xc_tst_str=`echo "$xc_tst_str" 2>/dev/null \ | wc -w 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null` case "x$xc_tst_str" in @%:@ (( x4) : ;; *) echo "$xc_msg_err 'wc' utility not found in 'PATH'. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_BASIC_CHK_UTIL_CAT dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that verifies that 'cat' utility dnl is found within 'PATH', otherwise aborts execution. AC_DEFUN([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl # # Verify that 'cat' utility is found within 'PATH', otherwise abort. # xc_tst_str='unknown' xc_tst_str=`cat <<_EOT 2>/dev/null \ | wc -l 2>/dev/null | tr -d "$xc_space$xc_tab" 2>/dev/null unknown unknown unknown _EOT` case "x$xc_tst_str" in @%:@ (( x3) : ;; *) echo "$xc_msg_err 'cat' utility not found in 'PATH'. $xc_msg_abrt" >&2 exit 1 ;; esac ]) dnl _XC_CFG_PRE_CHECK_PATH_SEPARATOR dnl ------------------------------------------------- dnl Private macro. dnl dnl Emits shell code that computes the path separator dnl and stores the result in 'PATH_SEPARATOR', unless dnl the user has already set it with a non-empty value. dnl dnl This path separator is the symbol used to separate dnl or diferentiate paths inside the 'PATH' environment dnl variable. dnl dnl Non-empty user provided 'PATH_SEPARATOR' always dnl overrides the auto-detected one. AC_DEFUN([_XC_CFG_PRE_CHECK_PATH_SEPARATOR], [dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl # # Auto-detect and set 'PATH_SEPARATOR', unless it is already non-empty set. # # Directory count in 'PATH' when using a colon separator. xc_tst_dirs_col='x' xc_tst_prev_IFS=$IFS; IFS=':' for xc_tst_dir in $PATH; do IFS=$xc_tst_prev_IFS xc_tst_dirs_col="x$xc_tst_dirs_col" done IFS=$xc_tst_prev_IFS xc_tst_dirs_col=`expr "$xc_tst_dirs_col" : '.*'` # Directory count in 'PATH' when using a semicolon separator. xc_tst_dirs_sem='x' xc_tst_prev_IFS=$IFS; IFS=';' for xc_tst_dir in $PATH; do IFS=$xc_tst_prev_IFS xc_tst_dirs_sem="x$xc_tst_dirs_sem" done IFS=$xc_tst_prev_IFS xc_tst_dirs_sem=`expr "$xc_tst_dirs_sem" : '.*'` if test $xc_tst_dirs_sem -eq $xc_tst_dirs_col; then # When both counting methods give the same result we do not want to # chose one over the other, and consider auto-detection not possible. if test -z "$PATH_SEPARATOR"; then # User should provide the correct 'PATH_SEPARATOR' definition. # Until then, guess that it is colon! echo "$xc_msg_warn path separator not determined, guessing colon" >&2 PATH_SEPARATOR=':' fi else # Separator with the greater directory count is the auto-detected one. if test $xc_tst_dirs_sem -gt $xc_tst_dirs_col; then xc_tst_auto_separator=';' else xc_tst_auto_separator=':' fi if test -z "$PATH_SEPARATOR"; then # Simply use the auto-detected one when not already set. PATH_SEPARATOR=$xc_tst_auto_separator elif test "x$PATH_SEPARATOR" != "x$xc_tst_auto_separator"; then echo "$xc_msg_warn 'PATH_SEPARATOR' does not match auto-detected one." >&2 fi fi xc_PATH_SEPARATOR=$PATH_SEPARATOR AC_SUBST([PATH_SEPARATOR])dnl ]) dnl _XC_CFG_PRE_POSTLUDE dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_CFG_PRE_POSTLUDE], [dnl AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl AC_REQUIRE([_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl dnl xc_configure_preamble_result='yes' ]) dnl XC_CONFIGURE_PREAMBLE dnl ------------------------------------------------- dnl Public macro. dnl dnl This macro emits shell code which does some dnl very basic checks related with the availability dnl of some commands and utilities needed to allow dnl configure script bootstrapping itself when using dnl these to figure out other settings. Also emits dnl code that performs PATH_SEPARATOR auto-detection dnl and sets its value unless it is already set with dnl a non-empty value. dnl dnl These basic checks are intended to be placed and dnl executed as early as possible in the resulting dnl configure script, and as such these must be pure dnl and portable shell code. dnl dnl This macro may be used directly, or indirectly dnl when using other macros that AC_REQUIRE it such dnl as XC_CHECK_PATH_SEPARATOR. dnl dnl Currently the mechanism used to ensure that this dnl macro expands early enough in generated configure dnl script is making it override autoconf and libtool dnl PATH_SEPARATOR check. AC_DEFUN([XC_CONFIGURE_PREAMBLE], [dnl AC_PREREQ([2.50])dnl dnl AC_BEFORE([$0],[_XC_CFG_PRE_PREAMBLE])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl AC_BEFORE([$0],[_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl AC_BEFORE([$0],[_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl AC_BEFORE([$0],[_XC_CFG_PRE_POSTLUDE])dnl dnl AC_BEFORE([$0],[AC_CHECK_TOOL])dnl AC_BEFORE([$0],[AC_CHECK_PROG])dnl AC_BEFORE([$0],[AC_CHECK_TOOLS])dnl AC_BEFORE([$0],[AC_CHECK_PROGS])dnl dnl AC_BEFORE([$0],[AC_PATH_TOOL])dnl AC_BEFORE([$0],[AC_PATH_PROG])dnl AC_BEFORE([$0],[AC_PATH_PROGS])dnl dnl AC_BEFORE([$0],[AC_PROG_SED])dnl AC_BEFORE([$0],[AC_PROG_GREP])dnl AC_BEFORE([$0],[AC_PROG_LN_S])dnl AC_BEFORE([$0],[AC_PROG_MKDIR_P])dnl AC_BEFORE([$0],[AC_PROG_INSTALL])dnl AC_BEFORE([$0],[AC_PROG_MAKE_SET])dnl AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl dnl AC_BEFORE([$0],[LT_INIT])dnl AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl dnl AC_REQUIRE([_XC_CFG_PRE_PREAMBLE])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_ECHO])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_TEST])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_VAR_PATH])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_CMD_EXPR])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_SED])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_GREP])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_TR])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_WC])dnl AC_REQUIRE([_XC_CFG_PRE_BASIC_CHK_UTIL_CAT])dnl AC_REQUIRE([_XC_CFG_PRE_CHECK_PATH_SEPARATOR])dnl AC_REQUIRE([_XC_CFG_PRE_POSTLUDE])dnl dnl m4_pattern_forbid([^_*XC])dnl m4_define([$0],[])dnl ]) dnl Override autoconf and libtool PATH_SEPARATOR check dnl ------------------------------------------------- dnl Macros overriding. dnl dnl This is done to ensure that the same check is dnl used across different autoconf versions and to dnl allow expansion of XC_CONFIGURE_PREAMBLE macro dnl early enough in the generated configure script. dnl dnl Override when using autoconf 2.53 and newer. dnl m4_ifdef([_AS_PATH_SEPARATOR_PREPARE], [dnl m4_undefine([_AS_PATH_SEPARATOR_PREPARE])dnl m4_defun([_AS_PATH_SEPARATOR_PREPARE], [dnl AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl m4_define([$0],[])dnl ])dnl ]) dnl dnl Override when using autoconf 2.50 to 2.52 dnl m4_ifdef([_AC_INIT_PREPARE_FS_SEPARATORS], [dnl m4_undefine([_AC_INIT_PREPARE_FS_SEPARATORS])dnl m4_defun([_AC_INIT_PREPARE_FS_SEPARATORS], [dnl AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl ac_path_separator=$PATH_SEPARATOR m4_define([$0],[])dnl ])dnl ]) dnl dnl Override when using libtool 1.4.2 dnl m4_ifdef([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], [dnl m4_undefine([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl m4_defun([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR], [dnl AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl lt_cv_sys_path_separator=$PATH_SEPARATOR m4_define([$0],[])dnl ])dnl ]) dnl XC_CHECK_PATH_SEPARATOR dnl ------------------------------------------------- dnl Public macro. dnl dnl Usage of this macro ensures that generated configure dnl script uses the same PATH_SEPARATOR check irrespective dnl of autoconf or libtool version being used to generate dnl configure script. dnl dnl Emits shell code that computes the path separator dnl and stores the result in 'PATH_SEPARATOR', unless dnl the user has already set it with a non-empty value. dnl dnl This path separator is the symbol used to separate dnl or diferentiate paths inside the 'PATH' environment dnl variable. dnl dnl Non-empty user provided 'PATH_SEPARATOR' always dnl overrides the auto-detected one. dnl dnl Strictly speaking the check is done in two steps. The dnl first, which does the actual check, takes place in dnl XC_CONFIGURE_PREAMBLE macro and happens very early in dnl generated configure script. The second one shows and dnl logs the result of the check into config.log at a later dnl configure stage. Placement of this second stage in dnl generated configure script will be done where first dnl direct or indirect usage of this macro happens. AC_DEFUN([XC_CHECK_PATH_SEPARATOR], [dnl AC_PREREQ([2.50])dnl dnl AC_BEFORE([$0],[AC_CHECK_TOOL])dnl AC_BEFORE([$0],[AC_CHECK_PROG])dnl AC_BEFORE([$0],[AC_CHECK_TOOLS])dnl AC_BEFORE([$0],[AC_CHECK_PROGS])dnl dnl AC_BEFORE([$0],[AC_PATH_TOOL])dnl AC_BEFORE([$0],[AC_PATH_PROG])dnl AC_BEFORE([$0],[AC_PATH_PROGS])dnl dnl AC_BEFORE([$0],[AC_PROG_SED])dnl AC_BEFORE([$0],[AC_PROG_GREP])dnl AC_BEFORE([$0],[AC_PROG_LN_S])dnl AC_BEFORE([$0],[AC_PROG_MKDIR_P])dnl AC_BEFORE([$0],[AC_PROG_INSTALL])dnl AC_BEFORE([$0],[AC_PROG_MAKE_SET])dnl AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl dnl AC_BEFORE([$0],[LT_INIT])dnl AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl dnl AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl dnl # # Check that 'XC_CONFIGURE_PREAMBLE' has already run. # if test -z "$xc_configure_preamble_result"; then AC_MSG_ERROR([xc_configure_preamble_result not set (internal problem)]) fi # # Check that 'PATH_SEPARATOR' has already been set. # if test -z "$xc_PATH_SEPARATOR"; then AC_MSG_ERROR([xc_PATH_SEPARATOR not set (internal problem)]) fi if test -z "$PATH_SEPARATOR"; then AC_MSG_ERROR([PATH_SEPARATOR not set (internal or config.site problem)]) fi AC_MSG_CHECKING([for path separator]) AC_MSG_RESULT([$PATH_SEPARATOR]) if test "x$PATH_SEPARATOR" != "x$xc_PATH_SEPARATOR"; then AC_MSG_CHECKING([for initial path separator]) AC_MSG_RESULT([$xc_PATH_SEPARATOR]) AC_MSG_ERROR([path separator mismatch (internal or config.site problem)]) fi dnl m4_pattern_forbid([^_*XC])dnl m4_define([$0],[])dnl ]) davix-0.8.0/deps/curl/m4/curl-reentrant.m40000644000000000000000000003726014121063461016765 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 10 dnl Note 1 dnl ------ dnl None of the CURL_CHECK_NEED_REENTRANT_* macros shall use HAVE_FOO_H to dnl conditionally include header files. These macros are used early in the dnl configure process much before header file availability is known. dnl CURL_CHECK_NEED_REENTRANT_ERRNO dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes errno available as a preprocessor macro. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_ERRNO], [ AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include ]],[[ if(0 != errno) return 1; ]]) ],[ tmp_errno="yes" ],[ tmp_errno="no" ]) if test "$tmp_errno" = "yes"; then AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include ]],[[ #ifdef errno int dummy=1; #else force compilation error #endif ]]) ],[ tmp_errno="errno_macro_defined" ],[ AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #define _REENTRANT #include ]],[[ #ifdef errno int dummy=1; #else force compilation error #endif ]]) ],[ tmp_errno="errno_macro_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_GMTIME_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function gmtime_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GMTIME_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gmtime_r]) ],[ tmp_gmtime_r="yes" ],[ tmp_gmtime_r="no" ]) if test "$tmp_gmtime_r" = "yes"; then AC_EGREP_CPP([gmtime_r],[ #include #include ],[ tmp_gmtime_r="proto_declared" ],[ AC_EGREP_CPP([gmtime_r],[ #define _REENTRANT #include #include ],[ tmp_gmtime_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_LOCALTIME_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function localtime_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_LOCALTIME_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([localtime_r]) ],[ tmp_localtime_r="yes" ],[ tmp_localtime_r="no" ]) if test "$tmp_localtime_r" = "yes"; then AC_EGREP_CPP([localtime_r],[ #include #include ],[ tmp_localtime_r="proto_declared" ],[ AC_EGREP_CPP([localtime_r],[ #define _REENTRANT #include #include ],[ tmp_localtime_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_STRERROR_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function strerror_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_STRERROR_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strerror_r]) ],[ tmp_strerror_r="yes" ],[ tmp_strerror_r="no" ]) if test "$tmp_strerror_r" = "yes"; then AC_EGREP_CPP([strerror_r],[ #include #include ],[ tmp_strerror_r="proto_declared" ],[ AC_EGREP_CPP([strerror_r],[ #define _REENTRANT #include #include ],[ tmp_strerror_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_STRTOK_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function strtok_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_STRTOK_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strtok_r]) ],[ tmp_strtok_r="yes" ],[ tmp_strtok_r="no" ]) if test "$tmp_strtok_r" = "yes"; then AC_EGREP_CPP([strtok_r],[ #include #include ],[ tmp_strtok_r="proto_declared" ],[ AC_EGREP_CPP([strtok_r],[ #define _REENTRANT #include #include ],[ tmp_strtok_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_INET_NTOA_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function inet_ntoa_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_INET_NTOA_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([inet_ntoa_r]) ],[ tmp_inet_ntoa_r="yes" ],[ tmp_inet_ntoa_r="no" ]) if test "$tmp_inet_ntoa_r" = "yes"; then AC_EGREP_CPP([inet_ntoa_r],[ #include #include #include #include ],[ tmp_inet_ntoa_r="proto_declared" ],[ AC_EGREP_CPP([inet_ntoa_r],[ #define _REENTRANT #include #include #include #include ],[ tmp_inet_ntoa_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_GETHOSTBYADDR_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function gethostbyaddr_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETHOSTBYADDR_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gethostbyaddr_r]) ],[ tmp_gethostbyaddr_r="yes" ],[ tmp_gethostbyaddr_r="no" ]) if test "$tmp_gethostbyaddr_r" = "yes"; then AC_EGREP_CPP([gethostbyaddr_r],[ #include #include ],[ tmp_gethostbyaddr_r="proto_declared" ],[ AC_EGREP_CPP([gethostbyaddr_r],[ #define _REENTRANT #include #include ],[ tmp_gethostbyaddr_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function gethostbyname_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gethostbyname_r]) ],[ tmp_gethostbyname_r="yes" ],[ tmp_gethostbyname_r="no" ]) if test "$tmp_gethostbyname_r" = "yes"; then AC_EGREP_CPP([gethostbyname_r],[ #include #include ],[ tmp_gethostbyname_r="proto_declared" ],[ AC_EGREP_CPP([gethostbyname_r],[ #define _REENTRANT #include #include ],[ tmp_gethostbyname_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function getprotobyname_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([getprotobyname_r]) ],[ tmp_getprotobyname_r="yes" ],[ tmp_getprotobyname_r="no" ]) if test "$tmp_getprotobyname_r" = "yes"; then AC_EGREP_CPP([getprotobyname_r],[ #include #include ],[ tmp_getprotobyname_r="proto_declared" ],[ AC_EGREP_CPP([getprotobyname_r],[ #define _REENTRANT #include #include ],[ tmp_getprotobyname_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_GETSERVBYPORT_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes function getservbyport_r compiler visible. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_GETSERVBYPORT_R], [ AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([getservbyport_r]) ],[ tmp_getservbyport_r="yes" ],[ tmp_getservbyport_r="no" ]) if test "$tmp_getservbyport_r" = "yes"; then AC_EGREP_CPP([getservbyport_r],[ #include #include ],[ tmp_getservbyport_r="proto_declared" ],[ AC_EGREP_CPP([getservbyport_r],[ #define _REENTRANT #include #include ],[ tmp_getservbyport_r="proto_needs_reentrant" tmp_need_reentrant="yes" ]) ]) fi ]) dnl CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl makes several _r functions compiler visible. dnl Internal macro for CURL_CONFIGURE_REENTRANT. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R], [ if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_GMTIME_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_LOCALTIME_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_STRERROR_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_STRTOK_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_INET_NTOA_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_GETHOSTBYADDR_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_GETHOSTBYNAME_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_GETPROTOBYNAME_R fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_GETSERVBYPORT_R fi ]) dnl CURL_CHECK_NEED_REENTRANT_SYSTEM dnl ------------------------------------------------- dnl Checks if the preprocessor _REENTRANT definition dnl must be unconditionally done for this platform. dnl Internal macro for CURL_CONFIGURE_REENTRANT. AC_DEFUN([CURL_CHECK_NEED_REENTRANT_SYSTEM], [ case $host_os in solaris*) tmp_need_reentrant="yes" ;; *) tmp_need_reentrant="no" ;; esac ]) dnl CURL_CHECK_NEED_THREAD_SAFE_SYSTEM dnl ------------------------------------------------- dnl Checks if the preprocessor _THREAD_SAFE definition dnl must be unconditionally done for this platform. dnl Internal macro for CURL_CONFIGURE_THREAD_SAFE. AC_DEFUN([CURL_CHECK_NEED_THREAD_SAFE_SYSTEM], [ case $host_os in aix[[123]].* | aix4.[[012]].*) dnl aix 4.2 and older tmp_need_thread_safe="no" ;; aix*) dnl AIX 4.3 and newer tmp_need_thread_safe="yes" ;; *) tmp_need_thread_safe="no" ;; esac ]) dnl CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT dnl ------------------------------------------------- dnl This macro ensures that configuration tests done dnl after this will execute with preprocessor symbol dnl _REENTRANT defined. This macro also ensures that dnl the generated config file defines NEED_REENTRANT dnl and that in turn curl_setup.h will define _REENTRANT. dnl Internal macro for CURL_CONFIGURE_REENTRANT. AC_DEFUN([CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT], [ AC_DEFINE(NEED_REENTRANT, 1, [Define to 1 if _REENTRANT preprocessor symbol must be defined.]) cat >>confdefs.h <<_EOF #ifndef _REENTRANT # define _REENTRANT #endif _EOF ]) dnl CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE dnl ------------------------------------------------- dnl This macro ensures that configuration tests done dnl after this will execute with preprocessor symbol dnl _THREAD_SAFE defined. This macro also ensures that dnl the generated config file defines NEED_THREAD_SAFE dnl and that in turn curl_setup.h will define _THREAD_SAFE. dnl Internal macro for CURL_CONFIGURE_THREAD_SAFE. AC_DEFUN([CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE], [ AC_DEFINE(NEED_THREAD_SAFE, 1, [Define to 1 if _THREAD_SAFE preprocessor symbol must be defined.]) cat >>confdefs.h <<_EOF #ifndef _THREAD_SAFE # define _THREAD_SAFE #endif _EOF ]) dnl CURL_CONFIGURE_REENTRANT dnl ------------------------------------------------- dnl This first checks if the preprocessor _REENTRANT dnl symbol is already defined. If it isn't currently dnl defined a set of checks are performed to verify dnl if its definition is required to make visible to dnl the compiler a set of *_r functions. Finally, if dnl _REENTRANT is already defined or needed it takes dnl care of making adjustments necessary to ensure dnl that it is defined equally for further configure dnl tests and generated config file. AC_DEFUN([CURL_CONFIGURE_REENTRANT], [ AC_PREREQ([2.50])dnl # AC_MSG_CHECKING([if _REENTRANT is already defined]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ #ifdef _REENTRANT int dummy=1; #else force compilation error #endif ]]) ],[ AC_MSG_RESULT([yes]) tmp_reentrant_initially_defined="yes" ],[ AC_MSG_RESULT([no]) tmp_reentrant_initially_defined="no" ]) # if test "$tmp_reentrant_initially_defined" = "no"; then AC_MSG_CHECKING([if _REENTRANT is actually needed]) CURL_CHECK_NEED_REENTRANT_SYSTEM if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_ERRNO fi if test "$tmp_need_reentrant" = "no"; then CURL_CHECK_NEED_REENTRANT_FUNCTIONS_R fi if test "$tmp_need_reentrant" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # AC_MSG_CHECKING([if _REENTRANT is onwards defined]) if test "$tmp_reentrant_initially_defined" = "yes" || test "$tmp_need_reentrant" = "yes"; then CURL_CONFIGURE_FROM_NOW_ON_WITH_REENTRANT AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi # ]) dnl CURL_CONFIGURE_THREAD_SAFE dnl ------------------------------------------------- dnl This first checks if the preprocessor _THREAD_SAFE dnl symbol is already defined. If it isn't currently dnl defined a set of checks are performed to verify dnl if its definition is required. Finally, if dnl _THREAD_SAFE is already defined or needed it takes dnl care of making adjustments necessary to ensure dnl that it is defined equally for further configure dnl tests and generated config file. AC_DEFUN([CURL_CONFIGURE_THREAD_SAFE], [ AC_PREREQ([2.50])dnl # AC_MSG_CHECKING([if _THREAD_SAFE is already defined]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ #ifdef _THREAD_SAFE int dummy=1; #else force compilation error #endif ]]) ],[ AC_MSG_RESULT([yes]) tmp_thread_safe_initially_defined="yes" ],[ AC_MSG_RESULT([no]) tmp_thread_safe_initially_defined="no" ]) # if test "$tmp_thread_safe_initially_defined" = "no"; then AC_MSG_CHECKING([if _THREAD_SAFE is actually needed]) CURL_CHECK_NEED_THREAD_SAFE_SYSTEM if test "$tmp_need_thread_safe" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # AC_MSG_CHECKING([if _THREAD_SAFE is onwards defined]) if test "$tmp_thread_safe_initially_defined" = "yes" || test "$tmp_need_thread_safe" = "yes"; then CURL_CONFIGURE_FROM_NOW_ON_WITH_THREAD_SAFE AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi # ]) davix-0.8.0/deps/curl/m4/curl-functions.m40000644000000000000000000060700714121063461016775 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 73 dnl CURL_INCLUDES_ARPA_INET dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when arpa/inet.h is to be included. AC_DEFUN([CURL_INCLUDES_ARPA_INET], [ curl_includes_arpa_inet="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_WINSOCK2_H #include #include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/socket.h netinet/in.h arpa/inet.h, [], [], [$curl_includes_arpa_inet]) ]) dnl CURL_INCLUDES_FCNTL dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when fcntl.h is to be included. AC_DEFUN([CURL_INCLUDES_FCNTL], [ curl_includes_fcntl="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_FCNTL_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h unistd.h fcntl.h, [], [], [$curl_includes_fcntl]) ]) dnl CURL_INCLUDES_IFADDRS dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when ifaddrs.h is to be included. AC_DEFUN([CURL_INCLUDES_IFADDRS], [ curl_includes_ifaddrs="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/socket.h netinet/in.h ifaddrs.h, [], [], [$curl_includes_ifaddrs]) ]) dnl CURL_INCLUDES_INTTYPES dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when inttypes.h is to be included. AC_DEFUN([CURL_INCLUDES_INTTYPES], [ curl_includes_inttypes="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif /* includes end */" case $host_os in irix*) ac_cv_header_stdint_h="no" ;; esac AC_CHECK_HEADERS( sys/types.h stdint.h inttypes.h, [], [], [$curl_includes_inttypes]) ]) dnl CURL_INCLUDES_LIBGEN dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when libgen.h is to be included. AC_DEFUN([CURL_INCLUDES_LIBGEN], [ curl_includes_libgen="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_LIBGEN_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h libgen.h, [], [], [$curl_includes_libgen]) ]) dnl CURL_INCLUDES_NETDB dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when netdb.h is to be included. AC_DEFUN([CURL_INCLUDES_NETDB], [ curl_includes_netdb="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETDB_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h netdb.h, [], [], [$curl_includes_netdb]) ]) dnl CURL_INCLUDES_POLL dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when poll.h is to be included. AC_DEFUN([CURL_INCLUDES_POLL], [ curl_includes_poll="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_POLL_H # include #endif #ifdef HAVE_SYS_POLL_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h poll.h sys/poll.h, [], [], [$curl_includes_poll]) ]) dnl CURL_INCLUDES_SETJMP dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when setjmp.h is to be included. AC_DEFUN([CURL_INCLUDES_SETJMP], [ curl_includes_setjmp="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SETJMP_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h setjmp.h, [], [], [$curl_includes_setjmp]) ]) dnl CURL_INCLUDES_SIGNAL dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when signal.h is to be included. AC_DEFUN([CURL_INCLUDES_SIGNAL], [ curl_includes_signal="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SIGNAL_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h signal.h, [], [], [$curl_includes_signal]) ]) dnl CURL_INCLUDES_SOCKET dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when socket.h is to be included. AC_DEFUN([CURL_INCLUDES_SOCKET], [ curl_includes_socket="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SOCKET_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h socket.h, [], [], [$curl_includes_socket]) ]) dnl CURL_INCLUDES_STDIO dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when stdio.h is to be included. AC_DEFUN([CURL_INCLUDES_STDIO], [ curl_includes_stdio="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_STDIO_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h stdio.h, [], [], [$curl_includes_stdio]) ]) dnl CURL_INCLUDES_STDLIB dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when stdlib.h is to be included. AC_DEFUN([CURL_INCLUDES_STDLIB], [ curl_includes_stdlib="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_STDLIB_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h stdlib.h, [], [], [$curl_includes_stdlib]) ]) dnl CURL_INCLUDES_STRING dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when string(s).h is to be included. AC_DEFUN([CURL_INCLUDES_STRING], [ curl_includes_string="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h string.h strings.h, [], [], [$curl_includes_string]) ]) dnl CURL_INCLUDES_STROPTS dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when stropts.h is to be included. AC_DEFUN([CURL_INCLUDES_STROPTS], [ curl_includes_stropts="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_STROPTS_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h unistd.h sys/socket.h sys/ioctl.h stropts.h, [], [], [$curl_includes_stropts]) ]) dnl CURL_INCLUDES_SYS_SOCKET dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when sys/socket.h is to be included. AC_DEFUN([CURL_INCLUDES_SYS_SOCKET], [ curl_includes_sys_socket="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/socket.h, [], [], [$curl_includes_sys_socket]) ]) dnl CURL_INCLUDES_SYS_TYPES dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when sys/types.h is to be included. AC_DEFUN([CURL_INCLUDES_SYS_TYPES], [ curl_includes_sys_types="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h, [], [], [$curl_includes_sys_types]) ]) dnl CURL_INCLUDES_SYS_UIO dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when sys/uio.h is to be included. AC_DEFUN([CURL_INCLUDES_SYS_UIO], [ curl_includes_sys_uio="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_UIO_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/uio.h, [], [], [$curl_includes_sys_uio]) ]) dnl CURL_INCLUDES_SYS_XATTR dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when sys/xattr.h is to be included. AC_DEFUN([CURL_INCLUDES_SYS_XATTR], [ curl_includes_sys_xattr="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_XATTR_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/xattr.h, [], [], [$curl_includes_sys_xattr]) ]) dnl CURL_INCLUDES_TIME dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when time.h is to be included. AC_DEFUN([CURL_INCLUDES_TIME], [ AC_REQUIRE([AC_HEADER_TIME])dnl curl_includes_time="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_TIME_H # include # ifdef TIME_WITH_SYS_TIME # include # endif #else # ifdef HAVE_TIME_H # include # endif #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h sys/time.h time.h, [], [], [$curl_includes_time]) ]) dnl CURL_INCLUDES_UNISTD dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when unistd.h is to be included. AC_DEFUN([CURL_INCLUDES_UNISTD], [ curl_includes_unistd="\ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif /* includes end */" AC_CHECK_HEADERS( sys/types.h unistd.h, [], [], [$curl_includes_unistd]) ]) dnl CURL_INCLUDES_WINSOCK2 dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when winsock(2).h is to be included. AC_DEFUN([CURL_INCLUDES_WINSOCK2], [ curl_includes_winsock2="\ /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif /* includes end */" CURL_CHECK_HEADER_WINDOWS CURL_CHECK_HEADER_WINSOCK CURL_CHECK_HEADER_WINSOCK2 ]) dnl CURL_INCLUDES_WS2TCPIP dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when ws2tcpip.h is to be included. AC_DEFUN([CURL_INCLUDES_WS2TCPIP], [ curl_includes_ws2tcpip="\ /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H # include # endif # endif #endif /* includes end */" CURL_CHECK_HEADER_WINDOWS CURL_CHECK_HEADER_WINSOCK2 CURL_CHECK_HEADER_WS2TCPIP ]) dnl CURL_INCLUDES_BSDSOCKET dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when bsdsocket.h is to be included. AC_DEFUN([CURL_INCLUDES_BSDSOCKET], [ curl_includes_bsdsocket="\ /* includes start */ #ifdef HAVE_PROTO_BSDSOCKET_H # include struct Library *SocketBase = NULL; #endif /* includes end */" AC_CHECK_HEADERS( proto/bsdsocket.h, [], [], [ $curl_includes_bsdsocket]) ]) dnl CURL_INCLUDES_NETIF dnl ------------------------------------------------- dnl Set up variable with list of headers that must be dnl included when net/if.h is to be included. AC_DEFUN([CURL_INCLUDES_NETIF], [ curl_includes_netif="\ /* includes start */ #ifdef HAVE_NET_IF_H # include #endif /* includes end */" AC_CHECK_HEADERS( net/if.h, [], [], [$curl_includes_netif]) ]) dnl CURL_PREPROCESS_CALLCONV dnl ------------------------------------------------- dnl Set up variable with a preprocessor block which dnl defines function calling convention. AC_DEFUN([CURL_PREPROCESS_CALLCONV], [ curl_preprocess_callconv="\ /* preprocess start */ #ifdef HAVE_WINDOWS_H # define FUNCALLCONV __stdcall #else # define FUNCALLCONV #endif /* preprocess end */" ]) dnl CURL_CHECK_FUNC_ALARM dnl ------------------------------------------------- dnl Verify if alarm is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_alarm, then dnl HAVE_ALARM will be defined. AC_DEFUN([CURL_CHECK_FUNC_ALARM], [ AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl # tst_links_alarm="unknown" tst_proto_alarm="unknown" tst_compi_alarm="unknown" tst_allow_alarm="unknown" # AC_MSG_CHECKING([if alarm can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([alarm]) ],[ AC_MSG_RESULT([yes]) tst_links_alarm="yes" ],[ AC_MSG_RESULT([no]) tst_links_alarm="no" ]) # if test "$tst_links_alarm" = "yes"; then AC_MSG_CHECKING([if alarm is prototyped]) AC_EGREP_CPP([alarm],[ $curl_includes_unistd ],[ AC_MSG_RESULT([yes]) tst_proto_alarm="yes" ],[ AC_MSG_RESULT([no]) tst_proto_alarm="no" ]) fi # if test "$tst_proto_alarm" = "yes"; then AC_MSG_CHECKING([if alarm is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_unistd ]],[[ if(0 != alarm(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_alarm="yes" ],[ AC_MSG_RESULT([no]) tst_compi_alarm="no" ]) fi # if test "$tst_compi_alarm" = "yes"; then AC_MSG_CHECKING([if alarm usage allowed]) if test "x$curl_disallow_alarm" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_alarm="yes" else AC_MSG_RESULT([no]) tst_allow_alarm="no" fi fi # AC_MSG_CHECKING([if alarm might be used]) if test "$tst_links_alarm" = "yes" && test "$tst_proto_alarm" = "yes" && test "$tst_compi_alarm" = "yes" && test "$tst_allow_alarm" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_ALARM, 1, [Define to 1 if you have the alarm function.]) curl_cv_func_alarm="yes" else AC_MSG_RESULT([no]) curl_cv_func_alarm="no" fi ]) dnl CURL_CHECK_FUNC_BASENAME dnl ------------------------------------------------- dnl Verify if basename is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_basename, then dnl HAVE_BASENAME will be defined. AC_DEFUN([CURL_CHECK_FUNC_BASENAME], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl AC_REQUIRE([CURL_INCLUDES_LIBGEN])dnl AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl # tst_links_basename="unknown" tst_proto_basename="unknown" tst_compi_basename="unknown" tst_allow_basename="unknown" # AC_MSG_CHECKING([if basename can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([basename]) ],[ AC_MSG_RESULT([yes]) tst_links_basename="yes" ],[ AC_MSG_RESULT([no]) tst_links_basename="no" ]) # if test "$tst_links_basename" = "yes"; then AC_MSG_CHECKING([if basename is prototyped]) AC_EGREP_CPP([basename],[ $curl_includes_string $curl_includes_libgen $curl_includes_unistd ],[ AC_MSG_RESULT([yes]) tst_proto_basename="yes" ],[ AC_MSG_RESULT([no]) tst_proto_basename="no" ]) fi # if test "$tst_proto_basename" = "yes"; then AC_MSG_CHECKING([if basename is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string $curl_includes_libgen $curl_includes_unistd ]],[[ if(0 != basename(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_basename="yes" ],[ AC_MSG_RESULT([no]) tst_compi_basename="no" ]) fi # if test "$tst_compi_basename" = "yes"; then AC_MSG_CHECKING([if basename usage allowed]) if test "x$curl_disallow_basename" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_basename="yes" else AC_MSG_RESULT([no]) tst_allow_basename="no" fi fi # AC_MSG_CHECKING([if basename might be used]) if test "$tst_links_basename" = "yes" && test "$tst_proto_basename" = "yes" && test "$tst_compi_basename" = "yes" && test "$tst_allow_basename" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_BASENAME, 1, [Define to 1 if you have the basename function.]) curl_cv_func_basename="yes" else AC_MSG_RESULT([no]) curl_cv_func_basename="no" fi ]) dnl CURL_CHECK_FUNC_CLOSESOCKET dnl ------------------------------------------------- dnl Verify if closesocket is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_closesocket, then dnl HAVE_CLOSESOCKET will be defined. AC_DEFUN([CURL_CHECK_FUNC_CLOSESOCKET], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl # tst_links_closesocket="unknown" tst_proto_closesocket="unknown" tst_compi_closesocket="unknown" tst_allow_closesocket="unknown" # AC_MSG_CHECKING([if closesocket can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_socket ]],[[ if(0 != closesocket(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_closesocket="yes" ],[ AC_MSG_RESULT([no]) tst_links_closesocket="no" ]) # if test "$tst_links_closesocket" = "yes"; then AC_MSG_CHECKING([if closesocket is prototyped]) AC_EGREP_CPP([closesocket],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_socket ],[ AC_MSG_RESULT([yes]) tst_proto_closesocket="yes" ],[ AC_MSG_RESULT([no]) tst_proto_closesocket="no" ]) fi # if test "$tst_proto_closesocket" = "yes"; then AC_MSG_CHECKING([if closesocket is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_socket ]],[[ if(0 != closesocket(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_closesocket="yes" ],[ AC_MSG_RESULT([no]) tst_compi_closesocket="no" ]) fi # if test "$tst_compi_closesocket" = "yes"; then AC_MSG_CHECKING([if closesocket usage allowed]) if test "x$curl_disallow_closesocket" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_closesocket="yes" else AC_MSG_RESULT([no]) tst_allow_closesocket="no" fi fi # AC_MSG_CHECKING([if closesocket might be used]) if test "$tst_links_closesocket" = "yes" && test "$tst_proto_closesocket" = "yes" && test "$tst_compi_closesocket" = "yes" && test "$tst_allow_closesocket" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_CLOSESOCKET, 1, [Define to 1 if you have the closesocket function.]) curl_cv_func_closesocket="yes" else AC_MSG_RESULT([no]) curl_cv_func_closesocket="no" fi ]) dnl CURL_CHECK_FUNC_CLOSESOCKET_CAMEL dnl ------------------------------------------------- dnl Verify if CloseSocket is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_closesocket_camel, dnl then HAVE_CLOSESOCKET_CAMEL will be defined. AC_DEFUN([CURL_CHECK_FUNC_CLOSESOCKET_CAMEL], [ AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl # tst_links_closesocket_camel="unknown" tst_proto_closesocket_camel="unknown" tst_compi_closesocket_camel="unknown" tst_allow_closesocket_camel="unknown" # AC_MSG_CHECKING([if CloseSocket can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_socket ]],[[ if(0 != CloseSocket(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_closesocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_links_closesocket_camel="no" ]) # if test "$tst_links_closesocket_camel" = "yes"; then AC_MSG_CHECKING([if CloseSocket is prototyped]) AC_EGREP_CPP([CloseSocket],[ $curl_includes_sys_socket ],[ AC_MSG_RESULT([yes]) tst_proto_closesocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_proto_closesocket_camel="no" ]) fi # if test "$tst_proto_closesocket_camel" = "yes"; then AC_MSG_CHECKING([if CloseSocket is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_socket ]],[[ if(0 != CloseSocket(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_closesocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_compi_closesocket_camel="no" ]) fi # if test "$tst_compi_closesocket_camel" = "yes"; then AC_MSG_CHECKING([if CloseSocket usage allowed]) if test "x$curl_disallow_closesocket_camel" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_closesocket_camel="yes" else AC_MSG_RESULT([no]) tst_allow_closesocket_camel="no" fi fi # AC_MSG_CHECKING([if CloseSocket might be used]) if test "$tst_links_closesocket_camel" = "yes" && test "$tst_proto_closesocket_camel" = "yes" && test "$tst_compi_closesocket_camel" = "yes" && test "$tst_allow_closesocket_camel" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_CLOSESOCKET_CAMEL, 1, [Define to 1 if you have the CloseSocket camel case function.]) curl_cv_func_closesocket_camel="yes" else AC_MSG_RESULT([no]) curl_cv_func_closesocket_camel="no" fi ]) dnl CURL_CHECK_FUNC_CONNECT dnl ------------------------------------------------- dnl Verify if connect is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_connect, then dnl HAVE_CONNECT will be defined. AC_DEFUN([CURL_CHECK_FUNC_CONNECT], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl # tst_links_connect="unknown" tst_proto_connect="unknown" tst_compi_connect="unknown" tst_allow_connect="unknown" # AC_MSG_CHECKING([if connect can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ]],[[ if(0 != connect(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_connect="yes" ],[ AC_MSG_RESULT([no]) tst_links_connect="no" ]) # if test "$tst_links_connect" = "yes"; then AC_MSG_CHECKING([if connect is prototyped]) AC_EGREP_CPP([connect],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ],[ AC_MSG_RESULT([yes]) tst_proto_connect="yes" ],[ AC_MSG_RESULT([no]) tst_proto_connect="no" ]) fi # if test "$tst_proto_connect" = "yes"; then AC_MSG_CHECKING([if connect is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ]],[[ if(0 != connect(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_connect="yes" ],[ AC_MSG_RESULT([no]) tst_compi_connect="no" ]) fi # if test "$tst_compi_connect" = "yes"; then AC_MSG_CHECKING([if connect usage allowed]) if test "x$curl_disallow_connect" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_connect="yes" else AC_MSG_RESULT([no]) tst_allow_connect="no" fi fi # AC_MSG_CHECKING([if connect might be used]) if test "$tst_links_connect" = "yes" && test "$tst_proto_connect" = "yes" && test "$tst_compi_connect" = "yes" && test "$tst_allow_connect" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_CONNECT, 1, [Define to 1 if you have the connect function.]) curl_cv_func_connect="yes" else AC_MSG_RESULT([no]) curl_cv_func_connect="no" fi ]) dnl CURL_CHECK_FUNC_FCNTL dnl ------------------------------------------------- dnl Verify if fcntl is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_fcntl, then dnl HAVE_FCNTL will be defined. AC_DEFUN([CURL_CHECK_FUNC_FCNTL], [ AC_REQUIRE([CURL_INCLUDES_FCNTL])dnl # tst_links_fcntl="unknown" tst_proto_fcntl="unknown" tst_compi_fcntl="unknown" tst_allow_fcntl="unknown" # AC_MSG_CHECKING([if fcntl can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([fcntl]) ],[ AC_MSG_RESULT([yes]) tst_links_fcntl="yes" ],[ AC_MSG_RESULT([no]) tst_links_fcntl="no" ]) # if test "$tst_links_fcntl" = "yes"; then AC_MSG_CHECKING([if fcntl is prototyped]) AC_EGREP_CPP([fcntl],[ $curl_includes_fcntl ],[ AC_MSG_RESULT([yes]) tst_proto_fcntl="yes" ],[ AC_MSG_RESULT([no]) tst_proto_fcntl="no" ]) fi # if test "$tst_proto_fcntl" = "yes"; then AC_MSG_CHECKING([if fcntl is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_fcntl ]],[[ if(0 != fcntl(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fcntl="yes" ],[ AC_MSG_RESULT([no]) tst_compi_fcntl="no" ]) fi # if test "$tst_compi_fcntl" = "yes"; then AC_MSG_CHECKING([if fcntl usage allowed]) if test "x$curl_disallow_fcntl" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_fcntl="yes" else AC_MSG_RESULT([no]) tst_allow_fcntl="no" fi fi # AC_MSG_CHECKING([if fcntl might be used]) if test "$tst_links_fcntl" = "yes" && test "$tst_proto_fcntl" = "yes" && test "$tst_compi_fcntl" = "yes" && test "$tst_allow_fcntl" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FCNTL, 1, [Define to 1 if you have the fcntl function.]) curl_cv_func_fcntl="yes" CURL_CHECK_FUNC_FCNTL_O_NONBLOCK else AC_MSG_RESULT([no]) curl_cv_func_fcntl="no" fi ]) dnl CURL_CHECK_FUNC_FCNTL_O_NONBLOCK dnl ------------------------------------------------- dnl Verify if fcntl with status flag O_NONBLOCK is dnl available, can be compiled, and seems to work. If dnl all of these are true, then HAVE_FCNTL_O_NONBLOCK dnl will be defined. AC_DEFUN([CURL_CHECK_FUNC_FCNTL_O_NONBLOCK], [ # tst_compi_fcntl_o_nonblock="unknown" tst_allow_fcntl_o_nonblock="unknown" # case $host_os in sunos4* | aix3* | beos*) dnl O_NONBLOCK does not work on these platforms curl_disallow_fcntl_o_nonblock="yes" ;; esac # if test "$curl_cv_func_fcntl" = "yes"; then AC_MSG_CHECKING([if fcntl O_NONBLOCK is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_fcntl ]],[[ int flags = 0; if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fcntl_o_nonblock="yes" ],[ AC_MSG_RESULT([no]) tst_compi_fcntl_o_nonblock="no" ]) fi # if test "$tst_compi_fcntl_o_nonblock" = "yes"; then AC_MSG_CHECKING([if fcntl O_NONBLOCK usage allowed]) if test "x$curl_disallow_fcntl_o_nonblock" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_fcntl_o_nonblock="yes" else AC_MSG_RESULT([no]) tst_allow_fcntl_o_nonblock="no" fi fi # AC_MSG_CHECKING([if fcntl O_NONBLOCK might be used]) if test "$tst_compi_fcntl_o_nonblock" = "yes" && test "$tst_allow_fcntl_o_nonblock" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FCNTL_O_NONBLOCK, 1, [Define to 1 if you have a working fcntl O_NONBLOCK function.]) curl_cv_func_fcntl_o_nonblock="yes" else AC_MSG_RESULT([no]) curl_cv_func_fcntl_o_nonblock="no" fi ]) dnl CURL_CHECK_FUNC_FGETXATTR dnl ------------------------------------------------- dnl Verify if fgetxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_fgetxattr, then dnl HAVE_FGETXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_FGETXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_fgetxattr="unknown" tst_proto_fgetxattr="unknown" tst_compi_fgetxattr="unknown" tst_allow_fgetxattr="unknown" tst_nargs_fgetxattr="unknown" # AC_MSG_CHECKING([if fgetxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([fgetxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_fgetxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_fgetxattr="no" ]) # if test "$tst_links_fgetxattr" = "yes"; then AC_MSG_CHECKING([if fgetxattr is prototyped]) AC_EGREP_CPP([fgetxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_fgetxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_fgetxattr="no" ]) fi # if test "$tst_proto_fgetxattr" = "yes"; then if test "$tst_nargs_fgetxattr" = "unknown"; then AC_MSG_CHECKING([if fgetxattr takes 4 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fgetxattr(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fgetxattr="yes" tst_nargs_fgetxattr="4" ],[ AC_MSG_RESULT([no]) tst_compi_fgetxattr="no" ]) fi if test "$tst_nargs_fgetxattr" = "unknown"; then AC_MSG_CHECKING([if fgetxattr takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fgetxattr(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fgetxattr="yes" tst_nargs_fgetxattr="6" ],[ AC_MSG_RESULT([no]) tst_compi_fgetxattr="no" ]) fi AC_MSG_CHECKING([if fgetxattr is compilable]) if test "$tst_compi_fgetxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_fgetxattr" = "yes"; then AC_MSG_CHECKING([if fgetxattr usage allowed]) if test "x$curl_disallow_fgetxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_fgetxattr="yes" else AC_MSG_RESULT([no]) tst_allow_fgetxattr="no" fi fi # AC_MSG_CHECKING([if fgetxattr might be used]) if test "$tst_links_fgetxattr" = "yes" && test "$tst_proto_fgetxattr" = "yes" && test "$tst_compi_fgetxattr" = "yes" && test "$tst_allow_fgetxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FGETXATTR, 1, [Define to 1 if you have the fgetxattr function.]) dnl AC_DEFINE_UNQUOTED(FGETXATTR_ARGS, $tst_nargs_fgetxattr, dnl [Specifies the number of arguments to fgetxattr]) # if test "$tst_nargs_fgetxattr" -eq "4"; then AC_DEFINE(HAVE_FGETXATTR_4, 1, [fgetxattr() takes 4 args]) elif test "$tst_nargs_fgetxattr" -eq "6"; then AC_DEFINE(HAVE_FGETXATTR_6, 1, [fgetxattr() takes 6 args]) fi # curl_cv_func_fgetxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_fgetxattr="no" fi ]) dnl CURL_CHECK_FUNC_FLISTXATTR dnl ------------------------------------------------- dnl Verify if flistxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_flistxattr, then dnl HAVE_FLISTXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_FLISTXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_flistxattr="unknown" tst_proto_flistxattr="unknown" tst_compi_flistxattr="unknown" tst_allow_flistxattr="unknown" tst_nargs_flistxattr="unknown" # AC_MSG_CHECKING([if flistxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([flistxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_flistxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_flistxattr="no" ]) # if test "$tst_links_flistxattr" = "yes"; then AC_MSG_CHECKING([if flistxattr is prototyped]) AC_EGREP_CPP([flistxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_flistxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_flistxattr="no" ]) fi # if test "$tst_proto_flistxattr" = "yes"; then if test "$tst_nargs_flistxattr" = "unknown"; then AC_MSG_CHECKING([if flistxattr takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != flistxattr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_flistxattr="yes" tst_nargs_flistxattr="3" ],[ AC_MSG_RESULT([no]) tst_compi_flistxattr="no" ]) fi if test "$tst_nargs_flistxattr" = "unknown"; then AC_MSG_CHECKING([if flistxattr takes 4 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != flistxattr(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_flistxattr="yes" tst_nargs_flistxattr="4" ],[ AC_MSG_RESULT([no]) tst_compi_flistxattr="no" ]) fi AC_MSG_CHECKING([if flistxattr is compilable]) if test "$tst_compi_flistxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_flistxattr" = "yes"; then AC_MSG_CHECKING([if flistxattr usage allowed]) if test "x$curl_disallow_flistxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_flistxattr="yes" else AC_MSG_RESULT([no]) tst_allow_flistxattr="no" fi fi # AC_MSG_CHECKING([if flistxattr might be used]) if test "$tst_links_flistxattr" = "yes" && test "$tst_proto_flistxattr" = "yes" && test "$tst_compi_flistxattr" = "yes" && test "$tst_allow_flistxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FLISTXATTR, 1, [Define to 1 if you have the flistxattr function.]) dnl AC_DEFINE_UNQUOTED(FLISTXATTR_ARGS, $tst_nargs_flistxattr, dnl [Specifies the number of arguments to flistxattr]) # if test "$tst_nargs_flistxattr" -eq "3"; then AC_DEFINE(HAVE_FLISTXATTR_3, 1, [flistxattr() takes 3 args]) elif test "$tst_nargs_flistxattr" -eq "4"; then AC_DEFINE(HAVE_FLISTXATTR_4, 1, [flistxattr() takes 4 args]) fi # curl_cv_func_flistxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_flistxattr="no" fi ]) dnl CURL_CHECK_FUNC_FREEADDRINFO dnl ------------------------------------------------- dnl Verify if freeaddrinfo is available, prototyped, dnl and can be compiled. If all of these are true, dnl and usage has not been previously disallowed with dnl shell variable curl_disallow_freeaddrinfo, then dnl HAVE_FREEADDRINFO will be defined. AC_DEFUN([CURL_CHECK_FUNC_FREEADDRINFO], [ AC_REQUIRE([CURL_INCLUDES_WS2TCPIP])dnl AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_freeaddrinfo="unknown" tst_proto_freeaddrinfo="unknown" tst_compi_freeaddrinfo="unknown" tst_allow_freeaddrinfo="unknown" # AC_MSG_CHECKING([if freeaddrinfo can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ]],[[ freeaddrinfo(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_links_freeaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_links_freeaddrinfo="no" ]) # if test "$tst_links_freeaddrinfo" = "yes"; then AC_MSG_CHECKING([if freeaddrinfo is prototyped]) AC_EGREP_CPP([freeaddrinfo],[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_freeaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_proto_freeaddrinfo="no" ]) fi # if test "$tst_proto_freeaddrinfo" = "yes"; then AC_MSG_CHECKING([if freeaddrinfo is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ]],[[ freeaddrinfo(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_freeaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_compi_freeaddrinfo="no" ]) fi # if test "$tst_compi_freeaddrinfo" = "yes"; then AC_MSG_CHECKING([if freeaddrinfo usage allowed]) if test "x$curl_disallow_freeaddrinfo" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_freeaddrinfo="yes" else AC_MSG_RESULT([no]) tst_allow_freeaddrinfo="no" fi fi # AC_MSG_CHECKING([if freeaddrinfo might be used]) if test "$tst_links_freeaddrinfo" = "yes" && test "$tst_proto_freeaddrinfo" = "yes" && test "$tst_compi_freeaddrinfo" = "yes" && test "$tst_allow_freeaddrinfo" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FREEADDRINFO, 1, [Define to 1 if you have the freeaddrinfo function.]) curl_cv_func_freeaddrinfo="yes" else AC_MSG_RESULT([no]) curl_cv_func_freeaddrinfo="no" fi ]) dnl CURL_CHECK_FUNC_FREEIFADDRS dnl ------------------------------------------------- dnl Verify if freeifaddrs is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_freeifaddrs, then dnl HAVE_FREEIFADDRS will be defined. AC_DEFUN([CURL_CHECK_FUNC_FREEIFADDRS], [ AC_REQUIRE([CURL_INCLUDES_IFADDRS])dnl # tst_links_freeifaddrs="unknown" tst_proto_freeifaddrs="unknown" tst_compi_freeifaddrs="unknown" tst_allow_freeifaddrs="unknown" # AC_MSG_CHECKING([if freeifaddrs can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([freeifaddrs]) ],[ AC_MSG_RESULT([yes]) tst_links_freeifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_links_freeifaddrs="no" ]) # if test "$tst_links_freeifaddrs" = "yes"; then AC_MSG_CHECKING([if freeifaddrs is prototyped]) AC_EGREP_CPP([freeifaddrs],[ $curl_includes_ifaddrs ],[ AC_MSG_RESULT([yes]) tst_proto_freeifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_proto_freeifaddrs="no" ]) fi # if test "$tst_proto_freeifaddrs" = "yes"; then AC_MSG_CHECKING([if freeifaddrs is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ifaddrs ]],[[ freeifaddrs(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_freeifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_compi_freeifaddrs="no" ]) fi # if test "$tst_compi_freeifaddrs" = "yes"; then AC_MSG_CHECKING([if freeifaddrs usage allowed]) if test "x$curl_disallow_freeifaddrs" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_freeifaddrs="yes" else AC_MSG_RESULT([no]) tst_allow_freeifaddrs="no" fi fi # AC_MSG_CHECKING([if freeifaddrs might be used]) if test "$tst_links_freeifaddrs" = "yes" && test "$tst_proto_freeifaddrs" = "yes" && test "$tst_compi_freeifaddrs" = "yes" && test "$tst_allow_freeifaddrs" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FREEIFADDRS, 1, [Define to 1 if you have the freeifaddrs function.]) curl_cv_func_freeifaddrs="yes" else AC_MSG_RESULT([no]) curl_cv_func_freeifaddrs="no" fi ]) dnl CURL_CHECK_FUNC_FREMOVEXATTR dnl ------------------------------------------------- dnl Verify if fremovexattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_fremovexattr, then dnl HAVE_FREMOVEXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_FREMOVEXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_fremovexattr="unknown" tst_proto_fremovexattr="unknown" tst_compi_fremovexattr="unknown" tst_allow_fremovexattr="unknown" tst_nargs_fremovexattr="unknown" # AC_MSG_CHECKING([if fremovexattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([fremovexattr]) ],[ AC_MSG_RESULT([yes]) tst_links_fremovexattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_fremovexattr="no" ]) # if test "$tst_links_fremovexattr" = "yes"; then AC_MSG_CHECKING([if fremovexattr is prototyped]) AC_EGREP_CPP([fremovexattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_fremovexattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_fremovexattr="no" ]) fi # if test "$tst_proto_fremovexattr" = "yes"; then if test "$tst_nargs_fremovexattr" = "unknown"; then AC_MSG_CHECKING([if fremovexattr takes 2 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fremovexattr(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fremovexattr="yes" tst_nargs_fremovexattr="2" ],[ AC_MSG_RESULT([no]) tst_compi_fremovexattr="no" ]) fi if test "$tst_nargs_fremovexattr" = "unknown"; then AC_MSG_CHECKING([if fremovexattr takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fremovexattr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fremovexattr="yes" tst_nargs_fremovexattr="3" ],[ AC_MSG_RESULT([no]) tst_compi_fremovexattr="no" ]) fi AC_MSG_CHECKING([if fremovexattr is compilable]) if test "$tst_compi_fremovexattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_fremovexattr" = "yes"; then AC_MSG_CHECKING([if fremovexattr usage allowed]) if test "x$curl_disallow_fremovexattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_fremovexattr="yes" else AC_MSG_RESULT([no]) tst_allow_fremovexattr="no" fi fi # AC_MSG_CHECKING([if fremovexattr might be used]) if test "$tst_links_fremovexattr" = "yes" && test "$tst_proto_fremovexattr" = "yes" && test "$tst_compi_fremovexattr" = "yes" && test "$tst_allow_fremovexattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FREMOVEXATTR, 1, [Define to 1 if you have the fremovexattr function.]) dnl AC_DEFINE_UNQUOTED(FREMOVEXATTR_ARGS, $tst_nargs_fremovexattr, dnl [Specifies the number of arguments to fremovexattr]) # if test "$tst_nargs_fremovexattr" -eq "2"; then AC_DEFINE(HAVE_FREMOVEXATTR_2, 1, [fremovexattr() takes 2 args]) elif test "$tst_nargs_fremovexattr" -eq "3"; then AC_DEFINE(HAVE_FREMOVEXATTR_3, 1, [fremovexattr() takes 3 args]) fi # curl_cv_func_fremovexattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_fremovexattr="no" fi ]) dnl CURL_CHECK_FUNC_FSETXATTR dnl ------------------------------------------------- dnl Verify if fsetxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_fsetxattr, then dnl HAVE_FSETXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_FSETXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_fsetxattr="unknown" tst_proto_fsetxattr="unknown" tst_compi_fsetxattr="unknown" tst_allow_fsetxattr="unknown" tst_nargs_fsetxattr="unknown" # AC_MSG_CHECKING([if fsetxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([fsetxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_fsetxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_fsetxattr="no" ]) # if test "$tst_links_fsetxattr" = "yes"; then AC_MSG_CHECKING([if fsetxattr is prototyped]) AC_EGREP_CPP([fsetxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_fsetxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_fsetxattr="no" ]) fi # if test "$tst_proto_fsetxattr" = "yes"; then if test "$tst_nargs_fsetxattr" = "unknown"; then AC_MSG_CHECKING([if fsetxattr takes 5 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fsetxattr(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fsetxattr="yes" tst_nargs_fsetxattr="5" ],[ AC_MSG_RESULT([no]) tst_compi_fsetxattr="no" ]) fi if test "$tst_nargs_fsetxattr" = "unknown"; then AC_MSG_CHECKING([if fsetxattr takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != fsetxattr(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_fsetxattr="yes" tst_nargs_fsetxattr="6" ],[ AC_MSG_RESULT([no]) tst_compi_fsetxattr="no" ]) fi AC_MSG_CHECKING([if fsetxattr is compilable]) if test "$tst_compi_fsetxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_fsetxattr" = "yes"; then AC_MSG_CHECKING([if fsetxattr usage allowed]) if test "x$curl_disallow_fsetxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_fsetxattr="yes" else AC_MSG_RESULT([no]) tst_allow_fsetxattr="no" fi fi # AC_MSG_CHECKING([if fsetxattr might be used]) if test "$tst_links_fsetxattr" = "yes" && test "$tst_proto_fsetxattr" = "yes" && test "$tst_compi_fsetxattr" = "yes" && test "$tst_allow_fsetxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FSETXATTR, 1, [Define to 1 if you have the fsetxattr function.]) dnl AC_DEFINE_UNQUOTED(FSETXATTR_ARGS, $tst_nargs_fsetxattr, dnl [Specifies the number of arguments to fsetxattr]) # if test "$tst_nargs_fsetxattr" -eq "5"; then AC_DEFINE(HAVE_FSETXATTR_5, 1, [fsetxattr() takes 5 args]) elif test "$tst_nargs_fsetxattr" -eq "6"; then AC_DEFINE(HAVE_FSETXATTR_6, 1, [fsetxattr() takes 6 args]) fi # curl_cv_func_fsetxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_fsetxattr="no" fi ]) dnl CURL_CHECK_FUNC_FTRUNCATE dnl ------------------------------------------------- dnl Verify if ftruncate is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_ftruncate, then dnl HAVE_FTRUNCATE will be defined. AC_DEFUN([CURL_CHECK_FUNC_FTRUNCATE], [ AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl # tst_links_ftruncate="unknown" tst_proto_ftruncate="unknown" tst_compi_ftruncate="unknown" tst_allow_ftruncate="unknown" # AC_MSG_CHECKING([if ftruncate can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([ftruncate]) ],[ AC_MSG_RESULT([yes]) tst_links_ftruncate="yes" ],[ AC_MSG_RESULT([no]) tst_links_ftruncate="no" ]) # if test "$tst_links_ftruncate" = "yes"; then AC_MSG_CHECKING([if ftruncate is prototyped]) AC_EGREP_CPP([ftruncate],[ $curl_includes_unistd ],[ AC_MSG_RESULT([yes]) tst_proto_ftruncate="yes" ],[ AC_MSG_RESULT([no]) tst_proto_ftruncate="no" ]) fi # if test "$tst_proto_ftruncate" = "yes"; then AC_MSG_CHECKING([if ftruncate is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_unistd ]],[[ if(0 != ftruncate(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ftruncate="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ftruncate="no" ]) fi # if test "$tst_compi_ftruncate" = "yes"; then AC_MSG_CHECKING([if ftruncate usage allowed]) if test "x$curl_disallow_ftruncate" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ftruncate="yes" else AC_MSG_RESULT([no]) tst_allow_ftruncate="no" fi fi # AC_MSG_CHECKING([if ftruncate might be used]) if test "$tst_links_ftruncate" = "yes" && test "$tst_proto_ftruncate" = "yes" && test "$tst_compi_ftruncate" = "yes" && test "$tst_allow_ftruncate" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_FTRUNCATE, 1, [Define to 1 if you have the ftruncate function.]) curl_cv_func_ftruncate="yes" else AC_MSG_RESULT([no]) curl_cv_func_ftruncate="no" fi ]) dnl CURL_CHECK_FUNC_GETADDRINFO dnl ------------------------------------------------- dnl Verify if getaddrinfo is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_getaddrinfo, then dnl HAVE_GETADDRINFO will be defined. Additionally when dnl HAVE_GETADDRINFO gets defined this will also attempt dnl to find out if getaddrinfo happens to be threadsafe, dnl defining HAVE_GETADDRINFO_THREADSAFE when true. AC_DEFUN([CURL_CHECK_FUNC_GETADDRINFO], [ AC_REQUIRE([CURL_INCLUDES_WS2TCPIP])dnl AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_STRING])dnl AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl AC_REQUIRE([CURL_INCLUDES_NETDB])dnl AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl # tst_links_getaddrinfo="unknown" tst_proto_getaddrinfo="unknown" tst_compi_getaddrinfo="unknown" tst_works_getaddrinfo="unknown" tst_allow_getaddrinfo="unknown" tst_tsafe_getaddrinfo="unknown" # AC_MSG_CHECKING([if getaddrinfo can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ]],[[ if(0 != getaddrinfo(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_getaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_links_getaddrinfo="no" ]) # if test "$tst_links_getaddrinfo" = "yes"; then AC_MSG_CHECKING([if getaddrinfo is prototyped]) AC_EGREP_CPP([getaddrinfo],[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_getaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getaddrinfo="no" ]) fi # if test "$tst_proto_getaddrinfo" = "yes"; then AC_MSG_CHECKING([if getaddrinfo is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ws2tcpip $curl_includes_sys_socket $curl_includes_netdb ]],[[ if(0 != getaddrinfo(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_compi_getaddrinfo="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_getaddrinfo" = "yes"; then AC_MSG_CHECKING([if getaddrinfo seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ws2tcpip $curl_includes_stdlib $curl_includes_string $curl_includes_sys_socket $curl_includes_netdb ]],[[ struct addrinfo hints; struct addrinfo *ai = 0; int error; #ifdef HAVE_WINSOCK2_H WSADATA wsa; if (WSAStartup(MAKEWORD(2,2), &wsa)) exit(2); #endif memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo("127.0.0.1", 0, &hints, &ai); if(error || !ai) exit(1); /* fail */ else exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_getaddrinfo="yes" ],[ AC_MSG_RESULT([no]) tst_works_getaddrinfo="no" ]) fi # if test "$tst_compi_getaddrinfo" = "yes" && test "$tst_works_getaddrinfo" != "no"; then AC_MSG_CHECKING([if getaddrinfo usage allowed]) if test "x$curl_disallow_getaddrinfo" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getaddrinfo="yes" else AC_MSG_RESULT([no]) tst_allow_getaddrinfo="no" fi fi # AC_MSG_CHECKING([if getaddrinfo might be used]) if test "$tst_links_getaddrinfo" = "yes" && test "$tst_proto_getaddrinfo" = "yes" && test "$tst_compi_getaddrinfo" = "yes" && test "$tst_allow_getaddrinfo" = "yes" && test "$tst_works_getaddrinfo" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETADDRINFO, 1, [Define to 1 if you have a working getaddrinfo function.]) curl_cv_func_getaddrinfo="yes" else AC_MSG_RESULT([no]) curl_cv_func_getaddrinfo="no" curl_cv_func_getaddrinfo_threadsafe="no" fi # if test "$curl_cv_func_getaddrinfo" = "yes"; then AC_MSG_CHECKING([if getaddrinfo is threadsafe]) case $host_os in aix[[1234]].* | aix5.[[01]].*) dnl aix 5.1 and older tst_tsafe_getaddrinfo="no" ;; aix*) dnl aix 5.2 and newer tst_tsafe_getaddrinfo="yes" ;; darwin[[12345]].*) dnl darwin 5.0 and mac os x 10.1.X and older tst_tsafe_getaddrinfo="no" ;; darwin*) dnl darwin 6.0 and mac os x 10.2.X and newer tst_tsafe_getaddrinfo="yes" ;; freebsd[[1234]].* | freebsd5.[[1234]]*) dnl freebsd 5.4 and older tst_tsafe_getaddrinfo="no" ;; freebsd*) dnl freebsd 5.5 and newer tst_tsafe_getaddrinfo="yes" ;; hpux[[123456789]].* | hpux10.* | hpux11.0* | hpux11.10*) dnl hpux 11.10 and older tst_tsafe_getaddrinfo="no" ;; hpux*) dnl hpux 11.11 and newer tst_tsafe_getaddrinfo="yes" ;; netbsd[[123]].*) dnl netbsd 3.X and older tst_tsafe_getaddrinfo="no" ;; netbsd*) dnl netbsd 4.X and newer tst_tsafe_getaddrinfo="yes" ;; *bsd*) dnl All other bsd's tst_tsafe_getaddrinfo="no" ;; solaris2*) dnl solaris which have it tst_tsafe_getaddrinfo="yes" ;; esac if test "$tst_tsafe_getaddrinfo" = "unknown" && test "$curl_cv_native_windows" = "yes"; then tst_tsafe_getaddrinfo="yes" fi if test "$tst_tsafe_getaddrinfo" = "unknown"; then CURL_CHECK_DEF_CC([h_errno], [ $curl_includes_sys_socket $curl_includes_netdb ], [silent]) if test "$curl_cv_have_def_h_errno" = "yes"; then tst_h_errno_macro="yes" else tst_h_errno_macro="no" fi AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_socket $curl_includes_netdb ]],[[ h_errno = 2; if(0 != h_errno) return 1; ]]) ],[ tst_h_errno_modifiable_lvalue="yes" ],[ tst_h_errno_modifiable_lvalue="no" ]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) return 0; #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700) return 0; #else force compilation error #endif ]]) ],[ tst_h_errno_sbs_issue_7="yes" ],[ tst_h_errno_sbs_issue_7="no" ]) if test "$tst_h_errno_macro" = "no" && test "$tst_h_errno_modifiable_lvalue" = "no" && test "$tst_h_errno_sbs_issue_7" = "no"; then tst_tsafe_getaddrinfo="no" else tst_tsafe_getaddrinfo="yes" fi fi AC_MSG_RESULT([$tst_tsafe_getaddrinfo]) if test "$tst_tsafe_getaddrinfo" = "yes"; then AC_DEFINE_UNQUOTED(HAVE_GETADDRINFO_THREADSAFE, 1, [Define to 1 if the getaddrinfo function is threadsafe.]) curl_cv_func_getaddrinfo_threadsafe="yes" else curl_cv_func_getaddrinfo_threadsafe="no" fi fi ]) dnl CURL_CHECK_FUNC_GETHOSTBYADDR dnl ------------------------------------------------- dnl Verify if gethostbyaddr is available, prototyped, dnl and can be compiled. If all of these are true, dnl and usage has not been previously disallowed with dnl shell variable curl_disallow_gethostbyaddr, then dnl HAVE_GETHOSTBYADDR will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYADDR], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_gethostbyaddr="unknown" tst_proto_gethostbyaddr="unknown" tst_compi_gethostbyaddr="unknown" tst_allow_gethostbyaddr="unknown" # AC_MSG_CHECKING([if gethostbyaddr can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gethostbyaddr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_gethostbyaddr="yes" ],[ AC_MSG_RESULT([no]) tst_links_gethostbyaddr="no" ]) # if test "$tst_links_gethostbyaddr" = "yes"; then AC_MSG_CHECKING([if gethostbyaddr is prototyped]) AC_EGREP_CPP([gethostbyaddr],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_gethostbyaddr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gethostbyaddr="no" ]) fi # if test "$tst_proto_gethostbyaddr" = "yes"; then AC_MSG_CHECKING([if gethostbyaddr is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gethostbyaddr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyaddr="yes" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyaddr="no" ]) fi # if test "$tst_compi_gethostbyaddr" = "yes"; then AC_MSG_CHECKING([if gethostbyaddr usage allowed]) if test "x$curl_disallow_gethostbyaddr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gethostbyaddr="yes" else AC_MSG_RESULT([no]) tst_allow_gethostbyaddr="no" fi fi # AC_MSG_CHECKING([if gethostbyaddr might be used]) if test "$tst_links_gethostbyaddr" = "yes" && test "$tst_proto_gethostbyaddr" = "yes" && test "$tst_compi_gethostbyaddr" = "yes" && test "$tst_allow_gethostbyaddr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYADDR, 1, [Define to 1 if you have the gethostbyaddr function.]) curl_cv_func_gethostbyaddr="yes" else AC_MSG_RESULT([no]) curl_cv_func_gethostbyaddr="no" fi ]) dnl CURL_CHECK_FUNC_GAI_STRERROR dnl ------------------------------------------------- dnl Verify if gai_strerror is available, prototyped, dnl and can be compiled. If all of these are true, dnl and usage has not been previously disallowed with dnl shell variable curl_disallow_gai_strerror, then dnl HAVE_GAI_STRERROR will be defined. AC_DEFUN([CURL_CHECK_FUNC_GAI_STRERROR], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_gai_strerror="unknown" tst_proto_gai_strerror="unknown" tst_compi_gai_strerror="unknown" tst_allow_gai_strerror="unknown" # AC_MSG_CHECKING([if gai_strerror can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gai_strerror(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_gai_strerror="yes" ],[ AC_MSG_RESULT([no]) tst_links_gai_strerror="no" ]) # if test "$tst_links_gai_strerror" = "yes"; then AC_MSG_CHECKING([if gai_strerror is prototyped]) AC_EGREP_CPP([gai_strerror],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_gai_strerror="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gai_strerror="no" ]) fi # if test "$tst_proto_gai_strerror" = "yes"; then AC_MSG_CHECKING([if gai_strerror is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gai_strerror(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gai_strerror="yes" ],[ AC_MSG_RESULT([no]) tst_compi_gai_strerror="no" ]) fi # if test "$tst_compi_gai_strerror" = "yes"; then AC_MSG_CHECKING([if gai_strerror usage allowed]) if test "x$curl_disallow_gai_strerror" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gai_strerror="yes" else AC_MSG_RESULT([no]) tst_allow_gai_strerror="no" fi fi # AC_MSG_CHECKING([if gai_strerror might be used]) if test "$tst_links_gai_strerror" = "yes" && test "$tst_proto_gai_strerror" = "yes" && test "$tst_compi_gai_strerror" = "yes" && test "$tst_allow_gai_strerror" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GAI_STRERROR, 1, [Define to 1 if you have the gai_strerror function.]) curl_cv_func_gai_strerror="yes" else AC_MSG_RESULT([no]) curl_cv_func_gai_strerror="no" fi ]) dnl CURL_CHECK_FUNC_GETHOSTBYADDR_R dnl ------------------------------------------------- dnl Verify if gethostbyaddr_r is available, prototyped, dnl and can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_gethostbyaddr_r, then dnl HAVE_GETHOSTBYADDR_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYADDR_R], [ AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_gethostbyaddr_r="unknown" tst_proto_gethostbyaddr_r="unknown" tst_compi_gethostbyaddr_r="unknown" tst_allow_gethostbyaddr_r="unknown" tst_nargs_gethostbyaddr_r="unknown" # AC_MSG_CHECKING([if gethostbyaddr_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gethostbyaddr_r]) ],[ AC_MSG_RESULT([yes]) tst_links_gethostbyaddr_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_gethostbyaddr_r="no" ]) # if test "$tst_links_gethostbyaddr_r" = "yes"; then AC_MSG_CHECKING([if gethostbyaddr_r is prototyped]) AC_EGREP_CPP([gethostbyaddr_r],[ $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_gethostbyaddr_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gethostbyaddr_r="no" ]) fi # if test "$tst_proto_gethostbyaddr_r" = "yes"; then if test "$tst_nargs_gethostbyaddr_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyaddr_r takes 5 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyaddr_r(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyaddr_r="yes" tst_nargs_gethostbyaddr_r="5" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyaddr_r="no" ]) fi if test "$tst_nargs_gethostbyaddr_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyaddr_r takes 7 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyaddr_r(0, 0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyaddr_r="yes" tst_nargs_gethostbyaddr_r="7" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyaddr_r="no" ]) fi if test "$tst_nargs_gethostbyaddr_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyaddr_r takes 8 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyaddr_r(0, 0, 0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyaddr_r="yes" tst_nargs_gethostbyaddr_r="8" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyaddr_r="no" ]) fi AC_MSG_CHECKING([if gethostbyaddr_r is compilable]) if test "$tst_compi_gethostbyaddr_r" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_gethostbyaddr_r" = "yes"; then AC_MSG_CHECKING([if gethostbyaddr_r usage allowed]) if test "x$curl_disallow_gethostbyaddr_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gethostbyaddr_r="yes" else AC_MSG_RESULT([no]) tst_allow_gethostbyaddr_r="no" fi fi # AC_MSG_CHECKING([if gethostbyaddr_r might be used]) if test "$tst_links_gethostbyaddr_r" = "yes" && test "$tst_proto_gethostbyaddr_r" = "yes" && test "$tst_compi_gethostbyaddr_r" = "yes" && test "$tst_allow_gethostbyaddr_r" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYADDR_R, 1, [Define to 1 if you have the gethostbyaddr_r function.]) dnl AC_DEFINE_UNQUOTED(GETHOSTBYADDR_R_ARGS, $tst_nargs_gethostbyaddr_r, dnl [Specifies the number of arguments to gethostbyaddr_r]) # if test "$tst_nargs_gethostbyaddr_r" -eq "5"; then AC_DEFINE(HAVE_GETHOSTBYADDR_R_5, 1, [gethostbyaddr_r() takes 5 args]) elif test "$tst_nargs_gethostbyaddr_r" -eq "7"; then AC_DEFINE(HAVE_GETHOSTBYADDR_R_7, 1, [gethostbyaddr_r() takes 7 args]) elif test "$tst_nargs_gethostbyaddr_r" -eq "8"; then AC_DEFINE(HAVE_GETHOSTBYADDR_R_8, 1, [gethostbyaddr_r() takes 8 args]) fi # curl_cv_func_gethostbyaddr_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_gethostbyaddr_r="no" fi ]) dnl CURL_CHECK_FUNC_GETHOSTBYNAME dnl ------------------------------------------------- dnl Verify if gethostbyname is available, prototyped, dnl and can be compiled. If all of these are true, dnl and usage has not been previously disallowed with dnl shell variable curl_disallow_gethostbyname, then dnl HAVE_GETHOSTBYNAME will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYNAME], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_gethostbyname="unknown" tst_proto_gethostbyname="unknown" tst_compi_gethostbyname="unknown" tst_allow_gethostbyname="unknown" # AC_MSG_CHECKING([if gethostbyname can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gethostbyname(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_gethostbyname="yes" ],[ AC_MSG_RESULT([no]) tst_links_gethostbyname="no" ]) # if test "$tst_links_gethostbyname" = "yes"; then AC_MSG_CHECKING([if gethostbyname is prototyped]) AC_EGREP_CPP([gethostbyname],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_gethostbyname="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gethostbyname="no" ]) fi # if test "$tst_proto_gethostbyname" = "yes"; then AC_MSG_CHECKING([if gethostbyname is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_netdb ]],[[ if(0 != gethostbyname(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyname="yes" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyname="no" ]) fi # if test "$tst_compi_gethostbyname" = "yes"; then AC_MSG_CHECKING([if gethostbyname usage allowed]) if test "x$curl_disallow_gethostbyname" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gethostbyname="yes" else AC_MSG_RESULT([no]) tst_allow_gethostbyname="no" fi fi # AC_MSG_CHECKING([if gethostbyname might be used]) if test "$tst_links_gethostbyname" = "yes" && test "$tst_proto_gethostbyname" = "yes" && test "$tst_compi_gethostbyname" = "yes" && test "$tst_allow_gethostbyname" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYNAME, 1, [Define to 1 if you have the gethostbyname function.]) curl_cv_func_gethostbyname="yes" else AC_MSG_RESULT([no]) curl_cv_func_gethostbyname="no" fi ]) dnl CURL_CHECK_FUNC_GETHOSTBYNAME_R dnl ------------------------------------------------- dnl Verify if gethostbyname_r is available, prototyped, dnl and can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_gethostbyname_r, then dnl HAVE_GETHOSTBYNAME_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETHOSTBYNAME_R], [ AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_gethostbyname_r="unknown" tst_proto_gethostbyname_r="unknown" tst_compi_gethostbyname_r="unknown" tst_allow_gethostbyname_r="unknown" tst_nargs_gethostbyname_r="unknown" # AC_MSG_CHECKING([if gethostbyname_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gethostbyname_r]) ],[ AC_MSG_RESULT([yes]) tst_links_gethostbyname_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_gethostbyname_r="no" ]) # if test "$tst_links_gethostbyname_r" = "yes"; then AC_MSG_CHECKING([if gethostbyname_r is prototyped]) AC_EGREP_CPP([gethostbyname_r],[ $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_gethostbyname_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gethostbyname_r="no" ]) fi # if test "$tst_proto_gethostbyname_r" = "yes"; then if test "$tst_nargs_gethostbyname_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyname_r takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyname_r(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyname_r="yes" tst_nargs_gethostbyname_r="3" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyname_r="no" ]) fi if test "$tst_nargs_gethostbyname_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyname_r takes 5 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyname_r(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyname_r="yes" tst_nargs_gethostbyname_r="5" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyname_r="no" ]) fi if test "$tst_nargs_gethostbyname_r" = "unknown"; then AC_MSG_CHECKING([if gethostbyname_r takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != gethostbyname_r(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostbyname_r="yes" tst_nargs_gethostbyname_r="6" ],[ AC_MSG_RESULT([no]) tst_compi_gethostbyname_r="no" ]) fi AC_MSG_CHECKING([if gethostbyname_r is compilable]) if test "$tst_compi_gethostbyname_r" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_gethostbyname_r" = "yes"; then AC_MSG_CHECKING([if gethostbyname_r usage allowed]) if test "x$curl_disallow_gethostbyname_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gethostbyname_r="yes" else AC_MSG_RESULT([no]) tst_allow_gethostbyname_r="no" fi fi # AC_MSG_CHECKING([if gethostbyname_r might be used]) if test "$tst_links_gethostbyname_r" = "yes" && test "$tst_proto_gethostbyname_r" = "yes" && test "$tst_compi_gethostbyname_r" = "yes" && test "$tst_allow_gethostbyname_r" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETHOSTBYNAME_R, 1, [Define to 1 if you have the gethostbyname_r function.]) dnl AC_DEFINE_UNQUOTED(GETHOSTBYNAME_R_ARGS, $tst_nargs_gethostbyname_r, dnl [Specifies the number of arguments to gethostbyname_r]) # if test "$tst_nargs_gethostbyname_r" -eq "3"; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_3, 1, [gethostbyname_r() takes 3 args]) elif test "$tst_nargs_gethostbyname_r" -eq "5"; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_5, 1, [gethostbyname_r() takes 5 args]) elif test "$tst_nargs_gethostbyname_r" -eq "6"; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_6, 1, [gethostbyname_r() takes 6 args]) fi # curl_cv_func_gethostbyname_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_gethostbyname_r="no" fi ]) dnl CURL_CHECK_FUNC_GETHOSTNAME dnl ------------------------------------------------- dnl Verify if gethostname is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_gethostname, then dnl HAVE_GETHOSTNAME will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETHOSTNAME], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl # tst_links_gethostname="unknown" tst_proto_gethostname="unknown" tst_compi_gethostname="unknown" tst_allow_gethostname="unknown" # AC_MSG_CHECKING([if gethostname can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_unistd ]],[[ if(0 != gethostname(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_gethostname="yes" ],[ AC_MSG_RESULT([no]) tst_links_gethostname="no" ]) # if test "$tst_links_gethostname" = "yes"; then AC_MSG_CHECKING([if gethostname is prototyped]) AC_EGREP_CPP([gethostname],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_unistd ],[ AC_MSG_RESULT([yes]) tst_proto_gethostname="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gethostname="no" ]) fi # if test "$tst_proto_gethostname" = "yes"; then AC_MSG_CHECKING([if gethostname is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_unistd ]],[[ if(0 != gethostname(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gethostname="yes" ],[ AC_MSG_RESULT([no]) tst_compi_gethostname="no" ]) fi # if test "$tst_compi_gethostname" = "yes"; then AC_MSG_CHECKING([for gethostname arg 2 data type]) tst_gethostname_type_arg2="unknown" for tst_arg1 in 'char *' 'unsigned char *' 'void *'; do for tst_arg2 in 'int' 'unsigned int' 'size_t'; do if test "$tst_gethostname_type_arg2" = "unknown"; then AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_unistd $curl_preprocess_callconv extern int FUNCALLCONV gethostname($tst_arg1, $tst_arg2); ]],[[ if(0 != gethostname(0, 0)) return 1; ]]) ],[ tst_gethostname_type_arg2="$tst_arg2" ]) fi done done AC_MSG_RESULT([$tst_gethostname_type_arg2]) if test "$tst_gethostname_type_arg2" != "unknown"; then AC_DEFINE_UNQUOTED(GETHOSTNAME_TYPE_ARG2, $tst_gethostname_type_arg2, [Define to the type of arg 2 for gethostname.]) fi fi # if test "$tst_compi_gethostname" = "yes"; then AC_MSG_CHECKING([if gethostname usage allowed]) if test "x$curl_disallow_gethostname" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gethostname="yes" else AC_MSG_RESULT([no]) tst_allow_gethostname="no" fi fi # AC_MSG_CHECKING([if gethostname might be used]) if test "$tst_links_gethostname" = "yes" && test "$tst_proto_gethostname" = "yes" && test "$tst_compi_gethostname" = "yes" && test "$tst_allow_gethostname" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETHOSTNAME, 1, [Define to 1 if you have the gethostname function.]) curl_cv_func_gethostname="yes" else AC_MSG_RESULT([no]) curl_cv_func_gethostname="no" fi ]) dnl CURL_CHECK_FUNC_GETPEERNAME dnl ------------------------------------------------- dnl Verify if getpeername is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_getpeername, then dnl HAVE_GETPEERNAME will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETPEERNAME], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl # tst_links_getpeername="unknown" tst_proto_getpeername="unknown" tst_compi_getpeername="unknown" tst_allow_getpeername="unknown" # AC_MSG_CHECKING([if getpeername can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != getpeername(0, (void *)0, (void *)0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_getpeername="yes" ],[ AC_MSG_RESULT([no]) tst_links_getpeername="no" ]) # if test "$tst_links_getpeername" = "yes"; then AC_MSG_CHECKING([if getpeername is prototyped]) AC_EGREP_CPP([getpeername],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ],[ AC_MSG_RESULT([yes]) tst_proto_getpeername="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getpeername="no" ]) fi # if test "$tst_proto_getpeername" = "yes"; then AC_MSG_CHECKING([if getpeername is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != getpeername(0, (void *)0, (void *)0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getpeername="yes" ],[ AC_MSG_RESULT([no]) tst_compi_getpeername="no" ]) fi # if test "$tst_compi_getpeername" = "yes"; then AC_MSG_CHECKING([if getpeername usage allowed]) if test "x$curl_disallow_getpeername" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getpeername="yes" else AC_MSG_RESULT([no]) tst_allow_getpeername="no" fi fi # AC_MSG_CHECKING([if getpeername might be used]) if test "$tst_links_getpeername" = "yes" && test "$tst_proto_getpeername" = "yes" && test "$tst_compi_getpeername" = "yes" && test "$tst_allow_getpeername" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETPEERNAME, 1, [Define to 1 if you have the getpeername function.]) curl_cv_func_getpeername="yes" else AC_MSG_RESULT([no]) curl_cv_func_getpeername="no" fi ]) dnl CURL_CHECK_FUNC_GETSOCKNAME dnl ------------------------------------------------- dnl Verify if getsockname is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_getsockname, then dnl HAVE_GETSOCKNAME will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETSOCKNAME], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_UNISTD])dnl AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl AC_REQUIRE([CURL_INCLUDES_BSDSOCKET])dnl # tst_links_getsockname="unknown" tst_proto_getsockname="unknown" tst_compi_getsockname="unknown" tst_allow_getsockname="unknown" # AC_MSG_CHECKING([if getsockname can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != getsockname(0, (void *)0, (void *)0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_getsockname="yes" ],[ AC_MSG_RESULT([no]) tst_links_getsockname="no" ]) # if test "$tst_links_getsockname" = "yes"; then AC_MSG_CHECKING([if getsockname is prototyped]) AC_EGREP_CPP([getsockname],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ],[ AC_MSG_RESULT([yes]) tst_proto_getsockname="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getsockname="no" ]) fi # if test "$tst_proto_getsockname" = "yes"; then AC_MSG_CHECKING([if getsockname is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != getsockname(0, (void *)0, (void *)0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getsockname="yes" ],[ AC_MSG_RESULT([no]) tst_compi_getsockname="no" ]) fi # if test "$tst_compi_getsockname" = "yes"; then AC_MSG_CHECKING([if getsockname usage allowed]) if test "x$curl_disallow_getsockname" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getsockname="yes" else AC_MSG_RESULT([no]) tst_allow_getsockname="no" fi fi # AC_MSG_CHECKING([if getsockname might be used]) if test "$tst_links_getsockname" = "yes" && test "$tst_proto_getsockname" = "yes" && test "$tst_compi_getsockname" = "yes" && test "$tst_allow_getsockname" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETSOCKNAME, 1, [Define to 1 if you have the getsockname function.]) curl_cv_func_getsockname="yes" else AC_MSG_RESULT([no]) curl_cv_func_getsockname="no" fi ]) dnl CURL_CHECK_FUNC_IF_NAMETOINDEX dnl ------------------------------------------------- dnl Verify if if_nametoindex is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_if_nametoindex, then dnl HAVE_IF_NAMETOINDEX will be defined. AC_DEFUN([CURL_CHECK_FUNC_IF_NAMETOINDEX], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_NETIF])dnl AC_REQUIRE([CURL_PREPROCESS_CALLCONV])dnl # tst_links_if_nametoindex="unknown" tst_proto_if_nametoindex="unknown" tst_compi_if_nametoindex="unknown" tst_allow_if_nametoindex="unknown" # AC_MSG_CHECKING([if if_nametoindex can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket #include ]],[[ if(0 != if_nametoindex("")) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_if_nametoindex="yes" ],[ AC_MSG_RESULT([no]) tst_links_if_nametoindex="no" ]) # if test "$tst_links_if_nametoindex" = "yes"; then AC_MSG_CHECKING([if if_nametoindex is prototyped]) AC_EGREP_CPP([if_nametoindex],[ $curl_includes_winsock2 $curl_includes_netif ],[ AC_MSG_RESULT([yes]) tst_proto_if_nametoindex="yes" ],[ AC_MSG_RESULT([no]) tst_proto_if_nametoindex="no" ]) fi # if test "$tst_proto_if_nametoindex" = "yes"; then AC_MSG_CHECKING([if if_nametoindex is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_netif ]],[[ if(0 != if_nametoindex("")) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_if_nametoindex="yes" ],[ AC_MSG_RESULT([no]) tst_compi_if_nametoindex="no" ]) fi # if test "$tst_compi_if_nametoindex" = "yes"; then AC_MSG_CHECKING([if if_nametoindex usage allowed]) if test "x$curl_disallow_if_nametoindex" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_if_nametoindex="yes" else AC_MSG_RESULT([no]) tst_allow_if_nametoindex="no" fi fi # AC_MSG_CHECKING([if if_nametoindex might be used]) if test "$tst_links_if_nametoindex" = "yes" && test "$tst_proto_if_nametoindex" = "yes" && test "$tst_compi_if_nametoindex" = "yes" && test "$tst_allow_if_nametoindex" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IF_NAMETOINDEX, 1, [Define to 1 if you have the if_nametoindex function.]) curl_cv_func_if_nametoindex="yes" else AC_MSG_RESULT([no]) curl_cv_func_if_nametoindex="no" fi ]) dnl CURL_CHECK_FUNC_GETIFADDRS dnl ------------------------------------------------- dnl Verify if getifaddrs is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_getifaddrs, then dnl HAVE_GETIFADDRS will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETIFADDRS], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_IFADDRS])dnl # tst_links_getifaddrs="unknown" tst_proto_getifaddrs="unknown" tst_compi_getifaddrs="unknown" tst_works_getifaddrs="unknown" tst_allow_getifaddrs="unknown" # AC_MSG_CHECKING([if getifaddrs can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([getifaddrs]) ],[ AC_MSG_RESULT([yes]) tst_links_getifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_links_getifaddrs="no" ]) # if test "$tst_links_getifaddrs" = "yes"; then AC_MSG_CHECKING([if getifaddrs is prototyped]) AC_EGREP_CPP([getifaddrs],[ $curl_includes_ifaddrs ],[ AC_MSG_RESULT([yes]) tst_proto_getifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getifaddrs="no" ]) fi # if test "$tst_proto_getifaddrs" = "yes"; then AC_MSG_CHECKING([if getifaddrs is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_ifaddrs ]],[[ if(0 != getifaddrs(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_compi_getifaddrs="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_getifaddrs" = "yes"; then AC_MSG_CHECKING([if getifaddrs seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_ifaddrs ]],[[ struct ifaddrs *ifa = 0; int error; error = getifaddrs(&ifa); if(error || !ifa) exit(1); /* fail */ else exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_getifaddrs="yes" ],[ AC_MSG_RESULT([no]) tst_works_getifaddrs="no" ]) fi # if test "$tst_compi_getifaddrs" = "yes" && test "$tst_works_getifaddrs" != "no"; then AC_MSG_CHECKING([if getifaddrs usage allowed]) if test "x$curl_disallow_getifaddrs" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getifaddrs="yes" else AC_MSG_RESULT([no]) tst_allow_getifaddrs="no" fi fi # AC_MSG_CHECKING([if getifaddrs might be used]) if test "$tst_links_getifaddrs" = "yes" && test "$tst_proto_getifaddrs" = "yes" && test "$tst_compi_getifaddrs" = "yes" && test "$tst_allow_getifaddrs" = "yes" && test "$tst_works_getifaddrs" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETIFADDRS, 1, [Define to 1 if you have a working getifaddrs function.]) curl_cv_func_getifaddrs="yes" else AC_MSG_RESULT([no]) curl_cv_func_getifaddrs="no" fi ]) dnl CURL_CHECK_FUNC_GETSERVBYPORT_R dnl ------------------------------------------------- dnl Verify if getservbyport_r is available, prototyped, dnl and can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_getservbyport_r, then dnl HAVE_GETSERVBYPORT_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETSERVBYPORT_R], [ AC_REQUIRE([CURL_INCLUDES_NETDB])dnl # tst_links_getservbyport_r="unknown" tst_proto_getservbyport_r="unknown" tst_compi_getservbyport_r="unknown" tst_allow_getservbyport_r="unknown" tst_nargs_getservbyport_r="unknown" # AC_MSG_CHECKING([if getservbyport_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([getservbyport_r]) ],[ AC_MSG_RESULT([yes]) tst_links_getservbyport_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_getservbyport_r="no" ]) # if test "$tst_links_getservbyport_r" = "yes"; then AC_MSG_CHECKING([if getservbyport_r is prototyped]) AC_EGREP_CPP([getservbyport_r],[ $curl_includes_netdb ],[ AC_MSG_RESULT([yes]) tst_proto_getservbyport_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getservbyport_r="no" ]) fi # if test "$tst_proto_getservbyport_r" = "yes"; then if test "$tst_nargs_getservbyport_r" = "unknown"; then AC_MSG_CHECKING([if getservbyport_r takes 4 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != getservbyport_r(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getservbyport_r="yes" tst_nargs_getservbyport_r="4" ],[ AC_MSG_RESULT([no]) tst_compi_getservbyport_r="no" ]) fi if test "$tst_nargs_getservbyport_r" = "unknown"; then AC_MSG_CHECKING([if getservbyport_r takes 5 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != getservbyport_r(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getservbyport_r="yes" tst_nargs_getservbyport_r="5" ],[ AC_MSG_RESULT([no]) tst_compi_getservbyport_r="no" ]) fi if test "$tst_nargs_getservbyport_r" = "unknown"; then AC_MSG_CHECKING([if getservbyport_r takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_netdb ]],[[ if(0 != getservbyport_r(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getservbyport_r="yes" tst_nargs_getservbyport_r="6" ],[ AC_MSG_RESULT([no]) tst_compi_getservbyport_r="no" ]) fi AC_MSG_CHECKING([if getservbyport_r is compilable]) if test "$tst_compi_getservbyport_r" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_getservbyport_r" = "yes"; then AC_MSG_CHECKING([if getservbyport_r usage allowed]) if test "x$curl_disallow_getservbyport_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getservbyport_r="yes" else AC_MSG_RESULT([no]) tst_allow_getservbyport_r="no" fi fi # AC_MSG_CHECKING([if getservbyport_r might be used]) if test "$tst_links_getservbyport_r" = "yes" && test "$tst_proto_getservbyport_r" = "yes" && test "$tst_compi_getservbyport_r" = "yes" && test "$tst_allow_getservbyport_r" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETSERVBYPORT_R, 1, [Define to 1 if you have the getservbyport_r function.]) AC_DEFINE_UNQUOTED(GETSERVBYPORT_R_ARGS, $tst_nargs_getservbyport_r, [Specifies the number of arguments to getservbyport_r]) if test "$tst_nargs_getservbyport_r" -eq "4"; then AC_DEFINE(GETSERVBYPORT_R_BUFSIZE, sizeof(struct servent_data), [Specifies the size of the buffer to pass to getservbyport_r]) else AC_DEFINE(GETSERVBYPORT_R_BUFSIZE, 4096, [Specifies the size of the buffer to pass to getservbyport_r]) fi curl_cv_func_getservbyport_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_getservbyport_r="no" fi ]) dnl CURL_CHECK_FUNC_GETXATTR dnl ------------------------------------------------- dnl Verify if getxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_getxattr, then dnl HAVE_GETXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_GETXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_getxattr="unknown" tst_proto_getxattr="unknown" tst_compi_getxattr="unknown" tst_allow_getxattr="unknown" tst_nargs_getxattr="unknown" # AC_MSG_CHECKING([if getxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([getxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_getxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_getxattr="no" ]) # if test "$tst_links_getxattr" = "yes"; then AC_MSG_CHECKING([if getxattr is prototyped]) AC_EGREP_CPP([getxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_getxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_getxattr="no" ]) fi # if test "$tst_proto_getxattr" = "yes"; then if test "$tst_nargs_getxattr" = "unknown"; then AC_MSG_CHECKING([if getxattr takes 4 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != getxattr(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getxattr="yes" tst_nargs_getxattr="4" ],[ AC_MSG_RESULT([no]) tst_compi_getxattr="no" ]) fi if test "$tst_nargs_getxattr" = "unknown"; then AC_MSG_CHECKING([if getxattr takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != getxattr(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_getxattr="yes" tst_nargs_getxattr="6" ],[ AC_MSG_RESULT([no]) tst_compi_getxattr="no" ]) fi AC_MSG_CHECKING([if getxattr is compilable]) if test "$tst_compi_getxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_getxattr" = "yes"; then AC_MSG_CHECKING([if getxattr usage allowed]) if test "x$curl_disallow_getxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_getxattr="yes" else AC_MSG_RESULT([no]) tst_allow_getxattr="no" fi fi # AC_MSG_CHECKING([if getxattr might be used]) if test "$tst_links_getxattr" = "yes" && test "$tst_proto_getxattr" = "yes" && test "$tst_compi_getxattr" = "yes" && test "$tst_allow_getxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GETXATTR, 1, [Define to 1 if you have the getxattr function.]) dnl AC_DEFINE_UNQUOTED(GETXATTR_ARGS, $tst_nargs_getxattr, dnl [Specifies the number of arguments to getxattr]) # if test "$tst_nargs_getxattr" -eq "4"; then AC_DEFINE(HAVE_GETXATTR_4, 1, [getxattr() takes 4 args]) elif test "$tst_nargs_getxattr" -eq "6"; then AC_DEFINE(HAVE_GETXATTR_6, 1, [getxattr() takes 6 args]) fi # curl_cv_func_getxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_getxattr="no" fi ]) dnl CURL_CHECK_FUNC_GMTIME_R dnl ------------------------------------------------- dnl Verify if gmtime_r is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_gmtime_r, then dnl HAVE_GMTIME_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_GMTIME_R], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_TIME])dnl # tst_links_gmtime_r="unknown" tst_proto_gmtime_r="unknown" tst_compi_gmtime_r="unknown" tst_works_gmtime_r="unknown" tst_allow_gmtime_r="unknown" # AC_MSG_CHECKING([if gmtime_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([gmtime_r]) ],[ AC_MSG_RESULT([yes]) tst_links_gmtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_gmtime_r="no" ]) # if test "$tst_links_gmtime_r" = "yes"; then AC_MSG_CHECKING([if gmtime_r is prototyped]) AC_EGREP_CPP([gmtime_r],[ $curl_includes_time ],[ AC_MSG_RESULT([yes]) tst_proto_gmtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_gmtime_r="no" ]) fi # if test "$tst_proto_gmtime_r" = "yes"; then AC_MSG_CHECKING([if gmtime_r is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_time ]],[[ if(0 != gmtime_r(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_gmtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_compi_gmtime_r="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_gmtime_r" = "yes"; then AC_MSG_CHECKING([if gmtime_r seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_time ]],[[ time_t local = 1170352587; struct tm *gmt = 0; struct tm result; gmt = gmtime_r(&local, &result); if(gmt) exit(0); else exit(1); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_gmtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_works_gmtime_r="no" ]) fi # if test "$tst_compi_gmtime_r" = "yes" && test "$tst_works_gmtime_r" != "no"; then AC_MSG_CHECKING([if gmtime_r usage allowed]) if test "x$curl_disallow_gmtime_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_gmtime_r="yes" else AC_MSG_RESULT([no]) tst_allow_gmtime_r="no" fi fi # AC_MSG_CHECKING([if gmtime_r might be used]) if test "$tst_links_gmtime_r" = "yes" && test "$tst_proto_gmtime_r" = "yes" && test "$tst_compi_gmtime_r" = "yes" && test "$tst_allow_gmtime_r" = "yes" && test "$tst_works_gmtime_r" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_GMTIME_R, 1, [Define to 1 if you have a working gmtime_r function.]) curl_cv_func_gmtime_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_gmtime_r="no" fi ]) dnl CURL_CHECK_FUNC_INET_NTOA_R dnl ------------------------------------------------- dnl Verify if inet_ntoa_r is available, prototyped, dnl and can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_inet_ntoa_r, then dnl HAVE_INET_NTOA_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_INET_NTOA_R], [ AC_REQUIRE([CURL_INCLUDES_ARPA_INET])dnl # tst_links_inet_ntoa_r="unknown" tst_proto_inet_ntoa_r="unknown" tst_compi_inet_ntoa_r="unknown" tst_allow_inet_ntoa_r="unknown" tst_nargs_inet_ntoa_r="unknown" # AC_MSG_CHECKING([if inet_ntoa_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([inet_ntoa_r]) ],[ AC_MSG_RESULT([yes]) tst_links_inet_ntoa_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_inet_ntoa_r="no" ]) # if test "$tst_links_inet_ntoa_r" = "yes"; then AC_MSG_CHECKING([if inet_ntoa_r is prototyped]) AC_EGREP_CPP([inet_ntoa_r],[ $curl_includes_arpa_inet ],[ AC_MSG_RESULT([yes]) tst_proto_inet_ntoa_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_inet_ntoa_r="no" ]) fi # if test "$tst_proto_inet_ntoa_r" = "yes"; then if test "$tst_nargs_inet_ntoa_r" = "unknown"; then AC_MSG_CHECKING([if inet_ntoa_r takes 2 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_arpa_inet ]],[[ struct in_addr addr; if(0 != inet_ntoa_r(addr, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_inet_ntoa_r="yes" tst_nargs_inet_ntoa_r="2" ],[ AC_MSG_RESULT([no]) tst_compi_inet_ntoa_r="no" ]) fi if test "$tst_nargs_inet_ntoa_r" = "unknown"; then AC_MSG_CHECKING([if inet_ntoa_r takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_arpa_inet ]],[[ struct in_addr addr; if(0 != inet_ntoa_r(addr, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_inet_ntoa_r="yes" tst_nargs_inet_ntoa_r="3" ],[ AC_MSG_RESULT([no]) tst_compi_inet_ntoa_r="no" ]) fi AC_MSG_CHECKING([if inet_ntoa_r is compilable]) if test "$tst_compi_inet_ntoa_r" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_inet_ntoa_r" = "yes"; then AC_MSG_CHECKING([if inet_ntoa_r usage allowed]) if test "x$curl_disallow_inet_ntoa_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_inet_ntoa_r="yes" else AC_MSG_RESULT([no]) tst_allow_inet_ntoa_r="no" fi fi # AC_MSG_CHECKING([if inet_ntoa_r might be used]) if test "$tst_links_inet_ntoa_r" = "yes" && test "$tst_proto_inet_ntoa_r" = "yes" && test "$tst_compi_inet_ntoa_r" = "yes" && test "$tst_allow_inet_ntoa_r" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_INET_NTOA_R, 1, [Define to 1 if you have the inet_ntoa_r function.]) dnl AC_DEFINE_UNQUOTED(INET_NTOA_R_ARGS, $tst_nargs_inet_ntoa_r, dnl [Specifies the number of arguments to inet_ntoa_r]) # if test "$tst_nargs_inet_ntoa_r" -eq "2"; then AC_DEFINE(HAVE_INET_NTOA_R_2, 1, [inet_ntoa_r() takes 2 args]) elif test "$tst_nargs_inet_ntoa_r" -eq "3"; then AC_DEFINE(HAVE_INET_NTOA_R_3, 1, [inet_ntoa_r() takes 3 args]) fi # curl_cv_func_inet_ntoa_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_inet_ntoa_r="no" fi ]) dnl CURL_CHECK_FUNC_INET_NTOP dnl ------------------------------------------------- dnl Verify if inet_ntop is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_inet_ntop, then dnl HAVE_INET_NTOP will be defined. AC_DEFUN([CURL_CHECK_FUNC_INET_NTOP], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_ARPA_INET])dnl AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_inet_ntop="unknown" tst_proto_inet_ntop="unknown" tst_compi_inet_ntop="unknown" tst_works_inet_ntop="unknown" tst_allow_inet_ntop="unknown" # AC_MSG_CHECKING([if inet_ntop can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([inet_ntop]) ],[ AC_MSG_RESULT([yes]) tst_links_inet_ntop="yes" ],[ AC_MSG_RESULT([no]) tst_links_inet_ntop="no" ]) # if test "$tst_links_inet_ntop" = "yes"; then AC_MSG_CHECKING([if inet_ntop is prototyped]) AC_EGREP_CPP([inet_ntop],[ $curl_includes_arpa_inet ],[ AC_MSG_RESULT([yes]) tst_proto_inet_ntop="yes" ],[ AC_MSG_RESULT([no]) tst_proto_inet_ntop="no" ]) fi # if test "$tst_proto_inet_ntop" = "yes"; then AC_MSG_CHECKING([if inet_ntop is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_arpa_inet ]],[[ if(0 != inet_ntop(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_inet_ntop="yes" ],[ AC_MSG_RESULT([no]) tst_compi_inet_ntop="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_inet_ntop" = "yes"; then AC_MSG_CHECKING([if inet_ntop seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_arpa_inet $curl_includes_string ]],[[ char ipv6res[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char ipv4res[sizeof "255.255.255.255"]; unsigned char ipv6a[26]; unsigned char ipv4a[5]; char *ipv6ptr = 0; char *ipv4ptr = 0; /* - */ ipv4res[0] = '\0'; ipv4a[0] = 0xc0; ipv4a[1] = 0xa8; ipv4a[2] = 0x64; ipv4a[3] = 0x01; ipv4a[4] = 0x01; /* - */ ipv4ptr = inet_ntop(AF_INET, ipv4a, ipv4res, sizeof(ipv4res)); if(!ipv4ptr) exit(1); /* fail */ if(ipv4ptr != ipv4res) exit(1); /* fail */ if(!ipv4ptr[0]) exit(1); /* fail */ if(memcmp(ipv4res, "192.168.100.1", 13) != 0) exit(1); /* fail */ /* - */ ipv6res[0] = '\0'; memset(ipv6a, 0, sizeof(ipv6a)); ipv6a[0] = 0xfe; ipv6a[1] = 0x80; ipv6a[8] = 0x02; ipv6a[9] = 0x14; ipv6a[10] = 0x4f; ipv6a[11] = 0xff; ipv6a[12] = 0xfe; ipv6a[13] = 0x0b; ipv6a[14] = 0x76; ipv6a[15] = 0xc8; ipv6a[25] = 0x01; /* - */ ipv6ptr = inet_ntop(AF_INET6, ipv6a, ipv6res, sizeof(ipv6res)); if(!ipv6ptr) exit(1); /* fail */ if(ipv6ptr != ipv6res) exit(1); /* fail */ if(!ipv6ptr[0]) exit(1); /* fail */ if(memcmp(ipv6res, "fe80::214:4fff:fe0b:76c8", 24) != 0) exit(1); /* fail */ /* - */ exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_inet_ntop="yes" ],[ AC_MSG_RESULT([no]) tst_works_inet_ntop="no" ]) fi # if test "$tst_compi_inet_ntop" = "yes" && test "$tst_works_inet_ntop" != "no"; then AC_MSG_CHECKING([if inet_ntop usage allowed]) if test "x$curl_disallow_inet_ntop" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_inet_ntop="yes" else AC_MSG_RESULT([no]) tst_allow_inet_ntop="no" fi fi # AC_MSG_CHECKING([if inet_ntop might be used]) if test "$tst_links_inet_ntop" = "yes" && test "$tst_proto_inet_ntop" = "yes" && test "$tst_compi_inet_ntop" = "yes" && test "$tst_allow_inet_ntop" = "yes" && test "$tst_works_inet_ntop" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_INET_NTOP, 1, [Define to 1 if you have a IPv6 capable working inet_ntop function.]) curl_cv_func_inet_ntop="yes" else AC_MSG_RESULT([no]) curl_cv_func_inet_ntop="no" fi ]) dnl CURL_CHECK_FUNC_INET_PTON dnl ------------------------------------------------- dnl Verify if inet_pton is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_inet_pton, then dnl HAVE_INET_PTON will be defined. AC_DEFUN([CURL_CHECK_FUNC_INET_PTON], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_ARPA_INET])dnl AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_inet_pton="unknown" tst_proto_inet_pton="unknown" tst_compi_inet_pton="unknown" tst_works_inet_pton="unknown" tst_allow_inet_pton="unknown" # AC_MSG_CHECKING([if inet_pton can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([inet_pton]) ],[ AC_MSG_RESULT([yes]) tst_links_inet_pton="yes" ],[ AC_MSG_RESULT([no]) tst_links_inet_pton="no" ]) # if test "$tst_links_inet_pton" = "yes"; then AC_MSG_CHECKING([if inet_pton is prototyped]) AC_EGREP_CPP([inet_pton],[ $curl_includes_arpa_inet ],[ AC_MSG_RESULT([yes]) tst_proto_inet_pton="yes" ],[ AC_MSG_RESULT([no]) tst_proto_inet_pton="no" ]) fi # if test "$tst_proto_inet_pton" = "yes"; then AC_MSG_CHECKING([if inet_pton is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_arpa_inet ]],[[ if(0 != inet_pton(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_inet_pton="yes" ],[ AC_MSG_RESULT([no]) tst_compi_inet_pton="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_inet_pton" = "yes"; then AC_MSG_CHECKING([if inet_pton seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_arpa_inet $curl_includes_string ]],[[ unsigned char ipv6a[16+1]; unsigned char ipv4a[4+1]; const char *ipv6src = "fe80::214:4fff:fe0b:76c8"; const char *ipv4src = "192.168.100.1"; /* - */ memset(ipv4a, 1, sizeof(ipv4a)); if(1 != inet_pton(AF_INET, ipv4src, ipv4a)) exit(1); /* fail */ /* - */ if( (ipv4a[0] != 0xc0) || (ipv4a[1] != 0xa8) || (ipv4a[2] != 0x64) || (ipv4a[3] != 0x01) || (ipv4a[4] != 0x01) ) exit(1); /* fail */ /* - */ memset(ipv6a, 1, sizeof(ipv6a)); if(1 != inet_pton(AF_INET6, ipv6src, ipv6a)) exit(1); /* fail */ /* - */ if( (ipv6a[0] != 0xfe) || (ipv6a[1] != 0x80) || (ipv6a[8] != 0x02) || (ipv6a[9] != 0x14) || (ipv6a[10] != 0x4f) || (ipv6a[11] != 0xff) || (ipv6a[12] != 0xfe) || (ipv6a[13] != 0x0b) || (ipv6a[14] != 0x76) || (ipv6a[15] != 0xc8) || (ipv6a[16] != 0x01) ) exit(1); /* fail */ /* - */ if( (ipv6a[2] != 0x0) || (ipv6a[3] != 0x0) || (ipv6a[4] != 0x0) || (ipv6a[5] != 0x0) || (ipv6a[6] != 0x0) || (ipv6a[7] != 0x0) ) exit(1); /* fail */ /* - */ exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_inet_pton="yes" ],[ AC_MSG_RESULT([no]) tst_works_inet_pton="no" ]) fi # if test "$tst_compi_inet_pton" = "yes" && test "$tst_works_inet_pton" != "no"; then AC_MSG_CHECKING([if inet_pton usage allowed]) if test "x$curl_disallow_inet_pton" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_inet_pton="yes" else AC_MSG_RESULT([no]) tst_allow_inet_pton="no" fi fi # AC_MSG_CHECKING([if inet_pton might be used]) if test "$tst_links_inet_pton" = "yes" && test "$tst_proto_inet_pton" = "yes" && test "$tst_compi_inet_pton" = "yes" && test "$tst_allow_inet_pton" = "yes" && test "$tst_works_inet_pton" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_INET_PTON, 1, [Define to 1 if you have a IPv6 capable working inet_pton function.]) curl_cv_func_inet_pton="yes" else AC_MSG_RESULT([no]) curl_cv_func_inet_pton="no" fi ]) dnl CURL_CHECK_FUNC_IOCTL dnl ------------------------------------------------- dnl Verify if ioctl is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_ioctl, then dnl HAVE_IOCTL will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTL], [ AC_REQUIRE([CURL_INCLUDES_STROPTS])dnl # tst_links_ioctl="unknown" tst_proto_ioctl="unknown" tst_compi_ioctl="unknown" tst_allow_ioctl="unknown" # AC_MSG_CHECKING([if ioctl can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([ioctl]) ],[ AC_MSG_RESULT([yes]) tst_links_ioctl="yes" ],[ AC_MSG_RESULT([no]) tst_links_ioctl="no" ]) # if test "$tst_links_ioctl" = "yes"; then AC_MSG_CHECKING([if ioctl is prototyped]) AC_EGREP_CPP([ioctl],[ $curl_includes_stropts ],[ AC_MSG_RESULT([yes]) tst_proto_ioctl="yes" ],[ AC_MSG_RESULT([no]) tst_proto_ioctl="no" ]) fi # if test "$tst_proto_ioctl" = "yes"; then AC_MSG_CHECKING([if ioctl is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stropts ]],[[ if(0 != ioctl(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctl="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctl="no" ]) fi # if test "$tst_compi_ioctl" = "yes"; then AC_MSG_CHECKING([if ioctl usage allowed]) if test "x$curl_disallow_ioctl" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctl="yes" else AC_MSG_RESULT([no]) tst_allow_ioctl="no" fi fi # AC_MSG_CHECKING([if ioctl might be used]) if test "$tst_links_ioctl" = "yes" && test "$tst_proto_ioctl" = "yes" && test "$tst_compi_ioctl" = "yes" && test "$tst_allow_ioctl" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTL, 1, [Define to 1 if you have the ioctl function.]) curl_cv_func_ioctl="yes" CURL_CHECK_FUNC_IOCTL_FIONBIO CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR else AC_MSG_RESULT([no]) curl_cv_func_ioctl="no" fi ]) dnl CURL_CHECK_FUNC_IOCTL_FIONBIO dnl ------------------------------------------------- dnl Verify if ioctl with the FIONBIO command is dnl available, can be compiled, and seems to work. If dnl all of these are true, then HAVE_IOCTL_FIONBIO dnl will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTL_FIONBIO], [ # tst_compi_ioctl_fionbio="unknown" tst_allow_ioctl_fionbio="unknown" # if test "$curl_cv_func_ioctl" = "yes"; then AC_MSG_CHECKING([if ioctl FIONBIO is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stropts ]],[[ int flags = 0; if(0 != ioctl(0, FIONBIO, &flags)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctl_fionbio="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctl_fionbio="no" ]) fi # if test "$tst_compi_ioctl_fionbio" = "yes"; then AC_MSG_CHECKING([if ioctl FIONBIO usage allowed]) if test "x$curl_disallow_ioctl_fionbio" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctl_fionbio="yes" else AC_MSG_RESULT([no]) tst_allow_ioctl_fionbio="no" fi fi # AC_MSG_CHECKING([if ioctl FIONBIO might be used]) if test "$tst_compi_ioctl_fionbio" = "yes" && test "$tst_allow_ioctl_fionbio" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTL_FIONBIO, 1, [Define to 1 if you have a working ioctl FIONBIO function.]) curl_cv_func_ioctl_fionbio="yes" else AC_MSG_RESULT([no]) curl_cv_func_ioctl_fionbio="no" fi ]) dnl CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR dnl ------------------------------------------------- dnl Verify if ioctl with the SIOCGIFADDR command is available, dnl struct ifreq is defined, they can be compiled, and seem to dnl work. If all of these are true, then HAVE_IOCTL_SIOCGIFADDR dnl will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR], [ # tst_compi_ioctl_siocgifaddr="unknown" tst_allow_ioctl_siocgifaddr="unknown" # if test "$curl_cv_func_ioctl" = "yes"; then AC_MSG_CHECKING([if ioctl SIOCGIFADDR is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stropts #include ]],[[ struct ifreq ifr; if(0 != ioctl(0, SIOCGIFADDR, &ifr)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctl_siocgifaddr="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctl_siocgifaddr="no" ]) fi # if test "$tst_compi_ioctl_siocgifaddr" = "yes"; then AC_MSG_CHECKING([if ioctl SIOCGIFADDR usage allowed]) if test "x$curl_disallow_ioctl_siocgifaddr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctl_siocgifaddr="yes" else AC_MSG_RESULT([no]) tst_allow_ioctl_siocgifaddr="no" fi fi # AC_MSG_CHECKING([if ioctl SIOCGIFADDR might be used]) if test "$tst_compi_ioctl_siocgifaddr" = "yes" && test "$tst_allow_ioctl_siocgifaddr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTL_SIOCGIFADDR, 1, [Define to 1 if you have a working ioctl SIOCGIFADDR function.]) curl_cv_func_ioctl_siocgifaddr="yes" else AC_MSG_RESULT([no]) curl_cv_func_ioctl_siocgifaddr="no" fi ]) dnl CURL_CHECK_FUNC_IOCTLSOCKET dnl ------------------------------------------------- dnl Verify if ioctlsocket is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_ioctlsocket, then dnl HAVE_IOCTLSOCKET will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl # tst_links_ioctlsocket="unknown" tst_proto_ioctlsocket="unknown" tst_compi_ioctlsocket="unknown" tst_allow_ioctlsocket="unknown" # AC_MSG_CHECKING([if ioctlsocket can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket ]],[[ if(0 != ioctlsocket(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_ioctlsocket="yes" ],[ AC_MSG_RESULT([no]) tst_links_ioctlsocket="no" ]) # if test "$tst_links_ioctlsocket" = "yes"; then AC_MSG_CHECKING([if ioctlsocket is prototyped]) AC_EGREP_CPP([ioctlsocket],[ $curl_includes_winsock2 $curl_includes_bsdsocket ],[ AC_MSG_RESULT([yes]) tst_proto_ioctlsocket="yes" ],[ AC_MSG_RESULT([no]) tst_proto_ioctlsocket="no" ]) fi # if test "$tst_proto_ioctlsocket" = "yes"; then AC_MSG_CHECKING([if ioctlsocket is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket ]],[[ if(0 != ioctlsocket(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctlsocket="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctlsocket="no" ]) fi # if test "$tst_compi_ioctlsocket" = "yes"; then AC_MSG_CHECKING([if ioctlsocket usage allowed]) if test "x$curl_disallow_ioctlsocket" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctlsocket="yes" else AC_MSG_RESULT([no]) tst_allow_ioctlsocket="no" fi fi # AC_MSG_CHECKING([if ioctlsocket might be used]) if test "$tst_links_ioctlsocket" = "yes" && test "$tst_proto_ioctlsocket" = "yes" && test "$tst_compi_ioctlsocket" = "yes" && test "$tst_allow_ioctlsocket" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET, 1, [Define to 1 if you have the ioctlsocket function.]) curl_cv_func_ioctlsocket="yes" CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO else AC_MSG_RESULT([no]) curl_cv_func_ioctlsocket="no" fi ]) dnl CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO dnl ------------------------------------------------- dnl Verify if ioctlsocket with the FIONBIO command is dnl available, can be compiled, and seems to work. If dnl all of these are true, then HAVE_IOCTLSOCKET_FIONBIO dnl will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_FIONBIO], [ # tst_compi_ioctlsocket_fionbio="unknown" tst_allow_ioctlsocket_fionbio="unknown" # if test "$curl_cv_func_ioctlsocket" = "yes"; then AC_MSG_CHECKING([if ioctlsocket FIONBIO is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket ]],[[ int flags = 0; if(0 != ioctlsocket(0, FIONBIO, &flags)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctlsocket_fionbio="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctlsocket_fionbio="no" ]) fi # if test "$tst_compi_ioctlsocket_fionbio" = "yes"; then AC_MSG_CHECKING([if ioctlsocket FIONBIO usage allowed]) if test "x$curl_disallow_ioctlsocket_fionbio" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctlsocket_fionbio="yes" else AC_MSG_RESULT([no]) tst_allow_ioctlsocket_fionbio="no" fi fi # AC_MSG_CHECKING([if ioctlsocket FIONBIO might be used]) if test "$tst_compi_ioctlsocket_fionbio" = "yes" && test "$tst_allow_ioctlsocket_fionbio" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_FIONBIO, 1, [Define to 1 if you have a working ioctlsocket FIONBIO function.]) curl_cv_func_ioctlsocket_fionbio="yes" else AC_MSG_RESULT([no]) curl_cv_func_ioctlsocket_fionbio="no" fi ]) dnl CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL dnl ------------------------------------------------- dnl Verify if IoctlSocket is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_ioctlsocket_camel, dnl then HAVE_IOCTLSOCKET_CAMEL will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL], [ AC_REQUIRE([CURL_INCLUDES_STROPTS])dnl # tst_links_ioctlsocket_camel="unknown" tst_proto_ioctlsocket_camel="unknown" tst_compi_ioctlsocket_camel="unknown" tst_allow_ioctlsocket_camel="unknown" # AC_MSG_CHECKING([if IoctlSocket can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([IoctlSocket]) ],[ AC_MSG_RESULT([yes]) tst_links_ioctlsocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_links_ioctlsocket_camel="no" ]) # if test "$tst_links_ioctlsocket_camel" = "yes"; then AC_MSG_CHECKING([if IoctlSocket is prototyped]) AC_EGREP_CPP([IoctlSocket],[ $curl_includes_stropts ],[ AC_MSG_RESULT([yes]) tst_proto_ioctlsocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_proto_ioctlsocket_camel="no" ]) fi # if test "$tst_proto_ioctlsocket_camel" = "yes"; then AC_MSG_CHECKING([if IoctlSocket is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stropts ]],[[ if(0 != IoctlSocket(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctlsocket_camel="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctlsocket_camel="no" ]) fi # if test "$tst_compi_ioctlsocket_camel" = "yes"; then AC_MSG_CHECKING([if IoctlSocket usage allowed]) if test "x$curl_disallow_ioctlsocket_camel" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctlsocket_camel="yes" else AC_MSG_RESULT([no]) tst_allow_ioctlsocket_camel="no" fi fi # AC_MSG_CHECKING([if IoctlSocket might be used]) if test "$tst_links_ioctlsocket_camel" = "yes" && test "$tst_proto_ioctlsocket_camel" = "yes" && test "$tst_compi_ioctlsocket_camel" = "yes" && test "$tst_allow_ioctlsocket_camel" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_CAMEL, 1, [Define to 1 if you have the IoctlSocket camel case function.]) curl_cv_func_ioctlsocket_camel="yes" CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO else AC_MSG_RESULT([no]) curl_cv_func_ioctlsocket_camel="no" fi ]) dnl CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO dnl ------------------------------------------------- dnl Verify if IoctlSocket with FIONBIO command is available, dnl can be compiled, and seems to work. If all of these are dnl true, then HAVE_IOCTLSOCKET_CAMEL_FIONBIO will be defined. AC_DEFUN([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL_FIONBIO], [ # tst_compi_ioctlsocket_camel_fionbio="unknown" tst_allow_ioctlsocket_camel_fionbio="unknown" # if test "$curl_cv_func_ioctlsocket_camel" = "yes"; then AC_MSG_CHECKING([if IoctlSocket FIONBIO is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stropts ]],[[ long flags = 0; if(0 != ioctlsocket(0, FIONBIO, &flags)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_ioctlsocket_camel_fionbio="yes" ],[ AC_MSG_RESULT([no]) tst_compi_ioctlsocket_camel_fionbio="no" ]) fi # if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes"; then AC_MSG_CHECKING([if IoctlSocket FIONBIO usage allowed]) if test "x$curl_disallow_ioctlsocket_camel_fionbio" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_ioctlsocket_camel_fionbio="yes" else AC_MSG_RESULT([no]) tst_allow_ioctlsocket_camel_fionbio="no" fi fi # AC_MSG_CHECKING([if IoctlSocket FIONBIO might be used]) if test "$tst_compi_ioctlsocket_camel_fionbio" = "yes" && test "$tst_allow_ioctlsocket_camel_fionbio" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_IOCTLSOCKET_CAMEL_FIONBIO, 1, [Define to 1 if you have a working IoctlSocket camel case FIONBIO function.]) curl_cv_func_ioctlsocket_camel_fionbio="yes" else AC_MSG_RESULT([no]) curl_cv_func_ioctlsocket_camel_fionbio="no" fi ]) dnl CURL_CHECK_FUNC_LISTXATTR dnl ------------------------------------------------- dnl Verify if listxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_listxattr, then dnl HAVE_LISTXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_LISTXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_listxattr="unknown" tst_proto_listxattr="unknown" tst_compi_listxattr="unknown" tst_allow_listxattr="unknown" tst_nargs_listxattr="unknown" # AC_MSG_CHECKING([if listxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([listxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_listxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_listxattr="no" ]) # if test "$tst_links_listxattr" = "yes"; then AC_MSG_CHECKING([if listxattr is prototyped]) AC_EGREP_CPP([listxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_listxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_listxattr="no" ]) fi # if test "$tst_proto_listxattr" = "yes"; then if test "$tst_nargs_listxattr" = "unknown"; then AC_MSG_CHECKING([if listxattr takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != listxattr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_listxattr="yes" tst_nargs_listxattr="3" ],[ AC_MSG_RESULT([no]) tst_compi_listxattr="no" ]) fi if test "$tst_nargs_listxattr" = "unknown"; then AC_MSG_CHECKING([if listxattr takes 4 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != listxattr(0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_listxattr="yes" tst_nargs_listxattr="4" ],[ AC_MSG_RESULT([no]) tst_compi_listxattr="no" ]) fi AC_MSG_CHECKING([if listxattr is compilable]) if test "$tst_compi_listxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_listxattr" = "yes"; then AC_MSG_CHECKING([if listxattr usage allowed]) if test "x$curl_disallow_listxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_listxattr="yes" else AC_MSG_RESULT([no]) tst_allow_listxattr="no" fi fi # AC_MSG_CHECKING([if listxattr might be used]) if test "$tst_links_listxattr" = "yes" && test "$tst_proto_listxattr" = "yes" && test "$tst_compi_listxattr" = "yes" && test "$tst_allow_listxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_LISTXATTR, 1, [Define to 1 if you have the listxattr function.]) dnl AC_DEFINE_UNQUOTED(LISTXATTR_ARGS, $tst_nargs_listxattr, dnl [Specifies the number of arguments to listxattr]) # if test "$tst_nargs_listxattr" -eq "3"; then AC_DEFINE(HAVE_LISTXATTR_3, 1, [listxattr() takes 3 args]) elif test "$tst_nargs_listxattr" -eq "4"; then AC_DEFINE(HAVE_LISTXATTR_4, 1, [listxattr() takes 4 args]) fi # curl_cv_func_listxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_listxattr="no" fi ]) dnl CURL_CHECK_FUNC_LOCALTIME_R dnl ------------------------------------------------- dnl Verify if localtime_r is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_localtime_r, then dnl HAVE_LOCALTIME_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_LOCALTIME_R], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_TIME])dnl # tst_links_localtime_r="unknown" tst_proto_localtime_r="unknown" tst_compi_localtime_r="unknown" tst_works_localtime_r="unknown" tst_allow_localtime_r="unknown" # AC_MSG_CHECKING([if localtime_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([localtime_r]) ],[ AC_MSG_RESULT([yes]) tst_links_localtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_localtime_r="no" ]) # if test "$tst_links_localtime_r" = "yes"; then AC_MSG_CHECKING([if localtime_r is prototyped]) AC_EGREP_CPP([localtime_r],[ $curl_includes_time ],[ AC_MSG_RESULT([yes]) tst_proto_localtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_localtime_r="no" ]) fi # if test "$tst_proto_localtime_r" = "yes"; then AC_MSG_CHECKING([if localtime_r is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_time ]],[[ if(0 != localtime_r(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_localtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_compi_localtime_r="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_localtime_r" = "yes"; then AC_MSG_CHECKING([if localtime_r seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_time ]],[[ time_t clock = 1170352587; struct tm *tmp = 0; struct tm result; tmp = localtime_r(&clock, &result); if(tmp) exit(0); else exit(1); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_localtime_r="yes" ],[ AC_MSG_RESULT([no]) tst_works_localtime_r="no" ]) fi # if test "$tst_compi_localtime_r" = "yes" && test "$tst_works_localtime_r" != "no"; then AC_MSG_CHECKING([if localtime_r usage allowed]) if test "x$curl_disallow_localtime_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_localtime_r="yes" else AC_MSG_RESULT([no]) tst_allow_localtime_r="no" fi fi # AC_MSG_CHECKING([if localtime_r might be used]) if test "$tst_links_localtime_r" = "yes" && test "$tst_proto_localtime_r" = "yes" && test "$tst_compi_localtime_r" = "yes" && test "$tst_allow_localtime_r" = "yes" && test "$tst_works_localtime_r" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_LOCALTIME_R, 1, [Define to 1 if you have a working localtime_r function.]) curl_cv_func_localtime_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_localtime_r="no" fi ]) dnl CURL_CHECK_FUNC_MEMRCHR dnl ------------------------------------------------- dnl Verify if memrchr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_memrchr, then dnl HAVE_MEMRCHR will be defined. AC_DEFUN([CURL_CHECK_FUNC_MEMRCHR], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_memrchr="unknown" tst_macro_memrchr="unknown" tst_proto_memrchr="unknown" tst_compi_memrchr="unknown" tst_allow_memrchr="unknown" # AC_MSG_CHECKING([if memrchr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([memrchr]) ],[ AC_MSG_RESULT([yes]) tst_links_memrchr="yes" ],[ AC_MSG_RESULT([no]) tst_links_memrchr="no" ]) # if test "$tst_links_memrchr" = "no"; then AC_MSG_CHECKING([if memrchr seems a macro]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != memrchr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_macro_memrchr="yes" ],[ AC_MSG_RESULT([no]) tst_macro_memrchr="no" ]) fi # if test "$tst_links_memrchr" = "yes"; then AC_MSG_CHECKING([if memrchr is prototyped]) AC_EGREP_CPP([memrchr],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_memrchr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_memrchr="no" ]) fi # if test "$tst_proto_memrchr" = "yes" || test "$tst_macro_memrchr" = "yes"; then AC_MSG_CHECKING([if memrchr is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != memrchr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_memrchr="yes" ],[ AC_MSG_RESULT([no]) tst_compi_memrchr="no" ]) fi # if test "$tst_compi_memrchr" = "yes"; then AC_MSG_CHECKING([if memrchr usage allowed]) if test "x$curl_disallow_memrchr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_memrchr="yes" else AC_MSG_RESULT([no]) tst_allow_memrchr="no" fi fi # AC_MSG_CHECKING([if memrchr might be used]) if (test "$tst_proto_memrchr" = "yes" || test "$tst_macro_memrchr" = "yes") && test "$tst_compi_memrchr" = "yes" && test "$tst_allow_memrchr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_MEMRCHR, 1, [Define to 1 if you have the memrchr function or macro.]) curl_cv_func_memrchr="yes" else AC_MSG_RESULT([no]) curl_cv_func_memrchr="no" fi ]) dnl CURL_CHECK_FUNC_POLL dnl ------------------------------------------------- dnl Verify if poll is available, prototyped, can dnl be compiled and seems to work. If all of these are dnl true, and usage has not been previously disallowed dnl with shell variable curl_disallow_poll, then dnl HAVE_POLL will be defined. AC_DEFUN([CURL_CHECK_FUNC_POLL], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_POLL])dnl # tst_links_poll="unknown" tst_proto_poll="unknown" tst_compi_poll="unknown" tst_works_poll="unknown" tst_allow_poll="unknown" # case $host_os in darwin*|interix*) dnl poll() does not work on these platforms dnl Interix: "does provide poll(), but the implementing developer must dnl have been in a bad mood, because poll() only works on the /proc dnl filesystem here" dnl macOS: poll() first didn't exist, then was broken until fixed in 10.9 dnl only to break again in 10.12. curl_disallow_poll="yes" tst_compi_poll="no" ;; esac # AC_MSG_CHECKING([if poll can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_poll ]],[[ if(0 != poll(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_poll="yes" ],[ AC_MSG_RESULT([no]) tst_links_poll="no" ]) # if test "$tst_links_poll" = "yes"; then AC_MSG_CHECKING([if poll is prototyped]) AC_EGREP_CPP([poll],[ $curl_includes_poll ],[ AC_MSG_RESULT([yes]) tst_proto_poll="yes" ],[ AC_MSG_RESULT([no]) tst_proto_poll="no" ]) fi # if test "$tst_proto_poll" = "yes"; then AC_MSG_CHECKING([if poll is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_poll ]],[[ if(0 != poll(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_poll="yes" ],[ AC_MSG_RESULT([no]) tst_compi_poll="no" ]) fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_compi_poll" = "yes"; then AC_MSG_CHECKING([if poll seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_poll $curl_includes_time ]],[[ /* detect the original poll() breakage */ if(0 != poll(0, 0, 10)) exit(1); /* fail */ else { /* detect the 10.12 poll() breakage */ struct timeval before, after; int rc; size_t us; gettimeofday(&before, NULL); rc = poll(NULL, 0, 500); gettimeofday(&after, NULL); us = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec); if(us < 400000) exit(1); } ]]) ],[ AC_MSG_RESULT([yes]) tst_works_poll="yes" ],[ AC_MSG_RESULT([no]) tst_works_poll="no" ]) fi # if test "$tst_compi_poll" = "yes" && test "$tst_works_poll" != "no"; then AC_MSG_CHECKING([if poll usage allowed]) if test "x$curl_disallow_poll" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_poll="yes" else AC_MSG_RESULT([no]) tst_allow_poll="no" fi fi # AC_MSG_CHECKING([if poll might be used]) if test "$tst_links_poll" = "yes" && test "$tst_proto_poll" = "yes" && test "$tst_compi_poll" = "yes" && test "$tst_allow_poll" = "yes" && test "$tst_works_poll" != "no"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_POLL, 1, [Define to 1 if you have a working poll function.]) AC_DEFINE_UNQUOTED(HAVE_POLL_FINE, 1, [If you have a fine poll]) curl_cv_func_poll="yes" else AC_MSG_RESULT([no]) curl_cv_func_poll="no" fi ]) dnl CURL_CHECK_FUNC_REMOVEXATTR dnl ------------------------------------------------- dnl Verify if removexattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_removexattr, then dnl HAVE_REMOVEXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_REMOVEXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_removexattr="unknown" tst_proto_removexattr="unknown" tst_compi_removexattr="unknown" tst_allow_removexattr="unknown" tst_nargs_removexattr="unknown" # AC_MSG_CHECKING([if removexattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([removexattr]) ],[ AC_MSG_RESULT([yes]) tst_links_removexattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_removexattr="no" ]) # if test "$tst_links_removexattr" = "yes"; then AC_MSG_CHECKING([if removexattr is prototyped]) AC_EGREP_CPP([removexattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_removexattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_removexattr="no" ]) fi # if test "$tst_proto_removexattr" = "yes"; then if test "$tst_nargs_removexattr" = "unknown"; then AC_MSG_CHECKING([if removexattr takes 2 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != removexattr(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_removexattr="yes" tst_nargs_removexattr="2" ],[ AC_MSG_RESULT([no]) tst_compi_removexattr="no" ]) fi if test "$tst_nargs_removexattr" = "unknown"; then AC_MSG_CHECKING([if removexattr takes 3 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != removexattr(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_removexattr="yes" tst_nargs_removexattr="3" ],[ AC_MSG_RESULT([no]) tst_compi_removexattr="no" ]) fi AC_MSG_CHECKING([if removexattr is compilable]) if test "$tst_compi_removexattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_removexattr" = "yes"; then AC_MSG_CHECKING([if removexattr usage allowed]) if test "x$curl_disallow_removexattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_removexattr="yes" else AC_MSG_RESULT([no]) tst_allow_removexattr="no" fi fi # AC_MSG_CHECKING([if removexattr might be used]) if test "$tst_links_removexattr" = "yes" && test "$tst_proto_removexattr" = "yes" && test "$tst_compi_removexattr" = "yes" && test "$tst_allow_removexattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_REMOVEXATTR, 1, [Define to 1 if you have the removexattr function.]) dnl AC_DEFINE_UNQUOTED(REMOVEXATTR_ARGS, $tst_nargs_removexattr, dnl [Specifies the number of arguments to removexattr]) # if test "$tst_nargs_removexattr" -eq "2"; then AC_DEFINE(HAVE_REMOVEXATTR_2, 1, [removexattr() takes 2 args]) elif test "$tst_nargs_removexattr" -eq "3"; then AC_DEFINE(HAVE_REMOVEXATTR_3, 1, [removexattr() takes 3 args]) fi # curl_cv_func_removexattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_removexattr="no" fi ]) dnl CURL_CHECK_FUNC_SETSOCKOPT dnl ------------------------------------------------- dnl Verify if setsockopt is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_setsockopt, then dnl HAVE_SETSOCKOPT will be defined. AC_DEFUN([CURL_CHECK_FUNC_SETSOCKOPT], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl # tst_links_setsockopt="unknown" tst_proto_setsockopt="unknown" tst_compi_setsockopt="unknown" tst_allow_setsockopt="unknown" # AC_MSG_CHECKING([if setsockopt can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != setsockopt(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_setsockopt="yes" ],[ AC_MSG_RESULT([no]) tst_links_setsockopt="no" ]) # if test "$tst_links_setsockopt" = "yes"; then AC_MSG_CHECKING([if setsockopt is prototyped]) AC_EGREP_CPP([setsockopt],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ],[ AC_MSG_RESULT([yes]) tst_proto_setsockopt="yes" ],[ AC_MSG_RESULT([no]) tst_proto_setsockopt="no" ]) fi # if test "$tst_proto_setsockopt" = "yes"; then AC_MSG_CHECKING([if setsockopt is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != setsockopt(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_setsockopt="yes" ],[ AC_MSG_RESULT([no]) tst_compi_setsockopt="no" ]) fi # if test "$tst_compi_setsockopt" = "yes"; then AC_MSG_CHECKING([if setsockopt usage allowed]) if test "x$curl_disallow_setsockopt" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_setsockopt="yes" else AC_MSG_RESULT([no]) tst_allow_setsockopt="no" fi fi # AC_MSG_CHECKING([if setsockopt might be used]) if test "$tst_links_setsockopt" = "yes" && test "$tst_proto_setsockopt" = "yes" && test "$tst_compi_setsockopt" = "yes" && test "$tst_allow_setsockopt" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SETSOCKOPT, 1, [Define to 1 if you have the setsockopt function.]) curl_cv_func_setsockopt="yes" CURL_CHECK_FUNC_SETSOCKOPT_SO_NONBLOCK else AC_MSG_RESULT([no]) curl_cv_func_setsockopt="no" fi ]) dnl CURL_CHECK_FUNC_SETSOCKOPT_SO_NONBLOCK dnl ------------------------------------------------- dnl Verify if setsockopt with the SO_NONBLOCK command is dnl available, can be compiled, and seems to work. If dnl all of these are true, then HAVE_SETSOCKOPT_SO_NONBLOCK dnl will be defined. AC_DEFUN([CURL_CHECK_FUNC_SETSOCKOPT_SO_NONBLOCK], [ # tst_compi_setsockopt_so_nonblock="unknown" tst_allow_setsockopt_so_nonblock="unknown" # if test "$curl_cv_func_setsockopt" = "yes"; then AC_MSG_CHECKING([if setsockopt SO_NONBLOCK is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket ]],[[ if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_setsockopt_so_nonblock="yes" ],[ AC_MSG_RESULT([no]) tst_compi_setsockopt_so_nonblock="no" ]) fi # if test "$tst_compi_setsockopt_so_nonblock" = "yes"; then AC_MSG_CHECKING([if setsockopt SO_NONBLOCK usage allowed]) if test "x$curl_disallow_setsockopt_so_nonblock" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_setsockopt_so_nonblock="yes" else AC_MSG_RESULT([no]) tst_allow_setsockopt_so_nonblock="no" fi fi # AC_MSG_CHECKING([if setsockopt SO_NONBLOCK might be used]) if test "$tst_compi_setsockopt_so_nonblock" = "yes" && test "$tst_allow_setsockopt_so_nonblock" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SETSOCKOPT_SO_NONBLOCK, 1, [Define to 1 if you have a working setsockopt SO_NONBLOCK function.]) curl_cv_func_setsockopt_so_nonblock="yes" else AC_MSG_RESULT([no]) curl_cv_func_setsockopt_so_nonblock="no" fi ]) dnl CURL_CHECK_FUNC_SETXATTR dnl ------------------------------------------------- dnl Verify if setxattr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_setxattr, then dnl HAVE_SETXATTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_SETXATTR], [ AC_REQUIRE([CURL_INCLUDES_SYS_XATTR])dnl # tst_links_setxattr="unknown" tst_proto_setxattr="unknown" tst_compi_setxattr="unknown" tst_allow_setxattr="unknown" tst_nargs_setxattr="unknown" # AC_MSG_CHECKING([if setxattr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([setxattr]) ],[ AC_MSG_RESULT([yes]) tst_links_setxattr="yes" ],[ AC_MSG_RESULT([no]) tst_links_setxattr="no" ]) # if test "$tst_links_setxattr" = "yes"; then AC_MSG_CHECKING([if setxattr is prototyped]) AC_EGREP_CPP([setxattr],[ $curl_includes_sys_xattr ],[ AC_MSG_RESULT([yes]) tst_proto_setxattr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_setxattr="no" ]) fi # if test "$tst_proto_setxattr" = "yes"; then if test "$tst_nargs_setxattr" = "unknown"; then AC_MSG_CHECKING([if setxattr takes 5 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != setxattr(0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_setxattr="yes" tst_nargs_setxattr="5" ],[ AC_MSG_RESULT([no]) tst_compi_setxattr="no" ]) fi if test "$tst_nargs_setxattr" = "unknown"; then AC_MSG_CHECKING([if setxattr takes 6 args.]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_xattr ]],[[ if(0 != setxattr(0, 0, 0, 0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_setxattr="yes" tst_nargs_setxattr="6" ],[ AC_MSG_RESULT([no]) tst_compi_setxattr="no" ]) fi AC_MSG_CHECKING([if setxattr is compilable]) if test "$tst_compi_setxattr" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # if test "$tst_compi_setxattr" = "yes"; then AC_MSG_CHECKING([if setxattr usage allowed]) if test "x$curl_disallow_setxattr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_setxattr="yes" else AC_MSG_RESULT([no]) tst_allow_setxattr="no" fi fi # AC_MSG_CHECKING([if setxattr might be used]) if test "$tst_links_setxattr" = "yes" && test "$tst_proto_setxattr" = "yes" && test "$tst_compi_setxattr" = "yes" && test "$tst_allow_setxattr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SETXATTR, 1, [Define to 1 if you have the setxattr function.]) dnl AC_DEFINE_UNQUOTED(SETXATTR_ARGS, $tst_nargs_setxattr, dnl [Specifies the number of arguments to setxattr]) # if test "$tst_nargs_setxattr" -eq "5"; then AC_DEFINE(HAVE_SETXATTR_5, 1, [setxattr() takes 5 args]) elif test "$tst_nargs_setxattr" -eq "6"; then AC_DEFINE(HAVE_SETXATTR_6, 1, [setxattr() takes 6 args]) fi # curl_cv_func_setxattr="yes" else AC_MSG_RESULT([no]) curl_cv_func_setxattr="no" fi ]) dnl CURL_CHECK_FUNC_SIGACTION dnl ------------------------------------------------- dnl Verify if sigaction is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_sigaction, then dnl HAVE_SIGACTION will be defined. AC_DEFUN([CURL_CHECK_FUNC_SIGACTION], [ AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl # tst_links_sigaction="unknown" tst_proto_sigaction="unknown" tst_compi_sigaction="unknown" tst_allow_sigaction="unknown" # AC_MSG_CHECKING([if sigaction can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([sigaction]) ],[ AC_MSG_RESULT([yes]) tst_links_sigaction="yes" ],[ AC_MSG_RESULT([no]) tst_links_sigaction="no" ]) # if test "$tst_links_sigaction" = "yes"; then AC_MSG_CHECKING([if sigaction is prototyped]) AC_EGREP_CPP([sigaction],[ $curl_includes_signal ],[ AC_MSG_RESULT([yes]) tst_proto_sigaction="yes" ],[ AC_MSG_RESULT([no]) tst_proto_sigaction="no" ]) fi # if test "$tst_proto_sigaction" = "yes"; then AC_MSG_CHECKING([if sigaction is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_signal ]],[[ if(0 != sigaction(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_sigaction="yes" ],[ AC_MSG_RESULT([no]) tst_compi_sigaction="no" ]) fi # if test "$tst_compi_sigaction" = "yes"; then AC_MSG_CHECKING([if sigaction usage allowed]) if test "x$curl_disallow_sigaction" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_sigaction="yes" else AC_MSG_RESULT([no]) tst_allow_sigaction="no" fi fi # AC_MSG_CHECKING([if sigaction might be used]) if test "$tst_links_sigaction" = "yes" && test "$tst_proto_sigaction" = "yes" && test "$tst_compi_sigaction" = "yes" && test "$tst_allow_sigaction" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SIGACTION, 1, [Define to 1 if you have the sigaction function.]) curl_cv_func_sigaction="yes" else AC_MSG_RESULT([no]) curl_cv_func_sigaction="no" fi ]) dnl CURL_CHECK_FUNC_SIGINTERRUPT dnl ------------------------------------------------- dnl Verify if siginterrupt is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_siginterrupt, then dnl HAVE_SIGINTERRUPT will be defined. AC_DEFUN([CURL_CHECK_FUNC_SIGINTERRUPT], [ AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl # tst_links_siginterrupt="unknown" tst_proto_siginterrupt="unknown" tst_compi_siginterrupt="unknown" tst_allow_siginterrupt="unknown" # AC_MSG_CHECKING([if siginterrupt can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([siginterrupt]) ],[ AC_MSG_RESULT([yes]) tst_links_siginterrupt="yes" ],[ AC_MSG_RESULT([no]) tst_links_siginterrupt="no" ]) # if test "$tst_links_siginterrupt" = "yes"; then AC_MSG_CHECKING([if siginterrupt is prototyped]) AC_EGREP_CPP([siginterrupt],[ $curl_includes_signal ],[ AC_MSG_RESULT([yes]) tst_proto_siginterrupt="yes" ],[ AC_MSG_RESULT([no]) tst_proto_siginterrupt="no" ]) fi # if test "$tst_proto_siginterrupt" = "yes"; then AC_MSG_CHECKING([if siginterrupt is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_signal ]],[[ if(0 != siginterrupt(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_siginterrupt="yes" ],[ AC_MSG_RESULT([no]) tst_compi_siginterrupt="no" ]) fi # if test "$tst_compi_siginterrupt" = "yes"; then AC_MSG_CHECKING([if siginterrupt usage allowed]) if test "x$curl_disallow_siginterrupt" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_siginterrupt="yes" else AC_MSG_RESULT([no]) tst_allow_siginterrupt="no" fi fi # AC_MSG_CHECKING([if siginterrupt might be used]) if test "$tst_links_siginterrupt" = "yes" && test "$tst_proto_siginterrupt" = "yes" && test "$tst_compi_siginterrupt" = "yes" && test "$tst_allow_siginterrupt" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SIGINTERRUPT, 1, [Define to 1 if you have the siginterrupt function.]) curl_cv_func_siginterrupt="yes" else AC_MSG_RESULT([no]) curl_cv_func_siginterrupt="no" fi ]) dnl CURL_CHECK_FUNC_SIGNAL dnl ------------------------------------------------- dnl Verify if signal is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_signal, then dnl HAVE_SIGNAL will be defined. AC_DEFUN([CURL_CHECK_FUNC_SIGNAL], [ AC_REQUIRE([CURL_INCLUDES_SIGNAL])dnl # tst_links_signal="unknown" tst_proto_signal="unknown" tst_compi_signal="unknown" tst_allow_signal="unknown" # AC_MSG_CHECKING([if signal can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([signal]) ],[ AC_MSG_RESULT([yes]) tst_links_signal="yes" ],[ AC_MSG_RESULT([no]) tst_links_signal="no" ]) # if test "$tst_links_signal" = "yes"; then AC_MSG_CHECKING([if signal is prototyped]) AC_EGREP_CPP([signal],[ $curl_includes_signal ],[ AC_MSG_RESULT([yes]) tst_proto_signal="yes" ],[ AC_MSG_RESULT([no]) tst_proto_signal="no" ]) fi # if test "$tst_proto_signal" = "yes"; then AC_MSG_CHECKING([if signal is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_signal ]],[[ if(0 != signal(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_signal="yes" ],[ AC_MSG_RESULT([no]) tst_compi_signal="no" ]) fi # if test "$tst_compi_signal" = "yes"; then AC_MSG_CHECKING([if signal usage allowed]) if test "x$curl_disallow_signal" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_signal="yes" else AC_MSG_RESULT([no]) tst_allow_signal="no" fi fi # AC_MSG_CHECKING([if signal might be used]) if test "$tst_links_signal" = "yes" && test "$tst_proto_signal" = "yes" && test "$tst_compi_signal" = "yes" && test "$tst_allow_signal" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SIGNAL, 1, [Define to 1 if you have the signal function.]) curl_cv_func_signal="yes" else AC_MSG_RESULT([no]) curl_cv_func_signal="no" fi ]) dnl CURL_CHECK_FUNC_SIGSETJMP dnl ------------------------------------------------- dnl Verify if sigsetjmp is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_sigsetjmp, then dnl HAVE_SIGSETJMP will be defined. AC_DEFUN([CURL_CHECK_FUNC_SIGSETJMP], [ AC_REQUIRE([CURL_INCLUDES_SETJMP])dnl # tst_links_sigsetjmp="unknown" tst_macro_sigsetjmp="unknown" tst_proto_sigsetjmp="unknown" tst_compi_sigsetjmp="unknown" tst_allow_sigsetjmp="unknown" # AC_MSG_CHECKING([if sigsetjmp can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([sigsetjmp]) ],[ AC_MSG_RESULT([yes]) tst_links_sigsetjmp="yes" ],[ AC_MSG_RESULT([no]) tst_links_sigsetjmp="no" ]) # if test "$tst_links_sigsetjmp" = "no"; then AC_MSG_CHECKING([if sigsetjmp seems a macro]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_setjmp ]],[[ sigjmp_buf env; if(0 != sigsetjmp(env, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_macro_sigsetjmp="yes" ],[ AC_MSG_RESULT([no]) tst_macro_sigsetjmp="no" ]) fi # if test "$tst_links_sigsetjmp" = "yes"; then AC_MSG_CHECKING([if sigsetjmp is prototyped]) AC_EGREP_CPP([sigsetjmp],[ $curl_includes_setjmp ],[ AC_MSG_RESULT([yes]) tst_proto_sigsetjmp="yes" ],[ AC_MSG_RESULT([no]) tst_proto_sigsetjmp="no" ]) fi # if test "$tst_proto_sigsetjmp" = "yes" || test "$tst_macro_sigsetjmp" = "yes"; then AC_MSG_CHECKING([if sigsetjmp is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_setjmp ]],[[ sigjmp_buf env; if(0 != sigsetjmp(env, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_sigsetjmp="yes" ],[ AC_MSG_RESULT([no]) tst_compi_sigsetjmp="no" ]) fi # if test "$tst_compi_sigsetjmp" = "yes"; then AC_MSG_CHECKING([if sigsetjmp usage allowed]) if test "x$curl_disallow_sigsetjmp" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_sigsetjmp="yes" else AC_MSG_RESULT([no]) tst_allow_sigsetjmp="no" fi fi # AC_MSG_CHECKING([if sigsetjmp might be used]) if (test "$tst_proto_sigsetjmp" = "yes" || test "$tst_macro_sigsetjmp" = "yes") && test "$tst_compi_sigsetjmp" = "yes" && test "$tst_allow_sigsetjmp" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SIGSETJMP, 1, [Define to 1 if you have the sigsetjmp function or macro.]) curl_cv_func_sigsetjmp="yes" else AC_MSG_RESULT([no]) curl_cv_func_sigsetjmp="no" fi ]) dnl CURL_CHECK_FUNC_SOCKET dnl ------------------------------------------------- dnl Verify if socket is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_socket, then dnl HAVE_SOCKET will be defined. AC_DEFUN([CURL_CHECK_FUNC_SOCKET], [ AC_REQUIRE([CURL_INCLUDES_WINSOCK2])dnl AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl # tst_links_socket="unknown" tst_proto_socket="unknown" tst_compi_socket="unknown" tst_allow_socket="unknown" # AC_MSG_CHECKING([if socket can be linked]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ]],[[ if(0 != socket(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_links_socket="yes" ],[ AC_MSG_RESULT([no]) tst_links_socket="no" ]) # if test "$tst_links_socket" = "yes"; then AC_MSG_CHECKING([if socket is prototyped]) AC_EGREP_CPP([socket],[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ],[ AC_MSG_RESULT([yes]) tst_proto_socket="yes" ],[ AC_MSG_RESULT([no]) tst_proto_socket="no" ]) fi # if test "$tst_proto_socket" = "yes"; then AC_MSG_CHECKING([if socket is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_winsock2 $curl_includes_bsdsocket $curl_includes_sys_socket $curl_includes_socket ]],[[ if(0 != socket(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_socket="yes" ],[ AC_MSG_RESULT([no]) tst_compi_socket="no" ]) fi # if test "$tst_compi_socket" = "yes"; then AC_MSG_CHECKING([if socket usage allowed]) if test "x$curl_disallow_socket" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_socket="yes" else AC_MSG_RESULT([no]) tst_allow_socket="no" fi fi # AC_MSG_CHECKING([if socket might be used]) if test "$tst_links_socket" = "yes" && test "$tst_proto_socket" = "yes" && test "$tst_compi_socket" = "yes" && test "$tst_allow_socket" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SOCKET, 1, [Define to 1 if you have the socket function.]) curl_cv_func_socket="yes" else AC_MSG_RESULT([no]) curl_cv_func_socket="no" fi ]) dnl CURL_CHECK_FUNC_SOCKETPAIR dnl ------------------------------------------------- dnl Verify if socketpair is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_socketpair, then dnl HAVE_SOCKETPAIR will be defined. AC_DEFUN([CURL_CHECK_FUNC_SOCKETPAIR], [ AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl # tst_links_socketpair="unknown" tst_proto_socketpair="unknown" tst_compi_socketpair="unknown" tst_allow_socketpair="unknown" # AC_MSG_CHECKING([if socketpair can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([socketpair]) ],[ AC_MSG_RESULT([yes]) tst_links_socketpair="yes" ],[ AC_MSG_RESULT([no]) tst_links_socketpair="no" ]) # if test "$tst_links_socketpair" = "yes"; then AC_MSG_CHECKING([if socketpair is prototyped]) AC_EGREP_CPP([socketpair],[ $curl_includes_sys_socket $curl_includes_socket ],[ AC_MSG_RESULT([yes]) tst_proto_socketpair="yes" ],[ AC_MSG_RESULT([no]) tst_proto_socketpair="no" ]) fi # if test "$tst_proto_socketpair" = "yes"; then AC_MSG_CHECKING([if socketpair is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_socket $curl_includes_socket ]],[[ int sv[2]; if(0 != socketpair(0, 0, 0, sv)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_socketpair="yes" ],[ AC_MSG_RESULT([no]) tst_compi_socketpair="no" ]) fi # if test "$tst_compi_socketpair" = "yes"; then AC_MSG_CHECKING([if socketpair usage allowed]) if test "x$curl_disallow_socketpair" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_socketpair="yes" else AC_MSG_RESULT([no]) tst_allow_socketpair="no" fi fi # AC_MSG_CHECKING([if socketpair might be used]) if test "$tst_links_socketpair" = "yes" && test "$tst_proto_socketpair" = "yes" && test "$tst_compi_socketpair" = "yes" && test "$tst_allow_socketpair" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the socketpair function.]) curl_cv_func_socketpair="yes" else AC_MSG_RESULT([no]) curl_cv_func_socketpair="no" fi ]) dnl CURL_CHECK_FUNC_STRCASECMP dnl ------------------------------------------------- dnl Verify if strcasecmp is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strcasecmp, then dnl HAVE_STRCASECMP will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRCASECMP], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strcasecmp="unknown" tst_proto_strcasecmp="unknown" tst_compi_strcasecmp="unknown" tst_allow_strcasecmp="unknown" # AC_MSG_CHECKING([if strcasecmp can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strcasecmp]) ],[ AC_MSG_RESULT([yes]) tst_links_strcasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_links_strcasecmp="no" ]) # if test "$tst_links_strcasecmp" = "yes"; then AC_MSG_CHECKING([if strcasecmp is prototyped]) AC_EGREP_CPP([strcasecmp],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strcasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strcasecmp="no" ]) fi # if test "$tst_proto_strcasecmp" = "yes"; then AC_MSG_CHECKING([if strcasecmp is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strcasecmp(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strcasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strcasecmp="no" ]) fi # if test "$tst_compi_strcasecmp" = "yes"; then AC_MSG_CHECKING([if strcasecmp usage allowed]) if test "x$curl_disallow_strcasecmp" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strcasecmp="yes" else AC_MSG_RESULT([no]) tst_allow_strcasecmp="no" fi fi # AC_MSG_CHECKING([if strcasecmp might be used]) if test "$tst_links_strcasecmp" = "yes" && test "$tst_proto_strcasecmp" = "yes" && test "$tst_compi_strcasecmp" = "yes" && test "$tst_allow_strcasecmp" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRCASECMP, 1, [Define to 1 if you have the strcasecmp function.]) curl_cv_func_strcasecmp="yes" else AC_MSG_RESULT([no]) curl_cv_func_strcasecmp="no" fi ]) dnl CURL_CHECK_FUNC_STRCMPI dnl ------------------------------------------------- dnl Verify if strcmpi is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strcmpi, then dnl HAVE_STRCMPI will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRCMPI], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strcmpi="unknown" tst_proto_strcmpi="unknown" tst_compi_strcmpi="unknown" tst_allow_strcmpi="unknown" # AC_MSG_CHECKING([if strcmpi can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strcmpi]) ],[ AC_MSG_RESULT([yes]) tst_links_strcmpi="yes" ],[ AC_MSG_RESULT([no]) tst_links_strcmpi="no" ]) # if test "$tst_links_strcmpi" = "yes"; then AC_MSG_CHECKING([if strcmpi is prototyped]) AC_EGREP_CPP([strcmpi],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strcmpi="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strcmpi="no" ]) fi # if test "$tst_proto_strcmpi" = "yes"; then AC_MSG_CHECKING([if strcmpi is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strcmpi(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strcmpi="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strcmpi="no" ]) fi # if test "$tst_compi_strcmpi" = "yes"; then AC_MSG_CHECKING([if strcmpi usage allowed]) if test "x$curl_disallow_strcmpi" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strcmpi="yes" else AC_MSG_RESULT([no]) tst_allow_strcmpi="no" fi fi # AC_MSG_CHECKING([if strcmpi might be used]) if test "$tst_links_strcmpi" = "yes" && test "$tst_proto_strcmpi" = "yes" && test "$tst_compi_strcmpi" = "yes" && test "$tst_allow_strcmpi" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRCMPI, 1, [Define to 1 if you have the strcmpi function.]) curl_cv_func_strcmpi="yes" else AC_MSG_RESULT([no]) curl_cv_func_strcmpi="no" fi ]) dnl CURL_CHECK_FUNC_STRDUP dnl ------------------------------------------------- dnl Verify if strdup is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strdup, then dnl HAVE_STRDUP will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRDUP], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strdup="unknown" tst_proto_strdup="unknown" tst_compi_strdup="unknown" tst_allow_strdup="unknown" # AC_MSG_CHECKING([if strdup can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strdup]) ],[ AC_MSG_RESULT([yes]) tst_links_strdup="yes" ],[ AC_MSG_RESULT([no]) tst_links_strdup="no" ]) # if test "$tst_links_strdup" = "yes"; then AC_MSG_CHECKING([if strdup is prototyped]) AC_EGREP_CPP([strdup],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strdup="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strdup="no" ]) fi # if test "$tst_proto_strdup" = "yes"; then AC_MSG_CHECKING([if strdup is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strdup(0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strdup="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strdup="no" ]) fi # if test "$tst_compi_strdup" = "yes"; then AC_MSG_CHECKING([if strdup usage allowed]) if test "x$curl_disallow_strdup" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strdup="yes" else AC_MSG_RESULT([no]) tst_allow_strdup="no" fi fi # AC_MSG_CHECKING([if strdup might be used]) if test "$tst_links_strdup" = "yes" && test "$tst_proto_strdup" = "yes" && test "$tst_compi_strdup" = "yes" && test "$tst_allow_strdup" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRDUP, 1, [Define to 1 if you have the strdup function.]) curl_cv_func_strdup="yes" else AC_MSG_RESULT([no]) curl_cv_func_strdup="no" fi ]) dnl CURL_CHECK_FUNC_STRERROR_R dnl ------------------------------------------------- dnl Verify if strerror_r is available, prototyped, can be compiled and dnl seems to work. If all of these are true, and usage has not been dnl previously disallowed with shell variable curl_disallow_strerror_r, dnl then HAVE_STRERROR_R and STRERROR_R_TYPE_ARG3 will be defined, as dnl well as one of HAVE_GLIBC_STRERROR_R or HAVE_POSIX_STRERROR_R. dnl dnl glibc-style strerror_r: dnl dnl char *strerror_r(int errnum, char *workbuf, size_t bufsize); dnl dnl glibc-style strerror_r returns a pointer to the error string, dnl and might use the provided workbuf as a scratch area if needed. A dnl quick test on a few systems shows that it's usually not used at all. dnl dnl POSIX-style strerror_r: dnl dnl int strerror_r(int errnum, char *resultbuf, size_t bufsize); dnl dnl POSIX-style strerror_r returns 0 upon successful completion and the dnl error string in the provided resultbuf. dnl AC_DEFUN([CURL_CHECK_FUNC_STRERROR_R], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strerror_r="unknown" tst_proto_strerror_r="unknown" tst_compi_strerror_r="unknown" tst_glibc_strerror_r="unknown" tst_posix_strerror_r="unknown" tst_allow_strerror_r="unknown" tst_works_glibc_strerror_r="unknown" tst_works_posix_strerror_r="unknown" tst_glibc_strerror_r_type_arg3="unknown" tst_posix_strerror_r_type_arg3="unknown" # AC_MSG_CHECKING([if strerror_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strerror_r]) ],[ AC_MSG_RESULT([yes]) tst_links_strerror_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_strerror_r="no" ]) # if test "$tst_links_strerror_r" = "yes"; then AC_MSG_CHECKING([if strerror_r is prototyped]) AC_EGREP_CPP([strerror_r],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strerror_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strerror_r="no" ]) fi # if test "$tst_proto_strerror_r" = "yes"; then AC_MSG_CHECKING([if strerror_r is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strerror_r(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strerror_r="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strerror_r="no" ]) fi # if test "$tst_compi_strerror_r" = "yes"; then AC_MSG_CHECKING([if strerror_r is glibc like]) tst_glibc_strerror_r_type_arg3="unknown" for arg3 in 'size_t' 'int' 'unsigned int'; do if test "$tst_glibc_strerror_r_type_arg3" = "unknown"; then AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string char *strerror_r(int errnum, char *workbuf, $arg3 bufsize); ]],[[ if(0 != strerror_r(0, 0, 0)) return 1; ]]) ],[ tst_glibc_strerror_r_type_arg3="$arg3" ]) fi done case "$tst_glibc_strerror_r_type_arg3" in unknown) AC_MSG_RESULT([no]) tst_glibc_strerror_r="no" ;; *) AC_MSG_RESULT([yes]) tst_glibc_strerror_r="yes" ;; esac fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_glibc_strerror_r" = "yes"; then AC_MSG_CHECKING([if strerror_r seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_string # include ]],[[ char buffer[1024]; char *string = 0; buffer[0] = '\0'; string = strerror_r(EACCES, buffer, sizeof(buffer)); if(!string) exit(1); /* fail */ if(!string[0]) exit(1); /* fail */ else exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_glibc_strerror_r="yes" ],[ AC_MSG_RESULT([no]) tst_works_glibc_strerror_r="no" ]) fi # if test "$tst_compi_strerror_r" = "yes" && test "$tst_works_glibc_strerror_r" != "yes"; then AC_MSG_CHECKING([if strerror_r is POSIX like]) tst_posix_strerror_r_type_arg3="unknown" for arg3 in 'size_t' 'int' 'unsigned int'; do if test "$tst_posix_strerror_r_type_arg3" = "unknown"; then AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string int strerror_r(int errnum, char *resultbuf, $arg3 bufsize); ]],[[ if(0 != strerror_r(0, 0, 0)) return 1; ]]) ],[ tst_posix_strerror_r_type_arg3="$arg3" ]) fi done case "$tst_posix_strerror_r_type_arg3" in unknown) AC_MSG_RESULT([no]) tst_posix_strerror_r="no" ;; *) AC_MSG_RESULT([yes]) tst_posix_strerror_r="yes" ;; esac fi # dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tst_posix_strerror_r" = "yes"; then AC_MSG_CHECKING([if strerror_r seems to work]) CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib $curl_includes_string # include ]],[[ char buffer[1024]; int error = 1; buffer[0] = '\0'; error = strerror_r(EACCES, buffer, sizeof(buffer)); if(error) exit(1); /* fail */ if(buffer[0] == '\0') exit(1); /* fail */ else exit(0); ]]) ],[ AC_MSG_RESULT([yes]) tst_works_posix_strerror_r="yes" ],[ AC_MSG_RESULT([no]) tst_works_posix_strerror_r="no" ]) fi # if test "$tst_works_glibc_strerror_r" = "yes"; then tst_posix_strerror_r="no" fi if test "$tst_works_posix_strerror_r" = "yes"; then tst_glibc_strerror_r="no" fi if test "$tst_glibc_strerror_r" = "yes" && test "$tst_works_glibc_strerror_r" != "no" && test "$tst_posix_strerror_r" != "yes"; then tst_allow_strerror_r="check" fi if test "$tst_posix_strerror_r" = "yes" && test "$tst_works_posix_strerror_r" != "no" && test "$tst_glibc_strerror_r" != "yes"; then tst_allow_strerror_r="check" fi if test "$tst_allow_strerror_r" = "check"; then AC_MSG_CHECKING([if strerror_r usage allowed]) if test "x$curl_disallow_strerror_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strerror_r="yes" else AC_MSG_RESULT([no]) tst_allow_strerror_r="no" fi fi # AC_MSG_CHECKING([if strerror_r might be used]) if test "$tst_links_strerror_r" = "yes" && test "$tst_proto_strerror_r" = "yes" && test "$tst_compi_strerror_r" = "yes" && test "$tst_allow_strerror_r" = "yes"; then AC_MSG_RESULT([yes]) if test "$tst_glibc_strerror_r" = "yes"; then AC_DEFINE_UNQUOTED(HAVE_STRERROR_R, 1, [Define to 1 if you have the strerror_r function.]) AC_DEFINE_UNQUOTED(HAVE_GLIBC_STRERROR_R, 1, [Define to 1 if you have a working glibc-style strerror_r function.]) AC_DEFINE_UNQUOTED(STRERROR_R_TYPE_ARG3, $tst_glibc_strerror_r_type_arg3, [Define to the type of arg 3 for strerror_r.]) fi if test "$tst_posix_strerror_r" = "yes"; then AC_DEFINE_UNQUOTED(HAVE_STRERROR_R, 1, [Define to 1 if you have the strerror_r function.]) AC_DEFINE_UNQUOTED(HAVE_POSIX_STRERROR_R, 1, [Define to 1 if you have a working POSIX-style strerror_r function.]) AC_DEFINE_UNQUOTED(STRERROR_R_TYPE_ARG3, $tst_posix_strerror_r_type_arg3, [Define to the type of arg 3 for strerror_r.]) fi curl_cv_func_strerror_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_strerror_r="no" fi # if test "$tst_compi_strerror_r" = "yes" && test "$tst_allow_strerror_r" = "unknown"; then AC_MSG_WARN([cannot determine strerror_r() style: edit lib/curl_config.h manually.]) fi # ]) dnl CURL_CHECK_FUNC_STRICMP dnl ------------------------------------------------- dnl Verify if stricmp is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_stricmp, then dnl HAVE_STRICMP will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRICMP], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_stricmp="unknown" tst_proto_stricmp="unknown" tst_compi_stricmp="unknown" tst_allow_stricmp="unknown" # AC_MSG_CHECKING([if stricmp can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([stricmp]) ],[ AC_MSG_RESULT([yes]) tst_links_stricmp="yes" ],[ AC_MSG_RESULT([no]) tst_links_stricmp="no" ]) # if test "$tst_links_stricmp" = "yes"; then AC_MSG_CHECKING([if stricmp is prototyped]) AC_EGREP_CPP([stricmp],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_stricmp="yes" ],[ AC_MSG_RESULT([no]) tst_proto_stricmp="no" ]) fi # if test "$tst_proto_stricmp" = "yes"; then AC_MSG_CHECKING([if stricmp is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != stricmp(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_stricmp="yes" ],[ AC_MSG_RESULT([no]) tst_compi_stricmp="no" ]) fi # if test "$tst_compi_stricmp" = "yes"; then AC_MSG_CHECKING([if stricmp usage allowed]) if test "x$curl_disallow_stricmp" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_stricmp="yes" else AC_MSG_RESULT([no]) tst_allow_stricmp="no" fi fi # AC_MSG_CHECKING([if stricmp might be used]) if test "$tst_links_stricmp" = "yes" && test "$tst_proto_stricmp" = "yes" && test "$tst_compi_stricmp" = "yes" && test "$tst_allow_stricmp" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRICMP, 1, [Define to 1 if you have the stricmp function.]) curl_cv_func_stricmp="yes" else AC_MSG_RESULT([no]) curl_cv_func_stricmp="no" fi ]) dnl CURL_CHECK_FUNC_STRNCASECMP dnl ------------------------------------------------- dnl Verify if strncasecmp is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strncasecmp, then dnl HAVE_STRNCASECMP will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRNCASECMP], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strncasecmp="unknown" tst_proto_strncasecmp="unknown" tst_compi_strncasecmp="unknown" tst_allow_strncasecmp="unknown" # AC_MSG_CHECKING([if strncasecmp can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strncasecmp]) ],[ AC_MSG_RESULT([yes]) tst_links_strncasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_links_strncasecmp="no" ]) # if test "$tst_links_strncasecmp" = "yes"; then AC_MSG_CHECKING([if strncasecmp is prototyped]) AC_EGREP_CPP([strncasecmp],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strncasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strncasecmp="no" ]) fi # if test "$tst_proto_strncasecmp" = "yes"; then AC_MSG_CHECKING([if strncasecmp is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strncasecmp(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strncasecmp="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strncasecmp="no" ]) fi # if test "$tst_compi_strncasecmp" = "yes"; then AC_MSG_CHECKING([if strncasecmp usage allowed]) if test "x$curl_disallow_strncasecmp" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strncasecmp="yes" else AC_MSG_RESULT([no]) tst_allow_strncasecmp="no" fi fi # AC_MSG_CHECKING([if strncasecmp might be used]) if test "$tst_links_strncasecmp" = "yes" && test "$tst_proto_strncasecmp" = "yes" && test "$tst_compi_strncasecmp" = "yes" && test "$tst_allow_strncasecmp" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRNCASECMP, 1, [Define to 1 if you have the strncasecmp function.]) curl_cv_func_strncasecmp="yes" else AC_MSG_RESULT([no]) curl_cv_func_strncasecmp="no" fi ]) dnl CURL_CHECK_FUNC_STRNCMPI dnl ------------------------------------------------- dnl Verify if strncmpi is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strncmpi, then dnl HAVE_STRNCMPI will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRNCMPI], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strncmpi="unknown" tst_proto_strncmpi="unknown" tst_compi_strncmpi="unknown" tst_allow_strncmpi="unknown" # AC_MSG_CHECKING([if strncmpi can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strncmpi]) ],[ AC_MSG_RESULT([yes]) tst_links_strncmpi="yes" ],[ AC_MSG_RESULT([no]) tst_links_strncmpi="no" ]) # if test "$tst_links_strncmpi" = "yes"; then AC_MSG_CHECKING([if strncmpi is prototyped]) AC_EGREP_CPP([strncmpi],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strncmpi="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strncmpi="no" ]) fi # if test "$tst_proto_strncmpi" = "yes"; then AC_MSG_CHECKING([if strncmpi is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strncmpi(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strncmpi="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strncmpi="no" ]) fi # if test "$tst_compi_strncmpi" = "yes"; then AC_MSG_CHECKING([if strncmpi usage allowed]) if test "x$curl_disallow_strncmpi" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strncmpi="yes" else AC_MSG_RESULT([no]) tst_allow_strncmpi="no" fi fi # AC_MSG_CHECKING([if strncmpi might be used]) if test "$tst_links_strncmpi" = "yes" && test "$tst_proto_strncmpi" = "yes" && test "$tst_compi_strncmpi" = "yes" && test "$tst_allow_strncmpi" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRNCMPI, 1, [Define to 1 if you have the strncmpi function.]) curl_cv_func_strncmpi="yes" else AC_MSG_RESULT([no]) curl_cv_func_strncmpi="no" fi ]) dnl CURL_CHECK_FUNC_STRNICMP dnl ------------------------------------------------- dnl Verify if strnicmp is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strnicmp, then dnl HAVE_STRNICMP will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRNICMP], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strnicmp="unknown" tst_proto_strnicmp="unknown" tst_compi_strnicmp="unknown" tst_allow_strnicmp="unknown" # AC_MSG_CHECKING([if strnicmp can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strnicmp]) ],[ AC_MSG_RESULT([yes]) tst_links_strnicmp="yes" ],[ AC_MSG_RESULT([no]) tst_links_strnicmp="no" ]) # if test "$tst_links_strnicmp" = "yes"; then AC_MSG_CHECKING([if strnicmp is prototyped]) AC_EGREP_CPP([strnicmp],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strnicmp="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strnicmp="no" ]) fi # if test "$tst_proto_strnicmp" = "yes"; then AC_MSG_CHECKING([if strnicmp is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strnicmp(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strnicmp="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strnicmp="no" ]) fi # if test "$tst_compi_strnicmp" = "yes"; then AC_MSG_CHECKING([if strnicmp usage allowed]) if test "x$curl_disallow_strnicmp" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strnicmp="yes" else AC_MSG_RESULT([no]) tst_allow_strnicmp="no" fi fi # AC_MSG_CHECKING([if strnicmp might be used]) if test "$tst_links_strnicmp" = "yes" && test "$tst_proto_strnicmp" = "yes" && test "$tst_compi_strnicmp" = "yes" && test "$tst_allow_strnicmp" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRNICMP, 1, [Define to 1 if you have the strnicmp function.]) curl_cv_func_strnicmp="yes" else AC_MSG_RESULT([no]) curl_cv_func_strnicmp="no" fi ]) dnl CURL_CHECK_FUNC_STRSTR dnl ------------------------------------------------- dnl Verify if strstr is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strstr, then dnl HAVE_STRSTR will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRSTR], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strstr="unknown" tst_proto_strstr="unknown" tst_compi_strstr="unknown" tst_allow_strstr="unknown" # AC_MSG_CHECKING([if strstr can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strstr]) ],[ AC_MSG_RESULT([yes]) tst_links_strstr="yes" ],[ AC_MSG_RESULT([no]) tst_links_strstr="no" ]) # if test "$tst_links_strstr" = "yes"; then AC_MSG_CHECKING([if strstr is prototyped]) AC_EGREP_CPP([strstr],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strstr="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strstr="no" ]) fi # if test "$tst_proto_strstr" = "yes"; then AC_MSG_CHECKING([if strstr is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strstr(0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strstr="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strstr="no" ]) fi # if test "$tst_compi_strstr" = "yes"; then AC_MSG_CHECKING([if strstr usage allowed]) if test "x$curl_disallow_strstr" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strstr="yes" else AC_MSG_RESULT([no]) tst_allow_strstr="no" fi fi # AC_MSG_CHECKING([if strstr might be used]) if test "$tst_links_strstr" = "yes" && test "$tst_proto_strstr" = "yes" && test "$tst_compi_strstr" = "yes" && test "$tst_allow_strstr" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRSTR, 1, [Define to 1 if you have the strstr function.]) curl_cv_func_strstr="yes" else AC_MSG_RESULT([no]) curl_cv_func_strstr="no" fi ]) dnl CURL_CHECK_FUNC_STRTOK_R dnl ------------------------------------------------- dnl Verify if strtok_r is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strtok_r, then dnl HAVE_STRTOK_R will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRTOK_R], [ AC_REQUIRE([CURL_INCLUDES_STRING])dnl # tst_links_strtok_r="unknown" tst_proto_strtok_r="unknown" tst_compi_strtok_r="unknown" tst_allow_strtok_r="unknown" # AC_MSG_CHECKING([if strtok_r can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strtok_r]) ],[ AC_MSG_RESULT([yes]) tst_links_strtok_r="yes" ],[ AC_MSG_RESULT([no]) tst_links_strtok_r="no" ]) # if test "$tst_links_strtok_r" = "yes"; then AC_MSG_CHECKING([if strtok_r is prototyped]) AC_EGREP_CPP([strtok_r],[ $curl_includes_string ],[ AC_MSG_RESULT([yes]) tst_proto_strtok_r="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strtok_r="no" ]) fi # if test "$tst_proto_strtok_r" = "yes"; then AC_MSG_CHECKING([if strtok_r is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_string ]],[[ if(0 != strtok_r(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strtok_r="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strtok_r="no" ]) fi # if test "$tst_compi_strtok_r" = "yes"; then AC_MSG_CHECKING([if strtok_r usage allowed]) if test "x$curl_disallow_strtok_r" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strtok_r="yes" else AC_MSG_RESULT([no]) tst_allow_strtok_r="no" fi fi # AC_MSG_CHECKING([if strtok_r might be used]) if test "$tst_links_strtok_r" = "yes" && test "$tst_proto_strtok_r" = "yes" && test "$tst_compi_strtok_r" = "yes" && test "$tst_allow_strtok_r" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRTOK_R, 1, [Define to 1 if you have the strtok_r function.]) curl_cv_func_strtok_r="yes" else AC_MSG_RESULT([no]) curl_cv_func_strtok_r="no" fi ]) dnl CURL_CHECK_FUNC_STRTOLL dnl ------------------------------------------------- dnl Verify if strtoll is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_strtoll, then dnl HAVE_STRTOLL will be defined. AC_DEFUN([CURL_CHECK_FUNC_STRTOLL], [ AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl # tst_links_strtoll="unknown" tst_proto_strtoll="unknown" tst_compi_strtoll="unknown" tst_allow_strtoll="unknown" # AC_MSG_CHECKING([if strtoll can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([strtoll]) ],[ AC_MSG_RESULT([yes]) tst_links_strtoll="yes" ],[ AC_MSG_RESULT([no]) tst_links_strtoll="no" ]) # if test "$tst_links_strtoll" = "yes"; then AC_MSG_CHECKING([if strtoll is prototyped]) AC_EGREP_CPP([strtoll],[ $curl_includes_stdlib ],[ AC_MSG_RESULT([yes]) tst_proto_strtoll="yes" ],[ AC_MSG_RESULT([no]) tst_proto_strtoll="no" ]) fi # if test "$tst_proto_strtoll" = "yes"; then AC_MSG_CHECKING([if strtoll is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_stdlib ]],[[ if(0 != strtoll(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_strtoll="yes" ],[ AC_MSG_RESULT([no]) tst_compi_strtoll="no" ]) fi # if test "$tst_compi_strtoll" = "yes"; then AC_MSG_CHECKING([if strtoll usage allowed]) if test "x$curl_disallow_strtoll" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_strtoll="yes" else AC_MSG_RESULT([no]) tst_allow_strtoll="no" fi fi # AC_MSG_CHECKING([if strtoll might be used]) if test "$tst_links_strtoll" = "yes" && test "$tst_proto_strtoll" = "yes" && test "$tst_compi_strtoll" = "yes" && test "$tst_allow_strtoll" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_STRTOLL, 1, [Define to 1 if you have the strtoll function.]) curl_cv_func_strtoll="yes" else AC_MSG_RESULT([no]) curl_cv_func_strtoll="no" fi ]) dnl CURL_CHECK_FUNC_WRITEV dnl ------------------------------------------------- dnl Verify if writev is available, prototyped, and dnl can be compiled. If all of these are true, and dnl usage has not been previously disallowed with dnl shell variable curl_disallow_writev, then dnl HAVE_WRITEV will be defined. AC_DEFUN([CURL_CHECK_FUNC_WRITEV], [ AC_REQUIRE([CURL_INCLUDES_SYS_UIO])dnl # tst_links_writev="unknown" tst_proto_writev="unknown" tst_compi_writev="unknown" tst_allow_writev="unknown" # AC_MSG_CHECKING([if writev can be linked]) AC_LINK_IFELSE([ AC_LANG_FUNC_LINK_TRY([writev]) ],[ AC_MSG_RESULT([yes]) tst_links_writev="yes" ],[ AC_MSG_RESULT([no]) tst_links_writev="no" ]) # if test "$tst_links_writev" = "yes"; then AC_MSG_CHECKING([if writev is prototyped]) AC_EGREP_CPP([writev],[ $curl_includes_sys_uio ],[ AC_MSG_RESULT([yes]) tst_proto_writev="yes" ],[ AC_MSG_RESULT([no]) tst_proto_writev="no" ]) fi # if test "$tst_proto_writev" = "yes"; then AC_MSG_CHECKING([if writev is compilable]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $curl_includes_sys_uio ]],[[ if(0 != writev(0, 0, 0)) return 1; ]]) ],[ AC_MSG_RESULT([yes]) tst_compi_writev="yes" ],[ AC_MSG_RESULT([no]) tst_compi_writev="no" ]) fi # if test "$tst_compi_writev" = "yes"; then AC_MSG_CHECKING([if writev usage allowed]) if test "x$curl_disallow_writev" != "xyes"; then AC_MSG_RESULT([yes]) tst_allow_writev="yes" else AC_MSG_RESULT([no]) tst_allow_writev="no" fi fi # AC_MSG_CHECKING([if writev might be used]) if test "$tst_links_writev" = "yes" && test "$tst_proto_writev" = "yes" && test "$tst_compi_writev" = "yes" && test "$tst_allow_writev" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(HAVE_WRITEV, 1, [Define to 1 if you have the writev function.]) curl_cv_func_writev="yes" else AC_MSG_RESULT([no]) curl_cv_func_writev="no" fi ]) dnl CURL_RUN_IFELSE dnl ------------------------------------------------- dnl Wrapper macro to use instead of AC_RUN_IFELSE. It dnl sets LD_LIBRARY_PATH locally for this run only, from the dnl CURL_LIBRARY_PATH variable. It keeps the LD_LIBRARY_PATH dnl changes contained within this macro. AC_DEFUN([CURL_RUN_IFELSE], [ AC_REQUIRE([AC_RUN_IFELSE])dnl old=$LD_LIBRARY_PATH LD_LIBRARY_PATH=$CURL_LIBRARY_PATH:$old export LD_LIBRARY_PATH AC_RUN_IFELSE([AC_LANG_SOURCE([$1])], $2, $3, $4) LD_LIBRARY_PATH=$old # restore ]) dnl CURL_COVERAGE dnl -------------------------------------------------- dnl Switch on options and libs to build with gcc's code coverage. dnl AC_DEFUN([CURL_COVERAGE],[ AC_REQUIRE([AC_PROG_SED]) AC_REQUIRE([AC_ARG_ENABLE]) AC_MSG_CHECKING([for code coverage support]) coverage="no" curl_coverage_msg="disabled" dnl check if enabled by argument AC_ARG_ENABLE(code-coverage, AC_HELP_STRING([--enable-code-coverage], [Provide code coverage]), coverage="$enableval") dnl if not gcc switch off again AS_IF([ test "$GCC" != "yes" ], coverage="no" ) AC_MSG_RESULT($coverage) if test "x$coverage" = "xyes"; then curl_coverage_msg="enabled" AC_CHECK_TOOL([GCOV], [gcov], [gcov]) if test -z "$GCOV"; then AC_MSG_ERROR([needs gcov for code coverage]) fi AC_CHECK_PROG([LCOV], [lcov], [lcov]) if test -z "$LCOV"; then AC_MSG_ERROR([needs lcov for code coverage]) fi CPPFLAGS="$CPPFLAGS -DNDEBUG" CFLAGS="$CLAGS -O0 -g -fprofile-arcs -ftest-coverage" LIBS="$LIBS -lgcov" fi ]) davix-0.8.0/deps/curl/m4/curl-override.m40000644000000000000000000000372114121063461016575 0ustar rootroot#*************************************************************************** #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 7 dnl CURL_OVERRIDE_AUTOCONF dnl ------------------------------------------------- dnl Placing a call to this macro in configure.ac after dnl the one to AC_INIT will make macros in this file dnl visible to the rest of the compilation overriding dnl those from Autoconf. AC_DEFUN([CURL_OVERRIDE_AUTOCONF], [ AC_BEFORE([$0],[AC_PROG_LIBTOOL]) # using curl-override.m4 ]) dnl Override Autoconf's AC_LANG_PROGRAM (C) dnl ------------------------------------------------- dnl This is done to prevent compiler warning dnl 'function declaration isn't a prototype' dnl in function main. This requires at least dnl a c89 compiler and does not support K&R. m4_define([AC_LANG_PROGRAM(C)], [$1 int main (void) { $2 ; return 0; }]) dnl Override Autoconf's AC_LANG_CALL (C) dnl ------------------------------------------------- dnl This is a backport of Autoconf's 2.60 with the dnl embedded comments that hit the resulting script dnl removed. This is done to reduce configure size dnl and use fixed macro across Autoconf versions. m4_define([AC_LANG_CALL(C)], [AC_LANG_PROGRAM([$1 m4_if([$2], [main], , [ #ifdef __cplusplus extern "C" #endif char $2 ();])], [return $2 ();])]) dnl Override Autoconf's AC_LANG_FUNC_LINK_TRY (C) dnl ------------------------------------------------- dnl This is a backport of Autoconf's 2.60 with the dnl embedded comments that hit the resulting script dnl removed. This is done to reduce configure size dnl and use fixed macro across Autoconf versions. m4_define([AC_LANG_FUNC_LINK_TRY(C)], [AC_LANG_PROGRAM( [ #define $1 innocuous_$1 #ifdef __STDC__ # include #else # include #endif #undef $1 #ifdef __cplusplus extern "C" #endif char $1 (); #if defined __stub_$1 || defined __stub___$1 choke me #endif ], [return $1 ();])]) davix-0.8.0/deps/curl/m4/curl-compilers.m40000644000000000000000000014536014121063461016761 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 67 dnl CURL_CHECK_COMPILER dnl ------------------------------------------------- dnl Verify if the C compiler being used is known. AC_DEFUN([CURL_CHECK_COMPILER], [ # compiler_id="unknown" compiler_num="0" # flags_dbg_all="unknown" flags_dbg_yes="unknown" flags_dbg_off="unknown" flags_opt_all="unknown" flags_opt_yes="unknown" flags_opt_off="unknown" # flags_prefer_cppflags="no" # CURL_CHECK_COMPILER_DEC_C CURL_CHECK_COMPILER_HPUX_C CURL_CHECK_COMPILER_IBM_C CURL_CHECK_COMPILER_INTEL_C CURL_CHECK_COMPILER_CLANG CURL_CHECK_COMPILER_GNU_C CURL_CHECK_COMPILER_LCC CURL_CHECK_COMPILER_SGI_MIPSPRO_C CURL_CHECK_COMPILER_SGI_MIPS_C CURL_CHECK_COMPILER_SUNPRO_C CURL_CHECK_COMPILER_TINY_C CURL_CHECK_COMPILER_WATCOM_C # if test "$compiler_id" = "unknown"; then cat <<_EOF 1>&2 *** *** Warning: This configure script does not have information about the *** compiler you are using, relative to the flags required to enable or *** disable generation of debug info, optimization options or warnings. *** *** Whatever settings are present in CFLAGS will be used for this run. *** *** If you wish to help the curl project to better support your compiler *** you can report this and the required info on the libcurl development *** mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ *** _EOF fi ]) dnl CURL_CHECK_COMPILER_CLANG dnl ------------------------------------------------- dnl Verify if compiler being used is clang. AC_DEFUN([CURL_CHECK_COMPILER_CLANG], [ AC_BEFORE([$0],[CURL_CHECK_COMPILER_GNU_C])dnl AC_MSG_CHECKING([if compiler is clang]) CURL_CHECK_DEF([__clang__], [], [silent]) if test "$curl_cv_have_def___clang__" = "yes"; then AC_MSG_RESULT([yes]) AC_MSG_CHECKING([if compiler is xlclang]) CURL_CHECK_DEF([__ibmxl__], [], [silent]) if test "$curl_cv_have_def___ibmxl__" = "yes" ; then dnl IBM's almost-compatible clang version AC_MSG_RESULT([yes]) compiler_id="XLCLANG" else AC_MSG_RESULT([no]) compiler_id="CLANG" fi fullclangver=`$CC -v 2>&1 | grep version` clangver=`echo $fullclangver | grep "based on LLVM " | "$SED" 's/.*(based on LLVM \(@<:@0-9@:>@*\.@<:@0-9@:>@*\).*)/\1/'` if test -z "$clangver"; then if echo $fullclangver | grep "Apple LLVM version " >/dev/null; then dnl Starting with XCode 7 / clang 3.7, Apple clang won't tell its upstream version clangver="3.7" else clangver=`echo $fullclangver | "$SED" 's/.*version \(@<:@0-9@:>@*\.@<:@0-9@:>@*\).*/\1/'` fi fi clangvhi=`echo $clangver | cut -d . -f1` clangvlo=`echo $clangver | cut -d . -f2` compiler_num=`(expr $clangvhi "*" 100 + $clangvlo) 2>/dev/null` flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_all="$flags_dbg_all -ggdb" flags_dbg_all="$flags_dbg_all -gstabs" flags_dbg_all="$flags_dbg_all -gstabs+" flags_dbg_all="$flags_dbg_all -gcoff" flags_dbg_all="$flags_dbg_all -gxcoff" flags_dbg_all="$flags_dbg_all -gdwarf-2" flags_dbg_all="$flags_dbg_all -gvms" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -Os -O3 -O4" flags_opt_yes="-Os" flags_opt_off="-O0" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_DEC_C dnl ------------------------------------------------- dnl Verify if compiler being used is DEC C. AC_DEFUN([CURL_CHECK_COMPILER_DEC_C], [ AC_MSG_CHECKING([if compiler is DEC/Compaq/HP C]) CURL_CHECK_DEF([__DECC], [], [silent]) CURL_CHECK_DEF([__DECC_VER], [], [silent]) if test "$curl_cv_have_def___DECC" = "yes" && test "$curl_cv_have_def___DECC_VER" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="DEC_C" flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_yes="-g2" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -O4" flags_opt_yes="-O1" flags_opt_off="-O0" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_GNU_C dnl ------------------------------------------------- dnl Verify if compiler being used is GNU C. AC_DEFUN([CURL_CHECK_COMPILER_GNU_C], [ AC_REQUIRE([CURL_CHECK_COMPILER_INTEL_C])dnl AC_REQUIRE([CURL_CHECK_COMPILER_CLANG])dnl AC_MSG_CHECKING([if compiler is GNU C]) CURL_CHECK_DEF([__GNUC__], [], [silent]) if test "$curl_cv_have_def___GNUC__" = "yes" && test "$compiler_id" = "unknown"; then AC_MSG_RESULT([yes]) compiler_id="GNU_C" gccver=`$CC -dumpversion` gccvhi=`echo $gccver | cut -d . -f1` gccvlo=`echo $gccver | cut -d . -f2` compiler_num=`(expr $gccvhi "*" 100 + $gccvlo) 2>/dev/null` flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_all="$flags_dbg_all -ggdb" flags_dbg_all="$flags_dbg_all -gstabs" flags_dbg_all="$flags_dbg_all -gstabs+" flags_dbg_all="$flags_dbg_all -gcoff" flags_dbg_all="$flags_dbg_all -gxcoff" flags_dbg_all="$flags_dbg_all -gdwarf-2" flags_dbg_all="$flags_dbg_all -gvms" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -Os -Og -Ofast" flags_opt_yes="-O2" flags_opt_off="-O0" CURL_CHECK_DEF([_WIN32], [], [silent]) else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_HPUX_C dnl ------------------------------------------------- dnl Verify if compiler being used is HP-UX C. AC_DEFUN([CURL_CHECK_COMPILER_HPUX_C], [ AC_MSG_CHECKING([if compiler is HP-UX C]) CURL_CHECK_DEF([__HP_cc], [], [silent]) if test "$curl_cv_have_def___HP_cc" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="HP_UX_C" flags_dbg_all="-g -s" flags_dbg_yes="-g" flags_dbg_off="-s" flags_opt_all="-O +O0 +O1 +O2 +O3 +O4" flags_opt_yes="+O2" flags_opt_off="+O0" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_IBM_C dnl ------------------------------------------------- dnl Verify if compiler being used is IBM C. AC_DEFUN([CURL_CHECK_COMPILER_IBM_C], [ AC_MSG_CHECKING([if compiler is IBM C]) CURL_CHECK_DEF([__IBMC__], [], [silent]) if test "$curl_cv_have_def___IBMC__" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="IBM_C" flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -O4 -O5" flags_opt_all="$flags_opt_all -qnooptimize" flags_opt_all="$flags_opt_all -qoptimize=0" flags_opt_all="$flags_opt_all -qoptimize=1" flags_opt_all="$flags_opt_all -qoptimize=2" flags_opt_all="$flags_opt_all -qoptimize=3" flags_opt_all="$flags_opt_all -qoptimize=4" flags_opt_all="$flags_opt_all -qoptimize=5" flags_opt_yes="-O2" flags_opt_off="-qnooptimize" flags_prefer_cppflags="yes" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_INTEL_C dnl ------------------------------------------------- dnl Verify if compiler being used is Intel C. AC_DEFUN([CURL_CHECK_COMPILER_INTEL_C], [ AC_BEFORE([$0],[CURL_CHECK_COMPILER_GNU_C])dnl AC_MSG_CHECKING([if compiler is Intel C]) CURL_CHECK_DEF([__INTEL_COMPILER], [], [silent]) if test "$curl_cv_have_def___INTEL_COMPILER" = "yes"; then AC_MSG_RESULT([yes]) compiler_num="$curl_cv_def___INTEL_COMPILER" CURL_CHECK_DEF([__unix__], [], [silent]) if test "$curl_cv_have_def___unix__" = "yes"; then compiler_id="INTEL_UNIX_C" flags_dbg_all="-g -g0" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -Os" flags_opt_yes="-O2" flags_opt_off="-O0" else compiler_id="INTEL_WINDOWS_C" flags_dbg_all="/ZI /Zi /zI /zi /ZD /Zd /zD /zd /Z7 /z7 /Oy /Oy-" flags_dbg_all="$flags_dbg_all /debug" flags_dbg_all="$flags_dbg_all /debug:none" flags_dbg_all="$flags_dbg_all /debug:minimal" flags_dbg_all="$flags_dbg_all /debug:partial" flags_dbg_all="$flags_dbg_all /debug:full" flags_dbg_all="$flags_dbg_all /debug:semantic_stepping" flags_dbg_all="$flags_dbg_all /debug:extended" flags_dbg_yes="/Zi /Oy-" flags_dbg_off="/debug:none /Oy-" flags_opt_all="/O /O0 /O1 /O2 /O3 /Od /Og /Og- /Oi /Oi-" flags_opt_yes="/O2" flags_opt_off="/Od" fi else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_LCC dnl ------------------------------------------------- dnl Verify if compiler being used is LCC. AC_DEFUN([CURL_CHECK_COMPILER_LCC], [ AC_MSG_CHECKING([if compiler is LCC]) CURL_CHECK_DEF([__LCC__], [], [silent]) if test "$curl_cv_have_def___LCC__" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="LCC" flags_dbg_all="-g" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="" flags_opt_yes="" flags_opt_off="" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_SGI_MIPS_C dnl ------------------------------------------------- dnl Verify if compiler being used is SGI MIPS C. AC_DEFUN([CURL_CHECK_COMPILER_SGI_MIPS_C], [ AC_REQUIRE([CURL_CHECK_COMPILER_SGI_MIPSPRO_C])dnl AC_MSG_CHECKING([if compiler is SGI MIPS C]) CURL_CHECK_DEF([__GNUC__], [], [silent]) CURL_CHECK_DEF([__sgi], [], [silent]) if test "$curl_cv_have_def___GNUC__" = "no" && test "$curl_cv_have_def___sgi" = "yes" && test "$compiler_id" = "unknown"; then AC_MSG_RESULT([yes]) compiler_id="SGI_MIPS_C" flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" flags_opt_yes="-O2" flags_opt_off="-O0" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_SGI_MIPSPRO_C dnl ------------------------------------------------- dnl Verify if compiler being used is SGI MIPSpro C. AC_DEFUN([CURL_CHECK_COMPILER_SGI_MIPSPRO_C], [ AC_BEFORE([$0],[CURL_CHECK_COMPILER_SGI_MIPS_C])dnl AC_MSG_CHECKING([if compiler is SGI MIPSpro C]) CURL_CHECK_DEF([__GNUC__], [], [silent]) CURL_CHECK_DEF([_COMPILER_VERSION], [], [silent]) CURL_CHECK_DEF([_SGI_COMPILER_VERSION], [], [silent]) if test "$curl_cv_have_def___GNUC__" = "no" && (test "$curl_cv_have_def__SGI_COMPILER_VERSION" = "yes" || test "$curl_cv_have_def__COMPILER_VERSION" = "yes"); then AC_MSG_RESULT([yes]) compiler_id="SGI_MIPSPRO_C" flags_dbg_all="-g -g0 -g1 -g2 -g3" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="-O -O0 -O1 -O2 -O3 -Ofast" flags_opt_yes="-O2" flags_opt_off="-O0" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_SUNPRO_C dnl ------------------------------------------------- dnl Verify if compiler being used is SunPro C. AC_DEFUN([CURL_CHECK_COMPILER_SUNPRO_C], [ AC_MSG_CHECKING([if compiler is SunPro C]) CURL_CHECK_DEF([__SUNPRO_C], [], [silent]) if test "$curl_cv_have_def___SUNPRO_C" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="SUNPRO_C" flags_dbg_all="-g -s" flags_dbg_yes="-g" flags_dbg_off="-s" flags_opt_all="-O -xO -xO1 -xO2 -xO3 -xO4 -xO5" flags_opt_yes="-xO2" flags_opt_off="" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_TINY_C dnl ------------------------------------------------- dnl Verify if compiler being used is Tiny C. AC_DEFUN([CURL_CHECK_COMPILER_TINY_C], [ AC_MSG_CHECKING([if compiler is Tiny C]) CURL_CHECK_DEF([__TINYC__], [], [silent]) if test "$curl_cv_have_def___TINYC__" = "yes"; then AC_MSG_RESULT([yes]) compiler_id="TINY_C" flags_dbg_all="-g -b" flags_dbg_yes="-g" flags_dbg_off="" flags_opt_all="" flags_opt_yes="" flags_opt_off="" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_WATCOM_C dnl ------------------------------------------------- dnl Verify if compiler being used is Watcom C. AC_DEFUN([CURL_CHECK_COMPILER_WATCOM_C], [ AC_MSG_CHECKING([if compiler is Watcom C]) CURL_CHECK_DEF([__WATCOMC__], [], [silent]) if test "$curl_cv_have_def___WATCOMC__" = "yes"; then AC_MSG_RESULT([yes]) CURL_CHECK_DEF([__UNIX__], [], [silent]) if test "$curl_cv_have_def___UNIX__" = "yes"; then compiler_id="WATCOM_UNIX_C" flags_dbg_all="-g1 -g1+ -g2 -g3" flags_dbg_yes="-g2" flags_dbg_off="" flags_opt_all="-O0 -O1 -O2 -O3" flags_opt_yes="-O2" flags_opt_off="-O0" else compiler_id="WATCOM_WINDOWS_C" flags_dbg_all="" flags_dbg_yes="" flags_dbg_off="" flags_opt_all="" flags_opt_yes="" flags_opt_off="" fi else AC_MSG_RESULT([no]) fi ]) dnl CURL_CONVERT_INCLUDE_TO_ISYSTEM dnl ------------------------------------------------- dnl Changes standard include paths present in CFLAGS dnl and CPPFLAGS into isystem include paths. This is dnl done to prevent GNUC from generating warnings on dnl headers from these locations, although on ancient dnl GNUC versions these warnings are not silenced. AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl AC_REQUIRE([CURL_CHECK_COMPILER])dnl if test "$compiler_id" = "GNU_C" || test "$compiler_id" = "CLANG"; then tmp_has_include="no" tmp_chg_FLAGS="$CFLAGS" for word1 in $tmp_chg_FLAGS; do case "$word1" in -I*) tmp_has_include="yes" ;; esac done if test "$tmp_has_include" = "yes"; then tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` CFLAGS="$tmp_chg_FLAGS" squeeze CFLAGS fi tmp_has_include="no" tmp_chg_FLAGS="$CPPFLAGS" for word1 in $tmp_chg_FLAGS; do case "$word1" in -I*) tmp_has_include="yes" ;; esac done if test "$tmp_has_include" = "yes"; then tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` CPPFLAGS="$tmp_chg_FLAGS" squeeze CPPFLAGS fi fi ]) dnl CURL_COMPILER_WORKS_IFELSE ([ACTION-IF-WORKS], [ACTION-IF-NOT-WORKS]) dnl ------------------------------------------------- dnl Verify if the C compiler seems to work with the dnl settings that are 'active' at the time the test dnl is performed. AC_DEFUN([CURL_COMPILER_WORKS_IFELSE], [ dnl compilation capability verification tmp_compiler_works="unknown" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ int i = 1; return i; ]]) ],[ tmp_compiler_works="yes" ],[ tmp_compiler_works="no" echo " " >&6 sed 's/^/cc-fail: /' conftest.err >&6 echo " " >&6 ]) dnl linking capability verification if test "$tmp_compiler_works" = "yes"; then AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ int i = 1; return i; ]]) ],[ tmp_compiler_works="yes" ],[ tmp_compiler_works="no" echo " " >&6 sed 's/^/link-fail: /' conftest.err >&6 echo " " >&6 ]) fi dnl only do runtime verification when not cross-compiling if test "x$cross_compiling" != "xyes" && test "$tmp_compiler_works" = "yes"; then CURL_RUN_IFELSE([ AC_LANG_PROGRAM([[ # ifdef __STDC__ # include # endif ]],[[ int i = 0; exit(i); ]]) ],[ tmp_compiler_works="yes" ],[ tmp_compiler_works="no" echo " " >&6 echo "run-fail: test program exited with status $ac_status" >&6 echo " " >&6 ]) fi dnl branch upon test result if test "$tmp_compiler_works" = "yes"; then ifelse($1,,:,[$1]) ifelse($2,,,[else $2]) fi ]) dnl CURL_SET_COMPILER_BASIC_OPTS dnl ------------------------------------------------- dnl Sets compiler specific options/flags which do not dnl depend on configure's debug, optimize or warnings dnl options. AC_DEFUN([CURL_SET_COMPILER_BASIC_OPTS], [ AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl # if test "$compiler_id" != "unknown"; then # if test "$compiler_id" = "GNU_C" || test "$compiler_id" = "CLANG"; then CURL_CONVERT_INCLUDE_TO_ISYSTEM fi # tmp_save_CPPFLAGS="$CPPFLAGS" tmp_save_CFLAGS="$CFLAGS" tmp_CPPFLAGS="" tmp_CFLAGS="" # case "$compiler_id" in # CLANG) # dnl Disable warnings for unused arguments, otherwise clang will dnl warn about compile-time arguments used during link-time, like dnl -O and -g and -pedantic. tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments" ;; # DEC_C) # dnl Select strict ANSI C compiler mode tmp_CFLAGS="$tmp_CFLAGS -std1" dnl Turn off optimizer ANSI C aliasing rules tmp_CFLAGS="$tmp_CFLAGS -noansi_alias" dnl Generate warnings for missing function prototypes tmp_CFLAGS="$tmp_CFLAGS -warnprotos" dnl Change some warnings into fatal errors tmp_CFLAGS="$tmp_CFLAGS -msg_fatal toofewargs,toomanyargs" ;; # GNU_C) # dnl turn implicit-function-declaration warning into error, dnl at least gcc 2.95 and later support this if test "$compiler_num" -ge "295"; then tmp_CFLAGS="$tmp_CFLAGS -Werror-implicit-function-declaration" fi ;; # HP_UX_C) # dnl Disallow run-time dereferencing of null pointers tmp_CFLAGS="$tmp_CFLAGS -z" dnl Disable some remarks dnl #4227: padding struct with n bytes to align member dnl #4255: padding size of struct with n bytes to alignment boundary tmp_CFLAGS="$tmp_CFLAGS +W 4227,4255" ;; # IBM_C) # dnl Ensure that compiler optimizations are always thread-safe. tmp_CPPFLAGS="$tmp_CPPFLAGS -qthreaded" dnl Disable type based strict aliasing optimizations, using worst dnl case aliasing assumptions when compiling. Type based aliasing dnl would restrict the lvalues that could be safely used to access dnl a data object. tmp_CPPFLAGS="$tmp_CPPFLAGS -qnoansialias" dnl Force compiler to stop after the compilation phase, without dnl generating an object code file when compilation has errors. tmp_CPPFLAGS="$tmp_CPPFLAGS -qhalt=e" ;; # INTEL_UNIX_C) # dnl On unix this compiler uses gcc's header files, so dnl we select ANSI C89 dialect plus GNU extensions. tmp_CFLAGS="$tmp_CFLAGS -std=gnu89" dnl Change some warnings into errors dnl #140: too many arguments in function call dnl #147: declaration is incompatible with 'previous one' dnl #165: too few arguments in function call dnl #266: function declared implicitly tmp_CPPFLAGS="$tmp_CPPFLAGS -we140,147,165,266" dnl Disable some remarks dnl #279: controlling expression is constant dnl #981: operands are evaluated in unspecified order dnl #1469: "cc" clobber ignored tmp_CPPFLAGS="$tmp_CPPFLAGS -wd279,981,1469" ;; # INTEL_WINDOWS_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # LCC) # dnl Disallow run-time dereferencing of null pointers tmp_CFLAGS="$tmp_CFLAGS -n" ;; # SGI_MIPS_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # SGI_MIPSPRO_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # SUNPRO_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # TINY_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # WATCOM_UNIX_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # WATCOM_WINDOWS_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # esac # squeeze tmp_CPPFLAGS squeeze tmp_CFLAGS # if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then AC_MSG_CHECKING([if compiler accepts some basic options]) CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" squeeze CPPFLAGS squeeze CFLAGS CURL_COMPILER_WORKS_IFELSE([ AC_MSG_RESULT([yes]) AC_MSG_NOTICE([compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS]) ],[ AC_MSG_RESULT([no]) AC_MSG_WARN([compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS]) dnl restore initial settings CPPFLAGS="$tmp_save_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS" ]) fi # fi ]) dnl CURL_SET_COMPILER_DEBUG_OPTS dnl ------------------------------------------------- dnl Sets compiler specific options/flags which depend dnl on configure's debug option. AC_DEFUN([CURL_SET_COMPILER_DEBUG_OPTS], [ AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl # if test "$compiler_id" != "unknown"; then # tmp_save_CFLAGS="$CFLAGS" tmp_save_CPPFLAGS="$CPPFLAGS" # tmp_options="" tmp_CFLAGS="$CFLAGS" tmp_CPPFLAGS="$CPPFLAGS" CURL_VAR_STRIP([tmp_CFLAGS],[$flags_dbg_all]) CURL_VAR_STRIP([tmp_CPPFLAGS],[$flags_dbg_all]) # if test "$want_debug" = "yes"; then AC_MSG_CHECKING([if compiler accepts debug enabling options]) tmp_options="$flags_dbg_yes" fi if test "$want_debug" = "no"; then AC_MSG_CHECKING([if compiler accepts debug disabling options]) tmp_options="$flags_dbg_off" fi # if test "$flags_prefer_cppflags" = "yes"; then CPPFLAGS="$tmp_CPPFLAGS $tmp_options" CFLAGS="$tmp_CFLAGS" else CPPFLAGS="$tmp_CPPFLAGS" CFLAGS="$tmp_CFLAGS $tmp_options" fi squeeze CPPFLAGS squeeze CFLAGS CURL_COMPILER_WORKS_IFELSE([ AC_MSG_RESULT([yes]) AC_MSG_NOTICE([compiler options added: $tmp_options]) ],[ AC_MSG_RESULT([no]) AC_MSG_WARN([compiler options rejected: $tmp_options]) dnl restore initial settings CPPFLAGS="$tmp_save_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS" ]) # fi ]) dnl CURL_SET_COMPILER_OPTIMIZE_OPTS dnl ------------------------------------------------- dnl Sets compiler specific options/flags which depend dnl on configure's optimize option. AC_DEFUN([CURL_SET_COMPILER_OPTIMIZE_OPTS], [ AC_REQUIRE([CURL_CHECK_OPTION_OPTIMIZE])dnl AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl # if test "$compiler_id" != "unknown"; then # tmp_save_CFLAGS="$CFLAGS" tmp_save_CPPFLAGS="$CPPFLAGS" # tmp_options="" tmp_CFLAGS="$CFLAGS" tmp_CPPFLAGS="$CPPFLAGS" honor_optimize_option="yes" # dnl If optimization request setting has not been explicitly specified, dnl it has been derived from the debug setting and initially assumed. dnl This initially assumed optimizer setting will finally be ignored dnl if CFLAGS or CPPFLAGS already hold optimizer flags. This implies dnl that an initially assumed optimizer setting might not be honored. # if test "$want_optimize" = "assume_no" || test "$want_optimize" = "assume_yes"; then AC_MSG_CHECKING([if compiler optimizer assumed setting might be used]) CURL_VAR_MATCH_IFELSE([tmp_CFLAGS],[$flags_opt_all],[ honor_optimize_option="no" ]) CURL_VAR_MATCH_IFELSE([tmp_CPPFLAGS],[$flags_opt_all],[ honor_optimize_option="no" ]) AC_MSG_RESULT([$honor_optimize_option]) if test "$honor_optimize_option" = "yes"; then if test "$want_optimize" = "assume_yes"; then want_optimize="yes" fi if test "$want_optimize" = "assume_no"; then want_optimize="no" fi fi fi # if test "$honor_optimize_option" = "yes"; then CURL_VAR_STRIP([tmp_CFLAGS],[$flags_opt_all]) CURL_VAR_STRIP([tmp_CPPFLAGS],[$flags_opt_all]) if test "$want_optimize" = "yes"; then AC_MSG_CHECKING([if compiler accepts optimizer enabling options]) tmp_options="$flags_opt_yes" fi if test "$want_optimize" = "no"; then AC_MSG_CHECKING([if compiler accepts optimizer disabling options]) tmp_options="$flags_opt_off" fi if test "$flags_prefer_cppflags" = "yes"; then CPPFLAGS="$tmp_CPPFLAGS $tmp_options" CFLAGS="$tmp_CFLAGS" else CPPFLAGS="$tmp_CPPFLAGS" CFLAGS="$tmp_CFLAGS $tmp_options" fi squeeze CPPFLAGS squeeze CFLAGS CURL_COMPILER_WORKS_IFELSE([ AC_MSG_RESULT([yes]) AC_MSG_NOTICE([compiler options added: $tmp_options]) ],[ AC_MSG_RESULT([no]) AC_MSG_WARN([compiler options rejected: $tmp_options]) dnl restore initial settings CPPFLAGS="$tmp_save_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS" ]) fi # fi ]) dnl CURL_SET_COMPILER_WARNING_OPTS dnl ------------------------------------------------- dnl Sets compiler options/flags which depend on dnl configure's warnings given option. AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ AC_REQUIRE([CURL_CHECK_OPTION_WARNINGS])dnl AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl # if test "$compiler_id" != "unknown"; then # tmp_save_CPPFLAGS="$CPPFLAGS" tmp_save_CFLAGS="$CFLAGS" tmp_CPPFLAGS="" tmp_CFLAGS="" # case "$compiler_id" in # CLANG) # if test "$want_warnings" = "yes"; then tmp_CFLAGS="$tmp_CFLAGS -pedantic" tmp_CFLAGS="$tmp_CFLAGS -Wall -Wextra" tmp_CFLAGS="$tmp_CFLAGS -Wpointer-arith -Wwrite-strings" tmp_CFLAGS="$tmp_CFLAGS -Wshadow" tmp_CFLAGS="$tmp_CFLAGS -Winline -Wnested-externs" tmp_CFLAGS="$tmp_CFLAGS -Wmissing-declarations" tmp_CFLAGS="$tmp_CFLAGS -Wmissing-prototypes" tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" tmp_CFLAGS="$tmp_CFLAGS -Wfloat-equal" tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar -Wsign-compare" tmp_CFLAGS="$tmp_CFLAGS -Wundef" tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" tmp_CFLAGS="$tmp_CFLAGS -Wendif-labels -Wstrict-prototypes" tmp_CFLAGS="$tmp_CFLAGS -Wdeclaration-after-statement" tmp_CFLAGS="$tmp_CFLAGS -Wcast-align" tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" tmp_CFLAGS="$tmp_CFLAGS -Wshorten-64-to-32" # dnl Only clang 1.1 or later if test "$compiler_num" -ge "101"; then tmp_CFLAGS="$tmp_CFLAGS -Wunused" fi # dnl Only clang 2.8 or later if test "$compiler_num" -ge "208"; then tmp_CFLAGS="$tmp_CFLAGS -Wvla" fi # dnl Only clang 2.9 or later if test "$compiler_num" -ge "209"; then tmp_CFLAGS="$tmp_CFLAGS -Wshift-sign-overflow" fi # dnl Only clang 3.2 or later if test "$compiler_num" -ge "302"; then case $host_os in cygwin* | mingw*) dnl skip missing-variable-declarations warnings for cygwin and dnl mingw because the libtool wrapper executable causes them ;; *) tmp_CFLAGS="$tmp_CFLAGS -Wmissing-variable-declarations" ;; esac fi # dnl Only clang 3.6 or later if test "$compiler_num" -ge "306"; then tmp_CFLAGS="$tmp_CFLAGS -Wdouble-promotion" fi # dnl Only clang 3.9 or later if test "$compiler_num" -ge "309"; then tmp_CFLAGS="$tmp_CFLAGS -Wcomma" # avoid the varargs warning, fixed in 4.0 # https://bugs.llvm.org/show_bug.cgi?id=29140 if test "$compiler_num" -lt "400"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-varargs" fi fi fi ;; # DEC_C) # if test "$want_warnings" = "yes"; then dnl Select a higher warning level than default level2 tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3" fi ;; # GNU_C) # if test "$want_warnings" = "yes"; then # dnl Do not enable -pedantic when cross-compiling with a gcc older dnl than 3.0, to avoid warnings from third party system headers. if test "x$cross_compiling" != "xyes" || test "$compiler_num" -ge "300"; then tmp_CFLAGS="$tmp_CFLAGS -pedantic" fi # dnl Set of options we believe *ALL* gcc versions support: tmp_CFLAGS="$tmp_CFLAGS -Wall -W" # dnl Only gcc 1.4 or later if test "$compiler_num" -ge "104"; then tmp_CFLAGS="$tmp_CFLAGS -Wpointer-arith -Wwrite-strings" dnl If not cross-compiling with a gcc older than 3.0 if test "x$cross_compiling" != "xyes" || test "$compiler_num" -ge "300"; then tmp_CFLAGS="$tmp_CFLAGS -Wunused -Wshadow" fi fi # dnl Only gcc 2.7 or later if test "$compiler_num" -ge "207"; then tmp_CFLAGS="$tmp_CFLAGS -Winline -Wnested-externs" dnl If not cross-compiling with a gcc older than 3.0 if test "x$cross_compiling" != "xyes" || test "$compiler_num" -ge "300"; then tmp_CFLAGS="$tmp_CFLAGS -Wmissing-declarations" tmp_CFLAGS="$tmp_CFLAGS -Wmissing-prototypes" fi fi # dnl Only gcc 2.95 or later if test "$compiler_num" -ge "295"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-long-long" tmp_CFLAGS="$tmp_CFLAGS -Wbad-function-cast" fi # dnl Only gcc 2.96 or later if test "$compiler_num" -ge "296"; then tmp_CFLAGS="$tmp_CFLAGS -Wfloat-equal" tmp_CFLAGS="$tmp_CFLAGS -Wno-multichar -Wsign-compare" dnl -Wundef used only if gcc is 2.96 or later since we get dnl lots of "`_POSIX_C_SOURCE' is not defined" in system dnl headers with gcc 2.95.4 on FreeBSD 4.9 tmp_CFLAGS="$tmp_CFLAGS -Wundef" fi # dnl Only gcc 2.97 or later if test "$compiler_num" -ge "297"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-format-nonliteral" fi # dnl Only gcc 3.0 or later if test "$compiler_num" -ge "300"; then dnl -Wunreachable-code seems totally unreliable on my gcc 3.3.2 on dnl on i686-Linux as it gives us heaps with false positives. dnl Also, on gcc 4.0.X it is totally unbearable and complains all dnl over making it unusable for generic purposes. Let's not use it. tmp_CFLAGS="$tmp_CFLAGS" fi # dnl Only gcc 3.3 or later if test "$compiler_num" -ge "303"; then tmp_CFLAGS="$tmp_CFLAGS -Wendif-labels -Wstrict-prototypes" fi # dnl Only gcc 3.4 or later if test "$compiler_num" -ge "304"; then tmp_CFLAGS="$tmp_CFLAGS -Wdeclaration-after-statement" tmp_CFLAGS="$tmp_CFLAGS -Wold-style-definition" fi # dnl Only gcc 4.0 or later if test "$compiler_num" -ge "400"; then tmp_CFLAGS="$tmp_CFLAGS -Wstrict-aliasing=3" fi # dnl Only gcc 4.2 or later if test "$compiler_num" -ge "402"; then tmp_CFLAGS="$tmp_CFLAGS -Wcast-align" fi # dnl Only gcc 4.3 or later if test "$compiler_num" -ge "403"; then tmp_CFLAGS="$tmp_CFLAGS -Wtype-limits -Wold-style-declaration" tmp_CFLAGS="$tmp_CFLAGS -Wmissing-parameter-type -Wempty-body" tmp_CFLAGS="$tmp_CFLAGS -Wclobbered -Wignored-qualifiers" tmp_CFLAGS="$tmp_CFLAGS -Wconversion -Wno-sign-conversion -Wvla" dnl required for -Warray-bounds, included in -Wall tmp_CFLAGS="$tmp_CFLAGS -ftree-vrp" fi # dnl Only gcc 4.5 or later if test "$compiler_num" -ge "405"; then dnl Only windows targets if test "$curl_cv_have_def__WIN32" = "yes"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-pedantic-ms-format" fi fi # dnl Only gcc 4.6 or later if test "$compiler_num" -ge "406"; then tmp_CFLAGS="$tmp_CFLAGS -Wdouble-promotion" fi # dnl only gcc 4.8 or later if test "$compiler_num" -ge "408"; then tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" fi # dnl Only gcc 5 or later if test "$compiler_num" -ge "500"; then tmp_CFLAGS="$tmp_CFLAGS -Warray-bounds=2" fi # dnl Only gcc 6 or later if test "$compiler_num" -ge "600"; then tmp_CFLAGS="$tmp_CFLAGS -Wshift-negative-value" tmp_CFLAGS="$tmp_CFLAGS -Wshift-overflow=2" tmp_CFLAGS="$tmp_CFLAGS -Wnull-dereference -fdelete-null-pointer-checks" tmp_CFLAGS="$tmp_CFLAGS -Wduplicated-cond" tmp_CFLAGS="$tmp_CFLAGS -Wunused-const-variable" fi # dnl Only gcc 7 or later if test "$compiler_num" -ge "700"; then tmp_CFLAGS="$tmp_CFLAGS -Wduplicated-branches" tmp_CFLAGS="$tmp_CFLAGS -Wrestrict" tmp_CFLAGS="$tmp_CFLAGS -Walloc-zero" tmp_CFLAGS="$tmp_CFLAGS -Wformat-overflow=2" tmp_CFLAGS="$tmp_CFLAGS -Wformat-truncation=2" tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough=4" fi # fi # dnl Do not issue warnings for code in system include paths. if test "$compiler_num" -ge "300"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-system-headers" else dnl When cross-compiling with a gcc older than 3.0, disable dnl some warnings triggered on third party system headers. if test "x$cross_compiling" = "xyes"; then if test "$compiler_num" -ge "104"; then dnl gcc 1.4 or later tmp_CFLAGS="$tmp_CFLAGS -Wno-unused -Wno-shadow" fi if test "$compiler_num" -ge "207"; then dnl gcc 2.7 or later tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-declarations" tmp_CFLAGS="$tmp_CFLAGS -Wno-missing-prototypes" fi fi fi ;; # HP_UX_C) # if test "$want_warnings" = "yes"; then dnl Issue all warnings tmp_CFLAGS="$tmp_CFLAGS +w1" fi ;; # IBM_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # INTEL_UNIX_C) # if test "$want_warnings" = "yes"; then if test "$compiler_num" -gt "600"; then dnl Show errors, warnings, and remarks tmp_CPPFLAGS="$tmp_CPPFLAGS -Wall -w2" dnl Perform extra compile-time code checking tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcheck" dnl Warn on nested comments tmp_CPPFLAGS="$tmp_CPPFLAGS -Wcomment" dnl Show warnings relative to deprecated features tmp_CPPFLAGS="$tmp_CPPFLAGS -Wdeprecated" dnl Enable warnings for missing prototypes tmp_CPPFLAGS="$tmp_CPPFLAGS -Wmissing-prototypes" dnl Enable warnings for 64-bit portability issues tmp_CPPFLAGS="$tmp_CPPFLAGS -Wp64" dnl Enable warnings for questionable pointer arithmetic tmp_CPPFLAGS="$tmp_CPPFLAGS -Wpointer-arith" dnl Check for function return typw issues tmp_CPPFLAGS="$tmp_CPPFLAGS -Wreturn-type" dnl Warn on variable declarations hiding a previous one tmp_CPPFLAGS="$tmp_CPPFLAGS -Wshadow" dnl Warn when a variable is used before initialized tmp_CPPFLAGS="$tmp_CPPFLAGS -Wuninitialized" dnl Warn if a declared function is not used tmp_CPPFLAGS="$tmp_CPPFLAGS -Wunused-function" fi fi dnl Disable using EBP register in optimizations tmp_CFLAGS="$tmp_CFLAGS -fno-omit-frame-pointer" dnl Disable use of ANSI C aliasing rules in optimizations tmp_CFLAGS="$tmp_CFLAGS -fno-strict-aliasing" dnl Value-safe optimizations on floating-point data tmp_CFLAGS="$tmp_CFLAGS -fp-model precise" dnl Only icc 10.0 or later if test "$compiler_num" -ge "1000"; then dnl Disable vectorizer diagnostic information tmp_CFLAGS="$tmp_CFLAGS -vec-report0" fi ;; # INTEL_WINDOWS_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # LCC) # if test "$want_warnings" = "yes"; then dnl Highest warning level is double -A, next is single -A. dnl Due to the big number of warnings these trigger on third dnl party header files it is impractical for us to use any of dnl them here. If you want them simply define it in CPPFLAGS. tmp_CFLAGS="$tmp_CFLAGS" fi ;; # SGI_MIPS_C) # if test "$want_warnings" = "yes"; then dnl Perform stricter semantic and lint-like checks tmp_CFLAGS="$tmp_CFLAGS -fullwarn" fi ;; # SGI_MIPSPRO_C) # if test "$want_warnings" = "yes"; then dnl Perform stricter semantic and lint-like checks tmp_CFLAGS="$tmp_CFLAGS -fullwarn" dnl Disable some remarks dnl #1209: controlling expression is constant tmp_CFLAGS="$tmp_CFLAGS -woff 1209" fi ;; # SUNPRO_C) # if test "$want_warnings" = "yes"; then dnl Perform stricter semantic and lint-like checks tmp_CFLAGS="$tmp_CFLAGS -v" fi ;; # TINY_C) # if test "$want_warnings" = "yes"; then dnl Activate all warnings tmp_CFLAGS="$tmp_CFLAGS -Wall" dnl Make string constants be of type const char * tmp_CFLAGS="$tmp_CFLAGS -Wwrite-strings" dnl Warn use of unsupported GCC features ignored by TCC tmp_CFLAGS="$tmp_CFLAGS -Wunsupported" fi ;; # WATCOM_UNIX_C) # if test "$want_warnings" = "yes"; then dnl Issue all warnings tmp_CFLAGS="$tmp_CFLAGS -Wall -Wextra" fi ;; # WATCOM_WINDOWS_C) # dnl Placeholder tmp_CFLAGS="$tmp_CFLAGS" ;; # esac # squeeze tmp_CPPFLAGS squeeze tmp_CFLAGS # if test ! -z "$tmp_CFLAGS" || test ! -z "$tmp_CPPFLAGS"; then AC_MSG_CHECKING([if compiler accepts strict warning options]) CPPFLAGS="$tmp_save_CPPFLAGS $tmp_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" squeeze CPPFLAGS squeeze CFLAGS CURL_COMPILER_WORKS_IFELSE([ AC_MSG_RESULT([yes]) AC_MSG_NOTICE([compiler options added: $tmp_CFLAGS $tmp_CPPFLAGS]) ],[ AC_MSG_RESULT([no]) AC_MSG_WARN([compiler options rejected: $tmp_CFLAGS $tmp_CPPFLAGS]) dnl restore initial settings CPPFLAGS="$tmp_save_CPPFLAGS" CFLAGS="$tmp_save_CFLAGS" ]) fi # fi ]) dnl CURL_SHFUNC_SQUEEZE dnl ------------------------------------------------- dnl Declares a shell function squeeze() which removes dnl redundant whitespace out of a shell variable. AC_DEFUN([CURL_SHFUNC_SQUEEZE], [ squeeze() { _sqz_result="" eval _sqz_input=\[$][$]1 for _sqz_token in $_sqz_input; do if test -z "$_sqz_result"; then _sqz_result="$_sqz_token" else _sqz_result="$_sqz_result $_sqz_token" fi done eval [$]1=\$_sqz_result return 0 } ]) dnl CURL_CHECK_CURLDEBUG dnl ------------------------------------------------- dnl Settings which depend on configure's curldebug given dnl option, and other additional configure pre-requisites. dnl Actually the curl debug memory tracking feature can dnl only be used/enabled when libcurl is built as a static dnl library or as a shared one on those systems on which dnl shared libraries support undefined symbols. AC_DEFUN([CURL_CHECK_CURLDEBUG], [ AC_REQUIRE([XC_LIBTOOL])dnl AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl supports_curldebug="unknown" if test "$want_curldebug" = "yes"; then if test "x$enable_shared" != "xno" && test "x$enable_shared" != "xyes"; then AC_MSG_WARN([unknown enable_shared setting.]) supports_curldebug="no" fi if test "x$enable_static" != "xno" && test "x$enable_static" != "xyes"; then AC_MSG_WARN([unknown enable_static setting.]) supports_curldebug="no" fi if test "$supports_curldebug" != "no"; then if test "$enable_shared" = "yes" && test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then supports_curldebug="no" AC_MSG_WARN([shared library does not support undefined symbols.]) fi fi fi # if test "$want_curldebug" = "yes"; then AC_MSG_CHECKING([if curl debug memory tracking can be enabled]) test "$supports_curldebug" = "no" || supports_curldebug="yes" AC_MSG_RESULT([$supports_curldebug]) if test "$supports_curldebug" = "no"; then AC_MSG_WARN([cannot enable curl debug memory tracking.]) want_curldebug="no" fi fi ]) dnl CURL_CHECK_COMPILER_HALT_ON_ERROR dnl ------------------------------------------------- dnl Verifies if the compiler actually halts after the dnl compilation phase without generating any object dnl code file, when the source compiles with errors. AC_DEFUN([CURL_CHECK_COMPILER_HALT_ON_ERROR], [ AC_MSG_CHECKING([if compiler halts on compilation errors]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ force compilation error ]]) ],[ AC_MSG_RESULT([no]) AC_MSG_ERROR([compiler does not halt on compilation errors.]) ],[ AC_MSG_RESULT([yes]) ]) ]) dnl CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE dnl ------------------------------------------------- dnl Verifies if the compiler actually halts after the dnl compilation phase without generating any object dnl code file, when the source code tries to define a dnl type for a constant array with negative dimension. AC_DEFUN([CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE], [ AC_REQUIRE([CURL_CHECK_COMPILER_HALT_ON_ERROR])dnl AC_MSG_CHECKING([if compiler halts on negative sized arrays]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ typedef char bad_t[sizeof(char) == sizeof(int) ? -1 : -1 ]; ]],[[ bad_t dummy; ]]) ],[ AC_MSG_RESULT([no]) AC_MSG_ERROR([compiler does not halt on negative sized arrays.]) ],[ AC_MSG_RESULT([yes]) ]) ]) dnl CURL_CHECK_COMPILER_STRUCT_MEMBER_SIZE dnl ------------------------------------------------- dnl Verifies if the compiler is capable of handling the dnl size of a struct member, struct which is a function dnl result, as a compilation-time condition inside the dnl type definition of a constant array. AC_DEFUN([CURL_CHECK_COMPILER_STRUCT_MEMBER_SIZE], [ AC_REQUIRE([CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE])dnl AC_MSG_CHECKING([if compiler struct member size checking works]) tst_compiler_check_one_works="unknown" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ struct mystruct { int mi; char mc; struct mystruct *next; }; struct mystruct myfunc(); typedef char good_t1[sizeof(myfunc().mi) == sizeof(int) ? 1 : -1 ]; typedef char good_t2[sizeof(myfunc().mc) == sizeof(char) ? 1 : -1 ]; ]],[[ good_t1 dummy1; good_t2 dummy2; ]]) ],[ tst_compiler_check_one_works="yes" ],[ tst_compiler_check_one_works="no" sed 's/^/cc-src: /' conftest.$ac_ext >&6 sed 's/^/cc-err: /' conftest.err >&6 ]) tst_compiler_check_two_works="unknown" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ struct mystruct { int mi; char mc; struct mystruct *next; }; struct mystruct myfunc(); typedef char bad_t1[sizeof(myfunc().mi) != sizeof(int) ? 1 : -1 ]; typedef char bad_t2[sizeof(myfunc().mc) != sizeof(char) ? 1 : -1 ]; ]],[[ bad_t1 dummy1; bad_t2 dummy2; ]]) ],[ tst_compiler_check_two_works="no" ],[ tst_compiler_check_two_works="yes" ]) if test "$tst_compiler_check_one_works" = "yes" && test "$tst_compiler_check_two_works" = "yes"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([compiler fails struct member size checking.]) fi ]) dnl CURL_CHECK_COMPILER_SYMBOL_HIDING dnl ------------------------------------------------- dnl Verify if compiler supports hiding library internal symbols, setting dnl shell variable supports_symbol_hiding value as appropriate, as well as dnl variables symbol_hiding_CFLAGS and symbol_hiding_EXTERN when supported. AC_DEFUN([CURL_CHECK_COMPILER_SYMBOL_HIDING], [ AC_REQUIRE([CURL_CHECK_COMPILER])dnl AC_BEFORE([$0],[CURL_CONFIGURE_SYMBOL_HIDING])dnl AC_MSG_CHECKING([if compiler supports hiding library internal symbols]) supports_symbol_hiding="no" symbol_hiding_CFLAGS="" symbol_hiding_EXTERN="" tmp_CFLAGS="" tmp_EXTERN="" case "$compiler_id" in CLANG) dnl All versions of clang support -fvisibility= tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" tmp_CFLAGS="-fvisibility=hidden" supports_symbol_hiding="yes" ;; GNU_C) dnl Only gcc 3.4 or later if test "$compiler_num" -ge "304"; then if $CC --help --verbose 2>/dev/null | grep fvisibility= >/dev/null ; then tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" tmp_CFLAGS="-fvisibility=hidden" supports_symbol_hiding="yes" fi fi ;; INTEL_UNIX_C) dnl Only icc 9.0 or later if test "$compiler_num" -ge "900"; then if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then tmp_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ # include ]],[[ printf("icc fvisibility bug test"); ]]) ],[ tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" tmp_CFLAGS="-fvisibility=hidden" supports_symbol_hiding="yes" ]) CFLAGS="$tmp_save_CFLAGS" fi fi ;; SUNPRO_C) if $CC 2>&1 | grep flags >/dev/null && $CC -flags | grep xldscope= >/dev/null ; then tmp_EXTERN="__global" tmp_CFLAGS="-xldscope=hidden" supports_symbol_hiding="yes" fi ;; esac if test "$supports_symbol_hiding" = "yes"; then tmp_save_CFLAGS="$CFLAGS" CFLAGS="$tmp_save_CFLAGS $tmp_CFLAGS" squeeze CFLAGS AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ $tmp_EXTERN char *dummy(char *buff); char *dummy(char *buff) { if(buff) return ++buff; else return buff; } ]],[[ char b[16]; char *r = dummy(&b[0]); if(r) return (int)*r; ]]) ],[ supports_symbol_hiding="yes" if test -f conftest.err; then grep 'visibility' conftest.err >/dev/null if test "$?" -eq "0"; then supports_symbol_hiding="no" fi fi ],[ supports_symbol_hiding="no" echo " " >&6 sed 's/^/cc-src: /' conftest.$ac_ext >&6 sed 's/^/cc-err: /' conftest.err >&6 echo " " >&6 ]) CFLAGS="$tmp_save_CFLAGS" fi if test "$supports_symbol_hiding" = "yes"; then AC_MSG_RESULT([yes]) symbol_hiding_CFLAGS="$tmp_CFLAGS" symbol_hiding_EXTERN="$tmp_EXTERN" else AC_MSG_RESULT([no]) fi ]) dnl CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH dnl ------------------------------------------------- dnl Verifies if the compiler actually halts after the dnl compilation phase without generating any object dnl code file, when the source code tries to redefine dnl a prototype which does not match previous one. AC_DEFUN([CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH], [ AC_REQUIRE([CURL_CHECK_COMPILER_HALT_ON_ERROR])dnl AC_MSG_CHECKING([if compiler halts on function prototype mismatch]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ # include int rand(int n); int rand(int n) { if(n) return ++n; else return n; } ]],[[ int i[2]={0,0}; int j = rand(i[0]); if(j) return j; ]]) ],[ AC_MSG_RESULT([no]) AC_MSG_ERROR([compiler does not halt on function prototype mismatch.]) ],[ AC_MSG_RESULT([yes]) ]) ]) dnl CURL_VAR_MATCH (VARNAME, VALUE) dnl ------------------------------------------------- dnl Verifies if shell variable VARNAME contains VALUE. dnl Contents of variable VARNAME and VALUE are handled dnl as whitespace separated lists of words. If at least dnl one word of VALUE is present in VARNAME the match dnl is considered positive, otherwise false. AC_DEFUN([CURL_VAR_MATCH], [ ac_var_match_word="no" for word1 in $[$1]; do for word2 in [$2]; do if test "$word1" = "$word2"; then ac_var_match_word="yes" fi done done ]) dnl CURL_VAR_MATCH_IFELSE (VARNAME, VALUE, dnl [ACTION-IF-MATCH], [ACTION-IF-NOT-MATCH]) dnl ------------------------------------------------- dnl This performs a CURL_VAR_MATCH check and executes dnl first branch if the match is positive, otherwise dnl the second branch is executed. AC_DEFUN([CURL_VAR_MATCH_IFELSE], [ CURL_VAR_MATCH([$1],[$2]) if test "$ac_var_match_word" = "yes"; then ifelse($3,,:,[$3]) ifelse($4,,,[else $4]) fi ]) dnl CURL_VAR_STRIP (VARNAME, VALUE) dnl ------------------------------------------------- dnl Contents of variable VARNAME and VALUE are handled dnl as whitespace separated lists of words. Each word dnl from VALUE is removed from VARNAME when present. AC_DEFUN([CURL_VAR_STRIP], [ AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl ac_var_stripped="" for word1 in $[$1]; do ac_var_strip_word="no" for word2 in [$2]; do if test "$word1" = "$word2"; then ac_var_strip_word="yes" fi done if test "$ac_var_strip_word" = "no"; then ac_var_stripped="$ac_var_stripped $word1" fi done dnl squeeze whitespace out of result [$1]="$ac_var_stripped" squeeze [$1] ]) davix-0.8.0/deps/curl/m4/curl-confopts.m40000644000000000000000000005717114121063461016621 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. # serial 19 dnl CURL_CHECK_OPTION_THREADED_RESOLVER dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-threaded-resolver or --disable-threaded-resolver, and dnl set shell variable want_thres as appropriate. AC_DEFUN([CURL_CHECK_OPTION_THREADED_RESOLVER], [ AC_MSG_CHECKING([whether to enable the threaded resolver]) OPT_THRES="default" AC_ARG_ENABLE(threaded_resolver, AC_HELP_STRING([--enable-threaded-resolver],[Enable threaded resolver]) AC_HELP_STRING([--disable-threaded-resolver],[Disable threaded resolver]), OPT_THRES=$enableval) case "$OPT_THRES" in no) dnl --disable-threaded-resolver option used want_thres="no" ;; *) dnl configure option not specified want_thres="yes" ;; esac AC_MSG_RESULT([$want_thres]) ]) dnl CURL_CHECK_OPTION_ARES dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-ares or --disable-ares, and dnl set shell variable want_ares as appropriate. AC_DEFUN([CURL_CHECK_OPTION_ARES], [ dnl AC_BEFORE([$0],[CURL_CHECK_OPTION_THREADS])dnl AC_BEFORE([$0],[CURL_CHECK_LIB_ARES])dnl AC_MSG_CHECKING([whether to enable c-ares for DNS lookups]) OPT_ARES="default" AC_ARG_ENABLE(ares, AC_HELP_STRING([--enable-ares@<:@=PATH@:>@],[Enable c-ares for DNS lookups]) AC_HELP_STRING([--disable-ares],[Disable c-ares for DNS lookups]), OPT_ARES=$enableval) case "$OPT_ARES" in no) dnl --disable-ares option used want_ares="no" ;; default) dnl configure option not specified want_ares="no" ;; *) dnl --enable-ares option used want_ares="yes" if test -n "$enableval" && test "$enableval" != "yes"; then want_ares_path="$enableval" fi ;; esac AC_MSG_RESULT([$want_ares]) ]) dnl CURL_CHECK_OPTION_CURLDEBUG dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-curldebug or --disable-curldebug, and set dnl shell variable want_curldebug value as appropriate. AC_DEFUN([CURL_CHECK_OPTION_CURLDEBUG], [ AC_BEFORE([$0],[CURL_CHECK_CURLDEBUG])dnl AC_MSG_CHECKING([whether to enable curl debug memory tracking]) OPT_CURLDEBUG_BUILD="default" AC_ARG_ENABLE(curldebug, AC_HELP_STRING([--enable-curldebug],[Enable curl debug memory tracking]) AC_HELP_STRING([--disable-curldebug],[Disable curl debug memory tracking]), OPT_CURLDEBUG_BUILD=$enableval) case "$OPT_CURLDEBUG_BUILD" in no) dnl --disable-curldebug option used want_curldebug="no" AC_MSG_RESULT([no]) ;; default) dnl configure's curldebug option not specified. Initially we will dnl handle this as a request to use the same setting as option dnl --enable-debug. IOW, initially, for debug-enabled builds dnl this will be handled as a request to enable curldebug if dnl possible, and for debug-disabled builds this will be handled dnl as a request to disable curldebug. if test "$want_debug" = "yes"; then AC_MSG_RESULT([(assumed) yes]) AC_DEFINE(CURLDEBUG, 1, [to enable curl debug memory tracking]) else AC_MSG_RESULT([no]) fi want_curldebug_assumed="yes" want_curldebug="$want_debug" ;; *) dnl --enable-curldebug option used. dnl The use of this option value is a request to enable curl's dnl debug memory tracking for the libcurl library. This can only dnl be done when some requisites are simultaneously satisfied. dnl Later on, these requisites are verified and if they are not dnl fully satisfied the option will be ignored and act as if dnl --disable-curldebug had been given setting shell variable dnl want_curldebug to 'no'. want_curldebug="yes" AC_DEFINE(CURLDEBUG, 1, [to enable curl debug memory tracking]) AC_MSG_RESULT([yes]) ;; esac ]) dnl CURL_CHECK_OPTION_DEBUG dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-debug or --disable-debug, and set shell dnl variable want_debug value as appropriate. AC_DEFUN([CURL_CHECK_OPTION_DEBUG], [ AC_BEFORE([$0],[CURL_CHECK_OPTION_WARNINGS])dnl AC_BEFORE([$0],[CURL_CHECK_OPTION_CURLDEBUG])dnl AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl AC_MSG_CHECKING([whether to enable debug build options]) OPT_DEBUG_BUILD="default" AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[Enable debug build options]) AC_HELP_STRING([--disable-debug],[Disable debug build options]), OPT_DEBUG_BUILD=$enableval) case "$OPT_DEBUG_BUILD" in no) dnl --disable-debug option used want_debug="no" ;; default) dnl configure option not specified want_debug="no" ;; *) dnl --enable-debug option used want_debug="yes" AC_DEFINE(DEBUGBUILD, 1, [enable debug build options]) ;; esac AC_MSG_RESULT([$want_debug]) ]) dnl CURL_CHECK_OPTION_OPTIMIZE dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-optimize or --disable-optimize, and set dnl shell variable want_optimize value as appropriate. AC_DEFUN([CURL_CHECK_OPTION_OPTIMIZE], [ AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl AC_MSG_CHECKING([whether to enable compiler optimizer]) OPT_COMPILER_OPTIMIZE="default" AC_ARG_ENABLE(optimize, AC_HELP_STRING([--enable-optimize],[Enable compiler optimizations]) AC_HELP_STRING([--disable-optimize],[Disable compiler optimizations]), OPT_COMPILER_OPTIMIZE=$enableval) case "$OPT_COMPILER_OPTIMIZE" in no) dnl --disable-optimize option used. We will handle this as dnl a request to disable compiler optimizations if possible. dnl If the compiler is known CFLAGS and CPPFLAGS will be dnl overridden, otherwise this can not be honored. want_optimize="no" AC_MSG_RESULT([no]) ;; default) dnl configure's optimize option not specified. Initially we will dnl handle this as a request contrary to configure's setting dnl for --enable-debug. IOW, initially, for debug-enabled builds dnl this will be handled as a request to disable optimizations if dnl possible, and for debug-disabled builds this will be handled dnl initially as a request to enable optimizations if possible. dnl Finally, if the compiler is known and CFLAGS and CPPFLAGS do dnl not have any optimizer flag the request will be honored, in dnl any other case the request can not be honored. dnl IOW, existing optimizer flags defined in CFLAGS or CPPFLAGS dnl will always take precedence over any initial assumption. if test "$want_debug" = "yes"; then want_optimize="assume_no" AC_MSG_RESULT([(assumed) no]) else want_optimize="assume_yes" AC_MSG_RESULT([(assumed) yes]) fi ;; *) dnl --enable-optimize option used. We will handle this as dnl a request to enable compiler optimizations if possible. dnl If the compiler is known CFLAGS and CPPFLAGS will be dnl overridden, otherwise this can not be honored. want_optimize="yes" AC_MSG_RESULT([yes]) ;; esac ]) dnl CURL_CHECK_OPTION_SYMBOL_HIDING dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-symbol-hiding or --disable-symbol-hiding, dnl setting shell variable want_symbol_hiding value. AC_DEFUN([CURL_CHECK_OPTION_SYMBOL_HIDING], [ AC_BEFORE([$0],[CURL_CHECK_COMPILER_SYMBOL_HIDING])dnl AC_MSG_CHECKING([whether to enable hiding of library internal symbols]) OPT_SYMBOL_HIDING="default" AC_ARG_ENABLE(symbol-hiding, AC_HELP_STRING([--enable-symbol-hiding],[Enable hiding of library internal symbols]) AC_HELP_STRING([--disable-symbol-hiding],[Disable hiding of library internal symbols]), OPT_SYMBOL_HIDING=$enableval) AC_ARG_ENABLE(hidden-symbols, AC_HELP_STRING([--enable-hidden-symbols],[To be deprecated, use --enable-symbol-hiding]) AC_HELP_STRING([--disable-hidden-symbols],[To be deprecated, use --disable-symbol-hiding]), OPT_SYMBOL_HIDING=$enableval) case "$OPT_SYMBOL_HIDING" in no) dnl --disable-symbol-hiding option used. dnl This is an indication to not attempt hiding of library internal dnl symbols. Default symbol visibility will be used, which normally dnl exposes all library internal symbols. want_symbol_hiding="no" AC_MSG_RESULT([no]) ;; default) dnl configure's symbol-hiding option not specified. dnl Handle this as if --enable-symbol-hiding option was given. want_symbol_hiding="yes" AC_MSG_RESULT([yes]) ;; *) dnl --enable-symbol-hiding option used. dnl This is an indication to attempt hiding of library internal dnl symbols. This is only supported on some compilers/linkers. want_symbol_hiding="yes" AC_MSG_RESULT([yes]) ;; esac ]) dnl CURL_CHECK_OPTION_THREADS dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-threads or --disable-threads, and dnl set shell variable want_threads as appropriate. dnl AC_DEFUN([CURL_CHECK_OPTION_THREADS], [ dnl AC_BEFORE([$0],[CURL_CHECK_LIB_THREADS])dnl dnl AC_MSG_CHECKING([whether to enable threads for DNS lookups]) dnl OPT_THREADS="default" dnl AC_ARG_ENABLE(threads, dnl AC_HELP_STRING([--enable-threads@<:@=PATH@:>@],[Enable threads for DNS lookups]) dnl AC_HELP_STRING([--disable-threads],[Disable threads for DNS lookups]), dnl OPT_THREADS=$enableval) dnl case "$OPT_THREADS" in dnl no) dnl dnl --disable-threads option used dnl want_threads="no" dnl AC_MSG_RESULT([no]) dnl ;; dnl default) dnl dnl configure option not specified dnl want_threads="no" dnl AC_MSG_RESULT([(assumed) no]) dnl ;; dnl *) dnl dnl --enable-threads option used dnl want_threads="yes" dnl want_threads_path="$enableval" dnl AC_MSG_RESULT([yes]) dnl ;; dnl esac dnl # dnl if test "$want_ares" = "assume_yes"; then dnl if test "$want_threads" = "yes"; then dnl AC_MSG_CHECKING([whether to ignore c-ares enabling assumed setting]) dnl AC_MSG_RESULT([yes]) dnl want_ares="no" dnl else dnl want_ares="yes" dnl fi dnl fi dnl if test "$want_threads" = "yes" && test "$want_ares" = "yes"; then dnl AC_MSG_ERROR([options --enable-ares and --enable-threads are mutually exclusive, at most one may be enabled.]) dnl fi dnl ]) dnl CURL_CHECK_OPTION_RT dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --disable-rt and set shell variable dontwant_rt dnl as appropriate. AC_DEFUN([CURL_CHECK_OPTION_RT], [ AC_BEFORE([$0], [CURL_CHECK_LIB_THREADS])dnl AC_MSG_CHECKING([whether to disable dependency on -lrt]) OPT_RT="default" AC_ARG_ENABLE(rt, AC_HELP_STRING([--disable-rt],[disable dependency on -lrt]), OPT_RT=$enableval) case "$OPT_RT" in no) dnl --disable-rt used (reverse logic) dontwant_rt="yes" AC_MSG_RESULT([yes]) ;; default) dnl configure option not specified (so not disabled) dontwant_rt="no" AC_MSG_RESULT([(assumed no)]) ;; *) dnl --enable-rt option used (reverse logic) dontwant_rt="no" AC_MSG_RESULT([no]) ;; esac ]) dnl CURL_CHECK_OPTION_WARNINGS dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-warnings or --disable-warnings, and set dnl shell variable want_warnings as appropriate. AC_DEFUN([CURL_CHECK_OPTION_WARNINGS], [ AC_REQUIRE([CURL_CHECK_OPTION_DEBUG])dnl AC_BEFORE([$0],[CURL_CHECK_OPTION_WERROR])dnl AC_BEFORE([$0],[XC_CHECK_PROG_CC])dnl AC_MSG_CHECKING([whether to enable strict compiler warnings]) OPT_COMPILER_WARNINGS="default" AC_ARG_ENABLE(warnings, AC_HELP_STRING([--enable-warnings],[Enable strict compiler warnings]) AC_HELP_STRING([--disable-warnings],[Disable strict compiler warnings]), OPT_COMPILER_WARNINGS=$enableval) case "$OPT_COMPILER_WARNINGS" in no) dnl --disable-warnings option used want_warnings="no" ;; default) dnl configure option not specified, so dnl use same setting as --enable-debug want_warnings="$want_debug" ;; *) dnl --enable-warnings option used want_warnings="yes" ;; esac AC_MSG_RESULT([$want_warnings]) ]) dnl CURL_CHECK_OPTION_WERROR dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-werror or --disable-werror, and set dnl shell variable want_werror as appropriate. AC_DEFUN([CURL_CHECK_OPTION_WERROR], [ AC_BEFORE([$0],[CURL_CHECK_COMPILER])dnl AC_MSG_CHECKING([whether to enable compiler warnings as errors]) OPT_COMPILER_WERROR="default" AC_ARG_ENABLE(werror, AC_HELP_STRING([--enable-werror],[Enable compiler warnings as errors]) AC_HELP_STRING([--disable-werror],[Disable compiler warnings as errors]), OPT_COMPILER_WERROR=$enableval) case "$OPT_COMPILER_WERROR" in no) dnl --disable-werror option used want_werror="no" ;; default) dnl configure option not specified want_werror="no" ;; *) dnl --enable-werror option used want_werror="yes" ;; esac AC_MSG_RESULT([$want_werror]) ]) dnl CURL_CHECK_NONBLOCKING_SOCKET dnl ------------------------------------------------- dnl Check for how to set a socket into non-blocking state. AC_DEFUN([CURL_CHECK_NONBLOCKING_SOCKET], [ AC_REQUIRE([CURL_CHECK_FUNC_FCNTL])dnl AC_REQUIRE([CURL_CHECK_FUNC_IOCTL])dnl AC_REQUIRE([CURL_CHECK_FUNC_IOCTLSOCKET])dnl AC_REQUIRE([CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL])dnl AC_REQUIRE([CURL_CHECK_FUNC_SETSOCKOPT])dnl # tst_method="unknown" AC_MSG_CHECKING([how to set a socket into non-blocking mode]) if test "x$curl_cv_func_fcntl_o_nonblock" = "xyes"; then tst_method="fcntl O_NONBLOCK" elif test "x$curl_cv_func_ioctl_fionbio" = "xyes"; then tst_method="ioctl FIONBIO" elif test "x$curl_cv_func_ioctlsocket_fionbio" = "xyes"; then tst_method="ioctlsocket FIONBIO" elif test "x$curl_cv_func_ioctlsocket_camel_fionbio" = "xyes"; then tst_method="IoctlSocket FIONBIO" elif test "x$curl_cv_func_setsockopt_so_nonblock" = "xyes"; then tst_method="setsockopt SO_NONBLOCK" fi AC_MSG_RESULT([$tst_method]) if test "$tst_method" = "unknown"; then AC_MSG_WARN([cannot determine non-blocking socket method.]) fi ]) dnl CURL_CONFIGURE_SYMBOL_HIDING dnl ------------------------------------------------- dnl Depending on --enable-symbol-hiding or --disable-symbol-hiding dnl configure option, and compiler capability to actually honor such dnl option, this will modify compiler flags as appropriate and also dnl provide needed definitions for configuration and Makefile.am files. dnl This macro should not be used until all compilation tests have dnl been done to prevent interferences on other tests. AC_DEFUN([CURL_CONFIGURE_SYMBOL_HIDING], [ AC_MSG_CHECKING([whether hiding of library internal symbols will actually happen]) CFLAG_CURL_SYMBOL_HIDING="" doing_symbol_hiding="no" if test x"$curl_cv_native_windows" != "xyes" && test "$want_symbol_hiding" = "yes" && test "$supports_symbol_hiding" = "yes"; then doing_symbol_hiding="yes" CFLAG_CURL_SYMBOL_HIDING="$symbol_hiding_CFLAGS" AC_DEFINE_UNQUOTED(CURL_EXTERN_SYMBOL, $symbol_hiding_EXTERN, [Definition to make a library symbol externally visible.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AM_CONDITIONAL(DOING_CURL_SYMBOL_HIDING, test x$doing_symbol_hiding = xyes) AC_SUBST(CFLAG_CURL_SYMBOL_HIDING) ]) dnl CURL_CHECK_LIB_ARES dnl ------------------------------------------------- dnl When c-ares library support has been requested, dnl performs necessary checks and adjustsments needed dnl to enable support of this library. AC_DEFUN([CURL_CHECK_LIB_ARES], [ # if test "$want_ares" = "yes"; then dnl c-ares library support has been requested clean_CPPFLAGS="$CPPFLAGS" clean_LDFLAGS="$LDFLAGS" clean_LIBS="$LIBS" embedded_ares="unknown" configure_runpath=`pwd` embedded_ares_builddir="$configure_runpath/ares" if test -n "$want_ares_path"; then dnl c-ares library path has been specified ARES_PCDIR="$want_ares_path/lib/pkgconfig" CURL_CHECK_PKGCONFIG(libcares, [$ARES_PCDIR]) if test "$PKGCONFIG" != "no" ; then ares_LIBS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) $PKGCONFIG --libs-only-l libcares` ares_LDFLAGS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) $PKGCONFIG --libs-only-L libcares` ares_CPPFLAGS=`CURL_EXPORT_PCDIR([$ARES_PCDIR]) $PKGCONFIG --cflags-only-I libcares` AC_MSG_NOTICE([pkg-config: ares LIBS: "$ares_LIBS"]) AC_MSG_NOTICE([pkg-config: ares LDFLAGS: "$ares_LDFLAGS"]) AC_MSG_NOTICE([pkg-config: ares CPPFLAGS: "$ares_CPPFLAGS"]) else dnl ... path without pkg-config ares_CPPFLAGS="-I$want_ares_path/include" ares_LDFLAGS="-L$want_ares_path/lib" ares_LIBS="-lcares" fi else dnl c-ares library path has not been given if test -d "$srcdir/ares"; then dnl c-ares sources embedded in curl tree embedded_ares="yes" AC_CONFIG_SUBDIRS(ares) dnl c-ares has installable configured header files, path dnl inclusion fully done in makefiles for in-tree builds. ares_CPPFLAGS="" ares_LDFLAGS="-L$embedded_ares_builddir" ares_LIBS="-lcares" else dnl c-ares path not specified, use defaults CURL_CHECK_PKGCONFIG(libcares) if test "$PKGCONFIG" != "no" ; then ares_LIBS=`$PKGCONFIG --libs-only-l libcares` ares_LDFLAGS=`$PKGCONFIG --libs-only-L libcares` ares_CPPFLAGS=`$PKGCONFIG --cflags-only-I libcares` AC_MSG_NOTICE([pkg-config: ares_LIBS: "$ares_LIBS"]) AC_MSG_NOTICE([pkg-config: ares_LDFLAGS: "$ares_LDFLAGS"]) AC_MSG_NOTICE([pkg-config: ares_CPPFLAGS: "$ares_CPPFLAGS"]) else ares_CPPFLAGS="" ares_LDFLAGS="" ares_LIBS="-lcares" fi fi fi # CPPFLAGS="$clean_CPPFLAGS $ares_CPPFLAGS" LDFLAGS="$clean_LDFLAGS $ares_LDFLAGS" LIBS="$ares_LIBS $clean_LIBS" # if test "$embedded_ares" != "yes"; then dnl check if c-ares new enough when not using an embedded dnl source tree one which normally has not been built yet. AC_MSG_CHECKING([that c-ares is good and recent enough]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #include /* set of dummy functions in case c-ares was built with debug */ void curl_dofree() { } void curl_sclose() { } void curl_domalloc() { } void curl_docalloc() { } void curl_socket() { } ]],[[ ares_channel channel; ares_cancel(channel); /* added in 1.2.0 */ ares_process_fd(channel, 0, 0); /* added in 1.4.0 */ ares_dup(&channel, channel); /* added in 1.6.0 */ ]]) ],[ AC_MSG_RESULT([yes]) ],[ AC_MSG_RESULT([no]) AC_MSG_ERROR([c-ares library defective or too old]) dnl restore initial settings CPPFLAGS="$clean_CPPFLAGS" LDFLAGS="$clean_LDFLAGS" LIBS="$clean_LIBS" # prevent usage want_ares="no" ]) fi if test "$want_ares" = "yes"; then dnl finally c-ares will be used AC_DEFINE(USE_ARES, 1, [Define to enable c-ares support]) AC_SUBST([USE_ARES], [1]) curl_res_msg="c-ares" fi fi ]) dnl CURL_CHECK_OPTION_NTLM_WB dnl ------------------------------------------------- dnl Verify if configure has been invoked with option dnl --enable-ntlm-wb or --disable-ntlm-wb, and set dnl shell variable want_ntlm_wb and want_ntlm_wb_file dnl as appropriate. AC_DEFUN([CURL_CHECK_OPTION_NTLM_WB], [ AC_BEFORE([$0],[CURL_CHECK_NTLM_WB])dnl OPT_NTLM_WB="default" AC_ARG_ENABLE(ntlm-wb, AC_HELP_STRING([--enable-ntlm-wb@<:@=FILE@:>@],[Enable NTLM delegation to winbind's ntlm_auth helper, where FILE is ntlm_auth's absolute filename (default: /usr/bin/ntlm_auth)]) AC_HELP_STRING([--disable-ntlm-wb],[Disable NTLM delegation to winbind's ntlm_auth helper]), OPT_NTLM_WB=$enableval) want_ntlm_wb_file="/usr/bin/ntlm_auth" case "$OPT_NTLM_WB" in no) dnl --disable-ntlm-wb option used want_ntlm_wb="no" ;; default) dnl configure option not specified want_ntlm_wb="yes" ;; *) dnl --enable-ntlm-wb option used want_ntlm_wb="yes" if test -n "$enableval" && test "$enableval" != "yes"; then want_ntlm_wb_file="$enableval" fi ;; esac ]) dnl CURL_CHECK_NTLM_WB dnl ------------------------------------------------- dnl Check if support for NTLM delegation to winbind's dnl ntlm_auth helper will finally be enabled depending dnl on given configure options and target platform. AC_DEFUN([CURL_CHECK_NTLM_WB], [ AC_REQUIRE([CURL_CHECK_OPTION_NTLM_WB])dnl AC_REQUIRE([CURL_CHECK_NATIVE_WINDOWS])dnl AC_MSG_CHECKING([whether to enable NTLM delegation to winbind's helper]) if test "$curl_cv_native_windows" = "yes" || test "x$SSL_ENABLED" = "x"; then want_ntlm_wb_file="" want_ntlm_wb="no" fi AC_MSG_RESULT([$want_ntlm_wb]) if test "$want_ntlm_wb" = "yes"; then AC_DEFINE(NTLM_WB_ENABLED, 1, [Define to enable NTLM delegation to winbind's ntlm_auth helper.]) AC_DEFINE_UNQUOTED(NTLM_WB_FILE, "$want_ntlm_wb_file", [Define absolute filename for winbind's ntlm_auth helper.]) NTLM_WB_ENABLED=1 fi ]) dnl CURL_CHECK_OPTION_ESNI dnl ----------------------------------------------------- dnl Verify whether configure has been invoked with option dnl --enable-esni or --disable-esni, and set dnl shell variable want_esni as appropriate. AC_DEFUN([CURL_CHECK_OPTION_ESNI], [ AC_MSG_CHECKING([whether to enable ESNI support]) OPT_ESNI="default" AC_ARG_ENABLE(esni, AC_HELP_STRING([--enable-esni],[Enable ESNI support]) AC_HELP_STRING([--disable-esni],[Disable ESNI support]), OPT_ESNI=$enableval) case "$OPT_ESNI" in no) dnl --disable-esni option used want_esni="no" curl_esni_msg="no (--enable-esni)" AC_MSG_RESULT([no]) ;; default) dnl configure option not specified want_esni="no" curl_esni_msg="no (--enable-esni)" AC_MSG_RESULT([no]) ;; *) dnl --enable-esni option used want_esni="yes" curl_esni_msg="enabled (--disable-esni)" experimental="esni" AC_MSG_RESULT([yes]) ;; esac ]) davix-0.8.0/deps/curl/m4/xc-cc-check.m40000644000000000000000000000560514121063461016066 0ustar rootroot#--------------------------------------------------------------------------- # # xc-cc-check.m4 # # Copyright (c) 2013 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl _XC_PROG_CC_PREAMBLE dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_PROG_CC_PREAMBLE], [ xc_prog_cc_prev_IFS=$IFS xc_prog_cc_prev_LIBS=$LIBS xc_prog_cc_prev_CFLAGS=$CFLAGS xc_prog_cc_prev_LDFLAGS=$LDFLAGS xc_prog_cc_prev_CPPFLAGS=$CPPFLAGS ]) dnl _XC_PROG_CC_POSTLUDE dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_PROG_CC_POSTLUDE], [ IFS=$xc_prog_cc_prev_IFS LIBS=$xc_prog_cc_prev_LIBS CFLAGS=$xc_prog_cc_prev_CFLAGS LDFLAGS=$xc_prog_cc_prev_LDFLAGS CPPFLAGS=$xc_prog_cc_prev_CPPFLAGS AC_SUBST([CC])dnl AC_SUBST([CPP])dnl AC_SUBST([LIBS])dnl AC_SUBST([CFLAGS])dnl AC_SUBST([LDFLAGS])dnl AC_SUBST([CPPFLAGS])dnl ]) dnl _XC_PROG_CC dnl ------------------------------------------------- dnl Private macro. AC_DEFUN([_XC_PROG_CC], [ AC_REQUIRE([_XC_PROG_CC_PREAMBLE])dnl AC_REQUIRE([XC_CHECK_BUILD_FLAGS])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AM_PROG_CC_C_O])dnl AC_REQUIRE([AC_PROG_CPP])dnl AC_REQUIRE([_XC_PROG_CC_POSTLUDE])dnl ]) dnl XC_CHECK_PROG_CC dnl ------------------------------------------------- dnl Public macro. dnl dnl Checks for C compiler and C preprocessor programs, dnl while doing some previous sanity validation on user dnl provided LIBS, LDFLAGS, CPPFLAGS and CFLAGS values dnl that must succeed in order to continue execution. dnl dnl This sets variables CC and CPP, while preventing dnl LIBS, LDFLAGS, CFLAGS, CPPFLAGS and IFS from being dnl unexpectedly changed by underlying macros. AC_DEFUN([XC_CHECK_PROG_CC], [ AC_PREREQ([2.50])dnl AC_BEFORE([$0],[_XC_PROG_CC_PREAMBLE])dnl AC_BEFORE([$0],[AC_PROG_INSTALL])dnl AC_BEFORE([$0],[AC_PROG_CC])dnl AC_BEFORE([$0],[AM_PROG_CC_C_O])dnl AC_BEFORE([$0],[AC_PROG_CPP])dnl AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl AC_BEFORE([$0],[_XC_PROG_CC_POSTLUDE])dnl AC_REQUIRE([_XC_PROG_CC])dnl ]) davix-0.8.0/deps/curl/m4/xc-lt-iface.m40000644000000000000000000002770214121063461016114 0ustar rootroot#--------------------------------------------------------------------------- # # xc-lt-iface.m4 # # Copyright (c) 2013 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl _XC_LIBTOOL_PREAMBLE dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks some configure script options related with dnl libtool and customizes its default behavior before dnl libtool code is actually used in script. m4_define([_XC_LIBTOOL_PREAMBLE], [dnl # ------------------------------------ # # Determine libtool default behavior # # ------------------------------------ # # # Default behavior is to enable shared and static libraries on systems # where libtool knows how to build both library versions, and does not # require separate configuration and build runs for each flavor. # xc_lt_want_enable_shared='yes' xc_lt_want_enable_static='yes' # # User may have disabled shared or static libraries. # case "x$enable_shared" in @%:@ ( xno) xc_lt_want_enable_shared='no' ;; esac case "x$enable_static" in @%:@ ( xno) xc_lt_want_enable_static='no' ;; esac if test "x$xc_lt_want_enable_shared" = 'xno' && test "x$xc_lt_want_enable_static" = 'xno'; then AC_MSG_ERROR([can not disable shared and static libraries simultaneously]) fi # # Default behavior on systems that require independent configuration # and build runs for shared and static is to enable shared libraries # and disable static ones. On these systems option '--disable-shared' # must be used in order to build a proper static library. # if test "x$xc_lt_want_enable_shared" = 'xyes' && test "x$xc_lt_want_enable_static" = 'xyes'; then case $host_os in @%:@ ( pw32* | cegcc* | os2* | aix*) xc_lt_want_enable_static='no' ;; esac fi # # Make libtool aware of current shared and static library preferences # taking in account that, depending on host characteristics, libtool # may modify these option preferences later in this configure script. # enable_shared=$xc_lt_want_enable_shared enable_static=$xc_lt_want_enable_static # # Default behavior is to build PIC objects for shared libraries and # non-PIC objects for static libraries. # xc_lt_want_with_pic='default' # # User may have specified PIC preference. # case "x$with_pic" in @%:@ (( xno) xc_lt_want_with_pic='no' ;; xyes) xc_lt_want_with_pic='yes' ;; esac # # Default behavior on some systems where building a shared library out # of non-PIC compiled objects will fail with following linker error # "relocation R_X86_64_32 can not be used when making a shared object" # is to build PIC objects even for static libraries. This behavior may # be overridden using 'configure --disable-shared --without-pic'. # if test "x$xc_lt_want_with_pic" = 'xdefault'; then case $host_cpu in @%:@ ( x86_64 | amd64 | ia64) case $host_os in @%:@ ( linux* | freebsd*) xc_lt_want_with_pic='yes' ;; esac ;; esac fi # # Make libtool aware of current PIC preference taking in account that, # depending on host characteristics, libtool may modify PIC default # behavior to fit host system idiosyncrasies later in this script. # with_pic=$xc_lt_want_with_pic dnl m4_define([$0],[])dnl ]) dnl _XC_LIBTOOL_BODY dnl ------------------------------------------------- dnl Private macro. dnl dnl This macro performs embedding of libtool code into dnl configure script, regardless of libtool version in dnl use when generating configure script. m4_define([_XC_LIBTOOL_BODY], [dnl ## ----------------------- ## ## Start of libtool code ## ## ----------------------- ## m4_ifdef([LT_INIT], [dnl LT_INIT([win32-dll]) ],[dnl AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL ])dnl ## --------------------- ## ## End of libtool code ## ## --------------------- ## dnl m4_define([$0], [])[]dnl ]) dnl _XC_CHECK_LT_BUILD_LIBRARIES dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks whether libtool shared and static libraries dnl are finally built depending on user input, default dnl behavior and knowledge that libtool has about host dnl characteristics. dnl Results stored in following shell variables: dnl xc_lt_build_shared dnl xc_lt_build_static m4_define([_XC_CHECK_LT_BUILD_LIBRARIES], [dnl # # Verify if finally libtool shared libraries will be built # case "x$enable_shared" in @%:@ (( xyes | xno) xc_lt_build_shared=$enable_shared ;; *) AC_MSG_ERROR([unexpected libtool enable_shared value: $enable_shared]) ;; esac # # Verify if finally libtool static libraries will be built # case "x$enable_static" in @%:@ (( xyes | xno) xc_lt_build_static=$enable_static ;; *) AC_MSG_ERROR([unexpected libtool enable_static value: $enable_static]) ;; esac dnl m4_define([$0],[])dnl ]) dnl _XC_CHECK_LT_SHLIB_USE_VERSION_INFO dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks if the -version-info linker flag must be dnl provided when building libtool shared libraries. dnl Result stored in xc_lt_shlib_use_version_info. m4_define([_XC_CHECK_LT_SHLIB_USE_VERSION_INFO], [dnl # # Verify if libtool shared libraries should be linked using flag -version-info # AC_MSG_CHECKING([whether to build shared libraries with -version-info]) xc_lt_shlib_use_version_info='yes' if test "x$version_type" = 'xnone'; then xc_lt_shlib_use_version_info='no' fi case $host_os in @%:@ ( amigaos*) xc_lt_shlib_use_version_info='yes' ;; esac AC_MSG_RESULT([$xc_lt_shlib_use_version_info]) dnl m4_define([$0], [])[]dnl ]) dnl _XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks if the -no-undefined linker flag must be dnl provided when building libtool shared libraries. dnl Result stored in xc_lt_shlib_use_no_undefined. m4_define([_XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED], [dnl # # Verify if libtool shared libraries should be linked using flag -no-undefined # AC_MSG_CHECKING([whether to build shared libraries with -no-undefined]) xc_lt_shlib_use_no_undefined='no' if test "x$allow_undefined" = 'xno'; then xc_lt_shlib_use_no_undefined='yes' elif test "x$allow_undefined_flag" = 'xunsupported'; then xc_lt_shlib_use_no_undefined='yes' fi case $host_os in @%:@ ( cygwin* | mingw* | pw32* | cegcc* | os2* | aix*) xc_lt_shlib_use_no_undefined='yes' ;; esac AC_MSG_RESULT([$xc_lt_shlib_use_no_undefined]) dnl m4_define([$0], [])[]dnl ]) dnl _XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks if the -mimpure-text linker flag must be dnl provided when building libtool shared libraries. dnl Result stored in xc_lt_shlib_use_mimpure_text. m4_define([_XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT], [dnl # # Verify if libtool shared libraries should be linked using flag -mimpure-text # AC_MSG_CHECKING([whether to build shared libraries with -mimpure-text]) xc_lt_shlib_use_mimpure_text='no' case $host_os in @%:@ ( solaris2*) if test "x$GCC" = 'xyes'; then xc_lt_shlib_use_mimpure_text='yes' fi ;; esac AC_MSG_RESULT([$xc_lt_shlib_use_mimpure_text]) dnl m4_define([$0], [])[]dnl ]) dnl _XC_CHECK_LT_BUILD_WITH_PIC dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks whether libtool shared and static libraries dnl would be built with PIC depending on user input, dnl default behavior and knowledge that libtool has dnl about host characteristics. dnl Results stored in following shell variables: dnl xc_lt_build_shared_with_pic dnl xc_lt_build_static_with_pic m4_define([_XC_CHECK_LT_BUILD_WITH_PIC], [dnl # # Find out whether libtool libraries would be built wit PIC # case "x$pic_mode" in @%:@ (((( xdefault) xc_lt_build_shared_with_pic='yes' xc_lt_build_static_with_pic='no' ;; xyes) xc_lt_build_shared_with_pic='yes' xc_lt_build_static_with_pic='yes' ;; xno) xc_lt_build_shared_with_pic='no' xc_lt_build_static_with_pic='no' ;; *) xc_lt_build_shared_with_pic='unknown' xc_lt_build_static_with_pic='unknown' AC_MSG_WARN([unexpected libtool pic_mode value: $pic_mode]) ;; esac AC_MSG_CHECKING([whether to build shared libraries with PIC]) AC_MSG_RESULT([$xc_lt_build_shared_with_pic]) AC_MSG_CHECKING([whether to build static libraries with PIC]) AC_MSG_RESULT([$xc_lt_build_static_with_pic]) dnl m4_define([$0],[])dnl ]) dnl _XC_CHECK_LT_BUILD_SINGLE_VERSION dnl ------------------------------------------------- dnl Private macro. dnl dnl Checks whether a libtool shared or static library dnl is finally built exclusively without the other. dnl Results stored in following shell variables: dnl xc_lt_build_shared_only dnl xc_lt_build_static_only m4_define([_XC_CHECK_LT_BUILD_SINGLE_VERSION], [dnl # # Verify if libtool shared libraries will be built while static not built # AC_MSG_CHECKING([whether to build shared libraries only]) if test "$xc_lt_build_shared" = 'yes' && test "$xc_lt_build_static" = 'no'; then xc_lt_build_shared_only='yes' else xc_lt_build_shared_only='no' fi AC_MSG_RESULT([$xc_lt_build_shared_only]) # # Verify if libtool static libraries will be built while shared not built # AC_MSG_CHECKING([whether to build static libraries only]) if test "$xc_lt_build_static" = 'yes' && test "$xc_lt_build_shared" = 'no'; then xc_lt_build_static_only='yes' else xc_lt_build_static_only='no' fi AC_MSG_RESULT([$xc_lt_build_static_only]) dnl m4_define([$0],[])dnl ]) dnl _XC_LIBTOOL_POSTLUDE dnl ------------------------------------------------- dnl Private macro. dnl dnl Performs several checks related with libtool that dnl can not be done unless libtool code has already dnl been executed. See individual check descriptions dnl for further info. m4_define([_XC_LIBTOOL_POSTLUDE], [dnl _XC_CHECK_LT_BUILD_LIBRARIES _XC_CHECK_LT_SHLIB_USE_VERSION_INFO _XC_CHECK_LT_SHLIB_USE_NO_UNDEFINED _XC_CHECK_LT_SHLIB_USE_MIMPURE_TEXT _XC_CHECK_LT_BUILD_WITH_PIC _XC_CHECK_LT_BUILD_SINGLE_VERSION dnl m4_define([$0],[])dnl ]) dnl XC_LIBTOOL dnl ------------------------------------------------- dnl Public macro. dnl dnl This macro embeds libtool machinery into configure dnl script, regardless of libtool version, and performs dnl several additional checks whose results can be used dnl later on. dnl dnl Usage of this macro ensures that generated configure dnl script uses equivalent logic irrespective of autoconf dnl or libtool version being used to generate configure dnl script. dnl dnl Results stored in following shell variables: dnl xc_lt_build_shared dnl xc_lt_build_static dnl xc_lt_shlib_use_version_info dnl xc_lt_shlib_use_no_undefined dnl xc_lt_shlib_use_mimpure_text dnl xc_lt_build_shared_with_pic dnl xc_lt_build_static_with_pic dnl xc_lt_build_shared_only dnl xc_lt_build_static_only AC_DEFUN([XC_LIBTOOL], [dnl AC_PREREQ([2.50])dnl dnl AC_BEFORE([$0],[LT_INIT])dnl AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl dnl AC_REQUIRE([XC_CHECK_PATH_SEPARATOR])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl dnl _XC_LIBTOOL_PREAMBLE _XC_LIBTOOL_BODY _XC_LIBTOOL_POSTLUDE dnl m4_ifdef([AC_LIBTOOL_WIN32_DLL], [m4_undefine([AC_LIBTOOL_WIN32_DLL])])dnl m4_ifdef([AC_PROG_LIBTOOL], [m4_undefine([AC_PROG_LIBTOOL])])dnl m4_ifdef([LT_INIT], [m4_undefine([LT_INIT])])dnl dnl m4_define([$0],[])dnl ]) davix-0.8.0/deps/curl/m4/xc-translit.m40000644000000000000000000001323614121063461016265 0ustar rootroot#--------------------------------------------------------------------------- # # xc-translit.m4 # # Copyright (c) 2011 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # File version for 'aclocal' use. Keep it a single number. # serial 2 dnl XC_SH_TR_SH (expression) dnl ------------------------------------------------- dnl Shell execution time transliteration of 'expression' dnl argument, where all non-alfanumeric characters are dnl converted to the underscore '_' character. dnl Normal shell expansion and substitution takes place dnl for given 'expression' at shell execution time before dnl transliteration is applied to it. AC_DEFUN([XC_SH_TR_SH], [`echo "$1" | sed 's/[[^a-zA-Z0-9_]]/_/g'`]) dnl XC_SH_TR_SH_EX (expression, [extra]) dnl ------------------------------------------------- dnl Like XC_SH_TR_SH but transliterating characters dnl given in 'extra' argument to lowercase 'p'. For dnl example [*+], [*], and [+] are valid 'extra' args. AC_DEFUN([XC_SH_TR_SH_EX], [ifelse([$2], [], [XC_SH_TR_SH([$1])], [`echo "$1" | sed 's/[[$2]]/p/g' | sed 's/[[^a-zA-Z0-9_]]/_/g'`])]) dnl XC_M4_TR_SH (expression) dnl ------------------------------------------------- dnl m4 execution time transliteration of 'expression' dnl argument, where all non-alfanumeric characters are dnl converted to the underscore '_' character. AC_DEFUN([XC_M4_TR_SH], [patsubst(XC_QPATSUBST(XC_QUOTE($1), [[^a-zA-Z0-9_]], [_]), [\(_\(.*\)_\)], [\2])]) dnl XC_M4_TR_SH_EX (expression, [extra]) dnl ------------------------------------------------- dnl Like XC_M4_TR_SH but transliterating characters dnl given in 'extra' argument to lowercase 'p'. For dnl example [*+], [*], and [+] are valid 'extra' args. AC_DEFUN([XC_M4_TR_SH_EX], [ifelse([$2], [], [XC_M4_TR_SH([$1])], [patsubst(XC_QPATSUBST(XC_QPATSUBST(XC_QUOTE($1), [[$2]], [p]), [[^a-zA-Z0-9_]], [_]), [\(_\(.*\)_\)], [\2])])]) dnl XC_SH_TR_CPP (expression) dnl ------------------------------------------------- dnl Shell execution time transliteration of 'expression' dnl argument, where all non-alfanumeric characters are dnl converted to the underscore '_' character and alnum dnl characters are converted to uppercase. dnl Normal shell expansion and substitution takes place dnl for given 'expression' at shell execution time before dnl transliteration is applied to it. AC_DEFUN([XC_SH_TR_CPP], [`echo "$1" | dnl sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | dnl sed 's/[[^A-Z0-9_]]/_/g'`]) dnl XC_SH_TR_CPP_EX (expression, [extra]) dnl ------------------------------------------------- dnl Like XC_SH_TR_CPP but transliterating characters dnl given in 'extra' argument to uppercase 'P'. For dnl example [*+], [*], and [+] are valid 'extra' args. AC_DEFUN([XC_SH_TR_CPP_EX], [ifelse([$2], [], [XC_SH_TR_CPP([$1])], [`echo "$1" | dnl sed 's/[[$2]]/P/g' | dnl sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | dnl sed 's/[[^A-Z0-9_]]/_/g'`])]) dnl XC_M4_TR_CPP (expression) dnl ------------------------------------------------- dnl m4 execution time transliteration of 'expression' dnl argument, where all non-alfanumeric characters are dnl converted to the underscore '_' character and alnum dnl characters are converted to uppercase. AC_DEFUN([XC_M4_TR_CPP], [patsubst(XC_QPATSUBST(XC_QTRANSLIT(XC_QUOTE($1), [abcdefghijklmnopqrstuvwxyz], [ABCDEFGHIJKLMNOPQRSTUVWXYZ]), [[^A-Z0-9_]], [_]), [\(_\(.*\)_\)], [\2])]) dnl XC_M4_TR_CPP_EX (expression, [extra]) dnl ------------------------------------------------- dnl Like XC_M4_TR_CPP but transliterating characters dnl given in 'extra' argument to uppercase 'P'. For dnl example [*+], [*], and [+] are valid 'extra' args. AC_DEFUN([XC_M4_TR_CPP_EX], [ifelse([$2], [], [XC_M4_TR_CPP([$1])], [patsubst(XC_QPATSUBST(XC_QTRANSLIT(XC_QPATSUBST(XC_QUOTE($1), [[$2]], [P]), [abcdefghijklmnopqrstuvwxyz], [ABCDEFGHIJKLMNOPQRSTUVWXYZ]), [[^A-Z0-9_]], [_]), [\(_\(.*\)_\)], [\2])])]) dnl XC_QUOTE (expression) dnl ------------------------------------------------- dnl Expands to quoted result of 'expression' expansion. AC_DEFUN([XC_QUOTE], [[$@]]) dnl XC_QPATSUBST (string, regexp[, repl]) dnl ------------------------------------------------- dnl Expands to quoted result of 'patsubst' expansion. AC_DEFUN([XC_QPATSUBST], [XC_QUOTE(patsubst([$1], [$2], [$3]))]) dnl XC_QTRANSLIT (string, chars, repl) dnl ------------------------------------------------- dnl Expands to quoted result of 'translit' expansion. AC_DEFUN([XC_QTRANSLIT], [XC_QUOTE(translit([$1], [$2], [$3]))]) davix-0.8.0/deps/curl/m4/xc-am-iface.m40000644000000000000000000001662714121063461016076 0ustar rootroot#--------------------------------------------------------------------------- # # xc-am-iface.m4 # # Copyright (c) 2013 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl _XC_AUTOMAKE_BODY dnl ------------------------------------------------- dnl Private macro. dnl dnl This macro performs embedding of automake initialization dnl code into configure script. When automake version 1.14 or dnl newer is used at configure script generation time, this dnl results in 'subdir-objects' automake option being used. dnl When using automake versions older than 1.14 this option dnl is not used when generating configure script. dnl dnl Existence of automake _AM_PROG_CC_C_O m4 private macro dnl is used to differentiate automake version 1.14 from older dnl ones which lack this macro. m4_define([_XC_AUTOMAKE_BODY], [dnl ## --------------------------------------- ## ## Start of automake initialization code ## ## --------------------------------------- ## m4_ifdef([_AM_PROG_CC_C_O], [ AM_INIT_AUTOMAKE([subdir-objects]) ],[ AM_INIT_AUTOMAKE ])dnl ## ------------------------------------- ## ## End of automake initialization code ## ## ------------------------------------- ## dnl m4_define([$0], [])[]dnl ]) dnl XC_AUTOMAKE dnl ------------------------------------------------- dnl Public macro. dnl dnl This macro embeds automake machinery into configure dnl script regardless of automake version used in order dnl to generate configure script. dnl dnl When using automake version 1.14 or newer, automake dnl initialization option 'subdir-objects' is used to dnl generate the configure script, otherwise this option dnl is not used. AC_DEFUN([XC_AUTOMAKE], [dnl AC_PREREQ([2.50])dnl dnl AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl dnl _XC_AUTOMAKE_BODY dnl m4_ifdef([AM_INIT_AUTOMAKE], [m4_undefine([AM_INIT_AUTOMAKE])])dnl dnl m4_define([$0], [])[]dnl ]) dnl _XC_AMEND_DISTCLEAN_BODY ([LIST-OF-SUBDIRS]) dnl ------------------------------------------------- dnl Private macro. dnl dnl This macro performs shell code embedding into dnl configure script in order to modify distclean dnl and maintainer-clean targets of makefiles which dnl are located in given list of subdirs. dnl dnl See XC_AMEND_DISTCLEAN comments for details. m4_define([_XC_AMEND_DISTCLEAN_BODY], [dnl ## ---------------------------------- ## ## Start of distclean amending code ## ## ---------------------------------- ## for xc_subdir in [$1] do if test ! -f "$xc_subdir/Makefile"; then echo "$xc_msg_err $xc_subdir/Makefile file not found. $xc_msg_abrt" >&2 exit 1 fi # Fetch dependency tracking file list from Makefile include lines. xc_inc_lines=`grep '^include .*(DEPDIR)' "$xc_subdir/Makefile" 2>/dev/null` xc_cnt_words=`echo "$xc_inc_lines" | wc -w | tr -d "$xc_space$xc_tab"` # --disable-dependency-tracking might have been used, consequently # there is nothing to amend without a dependency tracking file list. if test $xc_cnt_words -gt 0; then AC_MSG_NOTICE([amending $xc_subdir/Makefile]) # Build Makefile specific patch hunk. xc_p="$xc_subdir/xc_patch.tmp" xc_rm_depfiles=`echo "$xc_inc_lines" \ | $SED 's%include% -rm -f%' 2>/dev/null` xc_dep_subdirs=`echo "$xc_inc_lines" \ | $SED 's%include[[ ]][[ ]]*%%' 2>/dev/null \ | $SED 's%(DEPDIR)/.*%(DEPDIR)%' 2>/dev/null \ | sort | uniq` echo "$xc_rm_depfiles" >$xc_p for xc_dep_dir in $xc_dep_subdirs; do echo "${xc_tab}@xm_dep_cnt=\`ls $xc_dep_dir | wc -l 2>/dev/null\`; \\" >>$xc_p echo "${xc_tab}if test \$\$xm_dep_cnt -eq 0 && test -d $xc_dep_dir; then \\" >>$xc_p echo "${xc_tab} rm -rf $xc_dep_dir; \\" >>$xc_p echo "${xc_tab}fi" >>$xc_p done # Build Makefile patching sed scripts. xc_s1="$xc_subdir/xc_script_1.tmp" xc_s2="$xc_subdir/xc_script_2.tmp" xc_s3="$xc_subdir/xc_script_3.tmp" cat >$xc_s1 <<\_EOT /^distclean[[ ]]*:/,/^[[^ ]][[^ ]]*:/{ s/^.*(DEPDIR)/___xc_depdir_line___/ } /^maintainer-clean[[ ]]*:/,/^[[^ ]][[^ ]]*:/{ s/^.*(DEPDIR)/___xc_depdir_line___/ } _EOT cat >$xc_s2 <<\_EOT /___xc_depdir_line___$/{ N /___xc_depdir_line___$/D } _EOT cat >$xc_s3 <<_EOT /^___xc_depdir_line___/{ r $xc_p d } _EOT # Apply patch to Makefile and cleanup. $SED -f "$xc_s1" "$xc_subdir/Makefile" >"$xc_subdir/Makefile.tmp1" $SED -f "$xc_s2" "$xc_subdir/Makefile.tmp1" >"$xc_subdir/Makefile.tmp2" $SED -f "$xc_s3" "$xc_subdir/Makefile.tmp2" >"$xc_subdir/Makefile.tmp3" if test -f "$xc_subdir/Makefile.tmp3"; then mv -f "$xc_subdir/Makefile.tmp3" "$xc_subdir/Makefile" fi test -f "$xc_subdir/Makefile.tmp1" && rm -f "$xc_subdir/Makefile.tmp1" test -f "$xc_subdir/Makefile.tmp2" && rm -f "$xc_subdir/Makefile.tmp2" test -f "$xc_subdir/Makefile.tmp3" && rm -f "$xc_subdir/Makefile.tmp3" test -f "$xc_p" && rm -f "$xc_p" test -f "$xc_s1" && rm -f "$xc_s1" test -f "$xc_s2" && rm -f "$xc_s2" test -f "$xc_s3" && rm -f "$xc_s3" fi done ## -------------------------------- ## ## End of distclean amending code ## ## -------------------------------- ## dnl m4_define([$0], [])[]dnl ]) dnl XC_AMEND_DISTCLEAN ([LIST-OF-SUBDIRS]) dnl ------------------------------------------------- dnl Public macro. dnl dnl This macro embeds shell code into configure script dnl that amends, at configure runtime, the distclean dnl and maintainer-clean targets of Makefiles located dnl in all subdirs given in the mandatory white-space dnl separated list argument. dnl dnl Embedding only takes place when using automake 1.14 dnl or newer, otherwise amending code is not included dnl in generated configure script. dnl dnl distclean and maintainer-clean targets are modified dnl to avoid unconditional removal of dependency subdirs dnl which triggers distclean and maintainer-clean errors dnl when using automake 'subdir-objects' option along dnl with per-target objects and source files existing in dnl multiple subdirs used for different build targets. dnl dnl New behavior first removes each dependency tracking dnl file independently, and only removes each dependency dnl subdir when it finds out that it no longer holds any dnl dependency tracking file. dnl dnl When configure option --disable-dependency-tracking dnl is used no amending takes place given that there are dnl no dependency tracking files. AC_DEFUN([XC_AMEND_DISTCLEAN], [dnl AC_PREREQ([2.50])dnl dnl m4_ifdef([_AC_OUTPUT_MAIN_LOOP], [m4_provide_if([_AC_OUTPUT_MAIN_LOOP], [], [m4_fatal([call to AC_OUTPUT needed before $0])])])dnl dnl m4_if([$#], [1], [], [m4_fatal([$0: wrong number of arguments])])dnl m4_if([$1], [], [m4_fatal([$0: missing argument])])dnl dnl AC_REQUIRE([XC_CONFIGURE_PREAMBLE])dnl dnl m4_ifdef([_AM_PROG_CC_C_O], [ _XC_AMEND_DISTCLEAN_BODY([$1]) ])dnl m4_define([$0], [])[]dnl ]) davix-0.8.0/deps/curl/m4/ax_compile_check_sizeof.m40000644000000000000000000001033714121063461020650 0ustar rootroot# ============================================================================ # https://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html # ============================================================================ # # SYNOPSIS # # AX_COMPILE_CHECK_SIZEOF(TYPE [, HEADERS [, EXTRA_SIZES...]]) # # DESCRIPTION # # This macro checks for the size of TYPE using compile checks, not run # checks. You can supply extra HEADERS to look into. the check will cycle # through 1 2 4 8 16 and any EXTRA_SIZES the user supplies. If a match is # found, it will #define SIZEOF_`TYPE' to that value. Otherwise it will # emit a configure time error indicating the size of the type could not be # determined. # # The trick is that C will not allow duplicate case labels. While this is # valid C code: # # switch (0) case 0: case 1:; # # The following is not: # # switch (0) case 0: case 0:; # # Thus, the AC_TRY_COMPILE will fail if the currently tried size does not # match. # # Here is an example skeleton configure.in script, demonstrating the # macro's usage: # # AC_PROG_CC # AC_CHECK_HEADERS(stddef.h unistd.h) # AC_TYPE_SIZE_T # AC_CHECK_TYPE(ssize_t, int) # # headers='#ifdef HAVE_STDDEF_H # #include # #endif # #ifdef HAVE_UNISTD_H # #include # #endif # ' # # AX_COMPILE_CHECK_SIZEOF(char) # AX_COMPILE_CHECK_SIZEOF(short) # AX_COMPILE_CHECK_SIZEOF(int) # AX_COMPILE_CHECK_SIZEOF(long) # AX_COMPILE_CHECK_SIZEOF(unsigned char *) # AX_COMPILE_CHECK_SIZEOF(void *) # AX_COMPILE_CHECK_SIZEOF(size_t, $headers) # AX_COMPILE_CHECK_SIZEOF(ssize_t, $headers) # AX_COMPILE_CHECK_SIZEOF(ptrdiff_t, $headers) # AX_COMPILE_CHECK_SIZEOF(off_t, $headers) # # LICENSE # # Copyright (c) 2008 Kaveh Ghazi # Copyright (c) 2017 Reini Urban # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 7 AU_ALIAS([AC_COMPILE_CHECK_SIZEOF], [AX_COMPILE_CHECK_SIZEOF]) AC_DEFUN([AX_COMPILE_CHECK_SIZEOF], [changequote(<<, >>)dnl dnl The name to #define. define(<>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl dnl The cache variable name. define(<>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl changequote([, ])dnl AC_MSG_CHECKING(size of $1) AC_CACHE_VAL(AC_CV_NAME, [for ac_size in 4 8 1 2 16 $3 ; do # List sizes in rough order of prevalence. AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include $2 ]], [[switch (0) case 0: case (sizeof ($1) == $ac_size):;]])], [AC_CV_NAME=$ac_size]) if test x$AC_CV_NAME != x ; then break; fi done ]) if test x$AC_CV_NAME = x ; then AC_MSG_ERROR([cannot determine a size for $1]) fi AC_MSG_RESULT($AC_CV_NAME) AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1]) undefine([AC_TYPE_NAME])dnl undefine([AC_CV_NAME])dnl ]) davix-0.8.0/deps/curl/m4/zz60-xc-ovr.m40000644000000000000000000000437114121063461016042 0ustar rootroot#--------------------------------------------------------------------------- # # zz60-xc-ovr.m4 # # Copyright (c) 2013 Daniel Stenberg # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # #--------------------------------------------------------------------------- # serial 1 dnl The funny name of this file is intentional in order to make it dnl sort alphabetically after any libtool, autoconf or automake dnl provided .m4 macro file that might get copied into this same dnl subdirectory. This allows that macro (re)definitions from this dnl file may override those provided in other files. dnl Override an autoconf provided macro dnl ------------------------------------------------- dnl This macro overrides the one provided by autoconf dnl 2.58 or newer, and provides macro definition for dnl autoconf 2.57 or older which lack it. This allows dnl using libtool 2.2 or newer, which requires that dnl this macro is used in configure.ac, with autoconf dnl 2.57 or older. m4_ifdef([AC_CONFIG_MACRO_DIR], [dnl m4_undefine([AC_CONFIG_MACRO_DIR])dnl ]) m4_define([AC_CONFIG_MACRO_DIR],[]) dnl XC_OVR_ZZ60 dnl ------------------------------------------------- dnl Placing a call to this macro in configure.ac will dnl make macros in this file visible to other macros dnl used for same configure script, overriding those dnl provided elsewhere. AC_DEFUN([XC_OVR_ZZ60], [dnl AC_BEFORE([$0],[LT_INIT])dnl AC_BEFORE([$0],[AM_INIT_AUTOMAKE])dnl AC_BEFORE([$0],[AC_LIBTOOL_WIN32_DLL])dnl AC_BEFORE([$0],[AC_PROG_LIBTOOL])dnl dnl AC_BEFORE([$0],[AC_CONFIG_MACRO_DIR])dnl AC_BEFORE([$0],[AC_CONFIG_MACRO_DIRS])dnl ]) davix-0.8.0/deps/curl/packages/0000755000000000000000000000000014121063461015004 5ustar rootrootdavix-0.8.0/deps/curl/packages/DOS/0000755000000000000000000000000014121063461015431 5ustar rootrootdavix-0.8.0/deps/curl/packages/DOS/README0000644000000000000000000000073014121063461016311 0ustar rootrootGisle Vanem made curl build fine on DOS (and MingW) with djgpp, OpenSSL and his Watt-32 stack. 'make djgpp' in the root curl dir should build it fine. Note 1: djgpp 2.04 beta has a sscanf() bug so the URL parsing isn't done properly. Use djgpp 2.03 until they fix it. Note 2: Compile Watt-32 (and OpenSSL) with the same version of djgpp. Otherwise things go wrong because things like FS-extensions and errnos have been changed between releases. davix-0.8.0/deps/curl/packages/DOS/common.dj0000644000000000000000000000505314121063461017243 0ustar rootroot# # Common defines for curl (djgpp/Watt-32) # # Assumes you've unpacked curl with long-file names # I.e use "set LFN=y" before untaring on Win9x/XP. # Requires sed, yacc, rm and the usual stuff. # # Define TOPDIR before including this file. .SUFFIXES: .exe .y MAKEFILE = Makefile.dj OBJ_DIR = djgpp # # Find out if using a Unix-like shell or a DOS command interpreter # ifneq ($(findstring COMMAND.COM,$(SHELL)),COMMAND.COM) ifneq ($(findstring CMD.EXE,$(SHELL)),CMD.EXE) ifneq ($(findstring 4DOS.COM,$(SHELL)),4DOS.COM) IS_UNIX_SHELL = 1 endif endif endif # # Define shell dependent commands and vars # ifeq ($(IS_UNIX_SHELL),1) COPY = cp -f DELETE = rm -f MKDIR = mkdir RMDIR = rm -f -r DS = / else COPY = copy DELETE = del MKDIR = mkdir RMDIR = rmdir DS = \$(NOTHING) endif # # OpenSSL is available from www.openssl.org and builds okay # with djgpp/Watt-32. Set to 0 if you don't need https URLs # (reduces curl.exe with approx 700 kB) # USE_SSL = 0 # # Use zlib for contents encoding # USE_ZLIB = 0 # # Use libidn for international domain names # USE_IDNA = 0 # # Use Watt-32 IPv6 stack (only IPv6 name resolution working at the moment) # USE_IPV6 = 0 # # Use C-Ares resolver library # USE_ARES = 0 # # Enable debug code in libcurl/curl # USE_DEBUG = 0 # # Enable memory tracking code in libcurl/curl # USE_CURLDEBUG = 0 default: all # # Root directory for Waterloo tcp/ip etc. Change to suite. # WATT_ROOT should be set during Watt-32 install. # WATT32_ROOT = $(subst \,/,$(WATT_ROOT)) OPENSSL_ROOT = e:/net/openssl.099 ZLIB_ROOT = $(DJDIR)/contrib/zlib LIBIDN_ROOT = $(TOPDIR)/../IDN/libidn ARES_ROOT = $(TOPDIR)/ares CC = gcc YACC = bison -y CFLAGS = -g -O2 -I. -I$(TOPDIR)/include -I$(TOPDIR)/lib \ -I$(WATT32_ROOT)/inc -Wall -DHAVE_CONFIG_H ifeq ($(USE_SSL),1) CFLAGS += -DUSE_OPENSSL -I$(OPENSSL_ROOT) endif ifeq ($(USE_ZLIB),1) CFLAGS += -DUSE_ZLIB -I$(ZLIB_ROOT) endif ifeq ($(USE_IPV6),1) CFLAGS += -DENABLE_IPV6 endif ifeq ($(USE_ARES),1) CFLAGS += -DUSE_ARES -I$(ARES_ROOT) endif ifeq ($(USE_IDNA),1) CFLAGS += -DHAVE_LIBIDN -DHAVE_IDN_FREE_H -DHAVE_IDN_FREE -DHAVE_TLD_H \ -DHAVE_TLD_STRERROR -I$(LIBIDN_ROOT)/lib endif ifeq ($(USE_DEBUG),1) CFLAGS += -DDEBUG=1 -DDEBUGBUILD endif ifeq ($(USE_CURLDEBUG),1) CFLAGS += -DCURLDEBUG endif $(OBJ_DIR): $(MKDIR) $(OBJ_DIR) $(OBJ_DIR)/%.o: %.c $(CC) $(CFLAGS) -o $@ -c $< @echo depend: $(DEPEND_PREREQ) $(MAKEFILE) $(CC) -MM $(CFLAGS) $(CSOURCES) | \ sed -e 's/^\([a-zA-Z0-9_-]*\.o:\)/$$(OBJ_DIR)\/\1/' > depend.dj davix-0.8.0/deps/curl/packages/README0000644000000000000000000000217314121063461015667 0ustar rootroot _ _ ____ _ ___| | | | _ \| | / __| | | | |_) | | | (__| |_| | _ <| |___ \___|\___/|_| \_\_____| PACKAGES This directory and all its subdirectories are for special package information, template, scripts and docs. The files herein should be of use for those of you who want to package curl in a binary or source format using one of those custom formats. The hierarchy for these directories is something like this: packages/[OS]/[FORMAT]/ Currently, we have Win32 and Linux for [OS]. There might be different formats for the same OS so for Linux we have RPM as format. We might need to add some differentiation for CPU as well, as there is Linux-RPMs for several CPUs. However, it might not be necessary since the packaging should be pretty much the same no matter what CPU that is used. For each unique OS-FORMAT pair, there's a directory to "fill"! I'd like to see a single README with as much details as possible, and then I'd like some template files for the package process. davix-0.8.0/deps/curl/packages/Makefile.am0000644000000000000000000000131114121063461017034 0ustar rootrootSUBDIRS = vms EXTRA_DIST = README \ DOS/README \ DOS/common.dj \ OS400/README.OS400 \ OS400/ccsidcurl.c \ OS400/ccsidcurl.h \ OS400/curl.inc.in \ OS400/initscript.sh \ OS400/make-include.sh \ OS400/make-lib.sh \ OS400/make-src.sh \ OS400/make-tests.sh \ OS400/makefile.sh \ OS400/os400sys.c \ OS400/os400sys.h \ Symbian/bwins/libcurlu.def \ Symbian/eabi/libcurlu.def \ Symbian/group/bld.inf \ Symbian/group/curl.iby \ Symbian/group/curl.mmp \ Symbian/group/curl.pkg \ Symbian/group/libcurl.iby \ Symbian/group/libcurl.mmp \ Symbian/group/libcurl.pkg \ Symbian/readme.txt \ TPF/curl.mak \ TPF/maketpf.env_curl \ TPF/maketpf.env_curllib \ Android/Android.mk davix-0.8.0/deps/curl/packages/vms/0000755000000000000000000000000014121063461015611 5ustar rootrootdavix-0.8.0/deps/curl/packages/vms/Makefile.am0000644000000000000000000000155414121063461017652 0ustar rootrootEXTRA_DIST = \ backup_gnv_curl_src.com \ build_curl-config_script.com \ build_gnv_curl.com \ build_gnv_curl_pcsi_desc.com \ build_gnv_curl_pcsi_text.com \ build_gnv_curl_release_notes.com \ build_libcurl_pc.com \ build_vms.com \ clean_gnv_curl.com \ compare_curl_source.com \ config_h.com \ curl_crtl_init.c \ curl_gnv_build_steps.txt \ curl_release_note_start.txt \ curl_startup.com \ curlmsg.h \ curlmsg.msg \ curlmsg.sdl \ curlmsg_vms.h \ generate_config_vms_h_curl.com \ generate_vax_transfer.com \ gnv_conftest.c_first \ gnv_curl_configure.sh \ gnv_libcurl_symbols.opt \ gnv_link_curl.com \ macro32_exactcase.patch \ make_gnv_curl_install.sh \ make_pcsi_curl_kit_name.com \ pcsi_gnv_curl_file_list.txt \ pcsi_product_gnv_curl.com \ readme \ report_openssl_version.c \ setup_gnv_curl_build.com \ stage_curl_install.com \ vms_eco_level.h davix-0.8.0/deps/curl/packages/vms/curl_startup.com0000644000000000000000000000602714121063461021045 0ustar rootroot$! File: curl_Startup.com $! $! $Id$ $! $! Procedure to setup the CURL libraries for use by programs from the $! VMS SYSTARTUP*.COM procedure. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 15-Jun-2009 J. Malmberg $! 30-Jul-2013 J. Malmberg Update for Curl 7.32 $!======================================================================== $! $! $! GNV$GNU if needed. $ if f$trnlnm("GNV$GNU") .eqs. "" $ then $ x = f$trnlnm("GNU","LNM$SYSTEM_TABLE") $ if x .eqs. "" $ then $ write sys$output "GNV must be started up before this procedure. $ exit 44 $ endif $ define/system/exec/trans=conc GNV$GNU 'x' $ endif $! $! $ myproc = f$environment("procedure") $! $! ZLIB needed. $ if f$trnlnm("GNV$LIBZSHR32") .eqs. "" $ then $ zlib_startup = f$parse("gnv$zlib_startup.com;0", myproc,,,) $ if f$search(zlib_startup) .nes. "" $ then $ @'zlib_startup $ else $ write sys$output "ZLIB package not found and is required." $ exit 44 $ endif $ endif $! $! $ curl_ssl_libcrypto32 = "" $ curl_ssl_libssl32 = "" $ gnv_ssl_libcrypto32 = "gnv$gnu:[lib]ssl$libcrypto_shr32.exe" $ gnv_ssl_libssl32 = "gnv$gnu:[lib]ssl$libssl_shr32.exe" $ if f$search(gnv_ssl_libcrypto32) .nes. "" $ then $ curl_ssl_libcrypto32 = gnv_ssl_libcrypto32 $ curl_ssl_libssl32 = gnv_ssl_libssl32 $ else $ hp_ssl_libcrypto32 = "sys$share:ssl$libcrypto_shr32.exe" $ hp_ssl_libssl32 = "sys$share:ssl$libssl_shr32.exe" $ if f$search(hp_ssl_libcrypto32) .nes. "" $ then $ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 $ curl_ssl_libssl32 = hp_ssl_libssl32 $ else $ write sys$output "HP SSL package not found and is required." $ endif $ endif $! $ define/system/exec gnv$curl_ssl_libcryptoshr32 'curl_ssl_libcrypto32' $ define/system/exec gnv$curl_ssl_libsslshr32 'curl_ssl_libssl32' $! $! $! CURL setup $ define/system/exec gnv$libcurl gnv$gnu:[usr.lib]GNV$LIBCURL.EXE $ define/system/exec gnv$curl_include gnv$gnu:[usr.include.curl] $ if .not. f$file_attributes("gnv$libcurl", "known") $ then $ install ADD gnv$libcurl/OPEN/SHARE/HEADER $ else $ install REPLACE gnv$libcurl/OPEN/SHARE/HEADER $ endif $! $! $ curl_exe = "gnv$gnu:[usr.bin]gnv$curl.exe" $ if .not. f$file_attributes(curl_exe, "known") $ then $ install ADD 'curl_exe'/OPEN/SHARE/HEADER $ else $ install REPLACE 'curl_exe'/OPEN/SHARE/HEADER $ endif $! $all_exit: $ exit davix-0.8.0/deps/curl/packages/vms/generate_config_vms_h_curl.com0000644000000000000000000003346714121063461023666 0ustar rootroot$! File: GENERATE_CONFIG_H_CURL.COM $! $! $Id$ $! $! Curl like most open source products uses a variant of a config.h file. $! Depending on the curl version, this could be config.h or curl_config.h. $! $! For GNV based builds, the configure script is run and that produces $! a [curl_]config.h file. Configure scripts on VMS generally do not $! know how to do everything, so there is also a [-.lib]config-vms.h file $! that has VMS specific code that compensates for bugs in some of the $! VMS shared images. $! $! This generates a [curl_]config.h file and also a config_vms.h file, $! which is used to supplement that file. Note that the config_vms.h file $! and the [.lib]config-vms.h file do two different tasks and that the $! filenames are slightly different. $! $! $! Copyright 2013, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 06-Jan-2013 J. Malmberg $! $!========================================================================= $! $! Allow arguments to be grouped together with comma or separated by spaces $! Do no know if we will need more than 8. $args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," $args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," $! $! Provide lower case version to simplify parsing. $args_lower = f$edit(args, "LOWERCASE") $! $args_len = f$length(args) $! $if (f$getsyi("HW_MODEL") .lt. 1024) $then $ arch_name = "VAX" $else $ arch_name = "" $ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") $ if (arch_name .eqs. "") then arch_name = "UNK" $endif $! $! $nossl = 0 $nohpssl = 1 $hpssl = 0 $libidn = 0 $libssh2 = 0 $noldap = 0 $nozlib = 0 $nokerberos = 0 $! $! First check to see if SSL is disabled. $!--------------------------------------- $if f$locate(",nossl,", args_lower) .lt. args_len then nossl = 1 $if .not. nossl $then $! $! ssl$* logicals means HP ssl is present $!---------------------------------------- $ if f$trnlnm("ssl$root") .nes. "" $ then $ nohpssl = 0 $ hpssl = 1 $ endif $! $! HP defines OPENSSL as SSL$INCLUDE as a convenience for linking. $! As it is a violation of VMS standards for this to be provided, $! some sites may have removed it, but if present, assume that $! it indicates which OpenSSL to use. $!------------------------------------ $ openssl_lnm = f$trnlnm("OPENSSL") $ if (openssl_lnm .nes. "SYS$INCLUDE") $ then $! Non HP SSL is installed, default to use it. $ nohpssl = 1 $ hpssl = 0 $ endif $! $! Now check to see if hpssl has been specifically disabled $!---------------------------------------------------------- $ if f$locate(",nohpssl,", args_lower) .lt. args_len $ then $ nohpssl = 1 $ hpssl = 0 $ endif $! $! Finally check to see if hp ssl has been specifically included. $!---------------------------------------------------------------- $ if f$locate(",nohpssl,", args_lower) .lt. args_len $ then $ nohpssl = 1 $ hpssl = 0 $ endif $endif $! $! Did someone port LIBIDN in the GNV compatible way? $!------------------------------------------------------ $if f$trnlnm("GNV$LIBIDNSHR") .nes. "" $then $ write sys$output "NOTICE: A LIBIDN port has been detected." $ write sys$output " This port of curl for VMS has not been tested with it." $ if f$locate(",libidn,", args_lower) .lt. args_len $ then $ libidn = 1 $ endif $ if .not. libidn $ then $ write sys$output " LIBIDN support is not enabled." $ write sys$output "Run with the ""libidn"" parameter to attempt to use." $ else $ write sys$output " Untested LIBIDN support requested." $ endif $endif $! $! Did someone port LIBSSH2 in the GNV compatible way? $!------------------------------------------------------ $if f$trnlnm("GNV$LIBSSH2SHR") .nes. "" $then $ write sys$output "NOTICE: A LIBSSH2 port has been detected." $ write sys$output " This port of curl for VMS has not been tested with it." $ if f$locate(",libssh2,", args_lower) .lt. args_len $ then $ libssh2 = 1 $ endif $ if .not. libssh2 $ then $ write sys$output " LIBSSH2 support is not enabled." $ write sys$output "Run with the ""libssh2"" parameter to attempt to use." $ else $ write sys$output " Untested LIBSSH2 support requested." $ endif $endif $! $! LDAP suppressed? $if f$locate(",noldap,", args_lower) .lt. args_len $then $ noldap = 1 $endif $if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. "" $then $ noldap = 1 $endif $! $if f$locate(",nokerberos,", args_lower) .lt. args_len then nokerberos = 1 $if .not. nokerberos $then $! If kerberos is installed: sys$share:gss$rtl.exe exists. $ if f$search("sys$shsare:gss$rtl.exe") .eqs. "" $ then $ nokerberos = 1 $ endif $endif $! $! $! Is GNV compatible LIBZ present? $!------------------------------------------------------ $if f$trnlnm("GNV$LIBZSHR") .nes. "" $then $ if f$locate(",nozlib,", args_lower) .lt. args_len $ then $ nozlib = 1 $ endif $! if .not. nozlib $! then $! write sys$output " GNV$LIBZSHR support is enabled." $! else $! write sys$output " GNV$LIBZSHR support is disabled by nozlib." $! endif $else $ nozlib = 1 $endif $! $! $! Start the configuration file. $! Need to do a create and then an append to make the file have the $! typical file attributes of a VMS text file. $create sys$disk:[curl.lib]config_vms.h $open/append cvh sys$disk:[curl.lib]config_vms.h $! $! Write the defines to prevent multiple includes. $! These are probably not needed in this case, $! but are best practice to put on all header files. $write cvh "#ifndef __CONFIG_VMS_H__" $write cvh "#define __CONFIG_VMS_H__" $write cvh "" $write cvh "/* Define cpu-machine-OS */" $! $! Curl uses an OS macro to set the build environment. $!---------------------------------------------------- $! Now the DCL builds usually say xxx-HP-VMS and configure scripts $! may put DEC or COMPAQ or HP for the middle part. $! $write cvh "#if defined(__alpha)" $write cvh "#define OS ""ALPHA-HP-VMS""" $write cvh "#elif defined(__vax)" $write cvh "#define OS ""VAX-HP-VMS""" $write cvh "#elif defined(__ia64)" $write cvh "#define OS ""IA64-HP-VMS"" $write cvh "#else" $write cvh "#define OS ""UNKNOWN-HP-VMS"" $write cvh "#endif" $write cvh "" $! $! We are now setting this on the GNV build, so also do this $! for compatibility. $write cvh "/* Location of default ca path */" $write cvh "#define curl_ca_path ""gnv$curl_ca_path""" $! $! NTLM_WB_ENABLED requires fork() but configure does not know this $! We have to disable this in the configure command line. $! config_h.com finds that configure defaults to it being enabled so $! reports it. So we need to turn it off here. $! $write cvh "#ifdef NTLM_WB_ENABLED" $write cvh "#undef NTLM_WB_ENABLED" $write cvh "#endif" $! $! The config_h.com finds a bunch of default disable commands in $! configure and will incorrectly disable these options. The config_h.com $! is a generic procedure and it would break more things to try to fix it $! to special case it for curl. So we will fix it here. $! $! We do them all here, even the ones that config_h.com currently gets correct. $! $write cvh "#ifdef CURL_DISABLE_COOKIES" $write cvh "#undef CURL_DISABLE_COOKIES" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_CRYPTO_AUTH" $write cvh "#undef CURL_DISABLE_CRYPTO_AUTH" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_DICT" $write cvh "#undef CURL_DISABLE_DICT" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_FILE" $write cvh "#undef CURL_DISABLE_FILE" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_FTP" $write cvh "#undef CURL_DISABLE_FTP" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_GOPHER" $write cvh "#undef CURL_DISABLE_GOPHER" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_HTTP" $write cvh "#undef CURL_DISABLE_HTTP" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_IMAP" $write cvh "#undef CURL_DISABLE_IMAP" $write cvh "#endif" $if .not. noldap $then $ write cvh "#ifdef CURL_DISABLE_LDAP" $ write cvh "#undef CURL_DISABLE_LDAP" $ write cvh "#endif" $ if .not. nossl $ then $ write cvh "#ifdef CURL_DISABLE_LDAPS" $ write cvh "#undef CURL_DISABLE_LDAPS" $ write cvh "#endif" $ endif $endif $write cvh "#ifdef CURL_DISABLE_LIBCURL_OPTION" $write cvh "#undef CURL_DISABLE_LIBCURL_OPTION" $write cvh "#endif" $write cvh "#ifndef __VAX" $write cvh "#ifdef CURL_DISABLE_NTLM" $write cvh "#undef CURL_DISABLE_NTLM" $write cvh "#endif" $write cvh "#else" $! NTLM needs long long or int64 support, missing from DECC C. $write cvh "#ifdef __DECC $write cvh "#ifndef CURL_DISABLE_NTLM" $write cvh "#define CURL_DISABLE_NTLM 1" $write cvh "#endif" $write cvh "#endif" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_POP3" $write cvh "#undef CURL_DISABLE_POP3" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_PROXY" $write cvh "#undef CURL_DISABLE_PROXY" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_RTSP" $write cvh "#undef CURL_DISABLE_RTSP" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_SMTP" $write cvh "#undef CURL_DISABLE_SMTP" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_TELNET" $write cvh "#undef CURL_DISABLE_TELNET" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_TFTP" $write cvh "#undef CURL_DISABLE_TFTP" $write cvh "#endif" $write cvh "#ifdef CURL_DISABLE_POP3" $write cvh "#undef CURL_DISABLE_POP3" $write cvh "#endif" $if .not. nossl $then $ write cvh "#ifdef CURL_DISABLE_TLS_SRP" $ write cvh "#undef CURL_DISABLE_TLS_SRP" $ write cvh "#endif" $! $endif $write cvh "#ifdef CURL_DISABLE_VERBOSE_STRINGS" $write cvh "#undef CURL_DISABLE_VERBOSE_STRINGS" $write cvh "#endif" $! $! configure defaults to USE_*, a real configure on VMS chooses different. $write cvh "#ifdef USE_ARES" $write cvh "#undef USE_ARES" $write cvh "#endif" $write cvh "#ifdef USE_WOLFSSL" $write cvh "#undef USE_WOLFSSL" $write cvh "#endif" $write cvh "#ifdef USE_GNUTLS" $write cvh "#undef USE_GNUTLS" $write cvh "#endif" $write cvh "#ifdef USE_GNUTLS_NETTLE" $write cvh "#undef USE_GNUTLS_NETTLE" $write cvh "#endif" $write cvh "#ifdef USE_LIBRTMP" $write cvh "#undef USE_LIBRTMP" $write cvh "#endif" $write cvh "#ifdef USE_MANUAL" $write cvh "#undef USE_MANUAL" $write cvh "#endif" $write cvh "#ifdef USE_NGHTTP2" $write cvh "#undef USE_NGHTTP2" $write cvh "#endif" $write cvh "#ifdef USE_NSS" $write cvh "#undef USE_NSS" $write cvh "#endif" $write cvh "#ifdef USE_OPENLDAP" $write cvh "#undef USE_OPENLDAP" $write cvh "#endif" $write cvh "#ifdef USE_POLARSSL" $write cvh "#undef USE_POLARSSL" $write cvh "#endif" $write cvh "#ifdef USE_THREADS_POSIX" $write cvh "#undef USE_THREADS_POSIX" $write cvh "#endif" $write cvh "#ifdef USE_TLS_SRP" $write cvh "#undef USE_TLS_SRP" $write cvh "#endif" $write cvh "#ifdef USE_UNIX_SOCKETS" $write cvh "#undef USE_UNIX_SOCKETS" $write cvh "#endif" $! $write cvh "#ifndef HAVE_OLD_GSSMIT" $write cvh "#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE" $write cvh "#endif" $! $! $! Note: $! The CURL_EXTERN_SYMBOL is used for platforms that need the compiler $! to know about universal symbols. VMS does not need this support so $! we do not set it here. $! $! $! I can not figure out where the C compiler is finding the ALLOCA.H file $! in the text libraries, so CONFIG_H.COM can not find it either. $! Usually the header file name is the module name in the text library. $! It does not appear to hurt anything to not find header file, so we $! are not overriding it here. $! $! $! Check to see if OpenSSL is present. $!---------------------------------- $ssl_include = f$trnlnm("OPENSSL") $if ssl_include .eqs. "" $then $ ssl_include = f$trnlnm("ssl$include") $endif $if ssl_include .eqs. "" then nossl = 1 $! $if .not. nossl $then $! $ write cvh "#ifndef USE_OPENSSL" $ write cvh "#define USE_OPENSSL 1" $ write cvh "#endif" $ if arch_name .eqs. "VAX" $ then $ old_mes = f$environment("message") $ set message/notext/nofaci/noseve/noident $ search/output=nla0: ssl$include:*.h CONF_MFLAGS_IGNORE_MISSING_FILE $ status = $severity $ set message'old_mes' $ if status .nes. "1" $ then $ write cvh "#define VMS_OLD_SSL 1" $ endif $ endif $endif $! $! $! LibIDN not ported to VMS at this time. $! This is for international domain name support. $! Allow explicit experimentation. $if libidn $then $ write cvh "#define HAVE_IDNA_STRERROR 1" $ write cvh "#define HAVE_IDNA_FREE 1" $ write cvh "#define HAVE_IDNA_FREE_H 1" $ write cvh "#define HAVE_LIBIDN 1" $else $ write cvh "#ifdef HAVE_LIBIDN" $ write cvh "#undef HAVE_LIBIDN" $ write cvh "#endif" $endif $! $! $! LibSSH2 not ported to VMS at this time. $! Allow explicit experimentation. $if libssh2 $then $ write cvh "#define HAVE_LIBSSH2_EXIT 1" $ write cvh "#define HAVE_LIBSSH2_H 1" $ write cvh "#define HAVE_LIBSSH2_INIT 1" $ write cvh "#define HAVE_LIBSSH2_SCP_SEND64 1" $ write cvh "#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1" $ write cvh "#define HAVE_LIBSSH2_VERSION 1 $ write cvh "#define HAVE_LIBSSH2 1 $! $ write cvh "#ifndef USE_LIBSSH2" $ write cvh "#define USE_LIBSSH2 1" $ write cvh "#endif" $else $ write cvh "#ifdef USE_LIBSSH2" $ write cvh "#undef USE_LIBSSH2" $ write cvh "#endif" $endif $! $! $! $if .not. nozlib $then $ write cvh "#define HAVE_LIBZ 1" $ write cvh "#define HAVE_ZLIB_H 1" $endif $! $! $! Suppress a message in curl_gssapi.c compile. $write cvh "#pragma message disable notconstqual" $! $! Close out the file $! $write cvh "" $write cvh "#endif /* __CONFIG_VMS_H__ */" $close cvh $! $all_exit: $exit davix-0.8.0/deps/curl/packages/vms/report_openssl_version.c0000644000000000000000000000552514121063461022607 0ustar rootroot/* File: report_openssl_version.c * * $Id$ * * This file dynamically loads the openssl shared image to report the * version string. * * It will optionally place that version string in a DCL symbol. * * Usage: report_openssl_version [] * * Copyright 2013, John Malmberg * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include #include #include #include #include #include #include #include unsigned long LIB$SET_SYMBOL( const struct dsc$descriptor_s * symbol, const struct dsc$descriptor_s * value, const unsigned long * table_type); int main(int argc, char ** argv) { void * libptr; const char * (*ssl_version)(int t); const char * version; if (argc < 1) { puts("report_openssl_version filename"); exit(1); } libptr = dlopen(argv[1], 0); ssl_version = (const char * (*)(int))dlsym(libptr, "SSLeay_version"); if ((void *)ssl_version == NULL) { ssl_version = (const char * (*)(int))dlsym(libptr, "ssleay_version"); if ((void *)ssl_version == NULL) { ssl_version = (const char * (*)(int))dlsym(libptr, "SSLEAY_VERSION"); } } dlclose(libptr); if ((void *)ssl_version == NULL) { puts("Unable to lookup version of OpenSSL"); exit(1); } version = ssl_version(SSLEAY_VERSION); puts(version); /* Was a symbol argument given? */ if (argc > 1) { int status; struct dsc$descriptor_s symbol_dsc; struct dsc$descriptor_s value_dsc; const unsigned long table_type = LIB$K_CLI_LOCAL_SYM; symbol_dsc.dsc$a_pointer = argv[2]; symbol_dsc.dsc$w_length = strlen(argv[2]); symbol_dsc.dsc$b_dtype = DSC$K_DTYPE_T; symbol_dsc.dsc$b_class = DSC$K_CLASS_S; value_dsc.dsc$a_pointer = (char *)version; /* Cast ok */ value_dsc.dsc$w_length = strlen(version); value_dsc.dsc$b_dtype = DSC$K_DTYPE_T; value_dsc.dsc$b_class = DSC$K_CLASS_S; status = LIB$SET_SYMBOL(&symbol_dsc, &value_dsc, &table_type); if (!$VMS_STATUS_SUCCESS(status)) { exit(status); } } exit(0); } davix-0.8.0/deps/curl/packages/vms/build_gnv_curl_pcsi_desc.com0000644000000000000000000003651214121063461023332 0ustar rootroot$! File: Build_GNV_CURL_PCSI_DESC.COM $! $! $Id$ $! $! Build the *.pcsi$text file in the following sections: $! Required software dependencies. $! install/upgrade/postinstall steps. $! 1. Duplicate filenames need an alias procedure. (N/A for curl) $! 2. ODS-5 filenames need an alias procedure. (N/A for curl) $! 3. Special alias links for executables (curl. -> curl.exe) $! if a lot, then an alias procedure is needed. $! 4. Rename the files to lowercase. $! Move Release Notes to destination $! Source kit option $! Create directory lines $! Add file lines for curl. $! Add Link alias procedure file (N/A for curl) $! Add [.SYS$STARTUP]curl_startup file $! Add Release notes file. $! $! The file PCSI_GNV_CURL_FILE_LIST.TXT is read in to get the files other $! than the release notes file and the source backup file. $! $! The PCSI system can really only handle ODS-2 format filenames and $! assumes that there is only one source directory. It also assumes that $! all destination files with the same name come from the same source file. $! Fortunately CURL does not trip most of these issues, so those steps $! above are marked N/A. $! $! A rename action section is needed to make sure that the files are $! created in the GNV$GNU: in the correct case, and to create the alias $! link [usr.bin]curl. for [usr.bin]curl.exe. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 15-Jun-2009 J. Malmberg $! $!=========================================================================== $! $ kit_name = f$trnlnm("GNV_PCSI_KITNAME") $ if kit_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ producer = f$trnlnm("GNV_PCSI_PRODUCER") $ if producer .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ filename_base = f$trnlnm("GNV_PCSI_FILENAME_BASE") $ if filename_base .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $! $! $! Parse the kit name into components. $!--------------------------------------- $ producer = f$element(0, "-", kit_name) $ base = f$element(1, "-", kit_name) $ product = f$element(2, "-", kit_name) $ mmversion = f$element(3, "-", kit_name) $ majorver = f$extract(0, 3, mmversion) $ minorver = f$extract(3, 2, mmversion) $ updatepatch = f$element(4, "-", kit_name) $ if updatepatch .eqs. "-" then updatepatch = "" $! $! kit type of "D" means a daily build $ kit_type = f$edit(f$extract(0, 1, majorver), "upcase") $! $! $ product_line = "product ''producer' ''base' ''product'" $ if updatepatch .eqs. "" $ then $ product_name = " ''majorver'.''minorver'" $ else $ product_name = " ''majorver'.''minorver'-''updatepatch'" $ endif $ product_line = product_line + " ''product_name' full;" $!write sys$output product_line $! $! $! $! Create the file as a VMS text file. $!---------------------------------------- $ base_file = kit_name $ create 'base_file'.pcsi$desc $! $! $! Start building file. $!---------------------- $ open/append pdsc 'base_file'.pcsi$desc $! $ write pdsc product_line $! $! Required product dependencies. $!---------------------------------- $ vmsprd = "DEC" $ if base .eqs. "I64VMS" then vmsprd = "HP" $ vsiprd = "VSI" $! $ write pdsc " software ''vmsprd' ''base' VMS ;" $ arch_type = f$getsyi("ARCH_NAME") $ node_swvers = f$getsyi("node_swvers") $ vernum = f$extract(1, f$length(node_swvers), node_swvers) $ majver = f$element(0, ".", vernum) $ minverdash = f$element(1, ".", vernum) $ minver = f$element(0, "-", minverdash) $ dashver = f$element(1, "-", minverdash) $ if dashver .eqs. "-" then dashver = "" $ vmstag = majver + minver + dashver $ code = f$extract(0, 1, arch_type) $ arch_code = f$extract(0, 1, arch_type) $ line_out = - " if ((not ) and" + - " (not ));" $ write pdsc line_out $ write pdsc " error NEED_VMS''vmstag';" $ write pdsc " end if;" $! $write pdsc " software VMSPORTS ''base' ZLIB ;" $write pdsc - " if (not ) ;" $write pdsc " error NEED_ZLIB;" $write pdsc " end if;" $! $! $! $! install/upgrade/postinstall steps. $!----------------------------------- $! 1. Duplicate filenames need an alias procedure. (N/A for curl) $! 2. ODS-5 filenames need an alias procedure. (N/A for curl) $! 3. Special alias links for executables (curl. -> curl.exe) $! if a lot, then an alias procedure is needed. $! 4. Rename the files to lowercase. $! $! $! Alias links needed. $!------------------------- $ add_alias_lines = "" $ rem_alias_lines = "" $ line_out = "" $! $! Read through the file list to set up aliases and rename commands. $!--------------------------------------------------------------------- $ open/read flst pcsi_gnv_curl_file_list.txt $! $inst_alias_loop: $ read/end=inst_alias_loop_end flst line_in $ line_in = f$edit(line_in,"compress,trim,uncomment") $ if line_in .eqs. "" then goto inst_alias_loop $ pathname = f$element(0, " ", line_in) $ linkflag = f$element(1, " ", line_in) $ if linkflag .nes. "->" then goto inst_alias_write $! $ linktarget = f$element(2, " ", line_in) $ if kit_type .eqs. "D" $ then $ old_start = f$locate("[gnv.usr", pathname) $ if old_start .lt. f$length(pathname) $ then $ pathname = "[gnv.beta" + pathname - "[gnv.usr" $ linktarget = "[gnv.beta" + linktarget - "[gnv.usr" $ endif $ endif $ nlink = "pcsi$destination:" + pathname $ ntarg = "pcsi$destination:" + linktarget $ new_add_alias_line = - """if f$search(""""''nlink'"""") .eqs. """""""" then" + - " set file/enter=''nlink' ''ntarg'""" $ if add_alias_lines .nes. "" $ then $ add_alias_lines = add_alias_lines + "," + new_add_alias_line $ else $ add_alias_lines = new_add_alias_line $ endif $! $ new_rem_alias_line = - """if f$search(""""''nlink'"""") .nes. """""""" then" + - " set file/remove ''nlink';""" $ if rem_alias_lines .nes. "" $ then $ rem_alias_lines = rem_alias_lines + "," + new_rem_alias_line $ else $ rem_alias_lines = new_rem_alias_line $ endif $! $ goto inst_alias_loop $! $inst_alias_write: $! $! execute install / remove $ write pdsc " execute install (" $! add aliases $ i = 0 $ex_ins_loop: $ line = f$element(i, ",", add_alias_lines) $ i = i + 1 $ if line .eqs. "" then goto ex_ins_loop $ if line .eqs. "," then goto ex_ins_loop_end $ if line_out .nes. "" then write pdsc line_out,"," $ line_out = line $ goto ex_ins_loop $ex_ins_loop_end: $ write pdsc line_out $ line_out = "" $ write pdsc " )" $ write pdsc " remove (" $! remove aliases $ i = 0 $ex_rem_loop: $ line = f$element(i, ",", rem_alias_lines) $ i = i + 1 $ if line .eqs. "" then goto ex_rem_loop $ if line .eqs. "," then goto ex_rem_loop_end $ if line_out .nes. "" then write pdsc line_out,"," $ line_out = line $ goto ex_rem_loop $ex_rem_loop_end: $ write pdsc line_out $ line_out = "" $ write pdsc " ) ;" $! $! execute upgrade $ write pdsc " execute upgrade (" $ i = 0 $ex_upg_loop: $ line = f$element(i, ",", rem_alias_lines) $ i = i + 1 $ if line .eqs. "" then goto ex_upg_loop $ if line .eqs. "," then goto ex_upg_loop_end $ if line_out .nes. "" then write pdsc line_out,"," $ line_out = line $ goto ex_upg_loop $ex_upg_loop_end: $ write pdsc line_out $ line_out = "" $! remove aliases $ write pdsc " ) ;" $! $! execute postinstall $ write pdsc " execute postinstall (" $ if arch_code .nes. "V" $ then $ line_out = " ""set process/parse=extended""" $ endif $ i = 0 $ex_pins_loop: $ line = f$element(i, ",", add_alias_lines) $ i = i + 1 $ if line .eqs. "" then goto ex_pins_loop $ if line .eqs. "," then goto ex_pins_loop_end $ if line_out .nes. "" then write pdsc line_out,"," $ line_out = line $ goto ex_pins_loop $ex_pins_loop_end: $ if line_out .eqs. "" then line_out = " ""continue""" $! write pdsc line_out $! line_out = "" $! add aliases and follow with renames. $! $goto inst_dir $! $inst_dir_loop: $ read/end=inst_alias_loop_end flst line_in $ line_in = f$edit(line_in,"compress,trim,uncomment") $ if line_in .eqs. "" then goto inst_dir_loop $inst_dir: $ pathname = f$element(0, " ", line_in) $ if kit_type .eqs. "D" $ then $ if pathname .eqs. "[gnv]usr.dir" $ then $ pathname = "[gnv]beta.dir" $ else $ old_start = f$locate("[gnv.usr", pathname) $ if old_start .lt. f$length(pathname) $ then $ pathname = "[gnv.beta" + pathname - "[gnv.usr" $ endif $ endif $ endif $! $! Ignore the directory entries for now. $!----------------------------------------- $ filedir = f$parse(pathname,,,"DIRECTORY") $ if pathname .eqs. filedir then goto inst_dir_loop $! $! process .dir extensions for rename $! If this is not a directory then start processing files. $!------------------------- $ filetype = f$parse(pathname,,,"TYPE") $ filetype_u = f$edit(filetype, "upcase") $ filename = f$parse(pathname,,,"NAME") $ if filetype_u .nes. ".DIR" then goto inst_file $! $! process directory lines for rename. $!-------------------------------------- $ if line_out .nes. "" $ then $ write pdsc line_out,"," $ line_out = "" $ endif $ if arch_code .nes. "V" $ then $ if line_out .nes. "" then write pdsc line_out,"," $ line_out = " ""rename pcsi$destination:''pathname' ''filename'.DIR""" $ else $ if line_out .nes. "" then write pdsc line_out $ line_out = "" $ endif $ goto inst_dir_loop $! $! $! process file lines for rename $!--------------------------------- $inst_file_loop: $ read/end=inst_alias_loop_end flst line_in $ line_in = f$edit(line_in,"compress,trim,uncomment") $ if line_in .eqs. "" then goto inst_dir_loop $ pathname = f$element(0, " ", line_in) $ if kit_type .eqs. "D" $ then $ if pathname .eqs. "[gnv]usr.dir" $ then $ pathname = "[gnv]beta.dir" $ else $ old_start = f$locate("[gnv.usr", pathname) $ if old_start .lt. f$length(pathname) $ then $ pathname = "[gnv.beta" + pathname - "[gnv.usr" $ endif $ endif $ endif $! $! Filenames with $ in them are VMS special and do not need to be lowercase. $! -------------------------------------------------------------------------- $ if f$locate("$", pathname) .lt. f$length(pathname) then goto inst_file_loop $! $ filetype = f$parse(pathname,,,"TYPE") $ filename = f$parse(pathname,,,"NAME") + filetype $inst_file: $ if arch_code .nes. "V" $ then $ if line_out .nes. "" then write pdsc line_out,"," $ filetype = f$parse(pathname,,,"TYPE") $ filename = f$parse(pathname,,,"NAME") + filetype $ line_out = " ""rename pcsi$destination:''pathname' ''filename'""" $ else $ if line_out .nes. "" then write pdsc line_out $ line_out = "" $ endif $ goto inst_file_loop $! $inst_alias_loop_end: $! $write pdsc line_out $write pdsc " ) ;" $close flst $! $! Move Release Notes to destination $!------------------------------------- $write pdsc " information RELEASE_NOTES phase after ;" $! $! Source kit option $!--------------------- $write pdsc " option SOURCE default 0;" $write pdsc " directory ""[gnv.common_src]"" PROTECTION PUBLIC ;" $write pdsc - " file ""[gnv.common_src]''filename_base'_original_src.bck""" $write pdsc - " source [common_src]''filename_base'_original_src.bck ;" $if f$search("gnv$gnu:[vms_src]''filename_base'_vms_src.bck") .nes. "" $then $ write pdsc " directory ""[gnv.vms_src]"" PROTECTION PUBLIC ;" $ write pdsc " file ""[gnv.vms_src]''filename_base'_vms_src.bck""" $ write pdsc " source [vms_src]''filename_base'_vms_src.bck ;" $endif $write pdsc " end option;" $! $! $! Read through the file list again. $!---------------------------------- $open/read flst pcsi_gnv_curl_file_list.txt $! $! $! Create directory lines $!------------------------- $flst_dir_loop: $ read/end=flst_loop_end flst line_in $ line_in = f$edit(line_in,"compress,trim,uncomment") $ if line_in .eqs. "" then goto flst_dir_loop $! $ filename = f$element(0, " ", line_in) $ linkflag = f$element(1, " ", line_in) $ if linkflag .eqs. "->" then goto flst_dir_loop $! $! Ignore .dir extensions $!------------------------- $ filetype = f$edit(f$parse(filename,,,"TYPE"), "upcase") $ if filetype .eqs. ".DIR" then goto flst_dir_loop $! $ destname = filename $ if kit_type .eqs. "D" $ then $ old_start = f$locate("[gnv.usr", destname) $ if old_start .lt. f$length(destname) $ then $ destname = "[gnv.beta" + destname - "[gnv.usr" $ endif $ endif $! $! It should be just a directory then. $!------------------------------------- $ filedir = f$edit(f$parse(filename,,,"DIRECTORY"), "lowercase") $! If this is not a directory then start processing files. $!--------------------------------------------------------- $ if filename .nes. filedir then goto flst_file $! $ write pdsc " directory ""''destname'"" PROTECTION PUBLIC ;" $ goto flst_dir_loop $! $! $! Add file lines for curl. $!--------------------------- $flst_file_loop: $ read/end=flst_loop_end flst line_in $ line_in = f$edit(line_in,"compress,trim,uncomment") $ if line_in .eqs. "" then goto inst_file_loop $ filename = f$element(0, " ", line_in) $ destname = filename $ if kit_type .eqs. "D" $ then $ old_start = f$locate("[gnv.usr", destname) $ if old_start .lt. f$length(destname) $ then $ destname = "[gnv.beta" + destname - "[gnv.usr" $ endif $ endif $flst_file: $ srcfile = filename - "gnv." $ write pdsc " file ""''destname'"" " $ write pdsc " source ""''srcfile'"" ;" $ goto flst_file_loop $! $flst_loop_end: $ close flst $! $! Add Link alias procedure file (N/A for curl) $!------------------------------------------------ $! $! Add [.SYS$STARTUP]curl_startup file $!--------------------------------------- $ if kit_type .eqs. "D" $ then $ write pdsc " file ""[sys$startup]curl_daily_startup.com""" $ else $ write pdsc " file ""[sys$startup]curl_startup.com""" $ endif $ write pdsc " source [usr.lib]curl_startup.com ;" $! $! Add Release notes file. $!------------------------------ $ write pdsc - " file ""[SYSHLP]''filename_base'.release_notes"" release notes ;" $! $! Close the product file $!------------------------ $ write pdsc "end product;" $! $close pdsc $! $all_exit: $ exit davix-0.8.0/deps/curl/packages/vms/clean_gnv_curl.com0000644000000000000000000001650114121063461021275 0ustar rootroot$! File: clean_gnv_curl.COM $! $! $Id$ $! $! The GNV environment leaves behind some during the configure and build $! procedure that need to be cleaned up. $! $! The default is to remove all the left over stuff from running the $! configure script and to remove all intermediate binary files. $! $! This should be run with no parameters after the gnv_curl_configure.sh $! script is run. $! $! Parameter P1: REALCLEAN $! This removes all build products and brings the environment back to $! the point where the gnv_curl_configure.sh procedure needs to be run again. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 07-Jul-2009 J. Malmberg $!============================================================================ $! $! Save this so we can get back. $ default_dir = f$environment("default") $! $! $! Move to where the base directory is. $ set def [--] $! $! $ file = "sys$login:sh*." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "sys$login:make*." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]confdefs.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]conftest.dsf" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]conftest.lis" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]conftest.sym" $ if f$search(file) .nes. "" then delete 'file';* $! $! $ file = "lcl_root:[.conf*...]*.*" $ if f$search(file) .nes. "" then delete 'file';* $ file = "lcl_root:[]conf*.dir $ if f$search(file) .nes. "" then delete 'file';* $! $! $ file = "lcl_root:[.lib]*.out" $ if f$search(file) .nes. "" then delete 'file';* $ file = "lcl_root:[.lib]*.o" $ if f$search(file) .nes. "" then delete 'file';* $! $! $ file = "lcl_root:[.lib]*.lis" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]*.lis" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]cc_temp*." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]*.dsf" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]*.o" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]ar*." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]cc_temp*." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.lo" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.a" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.la" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.lai" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl-*_original_src.bck" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl_d-*_original_src.bck" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl-*_vms_src.bck" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl_d-*_vms_src.bck" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl-*.release_notes" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]curl_d-*.release_notes" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]*-curl-*.pcsi$desc" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]*-curl_d-*.pcsi$desc" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]*-curl-*.pcsi$text" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]*-curl_d-*.pcsi$text" $ if f$search(file) .nes. "" then delete 'file';* $! $!====================================================================== $! $ if p1 .nes. "REALCLEAN" then goto all_exit $! $ file = "lcl_root:[...]*.obj" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]Makefile." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]libtool." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.lis" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]POTFILES." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]libcurl.pc" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]curl-config." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]config.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]config.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]curl." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.tests]configurehelp.pm" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]config.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]curl_config.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]libcurl.vers" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]ca-bundle.h" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]config.log" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]config.status" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]conftest.dangle" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]CXX$DEMANGLER_DB." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[]stamp-h1." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]stamp-h1." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]stamp-h2." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]stamp-h3." $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.lib]*.a" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]*.spec" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]gnv$*.*" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[...]gnv*.opt" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]macro32_exactcase.exe" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]report_openssl_version.exe" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.packages.vms]hp_ssl_release_info.txt" $ if f$search(file) .nes. "" then delete 'file';* $! $ file = "lcl_root:[.src]curl.exe" $ if f$search(file) .nes. "" then delete 'file';* $! $all_exit: $! $! Put the default back. $!----------------------- $ set def 'default_dir' $! $ exit davix-0.8.0/deps/curl/packages/vms/curl_gnv_build_steps.txt0000644000000000000000000002621714121063461022576 0ustar rootrootFrom File: curl_gnv_build_steps.txt Copyright 2009, John Malmberg Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Currently building Curl using GNV takes longer than building Curl via DCL. The GNV procedure actually uses the same configure and makefiles that Unix builds use. Building CURL on OpenVMS using GNV requires GNV V2.1-2 or the updated images that are available via anonymous FTP at encompasserve.org in the gnv directory. It also requires the GNV Bash 4.2.45 kit as an update from the same location or from the sourceforge.net GNV project. The HP C 7.x compiler was used for building the GNV version. The source kits are provided in backup savesets inside of the PCSI install kit. Backup save sets are currently the only distribution medium that I can be sure is installed on a target VMS system that will correctly unpack files with extended character sets in them. You may need to adjust the ownership of the restored files, since /Interchange/noconvert was not available at the time that this document was written. [gnv.common_src]curl_*_original_src.bck is the original source of the curl kit as provided by the curl project. [gnv.vms_src]curl-*_vms_src.bck, if present, has the OpenVMS specific files that are used for building that are not yet in the curl source kits for that release distributed https://curl.haxx.se These backup savesets should be restored to different directory trees on an ODS-5 volume(s) which are referenced by concealed rooted logical names. SRC_ROOT: is for the source files common to all platforms. VMS_ROOT: is for the source files that are specific to OpenVMS. Note, you should create the VMS_ROOT: directory tree even if it is initially empty. This is where you should put edits if you are making changes. LCL_ROOT: is manually created to have the same base and sub-directories as SRC_ROOT: and VMS_ROOT: The logical name REF_ROOT: may be defined to be a search list for VMS_ROOT:,SRC_ROOT: The logical name PRJ_ROOT: is defined to be a search list for LCL_ROOT:,VMS_ROOT:,SRC_ROOT: For the make install process to work, it must have write access to the directories referenced by the GNU: logical name. In future releases of GNV, and with GNV Bash 4.3.30 installed, this name should be GNV$GNU: As directly updating those directories would probably be disruptive to other users of the system and require elevated privilege, this can be handled by creating a separate directory tree to install into which can be referenced by the concealed rooted logical name new_gnu:. A concealed logical name of OLD_GNU: can be set up to reference the real GNV directory tree. Then a local copy of the GNU/GNV$GNU logical names can be set up as a search list such as NEW_GNU:,OLD_GNU: The directory NEW_GNU:[usr] should be created. The make install phase should create all the other directories. The make install process may abort if curl is already because it can not uninstall the older version of curl because it does not have permission. The file stage_curl_install.com is used set up a new_gnu: directory tree for testing. The PCSI kitting procedure uses these files as input. These files do not create the directories in the VMS_ROOT and LCL_ROOT directory trees. You can create them with commands similar to: $ create/dir lcl_root:[curl]/prot=w:re $ copy src_root:[curl...]*.dir - lcl_root:[curl...]/prot=(o:rwed,w:re) $ create/dir vms_root:[curl]/prot=w:re $ copy src_root:[curl...]*.dir - vms_root:[curl...]/prot=(o:rwed,w:re) One of the ways with to protect the source from being modified is to have the directories under src_root: owned by a user or resource where the build username only has read access to it. Note to builders: GNV currently has a bug where configure scripts take a long time to run. Some of the configure steps take a while to complete, and on a 600 Mhz DS10 with IDE disks, taking an hour to run the CURL configure is normal. The following messages can be ignored and may get fixed in a future version of GNV. The GNV$*.OPT files are used to find the libraries as many have different names on VMS than on Unix. The Bash environment variable GNV_CC_QUALIFIERS can override all other settings for the C Compiler. ? cc: No support for switch -warnprotos ? cc: Unrecognized file toomanyargs ? cc: Warning: library "ssl" not found ? cc: Warning: library "crypto" not found ? cc: Warning: library "gssapi" not found ? cc: Warning: library "z" not found u unimplemented switch - ignored With these search lists set up and the properly, curl can be built by setting your default to PRJ_ROOT:[curl.packages.vms] and then issuing either the command: $ @pcsi_product_gnv_curl.com or $ @build_gnv_curl.com. The GNV configure procedure takes considerably longer than the DCL build procecure takes. It is of use for testing the GNV build environment, and may not have been kept up to date. The pcsi_product_gnv_curl.com needs the following logical names which are described in the section below: gnv_pcsi_producer gnv_pcsi_producer_full_name stage_root vms_root1 (Optional if vms_root is on a NFS volume) src_root1 (Optional if src_root is on a NFS volume) The pcsi_product_gnv_curl.com is described in more detail below. It does the following steps. The build steps are only done if they are needed to allow using either DCL or GNV based building procedures. $ @build_vms list $ @gnv_link_curl.com $ @build_gnv_curl_release_notes.com $ @backup_gnv_curl_src.com $ @build_gnv_curl_pcsi_desc.com $ @build_gnv_curl_pcsi_text.com $ @stage_curl_install remove $ @stage_curl_install Then builds the kit. The build_gnv_curl.com command procedure does the following: $ @setup_gnv_curl_build.com $ bash gnv_curl_configure.sh $ @clean_gnv_curl.com $ bash make_gnv_curl_install.sh $ @gnv_link_curl.com $ @stage_curl_install.com $ purge new_gnu:[*...]/log To clean up after a GNV based build to start over, the following commands are used: $ bash bash$ cd ../.. bash$ make clean bash$ exit Then run the @clean_gnv_curl.com. Use the parameter "realclean" if you are going to run the setup_gnv_curl_build.com and configure script again. $ @clean_gnv_curl.com realclean If new public symbols have been added, adjust the file gnv_libcurl_symbols.opt to have the new symbols. If the symbols are longer than 32 characters, then they will need to have the original be exact case CRC shortened and an alias in upper case with CRC shortened, in addition to having an exact case truncated alias and an uppercase truncated alias. The *.EXE files are not moved to the new_gnu: directory. After you are satisfied with the results of your build, you can move the files from new_gnu: to old_gnu: at your convenience. Building a PCSI kit for an architecture takes the following steps after making sure that you have a working build environment. Note that it requires manually creating two logical names as described below. It is intentional that they be manually set. This is for branding the PCSI kit based on who is making the kit. 1. Make sure that you have a staging directory that can be referenced by the path STAGE_ROOT:[KIT] 2. Edit the file curl_release_note_start.txt or other text files to reflect any changes. 3. Define the logical name GNV_PCSI_PRODUCER to indicate who is making the distribution. For making updates to an existing open source kit you may need to keep the producer the same. 4. Define the logical name GNV_PCSI_PRODUCER_FULL_NAME to be your full name or full name of your company. 5. If you are producing an update kit, then update the file vms_eco_level.h by changing the value for the VMS_ECO_LEVEL macro. This file is currently only used in building the PCSI kit. 6. Edit the file PCSI_GNV_CURL_FILE_LIST.TXT if there are new files added to the kit. These files should all be ODS-2 legal filenames and directories. A limitation of the PCSI kitting procedure is that when selecting files, it tends to ignore the directory structure and assumes that all files with the same name are the same file, so every file placed in the kit must have a unique name. Then a procedure needs to be added to the kit to create an alias link on install and remove the link on remove. Since at this time curl does not need this alias procedure, the steps to automatically build it are not included here. While newer versions of PCSI can support ODS-5 filenames, not all versions of PCSI on systems that have ODS-5 filenames do. So as a post install step, the PCSI kit built by these steps does a rename to the correct case as a post install step. 7. Edit the build_curl_pcsi_desc.com and build_curl_pcsi_text.com if you have changed the version of ZLIB that curl is built against. 8. Prepare to backup the files for building the kit. Note that if src_root: or vms_root: are NFS mounted disks, the step of backing up the source files will probably hang or fail. You need to copy the source files to VMS mounted disks and create logical names SRC_ROOT1 and VMS_ROOT1 to work around this to to reference local disks. Make sure src_root1:[000000] and vms_root1:[000000] exist and can be written to. The command procedure compare_curl_source can be used to check those directories and keep them up to date. @compare_curl_source.com SRCBCK UPDATE This compares the reference project source with the backup staging directory for it and updates with any changes. @compare_curl_source.com VMSBCK UPDATE This compares the VMS specific source with the backup staging directory for it and updates with any changes. Leave off "UPDATE" to just check without doing any changes. If you are not using NFS mounted disks and do not want to have a separate directory for staging the sources for backup make sure that src_root1: and vms_root1: do not exist. 9. Build the PCSI kit with @pcsi_product_gnv_curl.com The following message is normal: %PCSI-I-CANNOTVAL, cannot validate EAGLE$DQA0:[stage_root.][kit]VMSPORTS-AXPVMS-CURL-V0731-0-1.PCSI;1 -PCSI-I-NOTSIGNED, product kit is not signed and therefore has no manifest file This will result in an uncompressed kit for the target platform. On Alpha and Integrity, the pcsi_product_gnv_curl.com can be used with the "COMPRESSED" parameter to build both a compressed and uncompressed kits. Good Luck. davix-0.8.0/deps/curl/packages/vms/build_libcurl_pc.com0000644000000000000000000001262714121063461021616 0ustar rootroot$! File: build_libcurl_pc.com $! $! $Id:$ $! $! Build the libcurl.pc file from the libcurl.pc.in file $! $! Copyright 2013, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 15-Jun-2013 J. Malmberg $! $!=========================================================================== $! $! Skip this if the libcurl.pc already exists. $ if f$search("[--]libcurl.pc") .nes. "" then goto all_exit $! $! Need to know the kit type. $ kit_name = f$trnlnm("GNV_PCSI_KITNAME") $ if kit_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $! $! $! Parse the kit name into components. $!--------------------------------------- $ producer = f$element(0, "-", kit_name) $ base = f$element(1, "-", kit_name) $ product = f$element(2, "-", kit_name) $ mmversion = f$element(3, "-", kit_name) $ majorver = f$extract(0, 3, mmversion) $ minorver = f$extract(3, 2, mmversion) $ updatepatch = f$element(4, "-", kit_name) $ if updatepatch .eqs. "-" then updatepatch = "" $! $! kit type of "D" means a daily build $ kit_type = f$edit(f$extract(0, 1, majorver), "upcase") $! $ pc_file_in = "[--]libcurl^.pc.in" $! $ if f$search(pc_file_in) .eqs. "" $ then $ pc_file_in = "[--]libcurl.pc$5nin" $ if f$search(pc_file_in) .eqs. "" $ then $ pc_file_in = "[--]libcurl.pc_in" $ if f$search(pc_file_in) .eqs. "" $ then $ write sys$output "Can not find libcurl.pc.in." $ goto all_exit $ endif $ endif $ endif $! $ if (f$getsyi("HW_MODEL") .lt. 1024) $ then $ arch_name = "VAX" $ else $ arch_name = "" $ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") $ if (arch_name .eqs. "") then arch_name = "UNK" $ endif $! $! $ curl_version = "0.0.0" $ open/read vf [--.src]tool_version.h $version_loop: $ read vf/end=version_loop_end line_in $ if line_in .eqs. "" then goto version_loop $ key = f$element(0, " ", line_in) $ if key .nes. "#define" then goto version_loop $ name = f$element(1, " ", line_in) $ if name .eqs. "VERSION" $ then $ curl_version = f$element(2, " ", line_in) - """" - """" $ else $ goto version_loop $ endif $version_loop_end: $ close vf $! $! $ create [--]libcurl.pc $ open/append pco [--]libcurl.pc $ open/read pci 'pc_file_in' $pc_file_loop: $ read pci/end=pc_file_loop_end line_in $! $! blank lines $ if line_in .eqs. "" $ then $ write pco "" $ goto pc_file_loop $ endif $! $! comment lines $ key = f$extract(0, 1, line_in) $ if key .eqs. "#" $ then $ write pco line_in $ goto pc_file_loop $ endif $! $! Special handling for libs. $ if f$locate("Libs:", line_in) .eq. 0 $ then $ write pco "#",line_in $ goto pc_file_loop $ endif $! No substitution line $ line_in_len = f$length(line_in) $ if f$locate("@", line_in) .ge. line_in_len $ then $ write pco line_in $ goto pc_file_loop $ endif $! $ if f$locate("@prefix@", line_in) .lt line_in_len $ then $ if kit_type .nes. "D" $ then $ write pco "prefix=/usr" $ else $ write pco "prefix=/beta" $ endif $ goto pc_file_loop $ endif $ if f$locate("@exec_prefix@", line_in) .lt line_in_len $ then $ if kit_type .nes. "D" $ then $ write pco "exec_prefix=/usr" $ else $ write pco "exec_prefix=/beta" $ endif $ goto pc_file_loop $ endif $ if f$locate("@libdir@", line_in) .lt line_in_len $ then $ write pco "libdir=$(exec_prefix}/lib" $ goto pc_file_loop $ endif $ if f$locate("@includedir@", line_in) .lt line_in_len $ then $ write pco "includedir=$(prefix}/include" $ goto pc_file_loop $ endif $ if f$locate("@SUPPORT_PROTOCOLS@", line_in) .lt line_in_len $ then $ proto1 = "DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS" $ proto2 = " LDAP LDAPS POP3 POP3S RTSP SMTP SMTPS TELNET TFTP" $ proto = proto1 + proto2 $ write pco "supported_protocols=""" + proto + """" $ goto pc_file_loop $ endif $ if f$locate("@SUPPORT_FEATURES@", line_in) .lt line_in_len $ then $ if arch_name .eqs. "VAX" $ then $ write pco "supported_features=""SSL libz NTLM""" $ else $ write pco "supported_features=""SSL IPv6 libz NTLM""" $ endif $ goto pc_file_loop $ endif $ if f$locate("@CURLVERSION@", line_in) .lt line_in_len $ then $ write pco "Version: ''curl_version'" $ goto pc_file_loop $ endif $ if f$locate("@LIBCURL_LIBS@", line_in) .lt line_in_len $ then $ if arch_name .eqs. "VAX" $ then $ write pco "Libs.private: -lssl -lcrypto -lz" $ else $ write pco "Libs.private: -lssl -lcrypto -lgssapi -lz" $ endif $ goto pc_file_loop $ endif $ if f$locate("@CPPFLAG_CURL_STATICLIB@", line_in) .lt line_in_len $ then $ write pco "Cflags: -I${includedir} -DCURL_STATICLIB" $ goto pc_file_loop $ endif $! $pc_file_loop_end: $ close pco $ close pci $! $all_exit: $ exit davix-0.8.0/deps/curl/packages/vms/config_h.com0000644000000000000000000015722514121063461020101 0ustar rootroot$! File: config_h.com $! $! $Id: config_h.com,v 1.1.1.1 2012/12/02 19:25:21 wb8tyw Exp $ $! $! This procedure attempts to figure out how to build a config.h file $! for the current project. $! $! P1 specifies the config.h.in file or equivalent. If it is not specified $! then this procedure will search for several common names of the file. $! $! The CONFIGURE shell script will be examined for hints and a few symbols $! but most of the tests will not produce valid results on OpenVMS. Some $! will produce false positives and some will produce false negatives. $! $! It is easier to just read the config.h_in file and make up tests based $! on what is in it! $! $! This file will create an empty config_vms.h file if one does not exist. $! The config_vms.h is intended for manual edits to handle things that $! this procedure can not. $! $! The config_vms.h will be invoked by the resulting config.h file. $! $! This procedure knows about the DEC C RTL on the system it is on. $! Future versions may be handle the GNV, the OpenVMS porting library, $! and others. $! $! This procedure may not guess the options correctly for all architectures, $! and is a work in progress. $! $! Copyright 2011, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 15-Jan-2001 J. Malmberg Original $! 29-Apr-2001 J. Malmberg Also look for config.*in* in a [.include] $! subdirectory $! 30-Apr-2001 J. Malmberg Update for SAMBA checks $! 09-Apr-2005 J. Malmberg Update for RSYNC and large file. $! 29-Sep-2011 J. Malmberg Update for Bash 4.2 $! 01-Mar-2012 J. Malmberg Warn about getcwd(0,0) $! 21-Dec-2012 J. Malmberg Update for gawk $! 29-Dec-2012 J. Malmberg Update for curl $!============================================================================ $! $ss_normal = 1 $ss_abort = 44 $ss_control_y = 1556 $status = ss_normal $on control_y then goto control_y $on warning then goto general_error $!on warning then set ver $! $! Some information for writing timestamps to created files $!---------------------------------------------------------- $my_proc = f$environment("PROCEDURE") $my_proc_file = f$parse(my_proc,,,"NAME") + f$parse(my_proc,,,"TYPE") $tab[0,8] = 9 $datetime = f$element(0,".",f$cvtime(,"ABSOLUTE","DATETIME")) $username = f$edit(f$getjpi("","USERNAME"),"TRIM") $! $pid = f$getjpi("","PID") $tfile1 = "SYS$SCRATCH:config_h_temp1_''pid'.TEMP" $dchfile = "SYS$SCRATCH:config_h_decc_''pid'.TEMP" $starhfile = "SYS$SCRATCH:config_h_starlet_''pid'.TEMP" $configure_script = "SYS$SCRATCH:configure_script_''pid'.TEMP" $! $! Get the system type $!---------------------- $arch_type = f$getsyi("arch_type") $! $! Does config_vms.h exist? $!------------------------- $update_config_vms = 0 $file = f$search("sys$disk:[]config_vms.h") $if file .nes. "" $then $ write sys$output "Found existing custom file ''file'." $else $ update_config_vms = 1 $ write sys$output "Creating new sys$disk:[]config_vms.h for you." $ gosub write_config_vms $endif $! $! $! On some platforms, DCL search has problems with searching a file $! on a NFS mounted volume. So copy it to sys$scratch: $! $if f$search(configure_script) .nes. "" then delete 'configure_script';* $copy sys$disk:[]configure 'configure_script' $! $ssl_header_dir = "OPENSSL:" $if f$trnlnm("OPENSSL") .eqs. "" $then $ ssl_header_dir = "SSL$INCLUDE:" $endif $! $! $! Write out the header $!---------------------- $gosub write_config_h_header $! $! $! $! config.h.in could have at least five different names depending $! on how it was transferred to OpenVMS $!------------------------------------------------------------------ $if p1 .nes. "" $then $ cfile = p1 $else $ cfile = f$search("sys$disk:[]config.h.in") $ if cfile .eqs. "" $ then $ cfile = f$search("sys$disk:[]config.h_in") $ if cfile .eqs. "" $ then $ cfile = f$search("sys$disk:[]configh.in") $ if cfile .eqs. "" $ then $ cfile = f$search("sys$disk:[]config__2eh.in") $ if cfile .eqs. "" $ then $ cfile = f$search("sys$disk:[]config.h__2ein") $ endif $ endif $ endif $ endif $endif $if f$trnlnm("PRJ_INCLUDE") .nes. "" $then $ cfile = f$search("PRJ_INCLUDE:config.h.in") $ if cfile .eqs. "" $ then $ cfile = f$search("PRJ_INCLUDE:config.h_in") $ if cfile .eqs. "" $ then $ cfile = f$search("PRJ_INCLUDE:config__2eh.in") $ if cfile .eqs. "" $ then $ cfile = f$search("PRJ_INCLUDE:config__2eh.in") $ if cfile .eqs. "" $ then $ cfile = f$search("PRJ_INCLUDE:config.h__2ein") $ endif $ endif $ endif $ endif $endif $if cfile .eqs. "" $then $ write sys$output "Can not find sys$disk:config.h.in" $ line_out = "Looked for config.h.in, config.h_in, configh.in, " $ line_out = line_out + "config__2eh.in, config.h__2ein" $ write/symbol sys$output line_out $ if f$trnlnm("PRJ_INCLUDE") .nes. "" $ then $ write sys$output "Also looked in PRJ_INCLUDE: for these files." $ endif $! $ write tf "" $ write tf - " /* Could not find sys$disk:config.h.in */" $ write tf - " /* Looked also for config.h_in, configh.in, config__2eh.in, */" $ write tf - " /* config.h__2ein */" $ if f$trnlnm("PRJ_INCLUDE") .nes. "" $ then $ write tf - " /* Also looked in PRJ_INCLUDE: for these files. */" $ endif $ write tf - "/*--------------------------------------------------------------*/ $ write tf "" $ goto write_tail $endif $! $! $! Locate the DECC libraries in use $!----------------------------------- $decc_rtldef = f$parse("decc$rtldef","sys$library:.tlb;0") $decc_starletdef = f$parse("sys$starlet_c","sys$library:.tlb;0") $decc_shr = f$parse("decc$shr","sys$share:.exe;0") $! $! Dump the DECC header names into a file $!---------------------------------------- $if f$search(dchfile) .nes. "" then delete 'dchfile';* $if f$search(tfile1) .nes. "" then delete 'tfile1';* $define/user sys$output 'tfile1' $library/list 'decc_rtldef' $open/read/error=rtldef_loop1_end tf1 'tfile1' $open/write/error=rtldef_loop1_end tf2 'dchfile' $rtldef_loop1: $ read/end=rtldef_loop1_end tf1 line_in $ line_in = f$edit(line_in,"TRIM,COMPRESS") $ key1 = f$element(0," ",line_in) $ key2 = f$element(1," ",line_in) $ if key1 .eqs. " " .or. key1 .eqs. "" then goto rtldef_loop1 $ if key2 .nes. " " .and. key2 .nes. "" then goto rtldef_loop1 $ write tf2 "|",key1,"|" $ goto rtldef_loop1 $rtldef_loop1_end: $if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 $if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 $if f$search(tfile1) .nes. "" then delete 'tfile1';* $! $! Dump the STARLET header names into a file $!---------------------------------------- $if f$search(starhfile) .nes. "" then delete 'starhfile';* $if f$search(tfile1) .nes. "" then delete 'tfile1';* $define/user sys$output 'tfile1' $library/list 'decc_starletdef' $open/read/error=stardef_loop1_end tf1 'tfile1' $open/write/error=stardef_loop1_end tf2 'starhfile' $stardef_loop1: $ read/end=stardef_loop1_end tf1 line_in $ line_in = f$edit(line_in,"TRIM,COMPRESS") $ key1 = f$element(0," ",line_in) $ key2 = f$element(1," ",line_in) $ if key1 .eqs. " " .or. key1 .eqs. "" then goto stardef_loop1 $ if key2 .nes. " " .and. key2 .nes. "" then goto stardef_loop1 $ write tf2 "|",key1,"|" $ goto stardef_loop1 $stardef_loop1_end: $if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 $if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 $if f$search(tfile1) .nes. "" then delete 'tfile1';* $! $! $! Now calculate what should be in the file from reading $! config.h.in and CONFIGURE. $!--------------------------------------------------------------- $open/read inf 'cfile' $do_comment = 0 $if_block = 0 $cfgh_in_loop1: $!set nover $ read/end=cfgh_in_loop1_end inf line_in $ xline = f$edit(line_in,"TRIM,COMPRESS") $! $! Blank line handling $!--------------------- $ if xline .eqs. "" $ then $ write tf "" $ goto cfgh_in_loop1 $ endif $ xlen = f$length(xline) $ key = f$extract(0,2,xline) $! $! deal with comments by copying exactly $!----------------------------------------- $ if (do_comment .eq. 1) .or. (key .eqs. "/*") $ then $ do_comment = 1 $ write tf line_in $ key = f$extract(xlen - 2, 2, xline) $ if key .eqs. "*/" then do_comment = 0 $ goto cfgh_in_loop1 $ endif $! $! Some quick parsing $!---------------------- $ keyif = f$extract(0,3,xline) $ key1 = f$element(0," ",xline) $ key2 = f$element(1," ",xline) $ key2a = f$element(0,"_",key2) $ key2b = f$element(1,"_",key2) $ key2_len = f$length(key2) $ key2_h = f$extract(key2_len - 2, 2, key2) $ key2_t = f$extract(key2_len - 5, 5, key2) $ if key2_t .eqs. "_TYPE" then key2_h = "_T" $ key64 = 0 $ if f$locate("64", xline) .lt. xlen then key64 = 1 $! $!write sys$output "xline = ''xline'" $! $! Comment out this section of the ifblock $!----------------------------------------- $ if if_block .ge. 3 $ then $ write tf "/* ", xline, " */" $ if keyif .eqs. "#en" then if_block = 0 $ goto cfgh_in_loop1 $ endif $! $! Handle the end of an ifblock $!------------------------------- $ if keyif .eqs. "#en" $ then $ write tf xline $ if_block = 0 $ goto cfgh_in_loop1 $ endif $! $ if key1 .eqs. "#ifndef" $ then $! Manual check for _ALL_SOURCE on AIX error $!----------------------------------------------- $ if key2 .eqs. "_ALL_SOURCE" $ then $ write tf "/* ", xline, " */" $! $! Ignore the rest of the block $!-------------------------------------- $ if_block = 3 $ goto cfgh_in_loop1 $ endif $ endif $! $! $! Default action for an #if/#else/#endif $!------------------------------------------ $ if keyif .eqs. "#if" .or. keyif .eqs. "#el" $ then $ if_block = 1 $ write tf xline $ goto cfgh_in_loop1 $ endif $! $! $! Process "normal?" stuff $!--------------------------- $ if key1 .eqs. "#undef" $ then $ key2c = f$element(2, "_", key2) $ if (key2c .eqs. "_") .or. (key2c .eqs. "H") then key2c = "" $ key2d = f$element(3, "_", key2) $ if (key2d .eqs. "_") .or. (key2d .eqs. "H") then key2d = "" $ key2e = f$element(4, "_", key2) $ if (key2e .eqs. "_") .or. (key2e .eqs. "H") then key2e = "" $ if key2d .eqs. "T" $ then $ if key2e .eqs. "TYPE" $ then $ key2_h = "_T" $ key2d = "" $ endif $ endif $! $ double_under = 0 $! $! Process FCNTL directives $!------------------------------------- $ if (key2b .eqs. "FCNTL") .and. (key2c .eqs. "O") .and. - (key2d .eqs. "NONBLOCK") $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process GETADDRINFO directives $!------------------------------------- $ if key2 .eqs. "GETADDRINFO_THREADSAFE" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process IOCTL directives $!------------------------------------- $ if (key2b .eqs. "IOCTL") .and. (key2c .nes. "") $ then $ if (key2c .eqs. "FIONBIO") .or. (key2c .eqs. "SIOCGIFADDR") $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! $! Manual check for LL on $!----------------------------------------------- $ if key2 .eqs. "LL" $ then $ write tf "#ifndef __VAX $ write tf "#define HAVE_''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "bool_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' short" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "bits16_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' short" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "u_bits16_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' unsigned short" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "bits32_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "u_bits32_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' unsigned int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "intmax_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#ifdef __VAX" $ write tf "#define ''key2' long" $ write tf "#else" $ write tf "#define ''key2' long long" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "uintmax_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#ifdef __VAX" $ write tf "#define ''key2' unsigned long" $ write tf "#else" $ write tf "#define ''key2' unsigned long long" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "socklen_t" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "GETGROUPS_T" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' gid_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_SYS_SIGLIST" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_SYS_ERRLIST" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_STRUCT_DIRENT_D_INO" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_STRUCT_TIMEVAL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! ! The header files have this information, however $! ! The ioctl() call only works on sockets. $! if key2 .eqs. "FIONREAD_IN_SYS_IOCTL" $! then $! write tf "#ifndef ''key2'" $! write tf "#define ''key2' 1" $! write tf "#endif" $! goto cfgh_in_loop1 $! endif $! $! ! The header files have this information, however $! ! The ioctl() call only works on sockets. $! if key2 .eqs. "GWINSZ_IN_SYS_IOCTL" $! then $! write tf "#ifndef ''key2'" $! write tf "#define ''key2' 1" $! write tf "#endif" $! goto cfgh_in_loop1 $! endif $! $! ! The header files have this information, however $! ! The ioctl() call only works on sockets. $! if key2 .eqs. "STRUCT_WINSIZE_IN_SYS_IOCTL" $! then $! write tf "#ifndef ''key2'" $! write tf "#define ''key2' 0" $! write tf "#endif" $! goto cfgh_in_loop1 $! endif $! $ if key2 .eqs. "HAVE_STRUCT_TM_TM_ZONE" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_TM_ZONE" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_TIMEVAL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "WEXITSTATUS_OFFSET" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 2" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_GETPW_DECLS" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_CONFSTR" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_PRINTF" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_SBRK" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRSIGNAL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2a .eqs. "HAVE_DECL_STRTOLD" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOIMAX" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOLL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOUL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOULL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_STRTOUMAX" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "GETPGRP_VOID" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "NAMED_PIPES_MISSING" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "OPENDIR_NOT_ROBUST" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "PGRP_PIPE" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "CAN_REDEFINE_GETENV" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_PRINTF_A_FORMAT" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "CTYPE_NON_ASCII" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_LANGINFO_CODESET" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 0" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! This wants execve() to do this automagically to pass. $! if key2 .eqs. "HAVE_HASH_BANG_EXEC" $! then $! write tf "#ifndef ''key2'" $! write tf "#define ''key2' 1" $! write tf "#endif" $! goto cfgh_in_loop1 $! endif $! $ if key2 .eqs. "ICONV_CONST" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2'" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "VOID_SIGHANDLER" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_POSIX_SIGNALS" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "UNUSABLE_RT_SIGNALS" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2a .eqs. "HAVE_DECL_FPURGE" $ then $ write tf "#ifndef ''key2a'" $ write tf "#define ''key2a' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_DECL_SETREGID" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_POSIX_SIGSETJMP" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "HAVE_LIBDL" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2b .eqs. "RAND" .and. key2c .nes. "" .and. key2d .eqs. "" $ then $ if (key2c .eqs. "EGD") .or. - (key2c .eqs. "STATUS") .or. - (key2c .eqs. "SCREEN") $ then $ if f$search("''ssl_header_dir'rand.h") .nes. "" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ else $ write tf "/* #undef ''key2' */" $ endif $ endif $ endif $! $ if key2 .eqs. "STRCOLL_BROKEN" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if key2 .eqs. "DUP_BROKEN" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! This is for a test that getcwd(0,0) works. $! It does not on VMS. $!-------------------------- $ if key2 .eqs. "GETCWD_BROKEN" $ then $ write sys$output "" $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being tested for!" $ write sys$output - "-CONFIG_H-I-GETCWD, GETCWD(0,0) does not work on VMS." $ write sys$output - "-CONFIG_H-I-GETCWD2, Work around hack probably required." $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $ if update_config_vms $ then $ open/append tfcv sys$disk:[]config_vms.h $ write tfcv "" $ write tfcv - "/* Check config.h for use of ''key2' settings */" $ write tfcv "" $ close tfcv $ endif $ $ goto cfgh_in_loop1 $ endif $! $ if (key2a .eqs. "HAVE") .or. (key2a .eqs. "STAT") .or. - (key2 .eqs. "ENABLE_IPV6") .or. (key2b .eqs. "LDAP") $ then $! $! Process extra underscores $!------------------------------------ $ if f$locate("HAVE___", key2) .lt. key2_len $ then $ key2b = "__" + key2d $ key2d = "" $ double_under = 1 $ else $ if f$locate("HAVE__", key2) .lt. key2_len $ then $ key2b = "_" + key2c $ key2c = "" $ double_under = 1 $ endif $ endif $! $ if (key2_h .eqs. "_H") .or. (key2 .eqs. "ENABLE_IPV6") .or. - (key2b .eqs. "LDAP") $ then $! $! Looking for a header file $!--------------------------------------- $ headf = key2b $ if key2c .nes. "" then headf = headf + "_" + key2c $ if key2d .nes. "" then headf = headf + "_" + key2d $! $! (key2b .eqs. "READLINE") $! $! Some special parsing $!------------------------------------------ $ if (key2b .eqs. "SYS") .or. (key2b .eqs. "ARPA") .or. - (key2b .eqs. "NET") .or. (key2b .eqs. "NETINET") $ then $ if key2c .nes. "" $ then $ headf = key2c $ if key2d .nes. "" then headf = key2c + "_" + key2d $ endif $ endif $! $! And of course what's life with out some special cases $!-------------------------------------------------------------------- $ if key2 .eqs. "ENABLE_IPV6" $ then $ headf = "in6" $ endif $! $ if key2b .eqs. "LDAP" $ then $ if (key2 .eqs. "HAVE_LDAP_SSL") .or. - (key2 .eqs. "HAVE_LDAP_URL_PARSE") $ then $ headf = "ldap" $ endif $ endif $! $! $ if key2b .eqs. "FILE" $ then $ write sys$output "" $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being asked for!" $ write sys$output - "-CONFIG_H-I-FILE_OLD, file.h will not be configured as is obsolete!" $ write sys$output - "-CONFIG_H_I-FCNTL_NEW, "Expecting fcntl.h to be configured instead!" $ write sys$output - "-CONFIG_H_I-FCNTL_CHK, "Unable to verify at this time!" $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $! $ if update_config_vms $ then $ open/append tfcv sys$disk:[]config_vms.h $ write tfcv "" $ write tfcv - "/* Check config.h for use of fcntl.h instead of file.h */" $ write tfcv "" $ close tfcv $ endif $ endif $! $! Now look it up in the DEC C RTL $!--------------------------------------------- $ define/user sys$output nl: $ define/user sys$error nl: $ search/output=nl: 'dchfile' |'headf'|/exact $ if '$severity' .eq. 1 $ then $ if key64 then write tf "#ifndef __VAX" $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $if p2 .nes. "" then write sys$output "''dchfile' - #define ''key2' 1" $ write tf "#endif" $ if key64 then write tf "#endif" $set nover $ goto cfgh_in_loop1 $ endif $! $! $! Now look it up in the DEC C STARLET_C $!--------------------------------------------- $ define/user sys$output nl: $ define/user sys$error nl: $ search/output=nl: 'starhfile' |'headf'|/exact $ if '$severity' .eq. 1 $ then $ if key64 then write tf "#ifndef __VAX" $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $if p2 .nes. "" then write sys$output "''starfile' - #define ''key2' 1" $ write tf "#endif" $ if key64 then write tf "#endif" $set nover $ goto cfgh_in_loop1 $ endif $! $! Now look for OPENSSL headers $!--------------------------------------------------------- $ if key2b .eqs. "OPENSSL" $ then $ headf = headf - "OPENSSL_" $ header = f$search("''ssl_header_dir'''headf'.h") $ if header .nes. "" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $set nover $ goto cfgh_in_loop1 $ endif $ endif $! $! Now look for Kerberos $!------------------------------------------------------------ $ if key2b .eqs. "GSSAPI" $ then $ header_dir = "sys$sysroot:[kerberos.include]" $ headf = headf - "GSSAPI_" $ header = f$search("''header_dir'''headf'.h") $ if header .nes. "" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $set nover $ goto cfgh_in_loop1 $ endif $ endif $! $set nover $ else $! $! Looking for a routine or a symbol $!------------------------------------------------ $ if key2c .eqs. "MACRO" $ then $ if (key2b .eqs. "FILE") .or. (key2b .eqs. "DATE") - .or. (key2b .eqs. "LINE") .or. (key2b .eqs. "TIME") $ then $ write tf "#ifndef HAVE_''key2b'" $ write tf "#define HAVE_''key2b' 1" $ write tf "#endif" $ endif $ goto cfgh_in_loop1 $ endif $! $! Special false tests $!------------------------------------- $ if double_under $ then $ if key2b .eqs. "_FCNTL" .or. key2b .eqs. "__FCNTL" $ then $ write tf "/* #undef HAVE_''key2b' */" $ goto cfgh_in_loop1 $ endif $! $ if key2b .eqs. "_STAT" .or. key2b .eqs. "__STAT" $ then $ write tf "/* #undef HAVE_''key2b' */" $ goto cfgh_in_loop1 $ endif $! $ if key2b .eqs. "_READ" .or. key2b .eqs. "__READ" $ then $ write tf "/* #undef HAVE_''key2b' */" $ goto cfgh_in_loop1 $ endif $ endif $! $ keysym = key2b $ if key2c .nes. "" then keysym = keysym + "_" + key2c $ if key2d .nes. "" then keysym = keysym + "_" + key2d $ if key2e .nes. "" then keysym = keysym + "_" + key2e $! $! $! Stat structure members $!------------------------------------- $ if key2b .eqs. "STRUCT" $ then $ if key2c .eqs. "STAT" .and (key2d .nes. "") $ then $ key2b = key2b + "_" + key2c + "_" + key2d $ key2c = key2e $ key2d = "" $ key2e = "" $ endif $ endif $ if (key2b .eqs. "ST") .or. (key2b .eqs. "STRUCT_STAT_ST") $ then $ keysym = "ST" + "_" + key2c $ keysym = f$edit(keysym,"LOWERCASE") $ endif $ if key2a .eqs. "STAT" $ then $ if (f$locate("STATVFS", key2b) .eq. 0) .and. key2c .eqs. "" $ then $ keysym = f$edit(key2b, "LOWERCASE") $ endif $!$ if (key2b .eqs. "STATVFS" .or. key2b .eqs. "STATFS2" - $! .or. key2b .eqs. "STATFS3") .and. key2c .nes. "" $! $ if (key2b .eqs. "STATVFS") .and. key2c .nes. "" $ then $! Should really verify that the structure $! named by key2b actually exists first. $!------------------------------------------------------------ $! $! Statvfs structure members $!------------------------------------------------- $ keysym = "f_" + f$edit(key2c,"LOWERCASE") $ endif $ endif $! $! UTMPX structure members $!-------------------------------------- $ if key2b .eqs. "UT" .and. key2c .eqs. "UT" $ then $ keysym = "ut_" + f$edit(key2d,"LOWERCASE") $ endif $! $ if f$locate("MMAP",key2) .lt. key2_len $ then $ write sys$output "" $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being asked for!" $ write sys$output - "-CONFIG_H-I-MMAP, MMAP operations only work on STREAM and BINARY files!" $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $ if update_config_vms $ then $ open/append tfcv sys$disk:[]config_vms.h $ write tfcv "" $ write tfcv - "/* Check config.h for use of ''key2' settings */" $ write tfcv "" $ close tfcv $ endif $ endif $! $! $ if keysym .eqs. "CRYPT" $ then $ write sys$output "" $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being asked for!" $ write sys$output - "-CONFIG_H-I-CRYPT, CRYPT operations on the VMS SYSUAF may not work!" $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $ if update_config_vms $ then $ open/append tfcv sys$disk:[]config_vms.h $ write tfcv "" $ write tfcv - "/* Check config.h for use of ''keysym' */" $ write tfcv "" $ close tfcv $ endif $ endif $! $! $ if keysym .eqs. "EXECL" $ then $ write sys$output "" $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being asked for!" $ write sys$output - "-CONFIG_H-I-EXCEL, EXECL configured, Will probably not work." $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $ if update_config_vms $ then $ open/append tfcv sys$disk:[]config_vms.h $ write tfcv "" $ write tfcv - "/* Check config.h for use of ''keysym' */" $ write tfcv "" $ close tfcv $ endif $ endif $! $! $! Process if cpp supports ANSI-C stringizing '#' operator $!----------------------------------------------------------------------- $ if keysym .eqs. "STRINGIZE" $ then $ write tf "#ifndef HAVE_STRINGIZE" $ write tf "#define HAVE_STRINGSIZE 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "VOLATILE" $ then $ write tf "#ifndef HAVE_VOLATILE" $ write tf "#define HAVE_VOLATILE 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "ALLOCA" $ then $ write tf "#ifndef HAVE_ALLOCA" $ write tf "#define HAVE_ALLOCA 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "ERRNO_DECL" $ then $ write tf "#ifndef HAVE_ERRNO_DECL" $ write tf "#define HAVE_ERRNO_DECL 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "LONGLONG" $ then $ write tf "#ifndef __VAX" $ write tf "#pragma message disable longlongtype" $ write tf "#ifndef HAVE_LONGLONG" $ write tf "#define HAVE_LONGLONG 1" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! May need to test compiler version $!----------------------------------------------- $ if keysym .eqs. "LONG_LONG" $ then $ write tf "#ifndef __VAX" $ write tf "#pragma message disable longlongtype" $ write tf "#ifndef HAVE_LONG_LONG" $ write tf "#define HAVE_LONG_LONG 1" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! May need to test compiler version $!----------------------------------------------- $ if keysym .eqs. "UNSIGNED_LONG_LONG" $ then $ write tf "#ifndef __VAX" $ write tf "#pragma message disable longlongtype" $ write tf "#ifndef HAVE_UNSIGNED_LONG_LONG" $ write tf "#define HAVE_UNSIGNED_LONG_LONG 1" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! May need to test compiler version $!----------------------------------------------- $ if keysym .eqs. "UNSIGNED_LONG_LONG_INT" $ then $ write tf "#ifndef __VAX" $ write tf "#pragma message disable longlongtype" $ write tf "#ifndef HAVE_UNSIGNED_LONG_LONG_INT" $ write tf "#define HAVE_UNSIGNED_LONG_LONG_INT 1" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! May need to test compiler version $!----------------------------------------------- $ if keysym .eqs. "LONG_DOUBLE" $ then $ write tf "#ifndef __VAX" $ write tf "#pragma message disable longlongtype" $ write tf "#ifndef HAVE_LONG_DOUBLE" $ write tf "#define HAVE_LONG_DOUBLE 1" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "FCNTL_LOCK" $ then $ write sys$output - "%CONFIG_H-I-NONPORT, ''key2' being asked for! $ write sys$output - "-CONFIG_H-I-REVIEW, Manual Code review required!" $ goto cfgh_in_loop1 $ endif $! $! $! These libraries are provided by the DEC C RTL $!------------------------------------------------------------- $ if keysym .eqs. "LIBINET" .or. keysym .eqs. "LIBSOCKET" $ then $ write tf "#ifndef HAVE_''keysym'" $ write tf "#define HAVE_''keysym' 1" $if p2 .nes. "" then write sys$output "''decc_shr' #define ''keysym' 1" $ write tf "#endif $ goto cfgh_in_loop1 $ endif $! $ if keysym .eqs. "HERRNO" then keysym = "h_errno" $ if keysym .eqs. "UTIMBUF" then keysym = "utimbuf" $ if key2c .eqs. "STRUCT" $ then $ keysym = f$edit(key2d,"LOWERCASE") $ else $ if key2_h .eqs. "_T" $ then $ if key2_t .eqs. "_TYPE" $ then $ keysym = f$extract(0, key2_len - 5, key2) - "HAVE_" $ endif $ keysym = f$edit(keysym,"LOWERCASE") $ endif $ endif $! $! Check the DEC C RTL shared image first $!------------------------------------------------------ $ if f$search(tfile1) .nes. "" then delete 'tfile1';* $ define/user sys$output nl: $ define/user sys$error nl: $ search/format=nonull/out='tfile1' 'decc_shr' 'keysym' $ if '$severity' .eq. 1 $ then $! $! Not documented, but from observation $!------------------------------------------------------ $ define/user sys$output nl: $ define/user sys$error nl: $ if arch_type .eq. 3 $ then $ keyterm = "''keysym'" $ else $ if arch_type .eq. 2 $ then $ keyterm = "''keysym'" $ else $ keyterm = "''keysym'" $ endif $ endif $ search/out=nl: 'tfile1' - "$''keyterm'","$g''keyterm'","$__utc_''keyterm'",- "$__utctz_''keyterm'","$__bsd44_''keyterm'","$bsd_''keyterm'",- "$''keysym'decc$","$G''keysym'decc$","$GX''keyterm'" $ severity = '$severity' $! $! $! Of course the 64 bit stuff is different $!--------------------------------------------------------- $ if severity .ne. 1 .and. key64 $ then $ define/user sys$output nl: $ define/user sys$error nl: $ search/out=nl: 'tfile1' "$_''keyterm'" $! search/out 'tfile1' "$_''keyterm'" $ severity = '$severity' $ endif $! $! Unix compatibility routines $!--------------------------------------------- $ if severity .ne. 1 $ then $ define/user sys$output nl: $ define/user sys$error nl: $ search/out=nl: 'tfile1' - "$__unix_''keyterm'","$__vms_''keyterm'","$_posix_''keyterm'" $ severity = '$severity' $ endif $! $! Show the result of the search $!------------------------------------------------ $ if 'severity' .eq. 1 $ then $ if key64 then write tf "#ifndef __VAX" $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $if p2 .nes. "" then write sys$output "''decc_shr' #define ''key2' 1" $ write tf "#endif" $ if key64 then write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $ if f$search(tfile1) .nes. "" then delete 'tfile1';* $! $! Check the DECC Header files next $!---------------------------------------------- $ define/user sys$output nl: $ define/user sys$error nl: $ search/out=nl: 'decc_rtldef' - "''keysym';", "''keysym'[", "struct ''keysym'"/exact $ severity = '$severity' $ if severity .eq. 1 $ then $ if key64 then write tf "#ifndef __VAX" $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $if p2 .nes. "" then write sys$output "''decc_rtldef' #define ''key2' 1" $ write tf "#endif" $ if key64 then write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Check kerberos $!-------------------------------------------- $ if f$search("SYS$SYSROOT:[kerberos]include.dir") .nes. "" $ then $ test_mit = "SYS$SYSROOT:[kerberos.include]gssapi_krb5.h" $ if (key2 .eqs. "HAVE_GSSAPI") $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! This is really do we have the newer MIT Kerberos $!---------------------------------------------------------------------- $ if (key2 .eqs. "HAVE_GSSMIT") $ then $ if f$search(test_mit) .nes. "" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ else $ write tf "#ifdef ''key2'" $ write tf "#undef ''key2'" $ endif $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Older MIT looks like Heimdal $!------------------------------------------------ $ if (key2 .eqs. "HAVE_HEIMDAL") $ then $ if f$search(test_mit) .eqs. "" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' 1" $ else $ write tf "#ifdef ''key2'" $ write tf "#undef ''key2'" $ endif $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $ endif $ write tf "/* ", xline, " */" $ goto cfgh_in_loop1 $ endif $! $! $! Process SIZEOF directives found in SAMBA and others $!---------------------------------------------------------- $ if key2a .eqs. "SIZEOF" $ then $ if key2b .eqs. "INO" .and. key2_h .eqs. "_T" $ then $ write tf "#ifndef SIZEOF_INO_T" $ write tf "#if !__USING_STD_STAT $ write tf "#define SIZEOF_INO_T 6" $ write tf "#else $ write tf "#define SIZEOF_INO_T 8" $ write tf "#endif $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "INTMAX" .and. key2_h .eqs. "_T" $ then $ write tf "#ifndef SIZEOF_INTMAX_T" $ write tf "#ifdef __VAX" $ write tf "#define SIZEOF_INTMAX_T 4" $ write tf "#else" $ write tf "#define SIZEOF_INTMAX_T 8" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "OFF" .and. key2_h .eqs. "_T" $ then $ write tf "#ifndef SIZEOF_OFF_T" $ write tf "#if __USE_OFF64_T" $ write tf "#define SIZEOF_OFF_T 8" $ write tf "#else" $ write tf "#define SIZEOF_OFF_T 4" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "CHAR" .and. key2_h .eqs. "_P" $ then $ write tf "#ifndef SIZEOF_CHAR_P" $ write tf "#if __INITIAL_POINTER_SIZE == 64" $ write tf "#define SIZEOF_CHAR_P 8" $ write tf "#else" $ write tf "#define SIZEOF_CHAR_P 4" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "VOIDP" $ then $ write tf "#ifndef SIZEOF_VOIDP" $ write tf "#if __INITIAL_POINTER_SIZE == 64" $ write tf "#define SIZEOF_VOIDP 8" $ write tf "#else" $ write tf "#define SIZEOF_VOIDP 4" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "INT" $ then $ write tf "#ifndef SIZEOF_INT" $ write tf "#define SIZEOF_INT 4" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "SIZE" .and. key2_h .eqs. "_T" $ then $ write tf "#ifndef SIZEOF_SIZE_T" $ write tf "#define SIZEOF_SIZE_T 4" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "TIME" .and. key2_h .eqs. "_T" $ then $ write tf "#ifndef SIZEOF_TIME_T" $ write tf "#define SIZEOF_TIME_T 4" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "DOUBLE" $ then $ write tf "#ifndef SIZEOF_DOUBLE" $ write tf "#define SIZEOF_DOUBLE 8" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "LONG" $ then $ if key2c .eqs. "" $ then $ write tf "#ifndef SIZEOF_LONG" $ write tf "#define SIZEOF_LONG 4" $ write tf "#endif" $ else $ write tf "#ifndef SIZEOF_LONG_LONG" $ write tf "#ifndef __VAX" $ write tf "#define SIZEOF_LONG_LONG 8" $ write tf "#endif" $ write tf "#endif" $ endif $ goto cfgh_in_loop1 $ endif $ if key2b .eqs. "SHORT" $ then $ write tf "#ifndef SIZEOF_SHORT" $ write tf "#define SIZEOF_SHORT 2" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ write tf "/* ", xline, " */" $ goto cfgh_in_loop1 $ endif $! $! Process NEED directives $!------------------------------- $ if key2a .eqs. "NEED" $ then $ if key2b .eqs. "STRINGS" .and. key2_h .eqs. "_H" $ then $ write tf "#ifndef NEED_STRINGS_H" $ write tf "#define NEED_STRINGS_H 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ write tf "/* ", xline, " */" $ goto cfgh_in_loop1 $ endif $! $! Process GETHOSTNAME directives $!------------------------------------- $ if key2 .eqs. "GETHOSTNAME_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#ifdef _DECC_V4_SOURCE" $ write tf "#define ''key2' int" $ write tf "#else" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process GETNAMEINFO directives $!------------------------------------- $ if key2a .eqs. "GETNAMEINFO" $ then $ if key2 .eqs. "GETNAMEINFO_QUAL_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' const" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "GETNAMEINFO_TYPE_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' struct sockaddr *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "GETNAMEINFO_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "GETNAMEINFO_TYPE_ARG46" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "GETNAMEINFO_TYPE_ARG7" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! Process RECV directives $!------------------------------------- $ if key2a .eqs. "RECV" $ then $ if key2 .eqs. "RECV_TYPE_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECV_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' void *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECV_TYPE_ARG3" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECV_TYPE_ARG4" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECV_TYPE_RETV" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! $! Process RECVFROM directives $!------------------------------------- $ if key2a .eqs. "RECVFROM" $ then $ if key2 .eqs. "RECVFROM_QUAL_ARG5" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2'" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' void *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG3" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG4" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG5" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' struct sockaddr" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_ARG6" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' unsigned int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "RECVFROM_TYPE_RETV" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! Process SELECT directives $!------------------------------------- $ if key2a .eqs. "SELECT" $ then $ if key2 .eqs. "SELECT_QUAL_ARG5" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' const" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SELECT_TYPE_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SELECT_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' void *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SELECT_TYPE_ARG234" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' fd_set *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SELECT_TYPE_ARG5" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' struct timeval *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SELECT_TYPE_RETV" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! Process SEND directives $!------------------------------------- $ if key2a .eqs. "SEND" $ then $ if key2 .eqs. "SEND_QUAL_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' const" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SEND_TYPE_ARG1" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SEND_TYPE_ARG2" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' void *" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SEND_TYPE_ARG3" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' size_t" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SEND_TYPE_ARG4" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ if key2 .eqs. "SEND_TYPE_RETV" $ then $ write tf "#ifndef ''key2'" $ write tf "#define ''key2' int" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $ endif $! $! $! Process STATFS directives $!------------------------------- $! if key2a .eqs. "STATFS" $! then $! write tf "/* ", xline, " */" $! goto cfgh_in_loop1 $! endif $! $! Process inline directive $!------------------------------ $ if key2 .eqs. "inline" $ then $ write tf "#ifndef inline" $ write tf "#define inline __inline" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process restrict directive $!-------------------------------- $ if key2 .eqs. "restrict" $ then $ write tf "#ifndef restrict" $ write tf "#define restrict __restrict" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process RETSIGTYPE directive $!---------------------------------- $ if key2 .eqs. "RETSIGTYPE" $ then $ write tf "#ifndef RETSIGTYPE" $ write tf "#define RETSIGTYPE void" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process STDC_HEADERS (SAMBA!) $!--------------------------- $ if key2 .eqs. "STDC_HEADERS" $ then $ write tf "#ifndef STDC_HEADERS" $ write tf "#define STDC_HEADERS 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Process PROTOTYPES directive $!------------------------------------- $ if key2 .eqs. "PROTOTYPES" $ then $ write tf "#ifndef PROTOTYPES" $ write tf "#define PROTOTYPES 1" $ write tf "#endif" $ goto cfgh_in_loop1 $ endif $! $! Special for SEEKDIR_RETURNS_VOID $!--------------------------------------- $ if key2 .eqs. "SEEKDIR_RETURNS_VOID" $ then $ write tf "#ifndef SEEKDIR_RETURNS_VOID" $ write tf "#define SEEKDIR_RETURNS_VOID 1" $ write tf "#endif" $ endif $! $! Unknown - See if CONFIGURE can give a clue for this $!---------------------------------------------------------- $ pflag = 0 $ set_flag = 0 $! gproj_name = proj_name - "_VMS" - "-VMS" $ if f$search(tfile1) .nes. "" then delete 'tfile1';* $ define/user sys$output nl: $ define/user sys$error nl: $! if f$locate("FILE", key2) .lt. key2_len then pflag = 1 $! if f$locate("DIR", key2) .eq. key2_len - 3 then pflag = 1 $! if f$locate("PATH", key2) .eq. key2_len - 4 then pflag = 1 $! $ search/out='tfile1' 'configure_script' "''key2'="/exact $ search_sev = '$severity' $ if 'search_sev' .eq. 1 $ then $ open/read/err=unknown_cf_rd_error sf 'tfile1' $search_file_rd_loop: $ read/end=unknown_cf_rd_err sf line_in $ line_in = f$edit(line_in, "TRIM") $ skey1 = f$element(0,"=",line_in) $ if skey1 .eqs. key2 $ then $ skey2 = f$element(1,"=",line_in) $ skey2a = f$extract(0,2,skey2) $! $! $! We can not handle assignment to shell symbols. $! For now skip them. $!------------------------------------------------------------ $ if f$locate("$", skey2) .lt. f$length(skey2) $ then $ write tf "/* ", xline, " */" $ set_flag = 1 $ goto found_in_configure $ endif $! $! Keep these two cases separate to make it easier to add $! more future intelligence to this routine $!---------------------------------------------------------------------- $ if skey2a .eqs. """`" $ then $! if pflag .eq. 1 $! then $! write tf "#ifndef ''key2'" $! write tf "#define ",key2," """,gproj_name,"_",key2,"""" $! write tf "#endif" $! else $! Ignore this for now $!------------------------------------------ $ write tf "/* ", xline, " */" $! endif $ set_flag = 1 $ goto found_in_configure $ endif $ if skey2a .eqs. """$" $ then $! if pflag .eq. 1 $! then $! write tf "#ifndef ''key2'" $! write tf "#define ",key2," """,gproj_name,"_",key2,"""" $! write tf "#endif" $! else $! Ignore this for now $!------------------------------------------- $ write tf "/* ", xline, " */" $! endif $ set_flag = 1 $ goto found_in_configure $ endif $! $! Remove multiple layers of quotes if present $!---------------------------------------------------------- $ if f$extract(0, 1, skey2) .eqs. "'" $ then $ skey2 = skey2 - "'" - "'" - "'" - "'" $ endif $ if f$extract(0, 1, skey2) .eqs. """" $ then $ skey2 = skey2 - """" - """" - """" - """" $ endif $ write tf "#ifndef ''key2'" $ if skey2 .eqs. "" $ then $ write tf "#define ",key2 $ else $! Only quote non-numbers $!---------------------------------------- $ if f$string(skey2+0) .eqs. skey2 $ then $ write tf "#define ",key2," ",skey2 $ else $ write tf "#define ",key2," """,skey2,"""" $ endif $ endif $ write tf "#endif" $ set_flag = 1 $ else $ goto search_file_rd_loop $! if pflag .eq. 1 $! then $! write tf "#ifndef ''key2'" $! write tf "#define ",key2," """,gproj_name,"_",key2,"""" $! write tf "#endif" $! set_flag = 1 $! endif $ endif $found_in_configure: $unknown_cf_rd_err: $ if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. "" $ then $ close sf $ endif $ if f$search(tfile1) .nes. "" then delete 'tfile1';* $ if set_flag .eq. 1 then goto cfgh_in_loop1 $ endif $ endif $! $! $! $! If it falls through everything else, comment it out $!----------------------------------------------------- $ write tf "/* ", xline, " */" $ goto cfgh_in_loop1 $cfgh_in_loop1_end: $close inf $! $! $! Write out the tail $!-------------------- $write_tail: $gosub write_config_h_tail $! $! Exit and clean up $!-------------------- $general_error: $status = '$status' $all_exit: $set noon $if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. "" then close sf $if f$trnlnm("tf","lnm$process",,"SUPERVISOR") .nes. "" then close tf $if f$trnlnm("inf","lnm$process",,"SUPERVISOR") .nes. "" then close inf $if f$trnlnm("tf1","lnm$process",,"SUPERVISOR") .nes. "" then close tf1 $if f$trnlnm("tf2","lnm$process",,"SUPERVISOR") .nes. "" then close tf2 $if f$trnlnm("tfcv","lnm$process",,"SUPERVISOR") .nes. "" then close tfcv $if f$type(tfile1) .eqs. "STRING" $then $ if f$search(tfile1) .nes. "" then delete 'tfile1';* $endif $if f$type(dchfile) .eqs. "STRING" $then $ if f$search(dchfile) .nes. "" then delete 'dchfile';* $endif $if f$type(starhfile) .eqs. "STRING" $then $ if f$search(starhfile) .nes. "" then delete 'starhfile';* $endif $if f$type(configure_script) .eqs. "STRING" $then $ if f$search(configure_script) .nes. "" then delete 'configure_script';* $endif $exit 'status' $! $! $control_y: $ status = ss_control_y $ goto all_exit $! $! $! $! Gosub to write a new config_vms.h $!----------------------------------- $write_config_vms: $outfile = "sys$disk:[]config_vms.h" $create 'outfile' $open/append tf 'outfile' $write tf "/* File: config_vms.h" $write tf "**" $write tf "** This file contains the manual edits needed for porting" $!write tf "** the ''proj_name' package to OpenVMS. $write tf "**" $write tf "** Edit this file as needed. The procedure that automatically" $write tf "** generated this header stub will not overwrite or make any" $write tf "** changes to this file." $write tf "**" $write tf - "** ", datetime, tab, username, tab, "Generated by ''my_proc_file'" $write tf "**" $write tf - "**========================================================================*/" $write tf "" $close tf $return $! $! gosub to write out a documentation header for config.h $!---------------------------------------------------------------- $write_config_h_header: $outfile = "sys$disk:[]config.h" $create 'outfile' $open/append tf 'outfile' $write tf "#ifndef CONFIG_H" $write tf "#define CONFIG_H" $write tf "/* File: config.h" $write tf "**" $write tf - "** This file contains the options needed for porting " $write tf "** the project on a VMS system." $write tf "**" $write tf "** Try not to make any edits to this file, as it is" $write tf "** automagically generated." $write tf "**" $write tf "** Manual edits should be made to the config_vms.h file." $write tf "**" $write tf - "** ", datetime, tab, username, tab, "Generated by ''my_proc_file'" $write tf "**" $write tf - "**========================================================================*/" $write tf "" $write tf "#if (__CRTL_VER >= 70200000) && !defined (__VAX)" $write tf "#define _LARGEFILE 1" $write tf "#endif" $write tf "" $write tf "#ifndef __VAX" $write tf "#ifdef __CRTL_VER" $write tf "#if __CRTL_VER >= 80200000" $write tf "#define _USE_STD_STAT 1" $write tf "#endif" $write tf "#endif" $write tf "#endif" $write tf "" $! $write tf " /* Allow compiler builtins */" $write tf "/*-------------------------*/" $write tf "#ifdef __DECC_VER" $write tf "#include " $write tf "#endif" $! $write tf "" $return $! $! gosub to write out the tail for config.h and close it $!--------------------------------------------------------- $write_config_h_tail: $write tf "" $write tf " /* Include the hand customized settings */" $write tf "/*--------------------------------------*/" $write tf "#include ""config_vms.h""" $write tf "" $write tf "#endif /* CONFIG_H */" $close tf $return $! davix-0.8.0/deps/curl/packages/vms/curlmsg.sdl0000644000000000000000000001541514121063461017777 0ustar rootroot MODULE $CURDEF; /* /* This SDL File Generated by VAX-11 Message V04-00 on 3-SEP-2008 13:33:54.09 /* /* $ID: CURLMSG.MSG,V 1.7 2008-05-30 23:51:09 CURLVMS EXP $ /* /* THESE VMS ERROR CODES ARE GENERATED BY TAKING APART THE CURL.H /* FILE AND PUTTING ALL THE CURLE_* ENUM STUFF INTO THIS FILE, /* CURLMSG.MSG. AN .SDL FILE IS CREATED FROM THIS FILE WITH /* MESSAGE/SDL. THE .H FILE IS CREATED USING THE FREEWARE SDL TOOL /* AGAINST THE .SDL FILE WITH SDL/ALPHA/LANG=CC COMMAND. /* /* WITH THE EXCEPTION OF CURLE_OK, ALL OF THE MESSAGES ARE AT /* THE ERROR SEVERITY LEVEL. WITH THE EXCEPTION OF /* PEER_FAILED_VERIF, WHICH IS A SHORTENED FORM OF /* PEER_FAILED_VERIFICATION, THESE ARE THE SAME NAMES AS THE /* CURLE_ ONES IN INCLUDE/CURL.H. THE MESSAGE UTILITY MANUAL STATES /* "THE COMBINED LENGTH OF THE PREFIX AND THE MESSAGE SYMBOL NAME CANNOT /* EXCEED 31 CHARACTERS." WITH A PREFIX OF FIVE THAT LEAVES US WITH 26 /* FOR THE MESSAGE NAME. /* /* IF YOU UPDATE THIS FILE ALSO UPDATE CURLMSG_VMS.H SO THAT THEY ARE IN SYNC /* CONSTANT "FACILITY" EQUALS 3841 PREFIX "CURL" TAG "" ,"OK" EQUALS %X0F018009 PREFIX "CURL" TAG "" ,"UNSUPPORTED_PROTOCOL" EQUALS %X0F018012 PREFIX "CURL" TAG "" ,"FAILED_INIT" EQUALS %X0F01801A PREFIX "CURL" TAG "" ,"URL_MALFORMAT" EQUALS %X0F018022 PREFIX "CURL" TAG "" ,"OBSOLETE4" EQUALS %X0F01802A PREFIX "CURL" TAG "" ,"COULDNT_RESOLVE_PROXY" EQUALS %X0F018032 PREFIX "CURL" TAG "" ,"COULDNT_RESOLVE_HOST" EQUALS %X0F01803A PREFIX "CURL" TAG "" ,"COULDNT_CONNECT" EQUALS %X0F018042 PREFIX "CURL" TAG "" ,"WEIRD_SERVER_REPLY" EQUALS %X0F01804A PREFIX "CURL" TAG "" ,"FTP_WEIRD_SERVER_REPLY" EQUALS %X0F01804A PREFIX "CURL" TAG "" ,"FTP_ACCESS_DENIED" EQUALS %X0F018052 PREFIX "CURL" TAG "" ,"OBSOLETE10" EQUALS %X0F01805A PREFIX "CURL" TAG "" ,"FTP_WEIRD_PASS_REPLY" EQUALS %X0F018062 PREFIX "CURL" TAG "" ,"OBSOLETE12" EQUALS %X0F01806A PREFIX "CURL" TAG "" ,"FTP_WEIRD_PASV_REPLY" EQUALS %X0F018072 PREFIX "CURL" TAG "" ,"FTP_WEIRD_227_FORMAT" EQUALS %X0F01807A PREFIX "CURL" TAG "" ,"FTP_CANT_GET_HOST" EQUALS %X0F018082 PREFIX "CURL" TAG "" ,"OBSOLETE16" EQUALS %X0F01808A PREFIX "CURL" TAG "" ,"FTP_COULDNT_SET_TYPE" EQUALS %X0F018092 PREFIX "CURL" TAG "" ,"PARTIAL_FILE" EQUALS %X0F01809A PREFIX "CURL" TAG "" ,"FTP_COULDNT_RETR_FILE" EQUALS %X0F0180A2 PREFIX "CURL" TAG "" ,"OBSOLETE20" EQUALS %X0F0180AA PREFIX "CURL" TAG "" ,"QUOTE_ERROR" EQUALS %X0F0180B2 PREFIX "CURL" TAG "" ,"HTTP_RETURNED_ERROR" EQUALS %X0F0180BA PREFIX "CURL" TAG "" ,"WRITE_ERROR" EQUALS %X0F0180C2 PREFIX "CURL" TAG "" ,"OBSOLETE24" EQUALS %X0F0180CA PREFIX "CURL" TAG "" ,"UPLOAD_FAILED" EQUALS %X0F0180D2 PREFIX "CURL" TAG "" ,"READ_ERROR" EQUALS %X0F0180DA PREFIX "CURL" TAG "" ,"OUT_OF_MEMORY" EQUALS %X0F0180E2 PREFIX "CURL" TAG "" ,"OPERATION_TIMEOUTED" EQUALS %X0F0180EA PREFIX "CURL" TAG "" ,"OBSOLETE29" EQUALS %X0F0180F2 PREFIX "CURL" TAG "" ,"FTP_PORT_FAILED" EQUALS %X0F0180FA PREFIX "CURL" TAG "" ,"FTP_COULDNT_USE_REST" EQUALS %X0F018102 PREFIX "CURL" TAG "" ,"OBSOLETE32" EQUALS %X0F01810A PREFIX "CURL" TAG "" ,"RANGE_ERROR" EQUALS %X0F018112 PREFIX "CURL" TAG "" ,"HTTP_POST_ERROR" EQUALS %X0F01811A PREFIX "CURL" TAG "" ,"SSL_CONNECT_ERROR" EQUALS %X0F018122 PREFIX "CURL" TAG "" ,"BAD_DOWNLOAD_RESUME" EQUALS %X0F01812A PREFIX "CURL" TAG "" ,"FILE_COULDNT_READ_FILE" EQUALS %X0F018132 PREFIX "CURL" TAG "" ,"LDAP_CANNOT_BIND" EQUALS %X0F01813A PREFIX "CURL" TAG "" ,"LDAP_SEARCH_FAILED" EQUALS %X0F018142 PREFIX "CURL" TAG "" ,"OBSOLETE40" EQUALS %X0F01814A PREFIX "CURL" TAG "" ,"FUNCTION_NOT_FOUND" EQUALS %X0F018152 PREFIX "CURL" TAG "" ,"ABORTED_BY_CALLBACK" EQUALS %X0F01815A PREFIX "CURL" TAG "" ,"BAD_FUNCTION_ARGUMENT" EQUALS %X0F018162 PREFIX "CURL" TAG "" ,"OBSOLETE44" EQUALS %X0F01816A PREFIX "CURL" TAG "" ,"INTERFACE_FAILED" EQUALS %X0F018172 PREFIX "CURL" TAG "" ,"OBSOLETE46" EQUALS %X0F01817A PREFIX "CURL" TAG "" ,"TOO_MANY_REDIRECTS" EQUALS %X0F018182 PREFIX "CURL" TAG "" ,"UNKNOWN_TELNET_OPTION" EQUALS %X0F01818A PREFIX "CURL" TAG "" ,"TELNET_OPTION_SYNTAX" EQUALS %X0F018192 PREFIX "CURL" TAG "" ,"OBSOLETE50" EQUALS %X0F01819A PREFIX "CURL" TAG "" ,"PEER_FAILED_VERIF" EQUALS %X0F0181A2 PREFIX "CURL" TAG "" ,"GOT_NOTHING" EQUALS %X0F0181AA PREFIX "CURL" TAG "" ,"SSL_ENGINE_NOTFOUND" EQUALS %X0F0181B2 PREFIX "CURL" TAG "" ,"SSL_ENGINE_SETFAILED" EQUALS %X0F0181BA PREFIX "CURL" TAG "" ,"SEND_ERROR" EQUALS %X0F0181C2 PREFIX "CURL" TAG "" ,"RECV_ERROR" EQUALS %X0F0181CA PREFIX "CURL" TAG "" ,"OBSOLETE57" EQUALS %X0F0181D2 PREFIX "CURL" TAG "" ,"SSL_CERTPROBLEM" EQUALS %X0F0181DA PREFIX "CURL" TAG "" ,"SSL_CIPHER" EQUALS %X0F0181E2 PREFIX "CURL" TAG "" ,"SSL_CACERT" EQUALS %X0F0181EA PREFIX "CURL" TAG "" ,"BAD_CONTENT_ENCODING" EQUALS %X0F0181F2 PREFIX "CURL" TAG "" ,"LDAP_INVALID_URL" EQUALS %X0F0181FA PREFIX "CURL" TAG "" ,"FILESIZE_EXCEEDED" EQUALS %X0F018202 PREFIX "CURL" TAG "" ,"USE_SSL_FAILED" EQUALS %X0F01820A PREFIX "CURL" TAG "" ,"SEND_FAIL_REWIND" EQUALS %X0F018212 PREFIX "CURL" TAG "" ,"SSL_ENGINE_INITFAILED" EQUALS %X0F01821A PREFIX "CURL" TAG "" ,"LOGIN_DENIED" EQUALS %X0F018222 PREFIX "CURL" TAG "" ,"TFTP_NOTFOUND" EQUALS %X0F01822A PREFIX "CURL" TAG "" ,"TFTP_PERM" EQUALS %X0F018232 PREFIX "CURL" TAG "" ,"REMOTE_DISK_FULL" EQUALS %X0F01823A PREFIX "CURL" TAG "" ,"TFTP_ILLEGAL" EQUALS %X0F018242 PREFIX "CURL" TAG "" ,"TFTP_UNKNOWNID" EQUALS %X0F01824A PREFIX "CURL" TAG "" ,"REMOTE_FILE_EXISTS" EQUALS %X0F018252 PREFIX "CURL" TAG "" ,"TFTP_NOSUCHUSER" EQUALS %X0F01825A PREFIX "CURL" TAG "" ,"CONV_FAILED" EQUALS %X0F018262 PREFIX "CURL" TAG "" ,"CONV_REQD" EQUALS %X0F01826A PREFIX "CURL" TAG "" ,"SSL_CACERT_BADFILE" EQUALS %X0F018272 PREFIX "CURL" TAG "" ,"REMOTE_FILE_NOT_FOUND" EQUALS %X0F01827A PREFIX "CURL" TAG "" ,"SSH" EQUALS %X0F018282 PREFIX "CURL" TAG "" ,"SSL_SHUTDOWN_FAILED" EQUALS %X0F01828A PREFIX "CURL" TAG "" ,"AGAIN" EQUALS %X0F018292 PREFIX "CURL" TAG "" ,"SSL_CRL_BADFILE" EQUALS %X0F01829A PREFIX "CURL" TAG "" ,"SSL_ISSUER_ERROR" EQUALS %X0F0182A2 PREFIX "CURL" TAG "" ,"CURL_LAST" EQUALS %X0F0182AA PREFIX "CURL" TAG "" ; END_MODULE; davix-0.8.0/deps/curl/packages/vms/curl_crtl_init.c0000644000000000000000000002221014121063461020766 0ustar rootroot/* File: curl_crtl_init.c * * This file makes sure that the DECC Unix settings are correct for * the mode the program is run in. * * The CRTL has not been initialized at the time that these routines * are called, so many routines can not be called. * * This is a module that provides a LIB$INITIALIZE routine that * will turn on some CRTL features that are not enabled by default. * * The CRTL features can also be turned on via logical names, but that * impacts all programs and some aren't ready, willing, or able to handle * those settings. * * On VMS versions that are too old to use the feature setting API, this * module falls back to using logical names. * * Copyright 2013, John Malmberg * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* Unix headers */ #include #include /* VMS specific headers */ #include #include #include #pragma member_alignment save #pragma nomember_alignment longword #pragma message save #pragma message disable misalgndmem struct itmlst_3 { unsigned short int buflen; unsigned short int itmcode; void *bufadr; unsigned short int *retlen; }; #pragma message restore #pragma member_alignment restore #ifdef __VAX #define ENABLE "ENABLE" #define DISABLE "DISABLE" #else #define ENABLE TRUE #define DISABLE 0 int decc$feature_get_index (const char *name); int decc$feature_set_value (int index, int mode, int value); #endif int SYS$TRNLNM( const unsigned long * attr, const struct dsc$descriptor_s * table_dsc, struct dsc$descriptor_s * name_dsc, const unsigned char * acmode, const struct itmlst_3 * item_list); int SYS$CRELNM( const unsigned long * attr, const struct dsc$descriptor_s * table_dsc, const struct dsc$descriptor_s * name_dsc, const unsigned char * acmode, const struct itmlst_3 * item_list); /* Take all the fun out of simply looking up a logical name */ static int sys_trnlnm (const char * logname, char * value, int value_len) { const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV"); const unsigned long attr = LNM$M_CASE_BLIND; struct dsc$descriptor_s name_dsc; int status; unsigned short result; struct itmlst_3 itlst[2]; itlst[0].buflen = value_len; itlst[0].itmcode = LNM$_STRING; itlst[0].bufadr = value; itlst[0].retlen = &result; itlst[1].buflen = 0; itlst[1].itmcode = 0; name_dsc.dsc$w_length = strlen(logname); name_dsc.dsc$a_pointer = (char *)logname; name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; name_dsc.dsc$b_class = DSC$K_CLASS_S; status = SYS$TRNLNM(&attr, &table_dsc, &name_dsc, 0, itlst); if ($VMS_STATUS_SUCCESS(status)) { /* Null terminate and return the string */ /*--------------------------------------*/ value[result] = '\0'; } return status; } /* How to simply create a logical name */ static int sys_crelnm (const char * logname, const char * value) { int ret_val; const char * proc_table = "LNM$PROCESS_TABLE"; struct dsc$descriptor_s proc_table_dsc; struct dsc$descriptor_s logname_dsc; struct itmlst_3 item_list[2]; proc_table_dsc.dsc$a_pointer = (char *) proc_table; proc_table_dsc.dsc$w_length = strlen(proc_table); proc_table_dsc.dsc$b_dtype = DSC$K_DTYPE_T; proc_table_dsc.dsc$b_class = DSC$K_CLASS_S; logname_dsc.dsc$a_pointer = (char *) logname; logname_dsc.dsc$w_length = strlen(logname); logname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; logname_dsc.dsc$b_class = DSC$K_CLASS_S; item_list[0].buflen = strlen(value); item_list[0].itmcode = LNM$_STRING; item_list[0].bufadr = (char *)value; item_list[0].retlen = NULL; item_list[1].buflen = 0; item_list[1].itmcode = 0; ret_val = SYS$CRELNM(NULL, &proc_table_dsc, &logname_dsc, NULL, item_list); return ret_val; } /* Start of DECC RTL Feature handling */ /* ** Sets default value for a feature */ #ifdef __VAX static void set_feature_default(const char *name, const char *value) { sys_crelnm(name, value); } #else static void set_feature_default(const char *name, int value) { int index; index = decc$feature_get_index(name); if (index > 0) decc$feature_set_value (index, 0, value); } #endif static void set_features(void) { int status; char unix_shell_name[255]; int use_unix_settings = 1; status = sys_trnlnm("GNV$UNIX_SHELL", unix_shell_name, sizeof unix_shell_name -1); if (!$VMS_STATUS_SUCCESS(status)) { use_unix_settings = 0; } /* ACCESS should check ACLs or it is lying. */ set_feature_default("DECC$ACL_ACCESS_CHECK", ENABLE); /* We always want the new parse style */ set_feature_default ("DECC$ARGV_PARSE_STYLE" , ENABLE); /* Unless we are in POSIX compliant mode, we want the old POSIX root * enabled. */ set_feature_default("DECC$DISABLE_POSIX_ROOT", DISABLE); /* EFS charset, means UTF-8 support */ /* VTF-7 support is controlled by a feature setting called UTF8 */ set_feature_default ("DECC$EFS_CHARSET", ENABLE); set_feature_default ("DECC$EFS_CASE_PRESERVE", ENABLE); /* Support timestamps when available */ set_feature_default ("DECC$EFS_FILE_TIMESTAMPS", ENABLE); /* Cache environment variables - performance improvements */ set_feature_default ("DECC$ENABLE_GETENV_CACHE", ENABLE); /* Start out with new file attribute inheritance */ #ifdef __VAX set_feature_default ("DECC$EXEC_FILEATTR_INHERITANCE", "2"); #else set_feature_default ("DECC$EXEC_FILEATTR_INHERITANCE", 2); #endif /* Don't display trailing dot after files without type */ set_feature_default ("DECC$READDIR_DROPDOTNOTYPE", ENABLE); /* For standard output channels buffer output until terminator */ /* Gets rid of output logs with single character lines in them. */ set_feature_default ("DECC$STDIO_CTX_EOL", ENABLE); /* Fix mv aa.bb aa */ set_feature_default ("DECC$RENAME_NO_INHERIT", ENABLE); if (use_unix_settings) { /* POSIX requires that open files be able to be removed */ set_feature_default ("DECC$ALLOW_REMOVE_OPEN_FILES", ENABLE); /* Default to outputting Unix filenames in VMS routines */ set_feature_default ("DECC$FILENAME_UNIX_ONLY", ENABLE); /* FILENAME_UNIX_ONLY Implicitly sets */ /* decc$disable_to_vms_logname_translation */ set_feature_default ("DECC$FILE_PERMISSION_UNIX", ENABLE); set_feature_default ("DECC$FILE_SHARING", ENABLE); set_feature_default ("DECC$FILE_OWNER_UNIX", ENABLE); set_feature_default ("DECC$POSIX_SEEK_STREAM_FILE", ENABLE); } else { set_feature_default("DECC$FILENAME_UNIX_REPORT", ENABLE); } /* When reporting Unix filenames, glob the same way */ set_feature_default ("DECC$GLOB_UNIX_STYLE", ENABLE); /* The VMS version numbers on Unix filenames is incompatible with most */ /* ported packages. */ set_feature_default("DECC$FILENAME_UNIX_NO_VERSION", ENABLE); /* The VMS version numbers on Unix filenames is incompatible with most */ /* ported packages. */ set_feature_default("DECC$UNIX_PATH_BEFORE_LOGNAME", ENABLE); /* Set strtol to proper behavior */ set_feature_default("DECC$STRTOL_ERANGE", ENABLE); /* Commented here to prevent future bugs: A program or user should */ /* never ever enable DECC$POSIX_STYLE_UID. */ /* It will probably break all code that accesses UIDs */ /* do_not_set_default ("DECC$POSIX_STYLE_UID", TRUE); */ } /* Some boilerplate to force this to be a proper LIB$INITIALIZE section */ #pragma nostandard #pragma extern_model save #ifdef __VAX #pragma extern_model strict_refdef "LIB$INITIALIZE" nowrt, long, nopic #else #pragma extern_model strict_refdef "LIB$INITIALIZE" nowrt, long # if __INITIAL_POINTER_SIZE # pragma __pointer_size __save # pragma __pointer_size 32 # else # pragma __required_pointer_size __save # pragma __required_pointer_size 32 # endif #endif /* Set our contribution to the LIB$INITIALIZE array */ void (* const iniarray[])(void) = {set_features, } ; #ifndef __VAX # if __INITIAL_POINTER_SIZE # pragma __pointer_size __restore # else # pragma __required_pointer_size __restore # endif #endif /* ** Force a reference to LIB$INITIALIZE to ensure it ** exists in the image. */ int LIB$INITIALIZE(void); #ifdef __DECC #pragma extern_model strict_refdef #endif int lib_init_ref = (int) LIB$INITIALIZE; #ifdef __DECC #pragma extern_model restore #pragma standard #endif davix-0.8.0/deps/curl/packages/vms/curlmsg.h0000644000000000000000000001425314121063461017443 0ustar rootroot#ifndef HEADER_CURLMSG_H #define HEADER_CURLMSG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #pragma __member_alignment __save #pragma __nomember_alignment /* */ /* CURLMSG.H */ /* */ /* SDL File Generated by VAX-11 Message V04-00 on 3-SEP-2008 13:33:54.09 */ /* */ /* THESE VMS ERROR CODES ARE GENERATED BY TAKING APART THE CURL.H */ /* FILE AND PUTTING ALL THE CURLE_* ENUM STUFF INTO THIS FILE, */ /* CURLMSG.MSG. AN .SDL FILE IS CREATED FROM THIS FILE WITH */ /* MESSAGE/SDL. THE .H FILE IS CREATED USING THE FREEWARE SDL TOOL */ /* AGAINST THE .SDL FILE WITH SDL/ALPHA/LANG=CC COMMAND. */ /* */ /* WITH THE EXCEPTION OF CURLE_OK, ALL OF THE MESSAGES ARE AT */ /* THE ERROR SEVERITY LEVEL. WITH THE EXCEPTION OF */ /* PEER_FAILED_VERIF, WHICH IS A SHORTENED FORM OF */ /* PEER_FAILED_VERIFICATION, THESE ARE THE SAME NAMES AS THE */ /* CURLE_ ONES IN INCLUDE/CURL.H. THE MESSAGE UTILITY MANUAL STATES */ /* "THE COMBINED LENGTH OF THE PREFIX AND THE MESSAGE SYMBOL NAME CANNOT */ /* EXCEED 31 CHARACTERS." WITH A PREFIX OF FIVE THAT LEAVES US WITH 26 */ /* FOR THE MESSAGE NAME. */ /* */ /* IF YOU UPDATE THIS FILE, UPDATE CURLMSG_VMS.H SO THAT THEY ARE IN SYNC */ /* */ #define CURL_FACILITY 3841 #define CURL_OK 251756553 #define CURL_UNSUPPORTED_PROTOCOL 251756562 #define CURL_FAILED_INIT 251756570 #define CURL_URL_MALFORMAT 251756578 #define CURL_OBSOLETE4 251756586 #define CURL_COULDNT_RESOLVE_PROXY 251756594 #define CURL_COULDNT_RESOLVE_HOST 251756602 #define CURL_COULDNT_CONNECT 251756610 #define CURL_WEIRD_SERVER_REPLY 251756618 #define CURL_FTP_WEIRD_SERVER_REPLY CURL_WEIRD_SERVER_REPLY #define CURL_FTP_ACCESS_DENIED 251756626 #define CURL_OBSOLETE10 251756634 #define CURL_FTP_WEIRD_PASS_REPLY 251756642 #define CURL_OBSOLETE12 251756650 #define CURL_FTP_WEIRD_PASV_REPLY 251756658 #define CURL_FTP_WEIRD_227_FORMAT 251756666 #define CURL_FTP_CANT_GET_HOST 251756674 #define CURL_OBSOLETE16 251756682 #define CURL_FTP_COULDNT_SET_TYPE 251756690 #define CURL_PARTIAL_FILE 251756698 #define CURL_FTP_COULDNT_RETR_FILE 251756706 #define CURL_OBSOLETE20 251756714 #define CURL_QUOTE_ERROR 251756722 #define CURL_HTTP_RETURNED_ERROR 251756730 #define CURL_WRITE_ERROR 251756738 #define CURL_OBSOLETE24 251756746 #define CURL_UPLOAD_FAILED 251756754 #define CURL_READ_ERROR 251756762 #define CURL_OUT_OF_MEMORY 251756770 #define CURL_OPERATION_TIMEOUTED 251756778 #define CURL_OBSOLETE29 251756786 #define CURL_FTP_PORT_FAILED 251756794 #define CURL_FTP_COULDNT_USE_REST 251756802 #define CURL_OBSOLETE32 251756810 #define CURL_RANGE_ERROR 251756818 #define CURL_HTTP_POST_ERROR 251756826 #define CURL_SSL_CONNECT_ERROR 251756834 #define CURL_BAD_DOWNLOAD_RESUME 251756842 #define CURL_FILE_COULDNT_READ_FILE 251756850 #define CURL_LDAP_CANNOT_BIND 251756858 #define CURL_LDAP_SEARCH_FAILED 251756866 #define CURL_OBSOLETE40 251756874 #define CURL_FUNCTION_NOT_FOUND 251756882 #define CURL_ABORTED_BY_CALLBACK 251756890 #define CURL_BAD_FUNCTION_ARGUMENT 251756898 #define CURL_OBSOLETE44 251756906 #define CURL_INTERFACE_FAILED 251756914 #define CURL_OBSOLETE46 251756922 #define CURL_TOO_MANY_REDIRECTS 251756930 #define CURL_UNKNOWN_TELNET_OPTION 251756938 #define CURL_TELNET_OPTION_SYNTAX 251756946 #define CURL_OBSOLETE50 251756954 #define CURL_PEER_FAILED_VERIF 251756962 #define CURL_GOT_NOTHING 251756970 #define CURL_SSL_ENGINE_NOTFOUND 251756978 #define CURL_SSL_ENGINE_SETFAILED 251756986 #define CURL_SEND_ERROR 251756994 #define CURL_RECV_ERROR 251757002 #define CURL_OBSOLETE57 251757010 #define CURL_SSL_CERTPROBLEM 251757018 #define CURL_SSL_CIPHER 251757026 #define CURL_SSL_CACERT 251757034 #define CURL_BAD_CONTENT_ENCODING 251757042 #define CURL_LDAP_INVALID_URL 251757050 #define CURL_FILESIZE_EXCEEDED 251757058 #define CURL_USE_SSL_FAILED 251757066 #define CURL_SEND_FAIL_REWIND 251757074 #define CURL_SSL_ENGINE_INITFAILED 251757082 #define CURL_LOGIN_DENIED 251757090 #define CURL_TFTP_NOTFOUND 251757098 #define CURL_TFTP_PERM 251757106 #define CURL_REMOTE_DISK_FULL 251757114 #define CURL_TFTP_ILLEGAL 251757122 #define CURL_TFTP_UNKNOWNID 251757130 #define CURL_REMOTE_FILE_EXISTS 251757138 #define CURL_TFTP_NOSUCHUSER 251757146 #define CURL_CONV_FAILED 251757154 #define CURL_CONV_REQD 251757162 #define CURL_SSL_CACERT_BADFILE 251757170 #define CURL_REMOTE_FILE_NOT_FOUND 251757178 #define CURL_SSH 251757186 #define CURL_SSL_SHUTDOWN_FAILED 251757194 #define CURL_AGAIN 251757202 #define CURL_SSL_CRL_BADFILE 251757210 #define CURL_SSL_ISSUER_ERROR 251757218 #define CURL_CURL_LAST 251757226 #pragma __member_alignment __restore #endif /* HEADER_CURLMSG_H */ davix-0.8.0/deps/curl/packages/vms/generate_vax_transfer.com0000644000000000000000000002007314121063461022667 0ustar rootroot$! File: generate_vax_transfer.com $! $! $Id$ $! $! File to generate and compile the VAX transfer vectors from reading in the $! Alpha/Itanium gnv_libcurl_symbols.opt file. $! $! This procedure patches the VAX Macro32 assembler to be case sensitive $! and then compiles the generated $! $! The output of this procedure is: $! gnv_libcurl_xfer.mar_exact $! gnv_libcurl_xfer.obj $! gnv_libcurl_xfer.opt $! macro32_exactcase.exe $! $! Copyright 2013, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 20-Jul-2013 J. Malmberg $!============================================================================ $! $! Save this so we can get back. $ default_dir = f$environment("default") $! $ on warning then goto all_exit $! $! Want hard tabs in the generated file. $ tab[0,8] = 9 $! $! This procedure is used on VAX only $ if (f$getsyi("HW_MODEL") .ge. 1024) $ then $ write sys$output "This procedure is only used on VAX." $ goto all_exit $ endif $! $! $! Get the libcurl version to generate the ident string. $! ident string is max of 31 characters. $! $ ident_string = "unknown" $ open/read cver [-.-.include.curl]curlver.h $cver_loop: $ read/end=cver_loop_end cver line_in $ line_in = f$edit(line_in, "COMPRESS,TRIM") $ if line_in .eqs. "" then goto cver_loop $ code = f$extract(0, 1, line_in) $ if code .nes. "#" then goto cver_loop $ directive = f$element(0, " ", line_in) $ if directive .nes. "#define" then goto cver_loop $ name = f$element(1, " ", line_in) $ if name .nes. "LIBCURL_VERSION" then goto cver_loop $ ident_string = f$element(2, " ", line_in) - "" - "" $cver_loop_end: $ close cver $! $ open/read aopt gnv_libcurl_symbols.opt $! $! Write out the header $ gosub do_header $! $ open/append vopt gnv_libcurl_xfer.mar_exact $ write vopt tab,".IDENT /", ident_string, "/" $! $ write vopt tab, ".PSECT LIBCURL_XFERVECTORS -" $ write vopt tab,tab,tab, "PIC,USR,CON,REL,GBL,SHR,EXE,RD,NOWRT,QUAD" $ write vopt "" $ write vopt tab, "SPARE", tab, "; never delete this spare" $ write vopt ";" $ write vopt ";", tab, "Exact case and upper case transfer vectors" $! $ alias_count = 0 $vector_loop: $! $! Read in symbol_vector $! $ read/end=vector_loop_end aopt line_in $ line = f$edit(line_in, "UNCOMMENT,COMPRESS,TRIM") $ if line .eqs. "" then goto vector_loop $! $ line_u = f$edit(line, "UPCASE") $ key = f$element(0, "=", line_u) $ if (key .eqs. "SYMBOL_VECTOR") $ then $ symbol_string = f$element(1, "=", line) - "(" $ symbol_type = f$element(2, "=", line_u) - ")" $ symbol_name = f$element(1, "/", symbol_string) $ if symbol_type .nes. "PROCEDURE" $ then $ write sys$output "%CURLBUILD-W-NOTPROC, " + - $ "This procedure can only handle procedure vectors" $ write sys$output - "Data vectors require manual construction for which this procedure or" $ write sys$output - "the shared library needs to be updated to resolve." $ write sys$output - "the preferred solution is to have a procedure return the address of the " $ write sys$output - "the variable instead of having a variable, as if the size of the variable " write sys$output - "changes, the symbol vector is no longer backwards compatible." $ endif $ if (symbol_name .eqs. "/") $ then $ symbol_name = symbol_string $ write vopt tab, symbol_type, tab, symbol_name $ else $ alias_count = alias_count + 1 $ symbol_alias = f$element(0, "/", symbol_string) $ write vopt - tab, "''symbol_type_U", tab, symbol_name, tab, symbol_alias $ endif $ endif $ goto vector_loop $vector_loop_end: $! $! End of pass one, second pass needed if aliases exist $ close aopt $! $ if alias_count .eq. 0 then goto finish_file $! $! Start pass 2, write stub routine header $! $ open/read aopt gnv_libcurl_symbols.opt $! $alias_loop: $! $! Read in symbol_vector $! $ read/end=alias_loop_end aopt line_in $ line = f$edit(line_in, "UNCOMMENT,COMPRESS,TRIM") $ if line .eqs. "" then goto alias_loop $! $ line_u = f$edit(line, "UPCASE") $ key = f$element(0, "=", line_u) $ if (key .eqs. "SYMBOL_VECTOR") $ then $ symbol_string = f$element(1, "=", line) - "(" $ symbol_type = f$element(2, "=", line_u) - ")" $ symbol_name = f$element(1, "/", symbol_string) $ if (symbol_name .eqs. "/") $ then $ symbol_name = symbol_string $ else $ alias_count = alias_count + 1 $ symbol_alias = f$element(0, "/", symbol_string) $ write vopt tab, ".ENTRY", tab, symbol_alias, ", ^M<>" $ endif $ endif $ goto alias_loop $! read in symbol_vector $! if not alias, then loop $! write out subroutine name $! $alias_loop_end: $! $ write vopt tab, "MOVL #1, R0" $ write vopt tab, "RET" $! $finish_file: $! $ write vopt "" $ write vopt tab, ".END" $! $ close aopt $ close vopt $! $! Patch the Macro32 compiler $!---------------------------- $ patched_macro = "sys$disk:[]macro32_exactcase.exe" $ if f$search(patched_macro) .eqs. "" $ then $ copy sys$system:macro32.exe 'patched_macro' $ patch @macro32_exactcase.patch $ endif $ define/user macro32 'patched_macro' $ macro/object=gnv_libcurl_xfer.obj gnv_libcurl_xfer.mar_exact $! $! Create the option file for linking the shared image. $ create gnv_libcurl_xfer.opt $ open/append lco gnv_libcurl_xfer.opt $ write lco "gsmatch=lequal,1,1" $ write lco "cluster=transfer_vector,,,''default_dir'gnv_libcurl_xfer" $ write lco "collect=libcurl_global, libcurl_xfervectors" $ close lco $! $! $ goto all_exit $! $! Process the header $do_header: $! $! Force the mode of the file to same as text editor generated. $ create gnv_libcurl_xfer.mar_exact $deck ; File: gnv_libcurl_xfer.mar_exact ; ; VAX transfer vectors ; ; This needs to be compiled with a specialized patch on Macro32 to make it ; preserve the case of symbols instead of converting it to uppercase. ; ; This patched Macro32 requires all directives to be in upper case. ; ; There are three sets of symbols for transfer vectors here. ; ; The first for upper case which matches the tradition method of generating ; VAX transfer vectors. ; ; The second is the exact case for compatibility with open source C programs ; that expect exact case symbols in images. These are separated because a ; previous kit had only upper case symbols. ; ; The third is the routine stub that is used to resolve part of the upper ; case transfer vectors, with exact case entry symbols. ; ; When you add routines, you need to add them after the second set of transfer ; vectors for both upper and exact case, and then additional entry points ; in upper case added to stub routines. ; ;************************************************************************* .TITLE libcurl_xfer - Transfer vector for libcurl .DISABLE GLOBAL ; ; Macro to generate a transfer vector entry ; .MACRO PROCEDURE NAME .EXTRN 'NAME .ALIGN QUAD .TRANSFER 'NAME .MASK 'NAME JMP 'NAME+2 .ENDM .MACRO PROCEDUREU NAME NAMEU .EXTRN 'NAME .ALIGN QUAD .TRANSFER 'NAMEU .MASK 'NAME JMP 'NAME+2 .ENDM ; ; ; Macro to reserve a spare entry. ; .MACRO SPARE .ALIGN QUAD .ALIGN QUAD .QUAD 0 .ENDM $EOD $! $! $ return $! $all_exit: $set def 'default_dir' $exit '$status' davix-0.8.0/deps/curl/packages/vms/curlmsg_vms.h0000644000000000000000000001006114121063461020321 0ustar rootroot#ifndef HEADER_CURLMSG_VMS_H #define HEADER_CURLMSG_VMS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* */ /* CURLMSG_VMS.H */ /* */ /* This defines the necessary bits to change CURLE_* error codes to VMS */ /* style error codes. CURLMSG.H is built from CURLMSG.SDL which is built */ /* from CURLMSG.MSG. The vms_cond array is used to return VMS errors by */ /* putting the VMS error codes into the array offset based on CURLE_* code. */ /* */ /* If you update CURLMSG.MSG make sure to update this file to match. */ /* */ #include "curlmsg.h" /* #define FAC_CURL 0xC01 #define FAC_SYSTEM 0 #define MSG_NORMAL 0 */ /* #define SEV_WARNING 0 #define SEV_SUCCESS 1 #define SEV_ERROR 2 #define SEV_INFO 3 #define SEV_FATAL 4 */ static const long vms_cond[] = { CURL_OK, CURL_UNSUPPORTED_PROTOCOL, CURL_FAILED_INIT, CURL_URL_MALFORMAT, CURL_OBSOLETE4, CURL_COULDNT_RESOLVE_PROXY, CURL_COULDNT_RESOLVE_HOST, CURL_COULDNT_CONNECT, CURL_WEIRD_SERVER_REPLY, CURL_FTP_ACCESS_DENIED, CURL_OBSOLETE10, CURL_FTP_WEIRD_PASS_REPLY, CURL_OBSOLETE12, CURL_FTP_WEIRD_PASV_REPLY, CURL_FTP_WEIRD_227_FORMAT, CURL_FTP_CANT_GET_HOST, CURL_OBSOLETE16, CURL_FTP_COULDNT_SET_TYPE, CURL_PARTIAL_FILE, CURL_FTP_COULDNT_RETR_FILE, CURL_OBSOLETE20, CURL_QUOTE_ERROR, CURL_HTTP_RETURNED_ERROR, CURL_WRITE_ERROR, CURL_OBSOLETE24, CURL_UPLOAD_FAILED, CURL_READ_ERROR, CURL_OUT_OF_MEMORY, CURL_OPERATION_TIMEOUTED, CURL_OBSOLETE29, CURL_FTP_PORT_FAILED, CURL_FTP_COULDNT_USE_REST, CURL_OBSOLETE32, CURL_RANGE_ERROR, CURL_HTTP_POST_ERROR, CURL_SSL_CONNECT_ERROR, CURL_BAD_DOWNLOAD_RESUME, CURL_FILE_COULDNT_READ_FILE, CURL_LDAP_CANNOT_BIND, CURL_LDAP_SEARCH_FAILED, CURL_OBSOLETE40, CURL_FUNCTION_NOT_FOUND, CURL_ABORTED_BY_CALLBACK, CURL_BAD_FUNCTION_ARGUMENT, CURL_OBSOLETE44, CURL_INTERFACE_FAILED, CURL_OBSOLETE46, CURL_TOO_MANY_REDIRECTS, CURL_UNKNOWN_TELNET_OPTION, CURL_TELNET_OPTION_SYNTAX, CURL_OBSOLETE50, CURL_PEER_FAILED_VERIF, CURL_GOT_NOTHING, CURL_SSL_ENGINE_NOTFOUND, CURL_SSL_ENGINE_SETFAILED, CURL_SEND_ERROR, CURL_RECV_ERROR, CURL_OBSOLETE57, CURL_SSL_CERTPROBLEM, CURL_SSL_CIPHER, CURL_SSL_CACERT, CURL_BAD_CONTENT_ENCODING, CURL_LDAP_INVALID_URL, CURL_FILESIZE_EXCEEDED, CURL_USE_SSL_FAILED, CURL_SEND_FAIL_REWIND, CURL_SSL_ENGINE_INITFAILED, CURL_LOGIN_DENIED, CURL_TFTP_NOTFOUND, CURL_TFTP_PERM, CURL_REMOTE_DISK_FULL, CURL_TFTP_ILLEGAL, CURL_TFTP_UNKNOWNID, CURL_REMOTE_FILE_EXISTS, CURL_TFTP_NOSUCHUSER, CURL_CONV_FAILED, CURL_CONV_REQD, CURL_SSL_CACERT_BADFILE, CURL_REMOTE_FILE_NOT_FOUND, CURL_SSH, CURL_SSL_SHUTDOWN_FAILED, CURL_AGAIN, CURLE_SSL_CRL_BADFILE, CURLE_SSL_ISSUER_ERROR, CURL_CURL_LAST }; #endif /* HEADER_CURLMSG_VMS_H */ davix-0.8.0/deps/curl/packages/vms/backup_gnv_curl_src.com0000644000000000000000000001015514121063461022326 0ustar rootroot$! File: Backup_gnv_curl_src.com $! $! $Id$ $! $! Procedure to create backup save sets for installing in a PCSI kit. $! $! To comply with most Open Source licenses, the source used for building $! a kit will be packaged with the distribution kit for the binary. $! $! Backup save sets are the only storage format that I can expect a $! VMS system to be able to extract ODS-5 filenames and directories. $! $! The make_pcsi_kit_name.com needs to be run before this procedure to $! properly name the files that will be created. $! $! This file is created from a template file for the purpose of making it $! easier to port Unix code, particularly open source code to VMS. $! Therefore permission is freely granted for any use. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 13-Jun-2009 J. Malmberg $! $!=========================================================================== $! $! Save default $ default_dir = f$environment("DEFAULT") $! $ arch_type = f$getsyi("ARCH_NAME") $ arch_code = f$extract(0, 1, arch_type) $! $ if arch_code .nes. "V" $ then $ set proc/parse=extended $ endif $! $ ss_abort = 44 $ status = ss_abort $! $ kit_name = f$trnlnm("GNV_PCSI_KITNAME") $ if kit_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ producer = f$trnlnm("GNV_PCSI_PRODUCER") $ if producer .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ filename_base = f$trnlnm("GNV_PCSI_FILENAME_BASE") $ if filename_base .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $! $ node_swvers = f$getsyi("NODE_SWVERS") $ node_swvers_type = f$extract(0, 1, node_swvers) $ node_swvers_vers = f$extract(1, f$length(node_swvers), node_swvers) $ swvers_maj = f$element(0, ".", node_swvers_vers) $ node_swvers_min_update = f$element(1, ".", node_swvers_vers) $ swvers_min = f$element(0, "-", node_swvers_min_update) $ swvers_update = f$element(1, "-", node_swvers_min_update) $! $ if swvers_update .eqs. "-" then swvers_update = "" $! $ vms_vers = f$fao("!2ZB!2ZB!AS", 'swvers_maj', 'swvers_min', swvers_update) $! $! $! $! If available make an interchange save set $!------------------------------------------- $ interchange = "" $ if arch_code .eqs. "V" $ then $ interchange = "/interchange" $ endif $ if (swvers_maj .ges. "8") .and. (swvers_min .ges. 4) $ then $ interchange = "/interchange/noconvert" $ endif $! $! $! Move to the base directories $ set def [--] $! $! Put things back on error. $ on warning then goto all_exit $! $ current_default = f$environment("DEFAULT") $ my_dir = f$parse(current_default,,,"DIRECTORY") - "[" - "<" - ">" - "]" $! $ src_root = "src_root:" $ if f$trnlnm("src_root1") .nes. "" then src_root = "src_root1:" $ backup'interchange' 'src_root'[curl...]*.*;0 - 'filename_base'_original_src.bck/sav $ status = $status $! $! There may be a VMS specific source kit $!----------------------------------------- $ vms_root = "vms_root:" $ if f$trnlnm("vms_root1") .nes. "" then vms_root = "vms_root1:" $ files_found = 0 $ define/user sys$error nl: $ define/user sys$output nl: $ directory 'vms_root'[...]*.*;*/exc=*.dir $ if '$severity' .eq. 1 then files_found = 1 $! $ if files_found .eq. 1 $ then $ backup'interchange' 'vms_root'[curl...]*.*;0 - 'filename_base'_vms_src.bck/sav $ status = $status $ endif $! $all_exit: $ set def 'default_dir' $ exit davix-0.8.0/deps/curl/packages/vms/vms_eco_level.h0000644000000000000000000000206514121063461020607 0ustar rootroot/* File: vms_eco_level.h * * $Id$ * * Copyright 2012, John Malmberg * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file should be incremented for each ECO that is kit */ /* for a specific curl x.y-z release. */ /* When any part of x.y-z is incremented, the ECO should be set back to 0 */ #ifndef _VMS_ECO_LEVEL_H #define _VMS_ECO_LEVEL_H #define VMS_ECO_LEVEL "0" #endif davix-0.8.0/deps/curl/packages/vms/pcsi_gnv_curl_file_list.txt0000644000000000000000000001120414121063461023237 0ustar rootroot! File: PCSI_GNV_CURL_FILE_LIST.TXT ! ! $Id$ ! ! File list for building a PCSI kit. ! Very simple format so that the parsing logic can be simple. ! links first, directory second, and files third. ! ! link -> file tells procedure to create/remove a link on install/uninstall ! If more than one link, consider using an alias file. ! ! [xxx.yyy]foo.dir is a directory file for the rename phase. ! [xxx.yyy.foo] is a directory file for the create phase. ! Each subdirectory needs to be on its own pair of lines. ! ! [xxx.yyy]file.ext is a file for the rename and add phases. ! ! Copyright 2009, John Malmberg ! ! Permission to use, copy, modify, and/or distribute this software for any ! purpose with or without fee is hereby granted, provided that the above ! copyright notice and this permission notice appear in all copies. ! ! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! ! 15-Jun-2009 J. Malmberg !============================================================================ [gnv.usr.bin]curl. -> [gnv.usr.bin]gnv$curl.exe [gnv.usr.bin]curl.exe -> [gnv.usr.bin]gnv$curl.exe [gnv] [000000]gnv.dir [gnv.usr] [gnv]usr.dir [gnv.usr]bin.dir [gnv.usr.bin] [gnv.usr]include.dir [gnv.usr.include] [gnv.usr.include]curl.dir [gnv.usr.include.curl] [gnv.usr]lib.dir [gnv.usr.lib] [gnv.usr.lib]pkgconfig.dir [gnv.usr.lib.pkgconfig] [gnv.usr]share.dir [gnv.usr.share] [gnv.usr.share]man.dir [gnv.usr.share.man] [gnv.usr.share.man]man1.dir [gnv.usr.share.man.man1] [gnv.usr.share.man]man3.dir [gnv.usr.share.man.man3] [gnv.usr.bin]curl-config. [gnv.usr.bin]gnv$curl.exe [gnv.usr.include.curl]curl.h [gnv.usr.include.curl]system.h [gnv.usr.include.curl]curlver.h [gnv.usr.include.curl]easy.h [gnv.usr.include.curl]mprintf.h [gnv.usr.include.curl]multi.h [gnv.usr.include.curl]stdcheaders.h [gnv.usr.include.curl]typecheck-gcc.h [gnv.usr.lib]gnv$libcurl.exe [gnv.usr.lib]gnv$curlmsg.exe [gnv.usr.lib.pkgconfig]libcurl.pc [gnv.usr.share.man.man1]curl-config.1 [gnv.usr.share.man.man1]curl.1 [gnv.usr.share.man.man3]curl_easy_cleanup.3 [gnv.usr.share.man.man3]curl_easy_duphandle.3 [gnv.usr.share.man.man3]curl_easy_escape.3 [gnv.usr.share.man.man3]curl_easy_getinfo.3 [gnv.usr.share.man.man3]curl_easy_init.3 [gnv.usr.share.man.man3]curl_easy_pause.3 [gnv.usr.share.man.man3]curl_easy_perform.3 [gnv.usr.share.man.man3]curl_easy_recv.3 [gnv.usr.share.man.man3]curl_easy_reset.3 [gnv.usr.share.man.man3]curl_easy_send.3 [gnv.usr.share.man.man3]curl_easy_setopt.3 [gnv.usr.share.man.man3]curl_easy_strerror.3 [gnv.usr.share.man.man3]curl_easy_unescape.3 [gnv.usr.share.man.man3]curl_escape.3 [gnv.usr.share.man.man3]curl_formadd.3 [gnv.usr.share.man.man3]curl_formfree.3 [gnv.usr.share.man.man3]curl_formget.3 [gnv.usr.share.man.man3]curl_free.3 [gnv.usr.share.man.man3]curl_getdate.3 [gnv.usr.share.man.man3]curl_getenv.3 [gnv.usr.share.man.man3]curl_global_cleanup.3 [gnv.usr.share.man.man3]curl_global_init.3 [gnv.usr.share.man.man3]curl_global_init_mem.3 [gnv.usr.share.man.man3]curl_mprintf.3 [gnv.usr.share.man.man3]curl_multi_add_handle.3 [gnv.usr.share.man.man3]curl_multi_assign.3 [gnv.usr.share.man.man3]curl_multi_cleanup.3 [gnv.usr.share.man.man3]curl_multi_fdset.3 [gnv.usr.share.man.man3]curl_multi_info_read.3 [gnv.usr.share.man.man3]curl_multi_init.3 [gnv.usr.share.man.man3]curl_multi_perform.3 [gnv.usr.share.man.man3]curl_multi_remove_handle.3 [gnv.usr.share.man.man3]curl_multi_setopt.3 [gnv.usr.share.man.man3]curl_multi_socket.3 [gnv.usr.share.man.man3]curl_multi_socket_action.3 [gnv.usr.share.man.man3]curl_multi_strerror.3 [gnv.usr.share.man.man3]curl_multi_timeout.3 [gnv.usr.share.man.man3]curl_multi_wait.3 [gnv.usr.share.man.man3]curl_share_cleanup.3 [gnv.usr.share.man.man3]curl_share_init.3 [gnv.usr.share.man.man3]curl_share_setopt.3 [gnv.usr.share.man.man3]curl_share_strerror.3 [gnv.usr.share.man.man3]curl_slist_append.3 [gnv.usr.share.man.man3]curl_slist_free_all.3 [gnv.usr.share.man.man3]curl_strequal.3 [gnv.usr.share.man.man3]curl_unescape.3 [gnv.usr.share.man.man3]curl_version.3 [gnv.usr.share.man.man3]curl_version_info.3 [gnv.usr.share.man.man3]libcurl-easy.3 [gnv.usr.share.man.man3]libcurl-errors.3 [gnv.usr.share.man.man3]libcurl-multi.3 [gnv.usr.share.man.man3]libcurl-share.3 [gnv.usr.share.man.man3]libcurl-tutorial.3 [gnv.usr.share.man.man3]libcurl.3 davix-0.8.0/deps/curl/packages/vms/curlmsg.msg0000644000000000000000000001110514121063461017773 0ustar rootroot! ! These VMS error codes are generated by taking apart the curl.h ! file and putting all the CURLE_* enum stuff into this file, ! CURLMSG.MSG. An .SDL file is created from this file with ! MESSAGE/SDL. The .H file is created using the freeware SDL tool ! against the .SDL file with SDL/ALPHA/LANG=CC command. ! ! With the exception of CURLE_OK, all of the messages are at ! the error severity level. With the exception of ! PEER_FAILED_VERIF, which is a shortened form of ! PEER_FAILED_VERIFICATION, these are the same names as the ! CURLE_ ones in include/curl.h. The Message Utility manual states ! "The combined length of the prefix and the message symbol name cannot ! exceed 31 characters." With a prefix of five that leaves us with 26 ! for the message name. ! ! If you update this file also update curlmsg_vms.h so that they are in sync ! .TITLE CURLMSG Message files .FACILITY CURL,1793 /PREFIX=CURL_ .BASE 1 .SEVERITY SUCCESS OK .SEVERITY ERROR UNSUPPORTED_PROTOCOL FAILED_INIT URL_MALFORMAT OBSOLETE4 COULDNT_RESOLVE_PROXY COULDNT_RESOLVE_HOST COULDNT_CONNECT WEIRD_SERVER_REPLY FTP_ACCESS_DENIED OBSOLETE10 FTP_WEIRD_PASS_REPLY OBSOLETE12 FTP_WEIRD_PASV_REPLY FTP_WEIRD_227_FORMAT FTP_CANT_GET_HOST OBSOLETE16 FTP_COULDNT_SET_TYPE PARTIAL_FILE FTP_COULDNT_RETR_FILE OBSOLETE20 QUOTE_ERROR HTTP_RETURNED_ERROR WRITE_ERROR OBSOLETE24 UPLOAD_FAILED READ_ERROR OUT_OF_MEMORY OPERATION_TIMEOUTED OBSOLETE29 FTP_PORT_FAILED FTP_COULDNT_USE_REST OBSOLETE32 RANGE_ERROR HTTP_POST_ERROR SSL_CONNECT_ERROR BAD_DOWNLOAD_RESUME FILE_COULDNT_READ_FILE LDAP_CANNOT_BIND LDAP_SEARCH_FAILED OBSOLETE40 FUNCTION_NOT_FOUND ABORTED_BY_CALLBACK BAD_FUNCTION_ARGUMENT OBSOLETE44 INTERFACE_FAILED OBSOLETE46 TOO_MANY_REDIRECTS UNKNOWN_TELNET_OPTION TELNET_OPTION_SYNTAX OBSOLETE50 PEER_FAILED_VERIF GOT_NOTHING SSL_ENGINE_NOTFOUND SSL_ENGINE_SETFAILED SEND_ERROR RECV_ERROR OBSOLETE57 SSL_CERTPROBLEM SSL_CIPHER SSL_CACERT BAD_CONTENT_ENCODING LDAP_INVALID_URL FILESIZE_EXCEEDED USE_SSL_FAILED SEND_FAIL_REWIND SSL_ENGINE_INITFAILED LOGIN_DENIED TFTP_NOTFOUND TFTP_PERM REMOTE_DISK_FULL TFTP_ILLEGAL TFTP_UNKNOWNID REMOTE_FILE_EXISTS TFTP_NOSUCHUSER CONV_FAILED CONV_REQD SSL_CACERT_BADFILE REMOTE_FILE_NOT_FOUND SSH SSL_SHUTDOWN_FAILED AGAIN SSL_CRL_BADFILE SSL_ISSUER_ERROR CURL_LAST .END davix-0.8.0/deps/curl/packages/vms/build_gnv_curl_release_notes.com0000644000000000000000000000606214121063461024223 0ustar rootroot$! File: Build_GNV_curl_release_notes.com $! $! $Id$ $! $! Build the release note file from the four components: $! 1. The curl_release_note_start.txt $! 2. The hp_ssl_release_info.txt $! 3. [--]readme. file from the Curl distribution. $! 4. The Curl_gnv-build_steps.txt. $! $! Set the name of the release notes from the GNV_PCSI_FILENAME_BASE $! logical name. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 14-Jun-2009 J. Malmberg $! $!=========================================================================== $! $ base_file = f$trnlnm("GNV_PCSI_FILENAME_BASE") $ if base_file .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $! $! $ curl_readme = f$search("sys$disk:[--]readme.") $ if curl_readme .eqs. "" $ then $ curl_readme = f$search("sys$disk:[--]$README.") $ endif $ if curl_readme .eqs. "" $ then $ write sys$output "Can not find Curl readme file." $ goto all_exit $ endif $! $ curl_copying = f$search("sys$disk:[--]copying.") $ if curl_copying .eqs. "" $ then $ curl_copying = f$search("sys$disk:[--]$COPYING.") $ endif $ if curl_copying .eqs. "" $ then $ write sys$output "Can not find Curl copying file." $ goto all_exit $ endif $! $ vms_readme = f$search("sys$disk:[]readme.") $ if vms_readme .eqs. "" $ then $ vms_readme = f$search("sys$disk:[]$README.") $ endif $ if vms_readme .eqs. "" $ then $ write sys$output "Can not find VMS specific Curl readme file." $ goto all_exit $ endif $! $ curl_release_notes = f$search("sys$disk:[--]release-notes.") $ if curl_release_notes .eqs. "" $ then $ curl_release_notes = f$search("sys$disk:[--]$RELEASE-NOTES.") $ endif $ if curl_release_notes .eqs. "" $ then $ write sys$output "Can not find Curl release-notes file." $ goto all_exit $ endif $! $ if f$search("sys$disk:[]hp_ssl_release_info.txt") .eqs. "" $ then $ write sys$output "GNV_LINK_CURL.COM has not been run!" $ goto all_exit $ endif $! $ type/noheader 'curl_readme', 'vms_readme', - 'curl_release_notes', - sys$disk:[]curl_release_note_start.txt, - sys$disk:[]hp_ssl_release_info.txt, - 'curl_copying', - sys$disk:[]curl_gnv_build_steps.txt - /out='base_file'.release_notes $! $ purge 'base_file'.release_notes $ rename 'base_file.release_notes ;1 $! $all_exit: $ exit davix-0.8.0/deps/curl/packages/vms/compare_curl_source.com0000644000000000000000000002544314121063461022354 0ustar rootroot$! Compare_curl_source.com $! $! $Id$ $! $! This procedure compares the files in two directories and reports the $! differences. It is customized for the vmsports repository layout. $! $! It needs to be customized to the local site directories. $! $! This is used by me for these purposes: $! 1. Compare the original source of a project with an existing $! VMS port. $! 2. Compare the checked out repository of a project with the $! the local working copy to make sure they are in sync. $! 3. Keep a copy directory up to date. The third is needed by $! me because VMS Backup can create a saveset of files from a $! NFS mounted volume. $! $! First the files in the original source directory which is assumed to be $! under source code control are compared with the copy directory. $! $! Then the files are are only in the copy directory are listed. $! $! The result will five diagnostics about of files: $! 1. Files that are not generation 1. $! 2. Files missing in the copy directory. $! 3. Files in the copy directory not in the source directory. $! 4. Files different from the source directory. $! 5. Files that VMS DIFF can not process. $! $! This needs to be run on an ODS-5 volume. $! $! If UPDATE is given as a second parameter, files missing or different in the $! copy directory will be updated. $! $! By default: $! The directory src_root:[project_name] will be translated to something like $! DISK:[dir.dir.reference.project_name] and this will be used $! to calculate DISK:[dir.dir.vms_source.project_name] for the VMS specific $! source directory. $! $! The copy directory is vms_root:[project_name] $! The UPDATE parameter is ignored. $! $! This setting is used to make sure that the working vms directory $! and the repository checkout directory have the same contents. $! $! If P1 is "SRCBCK" then this $! The source directory tree is: src_root:[project_name] $! The copy directory is src_root1:[project_name] $! $! src_root1:[project_name] is used by me to work around that VMS backup will $! not use NFS as a source directory so I need to make a copy. $! $! This is to make sure that the backup save set for the unmodified $! source is up to date. $! $! If your repository checkout is not on an NFS mounted volume, you do not $! need to use this option or have the logical name src_root1 defined. $! $! If P1 is "VMSBCK" then this changes the two directories: $! The source directory is vms_root:[project_name] $! The copy directory is vms_root1:[project_name] $! $! vms_root:[project_name] is where I do the VMS specific edits. $! vms_root1:[project_name] is used by me to work around that VMS backup will $! not use NFS as a source directory so I need to make a copy. $! $! This is to make sure that the backup save set for the unmodified $! source is up to date. $! $! Copyright 2011, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 18-Aug-2011 J. Malmberg $!========================================================================== $! $! Update missing/changed files. $ update_file = 0 $ if (p2 .eqs. "UPDATE") $ then $ update_file = 1 $ endif $! $ myproc = f$environment("PROCEDURE") $ myprocdir = f$parse(myproc,,,"DIRECTORY") - "[" - "]" - "<" - ">" $ myprocdir = f$edit(myprocdir, "LOWERCASE") $ mydefault = f$environment("DEFAULT") $ mydir = f$parse(mydefault,,,"DIRECTORY") $ mydir = f$edit(mydir, "LOWERCASE") $ odelim = f$extract(0, 1, mydir) $ mydir = mydir - "[" - "]" - "<" - ">" $ mydev = f$parse(mydefault,,,"DEVICE") $! $ ref = "" $ if P1 .eqs. "" $ then $ ref_base_dir = myprocdir $ wrk_base_dir = mydir $ update_file = 0 $ resultd = f$parse("src_root:",,,,"NO_CONCEAL") $ resultd = f$edit(resultd, "LOWERCASE") $ resultd = resultd - "][" - "><" - ".;" - ".." $ resultd_len = f$length(resultd) - 1 $ delim = f$extract(resultd_len, 1, resultd) $ ref_root_base = mydir + delim $ resultd = resultd - ref_root_base - "reference." + "vms_source." $ ref = resultd + ref_base_dir $ wrk = "VMS_ROOT:" + odelim + wrk_base_dir $ resultd_len = f$length(resultd) - 1 $ resultd = f$extract(0, resultd_len, resultd) + delim $ ref_root_dir = f$parse(resultd,,,"DIRECTORY") $ ref_root_dir = f$edit(ref_root_dir, "LOWERCASE") $ ref_root_dir = ref_root_dir - "[" - "]" $ ref_base_dir = ref_root_dir + "." + ref_base_dir $ endif $! $ if p1 .eqs. "SRCBCK" $ then $ ref_base_dir = "curl" $ wrk_base_dir = "curl" $ ref = "src_root:[" + ref_base_dir $ wrk = "src_root1:[" + wrk_base_dir $ if update_file $ then $ if f$search("src_root1:[000000]curl.dir") .eqs. "" $ then $ create/dir/prot=o:rwed src_root1:[curl] $ endif $ endif $ endif $! $! $ if p1 .eqs. "VMSBCK" $ then $ ref_base_dir = "curl" $ wrk_base_dir = "curl" $ ref = "vms_root:[" + ref_base_dir $ wrk = "vms_root1:[" + wrk_base_dir $ if update_file $ then $ if f$search("vms_root1:[000000]curl.dir") .eqs. "" $ then $ create/dir/prot=o:rwed vms_root1:[curl] $ endif $ endif $ endif $! $! $ if ref .eqs. "" $ then $ write sys$output "Unknown compare type specified!" $ exit 44 $ endif $! $! $! Future - check the device types involved for the $! the syntax to check. $ ODS2_SYNTAX = 0 $ NFS_MANGLE = 0 $ PWRK_MANGLE = 0 $! $ vax = f$getsyi("HW_MODEL") .lt. 1024 $ if vax $ then $ ODS2_SYNTAX = 1 $ endif $! $ report_missing = 1 $! $ if .not. ODS2_SYNTAX $ then $ set proc/parse=extended $ endif $! $loop: $ ref_spec = f$search("''ref'...]*.*;",1) $ if ref_spec .eqs. "" then goto loop_end $! $ ref_dev = f$parse(ref_spec,,,"DEVICE") $ ref_dir = f$parse(ref_spec,,,"DIRECTORY") $ ref_dir = f$edit(ref_dir, "LOWERCASE") $ ref_name = f$parse(ref_spec,,,"NAME") $ ref_type = f$parse(ref_spec,,,"TYPE") $! $! $ rel_path = ref_dir - "[" - ref_base_dir $! rel_path_len = f$length(rel_path) - 1 $! delim = f$extract(rel_path_len, 1, rel_path) $! rel_path = rel_path - ".]" - ".>" - "]" - ">" $! rel_path = rel_path + delim $! $ if ODS2_SYNTAX $ then $! if rel_path .eqs. ".examples.scripts^.noah]" $! then $! rel_path = ".examples.scripts_noah]" $! endif $! if rel_path .eqs. ".examples.scripts^.v2]" $! then $! rel_path = ".examples.scripts_v2]" $! endif $ endif $! $ wrk_path = wrk + rel_path $! $ ref_name_type = ref_name + ref_type $! $ if ODS2_SYNTAX $ then $ endif $! $ wrk_spec = wrk_path + ref_name_type $! $! $ wrk_chk = f$search(wrk_spec, 0) $ if wrk_chk .eqs. "" $ then $ if report_missing $ then $ write sys$output "''wrk_spec' is missing" $ endif $ if update_file $ then $ copy/log 'ref_spec' 'wrk_spec' $ endif $ goto loop $ endif $! $ wrk_name = f$parse(wrk_spec,,,"NAME") $ wrk_type = f$parse(wrk_spec,,,"TYPE") $ wrk_fname = wrk_name + wrk_type" $ ref_fname = ref_name + ref_type $! $ if ref_fname .nes. wrk_fname $ then $ write sys$output "''wrk_spc' wrong name, should be ""''ref_fname'""" $ endif $! $ ref_type = f$edit(ref_type, "UPCASE") $ if ref_type .eqs. ".DIR" then goto loop $! $ if ODS2_SYNTAX $ then $ ref_fname = f$edit(ref_fname, "LOWERCASE") $ endif $! $! These files are in the wrong format for VMS diff, and we don't change them. $ ref_skip = 0 $ if ref_type .eqs. ".PDF" then ref_skip = 1 $ if ref_type .eqs. ".HTML" then ref_skip = 1 $ if ref_type .eqs. ".HQX" then ref_skip = 1 $ if ref_type .eqs. ".P12" then ref_skip = 1 $ if ref_type .eqs. "." $ then $ if f$locate("test", ref_fname) .eq. 0 then ref_skip = 1 $ if ref_fname .eqs. "configure." then ref_skip = 1 $ endif $ if ref_fname .eqs. "MACINSTALL.TXT" then ref_skip = 1 $ if ref_fname .eqs. "$macinstall.txt" then ref_skip = 1 $ if ref_fname .eqs. "curl.mcp$5nxml$5nsit$5nhqx" then ref_skip = 1 $ if ref_fname .eqs. "curl_GUSIConfig.cpp" then ref_skip = 1 $ if ref_fname .eqs. "curl_$gusic$onfig.cpp" then ref_skip = 1 $ if ref_fname .eqs. "macos_main.cpp" then ref_skip = 1 $! $! $ if ref_skip .ne. 0 $ then $ if report_missing $ then $ write sys$output "Skipping diff of ''ref_fname'" $ endif $ goto loop $ endif $! $! $ wrk_ver = f$parse(wrk_chk,,,"VERSION") $ if wrk_ver .nes. ";1" $ then $ write sys$output "Version for ''wrk_spec' is not 1" $ endif $ set noon $ diff/out=nl: 'wrk_spec' 'ref_spec' $ if $severity .nes. "1" $ then $ write sys$output "''wrk_spec' is different from ''ref_spec'" $ if update_file $ then $ delete 'wrk_spec';* $ copy/log 'ref_spec' 'wrk_spec' $ endif $ endif $ set on $ $! $ goto loop $loop_end: $! $! $missing_loop: $! For missing loop, check the latest generation. $ ref_spec = f$search("''wrk'...]*.*;") $ if ref_spec .eqs. "" then goto missing_loop_end $! $ ref_dev = f$parse(ref_spec,,,"DEVICE") $ ref_dir = f$parse(ref_spec,,,"DIRECTORY") $ ref_dir = f$edit(ref_dir, "LOWERCASE") $ ref_name = f$parse(ref_spec,,,"NAME") $ ref_type = f$parse(ref_spec,,,"TYPE") $ ref_name_type = ref_name + ref_type $! $ rel_path = ref_dir - "[" - wrk_base_dir $! $! $ wrk_path = ref + rel_path $ wrk_spec = wrk_path + ref_name + ref_type $ wrk_name = f$parse(wrk_spec,,,"NAME") $ wrk_type = f$parse(wrk_spec,,,"TYPE") $! $ wrk_fname = wrk_name + wrk_type" $ ref_fname = ref_name + ref_type $! $ wrk_skip = 0 $ ref_utype = f$edit(ref_type,"UPCASE") $ ref_ufname = f$edit(ref_fname,"UPCASE") $! $ if wrk_skip .eq. 0 $ then $ wrk_chk = f$search(wrk_spec, 0) $ if wrk_chk .eqs. "" $ then $ if report_missing $ then $ write sys$output "''wrk_spec' is missing" $ endif $ goto missing_loop $ endif $ else $ goto missing_loop $ endif $! $ if ref_fname .nes. wrk_fname $ then $ write sys$output "''wrk_spc' wrong name, should be ""''ref_fname'""" $ endif $! $ if ref_utype .eqs. ".DIR" then goto missing_loop $! $ wrk_ver = f$parse(wrk_chk,,,"VERSION") $ if wrk_ver .nes. ";1" $ then $ write sys$output "Version for ''wrk_spec' is not 1" $ endif $! $ goto missing_loop $! $! $missing_loop_end: $! $exit davix-0.8.0/deps/curl/packages/vms/gnv_link_curl.com0000644000000000000000000006175314121063461021161 0ustar rootroot$! File: gnv_link_curl.com $! $! $Id$ $! $! File to build images using gnv$libcurl.exe $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 10-Jun-2009 J. Malmberg $!============================================================================ $! $! Save this so we can get back. $ default_dir = f$environment("default") $ define/job gnv_packages_vms 'default_dir' $! $ on warning then goto all_exit $! $! On VAX, we need to generate a Macro transfer vector. $ parse_style = "TRADITIONAL" $ if (f$getsyi("HW_MODEL") .lt. 1024) $ then $ @generate_vax_transfer.com $ arch_name = "VAX" $ else $ arch_name = "" $ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") $ if (arch_name .eqs. "") then arch_name = "UNK" $! $! Extended parsing option starts with VMS 7.3-1. $! There is no 7.4, so that simplifies the parse a bit. $! $ node_swvers = f$getsyi("node_swvers") $ version_patch = f$extract(1, f$length(node_swvers), node_swvers) $ maj_ver = f$element(0, ".", version_patch) $ min_ver_patch = f$element(1, ".", version_patch) $ min_ver = f$element(0, "-", min_ver_patch) $ patch = f$element(1, "-", min_ver_patch) $ if patch .eqs. "-" then patch = "" $ parse_x = 0 $ if maj_ver .ges. "8" $ then $ parse_x = 1 $ else $ if maj_ver .eqs. "7" .and. min_ver .ges. "3" .and. patch .nes. "" $ then $ parse_x = 1 $ endif $ endif $ if parse_x $ then $ parse_style = f$getjpi("", "parse_style_perm") $ endif $ endif $! $! $! Move to where the base directories. $ set def [--] $! $! $! Build the Message file. $!-------------------------- $ if f$search("[.packages.vms]curlmsg.obj") .eqs. "" $ then $ message [.packages.vms]curlmsg.msg/object=[.packages.vms] $ endif $ if f$search("gnv$curlmsg.exe") .eqs. "" $ then $ link/share=gnv$curlmsg.exe [.packages.vms]curlmsg.obj $ endif $! $! $! Need to build the common init module. $!------------------------------------------- $ cflags = "/list/show=(expan,includ)" $ init_obj = "[.packages.vms]curl_crtl_init.obj" $ if f$search(init_obj) .eqs. "" $ then $ cc'cflags' 'default_dir'curl_crtl_init.c/obj='init_obj' $ endif $ purge 'init_obj' $ rename 'init_obj' ;1 $! $! $! Need to build the module to test the HP OpenSSL version $!-------------------------------------------------------- $ if arch_name .nes. "VAX" $ then $ rpt_obj = "[.packages.vms]report_openssl_version.obj $ if f$search(rpt_obj) .eqs. "" $ then $ cc'cflags' 'default_dir'report_openssl_version.c/obj='rpt_obj' $ endif $ purge 'rpt_obj' $ rename 'rpt_obj' ;1 $! $ link/exe='default_dir'report_openssl_version.exe 'rpt_obj' $ report_openssl_version := $'default_dir'report_openssl_version.exe $ endif $! $! $ base_link_opt_file = "[.packages.vms.''arch_name']gnv_libcurl_linker.opt" $ share_link_opt_file = "[.packages.vms.''arch_name']gnv_ssl_libcurl_linker.opt" $ if f$search(base_link_opt_file) .eqs. "" $ then $ base_link_opt_file = "[.packages.vms]gnv_libcurl_linker.opt" $ share_link_opt_file = "[.packages.vms]gnv_ssl_libcurl_linker.opt" $ if f$search(base_link_opt_file) .eqs. "" $ then $ write sys$output "Can not find base library option file!" $ goto all_exit $ endif $ endif $! $! Create the a new option file with special fixup for HP SSL $! For a shared image, we always want ZLIB and 32 bit HPSSL $! $ if f$search("gnv$libzshr32") .eqs. "" $ then $ write sys$output "VMSPORTS/GNV LIBZ Shared image not found!" $ goto all_exit $ endif $! $! $! Need to check the version of the HP SSL shared image. $! $! VAX platform can not be checked this way, it appears symbol lookup $! was disabled. VAX has not been updated in a while. $ if arch_name .eqs. "VAX" $ then $ hp_ssl_libcrypto32 = "sys$common:[syslib]ssl$libcrypto_shr32.exe" $ hp_ssl_libssl32 = "sys$common:[syslib]ssl$libssl_shr32.exe" $ if f$search(hp_ssl_libcrypto32) .nes. "" $ then $ use_hp_ssl = 1 $ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 $ curl_ssl_libssl32 = hp_ssl_libssl32 $ curl_ssl_version = "OpenSSL/0.9.6g" $ else $ write sys$output "HP OpenSSL Shared images not found!" $ goto all_exit $ endif $ else $! $! Minimum HP version we can use reports: $! "OpenSSL 0.9.8w 23 Apr 2012" $! $ use_hp_ssl = 0 $ hp_ssl_libcrypto32 = "sys$share:ssl$libcrypto_shr32.exe" $ hp_ssl_libssl32 = "sys$share:ssl$libssl_shr32.exe" $ if f$search(hp_ssl_libcrypto32) .nes. "" $ then $ curl_ssl_libcrypto32 = hp_ssl_libcrypto32 $ curl_ssl_libssl32 = hp_ssl_libssl32 $ report_openssl_version 'hp_ssl_libcrypto32' hp_ssl_version $ endif $! $ if f$type(hp_ssl_version) .eqs. "STRING" $ then $ curl_ssl_version = hp_ssl_version $ full_version = f$element(1, " ", hp_ssl_version) $ ver_maj = f$element(0, ".", full_version) $ ver_min = f$element(1, ".", full_version) $ ver_patch = f$element(2, ".", full_version) $! ! ver_patch is typically both a number and some letters $ ver_patch_len = f$length(ver_patch) $ ver_patchltr = "" $ver_patch_loop: $ ver_patchltr_c = f$extract(ver_patch_len - 1, 1, ver_patch) $ if ver_patchltr_c .les. "9" then goto ver_patch_loop_end $ ver_patchltr = ver_patchltr_c + ver_patchltr $ ver_patch_len = ver_patch_len - 1 $ goto ver_patch_loop $ver_patch_loop_end: $ ver_patchnum = ver_patch - ver_patchltr $ if 'ver_maj' .ge. 0 $ then $ if 'ver_min' .ge. 9 $ then $ if 'ver_patchnum' .ge. 8 $ then $ if ver_patchltr .ges. "w" then use_hp_ssl = 1 $ endif $ endif $ endif $set nover $ if use_hp_ssl .eq. 0 $ then $ write sys$output - " HP OpenSSL version of ""''hp_ssl_version'"" is too old for shared libcurl!" $ endif $ else $ write sys$output "Unable to get version of HP OpenSSL" $ endif $! $ gnv_ssl_libcrypto32 = "gnv$gnu:[lib]ssl$libcrypto_shr32.exe" $ gnv_ssl_libssl32 = "gnv$gnu:[lib]ssl$libssl_shr32.exe" $ if f$search(gnv_ssl_libcrypto32) .nes. "" $ then $ report_openssl_version 'gnv_ssl_libcrypto32' gnv_ssl_version $ endif $! $ use_gnv_ssl = 0 $ if f$type(gnv_ssl_version) .eqs. "STRING" $ then $ gnv_full_version = f$element(1, " ", gnv_ssl_version) $ gnv_ver_maj = f$element(0, ".", gnv_full_version) $ gnv_ver_min = f$element(1, ".", gnv_full_version) $ gnv_ver_patch = f$element(2, ".", gnv_full_version) $ gnv_ver_patch_len = f$length(gnv_ver_patch) $ gnv_ver_patchnum = f$extract(0, gnv_ver_patch_len - 1, gnv_ver_patch) $ gnv_ver_patchltr = f$extract(gnv_ver_patch_len - 1, 1, gnv_ver_patch) $ if 'gnv_ver_maj' .ge. 0 $ then $ if 'gnv_ver_min' .ge. 9 $ then $ if 'gnv_ver_patchnum' .ge. 8 $ then $ if gnv_ver_patchltr .ges. "w" then use_gnv_ssl = 1 $ endif $ endif $ endif $ if use_gnv_ssl .eq. 0 $ then $ write sys$output - "GNV OpenSSL version of ""''gnv_ssl_version'" is too old for shared libcurl!" $ endif $! $! Prefer to break the tie with the lowest supported version $! For simplicity, if the GNV image is present, it will be used. $! Version tuple is not a simple compare. $! $ if use_gnv_ssl .eq. 1 then $ curl_ssl_libcrypto32 = gnv_ssl_libcrypto32 $ curl_ssl_libssl32 = gnv_ssl_libssl32 $ curl_ssl_version = gnv_ssl_version $ use_hp_ssl = 0 $ endif !$! $ else $ write sys$output "Unable to get version of GNV OpenSSL" $ endif $! $! Need to write a release note section about HP OpenSSL $! $create 'default_dir'hp_ssl_release_info.txt $deck This package is built on with the OpenSSL version listed below and requires the shared images from the HP OpenSSL product that is kitted with that version or a compatible later version. For Alpha and IA64 platforms, see the url below to register to get the download URL. The kit will be HP 1.4-467 or later. https://h41379.www4.hpe.com/openvms/products/ssl/ssl.html For VAX, use the same registration, but remove the kit name from any of the download URLs provided and put in CPQ-VAXVMS-SSL-V0101-B-1.PCSI-DCX_VAXEXE If your system can not be upgraded to a compatible version of OpenSSL, then you can extract the two shared images from the kit and place them in the [vms$common.gnv.lib]directory of the volume that you are installing GNV and or GNV compatible components like Curl. If GNV is installed, you must run the GNV startup procedure before these steps and before installing Curl. 1. make sure that [vms$common.gnv.lib] exists by using the following commands. We want the directory to be in lowercase except on VAX. $SET PROCESS/PARSE=extend !If not VAX. $CREATE/DIR device:[vms$common.gnv.lib]/prot=w:re 2. Extract the ssl$crypto_shr32.exe and ssl$libssl_shr32.exe images. $PRODUCT EXTRACT FILE - /select=(ssl$libcrypto_shr32.exe,ssl$libssl_shr32.exe)- /source=device:[dir] - /options=noconfirm - /destination=device:[vms$common.gnv.lib] SSL The [vms$common.sys$startup}curl_startup.com procedure will then configure libcurl to use these shared images instead of the system ones. When you upgrade SSL on VMS to the newer version of HP SSL, then these copies should be deleted. $eod $! $ open/append sslr 'default_dir'hp_ssl_release_info.txt $ write sslr "OpenSSL version used for building this kit: ",curl_ssl_version $ write sslr "" $ close sslr $! $! $! LIBZ $ libzshr_line = "" $ try_shr = "gnv$libzshr32" $ if f$search(try_shr) .nes. "" $ then $ libzshr_line = "''try_shr'/share" $ else $ write sys$output "''try_shr' image not found!" $ goto all_exit $ endif $! $! $ gssrtlshr_line = "" $ if arch_name .nes. "VAX" $ then $ try_shr = "sys$share:gss$rtl" $ if f$search("''try_shr'.exe") .nes. "" $ then $ gssrtlshr_line = "''try_shr'/share" $ else $ write sys$output "''try_shr' image not found!" $ goto all_exit $ endif $ endif $! $! $! $ if f$search(share_link_opt_file) .eqs. "" $ then $ create 'share_link_opt_file' $ open/append slopt 'share_link_opt_file' $ if libzshr_line .nes. "" then write slopt libzshr_line $ if gssrtlshr_line .nes. "" then write slopt gssrtlshr_line $ write slopt "gnv$curl_ssl_libcryptoshr32/share" $ write slopt "gnv$curl_ssl_libsslshr32/share" $ close slopt $ endif $! $! DCL build puts curllib in architecture directory $! GNV build uses the makefile. $ libfile = "[.packages.vms.''arch_name']curllib.olb" $ if f$search(libfile) .nes. "" $ then $ olb_file = libfile $ else $ ! GNV based build $ libfile = "[.lib.^.libs]libcurl.a" $ if f$search(libfile) .nes. "" $ then $ olb_file = libfile $ else $ write sys$output - "Can not build shared image, libcurl object library not found!" $ goto all_exit $ endif $ endif $! $gnv_libcurl_share = "''default_dir'gnv$libcurl.exe" $! $ if f$search(gnv_libcurl_share) .eqs. "" $ then $ if arch_name .nes. "VAX" $ then $ define/user gnv$curl_ssl_libcryptoshr32 'curl_ssl_libcrypto32' $ define/user gnv$curl_ssl_libsslshr32 'curl_ssl_libssl32' $ link/dsf='default_dir'gnv$libcurl.dsf/share='gnv_libcurl_share' - /map='default_dir'gnv$libcurl.map - gnv_packages_vms:gnv_libcurl_symbols.opt/opt,- 'olb_file'/lib,- 'share_link_opt_file'/opt $ else $! VAX will not allow the logical name hack for the $! SSL libcryto library, it is pulling it in twice if I try it. $ link/share='gnv_libcurl_share'/map='default_dir'gnv$libcurl.map - gnv_packages_vms:gnv_libcurl_xfer.opt/opt,- 'olb_file'/lib,- 'base_link_opt_file'/opt $ endif $ endif $! $! $ if f$search("[.src]curl-tool_main.o") .nes. "" $ then $! From src/makefile.inc: $! # libcurl has sources that provide functions named curlx_* that aren't $! # part of the official API, but we re-use the code here to avoid $! # duplication. $! $! $ if f$search("[.src]curl.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.src]curl.exe/dsf=[.src]curl.dsf - [.src]curl-tool_main.o, [.src]curl-tool_binmode.o, - [.src]curl-tool_bname.o, [.src]curl-tool_cb_dbg.o, - [.src]curl-tool_cb_hdr.o, [.src]curl-tool_cb_prg.o, - [.src]curl-tool_cb_rea.o, [.src]curl-tool_cb_see.o, - [.src]curl-tool_cb_wrt.o, [.src]curl-tool_cfgable.o, - [.src]curl-tool_convert.o, [.src]curl-tool_dirhie.o, - [.src]curl-tool_doswin.o, [.src]curl-tool_easysrc.o, - [.src]curl-tool_formparse.o, [.src]curl-tool_getparam.o, - [.src]curl-tool_getpass.o, [.src]curl-tool_help.o, - [.src]curl-tool_helpers.o, [.src]curl-tool_homedir.o, - [.src]curl-tool_hugehelp.o, [.src]curl-tool_libinfo.o, - [.src]curl-tool_metalink.o, [.src]curl-tool_mfiles.o, - [.src]curl-tool_msgs.o, [.src]curl-tool_operate.o, - [.src]curl-tool_operhlp.o, [.src]curl-tool_panykey.o, - [.src]curl-tool_paramhlp.o, [.src]curl-tool_parsecfg.o, - [.src]curl-tool_setopt.o, [.src]curl-tool_sleep.o, - [.src]curl-tool_urlglob.o, [.src]curl-tool_util.o, - [.src]curl-tool_vms.o, [.src]curl-tool_writeenv.o, - [.src]curl-tool_writeout.o, [.src]curl-tool_xattr.o, - [.src]curl-strtoofft.o, [.src]curl-strdup.o, [.src]curl-strcase.o, - [.src]curl-nonblock.o, gnv_packages_vms:curlmsg.obj,- sys$input:/opt gnv$libcurl/share gnv_packages_vms:curl_crtl_init.obj $ endif $ else $ curl_exe = "[.src]curl.exe" $ curl_dsf = "[.src]curl.dsf" $ curl_main = "[.packages.vms.''arch_name']tool_main.obj" $ curl_src = "[.packages.vms.''arch_name']curlsrc.olb" $ curl_lib = "[.packages.vms.''arch_name']curllib.olb" $ strcase = "strcase" $ nonblock = "nonblock" $ warnless = "warnless" $! $! Extended parse style requires special quoting $! $ if (arch_name .nes. "VAX") .and. (parse_style .eqs. "EXTENDED") $ then $ strcase = """strcase""" $ nonblock = """nonblock""" $ warnless = """warnless""" $ endif $ if f$search(curl_exe) .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe='curl_exe'/dsf='curl_dsf' - 'curl_main','curl_src'/lib, - 'curl_lib'/library/include=- ('strcase','nonblock','warnless'),- gnv_packages_vms:curlmsg.obj,- sys$input:/opt gnv$libcurl/share gnv_packages_vms:curl_crtl_init.obj $ endif $ endif $! $! $! $! in6addr_missing so skip building: $! [.server]sws.o $! [.server]sockfilt.o $! [.server]tftpd.o $! $! $ target = "10-at-a-time" $ if f$search("[.docs.examples]''target'.o") .eqs. "" $ then $ write sys$output "examples not built" $ goto all_exit $ endif $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "anyauthput" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "certinfo" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "cookie_interface" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "debug" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "fileupload" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $ target = "fopen" $ if f$search("[.docs.examples]''target'.exe") .eqs. "" $ then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $ endif $! $! $target = "ftpget" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "ftpgetresp" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "ftpupload" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "getinfo" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "getinmemory" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "http-post" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "httpcustomheader" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "httpput" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "https" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "multi-app" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "multi-debugcallback" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "multi-double" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "multi-post" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "multi-single" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "persistent" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "post-callback" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "postit2" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "sendrecv" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "sepheaders" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "simple" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "simplepost" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! $target = "simplessl" $if f$search("[.docs.examples]''target'.exe") .eqs. "" $then $ define/user gnv$libcurl 'gnv_libcurl_share' $ link'ldebug'/exe=[.docs.examples]'target'.exe- /dsf=[.docs.examples]'target'.dsf - [.docs.examples]'target'.o,- gnv$'target'.opt/opt,- sys$input:/opt gnv$libcurl/share $endif $! $! =============== End of docs/examples ========================= $! $! $all_exit: $set def 'default_dir' $exit '$status' $! davix-0.8.0/deps/curl/packages/vms/readme0000644000000000000000000002166314121063461017001 0ustar rootroot _ _ ____ _ ___| | | | _ \| | / __| | | | |_) | | ( (__| |_| | _ <| |___ \___|\___/|_| \_\_____| for OpenVMS History: 9-MAR-2004, Created this readme. file. Marty Kuhrt (MSK). 15-MAR-2004, MSK, Updated to reflect the new files in this directory. 14-FEB-2005, MSK, removed config-vms.h_with* file comments 10-FEB-2010, SMS. General update. 14-Jul-2013, JEM, General Update, add GNV build information. The release notes installed by the PCSI kit consist of this file and the curl_gnv_build_steps.txt and other useful information. Prerequisites: OpenVMS V7.0 or later (any platform) DECC V6.5 or later OpenSSL or hp SSL, if you want SSL support What is Here: This directory contains the following files for a DCL based build. backup_gnv_curl_src.com This procedure backs up the source modules for creating a PCSI kit. build_curl-config_script.com Procedure to create the curl-config script. build_gnv_curl.com This procedure does a build of curl using the GNV utilities and then uses DCL tools to build the libcurl shared image. The setup_gnv_curl_build.com procedure must be run first. build_gnv_curl_pcsi_desc.com This procedure builds the pcsi$desc file for creating a PCSI based package. build_gnv_curl_pcsi_text.com This procedure builds the pcsi$text file for creating a PCSI based package. build_gnv_curl_release_notes.com This procedure creates the release notes for a PCSI kit based on curl_release_note_start.txt, this readme file, and the curl_gnv_build_steps.txt build_libcurl_pc.com Procedure to create a libcurl.pc file. build_vms.com DCL based build procedure. clean_gnv_curl.com This procedure cleans up the files generated by a GNV based build. config_h.com DCL based procedure used by build_vms.com to run generate the curl_config.h file. This is a generic procedure that does most of the work for generating config.h files. compare_curl_source.com Procedure to compare the working directory with a repository directory or a backup staging directory. curl_crtl_init.c A special pre-initialization routine to for programs to behave more Unix like when run under GNV. curl_gnv_build_steps.txt Detailed instructions on how to built curl using GNV and how to build the libcurl shared image and PCSI kit. curl_release_note_start.txt The first part of the curl release notes. curl_startup.com A procedure run at VMS startup to install the libcurl shared image and to set up the needed logical names. curlmsg.h C header defining curl status code macros. curlmsg.msg Error message source for curlmsg.h and curlmsg.sdl. curlmsg.sdl SDL source defining curl status code constants. curlmsg_vms.h Mapping of curl status codes to VMS-form codes. generate_config_vms_h_curl.com DCL procedure to generate the curl specific definitions for curl_config.h that config_h.com can not properly generate. generate_vax_transfer.com DCL procedure to read an Alpha/IA64 symbol vector linker option file and generate the VAX transfer vector modules. gnv_conftest.c_first A helper file for the configure script. gnv_curl_configure.sh A script to run the configure script with the options needed for VMS. gnv_libcurl_symbols.opt The symbol vectors needed for Alpha and IA64 libcurl shared image. gnv_link_curl.com Links the libcurl shared image and then links a curl image to use the libcurl. macro32_exactcase.patch The patch file needed to modify VAX Macro32 to be case sensitive and case preserving. Makefile.am curl kit file list for this directory. Makefile.in curl kit makefile source for this directory. make_gnv_curl_install.sh Script to do a make install using GNV after running the configure script. make_pcsi_curl_kit_name.com This generates the name of the PCSI kit based on the version of curl being built. pcsi_gnv_curl_file_list.txt This is a text file describing what files should be included in a PCSI kit. pcsi_product_gnv_curl.com This generates the PCSI kit after the libcurl shared image has been made. readme. This file. report_openssl_version.c Program to check that the openssl version is new enough for building a shared libcurl image. setup_gnv_curl_build.com This procedure sets up symbols and logical names for a GNV build environment and also copies some helper files. stage_curl_install.com This procedure sets up new_gnu: directory tree to for testing the install and building the PCSI kit. It takes a "remove" option to remove all the staged files. vms_eco_level.h This sets the ECO level for the PCSI kit name. How to Build: The GNV based build and the DCL based build procedures are not compatible and you must make sure that none of the build files are present before running a different type of build. Use the "REALCLEAN" option for BUILD_VMS.COM and the "REALCLEAN" option for clean_gnv_curl.com. The (brute-force) DCL based builder is [.packages.vms]build_vms.com. Comments in this procedure describe various optional parameters which enable or disable optional program features, or which control the build in other ways. Product files (.EXE, .H, .LIS, .MAP, .OBJ, .OLB, ...) should be produced in an architecture-specific subdirectory under this directory ([.ALPHA], [.IA64], [.VAX]). The file curl_gnv_build_steps.txt contains information on buildling using the GNV tool kit, building a shared libcurl, and producting a PCSI kit for distribution. The curl_gnv_build_steps.text is included in the release notes file of the PCSI kit. The building with 64 bit pointers does not currently work. The build procedure will detect if HP OpenSSL, LDAP, and Kerberos are installed and default to building with them. The build procedure will also detect if a compatible ZLIB shared image is installed from a PCSI kit and default to using it. Example build commands: @ [.packages.vms]build_vms.com CLEAN @ [.packages.vms]build_vms.com LARGE LDAP submit /noprint [.packages.vms]build_vms.com /param = (LARGE, LDAP) The build_vms.com procedure does not build the shared image file or the PCSI kit. If you have built a curl with ZLIB and HPSSL support as well as if LDAP and Kerberos installed, you can use the GNV_LINK_CURL.COM file. The GNV_LINK_CURL.COM contains information on how to link and run with a newer version of HP SSL than what may be install on an Alpha or IA64 based system. To build the PCSI kit, follow the instructions in the file curl_gnv_build_steps.txt. Other Notes: This release fixes known bugs #22, and #57 in the [curl.docs]known_bugs. file. The libcurl formdata.c module and Curl tools post form now have some understanding of VMS file types. Files will be posted in STREAM_LF format. The Curl tool now has some understanding of VMS file types and will upload the files in STREAM_LF format. When CURL is uploading a VARIABLE format VMS file, it is less efficient as in order to get the file size, it will first read the entire file once, and then read the file again for the actual upload. The Curl tool will now always download files into STREAM_LF format. Even if a file by that name with a different format already exists. This is needed to allow interrupted downloads to be continued. The libcurl file module still does not understand VMS file types and requires the input files to be in STREAM_LF to work property. The test suites are not supported as of 7.11.0. The curlmsg.sdl and curlmsg.h files are generated from curlmsg.msg. This is not done automatically, since the .MSG file is a hand edit of the relevant stuff from the curl.h file. If you want to do this yourself you'll need the SDL package from the freeware collection. davix-0.8.0/deps/curl/packages/vms/pcsi_product_gnv_curl.com0000644000000000000000000001301214121063461022703 0ustar rootroot$! File: PCSI_PRODUCT_GNV_CURL.COM $! $! $Id$ $! $! This command file packages up the product CURL into a sequential $! format kit $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 16-Jun-2009 J.Malmberg $! $!========================================================================= $! $! Save default $ default_dir = f$environment("DEFAULT") $! $! Put things back on error. $ on warning then goto all_exit $! $! $ can_build = 1 $ producer = f$trnlnm("GNV_PCSI_PRODUCER") $ if producer .eqs. "" $ then $ write sys$output "GNV_PCSI_PRODUCER logical name has not been set." $ can_build = 0 $ endif $ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") $ if producer_full_name .eqs. "" $ then $ write sys$output - "GNV_PCSI_PRODUCER_FULL_NAME logical name has not been set." $ can_build = 0 $ endif $ stage_root_name = f$trnlnm("STAGE_ROOT") $ if stage_root_name .eqs. "" $ then $ write sys$output "STAGE_ROOT logical name has not been set." $ can_build = 0 $ endif $! $ if (can_build .eq. 0) $ then $ write sys$output "Not able to build a kit." $ goto all_exit $ endif $! $! Make sure that the kit name is up to date for this build $!---------------------------------------------------------- $ @MAKE_PCSI_CURL_KIT_NAME.COM $! $! $! Make sure that the image is built $!---------------------------------- $ arch_name = f$edit(f$getsyi("arch_name"),"UPCASE") $ if f$search("[--.src]curl.exe") .eqs. "" $ then $ build_it = 1 $ libfile = "[.packages.vms.''arch_name']curllib.olb" $ if f$search(libfile) .nes. "" $ then $ build_it = 0 $ else $ ! GNV based build $ libfile = "[.lib.^.libs]libcurl.a" $ if f$search(libfile) .nes. "" $ then $ build_it = 0; $ endif $ endif $ if build_it .eq. 1 $ then $ @build_vms list $ endif $ @gnv_link_curl.com $ endif $! $! Make sure that the release note file name is up to date $!--------------------------------------------------------- $ @BUILD_GNV_CURL_RELEASE_NOTES.COM $! $! $! Make sure that the source has been backed up. $!---------------------------------------------- $ arch_type = f$getsyi("ARCH_NAME") $ arch_code = f$extract(0, 1, arch_type) $ @backup_gnv_curl_src.com $! $! Regenerate the PCSI description file. $!-------------------------------------- $ @BUILD_GNV_CURL_PCSI_DESC.COM $! $! Regenerate the PCSI Text file. $!--------------------------------- $ @BUILD_GNV_CURL_PCSI_TEXT.COM $! $! $! Parse the kit name into components. $!--------------------------------------- $ kit_name = f$trnlnm("GNV_PCSI_KITNAME") $ if kit_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ producer = f$element(0, "-", kit_name) $ base = f$element(1, "-", kit_name) $ product_name = f$element(2, "-", kit_name) $ mmversion = f$element(3, "-", kit_name) $ majorver = f$extract(0, 3, mmversion) $ minorver = f$extract(3, 2, mmversion) $ updatepatch = f$element(4, "-", kit_name) $ if updatepatch .eqs. "" then updatepatch = "" $! $ version_fao = "!AS.!AS" $ mmversion = f$fao(version_fao, "''majorver'", "''minorver'") $ if updatepatch .nes. "" $ then $ version = "''mmversion'" + "-" + updatepatch $ else $ version = "''mmversion'" $ endif $! $ @stage_curl_install remove $ @stage_curl_install $! $! Move to the base directories $ set def [--] $ current_default = f$environment("DEFAULT") $ my_dir = f$parse(current_default,,,"DIRECTORY") - "[" - "<" - ">" - "]" $! $! $! $ source = "''default_dir'" $ src1 = "new_gnu:[usr.bin]," $ src2 = "new_gnu:[usr.include.curl]," $ src3 = "new_gnu:[usr.lib]," $ src4 = "new_gnu:[usr.lib.pkgconfig]," $ src5 = "new_gnu:[usr.share.man.man1]," $ src6 = "new_gnu:[usr.share.man.man3]," $ src7 = "new_gnu:[vms_src]," $ src8 = "new_gnu:[common_src]," $ src9 = "prj_root:[''my_dir'],prj_root:[''my_dir'.src]" $ gnu_src = src1 + src2 + src3 + src4 + src5 + src6 + src7 + src8 + src9 $! $! $ base = "" $ if arch_name .eqs. "ALPHA" then base = "AXPVMS" $ if arch_name .eqs. "IA64" then base = "I64VMS" $ if arch_name .eqs. "VAX" then base = "VAXVMS" $! $ if base .eqs. "" then exit 44 $! $ pcsi_option = "/option=noconfirm" $ if arch_code .eqs. "V" $ then $ pcsi_option = "" $ endif $! $! $product package 'product_name' - /base='base' - /producer='producer' - /source='source' - /destination=STAGE_ROOT:[KIT] - /material=('gnu_src','source') - /format=sequential 'pcsi_option' $! $! $! VAX can not do a compressed kit. $! ZIP -9 "-V" does a better job, so no reason to normally build a compressed $! kit. $!---------------------------------- $if p1 .eqs. "COMPRESSED" $then $ if arch_code .nes. "V" $ then $ product copy /options=(novalidate, noconfirm) /format=compressed - 'product_name' - /source=stage_root:[kit]/dest=stage_root:[kit] - /version='version'/base='base' $ endif $endif $! $all_exit: $ set def 'default_dir' $ exit davix-0.8.0/deps/curl/packages/vms/build_curl-config_script.com0000644000000000000000000001115014121063461023262 0ustar rootroot$! build_curl-config_script.com $! $! This generates the curl-config. script from the curl-config.in file. $! $! Copyright 2014, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 16-Dec-2014 J. Malmberg $! $!=========================================================================== $! $! Skip this if the curl-config. already exists. $ if f$search("[--]curl-config.") .nes. "" then goto all_exit $! $ if (f$getsyi("HW_MODEL") .lt. 1024) $ then $ arch_name = "VAX" $ else $ arch_name = "" $ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") $ if (arch_name .eqs. "") then arch_name = "UNK" $ endif $! $ x_prefix = "/usr" $ x_exec_prefix = "/usr" $ x_includedir = "${prefix}/include" $ x_cppflag_curl_staticlib = "-DCURL_STATICLIB" $ x_enabled_shared = "no" $ x_curl_ca_bundle = "" $ x_cc = "cc" $ x_support_features = "SSL IPv6 libz NTLM" $ x_support_protocols1 = "DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP" $ x_support_protocols2 = " LDAPS POP3 POP3S RTSP SMTP SMTPS TELNET TFTP" $ x_support_protocols = x_support_protocols1 + x_support_protocols2 $ x_curlversion = "0.0.0.0" $ x_versionnum = "" $ x_libdir = "${prefix}/lib" $ x_require_lib_deps = "" $ x_enable_static = "" $ x_ldflags = "" $ part1 = "-L/usr/lib -L/SSL_LIB -lssl -lcrypto -lz" $ if arch_name .eqs. "VAX" $ then $ x_libcurl_libs = part1 $ else $ x_libcurl_libs = part1 + " -lgssapi" $ endif $ x_libext = "a" $! $! Get the version number $!----------------------- $ i = 0 $ open/read/error=version_loop_end vhf [--.include.curl]curlver.h $ version_loop: $ read/end=version_loop_end vhf line_in $ if line_in .eqs. "" then goto version_loop $ if f$locate("#define LIBCURL_VERSION ", line_in) .eq. 0 $ then $ x_curlversion = f$element(2," ", line_in) - """" - """" $ i = i + 1 $ endif $ if f$locate("#define LIBCURL_VERSION_NUM ", line_in) .eq. 0 $ then $ x_versionnum = f$element(2," ", line_in) - """" - """" $ i = i + 1 $ endif $ if i .lt 2 then goto version_loop $ version_loop_end: $ close vhf $! $ kit_type = "V" $ if f$locate("-", x_curlversion) .lt. f$length(x_curlversion) $ then $ kit_type = "D" $ x_prefix = "/beta" $ x_exec_prefix = "/beta" $ endif $! $ if kit_type .nes. "D" $ then $ part1 = " echo "" '--prefix=/usr' '--exec-prefix=/usr' " $ else $ part1 = " echo "" '--prefix=/beta' '--exec_prefix=/beta' " $ endif $ if arch_name .eqs. "VAX" $ then $ part3 = "" $ else $ part3 = "'--with-gssapi' " $ endif $ part2 = "'--disable-dependency-tracking' '--disable-libtool-lock' " $ part4 = "'--disable-ntlm-wb' '--with-ca-path=gnv$curl_ca_path'""" $! $ x_configure_options = part1 + part2 + part3 + part4 $! $! $ open/read/error=read_loop_end c_c_in sys$disk:[--]curl-config.in $ create sys$disk:[--]curl-config. $ open/append c_c_out sys$disk:[--]curl-config. $read_loop: $ read/end=read_loop_end c_c_in line_in $ line_in_len = f$length(line_in) $ if f$locate("@", line_in) .ge. line_in_len $ then $ write c_c_out line_in $ goto read_loop $ endif $ i = 0 $ line_out = "" $sub_loop: $ ! Replace between pairs of @ by alternating the elements. $ ! If mis-matched pairs, do not substitute anything. $ section1 = f$element(i, "@", line_in) $ if section1 .eqs. "@" $ then $ goto sub_loop_end $ endif $ i = i + 1 $ section2 = f$element(i, "@", line_in) $ if section2 .eqs. "@" $ then $ goto sub_loop_end $ endif $ i = i + 1 $ section3 = f$element(i, "@", line_in) $ if section3 .eqs. "@" $ then $ if line_out .eqs. "" then line_out = line_in $ goto sub_loop_end $ endif $ line_out = line_out + section1 $ if f$type(x_'section2') .eqs. "STRING" $ then $ line_out = line_out + x_'section2' $ endif $ goto sub_loop $sub_loop_end: $ write c_c_out line_out $ goto read_loop $read_loop_end: $ close c_c_in $ close c_c_out davix-0.8.0/deps/curl/packages/vms/curl_release_note_start.txt0000644000000000000000000000634014121063461023264 0ustar rootrootFrom file: CURL_RELEASE_NOTE_START.TXT Note: These kits are produced by a hobbyist and are providing any support or any commitment to supply bug fixes or future releases. This code is as-is with no warrantees. The testing of this build of curl was minimal and involved building some of the sample and test programs, accessing a public HTTPS: website, doing a form post of some VMS test files, and FTP upload of some text files. Due to the way that PCSI identifies packages, if you install a package from one producer and then want to upgrade it from another producer, you will probably need to uninstall the previous package first. OpenVMS specific building and kitting instructions are after the standard curl readme file. This product may be available for your platform in a PCSI kit. The source kit contains files for building CURL using GNV or with a DCL procedure. The GNV based build creates a libcurl share imaged which is supplied in the PCSI kit. This version of CURL will return VMS compatible status codes when run from DCL and Unix compatible exit codes and messages when run with the SHELL environment variable set. This port of Curl uses the OpenSSL, Ldap, and Kerberos V5 that are bundled with OpenVMS or supplied as updates by HP. Ldap and Kerberos are not available on the VAX platform. See section below for a special note about HP OpenSSL on Alpha and IA64. The supplied CURL_STARTUP.COM procedure that is installed in [VMS$COMMON.SYS$STARTUP] can be put in your VMS startup procedure to install the GNV$LIBCURL shared image and create logical names GNV$LIBCURL to reference it. It will create the GNV$CURL_INCLUDE logical name for build procedures to access the header files. Normally to use curl from DCL, just create a foreign command as: curl :== $gnv$gnu:[usr.bin]gnv$curl.exe If you need to work around having the older HP SSL kit installed, then for DCL create this command procedure: $ create/dir gnv$gnu:[vms_bin]/prot=w:re $ create gnv$gnu:[vms_bin]curl.com $ curl := $gnv$gnu:[usr.bin]gnv$curl.exe $ define/user ssl$libcrypto_shr32 gnv$curl_ssl_libcryptoshr32 $ curl "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'" ^Z Then you can use: curl :== @gnv$gnu:[vms_bin]curl.com to run curl. For the HP SSL work around to work for GNV do the following: $ create/dir gnv$gnu:[usr.local.bin]/prot=w:re $ create gnv$gnu:[usr.local.bin]curl. #! /bin/sh dcl @gnv\$gnu:[vms_bin]curl.com $* ^Z Similar work arounds will be needed for any program linked with GNV$LIBCURL until the HP OpenSSL is upgraded to the current 1.4 version or later. If you are installing a "daily" build instead of a release build of Curl, some things have been changed so that it can be installed at the same time as a production build with out conflicts. The CURL_DAILY_STARTUP.COM will be supplied instead of CURL_STARTUP.COM. This file is actually not used with the daily package and is provided as a preview of what the next CURL_STARTUP.COM will be for the next release. Do not run it. The files that are normally installed in [VMS$COMMON.GNV.usr], for the daily build are installed in [VMS$COMMON.GNV.beta] directory. To use the daily GNV$LIBCURL image, you will need to define the logical name GNV$LIBCURL to the image. davix-0.8.0/deps/curl/packages/vms/gnv_conftest.c_first0000644000000000000000000000474114121063461021671 0ustar rootroot/* File: GNV$CONFTEST.C_FIRST * * $Id$ * * Copyright 2009, John Malmberg * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* This is needed for Configure tests to get the correct exit status */ void __posix_exit(int __status); #define exit(__p1) __posix_exit(__p1) /* Fake pass the test to find a standard ldap routine that we know is */ /* present on VMS, but with the wrong case for the symbol */ char ldap_url_parse(void) {return 0;} /* These are to pass the test that does not use headers */ /* Because configure does an #undef which keeps us from using #define */ /* char CRYPTO_add_lock(void) {return 0;} */ char SSL_connnect(void) {return 0;} char ENGINE_init(void) {return 0;} char RAND_status(void) {return 0;} /* char RAND_screen(void) {return 0;} In headers, but not present */ char RAND_egd(void) {return 0;} char CRYPTO_cleanup_all_ex_data(void) {return 0;} char SSL_get_shutdown(void) {return 0;} char ENGINE_load_builtin_engines (void) {return 0;} /* And these are to pass the test that uses headers. */ /* Because the HP OpenSSL transfer vectors are currently in Upper case only */ #pragma message disable macroredef #define CRYPTO_add_lock CRYPTO_ADD_LOCK #define SSL_connect SSL_CONNECT #define ENGINE_init ENGINE_INIT #define RAND_status RAND_STATUS /* #define RAND_screen RAND_SCREEN */ #define RAND_egd RAND_EGD #define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA #define SSL_get_shutdown SSL_GET_SHUTDOWN #define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES /* Can not use the #define macro to fix the case on CRYPTO_lock because */ /* there is a macro CRYPTO_LOCK that is a number */ /* After all the work to get configure to pass the CRYPTO_LOCK tests, * it turns out that VMS does not have the CRYPTO_LOCK symbol in the * transfer vector, even though it is in the header file. */ davix-0.8.0/deps/curl/packages/vms/gnv_libcurl_symbols.opt0000644000000000000000000002116314121063461022416 0ustar rootroot! File GNV$LIBCURL_SYMBOLS.OPT ! ! $Id$ ! ! This file must be manually maintained to allow upward compatibility ! The SYMBOL_VECTORs are set up so that applications can be compiled ! with either case sensitive symbol names or the default of uppercase. ! This is because many of the Open Source applications that would call ! the LIBCURL library need to be built with case sensitive names. ! ! Automatic generation is currently not practical because the order of ! the entries are important for upward compatibility. ! ! The GSMATCH is manually set to the major version of 1, with the minor ! version being the next two sections multiplied by a power of 10 to ! become the minor version. ! So LIBCURL 7.18.1 becomes 1,718010. ! And a future LIBCURL of 7.18.2 would be 1,718020 if new routines were added. ! ! This leaves some spare digits for minor patches. ! ! Note that the GSMATCH does not need to have any real relationship to the ! actual package version number. ! ! New SYMBOL_VECTORs must be added to the end of this list, and added ! in pairs for both exact and with an uppercase alias. ! If the public symbol is more than 31 characters long, then a special ! shortened symbol will be exported, and three aliases should be created, ! The aliases will be the special shortened uppercase alias, and both ! upper and lowercase versions of a truncated name (preferred) or a ! modified manually shortened name if a truncated name will not be ! unique. ! ! Routines can not be removed, the functionality must be maintained. ! If a new routine is supplied where the arguments are incompatible with ! the older version, both versions are needed to be maintained. ! The old version can be given a different name, but must be in the same ! SYMBOL_VECTOR positions in this file. ! ! Changing the number of parameters for an existing routine does not require ! maintaining multiple versions as long as the routine can be called with ! the old number of parameters. ! ! Copyright 2009, John Malmberg ! ! Permission to use, copy, modify, and/or distribute this software for any ! purpose with or without fee is hereby granted, provided that the above ! copyright notice and this permission notice appear in all copies. ! ! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT ! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. !============================================================================ GSMATCH=LEQUAL,1,719050 CASE_SENSITIVE=YES SYMBOL_VECTOR=(curl_strequal=PROCEDURE) SYMBOL_VECTOR=(CURL_STREQUAL/curl_strequal=PROCEDURE) SYMBOL_VECTOR=(curl_strnequal=PROCEDURE) SYMBOL_VECTOR=(CURL_STRNEQUAL/curl_strnequal=PROCEDURE) SYMBOL_VECTOR=(curl_formadd=PROCEDURE) SYMBOL_VECTOR=(CURL_FORMADD/curl_formadd=PROCEDURE) SYMBOL_VECTOR=(curl_formget=PROCEDURE) SYMBOL_VECTOR=(CURL_FORMGET/curl_formget=PROCEDURE) SYMBOL_VECTOR=(curl_formfree=PROCEDURE) SYMBOL_VECTOR=(CURL_FORMFREE/curl_formfree=PROCEDURE) SYMBOL_VECTOR=(curl_getenv=PROCEDURE) SYMBOL_VECTOR=(CURL_GETENV/curl_getenv=PROCEDURE) SYMBOL_VECTOR=(curl_version=PROCEDURE) SYMBOL_VECTOR=(CURL_VERSION/curl_version=PROCEDURE) SYMBOL_VECTOR=(curl_easy_escape=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_ESCAPE/curl_easy_escape=PROCEDURE) SYMBOL_VECTOR=(curl_escape=PROCEDURE) SYMBOL_VECTOR=(CURL_ESCAPE/curl_escape=PROCEDURE) SYMBOL_VECTOR=(curl_easy_unescape=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_UNESCAPE/curl_easy_unescape=PROCEDURE) SYMBOL_VECTOR=(curl_unescape=PROCEDURE) SYMBOL_VECTOR=(CURL_UNESCAPE/curl_unescape=PROCEDURE) SYMBOL_VECTOR=(curl_free=PROCEDURE) SYMBOL_VECTOR=(CURL_FREE/curl_free=PROCEDURE) SYMBOL_VECTOR=(curl_global_init=PROCEDURE) SYMBOL_VECTOR=(CURL_GLOBAL_INIT/curl_global_init=PROCEDURE) SYMBOL_VECTOR=(curl_global_init_mem=PROCEDURE) SYMBOL_VECTOR=(CURL_GLOBAL_INIT_MEM/curl_global_init_mem=PROCEDURE) SYMBOL_VECTOR=(curl_global_cleanup=PROCEDURE) SYMBOL_VECTOR=(CURL_GLOBAL_CLEANUP/curl_global_cleanup=PROCEDURE) SYMBOL_VECTOR=(curl_slist_append=PROCEDURE) SYMBOL_VECTOR=(CURL_SLIST_APPEND/curl_slist_append=PROCEDURE) SYMBOL_VECTOR=(curl_slist_free_all=PROCEDURE) SYMBOL_VECTOR=(CURL_SLIST_FREE_ALL/curl_slist_free_all=PROCEDURE) SYMBOL_VECTOR=(curl_getdate=PROCEDURE) SYMBOL_VECTOR=(CURL_GETDATE/curl_getdate=PROCEDURE) SYMBOL_VECTOR=(curl_share_init=PROCEDURE) SYMBOL_VECTOR=(CURL_SHARE_INIT/curl_share_init=PROCEDURE) SYMBOL_VECTOR=(curl_share_setopt=PROCEDURE) SYMBOL_VECTOR=(CURL_SHARE_SETOPT/curl_share_setopt=PROCEDURE) SYMBOL_VECTOR=(curl_share_cleanup=PROCEDURE) SYMBOL_VECTOR=(CURL_SHARE_CLEANUP/curl_share_cleanup=PROCEDURE) SYMBOL_VECTOR=(curl_version_info=PROCEDURE) SYMBOL_VECTOR=(CURL_VERSION_INFO/curl_version_info=PROCEDURE) SYMBOL_VECTOR=(curl_easy_strerror=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_STRERROR/curl_easy_strerror=PROCEDURE) SYMBOL_VECTOR=(curl_share_strerror=PROCEDURE) SYMBOL_VECTOR=(CURL_SHARE_STRERROR/curl_share_strerror=PROCEDURE) SYMBOL_VECTOR=(curl_easy_pause=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_PAUSE/curl_easy_pause=PROCEDURE) ! ! easy.h SYMBOL_VECTOR=(curl_easy_init=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_INIT/curl_easy_init=PROCEDURE) SYMBOL_VECTOR=(curl_easy_setopt=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_SETOPT/curl_easy_setopt=PROCEDURE) SYMBOL_VECTOR=(curl_easy_perform=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_PERFORM/curl_easy_perform=PROCEDURE) SYMBOL_VECTOR=(curl_easy_cleanup=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_CLEANUP/curl_easy_cleanup=PROCEDURE) SYMBOL_VECTOR=(curl_easy_getinfo=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_GETINFO/curl_easy_getinfo=PROCEDURE) SYMBOL_VECTOR=(curl_easy_duphandle=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_DUPHANDLE/curl_easy_duphandle=PROCEDURE) SYMBOL_VECTOR=(curl_easy_reset=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_RESET/curl_easy_reset=PROCEDURE) SYMBOL_VECTOR=(curl_easy_recv=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_RECV/curl_easy_recv=PROCEDURE) SYMBOL_VECTOR=(curl_easy_send=PROCEDURE) SYMBOL_VECTOR=(CURL_EASY_SEND/curl_easy_send=PROCEDURE) ! ! multi.h SYMBOL_VECTOR=(curl_multi_init=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_INIT/curl_multi_init=PROCEDURE) SYMBOL_VECTOR=(curl_multi_add_handle=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_ADD_HANDLE/curl_multi_add_handle=PROCEDURE) SYMBOL_VECTOR=(curl_multi_remove_handle=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_REMOVE_HANDLE/curl_multi_remove_handle=PROCEDURE) SYMBOL_VECTOR=(curl_multi_fdset=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_FDSET/curl_multi_fdset=PROCEDURE) SYMBOL_VECTOR=(curl_multi_perform=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_PERFORM/curl_multi_perform=PROCEDURE) SYMBOL_VECTOR=(curl_multi_cleanup=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_CLEANUP/curl_multi_cleanup=PROCEDURE) SYMBOL_VECTOR=(curl_multi_info_read=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_INFO_READ/curl_multi_info_read=PROCEDURE) SYMBOL_VECTOR=(curl_multi_strerror=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_STRERROR/curl_multi_strerror=PROCEDURE) SYMBOL_VECTOR=(curl_multi_socket=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_SOCKET/curl_multi_socket=PROCEDURE) SYMBOL_VECTOR=(curl_multi_socket_action=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_SOCKET_ACTION/curl_multi_socket_action=PROCEDURE) SYMBOL_VECTOR=(curl_multi_socket_all=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_SOCKET_ALL/curl_multi_socket_all=PROCEDURE) SYMBOL_VECTOR=(curl_multi_timeout=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_TIMEOUT/curl_multi_timeout=PROCEDURE) SYMBOL_VECTOR=(curl_multi_setopt=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_SETOPT/curl_multi_setopt=PROCEDURE) SYMBOL_VECTOR=(curl_multi_assign=PROCEDURE) SYMBOL_VECTOR=(CURL_MULTI_ASSIGN/curl_multi_assign=PROCEDURE) ! ! mprintf.h SYMBOL_VECTOR=(curl_mprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MPRINTF/curl_mprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mfprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MFPRINTF/curl_mfprintf=PROCEDURE) SYMBOL_VECTOR=(curl_msprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MSPRINTF/curl_msprintf=PROCEDURE) SYMBOL_VECTOR=(curl_msnprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MSNPRINTF/curl_msnprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mvprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MVPRINTF/curl_mvprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mvfprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MVFPRINTF/curl_mvfprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mvsprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MVSPRINTF/curl_mvsprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mvsnprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MVSNPRINTF/curl_mvsnprintf=PROCEDURE) SYMBOL_VECTOR=(curl_maprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MAPRINTF/curl_maprintf=PROCEDURE) SYMBOL_VECTOR=(curl_mvaprintf=PROCEDURE) SYMBOL_VECTOR=(CURL_MVAPRINTF/curl_mvaprintf=PROCEDURE) davix-0.8.0/deps/curl/packages/vms/stage_curl_install.com0000644000000000000000000001334714121063461022177 0ustar rootroot$! File: stage_curl_install.com $! $! $Id$ $! $! This updates or removes the GNV$CURL.EXE and related files for the $! new_gnu:[*...] directory tree for running the self tests. $! $! The files installed/removed are: $! [usr.bin]gnv$curl.exe $! [usr.bin]curl-config. $! [usr.lib]gnv$libcurl.exe $! [usr.bin]curl. hard link for [usr.bin]gnv$curl.exe $! [usr.include.curl]curl.h $! [usr.include.curl]curlver.h $! [usr.include.curl]easy.h $! [usr.include.curl]mprintf.h $! [usr.include.curl]multi.h $! [usr.include.curl]stdcheaders.h $! [usr.include.curl]typecheck-gcc.h $! [usr.lib.pkgconfig]libcurl.pc $! [usr.share.man.man1]curl-config.1 $! [usr.share.man.man1]curl.1 $! [usr.share.man.man3]curl*.3 $! [usr.share.man.man3]libcurl*.3 $! Future: A symbolic link to the release notes? $! $! Copyright 2012, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 20-Aug-2012 J. Malmberg $! $!=========================================================================== $! $ arch_type = f$getsyi("ARCH_NAME") $ arch_code = f$extract(0, 1, arch_type) $! $ if arch_code .nes. "V" $ then $ set proc/parse=extended $ endif $! $! $! If the first parameter begins with "r" or "R" then this is to $! remove the files instead of installing them. $ remove_filesq = f$edit(p1, "upcase,trim") $ remove_filesq = f$extract(0, 1, remove_filesq) $ remove_files = 0 $ if remove_filesq .eqs. "R" then remove_files = 1 $! $! $! If we are staging files, make sure that the libcurl.pc and curl-config $! files are present. $ if remove_files .eq. 0 $ then $ if f$search("[--]libcurl.pc") .eqs. "" $ then $ @build_libcurl_pc.com $ endif $ if f$search("[--]curl-config") .eqs. "" $ then $ @build_curl-config_script.com $ endif $ endif $! $! $! Dest dirs $!------------------ $ dest_dirs1 = "[usr],[usr.bin],[usr.include],[usr.include.curl]" $ dest_dirs2 = ",[usr.bin],[usr.lib.pkgconfig],[usr.share]" $ dest_dirs3 = ",[usr.share.man],[usr.share.man.man1],[usr.share.man.man3]" $ dest_dirs = dest_dirs1 + dest_dirs2 + dest_dirs3 $! $! $! Alias links needed. $!------------------------- $ source_curl = "gnv$curl.exe" $ dest_curl = "[bin]gnv$curl.exe" $ curl_links = "[bin]curl." $ new_gnu = "new_gnu:" $! $! $! Create the directories if they do not exist $!--------------------------------------------- $ i = 0 $curl_dir_loop: $ this_dir = f$element(i, ",", dest_dirs) $ i = i + 1 $ if this_dir .eqs. "" then goto curl_dir_loop $ if this_dir .eqs. "," then goto curl_dir_loop_end $! Just create the directories, do not delete them. $! -------------------------------------------------- $ if remove_files .eq. 0 $ then $ create/dir 'new_gnu''this_dir'/prot=(o:rwed) $ endif $ goto curl_dir_loop $curl_dir_loop_end: $! $! $! Need to add in the executable file $!----------------------------------- $ if remove_files .eq. 0 $ then $ copy [--.src]curl.exe 'new_gnu'[usr.bin]gnv$curl.exe/prot=w:re $ copy [--]curl-config. 'new_gnu'[usr.bin]curl-config./prot=w:re $ copy sys$disk:[]gnv$libcurl.exe 'new_gnu'[usr.lib]gnv$libcurl.exe/prot=w:re $ endif $! $ if remove_files .eq. 0 $ then $ set file/enter='new_gnu'[bin]curl. 'new_gnu'[usr.bin]gnv$curl.exe $ else $ file = "''new_gnu'[bin]curl." $ if f$search(file) .nes. "" then set file/remove 'file';* $ endif $! $! $ if remove_files .eq. 0 $ then $ copy [--.include.curl]curl.h 'new_gnu'[usr.include.curl]curl.h $ copy [--.include.curl]system.h - 'new_gnu'[usr.include.curl]system.h $ copy [--.include.curl]curlver.h - 'new_gnu'[usr.include.curl]curlver.h $ copy [--.include.curl]easy.h - 'new_gnu'[usr.include.curl]easy.h $ copy [--.include.curl]mprintf.h - 'new_gnu'[usr.include.curl]mprintf.h $ copy [--.include.curl]multi.h - 'new_gnu'[usr.include.curl]multi.h $ copy [--.include.curl]stdcheaders.h - 'new_gnu'[usr.include.curl]stdcheaders.h $ copy [--.include.curl]typecheck-gcc.h - 'new_gnu'[usr.include.curl]typecheck-gcc.h $ copy [--]libcurl.pc 'new_gnu'[usr.lib.pkgconfig]libcurl.pc $! $ copy [--.docs]curl-config.1 'new_gnu'[usr.share.man.man1]curl-config.1 $ copy [--.docs]curl.1 'new_gnu'[usr.share.man.man1]curl.1 $! $ copy [--.docs.libcurl]*.3 - 'new_gnu'[usr.share.man.man3]*.3 $! $ else $ file = "''new_gnu'[usr.bin]curl-config." $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.bin]gnv$curl.exe" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.lib]gnv$libcurl.exe" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.include.curl]*.h" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.share.man.man1]curl-config.1" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.share.man.man1]curl.1" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.share.man.man3]curl*.3" $ if f$search(file) .nes. "" then delete 'file';* $ file = "''new_gnu'[usr.share.man.man3]libcurl*.3" $ if f$search(file) .nes. "" then delete 'file';* $ endif $! davix-0.8.0/deps/curl/packages/vms/build_vms.com0000644000000000000000000010633014121063461020300 0ustar rootroot$! BUILD_VMS.COM $! $! I've taken the original build_vms.com, supplied by Nico Baggus, if $! memory serves me correctly, and made some modifications. $! $! SSL support is controlled by logical names. If SSL$INCLUDE is $! defined, then it is assumed that HP's SSL product has been installed. $! If OPENSSL is defined, but SSL$INCLUDE is not, then OpenSSL will be $! used. If neither logical name is defined, then SSL support will not $! be compiled/linked in. Command-line options NOHPSSL and NOSSL can be $! specified to override the automatic SSL selection. $! $! Command-line Options: $! $! CLEAN Delete product files for this host architecture. (No $! build done.) $! CLEAN_ALL Delete product files for all host architectures. (No $! build done.) $! $! 64 Compile with 64-bit pointers. $! Note, you must match the pointer size that the OpenSSL $! shared image expects. $! Currently curl is not building properly with 64 bit pointers $! on VMS because it is trying to cast pointers to 32 bit $! integers and some OpenVMS library routines called by curl $! do not yet support 64 bit pointers. $! CCQUAL=x Add "x" to the C compiler qualifiers. $! Default qualifiers are: $! /standard=relaxed $! /names=(as_is, shortened) $! /repository=[.'arch'] $! /nested_include_directory=none $! /define=(_LARGEFILE=1,_USE_STD_STAT=1) (non-vax) $! /float=ieee/ieee_mode=denorm_results (non-vax) $! DEBUG Compile debug and nooptimize $! Alpha/IA64 always compiles /debug. $! Always link a debug image. $! NOIEEE Do not use IEEE floating point. (Alpha/I64) $! VAX must always use DFLOAT $! NOLARGE Disable large-file support if large file support available. $! (Non-VAX, VMS >= V7.2.) $! NOLDAP Disable LDAP support if LDAP is available. $! NOKERBEROS Disable Kerberos support if Kerberos is available. $! LIST Create C compiler listings and linker maps. $! /list/show=(expan,includ)/machine $! FULLLIST Full detailed listing. $! /list/show=(all, nomessages)/machine $! NOHPSSL Don't use HP SSL, even if available. $! Note, you must match the pointer size that the OpenSSL $! shared image expects. This procedure will select the $! correct HP OpenSSL image. $! NOSSL Don't use any SSL, even if available. $! OSSLOLB Use OpenSSL object libraries (.OLB), even if shared $! images (.EXE) are available. $! NOZLIB Don't use GNV$ZLIB shared image even if available. $! REALCLEAN Delete product files for all host architectures. (No $! build done.) Alias for CLEAN_ALL $! $! DCL Symbols: $! $! CURL_CCDEFS="c_macro_1=value1 [, c_macro_2=value2 [...]]" $! Compile with these additional C macros defined. $! $! Revisions: $! $! 2-DEC-2003, MSK, the "original" version. $! It works for me. Your mileage may vary. $! 13-JAN-2004, MSK, moved this procedure to the [.packages.vms] directory $! and updated it to do hardware dependent builds. $! 29-JAN-2004, MSK, moved logical defines into defines.com $! 6-FEB-2004, MSK, put in various SSL support bits $! 9-MAR-2004, MSK, the config-vms.h* files are now copied to the lib and $! src directories as curl_config.h. $! 15-MAR-2004, MSK, All of the curlmsg*.* files have also been moved to $! this build directory. They will be copied to the src $! directory before build. The .msg file will be compiled $! to get the .obj for messages, but the .h and .sdl files $! are not automatically created since they partly rely on $! the freeware SDL tool. $! 8-FEB-2005, MSK, merged the two config-vms.h* files into one that uses $! USE_SSLEAY to define if the target has SSL support built $! in. Changed the cc/define parameter accordingly. $! 11-FEB-2005, MSK, If [--.LIB]AMIGAOS.C and NWLIB.C are there, rename them $! 23-MAR-2005, MSK, relocated cc_qual define so that DEBUG option would work $! 25-APR-2007, STL, allow compilation in 64-bit mode. $! 13-DEC-2009. SMS, Changed to skip unwanted source files without $! renaming the original files. $! Eliminated needless, persistent logical names. $! Added CURL_CCDEFS DCL symbol for user-specified C $! macro definitions. $! Added CLEAN and CLEAN_ALL options. $! Added CCQUAL option for user-specified C compiler $! qualifiers. $! Added IEEE option for IEEE floating point (Alpha). $! Added LARGE option for large-file support. $! Added OSSLOLB option, and support for OpenSSL $! shared images. $! Changed to put listing and map files into lisdir:. $! Changed to avoid case confusion on ODS5 disks. $! Added more default dev:[dir] save+restore. $! Moved remaining "defines.com" code (back) into $! here, eliminating the hard-coded OpenSSL nonsense. $! Changed to use F$GETSYI("ARCH_NAME") (or $! equivalent) to name architecture-specific product $! file destination directory, and to create the $! directory if needed (obviating inclusion of these $! directories and dummy files in the distribution $! kit). $! Changed the "compile" subroutine to break the CC $! command across multiple lines to avoid DCL $! line-too-long problems. $! Changed "vo_c" messages to show the CC qualifiers $! once, not with every compile command. $! 01-Jan-2013 J. Malmberg $! VMS build procedures need to be able to work with $! the default set to a search list, with created or $! modified files only in the first member of the search $! list. $! Whitespace change to be more compatible with current $! practices. $! One pass option parsing instead of loop. $! GNV ZLIB shared image support. $! KERBEROS support where available. $! LDAP default to on where available $! LARGEFILE default to on where available $! IEEE float default to on where available. $! Generate the curl_config.h file from system inspection. $! Linker finds ldap with out option file. $! 13-Mar-2013, Tom Grace $! Added missing slash in cc_full_list. $! Removed unwanted extra quotes inside symbol tool_main $! for non-VAX architectures that triggered link failure. $! Replaced curl_sys_inc with sys_inc. $! 19-Mar-2013, John Malmberg $! symbol tool_main needs to be quoted when parse style is $! set to exended in versions of VMS greater than 7.3-1. $! Remove curlbuild.h generation as it should be pre-built $! in the curl release or daily tarball. $! 12-Jul-2013, John Malmberg $! Adjust to find and use ZLIB from the Jean-Francois $! Pieronne shared image and newer GNV ZLIB kit that $! is upward compatible with Jean-Francois's kit. $! Remove tabs from file. $! Fixed DCL formatting as follows: $! * Labels have no space after leading $. $! * 1 space after $ for first level. $! * 3 spaces after $ for second level. Line start + 4. $! * 7 spaces after $ for third level. Line start + 8. $! * Each level after that indents 4 characters. $! * then/else/endif same indentation as if statement. $! 17-Nov-2014, Michael Steve $! Modified build to handle new location of the VTLS lib $! source within zip archive. Not a pretty fix. $! $!=========================================================================== $! $! $! Save the original default dev:[dir], and arrange for its restoration $! at exit. $!------------------------------------------------------------------------ $ curl = "" $ orig_def = f$environment("DEFAULT") $ on error then goto Common_Exit $ on control_y then goto Common_Exit $! $ ctrl_y = 1556 $ proc = f$environment("PROCEDURE") $ proc_fid = f$file_attributes(proc, "FID") $ proc_dev = f$parse(proc, , , "DEVICE") $ proc_dir = f$parse(proc, , , "DIRECTORY") $ proc_name = f$parse(proc, , , "NAME") $ proc_type = f$parse(proc, , , "TYPE") $ proc_dev_dir = proc_dev + proc_dir $! $! Have to manually parse the device for a search list. $! Can not use the f$parse() as it will return the first name $! in the search list. $! $ orig_def_dev = f$element(0, ":", orig_def) + ":" $ if orig_def_dev .eqs. "::" then orig_def_dev = "sys$disk:" $ test_proc = orig_def_dev + proc_dir + proc_name + proc_type $! $! If we can find this file using the default directory $! then we know that we should use the original device from the $! default directory which could be a search list. $! $ test_proc_fid = f$file_attributes(test_proc, "FID") $! $ if (test_proc_fid .eq. proc_fid) $ then $ proc_dev_dir = orig_def_dev + proc_dir $ endif $! $! $! Verbose output message stuff. Define symbol to "write sys$output" or "!". $! vo_c - verbose output for compile $! vo_l - link $! vo_o - object check $! $ vo_c := "write sys$output" $ vo_l := "write sys$output" $ vo_o := "!" $! $! Determine the main distribution directory ("[--]") in an $! ODS5-tolerant (case-insensitive) way. (We do assume that the only $! "]" or ">" is the one at the end.) $! $! Some non-US VMS installations report ">" for the directory delimiter $! so do not assume that it is "]". $! $ orig_def_len = f$length(orig_def) $ delim = f$extract(orig_def_len - 1, 1, orig_def) $! $ set default 'proc_dev_dir' $ set default [--] $ base_dev_dir = f$environment("default") $ top_dev_dir = base_dev_dir - delim $! $! $! $! Define the architecture-specific product file destination directory $! name(s). $! $ parse_style = "TRADITIONAL" $ if (f$getsyi("HW_MODEL") .lt. 1024) $ then $ arch_name = "VAX" $ else $ arch_name = "" $ arch_name = arch_name + f$edit(f$getsyi("ARCH_NAME"), "UPCASE") $ if (arch_name .eqs. "") then arch_name = "UNK" $! $! Extended parsing option starts with VMS 7.3-1. $! There is no 7.4, so that simplifies the parse a bit. $! $ node_swvers = f$getsyi("node_swvers") $ version_patch = f$extract(1, f$length(node_swvers), node_swvers) $ maj_ver = f$element(0, ".", version_patch) $ min_ver_patch = f$element(1, ".", version_patch) $ min_ver = f$element(0, "-", min_ver_patch) $ patch = f$element(1, "-", min_ver_patch) $ if patch .eqs. "-" then patch = "" $ parse_x = 0 $ if maj_ver .ges. "8" $ then $ parse_x = 1 $ else $ if maj_ver .eqs. "7" .and. min_ver .ges. "3" .and. patch .nes. "" $ then $ parse_x = 1 $ endif $ endif $ if parse_x $ then $ parse_style = f$getjpi("", "parse_style_perm") $ endif $ endif $! $ exedir = proc_dev_dir - delim + ".''arch_name'" + delim $ lisdir = exedir $ objdir = exedir $! $! When building on a search list, need to do a create to make sure that $! the output directory exists, since the clean procedure tries to delete $! it. $ create/dir 'exedir'/prot=o:rwed $! $! Interpret command-line options. $! $ hpssl = 0 $ ldap = 1 $ list = 0 $ full_list = 0 $ nohpssl = 0 $ nossl = 0 $ openssl = 0 $ osslolb = 0 $ nozlib = 0 $ nokerberos = 0 $ cc_names = "/names=(shortened, as_is)/repository='exedir' $ cc_defs = "HAVE_CONFIG_H=1" $ cc_list = "/list='objdir'/show=(expan, includ)/machine $ cc_full_list = "/list='objdir'/show=(all, nomessages)/machine $ link_qual = "" $ if arch_name .eqs. "VAX" $ then $ cc_debug = "/nodebug/optimize" $ !cc_defs = cc_defs + "" $ cc_float = "" $ cc_large = "" $ else $ cc_debug = "/debug/optimize" $ cc_defs = cc_defs + ",_USE_STD_STAT" $ cc_float = "/float=ieee/ieee_mode=denorm_results" $ cc_large = ",_LARGEFILE" $ endif $ cc_qual1 = "" $ cc_qual2 = "" $ if (f$type(CURL_CCDEFS) .nes. "") $ then $ CURL_CCDEFS = f$edit(CURL_CCDEFS, "TRIM") $ cc_defs = cc_defs + ", " + CURL_CCDEFS $ endif $ msg_qual = "/object = ''objdir'" $ ssl_opt = "" $! $! Allow arguments to be grouped together with comma or separated by spaces $! Do no know if we will need more than 8. $ args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," $ args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," $! $! Provide lower case version to simplify parsing. $ args_lower = f$edit(args, "LOWERCASE,COLLAPSE") $! $ args_len = f$length(args) $ args_lower_len = f$length(args_lower) $! $ clean = 0 $ if f$locate(",clean,", args_lower) .lt. args_lower_len $ then $ clean = 1 $ endif $ clean_all = 0 $ if f$locate(",clean_all,", args_lower) .lt. args_lower_len $ then $ clean = 1 $ clean_all = 1 $ endif $ if f$locate(",realclean,", args_lower) .lt. args_lower_len $ then $ clean = 1 $ clean_all = 1 $ endif $! $ if clean .ne. 0 $ then $ prods = "''exedir'*.*;*" $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir + arch_name + ".DIR;1" $ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' $ if (f$search(prods) .nes. "") then delete /log 'prods' $ file = "[]config_vms.h" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[]config.h" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[]curl-config." $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[]libcurl.pc" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[.lib.cxx_repository]cxx$demangler_db." $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[.src.cxx_repository]cxx$demangler_db." $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[.lib]config_vms.h" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl_crtl_init" $ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* $ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* $ file = "[...]gnv$curlmsg" $ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* $ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ file = "[...]curlmsg" $ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* $ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ file = "[...]report_openssl_version" $ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* $ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ file = "[...]hp_ssl_release_info.txt" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]gnv_libcurl_xfer.mar_exact" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]gnv_libcurl_xfer" $ if f$search("''file'.lis") .nes. "" then delete/log 'file'.lis;* $ if f$search("''file'.obj") .nes. "" then delete/log 'file'.obj;* $ if f$search("''file'.opt") .nes. "" then delete/log 'file'.opt;* $ file = "[...]curl-*_original_src.bck" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl_d-*_original_src.bck" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl-*_vms_src.bck" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl_d-*_vms_src.bck" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl-*.release_notes" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]curl_d-*.release_notes" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]*curl*.pcsi$desc" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]*curl_d*.pcsi$desc" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]*curl*.pcsi$text" $ if f$search(file) .nes. "" then delete/log 'file';* $ file = "[...]*curl_d*.pcsi$text" $ if f$search(file) .nes. "" then delete/log 'file';* $! $ if clean_all .eq. 0 then goto Common_Exit $ endif $! $! $ if clean_all .ne. 0 $ then $ file = "[...]gnv$libcurl" $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ if f$search("''file'.map") .nes. "" then delete/log 'file'.map;* $ if f$search("''file'.dsf") .nes. "" then delete/log 'file'.dsf;* $ file = "[.src]curl" $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ if f$search("''file'.map") .nes. "" then delete/log 'file'.map;* $ if f$search("''file'.dsf") .nes. "" then delete/log 'file'.dsf;* $ prods = proc_dev_dir - delim + ".ALPHA" + delim + "*.*;*" $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir + "ALPHA" + ".DIR;1" $ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir - delim + ".IA64" + delim + "*.*;*" $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir + "IA64" + ".DIR;1" $ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir - delim + ".VAX" + delim + "*.*;*" $ if (f$search(prods) .nes. "") then delete /log 'prods' $ prods = proc_dev_dir + "VAX"+ ".DIR;1" $ if (f$search(prods) .nes. "") then set prot=o:rwed 'prods' $ if (f$search(prods) .nes. "") then delete /log 'prods' $ file = "[...]macro32_exactcase" $ if f$search("''file'.exe") .nes. "" then delete/log 'file'.exe;* $ if f$search("''file'.jnl") .nes. "" then delete/log 'file'.jnl;* $ goto Common_Exit $ endif $! $ build_64 = 0 $ if f$locate(",64,", args_lower) .lt. args_lower_len $ then $ cc_qual1 = cc_qual1 + " /POINTER = 64" $ build_64 = 1 $ endif $! $ args_loc = f$locate(",ccqual=", args_lower) $ if args_loc .lt. args_lower_len $ then $ arg = f$extract(args_loc + 1, args_lower_len, args_lower) $ arg_val = f$element(0, ",", arg) $ cc_qual2 = f$element(1, "=", arg_val); $ endif $! $! On Alpha/IA64 no size penalty for compiling /debug/optimize $! by default. $ if f$locate(",debug,", args_lower) .lt. args_lower_len $ then $ cc_debug = "/debug/nooptimize" $ endif $! $! We normally want IEEE float if it is available. Programs that are $! calling libcurl will typically prefer IEEE behavior, unless on the $! VAX where we have no choice. $! $ if f$locate(",noieee,", args_lower) .lt. args_lower_len $ then $ cc_float = "" $ endif $! $! Normally we want large file if it is available. $ if f$locate(",nolarge,", args_lower) .lt. args_lower_len $ then $ write sys$output "Handling of large files disabled." $ cc_large = "" $ endif $ if cc_large .nes. "" $ then $ cc_defs = cc_defs + cc_large $ endif $! $ if f$locate(",noldap,", args_lower) .lt. args_lower_len $ then $ ldap = 0 $ endif $! $ if f$locate(",list,", args_lower) .lt. args_lower_len $ then $ list = 1 $ endif $ if f$locate(",fulllist,", args_lower) .lt. args_lower_len $ then $ list = 1 $ full_list = 1 $ endif $! $ if f$locate(",nohpssl,", args_lower) .lt. args_lower_len $ then $ nohpssl = 1 $ endif $! $ if f$locate(",nossl,", args_lower) .lt. args_lower_len $ then $ nossl = 1 $ endif $! $ if f$locate(",osslolb,", args_lower) .lt. args_lower_len $ then $ osslolb = 1 $ endif $! $ if f$locate(",nozlib,", args_lower) .lt. args_lower_len $ then $ nozlib = 1 $ endif $! $ if f$locate(",nokerberos,", args_lower) .lt. args_lower_len $ then $ nokerberos = 1 $ endif $! $! $! CC /LIST, LINK /MAP, and MESSAGE /LIST are defaults in batch mode, $! so be explicit when they're not desired. $! $ $ if list .eq. 0 $ then $ cc_qual1 = cc_qual1 + "/nolist" $ msg_qual = msg_qual + "/nolist" $ else $ msg_qual = msg_qual + "/list='objdir'" $ if (full_list .ne. 0) $ then $ cc_qual1 = cc_qual1 + cc_full_list $ else $ cc_qual1 = cc_qual1 + cc_list $ endif $ endif $ cc_qual1 = cc_qual1 + cc_names + cc_float + cc_debug $! $! Create product directory, if needed. $! $ if (f$search(proc_dev_dir + arch_name + ".DIR;1") .eqs. "") $ then $ create /directory 'exedir' $ endif $! $! Detect available (but not prohibited) SSL software. $! $ libsslshr_line = "" $ libcryptoshr_line = "" $ if (.not. nossl) $ then $ if (f$trnlnm("OPENSSL") .nes. "") $ then $! cc_defs = cc_defs + ", USE_OPENSSL=1" $ if ((f$trnlnm("SSL$INCLUDE") .nes. "") .and. (.not. nohpssl)) $ then $! Use HP SSL. $ hpssl = 1 $! $! Older SSL only has lib*_shr32 images $!----------------------------------------------- $ libsslshr = "sys$share:ssl$libssl_shr" $ if (f$search("''libsslshr'.exe") .eqs. "") .or. (.not. build_64) $ then $ libsslshr = libsslshr + "32" $ endif $ libcryptoshr = "sys$share:ssl$libcrypto_shr" $ if (f$search("''libcryptoshr'.exe") .eqs. "") .or. (.not. build_64) $ then $ libcryptoshr = libcryptoshr + "32" $ endif $ libsslshr_line = "''libsslshr'.exe/share" $ libcryptoshr_line = "''libcryptoshr'.exe/share" $ else $! Use OpenSSL. Assume object libraries, unless shared images $! are found (and not prohibited). $! TODO: We do not know how to automatically choose based on the $! pointer size. $! $ openssl = 1 $ libsslshr_line = "ssllib:libssl.olb/lib" $ libcryptoshr_line = "ssllib:libcrypto.olb/lib" $ ssl_opt = ", ssllib:libssl.olb /library" + - ", ssllib:libcrypto.olb /library" $ if (osslolb .eq. 0) $ then if ((f$search("ssllib:ssl_libcrypto.exe") .nes. "") .and. - (f$search("ssllib:ssl_libssl.exe") .nes. "")) $ then $! OpenSSL shared images with "SSL_xxx.EXE names. $ openssl = 2 $ libsslshr_line = "ssllib:ssl_libssl_shr.exe/share" $ libcryptoshr_line = "ssllib:ssl_libcrypto_shr.exe/share" $ else $ if ((f$search("ssllib:libcrypto.exe") .nes. "") .and. - (f$search("ssllib:libssl.exe") .nes. "")) $ then $! OpenSSL shared images with "xxx.EXE names. $ openssl = 3 $ libsslshr_line = "ssllib:libssl_shr.exe/share" $ libcryptoshr_line = "ssllib:libcrypto_shr.exe/share" $ endif $ endif $ endif $ endif $ endif $ endif $! $! LDAP. $! $ if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. "" $ then $ ldap = 0 $ endif $ if (ldap .eq. 0) $ then $! cc_defs = cc_defs + ", CURL_DISABLE_LDAP=1" $ else $ 'vo_c' "%CURL-I-BLDHPLDAP, building with HP LDAP support" $ endif $! $! KERBEROS $ gssrtlshr_line = "" $ try_shr = "sys$share:gss$rtl" $ if f$search("''try_shr'.exe") .eqs. "" $ then $ nokerberos = 1 $ endif $ curl_sys_krbinc = "" $ if nokerberos .eq. 0 $ then $ 'vo_c' "%CURL-I-BLDHPKERBEROS, building with HP KERBEROS support" $ curl_sys_krbinc = "sys$sysroot:[kerberos.include]" $ gssrtlshr_line = "''try_shr'/share" $ endif $! $! $! LIBZ $ libzshr_line = "" $ try_shr = "gnv$libzshr" $ if build_64 $ then $! First look for 64 bit $ if f$search("''try_shr'64") .eqs. "" $ then $! Second look for the J.F. Pieronne 64 bit shared image $ try_shr = "LIBZ_SHR64" $ if f$search(try_shr) .eqs. "" then nozlib = 1 $ endif $ else $! First look for 32 bit $ if f$search("''try_shr'32") .eqs. "" $ then $! Second look for old 32 bit image $ if f$search(try_shr) .eqs. "" $ then $! Third look for the J.F. Pieronne 32 bit shared image $ try_shr = "LIBZ_SHR32" $ if f$search(try_shr) .eqs. "" then nozlib = 1 $ endif $ endif $ endif $ if f$search(try_shr) .eqs. "" $ then $ nozlib = 1 $ endif $ curl_sys_zlibinc = "" $ if nozlib .eq. 0 $ then $ libzshr_line = "''try_shr'/share" $ if f$locate("LIBZ", try_shr) .eq. 0 $ then $ 'vo_c' "%CURL-I-BLDJFPLIBZ, building with JFP LIBZ support" $ curl_sys_zlibinc = "LIBZ:" $ else $ 'vo_c' "%CURL-I-BLDGNVLIBZ, building with GNV LIBZ support" $ curl_sys_zlibinc = "GNV$ZLIB_INCLUDE:" $ endif $ endif $! $! Form CC qualifiers. $! $ cc_defs = "/define = (''cc_defs')" $ cc_qual2 = cc_qual2 + " /object = ''objdir'" $ cc_qual2 = cc_qual2 + "/nested_include_directory=none" $! $ 'vo_c' "CC opts:", - " ''cc_defs'", - " ''cc_qual1'", - " ''cc_qual2'" $! $! Inform the victim of our plans. $! $ if (hpssl) $ then $ 'vo_c' "%CURL-I-BLDHPSSL, building with HP SSL support" $ else $ if (openssl .ne. 0) $ then $ if (openssl .eq. 1) $ then $ 'vo_c' - "%CURL-I-BLDOSSL_OLB, building with OpenSSL (object library) support" $ else $ 'vo_c' - "%CURL-I-BLDOSSL_EXE, building with OpenSSL (shared image) support" $ endif $ else $ 'vo_c' "%CURL-I-BLDNOSSL, building with NO SSL support" $ endif $ endif $! $! Announce destination and SSL directories. $! $ 'vo_c' " OBJDIR = ''objdir'" $ 'vo_c' " EXEDIR = ''exedir'" $! $ if (openssl .ne. 0) $ then $ ssllib = f$trnlnm("ssllib") $ if (ssllib .eqs. "") $ then $ ssllib = "(undefined)" $ endif $ 'vo_c' " SSLLIB = ''ssllib'" $! $! TODO: Why are we translating the logical name? $! The logical aname used to find the shared image should just be used $! as translating it could result in the wrong location at run time. $ if (openssl .eq. 1) $ then $ ossl_lib1 = f$trnlnm("ssllib")+ "LIBSSL.OLB" $ ossl_lib2 = f$trnlnm("ssllib")+ "LIBCRYPTO.OLB" $ msg = "object libraries" $ else $ if (openssl .eq. 2) $ then $ ossl_lib1 = f$trnlnm("ssllib")+ "SSL_LIBSSL.EXE" $ ossl_lib2 = f$trnlnm("ssllib")+ "SSL_LIBCRYPTO.EXE" $ else $ ossl_lib1 = f$trnlnm("ssllib")+ "LIBSSL.EXE" $ ossl_lib2 = f$trnlnm("ssllib")+ "LIBCRYPTO.EXE" $ endif $ msg = "shared images" $ endif $ if ((f$search(ossl_lib1) .eqs. "") .or. - (f$search(ossl_lib2) .eqs. "")) $ then $ write sys$output "Can't find OpenSSL ''msg':" $ write sys$output " ''ossl_lib1'" $ write sys$output " ''ossl_lib2'" $ goto Common_Exit $ endif $ endif $! $! Define the "curl" (process) logical name for "#include ". $! $ curl = f$trnlnm("curl", "LNM$PROCESS") $ if (curl .nes. "") $ then $ write sys$output "" $ write sys$output - "Process logical name ""curl"" is already defined, but this procedure" $ write sys$output - "would override that definition. Use a command like" $ write sys$output - " deassign /process curl" $ write sys$output - "to cancel that logical name definition, and then and re-run this procedure." $ write sys$output "" $ goto Common_Exit $ endif $ curl_logical = top_dev_dir + ".include.curl" + delim $ curl_sys_inc2 = curl_logical $ curl_sys_inc1 = top_dev_dir + ".include" + delim $! define curl 'top_dev_dir'.include.curl'delim' $! $! Generate config file into the product directory. $! $! call MoveIfDiff [.lib]config-vms.h 'objdir'curl_config.h $! $ conf_params = "" $ if nossl .ne. 0 then conf_params = conf_params + ",nossl" $ if nohpssl .ne. 0 then conf_params = conf_params + ",nohpssl," $ if ldap .eq. 0 then conf_params = conf_params + ",noldap," $ if nozlib .ne. 0 then conf_params = conf_params + ",nozlib," $ if nokerberos .ne. 0 then conf_params = conf_params + ",nokerberos" $ conf_params = conf_params - "," $! $! $ new_conf = f$search("''objdir'curl_config.h") $ if new_conf .eqs. "" $ then $! set ver $ write sys$output "Generating curl custom config_vms.h" $ @'proc_dev_dir'generate_config_vms_h_curl.com ''conf_params' $! $ write sys$output "Generating curl_config.h" $ conf_in = f$search("[.lib]curl_config*.*in") $ if conf_in .eqs. "" $ then $ write sys$output "Can not find [.lib]curl_config*.*in file!" $ goto common_exit $ endif $ @'proc_dev_dir'config_h.com 'conf_in' $ copy config.h 'objdir'curl_config.h $ delete config.h; $! set nover $ endif $! $! $ on control_y then goto Common_Exit $! $ set default 'proc_dev_dir' $ sys_inc = "''curl_sys_inc1', ''curl_sys_inc2', ''curl_logical'" $ if curl_sys_krbinc .nes. "" $ then $ sys_inc = sys_inc + ",''curl_sys_krbinc'" $ endif $ if curl_sys_zlibinc .nes. "" $ then $ sys_inc = sys_inc + ",''curl_sys_zlibinc'" $ endif $! Build LIB $ cc_include = "/include=([-.lib],[-.lib.vtls],[-.packages.vms]" $ cc_include = cc_include + ",[-.packages.vms.''arch_name'])" $ call build "[--.lib]" "*.c" "''objdir'CURLLIB.OLB" "amigaos, nwlib, nwos" $ if ($status .eq. ctrl_y) then goto Common_Exit $! Build VTLS $ cc_include = "/include=([--.lib.vtls],[--.lib],[--.src]" $ cc_include = cc_include + ",[--.packages.vms],[--.packages.vms.''arch_name'])" $ call build "[--.lib.vtls]" "*.c" "''objdir'CURLLIB.OLB" "amigaos, nwlib, nwos" $! Build SRC $ cc_include = "/include=([-.src],[-.lib],[-.lib.vtls]" $ cc_include = cc_include + ",[-.packages.vms],[-.packages.vms.''arch_name'])" $ call build "[--.src]" "*.c" "''objdir'CURLSRC.OLB" $ if ($status .eq. ctrl_y) then goto Common_Exit $! Build MSG $ call build "[]" "*.msg" "''objdir'CURLSRC.OLB" $ if ($status .eq. ctrl_y) then goto Common_Exit $! $! $ if (openssl .ne. 0) $ then $ if (openssl .eq. 1) $ then $ 'vo_l' "%CURL-I-LINK_OSSL, linking with OpenSSL (object library)" $ else $ 'vo_l' "%CURL-I-LINK_HPSSL, linking with OpenSSL (shared image)" $ endif $ else $ if (hpssl) $ then $ 'vo_l' "%CURL-I-LINK_HPSSL, linking with HP SSL" $ else $ 'vo_l' "%CURL-I-LINK_NOSSL, linking with NO SSL support" $ endif $ endif $! $! $! GNV helper files for building the test curl binary. $!----------------------------------------------- $ create 'exedir'gnv$curl.opt $ open/append opt 'exedir'gnv$curl.opt $ if libzshr_line .nes. "" then write opt libzshr_line $ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $! $! $! Create the libcurl $!------------------------------------------------------ $ create 'exedir'gnv_libcurl_linker.opt $ open/append opt 'exedir'gnv_libcurl_linker.opt $ if libzshr_line .nes. "" then write opt libzshr_line $ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $! $! $! If we are not on VAX, then we want the debug symbol table in $! a separate file. $! VAX needs the tool_main unquoted in uppercase, $! Alpha and IA64 need tool_main quoted in exact case when parse style is $! extended. $ link_dsf1 = "" $ link_dsf2 = "" $ tool_main = "tool_main" $ if arch_name .nes. "VAX" $ then $ if parse_style .eqs. "EXTENDED" $ then $ tool_main = """tool_main""" $ endif $ link_dsf1 = "/dsf=" + exedir + "CURL.DSF" $ link_dsf2 = "/dsf=" + exedir + "CURL_DEBUG.DSF" $ endif $ if (list .eq. 0) $ then $ link_map1 = "/nomap" $ link_map2 = "/nomap" $ else $ link_map1 = "/map=" + exedir + "CURL.MAP" $ link_map2 = "/map=" + exedir + "CURL_DEBUG.MAP" $ endif $! $! $! Make a normal image. $ set ver $ link 'link_map1' 'link_dsf1' /executable = 'exedir'CURL.EXE - 'objdir'curlsrc.olb /library /include = ('tool_main', curlmsg), - 'objdir'curllib.olb /library, - 'exedir'gnv$curl.opt/opt $! $! Also make a debug copy. $ link/debug 'link_map2' 'link_dsf2' /executable = 'exedir'CURL_DEBUG.EXE - 'objdir'curlsrc.olb /library /include = ('tool_main', curlmsg), - 'objdir'curllib.olb /library, - 'exedir'gnv$curl.opt/opt $ set nover $! $ goto Common_Exit $! $! Subroutine to build everything with a filetype passed in via P2 in $! the directory passed in via P1 and put it in the object library named $! via P3. Exclude items in P4. $! $build: subroutine $ build_def = f$environment("default") $ on control_y then goto EndLoop ! SS$_CONTROLY $ sts = 1 ! SS$_NORMAL. $! set noon $ set default 'p1' $ search = "sys$disk:" + p2 $ reset = f$search("reset") $ if f$search( p3) .eqs. "" $ then $ librarian /create /object 'p3' $ endif $ reject_list__ = "," + f$edit(p4, "COLLAPSE, UPCASE") + "," $ reject_list___len = f$length(reject_list__) $ reset = f$search( "reset", 1) $Loop: $ file = f$search( search, 1) $ if file .eqs. "" then goto EndLoop $! Skip a name if it's in the P4 exclusion list. $ if (p4 .nes. "") $ then $ name__ = "," + - f$edit(f$parse(file, , , "NAME", "SYNTAX_ONLY"), "UPCASE") + - "," $ if (f$locate(name__, reject_list__) .lt. reject_list___len) $ then $ goto Loop $ endif $ endif $ objfile = f$parse("''objdir'.OBJ;", file) $ obj = f$search(objfile, 2) $ if (obj .nes. "") $ then $ if (f$cvtime(f$file(file,"rdt")) .gts. f$cvtime(f$file(obj,"rdt"))) $ then $ call compile 'file' $ sts = $status $ if .not. sts $ then $ goto EndLoop $ endif $ librarian /object 'p3' 'objfile' $ else $ 'vo_o' "%CURL-I-OBJUTD, ", objfile, " is up to date" $ endif $ else $ 'vo_o' "%CURL-I-OBJDNE, ", file, " does not exist" $ call compile 'file' $ sts = $status $ if .not. sts $ then $ goto EndLoop $ endif $ librarian /object 'p3' 'objfile' $ endif $ goto Loop $EndLoop: $!!! purge $ set default 'build_def' $ exit 'sts' $ endsubroutine ! Build $! $! Based on the file TYPE, do the right compile command. $! Only C and MSG supported. $! $compile: subroutine $ on control_y then return ctrl_y ! SS$_CONTROLY $! set noon $ file = p1 $ qual = p2+ p3+ p4+ p5+ p6+ p7+ p8 $ typ = f$edit(f$parse(file, , , "TYPE"), "UPCASE") - "." $ if (typ .eqs. "C") $ then $ 'vo_c' "CC (opts) ", file $ define/user curl 'curl_logical' $ if curl_sys_krbinc .nes. "" then define/user gssapi 'curl_sys_krbinc' $ define/user decc$system_include 'sys_inc' $ CC 'cc_defs' - 'cc_qual1' - 'cc_qual2' - 'cc_include' - 'file' $ else $ cmd_msg = "MESSAGE " + msg_qual $ x = cmd_'typ' $ 'vo_c' x, " ", file $ 'x' 'file' $ endif $ ENDSUBROUTINE ! Compile $! $! Do a diff of the file specified in P1 with that in P2. If different $! copy P1 to P2. This also covers if P2 doesn't exist, but not if P2 $! is an invalid filespec. $! $MoveIfDiff: subroutine $ set NoOn $ define /user_mode sys$error nl: $ define /user_mode sys$output nl: $ differences 'p1' 'p2' $ status = $status $ if (status .ne. %X006C8009) ! if status is not "no diff" $ then $ copy 'p1' 'p2' $ purge /nolog 'p2' $ endif $ on control_y then return ctrl_y ! SS$_CONTROLY $ ENDSUBROUTINE ! MoveIfDiff $! $Common_Exit: $ set default 'orig_def' $ exit davix-0.8.0/deps/curl/packages/vms/make_gnv_curl_install.sh0000644000000000000000000000317114121063461022511 0ustar rootroot# File: make_gnv_curl_install.sh # # $Id$ # # Set up and run the make script for Curl. # # This makes the library, the curl binary and attempts an install. # A search list should be set up for GNU (GNV$GNU). # # Copyright 2009, John Malmberg # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # 06-Jun-2009 J. Malmberg #========================================================================== # # # Needed VMS build setups for GNV. export GNV_OPT_DIR=. export GNV_CC_QUALIFIERS=/DEBUG/OPTIMIZE/STANDARD=RELAXED\ /float=ieee_float/ieee_mode=denorm_results export GNV_CXX_QUALIFIERS=/DEBUG/OPTIMIZE/float=ieee/ieee_mode=denorm_results export GNV_CC_NO_INC_PRIMARY=1 # # # POSIX exit mode is needed for Unix shells. export GNV_CC_MAIN_POSIX_EXIT=1 make cd ../.. # adjust the libcurl.pc file, GNV currently ignores the Lib: line. # but is noisy about it, so we just remove it. sed -e 's/^Libs:/#Libs:/g' libcurl.pc > libcurl.pc_new rm libcurl.pc mv libcurl.pc_new libcurl.pc make install davix-0.8.0/deps/curl/packages/vms/gnv_curl_configure.sh0000644000000000000000000000314114121063461022024 0ustar rootroot# File: gnv_curl_configure.sh # # $Id$ # # Set up and run the configure script for Curl so that it can find the # proper options for VMS. # # Copyright 2009, John Malmberg # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # 06-Jun-2009 J. Malmberg # 28-Dec-2012 J. Malmberg Update for Bash 4.2.39 #========================================================================== # # POSIX exit mode is needed for Unix shells. export GNV_CC_MAIN_POSIX_EXIT=1 # # Where to look for the helper files. export GNV_OPT_DIR=. # # How to find the SSL library files. export LIB_OPENSSL=/SSL_LIB # # Override configure adding -std1 which is too strict for what curl # actually wants. export GNV_CC_QUALIFIERS=/STANDARD=RELAXED # # Set the directory to where the Configure script actually is. cd ../.. # # ./configure --prefix=/usr --exec-prefix=/usr --disable-dependency-tracking \ --disable-libtool-lock --with-gssapi --disable-ntlm-wb \ --with-ca-path=gnv\$curl_ca_path # davix-0.8.0/deps/curl/packages/vms/build_gnv_curl.com0000644000000000000000000000216014121063461021306 0ustar rootroot$! File: build_gnv_curl.com $! $! $Id$ $! $! All in one build procedure $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 11-Jun-2009 J. Malmberg $!----------------------------------------------------------------------- $! $ @setup_gnv_curl_build.com $! $ bash gnv_curl_configure.sh $! $ @clean_gnv_curl.com $! $ bash make_gnv_curl_install.sh $! $ @gnv_link_curl.com $! $ purge new_gnu:[*...]/log $! $! $exit davix-0.8.0/deps/curl/packages/vms/macro32_exactcase.patch0000644000000000000000000000016514121063461022122 0ustar rootrootmacro32_exactcase.exe SE EC ^X00000001 RE /I ^X00012B1D 'BICB2 #^X00000020,R3' EXIT 'BICB2 #^X00000000,R3' EXI U EXI davix-0.8.0/deps/curl/packages/vms/make_pcsi_curl_kit_name.com0000644000000000000000000001405514121063461023145 0ustar rootroot$! File: MAKE_PCSI_CURL_KIT_NAME.COM $! $! $Id$ $! $! Calculates the PCSI kit name for use in building an installation kit. $! PCSI is HP's PolyCenter Software Installation Utility. $! $! The results are stored in as logical names so that other procedures $! can use them. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 11-Jun-2009 J. Malmberg $! $!======================================================================== $! $! Save default $ default_dir = f$environment("DEFAULT") $! $! Move to the base directories $ set def [--] $! $! Put things back on error. $ on warning then goto all_exit $! $! The producer is the name or common abbreviation for the entity that is $! making the kit. It must be set as a logical name before running this $! procedure. $! $! HP documents the producer as the legal owner of the software, but for $! open source work, it should document who is creating the package for $! distribution. $! $ producer = f$trnlnm("GNV_PCSI_PRODUCER") $ if producer .eqs. "" $ then $ write sys$output "The logical name GNV_PCSI_PRODUCER needs to be defined." $ write sys$output "This should be set to the common abbreviation or name of" $ write sys$output "the entity creating this kit. If you are an individual" $ write sys$output "then use your initials." $ goto all_exit $ endif $ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") $ if producer_full_name .eqs. "" $ then $ write sys$output "The logical name GNV_PCSI_PRODUCER_FULL_NAME needs to" $ write sys$output "be defined. This should be set to the full name of" $ write sys$output "the entity creating this kit. If you are an individual" $ write sys$output "then use your name." $ write sys$output "EX: DEFINE GNV_PCSI_PRODUCER_FULL_NAME ""First M. Last""" $ goto all_exit $ endif $! $ write sys$output "*****" $ write sys$output "***** Producer = ''producer'" $ write sys$output "*****" $! $! $! Base is one of 'VMS', 'AXPVMS', 'I64VMS', 'VAXVMS' and indicates what $! binaries are in the kit. A kit with just 'VMS' can be installed on all $! architectures. $! $ base = "VMS" $ arch_type = f$getsyi("ARCH_NAME") $ code = f$extract(0, 1, arch_type) $ if (code .eqs. "I") then base = "I64VMS" $ if (code .eqs. "V") then base = "VAXVMS" $ if (code .eqs. "A") then base = "AXPVMS" $! $! $ product = "curl" $! $! $! We need to get the version from curlver_h. It will have a line like $! #define LIBCURL_VERSION "7.31.0" $! or $! #define LIBCURL_VERSION "7.32.0-20130731". $! $! The dash indicates that this is a daily pre-release. $! $! $ open/read/error=version_loop_end vhf [.include.curl]curlver.h $ version_loop: $ read vhf line_in $ if line_in .eqs. "" then goto version_loop $ if f$locate("#define LIBCURL_VERSION ", line_in) .ne. 0 $ then $ goto version_loop $ endif $ raw_version = f$element(2," ", line_in) - """" - """" $ version_loop_end: $ close vhf $! $! $ eco_level = "" $ if f$search("''default_dir'vms_eco_level.h") .nes. "" $ then $ open/read ef 'default_dir'vms_eco_level.h $ecolevel_loop: $ read/end=ecolevel_loop_end ef line_in $ prefix = f$element(0, " ", line_in) $ if prefix .nes. "#define" then goto ecolevel_loop $ key = f$element(1, " ", line_in) $ value = f$element(2, " ", line_in) - """" - """" $ if key .eqs. "VMS_ECO_LEVEL" $ then $ eco_level = "''value'" $ if eco_level .eqs. "0" $ then $ eco_level = "" $ else $ eco_level = "E" + eco_level $ endif $ goto ecolevel_loop_end $ endif $ goto ecolevel_loop $ecolevel_loop_end: $ close ef $ endif $! $! $! This translates to V0732-0 or D0732-0 $! We encode the snapshot date into the version as an ECO since a daily $! can never have an ECO. $! $! version_type = 'V' for a production release, and 'D' for a build from a $! daiy snapshot of the curl source. $ majorver = f$element(0, ".", raw_version) $ minorver = f$element(1, ".", raw_version) $ raw_update = f$element(2, ".", raw_version) $ update = f$element(0, "-", raw_update) $ if update .eqs. "0" then update = "" $ daily_tag = f$element(1, "-", raw_update) $ vtype = "V" $ patch = "" $ if daily_tag .nes. "-" $ then $ vtype = "D" $ daily_tag_len = f$length(daily_tag) $ daily_tag = f$extract(4, daily_tag_len - 4, daily_tag) $ patch = vtype + daily_tag $ product = product + "_d" $ else $ daily_tag = "" $ if eco_level .nes. "" then patch = eco_level $ endif $! $! $ version_fao = "!2ZB!2ZB" $ mmversion = f$fao(version_fao, 'majorver', 'minorver') $ version = vtype + "''mmversion'" $ if update .nes. "" .or. patch .nes. "" $ then $! The presence of a patch implies an update $ if update .eqs. "" .and. patch .nes. "" then update = "0" $ version = version + "-" + update + patch $ fversion = version $ else $ fversion = version $ version = version + "-" $ endif $! $! Kit type 1 is complete kit, the only type that this procedure will make. $ kittype = 1 $! $! Write out a logical name for the resulting base kit name. $ name = "''producer'-''base'-''product'-''version'-''kittype'" $ define GNV_PCSI_KITNAME "''name'" $ fname = "''product'-''fversion'" $ define GNV_PCSI_FILENAME_BASE "''fname'" $ write sys$output "*****" $ write sys$output "***** GNV_PCSI_KITNAME = ''name'." $ write sys$output "***** GNV_PCSI_FILENAME_BASE = ''fname'." $ write sys$output "*****" $! $all_exit: $ set def 'default_dir' $ exit '$status' davix-0.8.0/deps/curl/packages/vms/setup_gnv_curl_build.com0000644000000000000000000002257214121063461022537 0ustar rootroot$! File: setup_gnv_curl_build.com $! $! $Id$ $! $! Set up build environment for building Curl under GNV on VMS. $! $! GNV needs some files moved into the other directories to help with $! the configure script and the build. $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! 30-May-2009 J. Malmberg $! $!======================================================================= $! $! Save this so we can get back. $ default_dir = f$environment("default") $! $! Move to where the Configure script is. $ set def [--] $! $! Get the path to where the Configure script is. $ base_dir = f$environment("default") $! $! Allow arguments to be grouped together with comma or separated by spaces $! Do no know if we will need more than 8. $ args = "," + p1 + "," + p2 + "," + p3 + "," + p4 + "," $ args = args + p5 + "," + p6 + "," + p7 + "," + p8 + "," $! $! Provide lower case version to simplify parsing. $ args_lower = f$edit(args, "LOWERCASE,COLLAPSE") $! $ args_len = f$length(args) $ args_lower_len = f$length(args_lower) $! $ tests = 0 $ if f$locate(",test", args_lower) .lt. args_lower_len $ then $ tests = 1 $ endif $! $ examples = 0 $ if f$locate(",exam", args_lower) .lt. args_lower_len $ then $ examples = 1 $ endif $! $! We want detailed build logs. $ clist = "/list/show=(expan,includ)" $! $! We want full symbol names in exact case. Need a common $! repository for all directories. $ cnames = "/names=(shortened,as_is)/repository=''base_dir'" $! $! Set the compiler options for GNV CC wrapper to inherit. $ cc :== cc'clist''cnames'/nested_include_directory=none $ cxx :== cxx'clist''cnames'/nested_include_directory=none $ pointer_size = "32" $! Note 64 bit pointers requires all libraries to either have $! 64 bit pointers or have #pragma directives. $! Currently building curl on VMS with 64 bit pointers does not work. $! $! A logical name to make it easier to find some of the hacks. $ define/job gnv_hacks 'base_dir' $! $! A logical name to find the [.packages.vms] directory where we started. $ define/job gnv_packages_vms 'default_dir' $! $! Kerberos headers: $ if f$trnlnm("gssapi") .eqs. "" $ then $ if f$search("sys$sysroot:[kerberos]include.dir") .nes. "" $ then $ define/job gssapi sys$sysroot:[kerberos.include] $ endif $ endif $! $! OpenSSL headers $ if f$trnlnm("openssl") .eqs. "" $ then $ if f$trnlnm("ssl$include") .nes. "" $ then $ define/job openssl ssl$include: $ endif $ endif $! $! C compiler include path. $ define/job decc$system_include prj_root:[.include.curl],- [-.packages.vms],- ssl$include:,gnv$gnu:[usr.include],- gnv$gnu:[usr.include.libz],gnv$gnu:[include],- gnv$zlib_include:,- sys$sysroot:[kerberos.include] $! $! Set up a include list for the compiler to find all the header files $! that they need. $! $ define/job decc$user_include src_root:[.include.curl] $ define ssl_lib sys$library: $! $! Calculate what is needed in the option files $ libzshr_line = "" $ try_shr = "gnv$libzshr''pointer_size'" $ if f$search(try_shr) .nes. "" then libzshr_line = "''try_shr'/share" $ if (libzshr_line .eqs. "") $ then $ try_shr = "sys$share:" + try_shr $ if f$search("''try_shr'.exe") .nes. "" $ then $ libzshr_line = "''try_shr'/share" $ endif $ endif $! $! Kerberos $ gssrtlshr_line = "" $ try_shr = "sys$share:gss$rtl" $ if f$search("''try_shr'.exe") .nes. "" $ then $ gssrtlshr_line = "''try_shr'/share" $ endif $! $! HP OpenSSL $ libcryptoshr_line = "" $ try_shr = "sys$share:ssl$libcrypto_shr''pointer_size'" $ if f$search("''try_shr'.exe") .nes. "" $ then $ libcryptoshr_line = "''try_shr'/share" $ endif $! $ libsslshr_line = "" $ try_shr = "sys$share:ssl$libssl_shr''pointer_size'" $ if f$search("''try_shr'.exe") .nes. "" $ then $ libsslshr_line = "''try_shr'/share" $ endif $! $! $! Copy over the gnv$conftest* files to base directory. $!----------------------------------------------------- $ copy 'default_dir'gnv_conftest.c_first 'base_dir'gnv$conftest.c_first $ create 'base_dir'gnv$conftest.opt $ open/append opt 'base_dir'gnv$conftest.opt $ if libzshr_line .nes. "" then write opt libzshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $ purge 'base_dir'gnv$conftest.* $ rename 'base_dir'gnv$conftest.* ;1 $! $! $! $! GNV helper files for building the test curl binary. $!----------------------------------------------- $ create [.src]gnv$curl.opt $ open/append opt [.src]gnv$curl.opt $ write opt "gnv_packages_vms:curlmsg.obj" $ if libzshr_line .nes. "" then write opt libzshr_line $ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $ purge [.src]gnv$*.* $ rename [.src]gnv$*.* ;1 $! $! $! Create the libcurl $!------------------------------------------------------ $ create 'default_dir'gnv_libcurl_linker.opt $ open/append opt 'default_dir'gnv_libcurl_linker.opt $ if libzshr_line .nes. "" then write opt libzshr_line $ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $! $! $! Create the template linker file $!--------------------------------- $ create 'default_dir'gnv_template_linker.opt $ open/append opt 'default_dir'gnv_template_linker.opt $ write opt "gnv_vms_common:vms_curl_init_unix.obj" $ if libzshr_line .nes. "" then write opt libzshr_line $ if gssrtlshr_line .nes. "" then write opt gssrtlshr_line $ if libcryptoshr_line .nes. "" then write opt libcryptoshr_line $ if libsslshr_line .nes. "" then write opt libsslshr_line $ close opt $! $! Copy over the gnv$*.opt files for [.docs.examples] $!---------------------------------------------------- $ if examples .ne. 0 $ then $ example_apps = "10-at-a-time,anyauthput,certinfo,cookie_interface,debug" $ example_apps = example_apps + ",fileupload,fopen,ftpget,ftpgetresp" $ example_apps = example_apps + ",ftpupload,getinfo,getinmemory" $ example_apps = example_apps + ",http-post,httpcustomheader,httpput" $ example_apps = example_apps + ",https,multi-app,multi-debugcallback" $ example_apps = example_apps + ",multi-double,multi-post,multi-single" $ example_apps = example_apps + ",persistent,post-callback,postit2" $ example_apps = example_apps + ",sendrecv,sepheaders,simple,simplepost" $ example_apps = example_apps + ",simplessl" $! $ i = 0 $example_loop: $ ap_name = f$element(i, ",", example_apps) $ if ap_name .eqs. "," then goto example_loop_end $ if ap_name .eqs. "" then goto example_loop_end $ copy 'default_dir'gnv_template_linker.opt - [.docs.examples]gnv$'ap_name'.opt $ i = i + 1 $ goto example_loop $example_loop_end: $! $! clean up the copy. $ purge [.docs.examples]gnv$*.opt $ rename [.docs.examples]gnv$*.opt ;1 $ endif $! $! $ if tests .ne. 0 $ then $ libtest_apps = "lib500,lib501,lib502,lib503,lib504,lib505,lib506,lib507" $ libtest_apps = libtest_apps + ",lib508,lib510,lib511,lib512,lib513,lib514" $ libtest_apps = libtest_apps + ",lib515,lib516,lib517,lib518,lib519,lib520" $ libtest_apps = libtest_apps + ",lib521,lib523,lib524,lib525,lib526,lib527" $ libtest_apps = libtest_apps + ",lib529,lib530,lib532,lib533,lib536,lib537" $ libtest_apps = libtest_apps + ",lib539,lib540,lib541,lib542,lib543,lib544" $ libtest_apps = libtest_apps + ",lib545,lib547,lib548,lib549,lib552,lib553" $ libtest_apps = libtest_apps + ",lib554,lib555,lib556,lib557,lib558,lib559" $ libtest_apps = libtest_apps + ",lib560,lib562,lib564" $ i = 0 $libtest_loop: $ ap_name = f$element(i, ",", libtest_apps) $ if ap_name .eqs. "," then goto libtest_loop_end $ if ap_name .eqs. "" then goto libtest_loop_end $ copy 'default_dir'gnv_template_linker.opt - [.tests.libtest]gnv$'ap_name'.opt $ i = i + 1 $ goto libtest_loop $libtest_loop_end: $! $! clean up the copy. $ purge [.tests.libtest]gnv$*.opt $ rename [.tests.libtest]gnv$*.opt ;1 $ endif $! $! $! Build the Message file. $!-------------------------- $ if f$search("[.packages.vms]curlmsg.obj") .eqs. "" $ then $ message [.packages.vms]curlmsg.msg/object=[.packages.vms] $ endif $ if f$search("gnv$curlmsg.exe") .eqs. "" $ then $ link/share=gnv$curlmsg.exe [.packages.vms]curlmsg.obj $ endif $! $! $! $! Need to build the common init module. $!------------------------------------------- $ init_obj = "[.packages.vms]curl_crtl_init.obj" $ if f$search(init_obj) .eqs. "" $ then $ cc'cflags' 'default_dir'curl_crtl_init.c/obj='init_obj' $ purge 'init_obj' $ rename 'init_obj' ;1 $ endif $! $all_exit: $! $ set def 'default_dir' $! $! Verify can break things in bash, especially in Configure scripts. $ set nover $ exit davix-0.8.0/deps/curl/packages/vms/build_gnv_curl_pcsi_text.com0000644000000000000000000001364114121063461023376 0ustar rootroot$! File: Build_GNV_curl_pcsi_text.com $! $! $Id$ $! $! Build the *.pcsi$text file from the four components: $! 1. Generated =product header section $! 2. [--]readme. file from the Curl distribution, modified to fit $! a pcsi$text file format. $! 3. [--]copying file from the Curl distribution, modified to fit $! a pcsi$text file format. $! 4. Generated Producer section. $! $! Set the name of the release notes from the GNV_PCSI_FILENAME_BASE $! $! Copyright 2009, John Malmberg $! $! Permission to use, copy, modify, and/or distribute this software for any $! purpose with or without fee is hereby granted, provided that the above $! copyright notice and this permission notice appear in all copies. $! $! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES $! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF $! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR $! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES $! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN $! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT $! OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $! $! $! 15-Jun-2009 J. Malmberg $! $!=========================================================================== $! $ kit_name = f$trnlnm("GNV_PCSI_KITNAME") $ if kit_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ producer = f$trnlnm("GNV_PCSI_PRODUCER") $ if producer .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $ producer_full_name = f$trnlnm("GNV_PCSI_PRODUCER_FULL_NAME") $ if producer_full_name .eqs. "" $ then $ write sys$output "@MAKE_PCSI_CURL_KIT_NAME.COM has not been run." $ goto all_exit $ endif $! $! $! Parse the kit name into components. $!--------------------------------------- $ producer = f$element(0, "-", kit_name) $ base = f$element(1, "-", kit_name) $ product = f$element(2, "-", kit_name) $ mmversion = f$element(3, "-", kit_name) $ majorver = f$extract(0, 3, mmversion) $ minorver = f$extract(3, 2, mmversion) $ updatepatch = f$element(4, "-", kit_name) $ if updatepatch .eqs. "-" then updatepatch = "" $! $! $ product_line = "=product ''producer' ''base' ''product'" $ if updatepatch .eqs. "" $ then $ product_name = " ''majorver'.''minorver'" $ else $ product_name = " ''majorver'.''minorver'-''updatepatch'" $ endif $ product_line = product_line + " ''product_name' full" $! $! $! If this is VAX and the file is on NFS, the names may be mangled. $!----------------------------------------------------------------- $ readme_file = "" $ if f$search("[--]readme.") .nes. "" $ then $ readme_file = "[--]readme." $ else $ if f$search("[--]$README.") .nes. "" $ then $ readme_file = "[--]$README." $ else $ write sys$output "Can not find readme file." $ goto all_exit $ endif $ endif $ copying_file = "" $ if f$search("[--]copying.") .nes. "" $ then $ copying_file = "[--]copying." $ else $ if f$search("[--]$COPYING.") .nes. "" $ then $ copying_file = "[--]$COPYING." $ else $ write sys$output "Can not find copying file." $ goto all_exit $ endif $ endif $! $! Create the file as a VMS text file. $!---------------------------------------- $ base_file = kit_name $ create 'base_file'.pcsi$text $! $! $! Start building file. $!---------------------- $ open/append ptxt 'base_file'.pcsi$text $ write ptxt product_line $! $! $! First insert the Readme file. $! $ open/read rf 'readme_file' $! $ write ptxt "1 'PRODUCT" $ write ptxt "=prompt ''producter' ''product' for OpenVMS" $! $rf_loop: $ read/end=rf_loop_end rf line_in $ if line_in .nes. "" $ then $! PCSI files use the first character in for their purposes. $!-------------------------------------------------------------- $ first_char = f$extract(0, 1, line_in) $ if first_char .nes. " " then line_in = " " + line_in $ endif $ write ptxt line_in $ goto rf_loop $rf_loop_end: $ close rf $! $! $! Now add in the copying file $!-------------------------------- $ write ptxt "" $ write ptxt "1 'NOTICE" $ write ptxt "" $! $ open/read cf 'copying_file' $! $cf_loop: $ read/end=cf_loop_end cf line_in $ if line_in .nes. "" $ then $! PCSI files use the first character in for their purposes. $!-------------------------------------------------------------- $ first_char = f$extract(0, 1, line_in) $ if first_char .nes. " " then line_in = " " + line_in $ endif $ write ptxt line_in $ goto cf_loop $cf_loop_end: $ close cf $! $! Now we need the rest of the boiler plate. $!-------------------------------------------- $ write ptxt "" $ write ptxt "1 'PRODUCER" $ write ptxt "=prompt ''producer_full_name'" $ write ptxt - "This software product is provided by ''producer_full_name' with no warranty." $! $ arch_type = f$getsyi("ARCH_NAME") $ node_swvers = f$getsyi("node_swvers") $ vernum = f$extract(1, f$length(node_swvers), node_swvers) $ majver = f$element(0, ".", vernum) $ minverdash = f$element(1, ".", vernum) $ minver = f$element(0, "-", minverdash) $ dashver = f$element(1, "-", minverdash) $ if dashver .eqs. "-" then dashver = "" $ vmstag = majver + minver + dashver $ code = f$extract(0, 1, arch_type) $! $ write ptxt "1 NEED_VMS''vmstag'" $ write ptxt - "=prompt OpenVMS ''vernum' or later is not installed on your system." $ write ptxt "This product requires OpenVMS ''vernum' or later to function." $ write ptxt "1 NEED_ZLIB" $ write ptxt "=prompt ZLIB 1.2-8 or later is not installed on your system." $ write ptxt "This product requires ZLIB 1.2-8 or later to function." $ write ptxt "1 SOURCE" $ write ptxt "=prompt Source modules for ''product'" $ write ptxt "The Source modules for ''product' will be installed." $ write ptxt "1 RELEASE_NOTES" $ write ptxt "=prompt Release notes are available in the [SYSHLP] directory." $! $ close ptxt $! $! $! $all_exit: $ exit davix-0.8.0/deps/curl/packages/TPF/0000755000000000000000000000000014121063461015435 5ustar rootrootdavix-0.8.0/deps/curl/packages/TPF/maketpf.env_curl0000644000000000000000000000232314121063461020623 0ustar rootroot################################################################################ ################################################################################ #env TPF CURL Includes ################################################################################ ################################################################################ ################################################################################ # Define the directories where the shared objects reside ################################################################################ ROOTLIBDIRS := $(foreach d,$(TPF_ROOT),$d/opensource/curl/output/lib) ################################################################################ # Set the include/header file directories ################################################################################ ROOTINCDIRS := $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/include) ROOTINCDIRS += $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/include/curl) ################################################################################ # Define "TPF" to enable TPF-specific code in Curl files. ################################################################################ CFLAGS_$(APP) += -D TPF davix-0.8.0/deps/curl/packages/TPF/curl.mak0000644000000000000000000000420714121063461017077 0ustar rootroot####################################################################### # # # MAKEFILE NAME..... curl.mak # # # # DESCRIPTION..... This is the makefile for libcurl. # # # ####################################################################### APP := CURL TPF_RUN_TPFSOCHK := NO ####################################################################### # Define any additional libs needed to link ####################################################################### LIBS := CRYP CSSL ####################################################################### # Define the envs needed to build this module ####################################################################### maketpf_env := curllib maketpf_env += openssl maketpf_env += base_rt maketpf_env += system ####################################################################### # Segments to be compiled with gcc compiler ####################################################################### # ### lib directory: include $(word 1,$(wildcard $(foreach d,$(TPF_ROOT),$d/opensource/curl/lib/Makefile.inc)) Makefile.inc_not_found) C_SRC := $(CSOURCES) ####################################################################### # Additions and overrides for gcc compiler flags ####################################################################### # suppress expected warnings in the ported code: CFLAGS_CURL += -w # use SSL # (overrides Curl's lib/config-tpf.h file) CFLAGS_CURL += -DUSE_OPENSSL # disable all protocols except FTP and HTTP # (overrides Curl's lib/config-tpf.h file) CFLAGS_CURL += -DCURL_DISABLE_DICT CFLAGS_CURL += -DCURL_DISABLE_FILE CFLAGS_CURL += -DCURL_DISABLE_LDAP CFLAGS_CURL += -DCURL_DISABLE_TELNET CFLAGS_CURL += -DCURL_DISABLE_TFTP ####################################################################### # Include the maketpf.rules ####################################################################### include maketpf.rules davix-0.8.0/deps/curl/packages/TPF/maketpf.env_curllib0000644000000000000000000000536614121063461021324 0ustar rootroot################################################################################ ################################################################################ #env TPF CURL Library Source and Output ################################################################################ ################################################################################ ################################################################################ # Define the directories where the shared objects reside ################################################################################ ROOTLIBDIRS := $(foreach d,$(TPF_ROOT),$d/opensource/curl/output/lib) ################################################################################ # Define the directories where the loadables (XXXXVV) are to be written ################################################################################ ROOTLOADDIRS := $(foreach d,$(TPF_ROOT),$d/opensource/curl/output/load) ################################################################################ # Define the location of the export files used by the LD postprocessor # - currently expected that .exp files will also live in lib dir ################################################################################ ROOTEXPDIRS := $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/output/exp) ################################################################################ # Define the object file directory name ################################################################################ ROOTOBJDIRS := $(foreach d,$(TPF_ROOT),$d/opensource/curl/output/obj) ################################################################################ # Define the listing files directory name ################################################################################ ROOTLSTDIRS := $(foreach d,$(TPF_ROOT),$d/opensource/curl/output/lst) ################################################################################ # Set the include/header file directories ################################################################################ ROOTINCDIRS := $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/lib) ROOTINCDIRS += $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/include) ROOTINCDIRS += $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/include/curl) ################################################################################ # Set the C file directories ################################################################################ ROOTCDIRS := $(foreach d,$(TPF_ROOT_LM),$d/opensource/curl/lib) ################################################################################ # Define "TPF" to enable TPF-specific code in Curl files. ################################################################################ CFLAGS_$(APP) += -D TPF davix-0.8.0/deps/curl/packages/Android/0000755000000000000000000000000014121063461016364 5ustar rootrootdavix-0.8.0/deps/curl/packages/Android/Android.mk0000644000000000000000000001056714121063461020306 0ustar rootroot# Google Android makefile for curl and libcurl # # This file can be used when building curl using the full Android source # release or the NDK. Most users do not want or need to do this; please # instead read the Android section in docs/INSTALL for alternate # methods. # # Place the curl source (including this makefile) into external/curl/ in the # Android source tree. Then build them with 'make curl' or just 'make libcurl' # from the Android root. Tested with Android versions 1.5, 2.1-2.3 # # Note: you must first create a curl_config.h file by running configure in the # Android environment. The only way I've found to do this is tricky. Perform a # normal Android build with libcurl in the source tree, providing the target # "showcommands" to make. The build will eventually fail (because curl_config.h # doesn't exist yet), but the compiler commands used to build curl will be # shown. Now, from the external/curl/ directory, run curl's normal configure # command with flags that match what Android itself uses. This will mean # putting the compiler directory into the PATH, putting the -I, -isystem and # -D options into CPPFLAGS, putting the -W, -m, -f, -O and -nostdlib options # into CFLAGS, and putting the -Wl, -L and -l options into LIBS, along with the # path to the files libgcc.a, crtbegin_dynamic.o, and ccrtend_android.o. # Remember that the paths must be absolute since you will not be running # configure from the same directory as the Android make. The normal # cross-compiler options must also be set. Note that the -c, -o, -MD and # similar flags must not be set. # # To see all the LIBS options, you'll need to do the "showcommands" trick on an # executable that's already buildable and watch what flags Android uses to link # it (dhcpcd is a good choice to watch). You'll also want to add -L options to # LIBS that point to the out/.../obj/lib/ and out/.../obj/system/lib/ # directories so that additional libraries can be found and used by curl. # # The end result will be a configure command that looks something like this # (the environment variable A is set to the Android root path which makes the # command shorter): # # A=`realpath ../..` && \ # PATH="$A/prebuilt/linux-x86/toolchain/arm-eabi-X/bin:$PATH" \ # ./configure --host=arm-linux CC=arm-eabi-gcc \ # CPPFLAGS="-I $A/system/core/include ..." \ # CFLAGS="-nostdlib -fno-exceptions -Wno-multichar ..." \ # LIBS="$A/prebuilt/linux-x86/toolchain/arm-eabi-X/lib/gcc/arm-eabi/X\ # /interwork/libgcc.a ..." # # Finally, copy the file COPYING to NOTICE so that the curl license gets put # into the right place (but see the note about this below). # # Dan Fandrich # November 2011 LOCAL_PATH:= $(call my-dir)/../.. common_CFLAGS := -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -DHAVE_CONFIG_H ######################### # Build the libcurl library include $(CLEAR_VARS) include $(LOCAL_PATH)/lib/Makefile.inc CURL_HEADERS := \ curl.h \ system.h \ curlver.h \ easy.h \ mprintf.h \ multi.h \ stdcheaders.h \ typecheck-gcc.h LOCAL_SRC_FILES := $(addprefix lib/,$(CSOURCES)) LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/ LOCAL_CFLAGS += $(common_CFLAGS) LOCAL_COPY_HEADERS_TO := libcurl/curl LOCAL_COPY_HEADERS := $(addprefix include/curl/,$(CURL_HEADERS)) LOCAL_MODULE:= libcurl LOCAL_MODULE_TAGS := optional # Copy the licence to a place where Android will find it. # Actually, this doesn't quite work because the build system searches # for NOTICE files before it gets to this point, so it will only be seen # on subsequent builds. ALL_PREBUILT += $(LOCAL_PATH)/NOTICE $(LOCAL_PATH)/NOTICE: $(LOCAL_PATH)/COPYING | $(ACP) $(copy-file-to-target) include $(BUILD_STATIC_LIBRARY) ######################### # Build the curl binary include $(CLEAR_VARS) include $(LOCAL_PATH)/src/Makefile.inc LOCAL_SRC_FILES := $(addprefix src/,$(CURL_CFILES)) LOCAL_MODULE := curl LOCAL_MODULE_TAGS := optional LOCAL_STATIC_LIBRARIES := libcurl LOCAL_SYSTEM_SHARED_LIBRARIES := libc LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/lib # This may also need to include $(CURLX_CFILES) in order to correctly link # if libcurl is changed to be built as a dynamic library LOCAL_CFLAGS += $(common_CFLAGS) include $(BUILD_EXECUTABLE) davix-0.8.0/deps/curl/packages/OS400/0000755000000000000000000000000014121063461015551 5ustar rootrootdavix-0.8.0/deps/curl/packages/OS400/README.OS4000000644000000000000000000003400514121063461017177 0ustar rootroot Implementation notes: This is a true OS/400 implementation, not a PASE implementation (for PASE, use AIX implementation). The biggest problem with OS/400 is EBCDIC. Libcurl implements an internal conversion mechanism, but it has been designed for computers that have a single native character set. OS/400 default native character set varies depending on the country for which it has been localized. And more, a job may dynamically alter its "native" character set. Several characters that do not have fixed code in EBCDIC variants are used in libcurl strings. As a consequence, using the existing conversion mechanism would have lead in a localized binary library - not portable across countries. For this reason, and because libcurl was originally designed for ASCII based operating systems, the current OS/400 implementation uses ASCII as internal character set. This has been accomplished using the QADRT library and include files, a C and system procedures ASCII wrapper library. See IBM QADRT description for more information. This then results in libcurl being an ASCII library: any function string argument is taken/returned in ASCII and a C/C++ calling program built around QADRT may use libcurl functions as on any other platform. QADRT does not define ASCII wrappers for all C/system procedures: the OS/400 configuration header file and an additional module (os400sys.c) define some more of them, that are used by libcurl and that QADRT left out. To support all the different variants of EBCDIC, non-standard wrapper procedures have been added to libcurl on OS/400: they provide an additional CCSID (numeric Coded Character Set ID specific to OS/400) parameter for each string argument. String values passed to callback procedures are NOT converted, so text gathered this way is (probably !) ASCII. Another OS/400 problem comes from the fact that the last fixed argument of a vararg procedure may not be of type char, unsigned char, short or unsigned short. Enums that are internally implemented by the C compiler as one of these types are also forbidden. Libcurl uses enums as vararg procedure tagfields... Happily, there is a pragma forcing enums to type "int". The original libcurl header files are thus altered during build process to use this pragma, in order to force libcurl enums of being type int (the pragma disposition in use before inclusion is restored before resuming the including unit compilation). Secure socket layer is provided by the IBM GSKit API: unlike other SSL implementations, GSKit is based on "certificate stores" or keyrings rather than individual certificate/key files. Certificate stores, as well as "certificate labels" are managed by external IBM-defined applications. There are two ways to specify an SSL context: - By an application identifier. - By a keyring file pathname and (optionally) certificate label. To identify an SSL context by application identifier, use option SETOPT_SSLCERT to specify the application identifier. To address an SSL context by keyring and certificate label, use CURLOPT_CAINFO to set-up the keyring pathname, CURLOPT_SSLCERT to define the certificate label (omitting it will cause the default certificate in keyring to be used) and CURLOPT_KEYPASSWD to give the keyring password. If SSL is used without defining any of these options, the default (i.e.: system) keyring is used for server certificate validation. Non-standard EBCDIC wrapper prototypes are defined in an additional header file: ccsidcurl.h. These should be self-explanatory to an OS/400-aware designer. CCSID 0 can be used to select the current job's CCSID. Wrapper procedures with variable arguments are described below: _ curl_easy_setopt_ccsid() Variable arguments are a string pointer and a CCSID (unsigned int) for options: CURLOPT_ABSTRACT_UNIX_SOCKET CURLOPT_ALTSVC CURLOPT_CAINFO CURLOPT_CAPATH CURLOPT_COOKIE CURLOPT_COOKIEFILE CURLOPT_COOKIEJAR CURLOPT_COOKIELIST CURLOPT_COPYPOSTFIELDS CURLOPT_CRLFILE CURLOPT_CUSTOMREQUEST CURLOPT_DEFAULT_PROTOCOL CURLOPT_DNS_SERVERS CURLOPT_DOH_URL CURLOPT_EGDSOCKET CURLOPT_ENCODING CURLOPT_FTPPORT CURLOPT_FTP_ACCOUNT CURLOPT_FTP_ALTERNATIVE_TO_USER CURLOPT_INTERFACE CURLOPT_ISSUERCERT CURLOPT_KEYPASSWD CURLOPT_KRBLEVEL CURLOPT_LOGIN_OPTIONS CURLOPT_MAIL_AUTH CURLOPT_MAIL_FROM CURLOPT_NETRC_FILE CURLOPT_NOPROXY CURLOPT_PASSWORD CURLOPT_PINNEDPUBLICKEY CURLOPT_PRE_PROXY CURLOPT_PROXY CURLOPT_PROXYPASSWORD CURLOPT_PROXYUSERNAME CURLOPT_PROXYUSERPWD CURLOPT_PROXY_CAINFO CURLOPT_PROXY_CAPATH CURLOPT_PROXY_CRLFILE CURLOPT_PROXY_KEYPASSWD CURLOPT_PROXY_PINNEDPUBLICKEY CURLOPT_PROXY_SERVICE_NAME CURLOPT_PROXY_SSLCERT CURLOPT_PROXY_SSLCERTTYPE CURLOPT_PROXY_SSLKEY CURLOPT_PROXY_SSLKEYTYPE CURLOPT_PROXY_SSL_CIPHER_LIST CURLOPT_PROXY_TLS13_CIPHERS CURLOPT_PROXY_TLSAUTH_PASSWORD CURLOPT_PROXY_TLSAUTH_TYPE CURLOPT_PROXY_TLSAUTH_USERNAME CURLOPT_RANDOM_FILE CURLOPT_RANGE CURLOPT_REFERER CURLOPT_REQUEST_TARGET CURLOPT_RTSP_SESSION_UID CURLOPT_RTSP_STREAM_URI CURLOPT_RTSP_TRANSPORT CURLOPT_SASL_AUTHZID CURLOPT_SERVICE_NAME CURLOPT_SOCKS5_GSSAPI_SERVICE CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 CURLOPT_SSH_KNOWNHOSTS CURLOPT_SSH_PRIVATE_KEYFILE CURLOPT_SSH_PUBLIC_KEYFILE CURLOPT_SSLCERT CURLOPT_SSLCERTTYPE CURLOPT_SSLENGINE CURLOPT_SSLKEY CURLOPT_SSLKEYTYPE CURLOPT_SSL_CIPHER_LIST CURLOPT_TLS13_CIPHERS CURLOPT_TLSAUTH_PASSWORD CURLOPT_TLSAUTH_TYPE CURLOPT_TLSAUTH_USERNAME CURLOPT_UNIX_SOCKET_PATH CURLOPT_URL CURLOPT_USERAGENT CURLOPT_USERNAME CURLOPT_USERPWD CURLOPT_XOAUTH2_BEARER Else it is the same as for curl_easy_setopt(). Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the address of an (empty) character buffer, not the address of a string. CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) and thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the CCSID conversion result length. _ curl_formadd_ccsid() In the variable argument list, string pointers should be followed by a (long) CCSID for the following options: CURLFORM_FILENAME CURLFORM_CONTENTTYPE CURLFORM_BUFFER CURLFORM_FILE CURLFORM_FILECONTENT CURLFORM_COPYCONTENTS CURLFORM_COPYNAME CURLFORM_PTRNAME If taken from an argument array, an additional array entry must follow each entry containing one of the above option. This additional entry holds the CCSID in its value field, and the option field is meaningless. It is not possible to have a string pointer and its CCSID across a function parameter/array boundary. Please note that CURLFORM_PTRCONTENTS and CURLFORM_BUFFERPTR are considered unconvertible strings and thus are NOT followed by a CCSID. _ curl_easy_getinfo_ccsid() The following options are followed by a 'char * *' and a CCSID. Unlike curl_easy_getinfo(), the value returned in the pointer should be freed after use: CURLINFO_EFFECTIVE_URL CURLINFO_CONTENT_TYPE CURLINFO_FTP_ENTRY_PATH CURLINFO_REDIRECT_URL CURLINFO_PRIMARY_IP CURLINFO_RTSP_SESSION_ID CURLINFO_LOCAL_IP CURLINFO_SCHEME Likewise, the following options are followed by a struct curl_slist * * and a CCSID. CURLINFO_SSL_ENGINES CURLINFO_COOKIELIST Lists returned should be released with curl_slist_free_all() after use. Option CURLINFO_CERTINFO is followed by a struct curl_certinfo * * and a CCSID. Returned structures should be free'ed using curl_certinfo_free_all() after use. Other options are processed like in curl_easy_getinfo(). _ curl_pushheader_bynum_cssid() and curl_pushheader_byname_ccsid() Although the prototypes are self-explanatory, the returned string pointer should be freed after use, as opposite to the non-ccsid versions of these procedures. Please note that HTTP2 is not (yet) implemented on OS/400, thus these functions will always return NULL. Standard compilation environment does support neither autotools nor make; in fact, very few common utilities are available. As a consequence, the config-os400.h has been coded manually and the compilation scripts are a set of shell scripts stored in subdirectory packages/OS400. The "curl" command and the test environment are currently not supported on OS/400. Protocols currently implemented on OS/400: _ DICT _ FILE _ FTP _ FTPS _ FTP with secure transmission _ GOPHER _ HTTP _ HTTPS _ IMAP _ IMAPS _ IMAP with secure transmission _ LDAP _ POP3 _ POP3S _ POP3 with secure transmission _ RTSP _ SCP if libssh2 is enabled _ SFTP if libssh2 is enabled _ SMTP _ SMTPS _ SMTP with secure transmission _ TELNET _ TFTP Compiling on OS/400: These instructions targets people who knows about OS/400, compiling, IFS and archive extraction. Do not ask questions about these subjects if you're not familiar with. _ As a prerequisite, QADRT development environment must be installed. _ If data compression has to be supported, ZLIB development environment must be installed. _ Likewise, if SCP and SFTP protocols have to be compiled in, LIBSSH2 developent environment must be installed. _ Install the curl source directory in IFS. Do NOT install it in the installation target directory (which defaults to /curl). _ Enter shell (QSH) _ Change current directory to the curl installation directory _ Change current directory to ./packages/OS400 _ Edit file iniscript.sh. You may want to change tunable configuration parameters, like debug info generation, optimisation level, listing option, target library, ZLIB/LIBSSH2 availability and location, etc. _ Copy any file in the current directory to makelog (i.e.: cp initscript.sh makelog): this is intended to create the makelog file with an ASCII CCSID! _ Enter the command "sh makefile.sh > makelog 2>&1' _ Examine the makelog file to check for compilation errors. Leaving file initscript.sh unchanged, this will produce the following OS/400 objects: _ Library CURL. All other objects will be stored in this library. _ Modules for all libcurl units. _ Binding directory CURL_A, to be used at calling program link time for statically binding the modules (specify BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR) when creating a program using CURL_A). _ Service program CURL., where is extracted from the lib/Makefile.am VERSION variable. To be used at calling program run-time when this program has dynamically bound curl at link time. _ Binding directory CURL. To be used to dynamically bind libcurl when linking a calling program. _ Source file H. It contains all the include members needed to compile a C/C++ module using libcurl, and an ILE/RPG /copy member for support in this language. _ Standard C/C++ libcurl include members in file H. _ CCSIDCURL member in file H. This defines the non-standard EBCDIC wrappers for C and C++. _ CURL.INC member in file H. This defines everything needed by an ILE/RPG program using libcurl. _ LIBxxx modules and programs. Although the test environment is not supported on OS/400, the libcurl test programs are compiled for manual tests. _ IFS directory /curl/include/curl containing the C header files for IFS source C/C++ compilation and curl.inc.rpgle for IFS source ILE/RPG compilation. Special programming consideration: QADRT being used, the following points must be considered: _ If static binding is used, service program QADRTTS must be linked too. _ The EBCDIC CCSID used by QADRT is 37 by default, NOT THE JOB'S CCSID. If another EBCDIC CCSID is required, it must be set via a locale through a call to setlocale_a (QADRT's setlocale() ASCII wrapper) with category LC_ALL or LC_CTYPE, or by setting environment variable QADRT_ENV_LOCALE to the locale object path before executing the program. _ Do not use original source include files unless you know what you are doing. Use the installed members instead (in /QSYS.LIB/CURL.LIB/H.FILE and /curl/include/curl). ILE/RPG support: Since 95% of the OS/400 programmers use ILE/RPG exclusively, a definition /INCLUDE member is provided for this language. To include all libcurl definitions in an ILE/RPG module, line h bnddir('CURL/CURL') must figure in the program header, and line d/include curl/h,curl.inc in the global data section of the module's source code. No vararg procedure support exists in ILE/RPG: for this reason, the following considerations apply: _ Procedures curl_easy_setopt_long(), curl_easy_setopt_object(), curl_easy_setopt_function() and curl_easy_setopt_offset() are all alias prototypes to curl_easy_setopt(), but with different parameter lists. _ Procedures curl_easy_getinfo_string(), curl_easy_getinfo_long(), curl_easy_getinfo_double(), curl_easy_getinfo_slist(), curl_easy_getinfo_ptr(), curl_easy_getinfo_socket() and curl_easy_getinfo_off_t() are all alias prototypes to curl_easy_getinfo(), but with different parameter lists. _ Procedures curl_multi_setopt_long(), curl_multi_setopt_object(), curl_multi_setopt_function() and curl_multi_setopt_offset() are all alias prototypes to curl_multi_setopt(), but with different parameter lists. _ The prototype of procedure curl_formadd() allows specifying a pointer option and the CURLFORM_END option. This makes possible to use an option array without any additional definition. If some specific incompatible argument list is used in the ILE/RPG program, the latter must define a specialised alias. The same applies to curl_formadd_ccsid() too. Since RPG cannot cast a long to a pointer, procedure curl_form_long_value() is provided for that purpose: this allows storing a long value in the curl_forms array. davix-0.8.0/deps/curl/packages/OS400/makefile.sh0000644000000000000000000000310214121063461017656 0ustar rootroot#!/bin/sh # # curl compilation script for the OS/400. # # # This is a shell script since make is not a standard component of OS/400. SCRIPTDIR=`dirname "${0}"` . "${SCRIPTDIR}/initscript.sh" cd "${TOPDIR}" # Create the OS/400 library if it does not exist. if action_needed "${LIBIFSNAME}" then CMD="CRTLIB LIB(${TARGETLIB}) TEXT('curl: multiprotocol support API')" system "${CMD}" fi # Create the DOCS source file if it does not exist. if action_needed "${LIBIFSNAME}/DOCS.FILE" then CMD="CRTSRCPF FILE(${TARGETLIB}/DOCS) RCDLEN(240)" CMD="${CMD} CCSID(${TGTCCSID}) TEXT('Documentation texts')" system "${CMD}" fi # Copy some documentation files if needed. for TEXT in "${TOPDIR}/COPYING" "${SCRIPTDIR}/README.OS400" \ "${TOPDIR}/CHANGES" "${TOPDIR}/docs/THANKS" "${TOPDIR}/docs/FAQ" \ "${TOPDIR}/docs/FEATURES" "${TOPDIR}/docs/SSLCERTS.md" \ "${TOPDIR}/docs/RESOURCES" "${TOPDIR}/docs/VERSIONS" \ "${TOPDIR}/docs/HISTORY.md" do MEMBER="`basename \"${TEXT}\" .OS400`" MEMBER="`basename \"${MEMBER}\" .md`" MEMBER="${LIBIFSNAME}/DOCS.FILE/`db2_name \"${MEMBER}\"`.MBR" if action_needed "${MEMBER}" "${TEXT}" then CMD="CPY OBJ('${TEXT}') TOOBJ('${MEMBER}') TOCCSID(${TGTCCSID})" CMD="${CMD} DTAFMT(*TEXT) REPLACE(*YES)" system "${CMD}" fi done # Build in each directory. # for SUBDIR in include lib src tests for SUBDIR in include lib src do "${SCRIPTDIR}/make-${SUBDIR}.sh" done davix-0.8.0/deps/curl/packages/OS400/os400sys.c0000644000000000000000000007764414121063461017343 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * ***************************************************************************/ /* OS/400 additional support. */ #include #include "config-os400.h" /* Not curl_setup.h: we only need some defines. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ZLIB_H #include #endif #ifdef USE_GSKIT #include #include #endif #ifdef HAVE_GSSAPI #include #endif #ifndef CURL_DISABLE_LDAP #include #endif #include #include #include "os400sys.h" /** *** QADRT OS/400 ASCII runtime defines only the most used procedures, but *** but a lot of them are not supported. This module implements *** ASCII wrappers for those that are used by libcurl, but not *** defined by QADRT. **/ #pragma convert(0) /* Restore EBCDIC. */ #define MIN_BYTE_GAIN 1024 /* Minimum gain when shortening a buffer. */ typedef struct { unsigned long size; /* Buffer size. */ char * buf; /* Buffer address. */ } buffer_t; static char * buffer_undef(localkey_t key, long size); static char * buffer_threaded(localkey_t key, long size); static char * buffer_unthreaded(localkey_t key, long size); static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t thdkey; static buffer_t * locbufs; char * (* Curl_thread_buffer)(localkey_t key, long size) = buffer_undef; static void thdbufdestroy(void * private) { if(private) { buffer_t * p = (buffer_t *) private; localkey_t i; for(i = (localkey_t) 0; i < LK_LAST; i++) { free(p->buf); p++; } free(private); } } static void terminate(void) { if(Curl_thread_buffer == buffer_threaded) { locbufs = pthread_getspecific(thdkey); pthread_setspecific(thdkey, (void *) NULL); pthread_key_delete(thdkey); } if(Curl_thread_buffer != buffer_undef) { thdbufdestroy((void *) locbufs); locbufs = (buffer_t *) NULL; } Curl_thread_buffer = buffer_undef; } static char * get_buffer(buffer_t * buf, long size) { char * cp; /* If `size' >= 0, make sure buffer at `buf' is at least `size'-byte long. Return the buffer address. */ if(size < 0) return buf->buf; if(!buf->buf) { buf->buf = malloc(size); if(buf->buf) buf->size = size; return buf->buf; } if((unsigned long) size <= buf->size) { /* Shorten the buffer only if it frees a significant byte count. This avoids some realloc() overhead. */ if(buf->size - size < MIN_BYTE_GAIN) return buf->buf; } /* Resize the buffer. */ cp = realloc(buf->buf, size); if(cp) { buf->buf = cp; buf->size = size; } else if(size <= buf->size) cp = buf->buf; return cp; } static char * buffer_unthreaded(localkey_t key, long size) { return get_buffer(locbufs + key, size); } static char * buffer_threaded(localkey_t key, long size) { buffer_t * bufs; /* Get the buffer for the given local key in the current thread, and make sure it is at least `size'-byte long. Set `size' to < 0 to get its address only. */ bufs = (buffer_t *) pthread_getspecific(thdkey); if(!bufs) { if(size < 0) return (char *) NULL; /* No buffer yet. */ /* Allocate buffer descriptors for the current thread. */ bufs = calloc((size_t) LK_LAST, sizeof(*bufs)); if(!bufs) return (char *) NULL; if(pthread_setspecific(thdkey, (void *) bufs)) { free(bufs); return (char *) NULL; } } return get_buffer(bufs + key, size); } static char * buffer_undef(localkey_t key, long size) { /* Define the buffer system, get the buffer for the given local key in the current thread, and make sure it is at least `size'-byte long. Set `size' to < 0 to get its address only. */ pthread_mutex_lock(&mutex); /* Determine if we can use pthread-specific data. */ if(Curl_thread_buffer == buffer_undef) { /* If unchanged during lock. */ if(!pthread_key_create(&thdkey, thdbufdestroy)) Curl_thread_buffer = buffer_threaded; else if(!(locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs)))) { pthread_mutex_unlock(&mutex); return (char *) NULL; } else Curl_thread_buffer = buffer_unthreaded; atexit(terminate); } pthread_mutex_unlock(&mutex); return Curl_thread_buffer(key, size); } static char * set_thread_string(localkey_t key, const char * s) { int i; char * cp; if(!s) return (char *) NULL; i = strlen(s) + 1; cp = Curl_thread_buffer(key, MAX_CONV_EXPANSION * i + 1); if(cp) { i = QadrtConvertE2A(cp, s, MAX_CONV_EXPANSION * i, i); cp[i] = '\0'; } return cp; } int Curl_getnameinfo_a(const struct sockaddr * sa, curl_socklen_t salen, char * nodename, curl_socklen_t nodenamelen, char * servname, curl_socklen_t servnamelen, int flags) { char *enodename = NULL; char *eservname = NULL; int status; if(nodename && nodenamelen) { enodename = malloc(nodenamelen); if(!enodename) return EAI_MEMORY; } if(servname && servnamelen) { eservname = malloc(servnamelen); if(!eservname) { free(enodename); return EAI_MEMORY; } } status = getnameinfo(sa, salen, enodename, nodenamelen, eservname, servnamelen, flags); if(!status) { int i; if(enodename) { i = QadrtConvertE2A(nodename, enodename, nodenamelen - 1, strlen(enodename)); nodename[i] = '\0'; } if(eservname) { i = QadrtConvertE2A(servname, eservname, servnamelen - 1, strlen(eservname)); servname[i] = '\0'; } } free(enodename); free(eservname); return status; } int Curl_getaddrinfo_a(const char * nodename, const char * servname, const struct addrinfo * hints, struct addrinfo * * res) { char * enodename; char * eservname; int status; int i; enodename = (char *) NULL; eservname = (char *) NULL; if(nodename) { i = strlen(nodename); enodename = malloc(i + 1); if(!enodename) return EAI_MEMORY; i = QadrtConvertA2E(enodename, nodename, i, i); enodename[i] = '\0'; } if(servname) { i = strlen(servname); eservname = malloc(i + 1); if(!eservname) { free(enodename); return EAI_MEMORY; } QadrtConvertA2E(eservname, servname, i, i); eservname[i] = '\0'; } status = getaddrinfo(enodename, eservname, hints, res); free(enodename); free(eservname); return status; } #ifdef USE_GSKIT /* ASCII wrappers for the GSKit procedures. */ /* * EBCDIC --> ASCII string mapping table. * Some strings returned by GSKit are dynamically allocated and automatically * released when closing the handle. * To provide the same functionality, we use a "private" handle that * holds the GSKit handle and a list of string mappings. This will allow * avoid conversion of already converted strings and releasing them upon * close time. */ struct gskstrlist { struct gskstrlist * next; const char * ebcdicstr; const char * asciistr; }; struct Curl_gsk_descriptor { gsk_handle h; struct gskstrlist * strlist; }; int Curl_gsk_environment_open(gsk_handle * my_env_handle) { struct Curl_gsk_descriptor * p; int rc; if(!my_env_handle) return GSK_OS400_ERROR_INVALID_POINTER; p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p)); if(!p) return GSK_INSUFFICIENT_STORAGE; p->strlist = (struct gskstrlist *) NULL; rc = gsk_environment_open(&p->h); if(rc != GSK_OK) free(p); else *my_env_handle = (gsk_handle) p; return rc; } int Curl_gsk_secure_soc_open(gsk_handle my_env_handle, gsk_handle * my_session_handle) { struct Curl_gsk_descriptor * p; gsk_handle h; int rc; if(!my_env_handle) return GSK_INVALID_HANDLE; if(!my_session_handle) return GSK_OS400_ERROR_INVALID_POINTER; h = ((struct Curl_gsk_descriptor *) my_env_handle)->h; p = (struct Curl_gsk_descriptor *) malloc(sizeof(*p)); if(!p) return GSK_INSUFFICIENT_STORAGE; p->strlist = (struct gskstrlist *) NULL; rc = gsk_secure_soc_open(h, &p->h); if(rc != GSK_OK) free(p); else *my_session_handle = (gsk_handle) p; return rc; } static void gsk_free_handle(struct Curl_gsk_descriptor * p) { struct gskstrlist * q; while((q = p->strlist)) { p->strlist = q; free((void *) q->asciistr); free(q); } free(p); } int Curl_gsk_environment_close(gsk_handle * my_env_handle) { struct Curl_gsk_descriptor * p; int rc; if(!my_env_handle) return GSK_OS400_ERROR_INVALID_POINTER; if(!*my_env_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) *my_env_handle; rc = gsk_environment_close(&p->h); if(rc == GSK_OK) { gsk_free_handle(p); *my_env_handle = (gsk_handle) NULL; } return rc; } int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle) { struct Curl_gsk_descriptor * p; int rc; if(!my_session_handle) return GSK_OS400_ERROR_INVALID_POINTER; if(!*my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) *my_session_handle; rc = gsk_secure_soc_close(&p->h); if(rc == GSK_OK) { gsk_free_handle(p); *my_session_handle = (gsk_handle) NULL; } return rc; } int Curl_gsk_environment_init(gsk_handle my_env_handle) { struct Curl_gsk_descriptor * p; if(!my_env_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_env_handle; return gsk_environment_init(p->h); } int Curl_gsk_secure_soc_init(gsk_handle my_session_handle) { struct Curl_gsk_descriptor * p; if(!my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_session_handle; return gsk_secure_soc_init(p->h); } int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, const char * buffer, int bufSize) { struct Curl_gsk_descriptor * p; char * ebcdicbuf; int rc; if(!my_gsk_handle) return GSK_INVALID_HANDLE; if(!buffer) return GSK_OS400_ERROR_INVALID_POINTER; if(bufSize < 0) return GSK_ATTRIBUTE_INVALID_LENGTH; p = (struct Curl_gsk_descriptor *) my_gsk_handle; if(!bufSize) bufSize = strlen(buffer); ebcdicbuf = malloc(bufSize + 1); if(!ebcdicbuf) return GSK_INSUFFICIENT_STORAGE; QadrtConvertA2E(ebcdicbuf, buffer, bufSize, bufSize); ebcdicbuf[bufSize] = '\0'; rc = gsk_attribute_set_buffer(p->h, bufID, ebcdicbuf, bufSize); free(ebcdicbuf); return rc; } int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID, GSK_ENUM_VALUE enumValue) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; return gsk_attribute_set_enum(p->h, enumID, enumValue); } int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle, GSK_NUM_ID numID, int numValue) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; return gsk_attribute_set_numeric_value(p->h, numID, numValue); } int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle, GSK_CALLBACK_ID callBackID, void * callBackAreaPtr) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; return gsk_attribute_set_callback(p->h, callBackID, callBackAreaPtr); } static int cachestring(struct Curl_gsk_descriptor * p, const char * ebcdicbuf, int bufsize, const char * * buffer) { int rc; char * asciibuf; struct gskstrlist * sp; for(sp = p->strlist; sp; sp = sp->next) if(sp->ebcdicstr == ebcdicbuf) break; if(!sp) { sp = (struct gskstrlist *) malloc(sizeof(*sp)); if(!sp) return GSK_INSUFFICIENT_STORAGE; asciibuf = malloc(bufsize + 1); if(!asciibuf) { free(sp); return GSK_INSUFFICIENT_STORAGE; } QadrtConvertE2A(asciibuf, ebcdicbuf, bufsize, bufsize); asciibuf[bufsize] = '\0'; sp->ebcdicstr = ebcdicbuf; sp->asciistr = asciibuf; sp->next = p->strlist; p->strlist = sp; } *buffer = sp->asciistr; return GSK_OK; } int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, const char * * buffer, int * bufSize) { struct Curl_gsk_descriptor * p; int rc; const char * mybuf; int mylen; if(!my_gsk_handle) return GSK_INVALID_HANDLE; if(!buffer || !bufSize) return GSK_OS400_ERROR_INVALID_POINTER; p = (struct Curl_gsk_descriptor *) my_gsk_handle; rc = gsk_attribute_get_buffer(p->h, bufID, &mybuf, &mylen); if(rc != GSK_OK) return rc; rc = cachestring(p, mybuf, mylen, buffer); if(rc == GSK_OK) *bufSize = mylen; return rc; } int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID, GSK_ENUM_VALUE * enumValue) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; return gsk_attribute_get_enum(p->h, enumID, enumValue); } int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle, GSK_NUM_ID numID, int * numValue) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; return gsk_attribute_get_numeric_value(p->h, numID, numValue); } int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle, GSK_CERT_ID certID, const gsk_cert_data_elem * * certDataElem, int * certDataElementCount) { struct Curl_gsk_descriptor * p; if(!my_gsk_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_gsk_handle; /* No need to convert code: text results are already in ASCII. */ return gsk_attribute_get_cert_info(p->h, certID, certDataElem, certDataElementCount); } int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, GSK_MISC_ID miscID) { struct Curl_gsk_descriptor * p; if(!my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_session_handle; return gsk_secure_soc_misc(p->h, miscID); } int Curl_gsk_secure_soc_read(gsk_handle my_session_handle, char * readBuffer, int readBufSize, int * amtRead) { struct Curl_gsk_descriptor * p; if(!my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_session_handle; return gsk_secure_soc_read(p->h, readBuffer, readBufSize, amtRead); } int Curl_gsk_secure_soc_write(gsk_handle my_session_handle, char * writeBuffer, int writeBufSize, int * amtWritten) { struct Curl_gsk_descriptor * p; if(!my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_session_handle; return gsk_secure_soc_write(p->h, writeBuffer, writeBufSize, amtWritten); } const char * Curl_gsk_strerror_a(int gsk_return_value) { return set_thread_string(LK_GSK_ERROR, gsk_strerror(gsk_return_value)); } int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle, int IOCompletionPort, Qso_OverlappedIO_t * communicationsArea) { struct Curl_gsk_descriptor * p; if(!my_session_handle) return GSK_INVALID_HANDLE; p = (struct Curl_gsk_descriptor *) my_session_handle; return gsk_secure_soc_startInit(p->h, IOCompletionPort, communicationsArea); } #endif /* USE_GSKIT */ #ifdef HAVE_GSSAPI /* ASCII wrappers for the GSSAPI procedures. */ static int Curl_gss_convert_in_place(OM_uint32 * minor_status, gss_buffer_t buf) { unsigned int i = buf->length; /* Convert `buf' in place, from EBCDIC to ASCII. If error, release the buffer and return -1. Else return 0. */ if(i) { char *t = malloc(i); if(!t) { gss_release_buffer(minor_status, buf); if(minor_status) *minor_status = ENOMEM; return -1; } QadrtConvertE2A(t, buf->value, i, i); memcpy(buf->value, t, i); free(t); } return 0; } OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status, gss_buffer_t in_name, gss_OID in_name_type, gss_name_t * out_name) { int rc; unsigned int i; gss_buffer_desc in; if(!in_name || !in_name->value || !in_name->length) return gss_import_name(minor_status, in_name, in_name_type, out_name); memcpy((char *) &in, (char *) in_name, sizeof(in)); i = in.length; in.value = malloc(i + 1); if(!in.value) { if(minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } QadrtConvertA2E(in.value, in_name->value, i, i); ((char *) in.value)[i] = '\0'; rc = gss_import_name(minor_status, &in, in_name_type, out_name); free(in.value); return rc; } OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status, OM_uint32 status_value, int status_type, gss_OID mech_type, gss_msg_ctx_t * message_context, gss_buffer_t status_string) { int rc; rc = gss_display_status(minor_status, status_value, status_type, mech_type, message_context, status_string); if(rc != GSS_S_COMPLETE || !status_string || !status_string->length || !status_string->value) return rc; /* No way to allocate a buffer here, because it will be released by gss_release_buffer(). The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ if(Curl_gss_convert_in_place(minor_status, status_string)) return GSS_S_FAILURE; return rc; } OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status, gss_cred_id_t cred_handle, gss_ctx_id_t * context_handle, gss_name_t target_name, gss_OID mech_type, gss_flags_t req_flags, OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, gss_flags_t * ret_flags, OM_uint32 * time_rec) { int rc; gss_buffer_desc in; gss_buffer_t inp; in.value = NULL; inp = input_token; if(inp) { if(inp->length && inp->value) { unsigned int i = inp->length; in.value = malloc(i + 1); if(!in.value) { if(minor_status) *minor_status = ENOMEM; return GSS_S_FAILURE; } QadrtConvertA2E(in.value, input_token->value, i, i); ((char *) in.value)[i] = '\0'; in.length = i; inp = ∈ } } rc = gss_init_sec_context(minor_status, cred_handle, context_handle, target_name, mech_type, req_flags, time_req, input_chan_bindings, inp, actual_mech_type, output_token, ret_flags, time_rec); free(in.value); if(rc != GSS_S_COMPLETE || !output_token || !output_token->length || !output_token->value) return rc; /* No way to allocate a buffer here, because it will be released by gss_release_buffer(). The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ if(Curl_gss_convert_in_place(minor_status, output_token)) return GSS_S_FAILURE; return rc; } OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, gss_buffer_t output_token) { int rc; rc = gss_delete_sec_context(minor_status, context_handle, output_token); if(rc != GSS_S_COMPLETE || !output_token || !output_token->length || !output_token->value) return rc; /* No way to allocate a buffer here, because it will be released by gss_release_buffer(). The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ if(Curl_gss_convert_in_place(minor_status, output_token)) return GSS_S_FAILURE; return rc; } #endif /* HAVE_GSSAPI */ #ifndef CURL_DISABLE_LDAP /* ASCII wrappers for the LDAP procedures. */ void * Curl_ldap_init_a(char * host, int port) { unsigned int i; char * ehost; void * result; if(!host) return (void *) ldap_init(host, port); i = strlen(host); ehost = malloc(i + 1); if(!ehost) return (void *) NULL; QadrtConvertA2E(ehost, host, i, i); ehost[i] = '\0'; result = (void *) ldap_init(ehost, port); free(ehost); return result; } int Curl_ldap_simple_bind_s_a(void * ld, char * dn, char * passwd) { int i; char * edn; char * epasswd; edn = (char *) NULL; epasswd = (char *) NULL; if(dn) { i = strlen(dn); edn = malloc(i + 1); if(!edn) return LDAP_NO_MEMORY; QadrtConvertA2E(edn, dn, i, i); edn[i] = '\0'; } if(passwd) { i = strlen(passwd); epasswd = malloc(i + 1); if(!epasswd) { free(edn); return LDAP_NO_MEMORY; } QadrtConvertA2E(epasswd, passwd, i, i); epasswd[i] = '\0'; } i = ldap_simple_bind_s(ld, edn, epasswd); free(epasswd); free(edn); return i; } int Curl_ldap_search_s_a(void * ld, char * base, int scope, char * filter, char * * attrs, int attrsonly, LDAPMessage * * res) { int i; int j; char * ebase; char * efilter; char * * eattrs; int status; ebase = (char *) NULL; efilter = (char *) NULL; eattrs = (char * *) NULL; status = LDAP_SUCCESS; if(base) { i = strlen(base); ebase = malloc(i + 1); if(!ebase) status = LDAP_NO_MEMORY; else { QadrtConvertA2E(ebase, base, i, i); ebase[i] = '\0'; } } if(filter && status == LDAP_SUCCESS) { i = strlen(filter); efilter = malloc(i + 1); if(!efilter) status = LDAP_NO_MEMORY; else { QadrtConvertA2E(efilter, filter, i, i); efilter[i] = '\0'; } } if(attrs && status == LDAP_SUCCESS) { for(i = 0; attrs[i++];) ; eattrs = calloc(i, sizeof(*eattrs)); if(!eattrs) status = LDAP_NO_MEMORY; else { for(j = 0; attrs[j]; j++) { i = strlen(attrs[j]); eattrs[j] = malloc(i + 1); if(!eattrs[j]) { status = LDAP_NO_MEMORY; break; } QadrtConvertA2E(eattrs[j], attrs[j], i, i); eattrs[j][i] = '\0'; } } } if(status == LDAP_SUCCESS) status = ldap_search_s(ld, ebase? ebase: "", scope, efilter? efilter: "(objectclass=*)", eattrs, attrsonly, res); if(eattrs) { for(j = 0; eattrs[j]; j++) free(eattrs[j]); free(eattrs); } free(efilter); free(ebase); return status; } struct berval * * Curl_ldap_get_values_len_a(void * ld, LDAPMessage * entry, const char * attr) { char * cp; struct berval * * result; cp = (char *) NULL; if(attr) { int i = strlen(attr); cp = malloc(i + 1); if(!cp) { ldap_set_lderrno(ld, LDAP_NO_MEMORY, NULL, ldap_err2string(LDAP_NO_MEMORY)); return (struct berval * *) NULL; } QadrtConvertA2E(cp, attr, i, i); cp[i] = '\0'; } result = ldap_get_values_len(ld, entry, cp); free(cp); /* Result data are binary in nature, so they haven't been converted to EBCDIC. Therefore do not convert. */ return result; } char * Curl_ldap_err2string_a(int error) { return set_thread_string(LK_LDAP_ERROR, ldap_err2string(error)); } char * Curl_ldap_get_dn_a(void * ld, LDAPMessage * entry) { int i; char * cp; char * cp2; cp = ldap_get_dn(ld, entry); if(!cp) return cp; i = strlen(cp); cp2 = malloc(i + 1); if(!cp2) return cp2; QadrtConvertE2A(cp2, cp, i, i); cp2[i] = '\0'; /* No way to allocate a buffer here, because it will be released by ldap_memfree() and ldap_memalloc() does not exist. The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ strcpy(cp, cp2); free(cp2); return cp; } char * Curl_ldap_first_attribute_a(void * ld, LDAPMessage * entry, BerElement * * berptr) { int i; char * cp; char * cp2; cp = ldap_first_attribute(ld, entry, berptr); if(!cp) return cp; i = strlen(cp); cp2 = malloc(i + 1); if(!cp2) return cp2; QadrtConvertE2A(cp2, cp, i, i); cp2[i] = '\0'; /* No way to allocate a buffer here, because it will be released by ldap_memfree() and ldap_memalloc() does not exist. The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ strcpy(cp, cp2); free(cp2); return cp; } char * Curl_ldap_next_attribute_a(void * ld, LDAPMessage * entry, BerElement * berptr) { int i; char * cp; char * cp2; cp = ldap_next_attribute(ld, entry, berptr); if(!cp) return cp; i = strlen(cp); cp2 = malloc(i + 1); if(!cp2) return cp2; QadrtConvertE2A(cp2, cp, i, i); cp2[i] = '\0'; /* No way to allocate a buffer here, because it will be released by ldap_memfree() and ldap_memalloc() does not exist. The solution is to overwrite the EBCDIC buffer with ASCII to return it. */ strcpy(cp, cp2); free(cp2); return cp; } #endif /* CURL_DISABLE_LDAP */ static int sockaddr2ebcdic(struct sockaddr_storage *dstaddr, const struct sockaddr *srcaddr, int srclen) { const struct sockaddr_un *srcu; struct sockaddr_un *dstu; unsigned int i; unsigned int dstsize; /* Convert a socket address to job CCSID, if needed. */ if(!srcaddr || srclen < offsetof(struct sockaddr, sa_family) + sizeof(srcaddr->sa_family) || srclen > sizeof(*dstaddr)) { errno = EINVAL; return -1; } memcpy((char *) dstaddr, (char *) srcaddr, srclen); switch (srcaddr->sa_family) { case AF_UNIX: srcu = (const struct sockaddr_un *) srcaddr; dstu = (struct sockaddr_un *) dstaddr; dstsize = sizeof(*dstaddr) - offsetof(struct sockaddr_un, sun_path); srclen -= offsetof(struct sockaddr_un, sun_path); i = QadrtConvertA2E(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen); dstu->sun_path[i] = '\0'; srclen = i + offsetof(struct sockaddr_un, sun_path); } return srclen; } static int sockaddr2ascii(struct sockaddr *dstaddr, int dstlen, const struct sockaddr_storage *srcaddr, int srclen) { const struct sockaddr_un *srcu; struct sockaddr_un *dstu; unsigned int dstsize; /* Convert a socket address to ASCII, if needed. */ if(!srclen) return 0; if(srclen > dstlen) srclen = dstlen; if(!srcaddr || srclen < 0) { errno = EINVAL; return -1; } memcpy((char *) dstaddr, (char *) srcaddr, srclen); if(srclen >= offsetof(struct sockaddr_storage, ss_family) + sizeof(srcaddr->ss_family)) { switch (srcaddr->ss_family) { case AF_UNIX: srcu = (const struct sockaddr_un *) srcaddr; dstu = (struct sockaddr_un *) dstaddr; dstsize = dstlen - offsetof(struct sockaddr_un, sun_path); srclen -= offsetof(struct sockaddr_un, sun_path); if(dstsize > 0 && srclen > 0) { srclen = QadrtConvertE2A(dstu->sun_path, srcu->sun_path, dstsize - 1, srclen); dstu->sun_path[srclen] = '\0'; } srclen += offsetof(struct sockaddr_un, sun_path); } } return srclen; } int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen) { int i; struct sockaddr_storage laddr; i = sockaddr2ebcdic(&laddr, destaddr, addrlen); if(i < 0) return -1; return connect(sd, (struct sockaddr *) &laddr, i); } int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen) { int i; struct sockaddr_storage laddr; i = sockaddr2ebcdic(&laddr, localaddr, addrlen); if(i < 0) return -1; return bind(sd, (struct sockaddr *) &laddr, i); } int Curl_os400_sendto(int sd, char * buffer, int buflen, int flags, struct sockaddr * dstaddr, int addrlen) { int i; struct sockaddr_storage laddr; i = sockaddr2ebcdic(&laddr, dstaddr, addrlen); if(i < 0) return -1; return sendto(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, i); } int Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags, struct sockaddr * fromaddr, int * addrlen) { int rcvlen; struct sockaddr_storage laddr; int laddrlen = sizeof(laddr); if(!fromaddr || !addrlen || *addrlen <= 0) return recvfrom(sd, buffer, buflen, flags, fromaddr, addrlen); laddr.ss_family = AF_UNSPEC; /* To detect if unused. */ rcvlen = recvfrom(sd, buffer, buflen, flags, (struct sockaddr *) &laddr, &laddrlen); if(rcvlen < 0) return rcvlen; if(laddr.ss_family == AF_UNSPEC) laddrlen = 0; else { laddrlen = sockaddr2ascii(fromaddr, *addrlen, &laddr, laddrlen); if(laddrlen < 0) return laddrlen; } *addrlen = laddrlen; return rcvlen; } int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen) { struct sockaddr_storage laddr; int laddrlen = sizeof(laddr); int retcode = getpeername(sd, (struct sockaddr *) &laddr, &laddrlen); if(!retcode) { laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen); if(laddrlen < 0) return laddrlen; *addrlen = laddrlen; } return retcode; } int Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen) { struct sockaddr_storage laddr; int laddrlen = sizeof(laddr); int retcode = getsockname(sd, (struct sockaddr *) &laddr, &laddrlen); if(!retcode) { laddrlen = sockaddr2ascii(addr, *addrlen, &laddr, laddrlen); if(laddrlen < 0) return laddrlen; *addrlen = laddrlen; } return retcode; } #ifdef HAVE_LIBZ const char * Curl_os400_zlibVersion(void) { return set_thread_string(LK_ZLIB_VERSION, zlibVersion()); } int Curl_os400_inflateInit_(z_streamp strm, const char * version, int stream_size) { z_const char * msgb4 = strm->msg; int ret; ret = inflateInit(strm); if(strm->msg != msgb4) strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); return ret; } int Curl_os400_inflateInit2_(z_streamp strm, int windowBits, const char * version, int stream_size) { z_const char * msgb4 = strm->msg; int ret; ret = inflateInit2(strm, windowBits); if(strm->msg != msgb4) strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); return ret; } int Curl_os400_inflate(z_streamp strm, int flush) { z_const char * msgb4 = strm->msg; int ret; ret = inflate(strm, flush); if(strm->msg != msgb4) strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); return ret; } int Curl_os400_inflateEnd(z_streamp strm) { z_const char * msgb4 = strm->msg; int ret; ret = inflateEnd(strm); if(strm->msg != msgb4) strm->msg = set_thread_string(LK_ZLIB_MSG, strm->msg); return ret; } #endif davix-0.8.0/deps/curl/packages/OS400/make-lib.sh0000644000000000000000000001703014121063461017567 0ustar rootroot#!/bin/sh # # libcurl compilation script for the OS/400. # SCRIPTDIR=`dirname "${0}"` . "${SCRIPTDIR}/initscript.sh" cd "${TOPDIR}/lib" # Need to have IFS access to the mih/cipher header file. if action_needed cipher.mih '/QSYS.LIB/QSYSINC.LIB/MIH.FILE/CIPHER.MBR' then rm -f cipher.mih ln -s '/QSYS.LIB/QSYSINC.LIB/MIH.FILE/CIPHER.MBR' cipher.mih fi # Create and compile the identification source file. echo '#pragma comment(user, "libcurl version '"${LIBCURL_VERSION}"'")' > os400.c echo '#pragma comment(user, __DATE__)' >> os400.c echo '#pragma comment(user, __TIME__)' >> os400.c echo '#pragma comment(copyright, "Copyright (C) 1998-2016 Daniel Stenberg et al. OS/400 version by P. Monnerat")' >> os400.c make_module OS400 os400.c LINK= # No need to rebuild service program yet. MODULES= # Get source list. sed -e ':begin' \ -e '/\\$/{' \ -e 's/\\$/ /' \ -e 'N' \ -e 'bbegin' \ -e '}' \ -e 's/\n//g' \ -e 's/[[:space:]]*$//' \ -e 's/^\([A-Za-z][A-Za-z0-9_]*\)[[:space:]]*=[[:space:]]*\(.*\)/\1="\2"/' \ -e 's/\$(\([A-Za-z][A-Za-z0-9_]*\))/${\1}/g' \ < Makefile.inc > tmpscript.sh . ./tmpscript.sh # Compile the sources into modules. INCLUDES="'`pwd`'" # Create a small C program to check ccsidcurl.c is up to date if action_needed "${LIBIFSNAME}/CHKSTRINGS.PGM" then CMD="CRTBNDC PGM(${TARGETLIB}/CHKSTRINGS) SRCSTMF('${SCRIPTDIR}/chkstrings.c')" CMD="${CMD} INCDIR('${TOPDIR}/include/curl' '${TOPDIR}/include' '${SRCDIR}' ${INCLUDES})" system -i "${CMD}" if [ $? -ne 0 ] then echo "ERROR: Failed to build CHKSTRINGS *PGM object!" exit 2 else ${LIBIFSNAME}/CHKSTRINGS.PGM if [ $? -ne 0 ] then echo "ERROR: CHKSTRINGS failed!" exit 2 fi fi fi make_module OS400SYS "${SCRIPTDIR}/os400sys.c" make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" for SRC in ${CSOURCES} do MODULE=`db2_name "${SRC}"` make_module "${MODULE}" "${SRC}" done # If needed, (re)create the static binding directory. if action_needed "${LIBIFSNAME}/${STATBNDDIR}.BNDDIR" then LINK=YES fi if [ "${LINK}" ] then rm -rf "${LIBIFSNAME}/${STATBNDDIR}.BNDDIR" CMD="CRTBNDDIR BNDDIR(${TARGETLIB}/${STATBNDDIR})" CMD="${CMD} TEXT('LibCurl API static binding directory')" system "${CMD}" for MODULE in ${MODULES} do CMD="ADDBNDDIRE BNDDIR(${TARGETLIB}/${STATBNDDIR})" CMD="${CMD} OBJ((${TARGETLIB}/${MODULE} *MODULE))" system "${CMD}" done fi # The exportation file for service program creation must be in a DB2 # source file, so make sure it exists. if action_needed "${LIBIFSNAME}/TOOLS.FILE" then CMD="CRTSRCPF FILE(${TARGETLIB}/TOOLS) RCDLEN(112)" CMD="${CMD} TEXT('curl: build tools')" system "${CMD}" fi # Gather the list of symbols to export. EXPORTS=`grep '^CURL_EXTERN[[:space:]]' \ "${TOPDIR}"/include/curl/*.h \ "${SCRIPTDIR}/ccsidcurl.h" | sed -e 's/^.*CURL_EXTERN[[:space:]]\(.*\)(.*$/\1/' \ -e 's/[[:space:]]*$//' \ -e 's/^.*[[:space:]][[:space:]]*//' \ -e 's/^\*//' \ -e 's/(\(.*\))/\1/'` # Create the service program exportation file in DB2 member if needed. BSF="${LIBIFSNAME}/TOOLS.FILE/BNDSRC.MBR" if action_needed "${BSF}" Makefile.am then LINK=YES fi if [ "${LINK}" ] then echo " STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('LIBCURL_${SONAME}')" \ > "${BSF}" for EXPORT in ${EXPORTS} do echo ' EXPORT SYMBOL("'"${EXPORT}"'")' >> "${BSF}" done echo ' ENDPGMEXP' >> "${BSF}" fi # Build the service program if needed. if action_needed "${LIBIFSNAME}/${SRVPGM}.SRVPGM" then LINK=YES fi if [ "${LINK}" ] then CMD="CRTSRVPGM SRVPGM(${TARGETLIB}/${SRVPGM})" CMD="${CMD} SRCFILE(${TARGETLIB}/TOOLS) SRCMBR(BNDSRC)" CMD="${CMD} MODULE(${TARGETLIB}/OS400)" CMD="${CMD} BNDDIR(${TARGETLIB}/${STATBNDDIR}" if [ "${WITH_ZLIB}" != 0 ] then CMD="${CMD} ${ZLIB_LIB}/${ZLIB_BNDDIR}" liblist -a "${ZLIB_LIB}" fi if [ "${WITH_LIBSSH2}" != 0 ] then CMD="${CMD} ${LIBSSH2_LIB}/${LIBSSH2_BNDDIR}" liblist -a "${LIBSSH2_LIB}" fi CMD="${CMD})" CMD="${CMD} BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR)" CMD="${CMD} TEXT('curl API library')" CMD="${CMD} TGTRLS(${TGTRLS})" system "${CMD}" LINK=YES fi # If needed, (re)create the dynamic binding directory. if action_needed "${LIBIFSNAME}/${DYNBNDDIR}.BNDDIR" then LINK=YES fi if [ "${LINK}" ] then rm -rf "${LIBIFSNAME}/${DYNBNDDIR}.BNDDIR" CMD="CRTBNDDIR BNDDIR(${TARGETLIB}/${DYNBNDDIR})" CMD="${CMD} TEXT('LibCurl API dynamic binding directory')" system "${CMD}" CMD="ADDBNDDIRE BNDDIR(${TARGETLIB}/${DYNBNDDIR})" CMD="${CMD} OBJ((*LIBL/${SRVPGM} *SRVPGM))" system "${CMD}" fi # Rebuild the formdata test if needed. if [ "${TEST_FORMDATA}" ] then MODULES= make_module TFORMDATA formdata.c "'_FORM_DEBUG' 'CURLDEBUG'" make_module TSTREQUAL strequal.c "'_FORM_DEBUG' 'CURLDEBUG'" make_module TMEMDEBUG memdebug.c "'_FORM_DEBUG' 'CURLDEBUG'" make_module TMPRINTF mprintf.c "'_FORM_DEBUG' 'CURLDEBUG'" make_module TSTRERROR strerror.c "'_FORM_DEBUG' 'CURLDEBUG'" # The following modules should not be needed (see comment in # formdata.c. However, there are some unsatisfied # external references leading in the following # modules to be (recursively) needed. MODULES="${MODULES} EASY STRDUP SSLGEN GSKIT HOSTIP HOSTIP4 HOSTIP6" MODULES="${MODULES} URL HASH TRANSFER GETINFO COOKIE SENDF SELECT" MODULES="${MODULES} INET_NTOP SHARE HOSTTHRE MULTI LLIST FTP HTTP" MODULES="${MODULES} HTTP_DIGES HTTP_CHUNK HTTP_NEGOT TIMEVAL HOSTSYN" MODULES="${MODULES} CONNECT SOCKS PROGRESS ESCAPE INET_PTON GETENV" MODULES="${MODULES} DICT LDAP TELNET FILE TFTP NETRC PARSEDATE" MODULES="${MODULES} SPEEDCHECK SPLAY BASE64 SECURITY IF2IP MD5" MODULES="${MODULES} KRB5 OS400SYS" PGMIFSNAME="${LIBIFSNAME}/TFORMDATA.PGM" if action_needed "${PGMIFSNAME}" then LINK=YES fi if [ "${LINK}" ] then CMD="CRTPGM PGM(${TARGETLIB}/TFORMDATA)" CMD="${CMD} ENTMOD(QADRT/QADRTMAIN2)" CMD="${CMD} MODULE(" for MODULE in ${MODULES} do CMD="${CMD} ${TARGETLIB}/${MODULE}" done CMD="${CMD} ) BNDSRVPGM(QADRTTS)" CMD="${CMD} TGTRLS(${TGTRLS})" system "${CMD}" fi fi davix-0.8.0/deps/curl/packages/OS400/chkstrings.c0000644000000000000000000000463014121063461020077 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #pragma enum(int) #include "curl_setup.h" #include "urldata.h" /* The following defines indicate the expected dupstring enum values * in curl_easy_setopt_ccsid() in packages/OS400/ccsidcurl.c. If a * mismatch is flagged during the build, it indicates that curl_easy_setopt_ccsid() * may need updating to perform data EBCDIC to ASCII data conversion on * the string. * Once any applicable changes to curl_easy_setopt_ccsid() have been * made, the EXPECTED_STRING_LASTZEROTERMINATED/EXPECTED_STRING_LAST * values can be updated to match the latest enum values in urldata.h. */ #define EXPECTED_STRING_LASTZEROTERMINATED (STRING_TEMP_URL + 1) #define EXPECTED_STRING_LAST (STRING_COPYPOSTFIELDS + 1) int main(int argc, char *argv[]) { int rc = 0; if (STRING_LASTZEROTERMINATED != EXPECTED_STRING_LASTZEROTERMINATED) { fprintf(stderr,"STRING_LASTZEROTERMINATED(%d) is not expected value(%d).\n", STRING_LASTZEROTERMINATED, EXPECTED_STRING_LASTZEROTERMINATED); rc += 1; } if (STRING_LAST != EXPECTED_STRING_LAST) { fprintf(stderr,"STRING_LAST(%d) is not expected value(%d).\n", STRING_LAST, EXPECTED_STRING_LAST); rc += 2; } if (rc != 0) { fprintf(stderr,"curl_easy_setopt_ccsid() in packages/OS400/ccsidcurl.c" " may need updating if new strings are provided as input via the curl API.\n"); } return rc; }davix-0.8.0/deps/curl/packages/OS400/make-include.sh0000644000000000000000000000364714121063461020455 0ustar rootroot#!/bin/sh # # Installation of the header files in the OS/400 library. # SCRIPTDIR=`dirname "${0}"` . "${SCRIPTDIR}/initscript.sh" cd "${TOPDIR}/include" # Create the OS/400 source program file for the header files. SRCPF="${LIBIFSNAME}/H.FILE" if action_needed "${SRCPF}" then CMD="CRTSRCPF FILE(${TARGETLIB}/H) RCDLEN(112)" CMD="${CMD} CCSID(${TGTCCSID}) TEXT('curl: Header files')" system "${CMD}" fi # Create the IFS directory for the header files. IFSINCLUDE="${IFSDIR}/include/curl" if action_needed "${IFSINCLUDE}" then mkdir -p "${IFSINCLUDE}" fi # Enumeration values are used as va_arg tagfields, so they MUST be # integers. copy_hfile() { destfile="${1}" srcfile="${2}" shift shift sed -e '1i\ #pragma enum(int)\ ' "${@}" -e '$a\ #pragma enum(pop)\ ' < "${srcfile}" > "${destfile}" } # Copy the header files. for HFILE in curl/*.h ${SCRIPTDIR}/ccsidcurl.h do case "`basename \"${HFILE}\" .h`" in stdcheaders|typecheck-gcc) continue;; esac DEST="${SRCPF}/`db2_name \"${HFILE}\" nomangle`.MBR" if action_needed "${DEST}" "${HFILE}" then copy_hfile "${DEST}" "${HFILE}" IFSDEST="${IFSINCLUDE}/`basename \"${HFILE}\"`" rm -f "${IFSDEST}" ln -s "${DEST}" "${IFSDEST}" fi done # Copy the ILE/RPG header file, setting-up version number. versioned_copy "${SCRIPTDIR}/curl.inc.in" "${SRCPF}/CURL.INC.MBR" rm -f "${IFSINCLUDE}/curl.inc.rpgle" ln -s "${SRCPF}/CURL.INC.MBR" "${IFSINCLUDE}/curl.inc.rpgle" # Duplicate file H as CURL to support more include path forms. if action_needed "${LIBIFSNAME}/CURL.FILE" then : else system "DLTF FILE(${TARGETLIB}/CURL)" fi CMD="CRTDUPOBJ OBJ(H) FROMLIB(${TARGETLIB}) OBJTYPE(*FILE) TOLIB(*FROMLIB)" CMD="${CMD} NEWOBJ(CURL) DATA(*YES)" system "${CMD}" davix-0.8.0/deps/curl/packages/OS400/make-tests.sh0000644000000000000000000001003514121063461020161 0ustar rootroot#!/bin/sh # # tests compilation script for the OS/400. # SCRIPTDIR=`dirname "${0}"` . "${SCRIPTDIR}/initscript.sh" cd "${TOPDIR}/tests" # tests directory not implemented yet. # Process the libtest subdirectory. cd libtest # Get definitions from the Makefile.inc file. # The `sed' statement works as follows: # _ Join \nl-separated lines. # _ Retain only lines that begins with "identifier =". # _ Turn these lines into shell variable assignments. eval "`sed -e ': begin' \ -e '/\\\\$/{' \ -e 'N' \ -e 's/\\\\\\n/ /' \ -e 'b begin' \ -e '}' \ -e '/^[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[=]/b keep' \ -e 'd' \ -e ': keep' \ -e 's/[[:space:]]*=[[:space:]]*/=/' \ -e 's/=\\(.*[^[:space:]]\\)[[:space:]]*$/=\\"\\1\\"/' \ -e 's/\\$(\\([^)]*\\))/${\\1}/g' \ < Makefile.inc`" # Special case: redefine chkhostname compilation parameters. chkhostname_SOURCES=chkhostname.c chkhostname_LDADD=curl_gethostname.o # Compile all programs. # The list is found in variable "noinst_PROGRAMS" INCLUDES="'${TOPDIR}/tests/libtest' '${TOPDIR}/lib'" for PGM in ${noinst_PROGRAMS} do DB2PGM=`db2_name "${PGM}"` PGMIFSNAME="${LIBIFSNAME}/${DB2PGM}.PGM" # Extract preprocessor symbol definitions from compilation # options for the program. PGMCFLAGS="`eval echo \"\\${${PGM}_CFLAGS}\"`" PGMDEFINES= for FLAG in ${PGMCFLAGS} do case "${FLAG}" in -D?*) DEFINE="`echo \"${FLAG}\" | sed 's/^..//'`" PGMDEFINES="${PGMDEFINES} '${DEFINE}'" ;; esac done # Compile all C sources for the program into modules. PGMSOURCES="`eval echo \"\\${${PGM}_SOURCES}\"`" LINK= MODULES= for SOURCE in ${PGMSOURCES} do case "${SOURCE}" in *.c) # Special processing for libxxx.c files: their # module name is determined by the target # PROGRAM name. case "${SOURCE}" in lib*.c) MODULE="${DB2PGM}" ;; *) MODULE=`db2_name "${SOURCE}"` ;; esac make_module "${MODULE}" "${SOURCE}" "${PGMDEFINES}" if action_needed "${PGMIFSNAME}" "${MODIFSNAME}" then LINK=yes fi ;; esac done # Link program if needed. if [ "${LINK}" ] then PGMLDADD="`eval echo \"\\${${PGM}_LDADD}\"`" for LDARG in ${PGMLDADD} do case "${LDARG}" in -*) ;; # Ignore non-module. *) MODULES="${MODULES} "`db2_name "${LDARG}"` ;; esac done MODULES="`echo \"${MODULES}\" | sed \"s/[^ ][^ ]*/${TARGETLIB}\/&/g\"`" CMD="CRTPGM PGM(${TARGETLIB}/${DB2PGM})" CMD="${CMD} ENTMOD(QADRT/QADRTMAIN2)" CMD="${CMD} MODULE(${MODULES})" CMD="${CMD} BNDSRVPGM(${TARGETLIB}/${SRVPGM} QADRTTS)" CMD="${CMD} TGTRLS(${TGTRLS})" system "${CMD}" fi done davix-0.8.0/deps/curl/packages/OS400/curl.inc.in0000644000000000000000000037752014121063461017634 0ustar rootroot ************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF * ANY KIND, either express or implied. * * ************************************************************************** * /if not defined(CURL_CURL_INC_) /define CURL_CURL_INC_ * * WARNING: this file should be kept in sync with C include files. * ************************************************************************** * Constants ************************************************************************** * d LIBCURL_VERSION... d c '@LIBCURL_VERSION@' d LIBCURL_VERSION_MAJOR... d c @LIBCURL_VERSION_MAJOR@ d LIBCURL_VERSION_MINOR... d c @LIBCURL_VERSION_MINOR@ d LIBCURL_VERSION_PATCH... d c @LIBCURL_VERSION_PATCH@ d LIBCURL_VERSION_NUM... d c X'00@LIBCURL_VERSION_NUM@' d LIBCURL_TIMESTAMP... d c '@LIBCURL_TIMESTAMP@' * d CURL_SOCKET_BAD... d c -1 d CURL_SOCKET_TIMEOUT... d c -1 * /if not defined(CURL_MAX_WRITE_SIZE) /define CURL_MAX_WRITE_SIZE d CURL_MAX_WRITE_SIZE... d c 16384 /endif * /if not defined(CURL_MAX_HTTP_HEADER) /define CURL_MAX_HTTP_HEADER d CURL_MAX_HTTP_HEADER... d c 102400 /endif * d CURLINFO_STRING... d c X'00100000' d CURLINFO_LONG c X'00200000' d CURLINFO_DOUBLE... d c X'00300000' d CURLINFO_SLIST c X'00400000' d CURLINFO_PTR c X'00400000' d CURLINFO_SOCKET... d c X'00500000' d CURLINFO_OFF_T... d c X'00600000' d CURLINFO_MASK c X'000FFFFF' d CURLINFO_TYPEMASK... d c X'00F00000' * d CURL_GLOBAL_SSL... d c X'00000001' d CURL_GLOBAL_WIN32... d c X'00000002' d CURL_GLOBAL_ALL... d c X'00000003' d CURL_GLOBAL_NOTHING... d c X'00000000' d CURL_GLOBAL_DEFAULT... d c X'00000003' d CURL_GLOBAL_ACK_EINTR... d c X'00000004' * d CURL_VERSION_IPV6... d c X'00000001' d CURL_VERSION_KERBEROS4... d c X'00000002' d CURL_VERSION_SSL... d c X'00000004' d CURL_VERSION_LIBZ... d c X'00000008' d CURL_VERSION_NTLM... d c X'00000010' d CURL_VERSION_GSSNEGOTIATE... d c X'00000020' Deprecated d CURL_VERSION_DEBUG... d c X'00000040' d CURL_VERSION_ASYNCHDNS... d c X'00000080' d CURL_VERSION_SPNEGO... d c X'00000100' d CURL_VERSION_LARGEFILE... d c X'00000200' d CURL_VERSION_IDN... d c X'00000400' d CURL_VERSION_SSPI... d c X'00000800' d CURL_VERSION_CONV... d c X'00001000' d CURL_VERSION_CURLDEBUG... d c X'00002000' d CURL_VERSION_TLSAUTH_SRP... d c X'00004000' d CURL_VERSION_NTLM_WB... d c X'00008000' d CURL_VERSION_HTTP2... d c X'00010000' d CURL_VERSION_GSSAPI... d c X'00020000' d CURL_VERSION_KERBEROS5... d c X'00040000' d CURL_VERSION_UNIX_SOCKETS... d c X'00080000' d CURL_VERSION_PSL... d c X'00100000' d CURL_VERSION_HTTPS_PROXY... d c X'00200000' d CURL_VERSION_MULTI_SSL... d c X'00400000' d CURL_VERSION_BROTLI... d c X'00800000' d CURL_VERSION_ALTSVC... d c X'01000000' d CURL_VERSION_HTTP3... d c X'02000000' * d CURL_HTTPPOST_FILENAME... d c X'00000001' d CURL_HTTPPOST_READFILE... d c X'00000002' d CURL_HTTPPOST_PTRNAME... d c X'00000004' d CURL_HTTPPOST_PTRCONTENTS... d c X'00000008' d CURL_HTTPPOST_BUFFER... d c X'00000010' d CURL_HTTPPOST_PTRBUFFER... d c X'00000020' d CURL_HTTPPOST_CALLBACK... d c X'00000040' d CURL_HTTPPOST_LARGE... d c X'00000080' * d CURL_SEEKFUNC_OK... d c 0 d CURL_SEEKFUNC_FAIL... d c 1 d CURL_SEEKFUNC_CANTSEEK... d c 2 * d CURL_READFUNC_ABORT... d c X'10000000' d CURL_READFUNC_PAUSE... d c X'10000001' * d CURL_WRITEFUNC_PAUSE... d c X'10000001' * d CURL_TRAILERFUNC_OK... d c 0 d CURL_TRAILERFUNC_ABORT... d c 1 * d CURLAUTH_NONE c X'00000000' d CURLAUTH_BASIC c X'00000001' d CURLAUTH_DIGEST... d c X'00000002' d CURLAUTH_NEGOTIATE... d c X'00000004' d CURLAUTH_NTLM c X'00000008' d CURLAUTH_DIGEST_IE... d c X'00000010' d CURLAUTH_NTLM_WB... d c X'00000020' d CURLAUTH_BEARER... d c X'00000040' d CURLAUTH_ONLY... d c X'80000000' d CURLAUTH_ANY c X'7FFFFFEF' d CURLAUTH_ANYSAFE... d c X'7FFFFFEE' * d CURLSSH_AUTH_ANY... d c X'7FFFFFFF' d CURLSSH_AUTH_NONE... d c X'00000000' d CURLSSH_AUTH_PUBLICKEY... d c X'00000001' d CURLSSH_AUTH_PASSWORD... d c X'00000002' d CURLSSH_AUTH_HOST... d c X'00000004' d CURLSSH_AUTH_KEYBOARD... d c X'00000008' d CURLSSH_AUTH_AGENT... d c X'00000010' d CURLSSH_AUTH_DEFAULT... d c X'7FFFFFFF' CURLSSH_AUTH_ANY * d CURLGSSAPI_DELEGATION_NONE... d c 0 d CURLGSSAPI_DELEGATION_POLICY_FLAG... d c X'00000001' d CURLGSSAPI_DELEGATION_FLAG... d c X'00000002' * d CURL_ERROR_SIZE... d c 256 * d CURLOPTTYPE_LONG... d c 0 d CURLOPTTYPE_OBJECTPOINT... d c 10000 d CURLOPTTYPE_STRINGPOINT... d c 10000 d CURLOPTTYPE_FUNCTIONPOINT... d c 20000 d CURLOPTTYPE_OFF_T... d c 30000 * d CURL_IPRESOLVE_WHATEVER... d c 0 d CURL_IPRESOLVE_V4... d c 1 d CURL_IPRESOLVE_V6... d c 2 * d CURL_HTTP_VERSION_NONE... d c 0 d CURL_HTTP_VERSION_1_0... d c 1 d CURL_HTTP_VERSION_1_1... d c 2 d CURL_HTTP_VERSION_2_0... d c 3 d CURL_HTTP_VERSION_2... d c 3 d CURL_HTTP_VERSION_2TLS... d c 4 d CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE... d c 5 * d CURL_NETRC_IGNORED... d c 0 d CURL_NETRC_OPTIONAL... d c 1 d CURL_NETRC_REQUIRED... d c 2 * d CURL_SSLVERSION_DEFAULT... d c 0 d CURL_SSLVERSION_TLSv1... d c 1 d CURL_SSLVERSION_SSLv2... d c 2 d CURL_SSLVERSION_SSLv3... d c 3 d CURL_SSLVERSION_TLSv1_0... d c 4 d CURL_SSLVERSION_TLSv1_1... d c 5 d CURL_SSLVERSION_TLSv1_2... d c 6 d CURL_SSLVERSION_TLSv1_3... d c 7 d CURL_SSLVERSION_MAX_DEFAULT... d c X'00010000' d CURL_SSLVERSION_MAX_TLSv1_0... d c X'00040000' d CURL_SSLVERSION_MAX_TLSv1_1... d c X'00050000' d CURL_SSLVERSION_MAX_TLSv1_2... d c X'00060000' d CURL_SSLVERSION_MAX_TLSv1_3... d c X'00070000' * d CURL_TLSAUTH_NONE... d c 0 d CURL_TLSAUTH_SRP... d c 1 * d CURL_REDIR_GET_ALL... d c 0 d CURL_REDIR_POST_301... d c 1 d CURL_REDIR_POST_302... d c 2 d CURL_REDIR_POST_303... d c 4 d CURL_REDIR_POST_ALL... d c 7 * d CURL_ZERO_TERMINATED... d c -1 * d CURL_POLL_NONE c 0 d CURL_POLL_IN c 1 d CURL_POLL_OUT c 2 d CURL_POLL_INOUT... d c 3 d CURL_POLL_REMOVE... d c 4 * d CURL_CSELECT_IN... d c X'00000001' d CURL_CSELECT_OUT... d c X'00000002' d CURL_CSELECT_ERR... d c X'00000004' * d CURL_PUSH_OK c 0 d CURL_PUSH_DENY c 1 * d CURLPAUSE_RECV c X'00000001' d CURLPAUSE_RECV_CONT... d c X'00000000' d CURLPAUSE_SEND c X'00000004' d CURLPAUSE_SEND_CONT... d c X'00000000' d CURLPAUSE_ALL c X'00000005' d CURLPAUSE_CONT c X'00000000' * d CURLINFOFLAG_KNOWN_FILENAME... d c X'00000001' d CURLINFOFLAG_KNOWN_FILETYPE... d c X'00000002' d CURLINFOFLAG_KNOWN_TIME... d c X'00000004' d CURLINFOFLAG_KNOWN_PERM... d c X'00000008' d CURLINFOFLAG_KNOWN_UID... d c X'00000010' d CURLINFOFLAG_KNOWN_GID... d c X'00000020' d CURLINFOFLAG_KNOWN_SIZE... d c X'00000040' d CURLINFOFLAG_KNOWN_HLINKCOUNT... d c X'00000080' * d CURL_CHUNK_BGN_FUNC_OK... d c 0 d CURL_CHUNK_BGN_FUNC_FAIL... d c 1 d CURL_CHUNK_BGN_FUNC_SKIP... d c 2 * d CURL_CHUNK_END_FUNC_OK... d c 0 d CURL_CHUNK_END_FUNC_FAIL... d c 1 * d CURL_FNMATCHFUNC_MATCH... d c 0 d CURL_FNMATCHFUNC_NOMATCH... d c 1 d CURL_FNMATCHFUNC_FAIL... d c 2 * d CURL_WAIT_POLLIN... d c X'0001' d CURL_WAIT_POLLPRI... d c X'0002' d CURL_WAIT_POLLOUT... d c X'0004' * d CURLU_DEFAULT_PORT... d c X'00000001' d CURLU_NO_DEFAULT_PORT... d c X'00000002' d CURLU_DEFAULT_SCHEME... d c X'00000004' d CURLU_NON_SUPPORT_SCHEME... d c X'00000008' d CURLU_PATH_AS_IS... d c X'00000010' d CURLU_DISALLOW_USER... d c X'00000020' d CURLU_URLDECODE... d c X'00000040' d CURLU_URLENCODE... d c X'00000080' d CURLU_APPENDQUERY... d c X'00000100' d CURLU_GUESS_SCHEME... d c X'00000200' * ************************************************************************** * Types ************************************************************************** * d curl_socket_t s 10i 0 based(######ptr######) * d curl_off_t s 20i 0 based(######ptr######) * d CURLcode s 10i 0 based(######ptr######) Enum d CURLE_OK c 0 d CURLE_UNSUPPORTED_PROTOCOL... d c 1 d CURLE_FAILED_INIT... d c 2 d CURLE_URL_MALFORMAT... d c 3 d CURLE_NOT_BUILT_IN... d c 4 d CURLE_COULDNT_RESOLVE_PROXY... d c 5 d CURLE_COULDNT_RESOLVE_HOST... d c 6 d CURLE_COULDNT_CONNECT... d c 7 d CURLE_WEIRD_SERVER_REPLY... d c 8 d CURLE_FTP_WEIRD_SERVER_REPLY... d c 8 d CURLE_REMOTE_ACCESS_DENIED... d c 9 d CURLE_FTP_ACCEPT_FAILED... d c 10 d CURLE_FTP_WEIRD_PASS_REPLY... d c 11 d CURLE_FTP_ACCEPT_TIMEOUT... d c 12 d CURLE_FTP_WEIRD_PASV_REPLY... d c 13 d CURLE_FTP_WEIRD_227_FORMAT... d c 14 d CURLE_FTP_CANT_GET_HOST... d c 15 d CURLE_HTTP2 c 16 d CURLE_FTP_COULDNT_SET_TYPE... d c 17 d CURLE_PARTIAL_FILE... d c 18 d CURLE_FTP_COULDNT_RETR_FILE... d c 19 d CURLE_OBSOLETE20... d c 20 d CURLE_QUOTE_ERROR... d c 21 d CURLE_HTTP_RETURNED_ERROR... d c 22 d CURLE_WRITE_ERROR... d c 23 d CURLE_OBSOLETE24... d c 24 d CURLE_UPLOAD_FAILED... d c 25 d CURLE_READ_ERROR... d c 26 d CURLE_OUT_OF_MEMORY... d c 27 d CURLE_OPERATION_TIMEDOUT... d c 28 d CURLE_OBSOLETE29... d c 29 d CURLE_FTP_PORT_FAILED... d c 30 d CURLE_FTP_COULDNT_USE_REST... d c 31 d CURLE_OBSOLETE32... d c 32 d CURLE_RANGE_ERROR... d c 33 d CURLE_HTTP_POST_ERROR... d c 34 d CURLE_SSL_CONNECT_ERROR... d c 35 d CURLE_BAD_DOWNLOAD_RESUME... d c 36 d CURLE_FILE_COULDNT_READ_FILE... d c 37 d CURLE_LDAP_CANNOT_BIND... d c 38 d CURLE_LDAP_SEARCH_FAILED... d c 39 d CURLE_OBSOLETE40... d c 40 d CURLE_FUNCTION_NOT_FOUND... d c 41 d CURLE_ABORTED_BY_CALLBACK... d c 42 d CURLE_BAD_FUNCTION_ARGUMENT... d c 43 d CURLE_OBSOLETE44... d c 44 d CURLE_INTERFACE_FAILED... d c 45 d CURLE_OBSOLETE46... d c 46 d CURLE_TOO_MANY_REDIRECTS... d c 47 d CURLE_UNKNOWN_OPTION... d c 48 d CURLE_TELNET_OPTION_SYNTAX... d c 49 d CURLE_OBSOLETE50... d c 50 d CURLE_OBSOLETE51... d c 51 d CURLE_GOT_NOTHING... d c 52 d CURLE_SSL_ENGINE_NOTFOUND... d c 53 d CURLE_SSL_ENGINE_SETFAILED... d c 54 d CURLE_SEND_ERROR... d c 55 d CURLE_RECV_ERROR... d c 56 d CURLE_OBSOLETE57... d c 57 d CURLE_SSL_CERTPROBLEM... d c 58 d CURLE_SSL_CIPHER... d c 59 d CURLE_PEER_FAILED_VERIFICATION... d c 60 d CURLE_BAD_CONTENT_ENCODING... d c 61 d CURLE_LDAP_INVALID_URL... d c 62 d CURLE_FILESIZE_EXCEEDED... d c 63 d CURLE_USE_SSL_FAILED... d c 64 d CURLE_SEND_FAIL_REWIND... d c 65 d CURLE_SSL_ENGINE_INITFAILED... d c 66 d CURLE_LOGIN_DENIED... d c 67 d CURLE_TFTP_NOTFOUND... d c 68 d CURLE_TFTP_PERM... d c 69 d CURLE_REMOTE_DISK_FULL... d c 70 d CURLE_TFTP_ILLEGAL... d c 71 d CURLE_TFTP_UNKNOWNID... d c 72 d CURLE_REMOTE_FILE_EXISTS... d c 73 d CURLE_TFTP_NOSUCHUSER... d c 74 d CURLE_CONV_FAILED... d c 75 d CURLE_CONV_REQD... d c 76 d CURLE_SSL_CACERT_BADFILE... d c 77 d CURLE_REMOTE_FILE_NOT_FOUND... d c 78 d CURLE_SSH... d c 79 d CURLE_SSL_SHUTDOWN_FAILED... d c 80 d CURLE_AGAIN... d c 81 d CURLE_SSL_CRL_BADFILE... d c 82 d CURLE_SSL_ISSUER_ERROR... d c 83 d CURLE_FTP_PRET_FAILED... d c 84 d CURLE_RTSP_CSEQ_ERROR... d c 85 d CURLE_RTSP_SESSION_ERROR... d c 86 d CURLE_FTP_BAD_FILE_LIST... d c 87 d CURLE_CHUNK_FAILED... d c 88 d CURLE_NO_CONNECTION_AVAILABLE... d c 89 d CURLE_SSL_PINNEDPUBKEYNOTMATCH... d c 90 d CURLE_SSL_INVALIDCERTSTATUS... d c 91 d CURLE_HTTP2_STREAM... d c 92 d CURLE_RECURSIVE_API_CALL... d c 93 d CURLE_AUTH_ERROR... d c 94 d CURLE_HTTP3... d c 95 d CURLE_QUIC_CONNECT_ERROR... d c 96 * /if not defined(CURL_NO_OLDIES) d CURLE_URL_MALFORMAT_USER... d c 4 d CURLE_FTP_ACCESS_DENIED... d c 9 d CURLE_FTP_USER_PASSWORD_INCORRECT... d c 10 d CURLE_FTP_WEIRD_USER_REPLY... d c 12 d CURLE_FTP_CANT_RECONNECT... d c 16 d CURLE_FTP_COULDNT_SET_BINARY... d c 17 d CURLE_FTP_PARTIAL_FILE... d c 18 d CURLE_FTP_WRITE_ERROR... d c 20 d CURLE_FTP_QUOTE_ERROR... d c 21 d CURLE_HTTP_NOT_FOUND... d c 22 d CURLE_MALFORMAT_USER... d c 24 d CURLE_FTP_COULDNT_STOR_FILE... d c 25 d CURLE_OPERATION_TIMEOUTED... d c 28 d CURLE_FTP_COULDNT_SET_ASCII... d c 29 d CURLE_FTP_COULDNT_GET_SIZE... d c 32 d CURLE_HTTP_RANGE_ERROR... d c 33 d CURLE_FTP_BAD_DOWNLOAD_RESUME... d c 36 d CURLE_LIBRARY_NOT_FOUND... d c 40 d CURLE_BAD_CALLING_ORDER... d c 44 d CURLE_HTTP_PORT_FAILED... d c 45 d CURLE_BAD_PASSWORD_ENTERED... d c 46 d CURLE_UNKNOWN_TELNET_OPTION... d c 48 d CURLE_OBSOLETE... d c 50 d CURLE_SSL_PEER_CERTIFICATE... d c 51 d CURLE_SHARE_IN_USE... d c 57 d CURLE_SSL_CACERT... d c 60 d CURLE_FTP_SSL_FAILED... d c 64 d CURLE_TFTP_DISKFULL... d c 70 d CURLE_TFTP_EXISTS... d c 73 d CURLE_ALREADY_COMPLETE... d c 99999 /endif * d curlioerr s 10i 0 based(######ptr######) Enum d CURLIOE_OK c 0 d CURLIOE_UNKNOWNCMD... d c 1 d CURLIOE_FAILRESTART... d c 2 * d curlfiletype s 10i 0 based(######ptr######) Enum d CURLFILETYPE_FILE... d c 0 d CURLFILETYPE_DIRECTORY... d c 1 d CURLFILETYPE_SYMLINK... d c 2 d CURLFILETYPE_DEVICE_BLOCK... d c 3 d CURLFILETYPE_DEVICE_CHAR... d c 4 d CURLFILETYPE_NAMEDPIPE... d c 5 d CURLFILETYPE_SOCKET... d c 6 d CURLFILETYPE_DOOR... d c 7 * d curliocmd s 10i 0 based(######ptr######) Enum d CURLIOCMD_NOP c 0 d CURLIOCMD_RESTARTREAD... d c 1 * d curl_infotype s 10i 0 based(######ptr######) Enum d CURLINFO_TEXT... d c 0 d CURLINFO_HEADER_IN... d c 1 d CURLINFO_HEADER_OUT... d c 2 d CURLINFO_DATA_IN... d c 3 d CURLINFO_DATA_OUT... d c 4 d CURLINFO_SSL_DATA_IN... d c 5 d CURLINFO_SSL_DATA_OUT... d c 6 d CURLINFO_END... d c 7 * d curl_proxytype s 10i 0 based(######ptr######) Enum d CURLPROXY_HTTP... d c 0 d CURLPROXY_HTTP_1_0... d c 1 d CURLPROXY_HTTPS... d c 2 d CURLPROXY_SOCKS4... d c 4 d CURLPROXY_SOCKS5... d c 5 d CURLPROXY_SOCKS4A... d c 6 d CURLPROXY_SOCKS5_HOSTNAME... d c 7 * d curl_khstat s 10i 0 based(######ptr######) Enum d CURLKHSTAT_FINE_ADD_TO_FILE... d c 0 d CURLKHSTAT_FINE... d c 1 d CURLKHSTAT_REJECT... d c 2 d CURLKHSTAT_DEFER... d c 3 d CURLKHSTAT_LAST... d c 4 * d curl_khmatch s 10i 0 based(######ptr######) Enum d CURLKHMATCH_OK... d c 0 d CURLKHMATCH_MISMATCH... d c 1 d CURLKHMATCH_MISSING... d c 2 d CURLKHMATCH_LAST... d c 3 * d curl_usessl s 10i 0 based(######ptr######) Enum d CURLUSESSL_NONE... d c 0 d CURLUSESSL_TRY... d c 1 d CURLUSESSL_CONTROL... d c 2 d CURLUSESSL_ALL... d c 3 * d CURLSSLOPT_ALLOW_BEAST... d c X'0001' d CURLSSLOPT_NO_REVOKE... d c X'0002' d CURLSSLOPT_NO_PARTIALCHAIN... d c X'0004' * d CURL_HET_DEFAULT... d c 200 * d CURL_UPKEEP_INTERVAL_DEFAULT... d c 60000 * /if not defined(CURL_NO_OLDIES) d curl_ftpssl s like(curl_usessl) d based(######ptr######) d CURLFTPSSL_NONE... d c 0 d CURLFTPSSL_TRY... d c 1 d CURLFTPSSL_CONTROL... d c 2 d CURLFTPSSL_ALL... d c 3 /endif * d curl_ftpccc s 10i 0 based(######ptr######) Enum d CURLFTPSSL_CCC_NONE... d c 0 d CURLFTPSSL_CCC_PASSIVE... d c 1 d CURLFTPSSL_CCC_ACTIVE... d c 2 * d curl_ftpauth s 10i 0 based(######ptr######) Enum d CURLFTPAUTH_DEFAULT... d c 0 d CURLFTPAUTH_SSL... d c 1 d CURLFTPAUTH_TLS... d c 2 * d curl_ftpcreatedir... d s 10i 0 based(######ptr######) Enum d CURLFTP_CREATE_DIR_NONE... d c 0 d CURLFTP_CREATE_DIR... d c 1 d CURLFTP_CREATE_DIR_RETRY... d c 2 * d curl_ftpmethod s 10i 0 based(######ptr######) Enum d CURLFTPMETHOD_DEFAULT... d c 0 d CURLFTPMETHOD_MULTICWD... d c 1 d CURLFTPMETHOD_NOCWD... d c 2 d CURLFTPMETHOD_SINGLECWD... d c 3 * d CURLHEADER_UNIFIED... d c X'00000000' d CURLHEADER_SEPARATE... d c X'00000001' * d CURLALTSVC_IMMEDIATELY... d c X'00000001' d CURLALTSVC_ALTUSED... d c X'00000002' d CURLALTSVC_READONLYFILE... d c X'00000004' d CURLALTSVC_H1... d c X'00000008' d CURLALTSVC_H2... d c X'00000010' d CURLALTSVC_H3... d c X'00000020' * d CURLPROTO_HTTP... d c X'00000001' d CURLPROTO_HTTPS... d c X'00000002' d CURLPROTO_FTP... d c X'00000004' d CURLPROTO_FTPS... d c X'00000008' d CURLPROTO_SCP... d c X'00000010' d CURLPROTO_SFTP... d c X'00000020' d CURLPROTO_TELNET... d c X'00000040' d CURLPROTO_LDAP... d c X'00000080' d CURLPROTO_LDAPS... d c X'00000100' d CURLPROTO_DICT... d c X'00000200' d CURLPROTO_FILE... d c X'00000400' d CURLPROTO_TFTP... d c X'00000800' d CURLPROTO_IMAP... d c X'00001000' d CURLPROTO_IMAPS... d c X'00002000' d CURLPROTO_POP3... d c X'00004000' d CURLPROTO_POP3S... d c X'00008000' d CURLPROTO_SMTP... d c X'00010000' d CURLPROTO_SMTPS... d c X'00020000' d CURLPROTO_RTSP... d c X'00040000' d CURLPROTO_RTMP... d c X'00080000' d CURLPROTO_RTMPT... d c X'00100000' d CURLPROTO_RTMPTE... d c X'00200000' d CURLPROTO_RTMPE... d c X'00400000' d CURLPROTO_RTMPS... d c X'00800000' d CURLPROTO_RTMPTS... d c X'01000000' d CURLPROTO_GOPHER... d c X'02000000' d CURLPROTO_SMB... d c X'04000000' d CURLPROTO_SMBS... d c X'08000000' * d CURLoption s 10i 0 based(######ptr######) Enum d CURLOPT_WRITEDATA... d c 10001 d CURLOPT_URL c 10002 d CURLOPT_PORT c 00003 d CURLOPT_PROXY c 10004 d CURLOPT_USERPWD... d c 10005 d CURLOPT_PROXYUSERPWD... d c 10006 d CURLOPT_RANGE c 10007 d CURLOPT_READDATA... d c 10009 d CURLOPT_ERRORBUFFER... d c 10010 d CURLOPT_WRITEFUNCTION... d c 20011 d CURLOPT_READFUNCTION... d c 20012 d CURLOPT_TIMEOUT... d c 00013 d CURLOPT_INFILESIZE... d c 00014 d CURLOPT_POSTFIELDS... d c 10015 d CURLOPT_REFERER... d c 10016 d CURLOPT_FTPPORT... d c 10017 d CURLOPT_USERAGENT... d c 10018 d CURLOPT_LOW_SPEED_LIMIT... d c 00019 d CURLOPT_LOW_SPEED_TIME... d c 00020 d CURLOPT_RESUME_FROM... d c 00021 d CURLOPT_COOKIE... d c 10022 d CURLOPT_HTTPHEADER... d c 10023 d CURLOPT_RTSPHEADER... d c 10023 d CURLOPT_HTTPPOST... d c 10024 d CURLOPT_SSLCERT... d c 10025 d CURLOPT_KEYPASSWD... d c 10026 d CURLOPT_CRLF c 00027 d CURLOPT_QUOTE c 10028 d CURLOPT_HEADERDATA... d c 10029 d CURLOPT_COOKIEFILE... d c 10031 d CURLOPT_SSLVERSION... d c 00032 d CURLOPT_TIMECONDITION... d c 00033 d CURLOPT_TIMEVALUE... d c 00034 d CURLOPT_CUSTOMREQUEST... d c 10036 d CURLOPT_STDERR... d c 10037 d CURLOPT_POSTQUOTE... d c 10039 d CURLOPT_VERBOSE... d c 00041 d CURLOPT_HEADER... d c 00042 d CURLOPT_NOPROGRESS... d c 00043 d CURLOPT_NOBODY... d c 00044 d CURLOPT_FAILONERROR... d c 00045 d CURLOPT_UPLOAD... d c 00046 d CURLOPT_POST c 00047 d CURLOPT_DIRLISTONLY... d c 00048 d CURLOPT_APPEND... d c 00050 d CURLOPT_NETRC c 00051 d CURLOPT_FOLLOWLOCATION... d c 00052 d CURLOPT_TRANSFERTEXT... d c 00053 d CURLOPT_PUT c 00054 d CURLOPT_PROGRESSFUNCTION... d c 20056 d CURLOPT_PROGRESSDATA... d c 10057 d CURLOPT_XFERINFODATA... d c 10057 PROGRESSDATA alias d CURLOPT_AUTOREFERER... d c 00058 d CURLOPT_PROXYPORT... d c 00059 d CURLOPT_POSTFIELDSIZE... d c 00060 d CURLOPT_HTTPPROXYTUNNEL... d c 00061 d CURLOPT_INTERFACE... d c 10062 d CURLOPT_KRBLEVEL... d c 10063 d CURLOPT_SSL_VERIFYPEER... d c 00064 d CURLOPT_CAINFO... d c 10065 d CURLOPT_MAXREDIRS... d c 00068 d CURLOPT_FILETIME... d c 00069 d CURLOPT_TELNETOPTIONS... d c 10070 d CURLOPT_MAXCONNECTS... d c 00071 d CURLOPT_FRESH_CONNECT... d c 00074 d CURLOPT_FORBID_REUSE... d c 00075 d CURLOPT_RANDOM_FILE... d c 10076 d CURLOPT_EGDSOCKET... d c 10077 d CURLOPT_CONNECTTIMEOUT... d c 00078 d CURLOPT_HEADERFUNCTION... d c 20079 d CURLOPT_HTTPGET... d c 00080 d CURLOPT_SSL_VERIFYHOST... d c 00081 d CURLOPT_COOKIEJAR... d c 10082 d CURLOPT_SSL_CIPHER_LIST... d c 10083 d CURLOPT_HTTP_VERSION... d c 00084 d CURLOPT_FTP_USE_EPSV... d c 00085 d CURLOPT_SSLCERTTYPE... d c 10086 d CURLOPT_SSLKEY... d c 10087 d CURLOPT_SSLKEYTYPE... d c 10088 d CURLOPT_SSLENGINE... d c 10089 d CURLOPT_SSLENGINE_DEFAULT... d c 00090 d CURLOPT_DNS_USE_GLOBAL_CACHE... d c 00091 d CURLOPT_DNS_CACHE_TIMEOUT... d c 00092 d CURLOPT_PREQUOTE... d c 10093 d CURLOPT_DEBUGFUNCTION... d c 20094 d CURLOPT_DEBUGDATA... d c 10095 d CURLOPT_COOKIESESSION... d c 00096 d CURLOPT_CAPATH... d c 10097 d CURLOPT_BUFFERSIZE... d c 00098 d CURLOPT_NOSIGNAL... d c 00099 d CURLOPT_SHARE c 10100 d CURLOPT_PROXYTYPE... d c 00101 d CURLOPT_ACCEPT_ENCODING... d c 10102 d CURLOPT_PRIVATE... d c 10103 d CURLOPT_HTTP200ALIASES... d c 10104 d CURLOPT_UNRESTRICTED_AUTH... d c 00105 d CURLOPT_FTP_USE_EPRT... d c 00106 d CURLOPT_HTTPAUTH... d c 00107 d CURLOPT_SSL_CTX_FUNCTION... d c 20108 d CURLOPT_SSL_CTX_DATA... d c 10109 d CURLOPT_FTP_CREATE_MISSING_DIRS... d c 00110 d CURLOPT_PROXYAUTH... d c 00111 d CURLOPT_FTP_RESPONSE_TIMEOUT... d c 00112 d CURLOPT_IPRESOLVE... d c 00113 d CURLOPT_MAXFILESIZE... d c 00114 d CURLOPT_INFILESIZE_LARGE... d c 30115 d CURLOPT_RESUME_FROM_LARGE... d c 30116 d CURLOPT_MAXFILESIZE_LARGE... d c 30117 d CURLOPT_NETRC_FILE... d c 10118 d CURLOPT_USE_SSL... d c 00119 d CURLOPT_POSTFIELDSIZE_LARGE... d c 30120 d CURLOPT_TCP_NODELAY... d c 00121 d CURLOPT_FTPSSLAUTH... d c 00129 d CURLOPT_IOCTLFUNCTION... d c 20130 d CURLOPT_IOCTLDATA... d c 10131 d CURLOPT_FTP_ACCOUNT... d c 10134 d CURLOPT_COOKIELIST... d c 10135 d CURLOPT_IGNORE_CONTENT_LENGTH... d c 00136 d CURLOPT_FTP_SKIP_PASV_IP... d c 00137 d CURLOPT_FTP_FILEMETHOD... d c 00138 d CURLOPT_LOCALPORT... d c 00139 d CURLOPT_LOCALPORTRANGE... d c 00140 d CURLOPT_CONNECT_ONLY... d c 00141 d CURLOPT_CONV_FROM_NETWORK_FUNCTION... d c 20142 d CURLOPT_CONV_TO_NETWORK_FUNCTION... d c 20143 d CURLOPT_CONV_FROM_UTF8_FUNCTION... d c 20144 d CURLOPT_MAX_SEND_SPEED_LARGE... d c 30145 d CURLOPT_MAX_RECV_SPEED_LARGE... d c 30146 d CURLOPT_FTP_ALTERNATIVE_TO_USER... d c 10147 d CURLOPT_SOCKOPTFUNCTION... d c 20148 d CURLOPT_SOCKOPTDATA... d c 10149 d CURLOPT_SSL_SESSIONID_CACHE... d c 00150 d CURLOPT_SSH_AUTH_TYPES... d c 00151 d CURLOPT_SSH_PUBLIC_KEYFILE... d c 10152 d CURLOPT_SSH_PRIVATE_KEYFILE... d c 10153 d CURLOPT_FTP_SSL_CCC... d c 00154 d CURLOPT_TIMEOUT_MS... d c 00155 d CURLOPT_CONNECTTIMEOUT_MS... d c 00156 d CURLOPT_HTTP_TRANSFER_DECODING... d c 00157 d CURLOPT_HTTP_CONTENT_DECODING... d c 00158 d CURLOPT_NEW_FILE_PERMS... d c 00159 d CURLOPT_NEW_DIRECTORY_PERMS... d c 00160 d CURLOPT_POSTREDIR... d c 00161 d CURLOPT_SSH_HOST_PUBLIC_KEY_MD5... d c 10162 d CURLOPT_OPENSOCKETFUNCTION... d c 20163 d CURLOPT_OPENSOCKETDATA... d c 10164 d CURLOPT_COPYPOSTFIELDS... d c 10165 d CURLOPT_PROXY_TRANSFER_MODE... d c 00166 d CURLOPT_SEEKFUNCTION... d c 20167 d CURLOPT_SEEKDATA... d c 10168 d CURLOPT_CRLFILE... d c 10169 d CURLOPT_ISSUERCERT... d c 10170 d CURLOPT_ADDRESS_SCOPE... d c 00171 d CURLOPT_CERTINFO... d c 00172 d CURLOPT_USERNAME... d c 10173 d CURLOPT_PASSWORD... d c 10174 d CURLOPT_PROXYUSERNAME... d c 10175 d CURLOPT_PROXYPASSWORD... d c 10176 d CURLOPT_NOPROXY... d c 10177 d CURLOPT_TFTP_BLKSIZE... d c 00178 d CURLOPT_SOCKS5_GSSAPI_SERVICE... d c 10179 d CURLOPT_SOCKS5_GSSAPI_NEC... d c 00180 d CURLOPT_PROTOCOLS... d c 00181 d CURLOPT_REDIR_PROTOCOLS... d c 00182 d CURLOPT_SSH_KNOWNHOSTS... d c 10183 d CURLOPT_SSH_KEYFUNCTION... d c 20184 d CURLOPT_SSH_KEYDATA... d c 10185 d CURLOPT_MAIL_FROM... d c 10186 d CURLOPT_MAIL_RCPT... d c 10187 d CURLOPT_FTP_USE_PRET... d c 00188 d CURLOPT_RTSP_REQUEST... d c 00189 d CURLOPT_RTSP_SESSION_ID... d c 10190 d CURLOPT_RTSP_STREAM_URI... d c 10191 d CURLOPT_RTSP_TRANSPORT... d c 10192 d CURLOPT_RTSP_CLIENT_CSEQ... d c 00193 d CURLOPT_RTSP_SERVER_CSEQ... d c 00194 d CURLOPT_INTERLEAVEDATA... d c 10195 d CURLOPT_INTERLEAVEFUNCTION... d c 20196 d CURLOPT_WILDCARDMATCH... d c 00197 d CURLOPT_CHUNK_BGN_FUNCTION... d c 20198 d CURLOPT_CHUNK_END_FUNCTION... d c 20199 d CURLOPT_FNMATCH_FUNCTION... d c 20200 d CURLOPT_CHUNK_DATA... d c 10201 d CURLOPT_FNMATCH_DATA... d c 10202 d CURLOPT_RESOLVE... d c 10203 d CURLOPT_TLSAUTH_USERNAME... d c 10204 d CURLOPT_TLSAUTH_PASSWORD... d c 10205 d CURLOPT_TLSAUTH_TYPE... d c 10206 d CURLOPT_TRANSFER_ENCODING... d c 00207 d CURLOPT_CLOSESOCKETFUNCTION... d c 20208 d CURLOPT_CLOSESOCKETDATA... d c 10209 d CURLOPT_GSSAPI_DELEGATION... d c 00210 d CURLOPT_DNS_SERVERS... d c 10211 d CURLOPT_ACCEPTTIMEOUT_MS... d c 00212 d CURLOPT_TCP_KEEPALIVE... d c 00213 d CURLOPT_TCP_KEEPIDLE... d c 00214 d CURLOPT_TCP_KEEPINTVL... d c 00215 d CURLOPT_SSL_OPTIONS... d c 00216 d CURLOPT_MAIL_AUTH... d c 10217 d CURLOPT_SASL_IR... d c 00218 d CURLOPT_XFERINFOFUNCTION... d c 20219 d CURLOPT_XOAUTH2_BEARER... d c 10220 d CURLOPT_DNS_INTERFACE... d c 10221 d CURLOPT_DNS_LOCAL_IP4... d c 10222 d CURLOPT_DNS_LOCAL_IP6... d c 10223 d CURLOPT_LOGIN_OPTIONS... d c 10224 d CURLOPT_SSL_ENABLE_NPN... d c 00225 d CURLOPT_SSL_ENABLE_ALPN... d c 00226 d CURLOPT_EXPECT_100_TIMEOUT_MS... d c 00227 d CURLOPT_PROXYHEADER... d c 10228 d CURLOPT_HEADEROPT... d c 00229 d CURLOPT_PINNEDPUBLICKEY... d c 10230 d CURLOPT_UNIX_SOCKET_PATH... d c 10231 d CURLOPT_SSL_VERIFYSTATUS... d c 00232 d CURLOPT_SSL_FALSESTART... d c 00233 d CURLOPT_PATH_AS_IS... d c 00234 d CURLOPT_PROXY_SERVICE_NAME... d c 10235 d CURLOPT_SERVICE_NAME... d c 10236 d CURLOPT_PIPEWAIT... d c 00237 d CURLOPT_DEFAULT_PROTOCOL... d c 10238 d CURLOPT_STREAM_WEIGHT... d c 00239 d CURLOPT_STREAM_DEPENDS... d c 10240 d CURLOPT_STREAM_DEPENDS_E... d c 10241 d CURLOPT_TFTP_NO_OPTIONS... d c 00242 d CURLOPT_CONNECT_TO... d c 10243 d CURLOPT_TCP_FASTOPEN... d c 00244 d CURLOPT_KEEP_SENDING_ON_ERROR... d c 00245 d CURLOPT_PROXY_CAINFO... d c 10246 d CURLOPT_PROXY_CAPATH... d c 10247 d CURLOPT_PROXY_SSL_VERIFYPEER... d c 00248 d CURLOPT_PROXY_SSL_VERIFYHOST... d c 00249 d CURLOPT_PROXY_SSLVERSION... d c 00250 d CURLOPT_PROXY_TLSAUTH_USERNAME... d c 10251 d CURLOPT_PROXY_TLSAUTH_PASSWORD... d c 10252 d CURLOPT_PROXY_TLSAUTH_TYPE... d c 10253 d CURLOPT_PROXY_SSLCERT... d c 10254 d CURLOPT_PROXY_SSLCERTTYPE... d c 10255 d CURLOPT_PROXY_SSLKEY... d c 10256 d CURLOPT_PROXY_SSLKEYTYPE... d c 10257 d CURLOPT_PROXY_KEYPASSWD... d c 10258 d CURLOPT_PROXY_SSL_CIPHER_LIST... d c 10259 d CURLOPT_PROXY_CRLFILE... d c 10260 d CURLOPT_PROXY_SSL_OPTIONS... d c 00261 d CURLOPT_PRE_PROXY... d c 10262 d CURLOPT_PROXY_PINNEDPUBLICKEY... d c 10263 d CURLOPT_ABSTRACT_UNIX_SOCKET... d c 10264 d CURLOPT_SUPPRESS_CONNECT_HEADERS... d c 00265 d CURLOPT_REQUEST_TARGET... d c 10266 d CURLOPT_SOCKS5_AUTH... d c 00267 d CURLOPT_SSH_COMPRESSION... d c 00268 d CURLOPT_MIMEPOST... d c 10269 d CURLOPT_TIMEVALUE_LARGE... d c 30270 d CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS... d c 00271 d CURLOPT_RESOLVER_START_FUNCTION... d c 20272 d CURLOPT_RESOLVER_START_DATA... d c 10273 d CURLOPT_HAPROXYPROTOCOL... d c 00274 d CURLOPT_DNS_SHUFFLE_ADDRESSES... d c 00275 d CURLOPT_TLS13_CIPHERS... d c 10276 d CURLOPT_PROXY_TLS13_CIPHERS... d c 10277 d CURLOPT_DISALLOW_USERNAME_IN_URL... d c 00278 d CURLOPT_DOH_URL... d c 10279 d CURLOPT_UPLOAD_BUFFERSIZE... d c 00280 d CURLOPT_UPKEEP_INTERVAL_MS... d c 00281 d CURLOPT_CURLU c 10282 d CURLOPT_TRAILERFUNCTION... d c 20283 d CURLOPT_TRAILERDATA... d c 10284 d CURLOPT_HTTP09_ALLOWED... d c 00285 d CURLOPT_ALTSVC_CTRL... d c 00286 d CURLOPT_ALTSVC... d c 10287 d CURLOPT_MAXAGE_CONN... d c 00288 d CURLOPT_SASL_AUTHZID... d c 10289 * /if not defined(CURL_NO_OLDIES) d CURLOPT_FILE c 10001 d CURLOPT_INFILE... d c 10009 d CURLOPT_SSLKEYPASSWD... d c 10026 d CURLOPT_SSLCERTPASSWD... d c 10026 d CURLOPT_WRITEHEADER... d c 10029 d CURLOPT_WRITEINFO... d c 10040 d CURLOPT_FTPLISTONLY... d c 00048 d CURLOPT_FTPAPPEND... d c 00050 d CURLOPT_CLOSEPOLICY... d c 00072 d CURLOPT_KRB4LEVEL... d c 10063 d CURLOPT_ENCODING... d c 10102 d CURLOPT_SERVER_RESPONSE_TIMEOUT... d c 00112 d CURLOPT_FTP_SSL... d c 00119 d CURLOPT_POST301... d c 00161 /endif * d CURLFORMcode s 10i 0 based(######ptr######) Enum d CURL_FORMADD_OK... d c 0 d CURL_FORMADD_MEMORY... d c 1 d CURL_FORMADD_OPTION_TWICE... d c 2 d CURL_FORMADD_NULL... d c 3 d CURL_FORMADD_UNKNOWN_OPTION... d c 4 d CURL_FORMADD_INCOMPLETE... d c 5 d CURL_FORMADD_ILLEGAL_ARRAY... d c 6 d CURL_FORMADD_DISABLED... d c 7 * d CURLformoption s 10i 0 based(######ptr######) Enum d CURLFORM_NOTHING... d c 0 d CURLFORM_COPYNAME... d c 1 d CURLFORM_PTRNAME... d c 2 d CURLFORM_NAMELENGTH... d c 3 d CURLFORM_COPYCONTENTS... d c 4 d CURLFORM_PTRCONTENTS... d c 5 d CURLFORM_CONTENTSLENGTH... d c 6 d CURLFORM_FILECONTENT... d c 7 d CURLFORM_ARRAY... d c 8 d CURLFORM_OBSOLETE... d c 9 d CURLFORM_FILE... d c 10 d CURLFORM_BUFFER... d c 11 d CURLFORM_BUFFERPTR... d c 12 d CURLFORM_BUFFERLENGTH... d c 13 d CURLFORM_CONTENTTYPE... d c 14 d CURLFORM_CONTENTHEADER... d c 15 d CURLFORM_FILENAME... d c 16 d CURLFORM_END... d c 17 d CURLFORM_OBSOLETE2... d c 18 d CURLFORM_STREAM... d c 19 d CURLFORM_CONTENTLEN... d c 20 * d CURLINFO s 10i 0 based(######ptr######) Enum d CURLINFO_EFFECTIVE_URL... CURLINFO_STRING + 1 d c X'00100001' d CURLINFO_RESPONSE_CODE... CURLINFO_LONG + 2 d c X'00200002' d CURLINFO_TOTAL_TIME... CURLINFO_DOUBLE + 3 d c X'00300003' d CURLINFO_NAMELOOKUP_TIME... CURLINFO_DOUBLE + 4 d c X'00300004' d CURLINFO_CONNECT_TIME... CURLINFO_DOUBLE + 5 d c X'00300005' d CURLINFO_PRETRANSFER_TIME... CURLINFO_DOUBLE + 6 d c X'00300006' d CURLINFO_SIZE_UPLOAD... CURLINFO_DOUBLE + 7 d c X'00300007' d CURLINFO_SIZE_UPLOAD_T... CURLINFO_OFF_T + 7 d c X'00600007' d CURLINFO_SIZE_DOWNLOAD... CURLINFO_DOUBLE + 8 d c X'00300008' d CURLINFO_SIZE_DOWNLOAD_T... CURLINFO_OFF_T + 8 d c X'00600008' d CURLINFO_SPEED_DOWNLOAD... CURLINFO_DOUBLE + 9 d c X'00300009' d CURLINFO_SPEED_DOWNLOAD_T... CURLINFO_OFF_T + 9 d c X'00600009' d CURLINFO_SPEED_UPLOAD... CURLINFO_DOUBLE + 10 d c X'0030000A' d CURLINFO_SPEED_UPLOAD_T... CURLINFO_OFF_T + 10 d c X'0060000A' d CURLINFO_HEADER_SIZE... CURLINFO_LONG + 11 d c X'0020000B' d CURLINFO_REQUEST_SIZE... CURLINFO_LONG + 12 d c X'0020000C' d CURLINFO_SSL_VERIFYRESULT... CURLINFO_LONG + 13 d c X'0020000D' d CURLINFO_FILETIME... CURLINFO_LONG + 14 d c X'0020000E' d CURLINFO_FILETIME_T... CURLINFO_OFF_T + 14 d c X'0060000E' d CURLINFO_CONTENT_LENGTH_DOWNLOAD... CURLINFO_DOUBLE + 15 d c X'0030000F' d CURLINFO_CONTENT_LENGTH_DOWNLOAD_T... CURLINFO_OFF_T + 15 d c X'0060000F' d CURLINFO_CONTENT_LENGTH_UPLOAD... CURLINFO_DOUBLE + 16 d c X'00300010' d CURLINFO_CONTENT_LENGTH_UPLOAD_T... CURLINFO_OFF_T + 16 d c X'00600010' d CURLINFO_STARTTRANSFER_TIME... CURLINFO_DOUBLE + 17 d c X'00300011' d CURLINFO_CONTENT_TYPE... CURLINFO_STRING + 18 d c X'00100012' d CURLINFO_REDIRECT_TIME... CURLINFO_DOUBLE + 19 d c X'00300013' d CURLINFO_REDIRECT_COUNT... CURLINFO_LONG + 20 d c X'00200014' d CURLINFO_PRIVATE... CURLINFO_STRING + 21 d c X'00100015' d CURLINFO_HTTP_CONNECTCODE... CURLINFO_LONG + 22 d c X'00200016' d CURLINFO_HTTPAUTH_AVAIL... CURLINFO_LONG + 23 d c X'00200017' d CURLINFO_PROXYAUTH_AVAIL... CURLINFO_LONG + 24 d c X'00200018' d CURLINFO_OS_ERRNO... CURLINFO_LONG + 25 d c X'00200019' d CURLINFO_NUM_CONNECTS... CURLINFO_LONG + 26 d c X'0020001A' d CURLINFO_SSL_ENGINES... CURLINFO_SLIST + 27 d c X'0040001B' d CURLINFO_COOKIELIST... CURLINFO_SLIST + 28 d c X'0040001C' d CURLINFO_LASTSOCKET... CURLINFO_LONG + 29 d c X'0020001D' d CURLINFO_FTP_ENTRY_PATH... CURLINFO_STRING + 30 d c X'0010001E' d CURLINFO_REDIRECT_URL... CURLINFO_STRING + 31 d c X'0010001F' d CURLINFO_PRIMARY_IP... CURLINFO_STRING + 32 d c X'00100020' d CURLINFO_APPCONNECT_TIME... CURLINFO_DOUBLE + 33 d c X'00300021' d CURLINFO_CERTINFO... CURLINFO_SLIST + 34 d c X'00400022' d CURLINFO_CONDITION_UNMET... CURLINFO_LONG + 35 d c X'00200023' d CURLINFO_RTSP_SESSION_ID... CURLINFO_STRING + 36 d c X'00100024' d CURLINFO_RTSP_CLIENT_CSEQ... CURLINFO_LONG + 37 d c X'00200025' d CURLINFO_RTSP_SERVER_CSEQ... CURLINFO_LONG + 38 d c X'00200026' d CURLINFO_RTSP_CSEQ_RECV... CURLINFO_LONG + 39 d c X'00200027' d CURLINFO_PRIMARY_PORT... CURLINFO_LONG + 40 d c X'00200028' d CURLINFO_LOCAL_IP... CURLINFO_STRING + 41 d c X'00100029' d CURLINFO_LOCAL_PORT... CURLINFO_LONG + 42 d c X'0020002A' d CURLINFO_TLS_SESSION... CURLINFO_SLIST + 43 d c X'0040002B' d CURLINFO_ACTIVESOCKET... CURLINFO_SOCKET + 44 d c X'0050002C' d CURLINFO_TLS_SSL_PTR... CURLINFO_SLIST + 45 d c X'0040002D' d CURLINFO_HTTP_VERSION... CURLINFO_LONG + 46 d c X'0020002E' d CURLINFO_PROXY_SSL_VERIFYRESULT... CURLINFO_LONG + 47 d c X'0020002F' d CURLINFO_PROTOCOL... CURLINFO_LONG + 48 d c X'00200030' d CURLINFO_SCHEME... CURLINFO_STRING + 49 d c X'00100031' d CURLINFO_TOTAL_TIME_T... CURLINFO_OFF_T + 50 d c X'00600032' d CURLINFO_NAMELOOKUP_TIME_T... CURLINFO_OFF_T + 51 d c X'00600033' d CURLINFO_CONNECT_TIME_T... CURLINFO_OFF_T + 52 d c X'00600034' d CURLINFO_PRETRANSFER_TIME_T... CURLINFO_OFF_T + 53 d c X'00600035' d CURLINFO_STARTTRANSFER_TIME_T... CURLINFO_OFF_T + 54 d c X'00600036' d CURLINFO_REDIRECT_TIME_T... CURLINFO_OFF_T + 55 d c X'00600037' d CURLINFO_APPCONNECT_TIME_T... CURLINFO_OFF_T + 56 d c X'00600036' * d CURLINFO_HTTP_CODE... Old ...RESPONSE_CODE d c X'00200002' * d curl_sslbackend... d s 10i 0 based(######ptr######) Enum d CURLSSLBACKEND_NONE... d c 0 d CURLSSLBACKEND_OPENSSL... d c 1 d CURLSSLBACKEND_GNUTLS... d c 2 d CURLSSLBACKEND_NSS... d c 3 d CURLSSLBACKEND_OBSOLETE4... d c 4 d CURLSSLBACKEND_GSKIT... d c 5 d CURLSSLBACKEND_POLARSSL... d c 6 d CURLSSLBACKEND_CYASSL... d c 7 d CURLSSLBACKEND_SCHANNEL... d c 8 d CURLSSLBACKEND_DARWINSSL... d c 9 d CURLSSLBACKEND_AXTLS... d c 10 d CURLSSLBACKEND_MBEDTLS... d c 11 d CURLSSLBACKEND_MESALINK... d c 12 * Aliases for clones. d CURLSSLBACKEND_LIBRESSL... d c 1 d CURLSSLBACKEND_BORINGSSL... d c 1 d CURLSSLBACKEND_WOLFSSL... d c 6 * d curl_closepolicy... d s 10i 0 based(######ptr######) Enum d CURLCLOSEPOLICY_OLDEST... d c 1 d CURLCLOSEPOLICY_LEAST_RECENTLY_USED... d c 2 d CURLCLOSEPOLICY_LEAST_TRAFFIC... d c 3 d CURLCLOSEPOLICY_SLOWEST... d c 4 d CURLCLOSEPOLICY_CALLBACK... d c 5 * d curl_lock_data... d s 10i 0 based(######ptr######) Enum d CURL_LOCK_DATA_NONE... d c 0 d CURL_LOCK_DATA_SHARE... d c 1 d CURL_LOCK_DATA_COOKIE... d c 2 d CURL_LOCK_DATA_DNS... d c 3 d CURL_LOCK_DATA_SSL_SESSION... d c 4 d CURL_LOCK_DATA_CONNECT... d c 5 d CURL_LOCK_DATA_PSL... d c 6 d CURL_LOCK_DATA_LAST... d c 7 * d curl_lock_access... d s 10i 0 based(######ptr######) Enum d CURL_LOCK_ACCESS_NONE... d c 0 d CURL_LOCK_ACCESS_SHARED... d c 1 d CURL_LOCK_ACCESS_SINGLE... d c 2 * d curl_TimeCond s 10i 0 based(######ptr######) Enum d CURL_TIMECOND_NONE... d c 0 d CURL_TIMECOND_IFMODSINCE... d c 1 d CURL_TIMECOND_LASTMOD... d c 2 d CURL_TIMECOND_LAST... d c 3 * d CURLSHcode s 10i 0 based(######ptr######) Enum d CURLSHE_OK c 0 d CURLSHE_BAD_OPTION... d c 1 d CURLSHE_IN_USE... d c 2 d CURLSHE_INVALID... d c 3 d CURLSHE_NOMEM... d c 4 d CURLSHE_NOT_BUILT_IN... d c 5 * d CURLSHoption... d s 10i 0 based(######ptr######) Enum d CURLSHOPT_SHARE... d c 1 d CURLSHOPT_UNSHARE... d c 2 d CURLSHOPT_LOCKFUNC... d c 3 d CURLSHOPT_UNLOCKFUNC... d c 4 d CURLSHOPT_USERDATA... d c 5 * d CURLversion s 10i 0 based(######ptr######) Enum d CURLVERSION_FIRST... d c 0 d CURLVERSION_SECOND... d c 1 d CURLVERSION_THIRD... d c 2 d CURLVERSION_FOURTH... d c 3 d CURLVERSION_NOW... d c 3 CURLVERSION_FOURTH * d curlsocktype s 10i 0 based(######ptr######) Enum d CURLSOCKTYPE_IPCXN... d c 0 d CURLSOCKTYPE_ACCEPT... d c 1 * d CURL_SOCKOPT_OK... d c 0 d CURL_SOCKOPT_ERROR... d c 1 d CURL_SOCKOPT_ALREADY_CONNECTED... d c 2 * d CURLMcode s 10i 0 based(######ptr######) Enum d CURLM_CALL_MULTI_PERFORM... d c -1 d CURLM_CALL_MULTI_SOCKET... d c -1 d CURLM_OK c 0 d CURLM_BAD_HANDLE... d c 1 d CURLM_BAD_EASY_HANDLE... d c 2 d CURLM_OUT_OF_MEMORY... d c 3 d CURLM_INTERNAL_ERROR... d c 4 d CURLM_BAD_SOCKET... d c 5 d CURLM_UNKNOWN_OPTION... d c 6 d CURLM_ADDED_ALREADY... d c 7 d CURLM_RECURSIVE_API_CALL... d c 8 d CURLM_WAKEUP_FAILURE... d c 9 d CURLM_BAD_FUNCTION_ARGUMENT... d c 10 d CURLM_LAST c 11 * d CURLMSG s 10i 0 based(######ptr######) Enum d CURLMSG_NONE c 0 d CURLMSG_DONE c 1 * d CURLMoption s 10i 0 based(######ptr######) Enum d CURLMOPT_SOCKETFUNCTION... d c 20001 d CURLMOPT_SOCKETDATA... d c 10002 d CURLMOPT_PIPELINING... d c 00003 d CURLMOPT_TIMERFUNCTION... d c 20004 d CURLMOPT_TIMERDATA... d c 10005 d CURLMOPT_MAXCONNECTS... d c 00006 d CURLMOPT_MAX_HOST_CONNECTIONS... d c 00007 d CURLMOPT_MAX_PIPELINE_LENGTH... d c 00008 d CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE... d c 30009 d CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE... d c 30010 d CURLMOPT_PIPELINING_SITE_BL... d c 10011 d CURLMOPT_PIPELINING_SERVER_BL... d c 10012 d CURLMOPT_MAX_TOTAL_CONNECTIONS... d c 00013 d CURLMOPT_PUSHFUNCTION... d c 20014 d CURLMOPT_PUSHDATA... d c 10015 d CURLMOPT_MAX_CONCURRENT_STREAMS... d c 10016 * * Bitmask bits for CURLMOPT_PIPELING. * d CURLPIPE_NOTHING... d c x'00000000' d CURLPIPE_HTTP1 c x'00000001' d CURLPIPE_MULTIPLEX... d c x'00000002' * * Public API enums for RTSP requests. * d CURLRTSPREQ_NONE... d c 0 d CURL_RTSPREQ_OPTIONS... d c 1 d CURL_RTSPREQ_DESCRIBE... d c 2 d CURL_RTSPREQ_ANNOUNCE... d c 3 d CURL_RTSPREQ_SETUP... d c 4 d CURL_RTSPREQ_PLAY... d c 5 d CURL_RTSPREQ_PAUSE... d c 6 d CURL_RTSPREQ_TEARDOWN... d c 7 d CURL_RTSPREQ_GET_PARAMETER... d c 8 d CURL_RTSPREQ_SET_PARAMETER... d c 9 d CURL_RTSPREQ_RECORD... d c 10 d CURL_RTSPREQ_RECEIVE... d c 12 d CURL_RTSPREQ_LAST... d c 13 * d CURLUcode s 10i 0 based(######ptr######) Enum d CURLUE_OK c 0 d CURLUE_BAD_HANDLE... d c 1 d CURLUE_BAD_PARTPOINTER... d c 2 d CURLUE_MALFORMED_INPUT... d c 3 d CURLUE_BAD_PORT_NUMBER... d c 4 d CURLUE_UNSUPPORTED_SCHEME... d c 5 d CURLUE_URLDECODE... d c 6 d CURLUE_OUT_OF_MEMORY... d c 7 d CURLUE_USER_NOT_ALLOWED... d c 8 d CURLUE_UNKNOWN_PART... d c 9 d CURLUE_NO_SCHEME... d c 10 d CURLUE_NO_USER... d c 11 d CURLUE_NO_PASSWORD... d c 12 d CURLUE_NO_OPTIONS... d c 13 d CURLUE_NO_HOST... d c 14 d CURLUE_NO_PORT... d c 15 d CURLUE_NO_QUERY... d c 16 d CURLUE_NO_FRAGMENT... d c 17 * d CURLUPart s 10i 0 based(######ptr######) Enum d CURLUPART_URL c 0 d CURLUPART_SCHEME... d c 1 d CURLUPART_USER... d c 2 d CURLUPART_PASSWORD... d c 3 d CURLUPART_OPTIONS... d c 4 d CURLUPART_HOST... d c 5 d CURLUPART_PORT... d c 6 d CURLUPART_PATH... d c 7 d CURLUPART_QUERY... d c 8 d CURLUPART_FRAGMENT... d c 9 * * Renaming CURLMsg to CURL_Msg to avoid case-insensivity name clash. * d CURL_Msg ds based(######ptr######) d qualified d msg like(CURLMSG) d easy_handle * CURL * d data * d whatever * overlay(data) void * d result overlay(data) like(CURLcode) * d curl_waitfd... d ds based(######ptr######) d qualified d fd like(curl_socket_t) d events 5i 0 d revents 5i 0 * d curl_http_post... d ds based(######ptr######) d qualified d next * curl_httppost * d name * char * d namelength 10i 0 long d contents * char * d contentslength... d 10i 0 long d buffer * char * d bufferlength... d 10i 0 long d contenttype * char * d contentheader... d * curl_slist * d more * curl_httppost * d flags 10i 0 long d showfilename * char * d userp * void * * d curl_sockaddr ds based(######ptr######) d qualified d family 10i 0 d socktype 10i 0 d protocol 10i 0 d addrlen 10u 0 d addr 16 struct sockaddr * d curl_khtype s 10i 0 based(######ptr######) enum d CURLKHTYPE_UNKNOWN... d c 0 d CURLKHTYPE_RSA1... d c 1 d CURLKHTYPE_RSA... d c 2 d CURLKHTYPE_DSS... d c 3 * d curl_khkey ds based(######ptr######) d qualified d key * const char * d len 10u 0 d keytype like(curl_khtype) * d curl_forms ds based(######ptr######) d qualified d option like(CURLformoption) d value * const char * d value_ptr * overlay(value) d value_procptr... d * overlay(value) procptr d value_num overlay(value: 8) like(curl_off_t) * d curl_slist ds based(######ptr######) d qualified d data * char * d next * struct curl_slist * * d curl_version_info_data... d ds based(######ptr######) d qualified d age like(CURLversion) d version * const char * d version_num 10u 0 d host * const char * d features 10i 0 d ssl_version * const char * d ssl_version_num... d 10i 0 long d libz_version * const char * d protocols * const char * const * d ares * const char * d ares_num 10i 0 d libidn * const char * d iconv_ver_num... d 10i 0 d libssh_version... d * const char * * d curl_certinfo ds based(######ptr######) d qualified d num_of_certs 10i 0 d certinfo * struct curl_slist ** * d curl_fistrgs ds based(######ptr######) d qualified d time * char * d perm * char * d user * char * d group * char * d target * char * * d curl_tlssessioninfo... d ds based(######ptr######) d qualified d backend like(curl_sslbackend) d internals * void * * d curl_fileinfo ds based(######ptr######) d qualified d filename * char * d filetype like(curlfiletype) d time 10i 0 time_t d perm 10u 0 d uid 10i 0 d gid 10i 0 d size like(curl_off_t) d hardlinks 10i 0 d strings likeds(curl_fistrgs) d flags 10u 0 d b_data * char * d b_size 10u 0 size_t d b_used 10u 0 size_t * d curl_formget_callback... d s * based(######ptr######) procptr * d curl_malloc_callback... d s * based(######ptr######) procptr * d curl_free_callback... d s * based(######ptr######) procptr * d curl_realloc_callback... d s * based(######ptr######) procptr * d curl_strdup_callback... d s * based(######ptr######) procptr * d curl_calloc_callback... d s * based(######ptr######) procptr * d curl_lock_function... d s * based(######ptr######) procptr * d curl_unlock_function... d s * based(######ptr######) procptr * d curl_progress_callback... d s * based(######ptr######) procptr * d curl_xferinfo_callback... d s * based(######ptr######) procptr * d curl_read_callback... d s * based(######ptr######) procptr * d curl_trailer_callback... d s * based(######ptr######) procptr * d curl_write_callback... d s * based(######ptr######) procptr * d curl_seek_callback... d s * based(######ptr######) procptr * d curl_sockopt_callback... d s * based(######ptr######) procptr * d curl_ioctl_callback... d s * based(######ptr######) procptr * d curl_debug_callback... d s * based(######ptr######) procptr * d curl_conv_callback... d s * based(######ptr######) procptr * d curl_ssl_ctx_callback... d s * based(######ptr######) procptr * d curl_socket_callback... d s * based(######ptr######) procptr * d curl_multi_timer_callback... d s * based(######ptr######) procptr * d curl_push_callback... d s * based(######ptr######) procptr * d curl_opensocket_callback... d s * based(######ptr######) procptr * d curl_sshkeycallback... d s * based(######ptr######) procptr * d curl_chunk_bgn_callback... d s * based(######ptr######) procptr * d curl_chunk_end_callback... d s * based(######ptr######) procptr * d curl_fnmatch_callback... d s * based(######ptr######) procptr * d curl_closesocket_callback... d s * based(######ptr######) procptr * d curl_resolver_start_callback... d s * based(######ptr######) procptr * ************************************************************************** * Prototypes ************************************************************************** * d curl_mime_init pr * extproc('curl_mime_init') curl_mime * d easy * value CURL * * d curl_mime_free pr extproc('curl_mime_free') d mime * value curl_mime * * d curl_mime_addpart... d pr * extproc('curl_mime_addpart') curl_mimepart * d mime * value curl_mime * * d curl_mime_name pr extproc('curl_mime_name') d like(CURLcode) d part * value curl_mimepart * d name * value options(*string) * d curl_mime_filename... d pr extproc('curl_mime_filename') d like(CURLcode) d part * value curl_mimepart * d filename * value options(*string) * d curl_mime_type pr extproc('curl_mime_type') d like(CURLcode) d part * value curl_mimepart * d mimetype * value options(*string) * d curl_mime_encoder... d pr extproc('curl_mime_encoder') d like(CURLcode) d part * value curl_mimepart * d encoding * value options(*string) * d curl_mime_data pr extproc('curl_mime_data') d like(CURLcode) d part * value curl_mimepart * d data * value options(*string) d datasize 10u 0 size_t * d curl_mime_filedata... d pr extproc('curl_mime_filedata') d like(CURLcode) d part * value curl_mimepart * d filename * value options(*string) * d curl_mime_data_cb... d pr extproc('curl_mime_data_cb') d like(CURLcode) d part * value curl_mimepart * d datasize value like(curl_off_t) d readfunc value like(curl_read_callback) d seekfunc value like(curl_seek_callback) d freefunc value like(curl_free_callback) d arg * value void * * d curl_mime_subparts... d pr extproc('curl_mime_subparts') d like(CURLcode) d part * value curl_mimepart * d subparts * value curl_mime * * d curl_mime_headers... d pr extproc('curl_mime_headers') d like(CURLcode) d part * value curl_mimepart * d headers * value curl_slist * d take_ownership... d 10i 0 value * * This procedure as a variable parameter list. * This prototype allows use of an option array, or a single "object" * option. Other argument lists may be implemented by alias procedure * prototype definitions. * d curl_formadd pr extproc('curl_formadd') d like(CURLFORMcode) d httppost * curl_httppost * d lastpost * curl_httppost * d option1 value like(CURLFORMoption) CURLFORM_ARRAY d options(*nopass) d object1 * value options(*string: *nopass) d option2 value like(CURLFORMoption) CURLFORM_END d options(*nopass) * * d curl_strequal pr 10i 0 extproc('curl_strequal') d s1 * value options(*string) d s2 * value options(*string) * d curl_strnequal pr 10i 0 extproc('curl_strnequal') d s1 * value options(*string) d s2 * value options(*string) d n 10u 0 value * d curl_formget pr 10i 0 extproc('curl_formget') d form * value curl_httppost * d arg * value d append value like(curl_formget_callback) * d curl_formfree pr extproc('curl_formfree') d form * value curl_httppost * * d curl_getenv pr * extproc('curl_getenv') d variable * value options(*string) * d curl_version pr * extproc('curl_version') * d curl_easy_escape... d pr * extproc('curl_easy_escape') char * d handle * value CURL * d string * value options(*string) d length 10i 0 value * d curl_escape pr * extproc('curl_escape') char * d string * value options(*string) d length 10i 0 value * d curl_easy_unescape... d pr * extproc('curl_easy_unescape') char * d handle * value CURL * d string * value options(*string) d length 10i 0 value d outlength 10i 0 options(*omit) * d curl_unescape pr * extproc('curl_unescape') char * d string * value options(*string) d length 10i 0 value * d curl_free pr extproc('curl_free') d p * value * d curl_global_init... d pr extproc('curl_global_init') d like(CURLcode) d flags 10i 0 value * d curl_global_init_mem... d pr extproc('curl_global_init_mem') d like(CURLcode) d m value like(curl_malloc_callback) d f value like(curl_free_callback) d r value like(curl_realloc_callback) d s value like(curl_strdup_callback) d c value like(curl_calloc_callback) * d curl_global_cleanup... d pr extproc('curl_global_cleanup') * d curl_slist_append... d pr * extproc('curl_slist_append') struct curl_slist * d list * value struct curl_slist * d data * value options(*string) const char * * d curl_slist_free_all... d pr extproc('curl_slist_free_all') d list * value struct curl_slist * * d curl_getdate pr 10i 0 extproc('curl_getdate') time_t d p * value options(*string) const char * d unused 10i 0 const options(*omit) time_t * d curl_share_init... d pr * extproc('curl_share_init') CURLSH * (= void *) * * Variable argument type procedure. * Multiply prototyped to support all possible types. * d curl_share_setopt_int... d pr extproc('curl_share_setopt') d like(CURLSHcode) d share * value CURLSH * (= void *) d option value like(CURLSHoption) d intarg 10i 0 value options(*nopass) * d curl_share_setopt_ptr... d pr extproc('curl_share_setopt') d like(CURLSHcode) d share * value CURLSH * (= void *) d option value like(CURLSHoption) d ptrarg * value options(*nopass) * d curl_share_setopt_proc... d pr extproc('curl_share_setopt') d like(CURLSHcode) d share * value CURLSH * (= void *) d option value like(CURLSHoption) d procarg * value procptr options(*nopass) * d curl_share_cleanup... d pr extproc('curl_share_cleanup') d like(CURLSHcode) d share * value CURLSH * (= void *) * d curl_version_info... d pr * extproc('curl_version_info') c_i_version_data * d version value like(CURLversion) * d curl_easy_strerror... d pr * extproc('curl_easy_strerror') const char * d code value like(CURLcode) * d curl_share_strerror... d pr * extproc('curl_share_strerror') const char * d code value like(CURLSHcode) * d curl_easy_init pr * extproc('curl_easy_init') CURL * * * Multiple prototypes for vararg procedure curl_easy_setopt. * d curl_easy_setopt_long... d pr extproc('curl_easy_setopt') d like(CURLcode) d curl * value CURL * d option value like(CURLoption) d longarg 10i 0 value options(*nopass) * d curl_easy_setopt_object... d pr extproc('curl_easy_setopt') d like(CURLcode) d curl * value CURL * d option value like(CURLoption) d objectarg * value options(*string: *nopass) * d curl_easy_setopt_function... d pr extproc('curl_easy_setopt') d like(CURLcode) d curl * value CURL * d option value like(CURLoption) d functionarg * value procptr options(*nopass) * d curl_easy_setopt_offset... d pr extproc('curl_easy_setopt') d like(CURLcode) d curl * value CURL * d option value like(CURLoption) d offsetarg value like(curl_off_t) d options(*nopass) * * d curl_easy_perform... d pr extproc('curl_easy_perform') d like(CURLcode) d curl * value CURL * * d curl_easy_cleanup... d pr extproc('curl_easy_cleanup') d curl * value CURL * * * Multiple prototypes for vararg procedure curl_easy_getinfo. * d curl_easy_getinfo_string... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d stringarg * options(*nopass) char * * d curl_easy_getinfo_long... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d longarg 10i 0 options(*nopass) * d curl_easy_getinfo_double... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d doublearg 8f options(*nopass) * d curl_easy_getinfo_slist... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d slistarg * options(*nopass) struct curl_slist * * d curl_easy_getinfo_ptr... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d ptrarg * options(*nopass) void * * d curl_easy_getinfo_socket... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d socketarg like(curl_socket_t) options(*nopass) * d curl_easy_getinfo_off_t... d pr extproc('curl_easy_getinfo') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d offsetarg like(curl_off_t) options(*nopass) * * d curl_easy_duphandle... d pr * extproc('curl_easy_duphandle') CURL * d curl * value CURL * * d curl_easy_reset... d pr extproc('curl_easy_reset') d curl * value CURL * * d curl_easy_recv... d pr extproc('curl_easy_recv') d like(CURLcode) d curl * value CURL * d buffer * value void * d buflen 10u 0 value size_t d n 10u 0 size_t * * d curl_easy_send... d pr extproc('curl_easy_send') d like(CURLcode) d curl * value CURL * d buffer * value const void * d buflen 10u 0 value size_t d n 10u 0 size_t * * d curl_easy_pause... d pr extproc('curl_easy_pause') d like(CURLcode) d curl * value CURL * d bitmask 10i 0 value * d curl_easy_upkeep... d pr extproc('curl_easy_upkeep') d like(CURLcode) d curl * value CURL * * d curl_multi_init... d pr * extproc('curl_multi_init') CURLM * * d curl_multi_add_handle... d pr extproc('curl_multi_add_handle') d like(CURLMcode) d multi_handle * value CURLM * d curl_handle * value CURL * * d curl_multi_remove_handle... d pr extproc('curl_multi_remove_handle') d like(CURLMcode) d multi_handle * value CURLM * d curl_handle * value CURL * * d curl_multi_fdset... d pr extproc('curl_multi_fdset') d like(CURLMcode) d multi_handle * value CURLM * d read_fd_set 65535 options(*varsize) fd_set d write_fd_set 65535 options(*varsize) fd_set d exc_fd_set 65535 options(*varsize) fd_set d max_fd 10i 0 * d curl_multi_wait... d pr extproc('curl_multi_wait') d like(CURLMcode) d multi_handle * value CURLM * d extra_fds * value curl_waitfd * d extra_nfds 10u 0 value d timeout_ms 10i 0 value d ret 10i 0 options(*omit) * d curl_multi_perform... d pr extproc('curl_multi_perform') d like(CURLMcode) d multi_handle * value CURLM * d running_handles... d 10i 0 * d curl_multi_cleanup... d pr extproc('curl_multi_cleanup') d like(CURLMcode) d multi_handle * value CURLM * * d curl_multi_info_read... d pr * extproc('curl_multi_info_read') CURL_Msg * d multi_handle * value CURLM * d msgs_in_queue 10i 0 * d curl_multi_strerror... d pr * extproc('curl_multi_strerror') char * d code value like(CURLMcode) * d curl_pushheader_bynum... d pr * extproc('curl_pushheader_bynum') char * d h * value curl_pushheaders * d num 10u 0 value * d curl_pushheader_byname... d pr * extproc('curl_pushheader_byname') char * d h * value curl_pushheaders * d header * value options(*string) const char * * d curl_multi_socket... d pr extproc('curl_multi_socket') d like(CURLMcode) d multi_handle * value CURLM * d s value like(curl_socket_t) d running_handles... d 10i 0 * d curl_multi_socket_action... d pr extproc('curl_multi_socket_action') d like(CURLMcode) d multi_handle * value CURLM * d s value like(curl_socket_t) d ev_bitmask 10i 0 value d running_handles... d 10i 0 * d curl_multi_socket_all... d pr extproc('curl_multi_socket_all') d like(CURLMcode) d multi_handle * value CURLM * d running_handles... d 10i 0 * d curl_multi_timeout... d pr extproc('curl_multi_timeout') d like(CURLMcode) d multi_handle * value CURLM * d milliseconds 10i 0 * * Multiple prototypes for vararg procedure curl_multi_setopt. * d curl_multi_setopt_long... d pr extproc('curl_multi_setopt') d like(CURLMcode) d multi_handle * value CURLM * d option value like(CURLMoption) d longarg 10i 0 value options(*nopass) * d curl_multi_setopt_object... d pr extproc('curl_multi_setopt') d like(CURLMcode) d multi_handle * value CURLM * d option value like(CURLMoption) d objectarg * value options(*string: *nopass) * d curl_multi_setopt_function... d pr extproc('curl_multi_setopt') d like(CURLMcode) d multi_handle * value CURLM * d option value like(CURLMoption) d functionarg * value procptr options(*nopass) * d curl_multi_setopt_offset... d pr extproc('curl_multi_setopt') d like(CURLMcode) d multi_handle * value CURLM * d option value like(CURLMoption) d offsetarg value like(curl_off_t) d options(*nopass) * * d curl_multi_assign... d pr extproc('curl_multi_assign') d like(CURLMcode) d multi_handle * value CURLM * d sockfd value like(curl_socket_t) d sockp * value void * * d curl_url pr * extproc('curl_url') CURLU * * d curl_url_cleanup... d pr extproc('curl_url_cleanup') d handle * value CURLU * * d curl_url_dup pr * extproc('curl_url_dup') CURLU * d in * value CURLU * * d curl_url_get pr extproc('curl_url_get') d like(CURLUcode) d handle * value CURLU * d what value like(CURLUPart) d part * char ** d flags 10u 0 value * d curl_url_set pr extproc('curl_url_set') d like(CURLUcode) d handle * value CURLU * d what value like(CURLUPart) d part * value options(*string) d flags 10u 0 value * ************************************************************************** * CCSID wrapper procedure prototypes ************************************************************************** * d curl_version_ccsid... d pr * extproc('curl_version_ccsid') d ccsid 10u 0 value * d curl_easy_escape_ccsid... d pr * extproc('curl_easy_escape_ccsid') char * d handle * value CURL * d string * value options(*string) d length 10i 0 value d ccsid 10u 0 value * d curl_easy_unescape_ccsid... d pr * extproc('curl_easy_unescape_ccsid') char * d handle * value CURL * d string * value options(*string) d length 10i 0 value d outlength 10i 0 options(*omit) d ccsid 10u 0 value * d curl_slist_append_ccsid... d pr * extproc('curl_slist_append_ccsid') struct curl_slist * d list * value struct curl_slist * d data * value options(*string) const char * d ccsid 10u 0 value * d curl_getdate_ccsid... d pr 10i 0 extproc('curl_getdate_ccsid') time_t d p * value options(*string) const char * d unused 10i 0 const options(*omit) time_t d ccsid 10u 0 value * d curl_version_info_ccsid... d pr * extproc('curl_version_info_ccsid') c_i_version_data * d version value like(CURLversion) d ccsid 10u 0 value * d curl_easy_strerror_ccsid... d pr * extproc('curl_easy_strerror_ccsid') const char * d code value like(CURLcode) d ccsid 10u 0 value * d curl_share_strerror_ccsid... d pr * extproc('curl_share_strerror_ccsid') const char * d code value like(CURLSHcode) d ccsid 10u 0 value * d curl_multi_strerror_ccsid... d pr * extproc('curl_multi_strerror_ccsid') char * d code value like(CURLMcode) d ccsid 10u 0 value * * May be used for strings and structures. d curl_easy_getinfo_ccsid... d pr extproc('curl_easy_getinfo_ccsid') d like(CURLcode) d curl * value CURL * d info value like(CURLINFO) d ptrarg * options(*nopass) char * d ccsid 10u 0 value options(*nopass) * d curl_certinfo_free_all... d pr extproc('curl_certinfo_free_all') d info * value * d curl_formadd_ccsid... d pr extproc('curl_formadd_ccsid') d like(CURLFORMcode) d httppost * curl_httppost * d lastpost * curl_httppost * d option1 value like(CURLFORMoption) CURLFORM_ARRAY d options(*nopass) d object1 * value options(*string: *nopass) d option2 value like(CURLFORMoption) CURLFORM_END d options(*nopass) * d curl_formget_ccsid... d pr 10i 0 extproc('curl_formget_ccsid') d form * value curl_httppost * d arg * value d append value like(curl_formget_callback) d ccsid 10u 0 value * d curl_form_long_value... d pr * extproc('curl_form_long_value') d value 10i 0 value curl_httppost * * d curl_easy_setopt_ccsid... d pr extproc('curl_easy_setopt_ccsid') d like(CURLcode) d curl * value CURL * d option value like(CURLoption) d objectarg * value options(*string: *nopass) d ccsid 10u 0 value options(*nopass) * d curl_pushheader_bynum_ccsid... d pr * extproc( char * d 'curl_pushheader_bynum_ccsid') d h * value curl_pushheaders * d num 10u 0 value d ccsid 10u 0 value * d curl_pushheader_byname_ccsid... d pr * extproc( char * d 'curl_pushheader_byname_ccsid') d h * value curl_pushheaders * d header * value options(*string) const char * d ccsidin 10u 0 value d ccsidout 10u 0 value * d curl_mime_name_ccsid... d pr extproc('curl_mime_name_ccsid') d like(CURLcode) d part * value curl_mimepart * d name * value options(*string) d ccsid 10u 0 value * d curl_mime_filename_ccsid... d pr extproc('curl_mime_filename_ccsid') d like(CURLcode) d part * value curl_mimepart * d filename * value options(*string) d ccsid 10u 0 value * d curl_mime_type_ccsid... d pr extproc('curl_mime_type_ccsid') d like(CURLcode) d part * value curl_mimepart * d mimetype * value options(*string) d ccsid 10u 0 value * d curl_mime_encoder_ccsid... d pr extproc('curl_mime_encoder_ccsid') d like(CURLcode) d part * value curl_mimepart * d encoding * value options(*string) d ccsid 10u 0 value * d curl_mime_data_ccsid... d pr extproc('curl_mime_data_ccsid') d like(CURLcode) d part * value curl_mimepart * d data * value options(*string) d datasize 10u 0 size_t d ccsid 10u 0 value * d curl_mime_filedata_ccsid... d pr extproc('curl_mime_filedata_ccsid') d like(CURLcode) d part * value curl_mimepart * d filename * value options(*string) d ccsid 10u 0 value * d curl_url_get_ccsid... d pr extproc('curl_url_get_ccsid') d like(CURLUcode) d handle * value CURLU * d what value like(CURLUPart) d part * char ** d flags 10u 0 value d ccsid 10u 0 value * d curl_url_set_ccsid... d pr extproc('curl_url_set_ccsid') d like(CURLUcode) d handle * value CURLU * d what value like(CURLUPart) d part * value options(*string) d flags 10u 0 value d ccsid 10u 0 value * /endif davix-0.8.0/deps/curl/packages/OS400/ccsidcurl.c0000644000000000000000000007746414121063461017712 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * ***************************************************************************/ /* CCSID API wrappers for OS/400. */ #include #include #include #include #include #pragma enum(int) #include "curl.h" #include "mprintf.h" #include "slist.h" #include "urldata.h" #include "url.h" #include "setopt.h" #include "getinfo.h" #include "ccsidcurl.h" #include "os400sys.h" #ifndef SIZE_MAX #define SIZE_MAX ((size_t) ~0) /* Is unsigned on OS/400. */ #endif #define ASCII_CCSID 819 /* Use ISO-8859-1 as ASCII. */ #define NOCONV_CCSID 65535 /* No conversion. */ #define ICONV_ID_SIZE 32 /* Size of iconv_open() code identifier. */ #define ICONV_OPEN_ERROR(t) ((t).return_value == -1) #define ALLOC_GRANULE 8 /* Alloc. granule for curl_formadd_ccsid(). */ static void makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid) { /** *** Convert a CCSID to the corresponding IBM iconv_open() character *** code identifier. *** This code is specific to the OS400 implementation of the iconv library. *** CCSID 65535 (no conversion) is replaced by the ASCII CCSID. *** CCSID 0 is interpreted by the OS400 as the job's CCSID. **/ ccsid &= 0xFFFF; if(ccsid == NOCONV_CCSID) ccsid = ASCII_CCSID; memset(buf, 0, ICONV_ID_SIZE); curl_msprintf(buf, "IBMCCSID%05u0000000", ccsid); } static iconv_t iconv_open_CCSID(unsigned int ccsidout, unsigned int ccsidin, unsigned int cstr) { char fromcode[ICONV_ID_SIZE]; char tocode[ICONV_ID_SIZE]; /** *** Like iconv_open(), but character codes are given as CCSIDs. *** If `cstr' is non-zero, conversion is set up to stop whenever a *** null character is encountered. *** See iconv_open() IBM description in "National Language Support API". **/ makeOS400IconvCode(fromcode, ccsidin); makeOS400IconvCode(tocode, ccsidout); memset(tocode + 13, 0, sizeof(tocode) - 13); /* Dest. code id format. */ if(cstr) fromcode[18] = '1'; /* Set null-terminator flag. */ return iconv_open(tocode, fromcode); } static int convert(char *d, size_t dlen, int dccsid, const char *s, int slen, int sccsid) { int i; iconv_t cd; size_t lslen; /** *** Convert `sccsid'-coded `slen'-data bytes at `s' into `dccsid'-coded *** data stored in the `dlen'-byte buffer at `d'. *** If `slen' < 0, source string is null-terminated. *** CCSID 65535 (no conversion) is replaced by the ASCII CCSID. *** Return the converted destination byte count, or -1 if error. **/ if(sccsid == 65535) sccsid = ASCII_CCSID; if(dccsid == 65535) dccsid = ASCII_CCSID; if(sccsid == dccsid) { lslen = slen >= 0? slen: strlen(s) + 1; i = lslen < dlen? lslen: dlen; if(s != d && i > 0) memcpy(d, s, i); return i; } if(slen < 0) { lslen = 0; cd = iconv_open_CCSID(dccsid, sccsid, 1); } else { lslen = (size_t) slen; cd = iconv_open_CCSID(dccsid, sccsid, 0); } if(ICONV_OPEN_ERROR(cd)) return -1; i = dlen; if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0) i = -1; else i -= dlen; iconv_close(cd); return i; } static char * dynconvert(int dccsid, const char *s, int slen, int sccsid) { char *d; char *cp; size_t dlen; int l; static const char nullbyte = 0; /* Like convert, but the destination is allocated and returned. */ dlen = (size_t) (slen < 0? strlen(s): slen) + 1; dlen *= MAX_CONV_EXPANSION; /* Allow some expansion. */ d = malloc(dlen); if(!d) return (char *) NULL; l = convert(d, dlen, dccsid, s, slen, sccsid); if(l < 0) { free(d); return (char *) NULL; } if(slen < 0) { /* Need to null-terminate even when source length is given. Since destination code size is unknown, use a conversion to generate terminator. */ int l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID); if(l2 < 0) { free(d); return (char *) NULL; } l += l2; } if((size_t) l < dlen) { cp = realloc(d, l); /* Shorten to minimum needed. */ if(cp) d = cp; } return d; } static struct curl_slist * slist_convert(int dccsid, struct curl_slist *from, int sccsid) { struct curl_slist *to = (struct curl_slist *) NULL; for(; from; from = from->next) { struct curl_slist *nl; char *cp = dynconvert(dccsid, from->data, -1, sccsid); if(!cp) { curl_slist_free_all(to); return (struct curl_slist *) NULL; } nl = Curl_slist_append_nodup(to, cp); if(!nl) { curl_slist_free_all(to); free(cp); return NULL; } to = nl; } return to; } char * curl_version_ccsid(unsigned int ccsid) { int i; char *aversion; char *eversion; aversion = curl_version(); if(!aversion) return aversion; i = strlen(aversion) + 1; i *= MAX_CONV_EXPANSION; eversion = Curl_thread_buffer(LK_CURL_VERSION, i); if(!eversion) return (char *) NULL; if(convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0) return (char *) NULL; return eversion; } char * curl_easy_escape_ccsid(CURL *handle, const char *string, int length, unsigned int sccsid, unsigned int dccsid) { char *s; char *d; if(!string) { errno = EINVAL; return (char *) NULL; } s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid); if(!s) return (char *) NULL; d = curl_easy_escape(handle, s, 0); free(s); if(!d) return (char *) NULL; s = dynconvert(dccsid, d, -1, ASCII_CCSID); free(d); return s; } char * curl_easy_unescape_ccsid(CURL *handle, const char *string, int length, int *outlength, unsigned int sccsid, unsigned int dccsid) { char *s; char *d; if(!string) { errno = EINVAL; return (char *) NULL; } s = dynconvert(ASCII_CCSID, string, length? length: -1, sccsid); if(!s) return (char *) NULL; d = curl_easy_unescape(handle, s, 0, outlength); free(s); if(!d) return (char *) NULL; s = dynconvert(dccsid, d, -1, ASCII_CCSID); free(d); if(s && outlength) *outlength = strlen(s); return s; } struct curl_slist * curl_slist_append_ccsid(struct curl_slist *list, const char *data, unsigned int ccsid) { char *s; s = (char *) NULL; if(!data) return curl_slist_append(list, data); s = dynconvert(ASCII_CCSID, data, -1, ccsid); if(!s) return (struct curl_slist *) NULL; list = curl_slist_append(list, s); free(s); return list; } time_t curl_getdate_ccsid(const char *p, const time_t * unused, unsigned int ccsid) { char *s; time_t t; if(!p) return curl_getdate(p, unused); s = dynconvert(ASCII_CCSID, p, -1, ccsid); if(!s) return (time_t) -1; t = curl_getdate(s, unused); free(s); return t; } static int convert_version_info_string(const char * * stringp, char * * bufp, int *left, unsigned int ccsid) { /* Helper for curl_version_info_ccsid(): convert a string if defined. Result is stored in the `*left'-byte buffer at `*bufp'. `*bufp' and `*left' are updated accordingly. Return 0 if ok, else -1. */ if(*stringp) { int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID); if(l <= 0) return -1; *stringp = *bufp; *bufp += l; *left -= l; } return 0; } curl_version_info_data * curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid) { curl_version_info_data * p; char *cp; int n; int nproto; curl_version_info_data * id; /* The assertion below is possible, because although the second operand is an enum member, the first is a #define. In that case, the OS/400 C compiler seems to compare string values after substitution. */ #if CURLVERSION_NOW != CURLVERSION_FOURTH #error curl_version_info_data structure has changed: upgrade this procedure. #endif /* If caller has been compiled with a new version, error. */ if(stamp > CURLVERSION_NOW) return (curl_version_info_data *) NULL; p = curl_version_info(stamp); if(!p) return p; /* Measure thread space needed. */ n = 0; nproto = 0; if(p->protocols) { while(p->protocols[nproto]) n += strlen(p->protocols[nproto++]); n += nproto++; } if(p->version) n += strlen(p->version) + 1; if(p->host) n += strlen(p->host) + 1; if(p->ssl_version) n += strlen(p->ssl_version) + 1; if(p->libz_version) n += strlen(p->libz_version) + 1; if(p->ares) n += strlen(p->ares) + 1; if(p->libidn) n += strlen(p->libidn) + 1; if(p->libssh_version) n += strlen(p->libssh_version) + 1; /* Allocate thread space. */ n *= MAX_CONV_EXPANSION; if(nproto) n += nproto * sizeof(const char *); cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n); id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO, sizeof(*id)); if(!id || !cp) return (curl_version_info_data *) NULL; /* Copy data and convert strings. */ memcpy((char *) id, (char *) p, sizeof(*p)); if(id->protocols) { int i = nproto * sizeof(id->protocols[0]); id->protocols = (const char * const *) cp; memcpy(cp, (char *) p->protocols, i); cp += i; n -= i; for(i = 0; id->protocols[i]; i++) if(convert_version_info_string(((const char * *) id->protocols) + i, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; } if(convert_version_info_string(&id->version, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->host, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->ssl_version, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->libz_version, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->ares, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->libidn, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; if(convert_version_info_string(&id->libssh_version, &cp, &n, ccsid)) return (curl_version_info_data *) NULL; return id; } const char * curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid) { int i; const char *s; char *buf; s = curl_easy_strerror(error); if(!s) return s; i = MAX_CONV_EXPANSION * (strlen(s) + 1); buf = Curl_thread_buffer(LK_EASY_STRERROR, i); if(!buf) return (const char *) NULL; if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) return (const char *) NULL; return (const char *) buf; } const char * curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid) { int i; const char *s; char *buf; s = curl_share_strerror(error); if(!s) return s; i = MAX_CONV_EXPANSION * (strlen(s) + 1); buf = Curl_thread_buffer(LK_SHARE_STRERROR, i); if(!buf) return (const char *) NULL; if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) return (const char *) NULL; return (const char *) buf; } const char * curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid) { int i; const char *s; char *buf; s = curl_multi_strerror(error); if(!s) return s; i = MAX_CONV_EXPANSION * (strlen(s) + 1); buf = Curl_thread_buffer(LK_MULTI_STRERROR, i); if(!buf) return (const char *) NULL; if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0) return (const char *) NULL; return (const char *) buf; } void curl_certinfo_free_all(struct curl_certinfo *info) { /* Free all memory used by certificate info. */ if(info) { if(info->certinfo) { int i; for(i = 0; i < info->num_of_certs; i++) curl_slist_free_all(info->certinfo[i]); free((char *) info->certinfo); } free((char *) info); } } CURLcode curl_easy_getinfo_ccsid(CURL *curl, CURLINFO info, ...) { va_list arg; void *paramp; CURLcode ret; struct Curl_easy * data; /* WARNING: unlike curl_easy_getinfo(), the strings returned by this procedure have to be free'ed. */ data = (struct Curl_easy *) curl; va_start(arg, info); paramp = va_arg(arg, void *); ret = Curl_getinfo(data, info, paramp); if(ret == CURLE_OK) { unsigned int ccsid; char **cpp; struct curl_slist **slp; struct curl_certinfo *cipf; struct curl_certinfo *cipt; switch((int) info & CURLINFO_TYPEMASK) { case CURLINFO_STRING: ccsid = va_arg(arg, unsigned int); cpp = (char * *) paramp; if(*cpp) { *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID); if(!*cpp) ret = CURLE_OUT_OF_MEMORY; } break; case CURLINFO_SLIST: ccsid = va_arg(arg, unsigned int); switch(info) { case CURLINFO_CERTINFO: cipf = *(struct curl_certinfo * *) paramp; if(cipf) { cipt = (struct curl_certinfo *) malloc(sizeof(*cipt)); if(!cipt) ret = CURLE_OUT_OF_MEMORY; else { cipt->certinfo = (struct curl_slist **) calloc(cipf->num_of_certs + 1, sizeof(struct curl_slist *)); if(!cipt->certinfo) ret = CURLE_OUT_OF_MEMORY; else { int i; cipt->num_of_certs = cipf->num_of_certs; for(i = 0; i < cipf->num_of_certs; i++) if(cipf->certinfo[i]) if(!(cipt->certinfo[i] = slist_convert(ccsid, cipf->certinfo[i], ASCII_CCSID))) { ret = CURLE_OUT_OF_MEMORY; break; } } } if(ret != CURLE_OK) { curl_certinfo_free_all(cipt); cipt = (struct curl_certinfo *) NULL; } *(struct curl_certinfo * *) paramp = cipt; } break; case CURLINFO_TLS_SESSION: case CURLINFO_TLS_SSL_PTR: case CURLINFO_SOCKET: break; default: slp = (struct curl_slist **) paramp; if(*slp) { *slp = slist_convert(ccsid, *slp, ASCII_CCSID); if(!*slp) ret = CURLE_OUT_OF_MEMORY; } break; } } } va_end(arg); return ret; } static int Curl_is_formadd_string(CURLformoption option) { switch(option) { case CURLFORM_FILENAME: case CURLFORM_CONTENTTYPE: case CURLFORM_BUFFER: case CURLFORM_FILE: case CURLFORM_FILECONTENT: case CURLFORM_COPYCONTENTS: case CURLFORM_COPYNAME: return 1; } return 0; } static void Curl_formadd_release_local(struct curl_forms * forms, int nargs, int skip) { while(nargs--) if(nargs != skip) if(Curl_is_formadd_string(forms[nargs].option)) if(forms[nargs].value) free((char *) forms[nargs].value); free((char *) forms); } static int Curl_formadd_convert(struct curl_forms * forms, int formx, int lengthx, unsigned int ccsid) { int l; char *cp; char *cp2; if(formx < 0 || !forms[formx].value) return 0; if(lengthx >= 0) l = (int) forms[lengthx].value; else l = strlen(forms[formx].value) + 1; cp = malloc(MAX_CONV_EXPANSION * l); if(!cp) return -1; l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID, forms[formx].value, l, ccsid); if(l < 0) { free(cp); return -1; } cp2 = realloc(cp, l); /* Shorten buffer to the string size. */ if(cp2) cp = cp2; forms[formx].value = cp; if(lengthx >= 0) forms[lengthx].value = (char *) l; /* Update length after conversion. */ return l; } CURLFORMcode curl_formadd_ccsid(struct curl_httppost * * httppost, struct curl_httppost * * last_post, ...) { va_list arg; CURLformoption option; CURLFORMcode result; struct curl_forms * forms; struct curl_forms * lforms; struct curl_forms * tforms; unsigned int lformlen; const char *value; unsigned int ccsid; int nargs; int namex; int namelengthx; int contentx; int lengthx; unsigned int contentccsid; unsigned int nameccsid; /* A single curl_formadd() call cannot be split in several calls to deal with all parameters: the original parameters are thus copied to a local curl_forms array and converted to ASCII when needed. CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME. CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in parameters is not defined; for this reason, the actual conversion is delayed to the end of parameter processing. The same applies to CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear several times in the parameter list; the problem resides here in knowing which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and when we can be sure to have both info for conversion: end of parameter list is such a point, but CURLFORM_CONTENTTYPE is also used here as a natural separator between content data definitions; this seems to be in accordance with FormAdd() behavior. */ /* Allocate the local curl_forms array. */ lformlen = ALLOC_GRANULE; lforms = malloc(lformlen * sizeof(*lforms)); if(!lforms) return CURL_FORMADD_MEMORY; /* Process the arguments, copying them into local array, latching conversion indexes and converting when needed. */ result = CURL_FORMADD_OK; nargs = 0; contentx = -1; lengthx = -1; namex = -1; namelengthx = -1; forms = (struct curl_forms *) NULL; va_start(arg, last_post); for(;;) { /* Make sure there is still room for an item in local array. */ if(nargs >= lformlen) { lformlen += ALLOC_GRANULE; tforms = realloc(lforms, lformlen * sizeof(*lforms)); if(!tforms) { result = CURL_FORMADD_MEMORY; break; } lforms = tforms; } /* Get next option. */ if(forms) { /* Get option from array. */ option = forms->option; value = forms->value; forms++; } else { /* Get option from arguments. */ option = va_arg(arg, CURLformoption); if(option == CURLFORM_END) break; } /* Dispatch by option. */ switch(option) { case CURLFORM_END: forms = (struct curl_forms *) NULL; /* Leave array mode. */ continue; case CURLFORM_ARRAY: if(!forms) { forms = va_arg(arg, struct curl_forms *); continue; } result = CURL_FORMADD_ILLEGAL_ARRAY; break; case CURLFORM_COPYNAME: option = CURLFORM_PTRNAME; /* Static for now. */ case CURLFORM_PTRNAME: if(namex >= 0) result = CURL_FORMADD_OPTION_TWICE; namex = nargs; if(!forms) { value = va_arg(arg, char *); nameccsid = (unsigned int) va_arg(arg, long); } else { nameccsid = (unsigned int) forms->value; forms++; } break; case CURLFORM_COPYCONTENTS: if(contentx >= 0) result = CURL_FORMADD_OPTION_TWICE; contentx = nargs; if(!forms) { value = va_arg(arg, char *); contentccsid = (unsigned int) va_arg(arg, long); } else { contentccsid = (unsigned int) forms->value; forms++; } break; case CURLFORM_PTRCONTENTS: case CURLFORM_BUFFERPTR: if(!forms) value = va_arg(arg, char *); /* No conversion. */ break; case CURLFORM_CONTENTSLENGTH: lengthx = nargs; if(!forms) value = (char *) va_arg(arg, long); break; case CURLFORM_CONTENTLEN: lengthx = nargs; if(!forms) value = (char *) va_arg(arg, curl_off_t); break; case CURLFORM_NAMELENGTH: namelengthx = nargs; if(!forms) value = (char *) va_arg(arg, long); break; case CURLFORM_BUFFERLENGTH: if(!forms) value = (char *) va_arg(arg, long); break; case CURLFORM_CONTENTHEADER: if(!forms) value = (char *) va_arg(arg, struct curl_slist *); break; case CURLFORM_STREAM: if(!forms) value = (char *) va_arg(arg, void *); break; case CURLFORM_CONTENTTYPE: /* If a previous content has been encountered, convert it now. */ if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) { result = CURL_FORMADD_MEMORY; break; } contentx = -1; lengthx = -1; /* Fall into default. */ default: /* Must be a convertible string. */ if(!Curl_is_formadd_string(option)) { result = CURL_FORMADD_UNKNOWN_OPTION; break; } if(!forms) { value = va_arg(arg, char *); ccsid = (unsigned int) va_arg(arg, long); } else { ccsid = (unsigned int) forms->value; forms++; } /* Do the conversion. */ lforms[nargs].value = value; if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) { result = CURL_FORMADD_MEMORY; break; } value = lforms[nargs].value; } if(result != CURL_FORMADD_OK) break; lforms[nargs].value = value; lforms[nargs++].option = option; } va_end(arg); /* Convert the name and the last content, now that we know their lengths. */ if(result == CURL_FORMADD_OK && namex >= 0) { if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0) result = CURL_FORMADD_MEMORY; else lforms[namex].option = CURLFORM_COPYNAME; /* Force copy. */ } if(result == CURL_FORMADD_OK) { if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) result = CURL_FORMADD_MEMORY; else contentx = -1; } /* Do the formadd with our converted parameters. */ if(result == CURL_FORMADD_OK) { lforms[nargs].option = CURLFORM_END; result = curl_formadd(httppost, last_post, CURLFORM_ARRAY, lforms, CURLFORM_END); } /* Terminate. */ Curl_formadd_release_local(lforms, nargs, contentx); return result; } typedef struct { curl_formget_callback append; void * arg; unsigned int ccsid; } cfcdata; static size_t Curl_formget_callback_ccsid(void *arg, const char *buf, size_t len) { cfcdata * p; char *b; int l; size_t ret; p = (cfcdata *) arg; if((long) len <= 0) return (*p->append)(p->arg, buf, len); b = malloc(MAX_CONV_EXPANSION * len); if(!b) return (size_t) -1; l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID); if(l < 0) { free(b); return (size_t) -1; } ret = (*p->append)(p->arg, b, l); free(b); return ret == l? len: -1; } int curl_formget_ccsid(struct curl_httppost *form, void *arg, curl_formget_callback append, unsigned int ccsid) { cfcdata lcfc; lcfc.append = append; lcfc.arg = arg; lcfc.ccsid = ccsid; return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid); } CURLcode curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...) { CURLcode result; va_list arg; struct Curl_easy *data; char *s; char *cp; unsigned int ccsid; curl_off_t pfsize; data = (struct Curl_easy *) curl; va_start(arg, tag); switch(tag) { case CURLOPT_ABSTRACT_UNIX_SOCKET: case CURLOPT_ALTSVC: case CURLOPT_CAINFO: case CURLOPT_CAPATH: case CURLOPT_COOKIE: case CURLOPT_COOKIEFILE: case CURLOPT_COOKIEJAR: case CURLOPT_COOKIELIST: case CURLOPT_CRLFILE: case CURLOPT_CUSTOMREQUEST: case CURLOPT_DEFAULT_PROTOCOL: case CURLOPT_DNS_SERVERS: case CURLOPT_DOH_URL: case CURLOPT_EGDSOCKET: case CURLOPT_ENCODING: case CURLOPT_FTPPORT: case CURLOPT_FTP_ACCOUNT: case CURLOPT_FTP_ALTERNATIVE_TO_USER: case CURLOPT_INTERFACE: case CURLOPT_ISSUERCERT: case CURLOPT_KEYPASSWD: case CURLOPT_KRBLEVEL: case CURLOPT_LOGIN_OPTIONS: case CURLOPT_MAIL_AUTH: case CURLOPT_MAIL_FROM: case CURLOPT_NETRC_FILE: case CURLOPT_NOPROXY: case CURLOPT_PASSWORD: case CURLOPT_PINNEDPUBLICKEY: case CURLOPT_PRE_PROXY: case CURLOPT_PROXY: case CURLOPT_PROXYPASSWORD: case CURLOPT_PROXYUSERNAME: case CURLOPT_PROXYUSERPWD: case CURLOPT_PROXY_CAINFO: case CURLOPT_PROXY_CAPATH: case CURLOPT_PROXY_CRLFILE: case CURLOPT_PROXY_KEYPASSWD: case CURLOPT_PROXY_PINNEDPUBLICKEY: case CURLOPT_PROXY_SERVICE_NAME: case CURLOPT_PROXY_SSLCERT: case CURLOPT_PROXY_SSLCERTTYPE: case CURLOPT_PROXY_SSLKEY: case CURLOPT_PROXY_SSLKEYTYPE: case CURLOPT_PROXY_SSL_CIPHER_LIST: case CURLOPT_PROXY_TLS13_CIPHERS: case CURLOPT_PROXY_TLSAUTH_PASSWORD: case CURLOPT_PROXY_TLSAUTH_TYPE: case CURLOPT_PROXY_TLSAUTH_USERNAME: case CURLOPT_RANDOM_FILE: case CURLOPT_RANGE: case CURLOPT_REFERER: case CURLOPT_REQUEST_TARGET: case CURLOPT_RTSP_SESSION_ID: case CURLOPT_RTSP_STREAM_URI: case CURLOPT_RTSP_TRANSPORT: case CURLOPT_SASL_AUTHZID: case CURLOPT_SERVICE_NAME: case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: case CURLOPT_SSH_KNOWNHOSTS: case CURLOPT_SSH_PRIVATE_KEYFILE: case CURLOPT_SSH_PUBLIC_KEYFILE: case CURLOPT_SSLCERT: case CURLOPT_SSLCERTTYPE: case CURLOPT_SSLENGINE: case CURLOPT_SSLKEY: case CURLOPT_SSLKEYTYPE: case CURLOPT_SSL_CIPHER_LIST: case CURLOPT_TLS13_CIPHERS: case CURLOPT_TLSAUTH_PASSWORD: case CURLOPT_TLSAUTH_TYPE: case CURLOPT_TLSAUTH_USERNAME: case CURLOPT_UNIX_SOCKET_PATH: case CURLOPT_URL: case CURLOPT_USERAGENT: case CURLOPT_USERNAME: case CURLOPT_USERPWD: case CURLOPT_XOAUTH2_BEARER: s = va_arg(arg, char *); ccsid = va_arg(arg, unsigned int); if(s) { s = dynconvert(ASCII_CCSID, s, -1, ccsid); if(!s) { result = CURLE_OUT_OF_MEMORY; break; } } result = curl_easy_setopt(curl, tag, s); free(s); break; case CURLOPT_COPYPOSTFIELDS: /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE prior to this call. In this case, convert the given byte count and replace the length according to the conversion result. */ s = va_arg(arg, char *); ccsid = va_arg(arg, unsigned int); pfsize = data->set.postfieldsize; if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) { result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s); break; } if(pfsize == -1) { /* Data is null-terminated. */ s = dynconvert(ASCII_CCSID, s, -1, ccsid); if(!s) { result = CURLE_OUT_OF_MEMORY; break; } } else { /* Data length specified. */ size_t len; if(pfsize < 0 || pfsize > SIZE_MAX) { result = CURLE_OUT_OF_MEMORY; break; } len = pfsize; pfsize = len * MAX_CONV_EXPANSION; if(pfsize > SIZE_MAX) pfsize = SIZE_MAX; cp = malloc(pfsize); if(!cp) { result = CURLE_OUT_OF_MEMORY; break; } pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid); if(pfsize < 0) { free(cp); result = CURLE_OUT_OF_MEMORY; break; } data->set.postfieldsize = pfsize; /* Replace data size. */ s = cp; } result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s); data->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */ break; case CURLOPT_ERRORBUFFER: /* This is an output buffer. */ default: result = Curl_vsetopt(curl, tag, arg); break; } va_end(arg); return result; } char * curl_form_long_value(long value) { /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */ return (char *) value; } char * curl_pushheader_bynum_cssid(struct curl_pushheaders *h, size_t num, unsigned int ccsid) { char *d = (char *) NULL; char *s = curl_pushheader_bynum(h, num); if(s) d = dynconvert(ccsid, s, -1, ASCII_CCSID); return d; } char * curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header, unsigned int ccsidin, unsigned int ccsidout) { char *d = (char *) NULL; if(header) { header = dynconvert(ASCII_CCSID, header, -1, ccsidin); if(header) { char *s = curl_pushheader_byname(h, header); free((char *) header); if(s) d = dynconvert(ccsidout, s, -1, ASCII_CCSID); } } return d; } static CURLcode mime_string_call(curl_mimepart *part, const char *string, unsigned int ccsid, CURLcode (*mimefunc)(curl_mimepart *part, const char *string)) { char *s = (char *) NULL; CURLcode result; if(!string) return mimefunc(part, string); s = dynconvert(ASCII_CCSID, string, -1, ccsid); if(!s) return CURLE_OUT_OF_MEMORY; result = mimefunc(part, s); free(s); return result; } CURLcode curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid) { return mime_string_call(part, name, ccsid, curl_mime_name); } CURLcode curl_mime_filename_ccsid(curl_mimepart *part, const char *filename, unsigned int ccsid) { return mime_string_call(part, filename, ccsid, curl_mime_filename); } CURLcode curl_mime_type_ccsid(curl_mimepart *part, const char *mimetype, unsigned int ccsid) { return mime_string_call(part, mimetype, ccsid, curl_mime_type); } CURLcode curl_mime_encoder_ccsid(curl_mimepart *part, const char *encoding, unsigned int ccsid) { return mime_string_call(part, encoding, ccsid, curl_mime_encoder); } CURLcode curl_mime_filedata_ccsid(curl_mimepart *part, const char *filename, unsigned int ccsid) { return mime_string_call(part, filename, ccsid, curl_mime_filedata); } CURLcode curl_mime_data_ccsid(curl_mimepart *part, const char *data, size_t datasize, unsigned int ccsid) { char *s = (char *) NULL; CURLcode result; if(!data) return curl_mime_data(part, data, datasize); s = dynconvert(ASCII_CCSID, data, datasize, ccsid); if(!s) return CURLE_OUT_OF_MEMORY; result = curl_mime_data(part, s, datasize); free(s); return result; } CURLUcode curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part, unsigned int flags, unsigned int ccsid) { char *s = (char *)NULL; CURLUcode result; if(!part) return CURLUE_BAD_PARTPOINTER; *part = (char *)NULL; result = curl_url_get(handle, what, &s, flags); if(result == CURLUE_OK) { if(s) { *part = dynconvert(ccsid, s, -1, ASCII_CCSID); if(!*part) result = CURLUE_OUT_OF_MEMORY; } } if(s) free(s); return result; } CURLUcode curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part, unsigned int flags, unsigned int ccsid) { char *s = (char *)NULL; CURLUcode result; if(part) { s = dynconvert(ASCII_CCSID, part, -1, ccsid); if(!s) return CURLUE_OUT_OF_MEMORY; } result = curl_url_set(handle, what, s, flags); if(s) free(s); return result; } davix-0.8.0/deps/curl/packages/OS400/make-src.sh0000644000000000000000000000006514121063461017610 0ustar rootroot#!/bin/sh # # # Not implemented yet on OS/400. davix-0.8.0/deps/curl/packages/OS400/ccsidcurl.h0000644000000000000000000001245514121063461017704 0ustar rootroot#ifndef CURLINC_CCSIDCURL_H #define CURLINC_CCSIDCURL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * ***************************************************************************/ #include "curl.h" #include "easy.h" #include "multi.h" CURL_EXTERN char * curl_version_ccsid(unsigned int ccsid); CURL_EXTERN char * curl_easy_escape_ccsid(CURL * handle, const char * string, int length, unsigned int sccsid, unsigned int dccsid); CURL_EXTERN char * curl_easy_unescape_ccsid(CURL * handle, const char * string, int length, int * outlength, unsigned int sccsid, unsigned int dccsid); CURL_EXTERN struct curl_slist * curl_slist_append_ccsid(struct curl_slist * l, const char * data, unsigned int ccsid); CURL_EXTERN time_t curl_getdate_ccsid(const char * p, const time_t * unused, unsigned int ccsid); CURL_EXTERN curl_version_info_data * curl_version_info_ccsid(CURLversion stamp, unsigned int cid); CURL_EXTERN const char * curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid); CURL_EXTERN const char * curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid); CURL_EXTERN const char * curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid); CURL_EXTERN CURLcode curl_easy_getinfo_ccsid(CURL * curl, CURLINFO info, ...); CURL_EXTERN CURLFORMcode curl_formadd_ccsid(struct curl_httppost * * httppost, struct curl_httppost * * last_post, ...); CURL_EXTERN char * curl_form_long_value(long value); CURL_EXTERN int curl_formget_ccsid(struct curl_httppost * form, void * arg, curl_formget_callback append, unsigned int ccsid); CURL_EXTERN CURLcode curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...); CURL_EXTERN void curl_certinfo_free_all(struct curl_certinfo *info); CURL_EXTERN char *curl_pushheader_bynum_cssid(struct curl_pushheaders *h, size_t num, unsigned int ccsid); CURL_EXTERN char *curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header, unsigned int ccsidin, unsigned int ccsidout); CURL_EXTERN CURLcode curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid); CURL_EXTERN CURLcode curl_mime_filename_ccsid(curl_mimepart *part, const char *filename, unsigned int ccsid); CURL_EXTERN CURLcode curl_mime_type_ccsid(curl_mimepart *part, const char *mimetype, unsigned int ccsid); CURL_EXTERN CURLcode curl_mime_encoder_ccsid(curl_mimepart *part, const char *encoding, unsigned int ccsid); CURL_EXTERN CURLcode curl_mime_filedata_ccsid(curl_mimepart *part, const char *filename, unsigned int ccsid); CURL_EXTERN CURLcode curl_mime_data_ccsid(curl_mimepart *part, const char *data, size_t datasize, unsigned int ccsid); CURL_EXTERN CURLUcode curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part, unsigned int flags, unsigned int ccsid); CURL_EXTERN CURLUcode curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part, unsigned int flags, unsigned int ccsid); #endif davix-0.8.0/deps/curl/packages/OS400/initscript.sh0000644000000000000000000002142514121063461020301 0ustar rootroot#!/bin/sh setenv() { # Define and export. eval ${1}="${2}" export ${1} } case "${SCRIPTDIR}" in /*) ;; *) SCRIPTDIR="`pwd`/${SCRIPTDIR}" esac while true do case "${SCRIPTDIR}" in */.) SCRIPTDIR="${SCRIPTDIR%/.}";; *) break;; esac done # The script directory is supposed to be in $TOPDIR/packages/os400. TOPDIR=`dirname "${SCRIPTDIR}"` TOPDIR=`dirname "${TOPDIR}"` export SCRIPTDIR TOPDIR # Extract the SONAME from the library makefile. SONAME=`sed -e '/^VERSIONINFO=/!d' -e 's/^.* \([0-9]*\):.*$/\1/' -e 'q' \ < "${TOPDIR}/lib/Makefile.am"` export SONAME ################################################################################ # # Tunable configuration parameters. # ################################################################################ setenv TARGETLIB 'CURL' # Target OS/400 program library. setenv STATBNDDIR 'CURL_A' # Static binding directory. setenv DYNBNDDIR 'CURL' # Dynamic binding directory. setenv SRVPGM "CURL.${SONAME}" # Service program. setenv TGTCCSID '500' # Target CCSID of objects. setenv DEBUG '*ALL' # Debug level. setenv OPTIMIZE '10' # Optimisation level setenv OUTPUT '*NONE' # Compilation output option. setenv TGTRLS 'V6R1M0' # Target OS release. setenv IFSDIR '/curl' # Installation IFS directory. # Define ZLIB availability and locations. setenv WITH_ZLIB 0 # Define to 1 to enable. setenv ZLIB_INCLUDE '/zlib/include' # ZLIB include IFS directory. setenv ZLIB_LIB 'ZLIB' # ZLIB library. setenv ZLIB_BNDDIR 'ZLIB_A' # ZLIB binding directory. # Define LIBSSH2 availability and locations. setenv WITH_LIBSSH2 0 # Define to 1 to enable. setenv LIBSSH2_INCLUDE '/libssh2/include' # LIBSSH2 include IFS directory. setenv LIBSSH2_LIB 'LIBSSH2' # LIBSSH2 library. setenv LIBSSH2_BNDDIR 'LIBSSH2_A' # LIBSSH2 binding directory. ################################################################################ # Need to get the version definitions. LIBCURL_VERSION=`grep '^#define *LIBCURL_VERSION ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/.*"\(.*\)".*/\1/'` LIBCURL_VERSION_MAJOR=`grep '^#define *LIBCURL_VERSION_MAJOR ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/^#define *LIBCURL_VERSION_MAJOR *\([^ ]*\).*/\1/'` LIBCURL_VERSION_MINOR=`grep '^#define *LIBCURL_VERSION_MINOR ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/^#define *LIBCURL_VERSION_MINOR *\([^ ]*\).*/\1/'` LIBCURL_VERSION_PATCH=`grep '^#define *LIBCURL_VERSION_PATCH ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/^#define *LIBCURL_VERSION_PATCH *\([^ ]*\).*/\1/'` LIBCURL_VERSION_NUM=`grep '^#define *LIBCURL_VERSION_NUM ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/^#define *LIBCURL_VERSION_NUM *0x\([^ ]*\).*/\1/'` LIBCURL_TIMESTAMP=`grep '^#define *LIBCURL_TIMESTAMP ' \ "${TOPDIR}/include/curl/curlver.h" | sed 's/.*"\(.*\)".*/\1/'` export LIBCURL_VERSION export LIBCURL_VERSION_MAJOR LIBCURL_VERSION_MINOR LIBCURL_VERSION_PATCH export LIBCURL_VERSION_NUM LIBCURL_TIMESTAMP ################################################################################ # # OS/400 specific definitions. # ################################################################################ LIBIFSNAME="/QSYS.LIB/${TARGETLIB}.LIB" ################################################################################ # # Procedures. # ################################################################################ # action_needed dest [src] # # dest is an object to build # if specified, src is an object on which dest depends. # # exit 0 (succeeds) if some action has to be taken, else 1. action_needed() { [ ! -e "${1}" ] && return 0 [ "${2}" ] || return 1 [ "${1}" -ot "${2}" ] && return 0 return 1 } # canonicalize_path path # # Return canonicalized path as: # - Absolute # - No . or .. component. canonicalize_path() { if expr "${1}" : '^/' > /dev/null then P="${1}" else P="`pwd`/${1}" fi R= IFSSAVE="${IFS}" IFS="/" for C in ${P} do IFS="${IFSSAVE}" case "${C}" in .) ;; ..) R=`expr "${R}" : '^\(.*/\)..*'` ;; ?*) R="${R}${C}/" ;; *) ;; esac done IFS="${IFSSAVE}" echo "/`expr "${R}" : '^\(.*\)/'`" } # make_module module_name source_name [additional_definitions] # # Compile source name into ASCII module if needed. # As side effect, append the module name to variable MODULES. # Set LINK to "YES" if the module has been compiled. make_module() { MODULES="${MODULES} ${1}" MODIFSNAME="${LIBIFSNAME}/${1}.MODULE" action_needed "${MODIFSNAME}" "${2}" || return 0; SRCDIR=`dirname \`canonicalize_path "${2}"\`` # #pragma convert has to be in the source file itself, i.e. # putting it in an include file makes it only active # for that include file. # Thus we build a temporary file with the pragma prepended to # the source file and we compile that themporary file. echo "#line 1 \"${2}\"" > __tmpsrcf.c echo "#pragma convert(819)" >> __tmpsrcf.c echo "#line 1" >> __tmpsrcf.c cat "${2}" >> __tmpsrcf.c CMD="CRTCMOD MODULE(${TARGETLIB}/${1}) SRCSTMF('__tmpsrcf.c')" # CMD="${CMD} SYSIFCOPT(*IFS64IO) OPTION(*INCDIRFIRST *SHOWINC *SHOWSYS)" CMD="${CMD} SYSIFCOPT(*IFS64IO) OPTION(*INCDIRFIRST)" CMD="${CMD} LOCALETYPE(*LOCALE) FLAG(10)" CMD="${CMD} INCDIR('/qibm/proddata/qadrt/include'" CMD="${CMD} '${TOPDIR}/include/curl' '${TOPDIR}/include' '${SRCDIR}'" CMD="${CMD} '${TOPDIR}/packages/OS400'" if [ "${WITH_ZLIB}" != "0" ] then CMD="${CMD} '${ZLIB_INCLUDE}'" fi if [ "${WITH_LIBSSH2}" != "0" ] then CMD="${CMD} '${LIBSSH2_INCLUDE}'" fi CMD="${CMD} ${INCLUDES})" CMD="${CMD} TGTCCSID(${TGTCCSID}) TGTRLS(${TGTRLS})" CMD="${CMD} OUTPUT(${OUTPUT})" CMD="${CMD} OPTIMIZE(${OPTIMIZE})" CMD="${CMD} DBGVIEW(${DEBUG})" DEFINES="${3} BUILDING_LIBCURL" if [ "${WITH_ZLIB}" != "0" ] then DEFINES="${DEFINES} HAVE_LIBZ HAVE_ZLIB_H" fi if [ "${WITH_LIBSSH2}" != "0" ] then DEFINES="${DEFINES} USE_LIBSSH2 HAVE_LIBSSH2_H" fi if [ "${DEFINES}" ] then CMD="${CMD} DEFINE(${DEFINES})" fi system "${CMD}" rm -f __tmpsrcf.c LINK=YES } # Determine DB2 object name from IFS name. db2_name() { if [ "${2}" = 'nomangle' ] then basename "${1}" | tr 'a-z-' 'A-Z_' | sed -e 's/\..*//' \ -e 's/^\(.\).*\(.........\)$/\1\2/' else basename "${1}" | tr 'a-z-' 'A-Z_' | sed -e 's/\..*//' \ -e 's/^CURL_*/C/' \ -e 's/^\(.\).*\(.........\)$/\1\2/' fi } # Copy IFS file replacing version info. versioned_copy() { sed -e "s/@LIBCURL_VERSION@/${LIBCURL_VERSION}/g" \ -e "s/@LIBCURL_VERSION_MAJOR@/${LIBCURL_VERSION_MAJOR}/g" \ -e "s/@LIBCURL_VERSION_MINOR@/${LIBCURL_VERSION_MINOR}/g" \ -e "s/@LIBCURL_VERSION_PATCH@/${LIBCURL_VERSION_PATCH}/g" \ -e "s/@LIBCURL_VERSION_NUM@/${LIBCURL_VERSION_NUM}/g" \ -e "s/@LIBCURL_TIMESTAMP@/${LIBCURL_TIMESTAMP}/g" \ < "${1}" > "${2}" } davix-0.8.0/deps/curl/packages/OS400/os400sys.h0000644000000000000000000000324314121063461017330 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * ***************************************************************************/ /* OS/400 additional definitions. */ #ifndef __OS400_SYS_ #define __OS400_SYS_ /* Per-thread item identifiers. */ typedef enum { LK_SSL_ERROR, LK_GSK_ERROR, LK_LDAP_ERROR, LK_CURL_VERSION, LK_VERSION_INFO, LK_VERSION_INFO_DATA, LK_EASY_STRERROR, LK_SHARE_STRERROR, LK_MULTI_STRERROR, LK_ZLIB_VERSION, LK_ZLIB_MSG, LK_LAST } localkey_t; extern char * (* Curl_thread_buffer)(localkey_t key, long size); /* Maximum string expansion factor due to character code conversion. */ #define MAX_CONV_EXPANSION 4 /* Can deal with UTF-8. */ #endif davix-0.8.0/deps/curl/packages/Symbian/0000755000000000000000000000000014121063461016406 5ustar rootrootdavix-0.8.0/deps/curl/packages/Symbian/eabi/0000755000000000000000000000000014121063461017306 5ustar rootrootdavix-0.8.0/deps/curl/packages/Symbian/eabi/libcurlu.def0000644000000000000000000000333714121063461021615 0ustar rootrootEXPORTS curl_easy_cleanup @ 1 NONAME curl_easy_duphandle @ 2 NONAME curl_easy_escape @ 3 NONAME curl_easy_getinfo @ 4 NONAME curl_easy_init @ 5 NONAME curl_easy_pause @ 6 NONAME curl_easy_perform @ 7 NONAME curl_easy_reset @ 8 NONAME curl_easy_setopt @ 9 NONAME curl_easy_strerror @ 10 NONAME curl_easy_unescape @ 11 NONAME curl_escape @ 12 NONAME curl_formadd @ 13 NONAME curl_formfree @ 14 NONAME curl_formget @ 15 NONAME curl_free @ 16 NONAME curl_getdate @ 17 NONAME curl_getenv @ 18 NONAME curl_global_cleanup @ 19 NONAME curl_global_init @ 20 NONAME curl_global_init_mem @ 21 NONAME curl_maprintf @ 22 NONAME curl_mfprintf @ 23 NONAME curl_mprintf @ 24 NONAME curl_msnprintf @ 25 NONAME curl_msprintf @ 26 NONAME curl_multi_add_handle @ 27 NONAME curl_multi_assign @ 28 NONAME curl_multi_cleanup @ 29 NONAME curl_multi_fdset @ 30 NONAME curl_multi_info_read @ 31 NONAME curl_multi_init @ 32 NONAME curl_multi_perform @ 33 NONAME curl_multi_remove_handle @ 34 NONAME curl_multi_setopt @ 35 NONAME curl_multi_socket @ 36 NONAME curl_multi_socket_action @ 37 NONAME curl_multi_socket_all @ 38 NONAME curl_multi_strerror @ 39 NONAME curl_multi_timeout @ 40 NONAME curl_mvaprintf @ 41 NONAME curl_mvfprintf @ 42 NONAME curl_mvprintf @ 43 NONAME curl_mvsnprintf @ 44 NONAME curl_mvsprintf @ 45 NONAME curl_share_cleanup @ 46 NONAME curl_share_init @ 47 NONAME curl_share_setopt @ 48 NONAME curl_share_strerror @ 49 NONAME curl_slist_append @ 50 NONAME curl_slist_free_all @ 51 NONAME curl_strequal @ 52 NONAME curl_strnequal @ 53 NONAME curl_unescape @ 54 NONAME curl_version @ 55 NONAME curl_version_info @ 56 NONAME curl_easy_recv @ 57 NONAME curl_easy_send @ 58 NONAME curl_multi_wait @ 59 NONAME davix-0.8.0/deps/curl/packages/Symbian/readme.txt0000644000000000000000000000751314121063461020412 0ustar rootrootCurl on Symbian OS ================== This is a basic port of curl and libcurl to Symbian OS. The port is a straightforward one using Symbian's P.I.P.S. POSIX compatibility layer, which was first available for OS version 9.1. A more complete port would involve writing a Symbian C++ binding, or wrapping libcurl as a Symbian application server with a C++ API to handle requests from client applications as well as creating a GUI application to allow file transfers. The author has no current plans to do so. This means that integration with standard Symbian OS programs can be tricky, since libcurl isn't designed with Symbian's native asynchronous message passing idioms in mind. However, it may be possible to use libcurl in an active object-based application through libcurl's multi interface. The port is most easily used when porting POSIX applications to Symbian OS using P.I.P.S. (a.k.a. Open C). libcurl is built as a standard Symbian ordinal-linked DLL, and curl is built as a text mode EXE application. They have not been Symbian Signed, which is required in order to install them on most phones. Following are some things to keep in mind when using this port. curl notes ---------- When starting curl in the Windows emulator from the Windows command-line, place a double-dash -- before the first curl command-line option. e.g. \epoc32\release\winscw\udeb\curl -- -v http://localhost/ Failure to do so may mean that some of your options won't be correctly processed. Symbian's ESHELL allows for redirecting stdin and stdout to files, but stderr goes to the epocwind.out file (on the emulator). The standard curl options -o, --stderr and --trace-ascii can be used to redirect output to a file (or stdout) instead. P.I.P.S. doesn't inherit the current working directory at startup from the shell, so relative path names are always relative to C:\Private\f0206442\. P.I.P.S. provides no way to disable echoing of characters as they are entered, so passwords typed in on the console will be visible. It also line buffers keyboard input so interactive telnet sessions are not very feasible. All screen output disappears after curl exits, so after a command completes, curl waits by default for Enter to be pressed before exiting. This behaviour is suppressed when the -s option is given. curl's "home directory" in Symbian is C:\Private\f0206442\. The .curlrc file is read from this directory on startup. libcurl notes ------------- libcurl uses writable static data, so the EPOCALLOWDLLDATA option is used in its MMP file, with the corresponding additional memory usage and limitations on the Windows emulator. curl_global_init() *must* be called (either explicitly or implicitly through calling certain other libcurl functions) before any libcurl functions that could allocate memory (like curl_getenv()). P.I.P.S. doesn't support signals or the alarm() call, so some timeouts (such as the connect timeout) are not honoured. This should not be an issue once support for CURLRES_THREADED is added for Symbian. P.I.P.S. causes a USER:87 panic if certain timeouts much longer than half an hour are selected. LDAP, SCP or SFTP methods are not supported due to lack of support for the dependent libraries on Symbian. gzip and deflate decompression is supported when the appropriate macro is uncommented in the libcurl.mmp file. SSL/TLS encryption is not enabled by default, but it is possible to add when the OpenSSL libraries included in the S60 Open C SDK are available. The appropriate macro in the libcurl.mmp file must be uncommented to enable support. NTLM authentication may not work on some servers due to the lack of MD4 support in the OpenSSL libraries included with Open C. Debug builds are not supported (i.e. --enable-debug) because they cause additional symbol exports in the library which are not frozen in the .def files. Dan Fandrich dan@coneharvesters.com March 2010 davix-0.8.0/deps/curl/packages/Symbian/bwins/0000755000000000000000000000000014121063461017530 5ustar rootrootdavix-0.8.0/deps/curl/packages/Symbian/bwins/libcurlu.def0000644000000000000000000000333714121063461022037 0ustar rootrootEXPORTS curl_easy_cleanup @ 1 NONAME curl_easy_duphandle @ 2 NONAME curl_easy_escape @ 3 NONAME curl_easy_getinfo @ 4 NONAME curl_easy_init @ 5 NONAME curl_easy_pause @ 6 NONAME curl_easy_perform @ 7 NONAME curl_easy_reset @ 8 NONAME curl_easy_setopt @ 9 NONAME curl_easy_strerror @ 10 NONAME curl_easy_unescape @ 11 NONAME curl_escape @ 12 NONAME curl_formadd @ 13 NONAME curl_formfree @ 14 NONAME curl_formget @ 15 NONAME curl_free @ 16 NONAME curl_getdate @ 17 NONAME curl_getenv @ 18 NONAME curl_global_cleanup @ 19 NONAME curl_global_init @ 20 NONAME curl_global_init_mem @ 21 NONAME curl_maprintf @ 22 NONAME curl_mfprintf @ 23 NONAME curl_mprintf @ 24 NONAME curl_msnprintf @ 25 NONAME curl_msprintf @ 26 NONAME curl_multi_add_handle @ 27 NONAME curl_multi_assign @ 28 NONAME curl_multi_cleanup @ 29 NONAME curl_multi_fdset @ 30 NONAME curl_multi_info_read @ 31 NONAME curl_multi_init @ 32 NONAME curl_multi_perform @ 33 NONAME curl_multi_remove_handle @ 34 NONAME curl_multi_setopt @ 35 NONAME curl_multi_socket @ 36 NONAME curl_multi_socket_action @ 37 NONAME curl_multi_socket_all @ 38 NONAME curl_multi_strerror @ 39 NONAME curl_multi_timeout @ 40 NONAME curl_mvaprintf @ 41 NONAME curl_mvfprintf @ 42 NONAME curl_mvprintf @ 43 NONAME curl_mvsnprintf @ 44 NONAME curl_mvsprintf @ 45 NONAME curl_share_cleanup @ 46 NONAME curl_share_init @ 47 NONAME curl_share_setopt @ 48 NONAME curl_share_strerror @ 49 NONAME curl_slist_append @ 50 NONAME curl_slist_free_all @ 51 NONAME curl_strequal @ 52 NONAME curl_strnequal @ 53 NONAME curl_unescape @ 54 NONAME curl_version @ 55 NONAME curl_version_info @ 56 NONAME curl_easy_recv @ 57 NONAME curl_easy_send @ 58 NONAME curl_multi_wait @ 59 NONAME davix-0.8.0/deps/curl/packages/Symbian/group/0000755000000000000000000000000014121063461017542 5ustar rootrootdavix-0.8.0/deps/curl/packages/Symbian/group/libcurl.mmp0000644000000000000000000000505314121063461021714 0ustar rootroot// // libcurl.dll curl network retrieval client library // // Build-time options (uncomment these to enable) #define ENABLE_ZLIB // Enable gzip/deflate decompression //#define ENABLE_SSL // Enable SSL for HTTPS/FTPS (requires S60 Open C SDK) TARGET libcurl.dll TARGETTYPE dll UID 0x1000008d 0xF0206D00 MACRO BUILDING_LIBCURL #ifdef ENABLE_ZLIB MACRO HAVE_LIBZ #endif #ifdef ENABLE_SSL MACRO USE_OPENSSL #endif SOURCEPATH ../../../lib SOURCE \ file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c vtls/openssl.c version.c getenv.c escape.c mprintf.c telnet.c \ netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \ curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \ http_negotiate.c inet_pton.c strtoofft.c strerror.c amigaos.c \ hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c \ select.c vtls/gtls.c vtls/vtls.c tftp.c splay.c strdup.c socks.c \ ssh.c vtls/nss.c strcase.c curl_addrinfo.c socks_gssapi.c \ socks_sspi.c curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c \ pop3.c smtp.c pingpong.c rtsp.c curl_threads.c warnless.c hmac.c \ vtls/polarssl.c curl_rtmp.c openldap.c curl_gethostname.c gopher.c \ idn_win32.c vtls/cyassl.c http_proxy.c non-ascii.c \ asyn-ares.c asyn-thread.c curl_gssapi.c http_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_sasl.c vtls/schannel.c curl_multibyte.c \ vtls/darwinssl.c conncache.c curl_sasl_sspi.c smb.c curl_endian.c \ curl_des.c curl_range.c system_win32.c sha256.c \ vauth/vauth.c vauth/cleartext.c vauth/cram.c vauth/digest.c \ vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c \ vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c \ vauth/spnego_sspi.c USERINCLUDE ../../../lib ../../../include/curl #ifdef ENABLE_SSL SYSTEMINCLUDE /epoc32/include/osextensions/stdapis // Older versions of the SDK need this instead: //USERINCLUDE /epoc32/include/stdapis/openssl #endif SYSTEMINCLUDE ../../../include /epoc32/include/stdapis /epoc32/include LIBRARY euser.lib libc.lib #ifdef ENABLE_ZLIB LIBRARY ezlib.lib #endif #ifdef ENABLE_SSL LIBRARY libssl.lib libcrypto.lib #endif CAPABILITY NetworkServices EPOCALLOWDLLDATA davix-0.8.0/deps/curl/packages/Symbian/group/curl.mmp0000644000000000000000000000233014121063461021220 0ustar rootroot// // curl network retrieval client // TARGET curl.exe TARGETTYPE exe UID 0x00000000 0xF0206442 SOURCEPATH ../../../src SOURCE \ tool_binmode.c \ tool_bname.c \ tool_cb_dbg.c \ tool_cb_hdr.c \ tool_cb_prg.c \ tool_cb_rea.c \ tool_cb_see.c \ tool_cb_wrt.c \ tool_cfgable.c \ tool_convert.c \ tool_dirhie.c \ tool_doswin.c \ tool_easysrc.c \ tool_formparse.c \ tool_getparam.c \ tool_getpass.c \ tool_help.c \ tool_helpers.c \ tool_homedir.c \ tool_hugehelp.c \ tool_libinfo.c \ tool_main.c \ tool_metalink.c \ tool_mfiles.c \ tool_msgs.c \ tool_operate.c \ tool_operhlp.c \ tool_panykey.c \ tool_paramhlp.c \ tool_parsecfg.c \ tool_setopt.c \ tool_sleep.c \ tool_urlglob.c \ tool_util.c \ tool_vms.c \ tool_writeenv.c \ tool_writeout.c \ tool_xattr.c SOURCEPATH ../../../lib SOURCE \ strcase.c nonblock.c USERINCLUDE ../../../src ../../../lib ../../../include/curl SYSTEMINCLUDE ../../../include /epoc32/include /epoc32/include/stdapis LIBRARY euser.lib libc.lib libcurl.lib STATICLIBRARY libcrt0.lib CAPABILITY NetworkServices EPOCSTACKSIZE 0x8000 davix-0.8.0/deps/curl/packages/Symbian/group/curl.iby0000644000000000000000000000043314121063461021214 0ustar rootroot// // curl file transfer utility command-line utility // // Use this file with buildrom to add curl to a device ROM // #ifndef CURL_IBY #define CURL_IBY #include #include file=ABI_DIR\BUILD_DIR\curl.exe \sys\bin\curl.exe #endif // CURL_IBY davix-0.8.0/deps/curl/packages/Symbian/group/libcurl.pkg0000644000000000000000000000137514121063461021707 0ustar rootroot; libcurl package definition file ; Use with makesis to create a Symbian .sis package ;Language - standard language definitions &EN ;Header - standard sis file header including version number ;Version scheme: curl's major, curl's minor, curl's subminor*100 + build number ; e.g. The third Symbian package of curl ver. 7.20.1 would have a SIS package ; version of 7, 20, 103 #{"libcurl"}, (0xF0206D00), 7, 20, , TYPE=SA ; Vendor name %{"curl project"} :"curl project" ; A dependency on P.I.P.S. is probably a good idea to add here ;(0x20009A80), *, *, *, {"Open C Standard Libraries"} ;(0x20009A81), *, *, *, {"P.I.P.S. for UIQ 3"} ;Files - standard file specifications "\epoc32\release\armv5\urel\libcurl.dll" - "$:\sys\bin\libcurl.dll" davix-0.8.0/deps/curl/packages/Symbian/group/curl.pkg0000644000000000000000000000154614121063461021220 0ustar rootroot; curl package definition file ; Use with makesis to create a Symbian .sis package ;Language - standard language definitions &EN ;Header - standard sis file header including version number ;Version scheme: curl's major, curl's minor, curl's subminor*100 + build number ; e.g. The third Symbian package of curl ver. 7.20.1 would have a SIS package ; version of 7, 20, 103 #{"curl"}, (0xF0206442), 7, 20, , TYPE=SA ; Vendor name %{"curl project"} :"curl project" ; Embedded component @"libcurl.sis",(0xF0206D00) ; A dependency on P.I.P.S. and the stdio server are probably good to have here ;(0x20009A80), *, *, *, {"Open C Standard Libraries"} ;(0x20009A81), *, *, *, {"P.I.P.S. for UIQ 3"} ;(0x20009AA2), *, *, *, {"Symbian OS STDIOSERVER"} ;Files - standard file specifications "\epoc32\release\armv5\urel\curl.exe" - "$:\sys\bin\curl.exe" davix-0.8.0/deps/curl/packages/Symbian/group/bld.inf0000644000000000000000000000032714121063461021003 0ustar rootroot// // libcurl and curl bld.inf file for Symbian OS // PRJ_EXPORTS libcurl.iby /epoc32/rom/include/libcurl.iby curl.iby /epoc32/rom/include/curl.iby PRJ_MMPFILES libcurl.mmp curl.mmp davix-0.8.0/deps/curl/packages/Symbian/group/libcurl.iby0000644000000000000000000000037414121063461021707 0ustar rootroot// // libcurl file transfer DLL // // Use this file with buildrom to add libcurl to a device ROM // #ifndef LIBCURL_IBY #define LIBCURL_IBY #include file=ABI_DIR\BUILD_DIR\libcurl.dll \sys\bin\libcurl.dll #endif // LIBCURL_IBY davix-0.8.0/deps/curl/RELEASE-NOTES0000644000000000000000000003240014121063461015116 0ustar rootrootcurl and libcurl 7.69.0 Public curl releases: 189 Command line options: 230 curl_easy_setopt() options: 270 Public functions in libcurl: 82 Contributors: 2113 This release includes the following changes: o polarssl: removed [16] o smtp: add CURLOPT_MAIL_RCPT_ALLLOWFAILS and --mail-rcpt-allowfails [23] o wolfSSH: new SSH backend [5] This release includes the following bugfixes: o altsvc: improved header parser [63] o altsvc: keep a copy of the file name to survive handle reset [50] o altsvc: make saving the cache an atomic operation [84] o altsvc: use h3-27 o azure: disable brotli on the macos debug-builds [68] o build: remove all HAVE_OPENSSL_ENGINE_H defines [99] o checksrc.bat: Fix not being able to run script from the main curl dir [54] o cleanup: fix several comment typos [78] o cleanup: fix typos and wording in docs and comments [39] o cmake: add support for CMAKE_LTO option [22] o cmake: clean up and improve build procedures [100] o cmake: enable SMB for Windows builds [12] o cmake: improve libssh2 check on Windows [8] o cmake: Show HTTPS-proxy in the features output [110] o cmake: support specifying the target Windows version [27] o cmake: use check_symbol_exists also for inet_pton [19] o configure.ac: fix comments about --with-quiche [53] o configure: disable metalink if mbedTLS is specified [105] o configure: disable metalink support for incompatible SSL/TLS [40] o conn: do not reuse connection if SOCKS proxy credentials differ [32] o conncache: removed unused Curl_conncache_bundle_size() [33] o connect: remove some spurious infof() calls [80] o connection reuse: respect the max_concurrent_streams limits [3] o contributors: also include people who contributed to curl-www [58] o contrithanks: use the most recent tag by default [59] o cookie: check __Secure- and __Host- case sensitively [43] o cookies: make saving atomic with a rename [85] o create-dirs.d: mention the mode [73] o curl: avoid using strlen for testing if a string is empty [37] o curl: error on --alt-svc use w/o support [61] o curl: let -D merge headers in one file again [25] o curl: make #0 not output the full URL [4] o curl: make the -# spaceship bar not wrap the line [30] o curl: remove 'config' field from OutStruct [6] o curl:progressbarinit: ignore column width from terminals < 20 [18] o curl_escape.3: add a link to curl_free [107] o curl_getenv.3: fix the memory handling description [107] o curl_global_init: assume the EINTR bit by default [31] o curl_global_init: move the IPv6 works status bool to multi handle [48] o CURLINFO_COOKIELIST.3: Fix example [67] o CURLOPT_ALTSVC_CTRL.3: fix the DEFAULT wording [74] o CURLOPT_PROXY_SSL_OPTIONS.3: Sync with CURLOPT_SSL_OPTIONS.3 o CURLOPT_REDIR_PROTOCOLS.3: update the DEFAULT section [83] o data.d: remove "Multiple files can also be specified" [26] o digest: do not quote algorithm in HTTP authorisation [55] o docs/HTTP3: add --enable-alt-svc to curl's configure o docs/HTTP3: update the OpenSSL branch to use for ngtcp2 o docs: fix typo on CURLINFO_RETRY_AFTER [101] o easy: remove dead code [72] o form.d: fix two minor typos [34] o ftp: convert 'sock_accepted' to a plain boolean [66] o ftp: remove superfluous checking for crlf in user or pwd [56] o ftp: shrink temp buffers used for PORT [60] o github action: add CIFuzz [77] o github: Instructions to post "uname -a" on Unix systems in issues [52] o GnuTLS: always send client cert [76] o gtls: fixed compilation when using GnuTLS < 3.5.0 [98] o hostip: move code to resolve IP address literals to `Curl_resolv` [13] o HTTP-COOKIES: describe the cookie file format [21] o HTTP-COOKIES: mention that a trailing newline is required [81] o http2: make pausing/unpausing set/clear local stream window [86] o http2: now requires nghttp2 >= 1.12.0 [75] o http: added 417 response treatment [89] o http: increase EXPECT_100_THRESHOLD to 1Mb [28] o http: mark POSTs with no body as "upload done" from the start [104] o http: move "oauth_bearer" from connectdata to Curl_easy [24] o include: remove non-curl prefixed defines [15] o KNOWN_BUGS: Multiple methods in a single WWW-Authenticate: header o libssh2: add support for forcing a hostkey type [7] o libssh2: fix variable type [17] o libssh: improve known hosts handling [87] o llist: removed unused Curl_llist_move() [33] o location.d: the method change is from POST to GET only [46] o md4: fixed compilation issues when using GNU TLS gcrypt [95] o md4: use init/update/final functions in Secure Transport [108] o md5: added implementation for mbedTLS [102] o mk-ca-bundle: add support for CKA_NSS_SERVER_DISTRUST_AFTER [36] o multi: change curl_multi_wait/poll to error on negative timeout [11] o multi: fix outdated comment [71] o multi: if Curl_readwrite sets 'comeback' use expire, not loop [65] o multi_done: if multiplexed, make conn->data point to another transfer [45] o multi_wait: stop loop when sread() returns zero [103] o ngtcp2: add error code for QUIC connection errors [10] o ngtcp2: fixed to only use AF_INET6 when ENABLE_IPV6 [63] o ngtcp2: update to git master and its draft-25 support [42] o ntlm: move the winbind data into the NTLM data structure o ntlm: pass the Curl_easy structure to the private winbind functions o ntlm: removed the dependency on the TLS libaries when using MD5 [93] o ntlm_wb: use Curl_socketpair() for greater portability [57] o oauth2-bearer.d: works for HTTP too [44] o openssl: make CURLINFO_CERTINFO not truncate x509v3 fields [35] o openssl: remove redundant assignment [38] o os400: fixed the build [29] o pause: force-drain the transfer on unpause [96] o quiche: update to draft-25 [41] o README: mention that the docs is in docs/ [49] o RELEASE-PROCEDURE: feature win is closed post-release a few days [62] o runtests: make random seed fixed for a month [1] o runtests: restore the command log [97] o schannel: make CURLOPT_CAINFO work better on Windows 7 [9] o schannel_verify: Fix alt names manual verify for UNICODE builds [20] o sha256: use crypto implementations when available [106] o singleuse.pl: support new API functions, fix curl_dbg_ handling [33] o smtp: support the SMTPUTF8 extension [90] o smtp: support UTF-8 based host names in MAIL FROM [109] o SOCKS: make the connect phase non-blocking [64] o strcase: turn Curl_raw_tolower into static [33] o strerror: increase STRERROR_LEN 128 -> 256 [70] o test1323: added missing 'unit test' feature requirement o tests: add a unit test for MD4 digest generation [92] o tests: add a unit test for SHA256 digest generation [94] o tests: add a unit test for the HMAC hash generation [91] o tests: deduce the tool name from the test case for unit tests [88] o tests: fix Python 3 compatibility of smbserver.py o tool_dirhie: allow directory traversal during creation [2] o tool_homedir: change GetEnv() to use libcurl's curl_getenv() [69] o tool_util: improve Windows version of tvnow() [82] o travis: update non-OpenSSL Linux jobs to Bionic [38] o url: include the failure reason when curl_win32_idn_to_ascii() fails [51] o urlapi: guess scheme properly with credentials given [47] o urldata: do string enums without #ifdefs for build scripts [29] o vtls: refactor Curl_multissl_version to make the code clearer [14] o win32: USE_WIN32_CRYPTO to enable Win32 based MD4, MD5 and SHA256 [79] This release includes the following known bugs: o see docs/KNOWN_BUGS (https://curl.haxx.se/docs/knownbugs.html) This release would not have looked like this without help, code, reports and advice from friends like these: 3dyd on github, Alessandro Ghedini, Anders Berg, Anderson Toshiyuki Sasaki, Andrew Potter, Andrius Merkys, Aron Rotteveel, Austin Green, bnfp on github, bramus on github, Brian Carpenter, bsammon on github, Christian Heimes, Christoph M. Becker, Craig Andrews, crazydef on github, Cristian Greco, Dan Fandrich, Daniel Gustafsson, Daniel Marjamäki, Daniel Stenberg, Dan Jacobson, dmitrmax on github, Edgaras JanuÅ¡auskas, Emil Engler, Faizur Rahman, Frank Gevaerts, hamstergene on github, Harry Sintonen, IvanoG on github, James Fuller, Jeroen Ooms, jethrogb on github, Johannes Schindelin, Jonathan Cardoso Machado, Jon Rumsey, Joonas Kuorilehto, Kristian Mide, Kunal Ekawde, Leo Neat, Marc Aldorasi, Marcel Raad, Marc Hörsken, mbeifuss on github, Mike Frysinger, Mike Norton, Mischa Salle, MrdUkk on github, naost3rn on github, Nick Zitzmann, Nicolas Guillier, Orgad Shaneh, Patrick Monnerat, Pavel Volgarev, Pedro Monreal, Peter Piekarski, Peter Wu, Pierre-Yves Bigourdan, Ray Satiro, Robert Dunaj, Rolf Eike Beer, RuurdBeerstra on github, Santino Keupp, Steve Holme, Sunny Bean, Tobias Hieta, vshmuk on hackerone, ygthien on github, 加藤éƒä¹‹, (69 contributors) Thanks! (and sorry if I forgot to mention someone) References to bug reports and discussions on issues: [1] = https://curl.haxx.se/bug/?i=4734 [2] = https://curl.haxx.se/bug/?i=4796 [3] = https://curl.haxx.se/bug/?i=4779 [4] = https://curl.haxx.se/bug/?i=4812 [5] = https://daniel.haxx.se/blog/2020/01/12/curl-even-more-wolfed/ [6] = https://curl.haxx.se/bug/?i=4807 [7] = https://curl.haxx.se/bug/?i=4747 [8] = https://curl.haxx.se/bug/?i=4804 [9] = https://curl.haxx.se/bug/?i=3711 [10] = https://curl.haxx.se/bug/?i=4754 [11] = https://curl.haxx.se/bug/?i=4763 [12] = https://curl.haxx.se/bug/?i=4717 [13] = https://curl.haxx.se/bug/?i=4798 [14] = https://curl.haxx.se/bug/?i=4803 [15] = https://curl.haxx.se/bug/?i=4793 [16] = https://curl.haxx.se/bug/?i=4825 [17] = https://curl.haxx.se/bug/?i=4823 [18] = https://curl.haxx.se/bug/?i=4818 [19] = https://curl.haxx.se/bug/?i=4808 [20] = https://curl.haxx.se/bug/?i=4761 [21] = https://curl.haxx.se/bug/?i=4805 [22] = https://curl.haxx.se/bug/?i=4799 [23] = https://curl.haxx.se/bug/?i=4816 [24] = https://curl.haxx.se/bug/?i=4824 [25] = https://curl.haxx.se/bug/?i=4762 [26] = https://curl.haxx.se/mail/archive-2020-01/0016.html [27] = https://curl.haxx.se/bug/?i=4815 [28] = https://curl.haxx.se/bug/?i=4814 [29] = https://curl.haxx.se/bug/?i=4822 [30] = https://curl.haxx.se/bug/?i=4849 [31] = https://curl.haxx.se/bug/?i=4840 [32] = https://curl.haxx.se/bug/?i=4835 [33] = https://curl.haxx.se/bug/?i=4842 [34] = https://curl.haxx.se/bug/?i=4843 [35] = https://curl.haxx.se/bug/?i=4837 [36] = https://curl.haxx.se/bug/?i=4834 [37] = https://curl.haxx.se/bug/?i=4873 [38] = https://curl.haxx.se/bug/?i=4872 [39] = https://curl.haxx.se/bug/?i=4869 [40] = https://curl.haxx.se/bug/?i=5006 [41] = https://curl.haxx.se/bug/?i=4867 [42] = https://curl.haxx.se/bug/?i=4865 [43] = https://curl.haxx.se/bug/?i=4864 [44] = https://curl.haxx.se/bug/?i=4862 [45] = https://curl.haxx.se/bug/?i=4845 [46] = https://curl.haxx.se/bug/?i=4859 [47] = https://curl.haxx.se/bug/?i=4856 [48] = https://curl.haxx.se/bug/?i=4851 [49] = https://curl.haxx.se/bug/?i=4830 [50] = https://curl.haxx.se/bug/?i=4898 [51] = https://curl.haxx.se/bug/?i=4899 [52] = https://curl.haxx.se/bug/?i=4896 [53] = https://curl.haxx.se/bug/?i=4897 [54] = https://curl.haxx.se/bug/?i=4894 [55] = https://curl.haxx.se/bug/?i=4890 [56] = https://curl.haxx.se/bug/?i=4887 [57] = https://curl.haxx.se/bug/?i=4886 [58] = https://curl.haxx.se/bug/?i=4884 [59] = https://curl.haxx.se/bug/?i=4883 [60] = https://curl.haxx.se/bug/?i=4880 [61] = https://curl.haxx.se/bug/?i=4878 [62] = https://curl.haxx.se/bug/?i=4877 [63] = https://curl.haxx.se/bug/?i=4875 [64] = https://curl.haxx.se/bug/?i=4907 [65] = https://curl.haxx.se/bug/?i=4927 [66] = https://curl.haxx.se/bug/?i=4929 [67] = https://curl.haxx.se/bug/?i=4930 [68] = https://curl.haxx.se/bug/?i=4925 [69] = https://curl.haxx.se/bug/?i=4774 [70] = https://curl.haxx.se/bug/?i=4920 [71] = https://curl.haxx.se/bug/?i=4901 [72] = https://curl.haxx.se/bug/?i=4900 [73] = https://curl.haxx.se/bug/?i=4766 [74] = https://curl.haxx.se/bug/?i=4909 [75] = https://curl.haxx.se/bug/?i=4961 [76] = https://curl.haxx.se/bug/?i=1411 [77] = https://curl.haxx.se/bug/?i=4960 [78] = https://curl.haxx.se/bug/?i=4957 [79] = https://curl.haxx.se/bug/?i=4955 [80] = https://curl.haxx.se/bug/?i=4951 [81] = https://curl.haxx.se/bug/?i=4946 [82] = https://curl.haxx.se/bug/?i=4947 [83] = https://curl.haxx.se/bug/?i=4943 [84] = https://curl.haxx.se/bug/?i=4936 [85] = https://curl.haxx.se/bug/?i=4914 [86] = https://curl.haxx.se/bug/?i=4939 [87] = https://curl.haxx.se/bug/?i=4953 [88] = https://curl.haxx.se/bug/?i=4976 [89] = https://curl.haxx.se/bug/?i=4949 [90] = https://curl.haxx.se/bug/?i=4892 [91] = https://curl.haxx.se/bug/?i=4973 [92] = https://curl.haxx.se/bug/?i=4970 [93] = https://curl.haxx.se/bug/?i=4967 [94] = https://curl.haxx.se/bug/?i=4968 [95] = https://curl.haxx.se/bug/?i=4959 [96] = https://curl.haxx.se/bug/?i=4966 [97] = https://curl.haxx.se/bug/?i=4911 [98] = https://curl.haxx.se/bug/?i=4984 [99] = https://curl.haxx.se/bug/?i=5007 [100] = https://curl.haxx.se/bug/?i=4975 [101] = https://curl.haxx.se/bug/?i=5005 [102] = https://curl.haxx.se/bug/?i=4980 [103] = https://curl.haxx.se/mail/archive-2020-02/0011.html [104] = https://curl.haxx.se/bug/?i=4996 [105] = https://curl.haxx.se/bug/?i=5013 [106] = https://curl.haxx.se/bug/?i=4956 [107] = https://curl.haxx.se/bug/?i=5016 [108] = https://curl.haxx.se/bug/?i=4979 [109] = https://curl.haxx.se/bug/?i=4928 [110] = https://curl.haxx.se/bug/?i=5025 davix-0.8.0/deps/curl/scripts/0000755000000000000000000000000014121063461014715 5ustar rootrootdavix-0.8.0/deps/curl/scripts/Makefile.am0000644000000000000000000000477314121063461016764 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@ FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ PERL = @PERL@ ZSH_COMPLETION_FUNCTION_FILENAME = _curl FISH_COMPLETION_FUNCTION_FILENAME = curl.fish CLEANFILES = $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) all-local: $(ZSH_COMPLETION_FUNCTION_FILENAME) $(FISH_COMPLETION_FUNCTION_FILENAME) $(ZSH_COMPLETION_FUNCTION_FILENAME): completion.pl if CROSSCOMPILING @echo "NOTICE: we can't generate zsh completion when cross-compiling!" else # if not cross-compiling: @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell zsh > $@ endif $(FISH_COMPLETION_FUNCTION_FILENAME): completion.pl if CROSSCOMPILING @echo "NOTICE: we can't generate fish completion when cross-compiling!" else # if not cross-compiling: @if ! test -x "$(PERL)"; then echo "No perl: can't install completion.pl"; exit 0; fi $(PERL) $(srcdir)/completion.pl --curl $(top_builddir)/src/curl$(EXEEXT) --shell fish > $@ endif install-data-local: if CROSSCOMPILING @echo "NOTICE: we can't install zsh completion when cross-compiling!" else # if not cross-compiling: $(MKDIR_P) $(DESTDIR)$(ZSH_FUNCTIONS_DIR) $(MKDIR_P) $(DESTDIR)$(FISH_FUNCTIONS_DIR) $(INSTALL_DATA) $(ZSH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(ZSH_FUNCTIONS_DIR)/$(ZSH_COMPLETION_FUNCTION_FILENAME) $(INSTALL_DATA) $(FISH_COMPLETION_FUNCTION_FILENAME) $(DESTDIR)$(FISH_FUNCTIONS_DIR)/$(FISH_COMPLETION_FUNCTION_FILENAME) endif davix-0.8.0/deps/curl/scripts/travis/0000755000000000000000000000000014121063461016225 5ustar rootrootdavix-0.8.0/deps/curl/scripts/travis/script.sh0000755000000000000000000000764614121063461020105 0ustar rootroot#!/bin/bash set -eo pipefail ./buildconf if [ "$T" = "coverage" ]; then ./configure --enable-debug --disable-shared --disable-threaded-resolver --enable-code-coverage --enable-werror --enable-alt-svc --with-libssh2 make make TFLAGS=-n test-nonflaky make "TFLAGS=-n -e" test-nonflaky tests="1 200 300 500 700 800 900 1000 1100 1200 1302 1400 1502 3000" make "TFLAGS=-n -t $tests" test-nonflaky coveralls --gcov /usr/bin/gcov-8 --gcov-options '\-lp' -i src -e lib -e tests -e docs -b $PWD/src coveralls --gcov /usr/bin/gcov-8 --gcov-options '\-lp' -e src -i lib -e tests -e docs -b $PWD/lib fi if [ "$T" = "torture" ]; then ./configure --enable-debug --disable-shared --disable-threaded-resolver --enable-code-coverage --enable-werror --enable-alt-svc --with-libssh2 make make TFLAGS=-n test-nonflaky make "TFLAGS=-n -e" test-nonflaky tests="1 200 300 500 700 800 900 1000 1100 1200 1302 1400 1502 3000" make "TFLAGS=-n --shallow=40 -t $tests" test-nonflaky fi if [ "$T" = "debug" ]; then ./configure --enable-debug --enable-werror $C make make examples if [ -z $NOTESTS ]; then if [ "$TRAVIS_ARCH" = "aarch64" ] ; then # TODO: find out why this test is failing on arm64 make "TFLAGS=-n !323" test-nonflaky else make TFLAGS=-n test-nonflaky fi fi fi if [ "$T" = "debug-wolfssl" ]; then ./configure --enable-debug --enable-werror $C make make "TFLAGS=-n !313" test-nonflaky fi if [ "$T" = "debug-mesalink" ]; then ./configure --enable-debug --enable-werror $C make make "TFLAGS=-n !313 !3001" test-nonflaky fi if [ "$T" = "novalgrind" ]; then ./configure --enable-werror $C make make examples make TFLAGS=-n test-nonflaky fi if [ "$T" = "normal" ]; then if [ $TRAVIS_OS_NAME = linux ]; then # Remove system curl to make sure we don't rely on it. # Only done on Linux since we're not permitted to on mac. sudo rm -f /usr/bin/curl fi ./configure --enable-warnings --enable-werror $C make make examples if [ -z $NOTESTS ]; then make test-nonflaky fi if [ -n $CHECKSRC ]; then echo "enable COPYRIGHTYEAR" > ./docs/examples/.checksrc echo "enable COPYRIGHTYEAR" > ./include/curl/.checksrc make checksrc fi fi if [ "$T" = "tidy" ]; then ./configure --enable-warnings --enable-werror $C make make tidy fi if [ "$T" = "iconv" ]; then source scripts/travis/iconv-env.sh ./configure --enable-debug --enable-werror $C make make examples make test-nonflaky fi if [ "$T" = "cmake" ]; then if [ $TRAVIS_OS_NAME = linux ]; then cmake -H. -Bbuild -DCURL_WERROR=ON cmake --build build else cmake -H. -Bbuild -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCURL_DISABLE_LDAP=ON -DCURL_DISABLE_LDAPS=ON cmake --build build fi fi if [ "$T" = "distcheck" ]; then # find BOM markers and exit if we do ! git grep `printf '\xef\xbb\xbf'` ./configure make ./maketgz 99.98.97 # verify in-tree build - and install it tar xf curl-99.98.97.tar.gz cd curl-99.98.97 ./configure --prefix=$HOME/temp make make TFLAGS=1 test make install # basic check of the installed files cd .. bash scripts/installcheck.sh $HOME/temp rm -rf curl-99.98.97 # verify out-of-tree build tar xf curl-99.98.97.tar.gz touch curl-99.98.97/docs/{cmdline-opts,libcurl}/Makefile.inc mkdir build cd build ../curl-99.98.97/configure make make TFLAGS='-p 1 1139' test # verify cmake build cd .. rm -rf curl-99.98.97 tar xf curl-99.98.97.tar.gz cd curl-99.98.97 mkdir build cd build cmake .. make cd ../.. fi if [ "$T" = "fuzzer" ]; then # Download the fuzzer to a temporary folder ./tests/fuzz/download_fuzzer.sh /tmp/curl_fuzzer export CURLSRC=$PWD # Run the mainline fuzzer test pushd /tmp/curl_fuzzer ./mainline.sh ${CURLSRC} popd fi if [ "$T" = "scan-build" ]; then scan-build ./configure --enable-debug --enable-werror $C scan-build --status-bugs make scan-build --status-bugs make examples fi davix-0.8.0/deps/curl/scripts/travis/iconv-env.sh0000755000000000000000000000014414121063461020467 0ustar rootrootexport CPPFLAGS="-DCURL_DOES_CONVERSIONS -DHAVE_ICONV -DCURL_ICONV_CODESET_OF_HOST='\"ISO8859-1\"'" davix-0.8.0/deps/curl/scripts/travis/before_script.sh0000755000000000000000000000560314121063461021416 0ustar rootroot#!/bin/bash set -eo pipefail ./buildconf if [ "$NGTCP2" = yes ]; then cd $HOME git clone --depth 1 -b openssl-quic-draft-23 https://github.com/tatsuhiro-t/openssl possl cd possl ./config enable-tls1_3 --prefix=$HOME/ngbuild make make install_sw cd $HOME git clone --depth 1 https://github.com/ngtcp2/nghttp3 cd nghttp3 autoreconf -i ./configure --prefix=$HOME/ngbuild --enable-lib-only make make install cd $HOME git clone --depth 1 https://github.com/ngtcp2/ngtcp2 cd ngtcp2 autoreconf -i ./configure PKG_CONFIG_PATH=$HOME/ngbuild/lib/pkgconfig LDFLAGS="-Wl,-rpath,$HOME/ngbuild/lib" --prefix=$HOME/ngbuild --enable-lib-only make make install fi if [ "$TRAVIS_OS_NAME" = linux -a "$BORINGSSL" ]; then cd $HOME git clone --depth=1 https://boringssl.googlesource.com/boringssl cd boringssl mkdir build cd build CXX="g++" CC="gcc" cmake -DCMAKE_BUILD_TYPE=release -DBUILD_SHARED_LIBS=1 .. make cd .. mkdir lib cd lib cp ../build/crypto/libcrypto.so . cp ../build/ssl/libssl.so . echo "BoringSSL lib dir: "`pwd` cd ../build make clean rm -f CMakeCache.txt CXX="g++" CC="gcc" cmake -DCMAKE_POSITION_INDEPENDENT_CODE=on .. make export LIBS=-lpthread fi if [ "$TRAVIS_OS_NAME" = linux -a "$QUICHE" ]; then cd $HOME git clone --depth=1 https://github.com/cloudflare/quiche.git curl https://sh.rustup.rs -sSf | sh -s -- -y source $HOME/.cargo/env cd $HOME/quiche QUICHE_BSSL_PATH=$HOME/boringssl cargo build -v --release --features pkg-config-meta fi # Install common libraries. # The library build directories are set to be cached by .travis.yml. If you are # changing a build directory name below (eg a version change) then you must # change it in .travis.yml `cache: directories:` as well. if [ $TRAVIS_OS_NAME = linux ]; then if [ ! -e $HOME/wolfssl-4.0.0-stable/Makefile ]; then cd $HOME curl -LO https://github.com/wolfSSL/wolfssl/archive/v4.0.0-stable.tar.gz tar -xzf v4.0.0-stable.tar.gz cd wolfssl-4.0.0-stable ./autogen.sh ./configure --enable-tls13 --enable-all touch wolfssl/wolfcrypt/fips.h make fi cd $HOME/wolfssl-4.0.0-stable sudo make install if [ ! -e $HOME/mesalink-1.0.0/Makefile ]; then cd $HOME curl https://sh.rustup.rs -sSf | sh -s -- -y source $HOME/.cargo/env curl -LO https://github.com/mesalock-linux/mesalink/archive/v1.0.0.tar.gz tar -xzf v1.0.0.tar.gz cd mesalink-1.0.0 ./autogen.sh ./configure --enable-tls13 make fi cd $HOME/mesalink-1.0.0 sudo make install if [ ! -e $HOME/nghttp2-1.39.2/Makefile ]; then cd $HOME curl -LO https://github.com/nghttp2/nghttp2/releases/download/v1.39.2/nghttp2-1.39.2.tar.gz tar -xzf nghttp2-1.39.2.tar.gz cd nghttp2-1.39.2 CXX="g++-8" CC="gcc-8" CFLAGS="" LDFLAGS="" LIBS="" ./configure --disable-threads --enable-app make fi cd $HOME/nghttp2-1.39.2 sudo make install fi davix-0.8.0/deps/curl/scripts/contrithanks.sh0000755000000000000000000000406014121063461017763 0ustar rootroot#!/bin/sh #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2013-2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # # This script shows all mentioned contributors from until HEAD and # puts them at the end of the THANKS document on stdout # start=$1 if test "$start" = "-h"; then echo "Usage: $0 " exit fi if test -z "$start"; then start=`git tag --sort=taggerdate | tail -1`; fi # We also include curl-www if possible. Override by setting CURLWWW if [ -z "$CURLWWW" ] ; then CURLWWW=../curl-www fi cat ./docs/THANKS ( ( git log --use-mailmap $start..HEAD if [ -d "$CURLWWW" ] then git -C ../curl-www log --use-mailmap $start..HEAD fi ) | \ egrep -ai '(^Author|^Commit|by):' | \ cut -d: -f2- | \ cut '-d(' -f1 | \ cut '-d<' -f1 | \ tr , '\012' | \ sed 's/ at github/ on github/' | \ sed 's/ and /\n/' | \ sed -e 's/^ //' -e 's/ $//g' -e 's/@users.noreply.github.com$/ on github/' # grep out the list of names from RELEASE-NOTES # split on ", " # remove leading white spaces grep -a "^ [^ (]" RELEASE-NOTES| \ sed 's/, */\n/g'| \ sed 's/^ *//' )| \ sed -f ./docs/THANKS-filter | \ grep -a ' ' | \ sort -fu | \ grep -aixvf ./docs/THANKS davix-0.8.0/deps/curl/scripts/completion.pl0000755000000000000000000000624414121063461017434 0ustar rootroot#!/usr/bin/env perl use strict; use warnings; use Getopt::Long(); use Pod::Usage(); my $curl = 'curl'; my $shell = 'zsh'; my $help = 0; Getopt::Long::GetOptions( 'curl=s' => \$curl, 'shell=s' => \$shell, 'help' => \$help, ) or Pod::Usage::pod2usage(); Pod::Usage::pod2usage() if $help; my $regex = '\s+(?:(-[^\s]+),\s)?(--[^\s]+)\s*(\<.+?\>)?\s+(.*)'; my @opts = parse_main_opts('--help', $regex); if ($shell eq 'fish') { print "# curl fish completion\n\n"; print qq{$_ \n} foreach (@opts); } elsif ($shell eq 'zsh') { my $opts_str; $opts_str .= qq{ $_ \\\n} foreach (@opts); chomp $opts_str; my $tmpl = <<"EOS"; #compdef curl # curl zsh completion local curcontext="\$curcontext" state state_descr line typeset -A opt_args local rc=1 _arguments -C -S \\ $opts_str '*:URL:_urls' && rc=0 return rc EOS print $tmpl; } else { die("Unsupported shell: $shell"); } sub parse_main_opts { my ($cmd, $regex) = @_; my @list; my @lines = call_curl($cmd); foreach my $line (@lines) { my ($short, $long, $arg, $desc) = ($line =~ /^$regex/) or next; my $option = ''; $arg =~ s/\:/\\\:/g if defined $arg; $desc =~ s/'/'\\''/g if defined $desc; $desc =~ s/\[/\\\[/g if defined $desc; $desc =~ s/\]/\\\]/g if defined $desc; $desc =~ s/\:/\\\:/g if defined $desc; if ($shell eq 'fish') { $option .= "complete --command curl"; $option .= " --short-option '" . strip_dash(trim($short)) . "'" if defined $short; $option .= " --long-option '" . strip_dash(trim($long)) . "'" if defined $long; $option .= " --description '" . strip_dash(trim($desc)) . "'" if defined $desc; } elsif ($shell eq 'zsh') { $option .= '{' . trim($short) . ',' if defined $short; $option .= trim($long) if defined $long; $option .= '}' if defined $short; $option .= '\'[' . trim($desc) . ']\'' if defined $desc; $option .= ":'$arg'" if defined $arg; $option .= ':_files' if defined $arg and ($arg eq '' || $arg eq '' || $arg eq ''); } push @list, $option; } # Sort longest first, because zsh won't complete an option listed # after one that's a prefix of it. @list = sort { $a =~ /([^=]*)/; my $ma = $1; $b =~ /([^=]*)/; my $mb = $1; length($mb) <=> length($ma) } @list if $shell eq 'zsh'; return @list; } sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s }; sub strip_dash { my $s = shift; $s =~ s/^-+//g; return $s }; sub call_curl { my ($cmd) = @_; my $output = `"$curl" $cmd`; if ($? == -1) { die "Could not run curl: $!"; } elsif ((my $exit_code = $? >> 8) != 0) { die "curl returned $exit_code with output:\n$output"; } return split /\n/, $output; } __END__ =head1 NAME completion.pl - Generates tab-completion files for various shells =head1 SYNOPSIS completion.pl [options...] --curl path to curl executable --shell zsh/fish --help prints this help =cut davix-0.8.0/deps/curl/scripts/coverage.sh0000755000000000000000000000071214121063461017047 0ustar rootroot#!/bin/sh ./buildconf mkdir -p cvr cd cvr ../configure --disable-shared --enable-debug --enable-maintainer-mode --enable-code-coverage make -sj # the regular test run make TFLAGS=-n test-nonflaky # make all allocs/file operations fail #make TFLAGS=-n test-torture # do everything event-based make TFLAGS=-n test-event lcov -d . -c -o cov.lcov genhtml cov.lcov --output-directory coverage --title "curl code coverage" tar -cjf curl-coverage.tar.bz2 coverage davix-0.8.0/deps/curl/scripts/singleuse.pl0000755000000000000000000001540614121063461017261 0ustar rootroot#!/usr/bin/perl #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # # This script is aimed to help scan for and detect globally declared functions # that are not used from other source files. # # Use it like this: # # $ ./scripts/singleuse.pl lib/.libs/libcurl.a # # Be aware that it might cause false positives due to various build options. # my $file = $ARGV[0]; my %wl = ( 'Curl_none_cert_status_request' => 'multiple TLS backends', 'Curl_none_check_cxn' => 'multiple TLS backends', 'Curl_none_cleanup' => 'multiple TLS backends', 'Curl_none_close_all' => 'multiple TLS backends', 'Curl_none_data_pending' => 'multiple TLS backends', 'Curl_none_engines_list' => 'multiple TLS backends', 'Curl_none_init' => 'multiple TLS backends', 'Curl_none_md5sum' => 'multiple TLS backends', 'Curl_none_random' => 'multiple TLS backends', 'Curl_none_session_free' => 'multiple TLS backends', 'Curl_none_set_engine' => 'multiple TLS backends', 'Curl_none_set_engine_default' => 'multiple TLS backends', 'Curl_none_shutdown' => 'multiple TLS backends', 'Curl_multi_dump' => 'debug build only', 'Curl_parse_port' => 'UNITTEST', 'Curl_shuffle_addr' => 'UNITTEST', 'de_cleanup' => 'UNITTEST', 'doh_decode' => 'UNITTEST', 'doh_encode' => 'UNITTEST', 'Curl_auth_digest_get_pair' => 'by digest_sspi', 'curlx_uztoso' => 'cmdline tool use', 'curlx_uztoul' => 'by krb5_sspi', 'curlx_uitous' => 'by schannel', 'Curl_islower' => 'by curl_fnmatch', 'getaddressinfo' => 'UNITTEST', ); my %api = ( 'curl_easy_cleanup' => 'API', 'curl_easy_duphandle' => 'API', 'curl_easy_escape' => 'API', 'curl_easy_getinfo' => 'API', 'curl_easy_init' => 'API', 'curl_easy_pause' => 'API', 'curl_easy_perform' => 'API', 'curl_easy_recv' => 'API', 'curl_easy_reset' => 'API', 'curl_easy_send' => 'API', 'curl_easy_setopt' => 'API', 'curl_easy_strerror' => 'API', 'curl_easy_unescape' => 'API', 'curl_easy_upkeep' => 'API', 'curl_escape' => 'API', 'curl_formadd' => 'API', 'curl_formfree' => 'API', 'curl_formget' => 'API', 'curl_free' => 'API', 'curl_getdate' => 'API', 'curl_getenv' => 'API', 'curl_global_cleanup' => 'API', 'curl_global_init' => 'API', 'curl_global_init_mem' => 'API', 'curl_global_sslset' => 'API', 'curl_maprintf' => 'API', 'curl_mfprintf' => 'API', 'curl_mime_addpart' => 'API', 'curl_mime_data' => 'API', 'curl_mime_data_cb' => 'API', 'curl_mime_encoder' => 'API', 'curl_mime_filedata' => 'API', 'curl_mime_filename' => 'API', 'curl_mime_free' => 'API', 'curl_mime_headers' => 'API', 'curl_mime_init' => 'API', 'curl_mime_name' => 'API', 'curl_mime_subparts' => 'API', 'curl_mime_type' => 'API', 'curl_mprintf' => 'API', 'curl_msnprintf' => 'API', 'curl_msprintf' => 'API', 'curl_multi_add_handle' => 'API', 'curl_multi_assign' => 'API', 'curl_multi_cleanup' => 'API', 'curl_multi_fdset' => 'API', 'curl_multi_info_read' => 'API', 'curl_multi_init' => 'API', 'curl_multi_perform' => 'API', 'curl_multi_remove_handle' => 'API', 'curl_multi_setopt' => 'API', 'curl_multi_socket' => 'API', 'curl_multi_socket_action' => 'API', 'curl_multi_socket_all' => 'API', 'curl_multi_poll' => 'API', 'curl_multi_strerror' => 'API', 'curl_multi_timeout' => 'API', 'curl_multi_wait' => 'API', 'curl_multi_wakeup' => 'API', 'curl_mvaprintf' => 'API', 'curl_mvfprintf' => 'API', 'curl_mvprintf' => 'API', 'curl_mvsnprintf' => 'API', 'curl_mvsprintf' => 'API', 'curl_pushheader_byname' => 'API', 'curl_pushheader_bynum' => 'API', 'curl_share_cleanup' => 'API', 'curl_share_init' => 'API', 'curl_share_setopt' => 'API', 'curl_share_strerror' => 'API', 'curl_slist_append' => 'API', 'curl_slist_free_all' => 'API', 'curl_strequal' => 'API', 'curl_strnequal' => 'API', 'curl_unescape' => 'API', 'curl_url' => 'API', 'curl_url_cleanup' => 'API', 'curl_url_dup' => 'API', 'curl_url_get' => 'API', 'curl_url_set' => 'API', 'curl_version' => 'API', 'curl_version_info' => 'API', # the following functions are provided globally in debug builds 'curl_easy_perform_ev' => 'debug-build', ); open(N, "nm $file|") || die; my %exist; my %uses; my $file; while () { my $l = $_; chomp $l; if($l =~ /^([0-9a-z_-]+)\.o:/) { $file = $1; } if($l =~ /^([0-9a-f]+) T (.*)/) { my ($name)=($2); #print "Define $name in $file\n"; $file =~ s/^libcurl_la-//; $exist{$name} = $file; } elsif($l =~ /^ U (.*)/) { my ($name)=($1); #print "Uses $name in $file\n"; $uses{$name} .= "$file, "; } } close(N); my $err; for(sort keys %exist) { #printf "%s is defined in %s, used by: %s\n", $_, $exist{$_}, $uses{$_}; if(!$uses{$_}) { # this is a symbol with no "global" user if($_ =~ /^curl_dbg_/) { # we ignore the memdebug symbols } elsif($_ =~ /^curl_/) { if(!$api{$_}) { # not present in the API, or for debug-builds print STDERR "Bad curl-prefix: $_\n"; $err++; } } elsif($wl{$_}) { #print "$_ is WL\n"; } else { printf "%s is defined in %s, but not used outside\n", $_, $exist{$_}; $err++; } } elsif($_ =~ /^curl_/) { # global prefix, make sure it is "blessed" if(!$api{$_}) { # not present in the API, or for debug-builds if($_ !~ /^curl_dbg_/) { # ignore the memdebug symbols print STDERR "Bad curl-prefix $_\n"; $err++; } } } } exit $err; davix-0.8.0/deps/curl/scripts/delta0000755000000000000000000001113514121063461015735 0ustar rootroot#!/usr/bin/perl #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2018-2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # Display changes done in the repository from [tag] until now. # # Uses git for repo data. # Uses docs/THANKS and RELEASE-NOTES for current status. # # In the git clone root, invoke 'scripts/delta [release tag]' $start = $ARGV[0]; if($start eq "-h") { print "Usage: summary [tag]\n"; exit; } elsif($start eq "") { $start = `git tag --sort=taggerdate | tail -1`; chomp $start; } $commits = `git log --oneline $start.. | wc -l`; $committers = `git shortlog -s $start.. | wc -l`; $bcommitters = `git shortlog -s $start | wc -l`; $acommits = `git log --oneline | wc -l`; $acommitters = `git shortlog -s | wc -l`; # delta from now compared to before $ncommitters = $acommitters - $bcommitters; # number of contributors right now $acontribs = `./scripts/contrithanks.sh | grep -c '^[^ ]'`; # number when the tag tag was set $bcontribs = `git show $start:docs/THANKS | grep -c '^[^ ]'`; # delta $contribs = $acontribs - $bcontribs; # number of setops: $asetopts=`grep '^ CURLOPT(' include/curl/curl.h | grep -cv OBSOLETE`; $bsetopts=`git show $start:include/curl/curl.h | grep '^ CURLOPT(' | grep -cv OBSOLETE`; $nsetopts = $asetopts - $bsetopts; # Number of command line options: $aoptions=`grep -c '{"....--' src/tool_help.c`; $boptions=`git show $start:src/tool_help.c | grep -c '{"....--'`; $noptions=$aoptions - $boptions; # Number of files in git $afiles=`git ls-files | wc -l`; $deletes=`git diff-tree --diff-filter=A -r --summary origin/master $start | wc -l`; $creates=`git diff-tree --diff-filter=D -r --summary origin/master $start | wc -l`; # Time since that tag $tagged=`git for-each-ref --format="%(refname:short) | %(taggerdate:unix)" refs/tags/* | grep ^$start | cut "-d|" -f2`; # unix timestamp $taggednice=`git for-each-ref --format="%(refname:short) | %(creatordate)" refs/tags/* | grep ^$start | cut '-d|' -f2`; # human readable time chomp $taggednice; $now=`date +%s`; $elapsed=$now - $tagged; # number of seconds since tag # Number of public functions in libcurl $apublic=`git grep ^CURL_EXTERN -- include/curl | wc -l`; $bpublic=`git grep ^CURL_EXTERN $start -- include/curl | wc -l`; $public = $apublic - $bpublic; # Changes/bug-fixes currently logged open(F, ") { if($_ =~ /following changes:/) { $mode=1; } elsif($_ =~ /following bugfixes:/) { $mode=2; } elsif($_ =~ /known bugs:/) { $mode=3; } elsif($_ =~ /like these:/) { $mode=4; } if($_ =~ /^ o /) { if($mode == 1) { $numchanges++; } elsif($mode == 2) { $numbugfixes++; } } if(($mode == 4) && ($_ =~ /^ \((\d+) contributors/)) { $numcontributors = $1; } } close(F); ######################################################################## # Produce the summary print "== Since $start ==\n"; printf "Commits: %d (out of %d)\n", $commits, $acommits; printf "Commit authors: %d out of which %d are new (out of %d)\n", $committers, $ncommitters, $acommitters; printf "Contributors in RELEASE-NOTES: %d\n", $numcontributors; printf "New contributors: %d (out of %d)\n", $contribs, $acontribs; printf "New curl_easy_setopt() options: %d (out of %d)\n", $nsetopts, $asetopts; printf "New command line options: %d (out of %d)\n", $noptions, $aoptions; printf "Deleted %d files, added %d files (total %d)\n", $deletes, $creates, $afiles; printf "Elapsed time: %.1f days (since$taggednice)\n", $elapsed / 3600 / 24; printf "Changes logged: %d\n", $numchanges; printf "Bugfixes logged: %d\n", $numbugfixes; printf "New public functions: %d (out of %d)\n", $public, $apublic; davix-0.8.0/deps/curl/scripts/contributors.sh0000755000000000000000000000512614121063461020015 0ustar rootroot#!/bin/sh #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2013-2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # # This script shows all mentioned contributors from the given / # until HEAD and adds the contributors already mentioned in the existing # RELEASE-NOTES. # start=$1 if test "$start" = "-h"; then echo "Usage: $0 [--releasenotes]" exit fi if test -z "$start"; then start=`git tag --sort=taggerdate | tail -1`; echo "Since $start:" fi # We also include curl-www if possible. Override by setting CURLWWW if [ -z "$CURLWWW" ] ; then CURLWWW=../curl-www fi # filter out Author:, Commit: and *by: lines # cut off the email parts # split list of names at comma # split list of names at " and " # cut off spaces first and last on the line # filter alternatives through THANKS-filter # only count names with a space (ie more than one word) # sort all unique names # awk them into RELEASE-NOTES format ( ( git log --pretty=full --use-mailmap $start..HEAD if [ -d "$CURLWWW" ] then git -C ../curl-www log --pretty=full --use-mailmap $start..HEAD fi ) | \ egrep -ai '(^Author|^Commit|by):' | \ cut -d: -f2- | \ cut '-d(' -f1 | \ cut '-d<' -f1 | \ tr , '\012' | \ sed 's/ at github/ on github/' | \ sed 's/ and /\n/' | \ sed -e 's/^ //' -e 's/ $//g' -e 's/@users.noreply.github.com$/ on github/' grep -a "^ [^ \(]" RELEASE-NOTES| \ sed 's/, */\n/g'| \ sed 's/^ *//' )| \ sed -f ./docs/THANKS-filter | \ grep -a ' ' | \ sort -fu | \ awk '{ num++; n = sprintf("%s%s%s,", n, length(n)?" ":"", $0); #print n; if(length(n) > 77) { printf(" %s\n", p); n=sprintf("%s,", $0); } p=n; } END { printf(" %s\n", p); printf(" (%d contributors)\n", num); } ' davix-0.8.0/deps/curl/scripts/log2changes.pl0000755000000000000000000000354314121063461017456 0ustar rootroot#!/usr/bin/env perl # git log --pretty=fuller --no-color --date=short --decorate=full my @mname = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ); sub nicedate { my ($date)=$_; if($date =~ /(\d\d\d\d)-(\d\d)-(\d\d)/) { return sprintf("%d %s %4d", $3, $mname[$2-1], $1); } return $date; } print ' _ _ ____ _ ___| | | | _ \| | / __| | | | |_) | | | (__| |_| | _ <| |___ \___|\___/|_| \_\_____| Changelog '; my $line; my $tag; while() { my $l = $_; if($l =~/^commit ([[:xdigit:]]*) ?(.*)/) { $co = $1; my $ref = $2; if ($ref =~ /refs\/tags\/curl-([0-9_]*)/) { $tag = $1; $tag =~ tr/_/./; } } elsif($l =~ /^Author: *(.*) +, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # Update man pages. use strict; use warnings; use Tie::File; # Data from the command line. my $curlver = $ARGV[0]; my $curldate = $ARGV[1]; # Directories and extensions. my @dirlist = ("docs/", "docs/libcurl/", "docs/libcurl/opts/", "tests/"); my @extlist = (".1", ".3"); my @excludelist = ("mk-ca-bundle.1", "template.3"); # Subroutines sub printargs{ # Print arguments and exit. print "usage: updatemanpages.pl \n"; exit; } sub getthline{ # Process file looking for .TH section. my $filename = shift; my $file_handle; my $file_line; # Open the file. open($file_handle, $filename); # Look for the .TH section, process it into an array, # modify it and write to file. tie(my @file_data, 'Tie::File', $filename); foreach my $file_data_line(@file_data) { if($file_data_line =~ /^.TH/) { $file_line = $file_data_line; last; } } # Close the file. close($file_handle); return $file_line; } sub extractth{ # Extract .TH section as an array. my $input = shift; # Split the line into an array. my @tharray; my $inputsize = length($input); my $inputcurrent = ""; my $quotemode = 0; for(my $inputseek = 0; $inputseek < $inputsize; $inputseek++) { if(substr($input, $inputseek, 1) eq " " && $quotemode eq 0) { push(@tharray, $inputcurrent); $inputcurrent = ""; next; } $inputcurrent = $inputcurrent . substr($input, $inputseek, 1); if(substr($input, $inputseek, 1) eq "\"") { if($quotemode eq 0) { $quotemode = 1; } else { $quotemode = 0; } } } if($inputcurrent ne "") { push(@tharray, $inputcurrent); } return @tharray; } sub getdate{ # Get the date from the .TH section. my $filename = shift; my $thline; my @tharray; my $date = ""; $thline = getthline($filename); # Return nothing if there is no .TH section found. if(!$thline || $thline eq "") { return ""; } @tharray = extractth($thline); # Remove the quotes at the start and end. $date = substr($tharray[3], 1, -1); return $date; } sub processth{ # Process .TH section. my $input = shift; my $date = shift; # Split the line into an array. my @tharray = extractth($input); # Alter the date. my $itemdate = "\""; $itemdate .= $date; $itemdate .= "\""; $tharray[3] = $itemdate; # Alter the item version. my $itemver = $tharray[4]; my $itemname = ""; for(my $itemnameseek = 1; $itemnameseek < length($itemver); $itemnameseek++) { if(substr($itemver, $itemnameseek, 1) eq " " || substr($itemver, $itemnameseek, 1) eq "\"") { last; } $itemname .= substr($itemver, $itemnameseek, 1); } $itemver = "\""; $itemver .= $itemname; $itemver .= " "; $itemver .= $curlver; $itemver .= "\""; $tharray[4] = $itemver; my $thoutput = ""; foreach my $thvalue (@tharray) { $thoutput .= $thvalue; $thoutput .= " "; } $thoutput =~ s/\s+$//; $thoutput .= "\n"; # Return updated string. return $thoutput; } sub processfile{ # Process file looking for .TH section. my $filename = shift; my $date = shift; my $file_handle; my $file_dist_handle; my $filename_dist; # Open a handle for the original file and a second file handle # for the dist file. $filename_dist = $filename . ".dist"; open($file_handle, $filename); open($file_dist_handle, ">" . $filename_dist); # Look for the .TH section, process it into an array, # modify it and write to file. tie(my @file_data, 'Tie::File', $filename); foreach my $file_data_line (@file_data) { if($file_data_line =~ /^.TH/) { my $file_dist_line = processth($file_data_line, $date); print $file_dist_handle $file_dist_line . "\n"; } else { print $file_dist_handle $file_data_line . "\n"; } } # Close the file. close($file_handle); close($file_dist_handle); } # Check that $curlver is set, otherwise print arguments and exit. if(!$curlver) { printargs(); } # check to see that the git command works, it requires git 2.6 something my $gitcheck = `git log -1 --date="format:%B %d, %Y" $dirlist[0] 2>/dev/null`; if(length($gitcheck) < 1) { print "git version too old or $dirlist[0] is a bad argument\n"; exit; } # Look in each directory. my $dir_handle; foreach my $dirname (@dirlist) { foreach my $extname (@extlist) { # Go through the directory looking for files ending with # the current extension. opendir($dir_handle, $dirname); my @filelist = grep(/.$extname$/i, readdir($dir_handle)); foreach my $file (@filelist) { # Skip if file is in exclude list. if(grep(/^$file$/, @excludelist)) { next; } # Load the file and get the date. my $filedate; # Check if dist version exists and load date from that # file if it does. if(-e ($dirname . $file . ".dist")) { $filedate = getdate(($dirname . $file . ".dist")); } else { $filedate = getdate(($dirname . $file)); } # Skip if value is empty. if(!$filedate || $filedate eq "") { next; } # Check the man page in the git repository. my $repodata = `LC_TIME=C git log -1 --date="format:%B %d, %Y" \\ --since="$filedate" $dirname$file | grep ^Date:`; # If there is output then update the man page # with the new date/version. # Process the file if there is output. if($repodata) { my $thisdate; if(!$curldate) { if($repodata =~ /^Date: +(.*)/) { $thisdate = $1; } else { print STDERR "Warning: " . ($dirname . $file) . ": found no " . "date\n"; } } else { $thisdate = $curldate; } processfile(($dirname . $file), $thisdate); print $dirname . $file . " page updated to $thisdate\n"; } } closedir($dir_handle); } } __END__ =pod =head1 updatemanpages.pl Updates the man pages with the version number and optional date. If the date isn't provided, the last modified date from git is used. =head2 USAGE updatemanpages.pl version [date] =head3 version Specifies version (required) =head3 date Specifies date (optional) =head2 SETTINGS =head3 @dirlist Specifies the list of directories to look for files in. =head3 @extlist Specifies the list of files with extensions to process. =head3 @excludelist Specifies the list of files to not process. =head2 NOTES This script is used during maketgz. =cut davix-0.8.0/deps/curl/CHANGES0000644000000000000000000000050214121063461014216 0ustar rootrootSee https://curl.haxx.se/changes.html for the edited and human readable online version of what has changed over the years in different curl releases. Generate a CHANGES file like the one present in every release like this: $ git log --pretty=fuller --no-color --date=short --decorate=full | \ ./scripts/log2changes.pl davix-0.8.0/deps/curl/SECURITY.md0000644000000000000000000000056214121063461015022 0ustar rootroot# Security Policy See [docs/SECURITY-PROCESS.md](docs/SECURITY-PROCESS.md) for full details. ## Reporting a Vulnerability If you have found or just suspect a security problem somewhere in curl or libcurl, report it on [https://hackerone.com/curl](https://hackerone.com/curl). We treat security issuse with confidentiality until disclosed controlled and responsibly. davix-0.8.0/deps/curl/.mailmap0000644000000000000000000000606414121063461014655 0ustar rootrootGuenter Knauf Gisle Vanem Gisle Vanem Alessandro Ghedini Alessandro Ghedini Björn Stenberg Björn Stenberg Viktor Szakats Viktor Szakats Daniel Gustafsson Daniel Gustafsson Linus Nielsen Yamada Yasuharu Ulion Tim Rühsen Steve Holme Claes Jakobsson Sergei Nikulov Patrick Monnerat Patrick Monnerat Patrick Monnerat Patrick Monnerat Nick Zitzmann Peter Wu David Woodhouse Marcel Raad Marcel Raad Marcel Raad Anthony Bryan Travis Burtrum Dmitry Kostjuchenko Richard Alcock Richard Alcock Jan Ehrhardt Florin Petriuc Pavel Pavlov Jason Juang Carlo Teubner Joel Depooter Sebastian Mundry Rainer Canavan Dan Fandrich Henrik S. Gaßmann Jiří Malák Nick Zitzmann Kees Dekker Max Savenkov Daniel Jelinski <30433125+djelinski@users.noreply.github.com> Amit Katyal Giorgos Oikonomou Evgeny Grin Peter Pih Anton Malov Marquis de Muesli Kyohei Kadota Lucas Pardue Massimiliano Fantuzzi Niall O'Reilly Mohammad Hasbini Andrew Ishchuk Nicolas Guillier <59726521+nicoguillier@users.noreply.github.com> davix-0.8.0/deps/curl/buildconf0000755000000000000000000003414714121063461015132 0ustar rootroot#!/bin/sh #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### #-------------------------------------------------------------------------- # die prints argument string to stdout and exits this shell script. # die(){ echo "buildconf: $@" exit 1 } #-------------------------------------------------------------------------- # findtool works as 'which' but we use a different name to make it more # obvious we aren't using 'which'! ;-) # Unlike 'which' does, the current directory is ignored. # findtool(){ file="$1" if { echo "$file" | grep "/" >/dev/null 2>&1; } then # when file is given with a path check it first if test -f "$file"; then echo "$file" return fi fi old_IFS=$IFS; IFS=':' for path in $PATH do IFS=$old_IFS # echo "checks for $file in $path" >&2 if test "$path" -a "$path" != '.' -a -f "$path/$file"; then echo "$path/$file" return fi done IFS=$old_IFS } #-------------------------------------------------------------------------- # removethis() removes all files and subdirectories with the given name, # inside and below the current subdirectory at invocation time. # removethis(){ if test "$#" = "1"; then find . -depth -name $1 -print > buildconf.tmp.$$ while read fdname do if test -f "$fdname"; then rm -f "$fdname" elif test -d "$fdname"; then rm -f -r "$fdname" fi done < buildconf.tmp.$$ rm -f buildconf.tmp.$$ fi } #-------------------------------------------------------------------------- # Ensure that buildconf runs from the subdirectory where configure.ac lives # if test ! -f configure.ac || test ! -f src/tool_main.c || test ! -f lib/urldata.h || test ! -f include/curl/curl.h || test ! -f m4/curl-functions.m4; then echo "Can not run buildconf from outside of curl's source subdirectory!" echo "Change to the subdirectory where buildconf is found, and try again." exit 1 fi #-------------------------------------------------------------------------- # autoconf 2.57 or newer. Unpatched version 2.67 does not generate proper # configure script. Unpatched version 2.68 is simply unusable, we should # disallow 2.68 usage. # need_autoconf="2.57" ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|head -n 1| sed -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` if test -z "$ac_version"; then echo "buildconf: autoconf not found." echo " You need autoconf version $need_autoconf or newer installed." exit 1 fi old_IFS=$IFS; IFS='.'; set $ac_version; IFS=$old_IFS if test "$1" = "2" -a "$2" -lt "57" || test "$1" -lt "2"; then echo "buildconf: autoconf version $ac_version found." echo " You need autoconf version $need_autoconf or newer installed." echo " If you have a sufficient autoconf installed, but it" echo " is not named 'autoconf', then try setting the" echo " AUTOCONF environment variable." exit 1 fi if test "$1" = "2" -a "$2" -eq "67"; then echo "buildconf: autoconf version $ac_version (BAD)" echo " Unpatched version generates broken configure script." elif test "$1" = "2" -a "$2" -eq "68"; then echo "buildconf: autoconf version $ac_version (BAD)" echo " Unpatched version generates unusable configure script." else echo "buildconf: autoconf version $ac_version (ok)" fi am4te_version=`${AUTOM4TE:-autom4te} --version 2>/dev/null|head -n 1| sed -e 's/autom4te\(.*\)/\1/' -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` if test -z "$am4te_version"; then echo "buildconf: autom4te not found. Weird autoconf installation!" exit 1 fi if test "$am4te_version" = "$ac_version"; then echo "buildconf: autom4te version $am4te_version (ok)" else echo "buildconf: autom4te version $am4te_version (ERROR: does not match autoconf version)" exit 1 fi #-------------------------------------------------------------------------- # autoheader 2.50 or newer # ah_version=`${AUTOHEADER:-autoheader} --version 2>/dev/null|head -n 1| sed -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` if test -z "$ah_version"; then echo "buildconf: autoheader not found." echo " You need autoheader version 2.50 or newer installed." exit 1 fi old_IFS=$IFS; IFS='.'; set $ah_version; IFS=$old_IFS if test "$1" = "2" -a "$2" -lt "50" || test "$1" -lt "2"; then echo "buildconf: autoheader version $ah_version found." echo " You need autoheader version 2.50 or newer installed." echo " If you have a sufficient autoheader installed, but it" echo " is not named 'autoheader', then try setting the" echo " AUTOHEADER environment variable." exit 1 fi echo "buildconf: autoheader version $ah_version (ok)" #-------------------------------------------------------------------------- # automake 1.7 or newer # need_automake="1.7" am_version=`${AUTOMAKE:-automake} --version 2>/dev/null|head -n 1| sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//' -e 's/\(.*\)\(-p.*\)/\1/'` if test -z "$am_version"; then echo "buildconf: automake not found." echo " You need automake version $need_automake or newer installed." exit 1 fi old_IFS=$IFS; IFS='.'; set $am_version; IFS=$old_IFS if test "$1" = "1" -a "$2" -lt "7" || test "$1" -lt "1"; then echo "buildconf: automake version $am_version found." echo " You need automake version $need_automake or newer installed." echo " If you have a sufficient automake installed, but it" echo " is not named 'automake', then try setting the" echo " AUTOMAKE environment variable." exit 1 fi echo "buildconf: automake version $am_version (ok)" acloc_version=`${ACLOCAL:-aclocal} --version 2>/dev/null|head -n 1| sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//' -e 's/\(.*\)\(-p.*\)/\1/'` if test -z "$acloc_version"; then echo "buildconf: aclocal not found. Weird automake installation!" exit 1 fi if test "$acloc_version" = "$am_version"; then echo "buildconf: aclocal version $acloc_version (ok)" else echo "buildconf: aclocal version $acloc_version (ERROR: does not match automake version)" exit 1 fi #-------------------------------------------------------------------------- # GNU libtoolize preliminary check # want_lt_major=1 want_lt_minor=4 want_lt_patch=2 want_lt_version=1.4.2 # This approach that tries 'glibtoolize' first is intended for systems that # have GNU libtool named as 'glibtoolize' and libtoolize not being GNU's. libtoolize=`findtool glibtoolize 2>/dev/null` if test ! -x "$libtoolize"; then libtoolize=`findtool ${LIBTOOLIZE:-libtoolize}` fi if test -z "$libtoolize"; then echo "buildconf: libtoolize not found." echo " You need GNU libtoolize $want_lt_version or newer installed." exit 1 fi lt_pver=`$libtoolize --version 2>/dev/null|head -n 1` lt_qver=`echo $lt_pver|sed -e "s/([^)]*)//g" -e "s/^[^0-9]*//g"` lt_version=`echo $lt_qver|sed -e "s/[- ].*//" -e "s/\([a-z]*\)$//"` if test -z "$lt_version"; then echo "buildconf: libtoolize not found." echo " You need GNU libtoolize $want_lt_version or newer installed." exit 1 fi old_IFS=$IFS; IFS='.'; set $lt_version; IFS=$old_IFS lt_major=$1 lt_minor=$2 lt_patch=$3 if test -z "$lt_major"; then lt_status="bad" elif test "$lt_major" -gt "$want_lt_major"; then lt_status="good" elif test "$lt_major" -lt "$want_lt_major"; then lt_status="bad" elif test -z "$lt_minor"; then lt_status="bad" elif test "$lt_minor" -gt "$want_lt_minor"; then lt_status="good" elif test "$lt_minor" -lt "$want_lt_minor"; then lt_status="bad" elif test -z "$lt_patch"; then lt_status="bad" elif test "$lt_patch" -gt "$want_lt_patch"; then lt_status="good" elif test "$lt_patch" -lt "$want_lt_patch"; then lt_status="bad" else lt_status="good" fi if test "$lt_status" != "good"; then echo "buildconf: libtoolize version $lt_version found." echo " You need GNU libtoolize $want_lt_version or newer installed." exit 1 fi echo "buildconf: libtoolize version $lt_version (ok)" #-------------------------------------------------------------------------- # m4 check # m4=`(${M4:-m4} --version 0<&- || ${M4:-gm4} --version) 2>/dev/null 0<&- | head -n 1`; m4_version=`echo $m4 | sed -e 's/^.* \([0-9]\)/\1/' -e 's/[a-z]* *$//'` if { echo $m4 | grep "GNU" >/dev/null 2>&1; } then echo "buildconf: GNU m4 version $m4_version (ok)" else if test -z "$m4"; then echo "buildconf: m4 version not recognized. You need a GNU m4 installed!" else echo "buildconf: m4 version $m4 found. You need a GNU m4 installed!" fi exit 1 fi #-------------------------------------------------------------------------- # perl check # PERL=`findtool ${PERL:-perl}` if test -z "$PERL"; then echo "buildconf: perl not found" exit 1 fi #-------------------------------------------------------------------------- # Remove files generated on previous buildconf/configure run. # for fname in .deps \ .libs \ *.la \ *.lo \ *.a \ *.o \ Makefile \ Makefile.in \ aclocal.m4 \ aclocal.m4.bak \ ares_build.h \ ares_config.h \ ares_config.h.in \ autom4te.cache \ compile \ config.guess \ curl_config.h \ curl_config.h.in \ config.log \ config.lt \ config.status \ config.sub \ configure \ configurehelp.pm \ curl-config \ depcomp \ libcares.pc \ libcurl.pc \ libtool \ libtool.m4 \ libtool.m4.tmp \ ltmain.sh \ ltoptions.m4 \ ltsugar.m4 \ ltversion.m4 \ lt~obsolete.m4 \ missing \ install-sh \ stamp-h1 \ stamp-h2 \ stamp-h3 ; do removethis "$fname" done #-------------------------------------------------------------------------- # run the correct scripts now # echo "buildconf: running libtoolize" ${libtoolize} --copy --force || die "libtoolize command failed" # When using libtool 1.5.X (X < 26) we copy libtool.m4 to our local m4 # subdirectory and this local copy is patched to fix some warnings that # are triggered when running aclocal and using autoconf 2.62 or later. if test "$lt_major" = "1" && test "$lt_minor" = "5"; then if test -z "$lt_patch" || test "$lt_patch" -lt "26"; then echo "buildconf: copying libtool.m4 to local m4 subdir" ac_dir=`${ACLOCAL:-aclocal} --print-ac-dir` if test -f $ac_dir/libtool.m4; then cp -f $ac_dir/libtool.m4 m4/libtool.m4 else echo "buildconf: $ac_dir/libtool.m4 not found" fi if test -f m4/libtool.m4; then echo "buildconf: renaming some variables in local m4/libtool.m4" $PERL -i.tmp -pe \ 's/lt_prog_compiler_pic_works/lt_cv_prog_compiler_pic_works/g; \ s/lt_prog_compiler_static_works/lt_cv_prog_compiler_static_works/g;' \ m4/libtool.m4 rm -f m4/libtool.m4.tmp fi fi fi if test -f m4/libtool.m4; then echo "buildconf: converting all mv to mv -f in local m4/libtool.m4" $PERL -i.tmp -pe 's/\bmv +([^-\s])/mv -f $1/g' m4/libtool.m4 rm -f m4/libtool.m4.tmp fi echo "buildconf: running aclocal" ${ACLOCAL:-aclocal} -I m4 $ACLOCAL_FLAGS || die "aclocal command failed" echo "buildconf: converting all mv to mv -f in local aclocal.m4" $PERL -i.bak -pe 's/\bmv +([^-\s])/mv -f $1/g' aclocal.m4 echo "buildconf: running autoheader" ${AUTOHEADER:-autoheader} || die "autoheader command failed" echo "buildconf: running autoconf" ${AUTOCONF:-autoconf} || die "autoconf command failed" if test -d ares; then cd ares echo "buildconf: running in ares" ./buildconf cd .. fi echo "buildconf: running automake" ${AUTOMAKE:-automake} --add-missing --copy || die "automake command failed" #-------------------------------------------------------------------------- # GNU libtool complementary check # # Depending on the libtool and automake versions being used, config.guess # might not be installed in the subdirectory until automake has finished. # So we can not attempt to use it until this very last buildconf stage. # if test ! -f ./config.guess; then echo "buildconf: config.guess not found" else buildhost=`./config.guess 2>/dev/null|head -n 1` case $buildhost in *-*-darwin*) need_lt_major=1 need_lt_minor=5 need_lt_patch=26 need_lt_check="yes" ;; *-*-hpux*) need_lt_major=1 need_lt_minor=5 need_lt_patch=24 need_lt_check="yes" ;; esac if test ! -z "$need_lt_check"; then if test -z "$lt_major"; then lt_status="bad" elif test "$lt_major" -gt "$need_lt_major"; then lt_status="good" elif test "$lt_major" -lt "$need_lt_major"; then lt_status="bad" elif test -z "$lt_minor"; then lt_status="bad" elif test "$lt_minor" -gt "$need_lt_minor"; then lt_status="good" elif test "$lt_minor" -lt "$need_lt_minor"; then lt_status="bad" elif test -z "$lt_patch"; then lt_status="bad" elif test "$lt_patch" -gt "$need_lt_patch"; then lt_status="good" elif test "$lt_patch" -lt "$need_lt_patch"; then lt_status="bad" else lt_status="good" fi if test "$lt_status" != "good"; then need_lt_version="$need_lt_major.$need_lt_minor.$need_lt_patch" echo "buildconf: libtool version $lt_version found." echo " $buildhost requires GNU libtool $need_lt_version or newer installed." rm -f configure exit 1 fi fi fi #-------------------------------------------------------------------------- # Finished successfully. # echo "buildconf: OK" exit 0 davix-0.8.0/deps/curl/.azure-pipelines.yml0000644000000000000000000003453214121063461017152 0ustar rootroot# Starter pipeline # Start with a minimal pipeline that you can customize to build and deploy your code. # Add steps that build, run tests, deploy, and more: # https://aka.ms/yaml trigger: - 'master' - '*/ci' stages: ########################################## ### Linux jobs first ########################################## - stage: linux dependsOn: [] jobs: - job: vanilla displayName: ubuntu default timeoutInMinutes: 20 pool: vmImage: 'ubuntu-latest' steps: - script: ./buildconf && ./configure --enable-debug --enable-werror displayName: 'configure debug' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: disable_ipv6 displayName: ubuntu w/o IPv6 timeoutInMinutes: 20 pool: vmImage: 'ubuntu-latest' steps: - script: ./buildconf && ./configure --disable-ipv6 displayName: 'configure disable ipv6' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: disable_http_smtp_imap displayName: ubuntu w/o HTTP/SMTP/IMAP timeoutInMinutes: 20 pool: vmImage: 'ubuntu-latest' steps: - script: ./buildconf && ./configure --disable-http --disable-smtp --disable-imap displayName: 'configure disable http/smtp/imap' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: disable_thredres displayName: ubuntu sync resolver timeoutInMinutes: 20 pool: vmImage: 'ubuntu-latest' steps: - script: ./buildconf && ./configure --disable-threaded-resolver displayName: 'configure disable threaded-resolver' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: http_only displayName: ubuntu HTTP only timeoutInMinutes: 20 pool: vmImage: 'ubuntu-latest' steps: - script: ./buildconf && ./configure --disable-dict --disable-file --disable-ftp --disable-gopher --disable-imap --disable-ldap --disable-pop3 --disable-rtmp --disable-rtsp --disable-scp --disable-sftp --disable-smb --disable-smtp --disable-telnet --disable-tftp displayName: 'configure disable non-http' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - stage: linux_torture dependsOn: linux jobs: - job: torture displayName: ubuntu torture tests timeoutInMinutes: 50 pool: vmImage: 'ubuntu-latest' steps: - script: sudo apt install libnghttp2-dev displayName: 'apt install' - script: ./buildconf && ./configure --enable-debug --disable-shared --disable-threaded-resolver --enable-alt-svc displayName: 'configure torture' - script: make displayName: 'make' - script: make "TFLAGS=-n -t --shallow=40 '!FTP'" test-nonflaky displayName: 'torture test' ########################################## ### macOS jobs below ########################################## - stage: macos dependsOn: [] jobs: - job: macos_vanilla displayName: macos default timeoutInMinutes: 30 pool: vmImage: 'macOS-latest' steps: - script: brew update && brew install libtool autoconf automake nghttp2 pkg-config displayName: 'brew install' - script: ./buildconf && ./configure --enable-debug --enable-werror --without-brotli displayName: 'configure debug without brotli' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: macos_libssh2 displayName: macos libssh2 timeoutInMinutes: 30 pool: vmImage: 'macOS-latest' steps: - script: brew update && brew install libtool autoconf automake nghttp2 pkg-config libssh2 displayName: 'brew install' - script: ./buildconf && ./configure --enable-debug --with-libssh2 displayName: 'configure debug with libssh2' - script: make displayName: 'make' - script: make test-nonflaky displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: macos_cmake displayName: macos cmake openssl timeoutInMinutes: 20 pool: vmImage: 'macOS-latest' steps: - script: brew update && brew install libtool autoconf automake nghttp2 pkg-config openssl displayName: 'brew install' - script: cmake -H. -Bbuild -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCURL_DISABLE_LDAP=ON -DCURL_DISABLE_LDAPS=ON && cmake --build build displayName: 'cmake build' - stage: macos_torture dependsOn: macos jobs: - job: macos_torture displayName: macos torture timeoutInMinutes: 50 pool: vmImage: 'macOS-latest' steps: - script: brew update && brew install libtool autoconf automake nghttp2 pkg-config displayName: 'brew install' - script: ./buildconf && ./configure --enable-debug --disable-shared --disable-threaded-resolver --enable-alt-svc displayName: 'configure torture' - script: make displayName: 'make' - script: make "TFLAGS=-n -t --shallow=25 '!FTP'" test-nonflaky displayName: 'torture test' ########################################## ### Windows jobs below ########################################## - stage: windows dependsOn: [] jobs: - job: windows_msys2_mingw32_debug_openssl displayName: msys2 mingw32 debug openssl timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys2-mingw32:ltsc2019 env: MSYSTEM: MINGW32 MSYS2_PATH_TYPE: inherit TFLAGS: "~323 ~1056 ~1299" steps: - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-w64-mingw32 --build=i686-w64-mingw32 --enable-debug --enable-werror" displayName: 'configure debug' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys2_mingw64_debug_openssl displayName: msys2 mingw64 debug openssl timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys2-mingw64:ltsc2019 env: MSYSTEM: MINGW64 MSYS2_PATH_TYPE: inherit TFLAGS: "~323 ~1056 ~1299" steps: - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --enable-debug --enable-werror" displayName: 'configure debug' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw_debug_openssl displayName: msys1 mingw debug openssl timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw:ltsc2019 env: TFLAGS: "~203 ~1056 ~1143" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-pc-mingw32 --build=i686-pc-mingw32 --prefix=/mingw --enable-debug" displayName: 'configure debug' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw32_debug_openssl displayName: msys1 mingw32 debug openssl timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw32:ltsc2019 env: TFLAGS: "~203 ~1056 ~1143 ~1299" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-w64-mingw32 --build=i686-w64-mingw32 --prefix=/mingw32 --enable-debug --enable-werror --without-zlib" displayName: 'configure debug without zlib' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw64_debug_openssl displayName: msys1 mingw64 debug openssl timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw64:ltsc2019 env: TFLAGS: "~203 ~1056 ~1143 ~1299" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --prefix=/mingw64 --enable-debug --enable-werror --without-zlib" displayName: 'configure debug without zlib' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys2_mingw32_debug_schannel displayName: msys2 mingw32 debug schannel timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys2-mingw32:ltsc2019 env: MSYSTEM: MINGW32 MSYS2_PATH_TYPE: inherit TFLAGS: "~165 ~310 ~1013 ~1056 ~1299 ~1448 ~2034 ~2037 ~2041 ~2046 ~2047 ~3000 ~3001" steps: - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-w64-mingw32 --build=i686-w64-mingw32 --enable-debug --enable-werror --enable-sspi --without-ssl --with-schannel --with-winidn" displayName: 'configure debug with sspi/schannel/winidn' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys2_mingw64_debug_schannel displayName: msys2 mingw64 debug schannel timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys2-mingw64:ltsc2019 env: MSYSTEM: MINGW64 MSYS2_PATH_TYPE: inherit TFLAGS: "~165 ~310 ~1013 ~1056 ~1299 ~1448 ~2034 ~2037 ~2041 ~2046 ~2047 ~3000 ~3001" steps: - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --enable-debug --enable-werror --enable-sspi --without-ssl --with-schannel --with-winidn" displayName: 'configure debug with sspi/schannel/winidn' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\msys64\usr\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw_debug_schannel displayName: msys1 mingw debug schannel timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw:ltsc2019 env: TFLAGS: "~203 ~305 ~310 ~311 ~312 ~313 ~404 ~1013 ~1056 ~1143 ~2034 ~2035 ~2037 ~2038 ~2041 ~2042 ~2048 ~3000 ~3001" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-pc-mingw32 --build=i686-pc-mingw32 --prefix=/mingw --enable-debug --enable-sspi --without-ssl --with-schannel --with-winidn" displayName: 'configure debug with sspi/schannel/winidn' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw32_debug_schannel displayName: msys1 mingw32 debug schannel timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw32:ltsc2019 env: TFLAGS: "~203 ~310 ~1013 ~1056 ~1143 ~1299 ~2034 ~2037 ~2041 ~3000 ~3001" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=i686-w64-mingw32 --build=i686-w64-mingw32 --prefix=/mingw32 --enable-debug --enable-werror --enable-sspi --without-ssl --with-schannel --with-winidn --without-zlib" displayName: 'configure debug with sspi/schannel/winidn without zlib' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" - job: windows_msys1_mingw64_debug_schannel displayName: msys1 mingw64 debug schannel timeoutInMinutes: 70 pool: vmImage: 'windows-2019' container: image: mback2k/curl-docker-winbuildenv-msys1-mingw64:ltsc2019 env: TFLAGS: "~203 ~310 ~1013 ~1056 ~1143 ~1299 ~2034 ~2037 ~2041 ~3000 ~3001" steps: - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && ./buildconf && ./configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --prefix=/mingw64 --enable-debug --enable-werror --enable-sspi --without-ssl --with-schannel --with-winidn --without-zlib" displayName: 'configure debug with sspi/schannel/winidn without zlib' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make" displayName: 'make' - script: C:\MinGW\msys\1.0\bin\sh -l -c "cd $(echo '%cd%') && make test-nonflaky" displayName: 'test' env: AZURE_ACCESS_TOKEN: "$(System.AccessToken)" davix-0.8.0/deps/curl/include/0000755000000000000000000000000014121063461014651 5ustar rootrootdavix-0.8.0/deps/curl/include/README0000644000000000000000000000132514121063461015532 0ustar rootroot _ _ ____ _ ___| | | | _ \| | / __| | | | |_) | | | (__| |_| | _ <| |___ \___|\___/|_| \_\_____| Include files for libcurl, external users. They're all placed in the curl subdirectory here for better fit in any kind of environment. You must include files from here using... #include ... style and point the compiler's include path to the directory holding the curl subdirectory. It makes it more likely to survive future modifications. The public curl include files can be shared freely between different platforms and different architectures. davix-0.8.0/deps/curl/include/Makefile.am0000644000000000000000000000012014121063461016676 0ustar rootrootSUBDIRS = curl EXTRA_DIST = README AUTOMAKE_OPTIONS = foreign no-dependencies davix-0.8.0/deps/curl/include/curl/0000755000000000000000000000000014121063461015616 5ustar rootrootdavix-0.8.0/deps/curl/include/curl/Makefile.am0000644000000000000000000000265414121063461017661 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### pkginclude_HEADERS = \ curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ typecheck-gcc.h system.h urlapi.h pkgincludedir= $(includedir)/curl CHECKSRC = $(CS_$(V)) CS_0 = @echo " RUN " $@; CS_1 = CS_ = $(CS_0) checksrc: $(CHECKSRC)@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) if CURLDEBUG # for debug builds, we scan the sources on all regular make invokes all-local: checksrc endif davix-0.8.0/deps/curl/include/curl/easy.h0000644000000000000000000000707314121063461016737 0ustar rootroot#ifndef CURLINC_EASY_H #define CURLINC_EASY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif CURL_EXTERN CURL *curl_easy_init(void); CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); CURL_EXTERN void curl_easy_cleanup(CURL *curl); /* * NAME curl_easy_getinfo() * * DESCRIPTION * * Request internal information from the curl session with this function. The * third argument MUST be a pointer to a long, a pointer to a char * or a * pointer to a double (as the documentation describes elsewhere). The data * pointed to will be filled in accordingly and can be relied upon only if the * function returns CURLE_OK. This function is intended to get used *AFTER* a * performed transfer, all results from this function are undefined until the * transfer is completed. */ CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); /* * NAME curl_easy_duphandle() * * DESCRIPTION * * Creates a new curl session handle with the same options set for the handle * passed in. Duplicating a handle could only be a matter of cloning data and * options, internal state info and things like persistent connections cannot * be transferred. It is useful in multithreaded applications when you can run * curl_easy_duphandle() for each new thread to avoid a series of identical * curl_easy_setopt() invokes in every thread. */ CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); /* * NAME curl_easy_reset() * * DESCRIPTION * * Re-initializes a CURL handle to the default values. This puts back the * handle to the same state as it was in when it was just created. * * It does keep: live connections, the Session ID cache, the DNS cache and the * cookies. */ CURL_EXTERN void curl_easy_reset(CURL *curl); /* * NAME curl_easy_recv() * * DESCRIPTION * * Receives data from the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n); /* * NAME curl_easy_send() * * DESCRIPTION * * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, size_t *n); /* * NAME curl_easy_upkeep() * * DESCRIPTION * * Performs connection upkeep for the given session handle. */ CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); #ifdef __cplusplus } #endif #endif davix-0.8.0/deps/curl/include/curl/mprintf.h0000644000000000000000000000403214121063461017445 0ustar rootroot#ifndef CURLINC_MPRINTF_H #define CURLINC_MPRINTF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #include /* needed for FILE */ #include "curl.h" /* for CURL_EXTERN */ #ifdef __cplusplus extern "C" { #endif CURL_EXTERN int curl_mprintf(const char *format, ...); CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...); CURL_EXTERN int curl_mvprintf(const char *format, va_list args); CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args); CURL_EXTERN char *curl_maprintf(const char *format, ...); CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); #ifdef __cplusplus } #endif #endif /* CURLINC_MPRINTF_H */ davix-0.8.0/deps/curl/include/curl/stdcheaders.h0000644000000000000000000000250014121063461020255 0ustar rootroot#ifndef CURLINC_STDCHEADERS_H #define CURLINC_STDCHEADERS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include size_t fread(void *, size_t, size_t, FILE *); size_t fwrite(const void *, size_t, size_t, FILE *); int strcasecmp(const char *, const char *); int strncasecmp(const char *, const char *, size_t); #endif /* CURLINC_STDCHEADERS_H */ davix-0.8.0/deps/curl/include/curl/multi.h0000644000000000000000000004130114121063461017120 0ustar rootroot#ifndef CURLINC_MULTI_H #define CURLINC_MULTI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* This is an "external" header file. Don't give away any internals here! GOALS o Enable a "pull" interface. The application that uses libcurl decides where and when to ask libcurl to get/send data. o Enable multiple simultaneous transfers in the same thread without making it complicated for the application. o Enable the application to select() on its own file descriptors and curl's file descriptors simultaneous easily. */ /* * This header file should not really need to include "curl.h" since curl.h * itself includes this file and we expect user applications to do #include * without the need for especially including multi.h. * * For some reason we added this include here at one point, and rather than to * break existing (wrongly written) libcurl applications, we leave it as-is * but with this warning attached. */ #include "curl.h" #ifdef __cplusplus extern "C" { #endif #if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) typedef struct Curl_multi CURLM; #else typedef void CURLM; #endif typedef enum { CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or curl_multi_socket*() soon */ CURLM_OK, CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was attempted to get added - again */ CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a callback */ CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ CURLM_LAST } CURLMcode; /* just to make code nicer when using curl_multi_socket() you can now check for CURLM_CALL_MULTI_SOCKET too in the same style it works for curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM /* bitmask bits for CURLMOPT_PIPELINING */ #define CURLPIPE_NOTHING 0L #define CURLPIPE_HTTP1 1L #define CURLPIPE_MULTIPLEX 2L typedef enum { CURLMSG_NONE, /* first, not used */ CURLMSG_DONE, /* This easy handle has completed. 'result' contains the CURLcode of the transfer */ CURLMSG_LAST /* last, not used */ } CURLMSG; struct CURLMsg { CURLMSG msg; /* what this message means */ CURL *easy_handle; /* the handle it concerns */ union { void *whatever; /* message-specific data */ CURLcode result; /* return code for transfer */ } data; }; typedef struct CURLMsg CURLMsg; /* Based on poll(2) structure and values. * We don't use pollfd and POLL* constants explicitly * to cover platforms without poll(). */ #define CURL_WAIT_POLLIN 0x0001 #define CURL_WAIT_POLLPRI 0x0002 #define CURL_WAIT_POLLOUT 0x0004 struct curl_waitfd { curl_socket_t fd; short events; short revents; /* not supported yet */ }; /* * Name: curl_multi_init() * * Desc: inititalize multi-style curl usage * * Returns: a new CURLM handle to use in all 'curl_multi' functions. */ CURL_EXTERN CURLM *curl_multi_init(void); /* * Name: curl_multi_add_handle() * * Desc: add a standard curl handle to the multi stack * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *curl_handle); /* * Name: curl_multi_remove_handle() * * Desc: removes a curl handle from the multi stack again * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle); /* * Name: curl_multi_fdset() * * Desc: Ask curl for its fd_set sets. The app can use these to select() or * poll() on. We want curl_multi_perform() called as soon as one of * them are ready. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd); /* * Name: curl_multi_wait() * * Desc: Poll on all fds within a CURLM set as well as any * additional fds passed to the function. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret); /* * Name: curl_multi_poll() * * Desc: Poll on all fds within a CURLM set as well as any * additional fds passed to the function. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret); /* * Name: curl_multi_wakeup() * * Desc: wakes up a sleeping curl_multi_poll call. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle); /* * Name: curl_multi_perform() * * Desc: When the app thinks there's data available for curl it calls this * function to read/write whatever there is right now. This returns * as soon as the reads and writes are done. This function does not * require that there actually is data available for reading or that * data can be written, it can be called just in case. It returns * the number of handles that still transfer data in the second * argument's integer-pointer. * * Returns: CURLMcode type, general multi error code. *NOTE* that this only * returns errors etc regarding the whole multi stack. There might * still have occurred problems on individual transfers even when * this returns OK. */ CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles); /* * Name: curl_multi_cleanup() * * Desc: Cleans up and removes a whole multi stack. It does not free or * touch any individual easy handles in any way. We need to define * in what state those handles will be if this function is called * in the middle of a transfer. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); /* * Name: curl_multi_info_read() * * Desc: Ask the multi handle if there's any messages/informationals from * the individual transfers. Messages include informationals such as * error code from the transfer or just the fact that a transfer is * completed. More details on these should be written down as well. * * Repeated calls to this function will return a new struct each * time, until a special "end of msgs" struct is returned as a signal * that there is no more to get at this point. * * The data the returned pointer points to will not survive calling * curl_multi_cleanup(). * * The 'CURLMsg' struct is meant to be very simple and only contain * very basic information. If more involved information is wanted, * we will provide the particular "transfer handle" in that struct * and that should/could/would be used in subsequent * curl_easy_getinfo() calls (or similar). The point being that we * must never expose complex structs to applications, as then we'll * undoubtably get backwards compatibility problems in the future. * * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out * of structs. It also writes the number of messages left in the * queue (after this read) in the integer the second argument points * to. */ CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue); /* * Name: curl_multi_strerror() * * Desc: The curl_multi_strerror function may be used to turn a CURLMcode * value into the equivalent human readable error string. This is * useful for printing meaningful error messages. * * Returns: A pointer to a zero-terminated error message. */ CURL_EXTERN const char *curl_multi_strerror(CURLMcode); /* * Name: curl_multi_socket() and * curl_multi_socket_all() * * Desc: An alternative version of curl_multi_perform() that allows the * application to pass in one of the file descriptors that have been * detected to have "action" on them and let libcurl perform. * See man page for details. */ #define CURL_POLL_NONE 0 #define CURL_POLL_IN 1 #define CURL_POLL_OUT 2 #define CURL_POLL_INOUT 3 #define CURL_POLL_REMOVE 4 #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD #define CURL_CSELECT_IN 0x01 #define CURL_CSELECT_OUT 0x02 #define CURL_CSELECT_ERR 0x04 typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ void *userp, /* private callback pointer */ void *socketp); /* private socket pointer */ /* * Name: curl_multi_timer_callback * * Desc: Called by libcurl whenever the library detects a change in the * maximum number of milliseconds the app is allowed to wait before * curl_multi_socket() or curl_multi_perform() must be called * (to allow libcurl's timed events to take place). * * Returns: The callback should return zero. */ typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp); /* private callback pointer */ CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles); CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, int ev_bitmask, int *running_handles); CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles); #ifndef CURL_ALLOW_OLD_MULTI_SOCKET /* This macro below was added in 7.16.3 to push users who recompile to use the new curl_multi_socket_action() instead of the old curl_multi_socket() */ #define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) #endif /* * Name: curl_multi_timeout() * * Desc: Returns the maximum number of milliseconds the app is allowed to * wait before curl_multi_socket() or curl_multi_perform() must be * called (to allow libcurl's timed events to take place). * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, long *milliseconds); typedef enum { /* This is the socket callback function pointer */ CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1), /* This is the argument passed to the socket callback */ CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2), /* set to 1 to enable pipelining for this multi handle */ CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3), /* This is the timer callback function pointer */ CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4), /* This is the argument passed to the timer callback */ CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5), /* maximum number of entries in the connection cache */ CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6), /* maximum number of (pipelining) connections to one host */ CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7), /* maximum number of requests in a pipeline */ CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8), /* a connection with a content-length longer than this will not be considered for pipelining */ CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9), /* a connection with a chunk length longer than this will not be considered for pipelining */ CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), /* a list of site names(+port) that are blacklisted from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), /* a list of server types that are blacklisted from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), /* maximum number of open connections in total */ CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13), /* This is the server push callback function pointer */ CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14), /* This is the argument passed to the server push callback */ CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15), /* maximum number of concurrent streams to support on a connection */ CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; /* * Name: curl_multi_setopt() * * Desc: Sets options for the multi handle. * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option, ...); /* * Name: curl_multi_assign() * * Desc: This function sets an association in the multi handle between the * given socket and a private pointer of the application. This is * (only) useful for curl_multi_socket uses. * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); /* * Name: curl_push_callback * * Desc: This callback gets called when a new stream is being pushed by the * server. It approves or denies the new stream. * * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. */ #define CURL_PUSH_OK 0 #define CURL_PUSH_DENY 1 struct curl_pushheaders; /* forward declaration only */ CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num); CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, const char *name); typedef int (*curl_push_callback)(CURL *parent, CURL *easy, size_t num_headers, struct curl_pushheaders *headers, void *userp); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif davix-0.8.0/deps/curl/include/curl/system.h0000644000000000000000000004513114121063461017317 0ustar rootroot#ifndef CURLINC_SYSTEM_H #define CURLINC_SYSTEM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Try to keep one section per platform, compiler and architecture, otherwise, * if an existing section is reused for a different one and later on the * original is adjusted, probably the piggybacking one can be adversely * changed. * * In order to differentiate between platforms/compilers/architectures use * only compiler built in predefined preprocessor symbols. * * curl_off_t * ---------- * * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit * wide signed integral data type. The width of this data type must remain * constant and independent of any possible large file support settings. * * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit * wide signed integral data type if there is no 64-bit type. * * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall * only be violated if off_t is the only 64-bit data type available and the * size of off_t is independent of large file support settings. Keep your * build on the safe side avoiding an off_t gating. If you have a 64-bit * off_t then take for sure that another 64-bit data type exists, dig deeper * and you will find it. * */ #if defined(__DJGPP__) || defined(__GO32__) # if defined(__DJGPP__) && (__DJGPP__ > 1) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__SALFORDC__) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__BORLANDC__) # if (__BORLANDC__ < 0x520) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TURBOC__) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__WATCOMC__) # if defined(__386__) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__POCC__) # if (__POCC__ < 280) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # elif defined(_MSC_VER) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # else # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__LCC__) # if defined(__e2k__) /* MCST eLbrus C Compiler */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # else /* Local (or Little) C Compiler */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int # endif #elif defined(__SYMBIAN32__) # if defined(__EABI__) /* Treat all ARM compilers equally */ # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__CW32__) # pragma longlong on # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__VC32__) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__MWERKS__) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(_WIN32_WCE) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__MINGW32__) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_WS2TCPIP_H 1 #elif defined(__VMS) # if defined(__VAX) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__OS400__) # if defined(__ILEC400__) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(__MVS__) # if defined(__IBMC__) || defined(__IBMCPP__) # if defined(_ILP32) # elif defined(_LP64) # endif # if defined(_LONG_LONG) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(__370__) # if defined(__IBMC__) || defined(__IBMCPP__) # if defined(_ILP32) # elif defined(_LP64) # endif # if defined(_LONG_LONG) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(TPF) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TINYC__) /* also known as tcc */ # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ # if !defined(__LP64) && (defined(__ILP32) || \ defined(__i386) || \ defined(__sparcv8) || \ defined(__sparcv8plus)) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__LP64) || \ defined(__amd64) || defined(__sparcv9) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__xlc__) /* IBM xlc compiler */ # if !defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 /* ===================================== */ /* KEEP MSVC THE PENULTIMATE ENTRY */ /* ===================================== */ #elif defined(_MSC_VER) # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int /* ===================================== */ /* KEEP GENERIC GCC THE LAST ENTRY */ /* ===================================== */ #elif defined(__GNUC__) && !defined(_SCO_DS) # if !defined(__LP64__) && \ (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ defined(__XTENSA__) || \ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__LP64__) || \ defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ defined(__e2k__) || \ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #else /* generic "safe guess" on old 32 bit style */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #endif #ifdef _AIX /* AIX needs */ #define CURL_PULL_SYS_POLL_H #endif /* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ /* ws2tcpip.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_WS2TCPIP_H # include # include # include #endif /* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ /* sys/types.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_TYPES_H # include #endif /* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ /* sys/socket.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_SOCKET_H # include #endif /* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ /* sys/poll.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_POLL_H # include #endif /* Data type definition of curl_socklen_t. */ #ifdef CURL_TYPEOF_CURL_SOCKLEN_T typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; #endif /* Data type definition of curl_off_t. */ #ifdef CURL_TYPEOF_CURL_OFF_T typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; #endif /* * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow * these to be visible and exported by the external libcurl interface API, * while also making them visible to the library internals, simply including * curl_setup.h, without actually needing to include curl.h internally. * If some day this section would grow big enough, all this should be moved * to its own header file. */ /* * Figure out if we can use the ## preprocessor operator, which is supported * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ * or __cplusplus so we need to carefully check for them too. */ #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ defined(__ILEC400__) /* This compiler is believed to have an ISO compatible preprocessor */ #define CURL_ISOCPP #else /* This compiler is believed NOT to have an ISO compatible preprocessor */ #undef CURL_ISOCPP #endif /* * Macros for minimum-width signed and unsigned curl_off_t integer constants. */ #if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) # define CURLINC_OFF_T_C_HLPR2(x) x # define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x) # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) #else # ifdef CURL_ISOCPP # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix # else # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix # endif # define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix) # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) #endif #endif /* CURLINC_SYSTEM_H */ davix-0.8.0/deps/curl/include/curl/typecheck-gcc.h0000644000000000000000000012242214121063461020503 0ustar rootroot#ifndef CURLINC_TYPECHECK_GCC_H #define CURLINC_TYPECHECK_GCC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* wraps curl_easy_setopt() with typechecking */ /* To add a new kind of warning, add an * if(curlcheck_sometype_option(_curl_opt)) * if(!curlcheck_sometype(value)) * _curl_easy_setopt_err_sometype(); * block and define curlcheck_sometype_option, curlcheck_sometype and * _curl_easy_setopt_err_sometype below * * NOTE: We use two nested 'if' statements here instead of the && operator, in * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x * when compiling with -Wlogical-op. * * To add an option that uses the same type as an existing option, you'll just * need to extend the appropriate _curl_*_option macro */ #define curl_easy_setopt(handle, option, value) \ __extension__({ \ __typeof__(option) _curl_opt = option; \ if(__builtin_constant_p(_curl_opt)) { \ if(curlcheck_long_option(_curl_opt)) \ if(!curlcheck_long(value)) \ _curl_easy_setopt_err_long(); \ if(curlcheck_off_t_option(_curl_opt)) \ if(!curlcheck_off_t(value)) \ _curl_easy_setopt_err_curl_off_t(); \ if(curlcheck_string_option(_curl_opt)) \ if(!curlcheck_string(value)) \ _curl_easy_setopt_err_string(); \ if(curlcheck_write_cb_option(_curl_opt)) \ if(!curlcheck_write_cb(value)) \ _curl_easy_setopt_err_write_callback(); \ if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ if(!curlcheck_resolver_start_callback(value)) \ _curl_easy_setopt_err_resolver_start_callback(); \ if((_curl_opt) == CURLOPT_READFUNCTION) \ if(!curlcheck_read_cb(value)) \ _curl_easy_setopt_err_read_cb(); \ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ if(!curlcheck_ioctl_cb(value)) \ _curl_easy_setopt_err_ioctl_cb(); \ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ if(!curlcheck_sockopt_cb(value)) \ _curl_easy_setopt_err_sockopt_cb(); \ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ if(!curlcheck_opensocket_cb(value)) \ _curl_easy_setopt_err_opensocket_cb(); \ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ if(!curlcheck_progress_cb(value)) \ _curl_easy_setopt_err_progress_cb(); \ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ if(!curlcheck_debug_cb(value)) \ _curl_easy_setopt_err_debug_cb(); \ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ if(!curlcheck_ssl_ctx_cb(value)) \ _curl_easy_setopt_err_ssl_ctx_cb(); \ if(curlcheck_conv_cb_option(_curl_opt)) \ if(!curlcheck_conv_cb(value)) \ _curl_easy_setopt_err_conv_cb(); \ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ if(!curlcheck_seek_cb(value)) \ _curl_easy_setopt_err_seek_cb(); \ if(curlcheck_cb_data_option(_curl_opt)) \ if(!curlcheck_cb_data(value)) \ _curl_easy_setopt_err_cb_data(); \ if((_curl_opt) == CURLOPT_ERRORBUFFER) \ if(!curlcheck_error_buffer(value)) \ _curl_easy_setopt_err_error_buffer(); \ if((_curl_opt) == CURLOPT_STDERR) \ if(!curlcheck_FILE(value)) \ _curl_easy_setopt_err_FILE(); \ if(curlcheck_postfields_option(_curl_opt)) \ if(!curlcheck_postfields(value)) \ _curl_easy_setopt_err_postfields(); \ if((_curl_opt) == CURLOPT_HTTPPOST) \ if(!curlcheck_arr((value), struct curl_httppost)) \ _curl_easy_setopt_err_curl_httpost(); \ if((_curl_opt) == CURLOPT_MIMEPOST) \ if(!curlcheck_ptr((value), curl_mime)) \ _curl_easy_setopt_err_curl_mimepost(); \ if(curlcheck_slist_option(_curl_opt)) \ if(!curlcheck_arr((value), struct curl_slist)) \ _curl_easy_setopt_err_curl_slist(); \ if((_curl_opt) == CURLOPT_SHARE) \ if(!curlcheck_ptr((value), CURLSH)) \ _curl_easy_setopt_err_CURLSH(); \ } \ curl_easy_setopt(handle, _curl_opt, value); \ }) /* wraps curl_easy_getinfo() with typechecking */ #define curl_easy_getinfo(handle, info, arg) \ __extension__({ \ __typeof__(info) _curl_info = info; \ if(__builtin_constant_p(_curl_info)) { \ if(curlcheck_string_info(_curl_info)) \ if(!curlcheck_arr((arg), char *)) \ _curl_easy_getinfo_err_string(); \ if(curlcheck_long_info(_curl_info)) \ if(!curlcheck_arr((arg), long)) \ _curl_easy_getinfo_err_long(); \ if(curlcheck_double_info(_curl_info)) \ if(!curlcheck_arr((arg), double)) \ _curl_easy_getinfo_err_double(); \ if(curlcheck_slist_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_slist *)) \ _curl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ if(curlcheck_certinfo_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ _curl_easy_getinfo_err_curl_certinfo(); \ if(curlcheck_socket_info(_curl_info)) \ if(!curlcheck_arr((arg), curl_socket_t)) \ _curl_easy_getinfo_err_curl_socket(); \ if(curlcheck_off_t_info(_curl_info)) \ if(!curlcheck_arr((arg), curl_off_t)) \ _curl_easy_getinfo_err_curl_off_t(); \ } \ curl_easy_getinfo(handle, _curl_info, arg); \ }) /* * For now, just make sure that the functions are called with three arguments */ #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) /* the actual warnings, triggered by calling the _curl_easy_setopt_err* * functions */ /* To define a new warning, use _CURL_WARNING(identifier, "message") */ #define CURLWARNING(id, message) \ static void __attribute__((__warning__(message))) \ __attribute__((__unused__)) __attribute__((__noinline__)) \ id(void) { __asm__(""); } CURLWARNING(_curl_easy_setopt_err_long, "curl_easy_setopt expects a long argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument for this option") CURLWARNING(_curl_easy_setopt_err_string, "curl_easy_setopt expects a " "string ('char *' or char[]) argument for this option" ) CURLWARNING(_curl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_resolver_start_callback, "curl_easy_setopt expects a " "curl_resolver_start_callback argument for this option" ) CURLWARNING(_curl_easy_setopt_err_read_cb, "curl_easy_setopt expects a curl_read_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_ioctl_cb, "curl_easy_setopt expects a curl_ioctl_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_sockopt_cb, "curl_easy_setopt expects a curl_sockopt_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_opensocket_cb, "curl_easy_setopt expects a " "curl_opensocket_callback argument for this option" ) CURLWARNING(_curl_easy_setopt_err_progress_cb, "curl_easy_setopt expects a curl_progress_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_debug_cb, "curl_easy_setopt expects a curl_debug_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb, "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_conv_cb, "curl_easy_setopt expects a curl_conv_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_seek_cb, "curl_easy_setopt expects a curl_seek_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_cb_data, "curl_easy_setopt expects a " "private data pointer as argument for this option") CURLWARNING(_curl_easy_setopt_err_error_buffer, "curl_easy_setopt expects a " "char buffer of CURL_ERROR_SIZE as argument for this option") CURLWARNING(_curl_easy_setopt_err_FILE, "curl_easy_setopt expects a 'FILE *' argument for this option") CURLWARNING(_curl_easy_setopt_err_postfields, "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_httpost, "curl_easy_setopt expects a 'struct curl_httppost *' " "argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_mimepost, "curl_easy_setopt expects a 'curl_mime *' " "argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_slist, "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") CURLWARNING(_curl_easy_setopt_err_CURLSH, "curl_easy_setopt expects a CURLSH* argument for this option") CURLWARNING(_curl_easy_getinfo_err_string, "curl_easy_getinfo expects a pointer to 'char *' for this info") CURLWARNING(_curl_easy_getinfo_err_long, "curl_easy_getinfo expects a pointer to long for this info") CURLWARNING(_curl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double for this info") CURLWARNING(_curl_easy_getinfo_err_curl_slist, "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, "curl_easy_getinfo expects a pointer to " "'struct curl_tlssessioninfo *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, "curl_easy_getinfo expects a pointer to " "'struct curl_certinfo *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_socket, "curl_easy_getinfo expects a pointer to curl_socket_t for this info") CURLWARNING(_curl_easy_getinfo_err_curl_off_t, "curl_easy_getinfo expects a pointer to curl_off_t for this info") /* groups of curl_easy_setops options that take the same type of argument */ /* To add a new option to one of the groups, just add * (option) == CURLOPT_SOMETHING * to the or-expression. If the option takes a long or curl_off_t, you don't * have to do anything */ /* evaluates to true if option takes a long argument */ #define curlcheck_long_option(option) \ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) #define curlcheck_off_t_option(option) \ ((option) > CURLOPTTYPE_OFF_T) /* evaluates to true if option takes a char* argument */ #define curlcheck_string_option(option) \ ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ (option) == CURLOPT_ACCEPT_ENCODING || \ (option) == CURLOPT_ALTSVC || \ (option) == CURLOPT_CAINFO || \ (option) == CURLOPT_CAPATH || \ (option) == CURLOPT_COOKIE || \ (option) == CURLOPT_COOKIEFILE || \ (option) == CURLOPT_COOKIEJAR || \ (option) == CURLOPT_COOKIELIST || \ (option) == CURLOPT_CRLFILE || \ (option) == CURLOPT_CUSTOMREQUEST || \ (option) == CURLOPT_DEFAULT_PROTOCOL || \ (option) == CURLOPT_DNS_INTERFACE || \ (option) == CURLOPT_DNS_LOCAL_IP4 || \ (option) == CURLOPT_DNS_LOCAL_IP6 || \ (option) == CURLOPT_DNS_SERVERS || \ (option) == CURLOPT_DOH_URL || \ (option) == CURLOPT_EGDSOCKET || \ (option) == CURLOPT_FTPPORT || \ (option) == CURLOPT_FTP_ACCOUNT || \ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ (option) == CURLOPT_INTERFACE || \ (option) == CURLOPT_ISSUERCERT || \ (option) == CURLOPT_KEYPASSWD || \ (option) == CURLOPT_KRBLEVEL || \ (option) == CURLOPT_LOGIN_OPTIONS || \ (option) == CURLOPT_MAIL_AUTH || \ (option) == CURLOPT_MAIL_FROM || \ (option) == CURLOPT_NETRC_FILE || \ (option) == CURLOPT_NOPROXY || \ (option) == CURLOPT_PASSWORD || \ (option) == CURLOPT_PINNEDPUBLICKEY || \ (option) == CURLOPT_PRE_PROXY || \ (option) == CURLOPT_PROXY || \ (option) == CURLOPT_PROXYPASSWORD || \ (option) == CURLOPT_PROXYUSERNAME || \ (option) == CURLOPT_PROXYUSERPWD || \ (option) == CURLOPT_PROXY_CAINFO || \ (option) == CURLOPT_PROXY_CAPATH || \ (option) == CURLOPT_PROXY_CRLFILE || \ (option) == CURLOPT_PROXY_KEYPASSWD || \ (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ (option) == CURLOPT_PROXY_SERVICE_NAME || \ (option) == CURLOPT_PROXY_SSLCERT || \ (option) == CURLOPT_PROXY_SSLCERTTYPE || \ (option) == CURLOPT_PROXY_SSLKEY || \ (option) == CURLOPT_PROXY_SSLKEYTYPE || \ (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ (option) == CURLOPT_PROXY_TLS13_CIPHERS || \ (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ (option) == CURLOPT_RANDOM_FILE || \ (option) == CURLOPT_RANGE || \ (option) == CURLOPT_REFERER || \ (option) == CURLOPT_REQUEST_TARGET || \ (option) == CURLOPT_RTSP_SESSION_ID || \ (option) == CURLOPT_RTSP_STREAM_URI || \ (option) == CURLOPT_RTSP_TRANSPORT || \ (option) == CURLOPT_SASL_AUTHZID || \ (option) == CURLOPT_SERVICE_NAME || \ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ (option) == CURLOPT_SSH_KNOWNHOSTS || \ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ (option) == CURLOPT_SSLCERT || \ (option) == CURLOPT_SSLCERTTYPE || \ (option) == CURLOPT_SSLENGINE || \ (option) == CURLOPT_SSLKEY || \ (option) == CURLOPT_SSLKEYTYPE || \ (option) == CURLOPT_SSL_CIPHER_LIST || \ (option) == CURLOPT_TLS13_CIPHERS || \ (option) == CURLOPT_TLSAUTH_PASSWORD || \ (option) == CURLOPT_TLSAUTH_TYPE || \ (option) == CURLOPT_TLSAUTH_USERNAME || \ (option) == CURLOPT_UNIX_SOCKET_PATH || \ (option) == CURLOPT_URL || \ (option) == CURLOPT_USERAGENT || \ (option) == CURLOPT_USERNAME || \ (option) == CURLOPT_USERPWD || \ (option) == CURLOPT_XOAUTH2_BEARER || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ #define curlcheck_write_cb_option(option) \ ((option) == CURLOPT_HEADERFUNCTION || \ (option) == CURLOPT_WRITEFUNCTION) /* evaluates to true if option takes a curl_conv_callback argument */ #define curlcheck_conv_cb_option(option) \ ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) /* evaluates to true if option takes a data argument to pass to a callback */ #define curlcheck_cb_data_option(option) \ ((option) == CURLOPT_CHUNK_DATA || \ (option) == CURLOPT_CLOSESOCKETDATA || \ (option) == CURLOPT_DEBUGDATA || \ (option) == CURLOPT_FNMATCH_DATA || \ (option) == CURLOPT_HEADERDATA || \ (option) == CURLOPT_INTERLEAVEDATA || \ (option) == CURLOPT_IOCTLDATA || \ (option) == CURLOPT_OPENSOCKETDATA || \ (option) == CURLOPT_PRIVATE || \ (option) == CURLOPT_PROGRESSDATA || \ (option) == CURLOPT_READDATA || \ (option) == CURLOPT_SEEKDATA || \ (option) == CURLOPT_SOCKOPTDATA || \ (option) == CURLOPT_SSH_KEYDATA || \ (option) == CURLOPT_SSL_CTX_DATA || \ (option) == CURLOPT_WRITEDATA || \ (option) == CURLOPT_RESOLVER_START_DATA || \ (option) == CURLOPT_TRAILERDATA || \ 0) /* evaluates to true if option takes a POST data argument (void* or char*) */ #define curlcheck_postfields_option(option) \ ((option) == CURLOPT_POSTFIELDS || \ (option) == CURLOPT_COPYPOSTFIELDS || \ 0) /* evaluates to true if option takes a struct curl_slist * argument */ #define curlcheck_slist_option(option) \ ((option) == CURLOPT_HTTP200ALIASES || \ (option) == CURLOPT_HTTPHEADER || \ (option) == CURLOPT_MAIL_RCPT || \ (option) == CURLOPT_POSTQUOTE || \ (option) == CURLOPT_PREQUOTE || \ (option) == CURLOPT_PROXYHEADER || \ (option) == CURLOPT_QUOTE || \ (option) == CURLOPT_RESOLVE || \ (option) == CURLOPT_TELNETOPTIONS || \ (option) == CURLOPT_CONNECT_TO || \ 0) /* groups of curl_easy_getinfo infos that take the same type of argument */ /* evaluates to true if info expects a pointer to char * argument */ #define curlcheck_string_info(info) \ (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) /* evaluates to true if info expects a pointer to long argument */ #define curlcheck_long_info(info) \ (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) /* evaluates to true if info expects a pointer to double argument */ #define curlcheck_double_info(info) \ (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) /* true if info expects a pointer to struct curl_slist * argument */ #define curlcheck_slist_info(info) \ (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) /* true if info expects a pointer to struct curl_tlssessioninfo * argument */ #define curlcheck_tlssessioninfo_info(info) \ (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) /* true if info expects a pointer to struct curl_certinfo * argument */ #define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO) /* true if info expects a pointer to struct curl_socket_t argument */ #define curlcheck_socket_info(info) \ (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) /* true if info expects a pointer to curl_off_t argument */ #define curlcheck_off_t_info(info) \ (CURLINFO_OFF_T < (info)) /* typecheck helpers -- check whether given expression has requested type*/ /* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros, * otherwise define a new macro. Search for __builtin_types_compatible_p * in the GCC manual. * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is * the actual expression passed to the curl_easy_setopt macro. This * means that you can only apply the sizeof and __typeof__ operators, no * == or whatsoever. */ /* XXX: should evaluate to true if expr is a pointer */ #define curlcheck_any_ptr(expr) \ (sizeof(expr) == sizeof(void *)) /* evaluates to true if expr is NULL */ /* XXX: must not evaluate expr, so this check is not accurate */ #define curlcheck_NULL(expr) \ (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) /* evaluates to true if expr is type*, const type* or NULL */ #define curlcheck_ptr(expr, type) \ (curlcheck_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), type *) || \ __builtin_types_compatible_p(__typeof__(expr), const type *)) /* evaluates to true if expr is one of type[], type*, NULL or const type* */ #define curlcheck_arr(expr, type) \ (curlcheck_ptr((expr), type) || \ __builtin_types_compatible_p(__typeof__(expr), type [])) /* evaluates to true if expr is a string */ #define curlcheck_string(expr) \ (curlcheck_arr((expr), char) || \ curlcheck_arr((expr), signed char) || \ curlcheck_arr((expr), unsigned char)) /* evaluates to true if expr is a long (no matter the signedness) * XXX: for now, int is also accepted (and therefore short and char, which * are promoted to int when passed to a variadic function) */ #define curlcheck_long(expr) \ (__builtin_types_compatible_p(__typeof__(expr), long) || \ __builtin_types_compatible_p(__typeof__(expr), signed long) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ __builtin_types_compatible_p(__typeof__(expr), int) || \ __builtin_types_compatible_p(__typeof__(expr), signed int) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ __builtin_types_compatible_p(__typeof__(expr), short) || \ __builtin_types_compatible_p(__typeof__(expr), signed short) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ __builtin_types_compatible_p(__typeof__(expr), char) || \ __builtin_types_compatible_p(__typeof__(expr), signed char) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned char)) /* evaluates to true if expr is of type curl_off_t */ #define curlcheck_off_t(expr) \ (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ /* XXX: also check size of an char[] array? */ #define curlcheck_error_buffer(expr) \ (curlcheck_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), char *) || \ __builtin_types_compatible_p(__typeof__(expr), char[])) /* evaluates to true if expr is of type (const) void* or (const) FILE* */ #if 0 #define curlcheck_cb_data(expr) \ (curlcheck_ptr((expr), void) || \ curlcheck_ptr((expr), FILE)) #else /* be less strict */ #define curlcheck_cb_data(expr) \ curlcheck_any_ptr(expr) #endif /* evaluates to true if expr is of type FILE* */ #define curlcheck_FILE(expr) \ (curlcheck_NULL(expr) || \ (__builtin_types_compatible_p(__typeof__(expr), FILE *))) /* evaluates to true if expr can be passed as POST data (void* or char*) */ #define curlcheck_postfields(expr) \ (curlcheck_ptr((expr), void) || \ curlcheck_arr((expr), char) || \ curlcheck_arr((expr), unsigned char)) /* helper: __builtin_types_compatible_p distinguishes between functions and * function pointers, hide it */ #define curlcheck_cb_compatible(func, type) \ (__builtin_types_compatible_p(__typeof__(func), type) || \ __builtin_types_compatible_p(__typeof__(func) *, type)) /* evaluates to true if expr is of type curl_resolver_start_callback */ #define curlcheck_resolver_start_callback(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_resolver_start_callback)) /* evaluates to true if expr is of type curl_read_callback or "similar" */ #define curlcheck_read_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fread) *) || \ curlcheck_cb_compatible((expr), curl_read_callback) || \ curlcheck_cb_compatible((expr), _curl_read_callback1) || \ curlcheck_cb_compatible((expr), _curl_read_callback2) || \ curlcheck_cb_compatible((expr), _curl_read_callback3) || \ curlcheck_cb_compatible((expr), _curl_read_callback4) || \ curlcheck_cb_compatible((expr), _curl_read_callback5) || \ curlcheck_cb_compatible((expr), _curl_read_callback6)) typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_write_callback or "similar" */ #define curlcheck_write_cb(expr) \ (curlcheck_read_cb(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \ curlcheck_cb_compatible((expr), curl_write_callback) || \ curlcheck_cb_compatible((expr), _curl_write_callback1) || \ curlcheck_cb_compatible((expr), _curl_write_callback2) || \ curlcheck_cb_compatible((expr), _curl_write_callback3) || \ curlcheck_cb_compatible((expr), _curl_write_callback4) || \ curlcheck_cb_compatible((expr), _curl_write_callback5) || \ curlcheck_cb_compatible((expr), _curl_write_callback6)) typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, const void *); typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, const void *); typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ #define curlcheck_ioctl_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ioctl_callback) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback4)) typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ #define curlcheck_sockopt_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_sockopt_callback) || \ curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \ curlcheck_cb_compatible((expr), _curl_sockopt_callback2)) typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, curlsocktype); /* evaluates to true if expr is of type curl_opensocket_callback or "similar" */ #define curlcheck_opensocket_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_opensocket_callback) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback4)) typedef curl_socket_t (*_curl_opensocket_callback1) (void *, curlsocktype, struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback2) (void *, curlsocktype, const struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback3) (const void *, curlsocktype, struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback4) (const void *, curlsocktype, const struct curl_sockaddr *); /* evaluates to true if expr is of type curl_progress_callback or "similar" */ #define curlcheck_progress_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_progress_callback) || \ curlcheck_cb_compatible((expr), _curl_progress_callback1) || \ curlcheck_cb_compatible((expr), _curl_progress_callback2)) typedef int (*_curl_progress_callback1)(void *, double, double, double, double); typedef int (*_curl_progress_callback2)(const void *, double, double, double, double); /* evaluates to true if expr is of type curl_debug_callback or "similar" */ #define curlcheck_debug_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_debug_callback) || \ curlcheck_cb_compatible((expr), _curl_debug_callback1) || \ curlcheck_cb_compatible((expr), _curl_debug_callback2) || \ curlcheck_cb_compatible((expr), _curl_debug_callback3) || \ curlcheck_cb_compatible((expr), _curl_debug_callback4) || \ curlcheck_cb_compatible((expr), _curl_debug_callback5) || \ curlcheck_cb_compatible((expr), _curl_debug_callback6) || \ curlcheck_cb_compatible((expr), _curl_debug_callback7) || \ curlcheck_cb_compatible((expr), _curl_debug_callback8)) typedef int (*_curl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); typedef int (*_curl_debug_callback2) (CURL *, curl_infotype, char *, size_t, const void *); typedef int (*_curl_debug_callback3) (CURL *, curl_infotype, const char *, size_t, void *); typedef int (*_curl_debug_callback4) (CURL *, curl_infotype, const char *, size_t, const void *); typedef int (*_curl_debug_callback5) (CURL *, curl_infotype, unsigned char *, size_t, void *); typedef int (*_curl_debug_callback6) (CURL *, curl_infotype, unsigned char *, size_t, const void *); typedef int (*_curl_debug_callback7) (CURL *, curl_infotype, const unsigned char *, size_t, void *); typedef int (*_curl_debug_callback8) (CURL *, curl_infotype, const unsigned char *, size_t, const void *); /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ /* this is getting even messier... */ #define curlcheck_ssl_ctx_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8)) typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); #ifdef HEADER_SSL_H /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX * this will of course break if we're included before OpenSSL headers... */ typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, const void *); #else typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; #endif /* evaluates to true if expr is of type curl_conv_callback or "similar" */ #define curlcheck_conv_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_conv_callback) || \ curlcheck_cb_compatible((expr), _curl_conv_callback1) || \ curlcheck_cb_compatible((expr), _curl_conv_callback2) || \ curlcheck_cb_compatible((expr), _curl_conv_callback3) || \ curlcheck_cb_compatible((expr), _curl_conv_callback4)) typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); /* evaluates to true if expr is of type curl_seek_callback or "similar" */ #define curlcheck_seek_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_seek_callback) || \ curlcheck_cb_compatible((expr), _curl_seek_callback1) || \ curlcheck_cb_compatible((expr), _curl_seek_callback2)) typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); #endif /* CURLINC_TYPECHECK_GCC_H */ davix-0.8.0/deps/curl/include/curl/curl.h0000644000000000000000000033472614121063461016753 0ustar rootroot#ifndef CURLINC_CURL_H #define CURLINC_CURL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * If you have libcurl problems, all docs and details are found here: * https://curl.haxx.se/libcurl/ * * curl-library mailing list subscription and unsubscription web interface: * https://cool.haxx.se/mailman/listinfo/curl-library/ */ #ifdef CURL_NO_OLDIES #define CURL_STRICTER #endif #include "curlver.h" /* libcurl version defines */ #include "system.h" /* determine things run-time */ /* * Define CURL_WIN32 when build target is Win32 API */ #if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && \ !defined(__SYMBIAN32__) #define CURL_WIN32 #endif #include #include #if defined(__FreeBSD__) && (__FreeBSD__ >= 2) /* Needed for __FreeBSD_version symbol definition */ #include #endif /* The include stuff here below is mainly for time_t! */ #include #include #if defined(CURL_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2 inclusion if winsock.h already was included, since they can't co-exist without problems */ #include #include #endif #endif /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish libc5-based Linux systems. Only include it on systems that are known to require it! */ #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ defined(__CYGWIN__) || \ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) #include #endif #if !defined(CURL_WIN32) && !defined(_WIN32_WCE) #include #endif #if !defined(CURL_WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) #include #endif #ifdef __BEOS__ #include #endif /* Compatibility for non-Clang compilers */ #ifndef __has_declspec_attribute # define __has_declspec_attribute(x) 0 #endif #ifdef __cplusplus extern "C" { #endif #if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) typedef struct Curl_easy CURL; typedef struct Curl_share CURLSH; #else typedef void CURL; typedef void CURLSH; #endif /* * libcurl external API function linkage decorations. */ #ifdef CURL_STATICLIB # define CURL_EXTERN #elif defined(CURL_WIN32) || defined(__SYMBIAN32__) || \ (__has_declspec_attribute(dllexport) && \ __has_declspec_attribute(dllimport)) # if defined(BUILDING_LIBCURL) # define CURL_EXTERN __declspec(dllexport) # else # define CURL_EXTERN __declspec(dllimport) # endif #elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) # define CURL_EXTERN CURL_EXTERN_SYMBOL #else # define CURL_EXTERN #endif #ifndef curl_socket_typedef /* socket typedef */ #if defined(CURL_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else typedef int curl_socket_t; #define CURL_SOCKET_BAD -1 #endif #define curl_socket_typedef #endif /* curl_socket_typedef */ /* enum for the different supported SSL backends */ typedef enum { CURLSSLBACKEND_NONE = 0, CURLSSLBACKEND_OPENSSL = 1, CURLSSLBACKEND_GNUTLS = 2, CURLSSLBACKEND_NSS = 3, CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ CURLSSLBACKEND_GSKIT = 5, CURLSSLBACKEND_POLARSSL = 6, CURLSSLBACKEND_WOLFSSL = 7, CURLSSLBACKEND_SCHANNEL = 8, CURLSSLBACKEND_SECURETRANSPORT = 9, CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ CURLSSLBACKEND_MBEDTLS = 11, CURLSSLBACKEND_MESALINK = 12, CURLSSLBACKEND_BEARSSL = 13 } curl_sslbackend; /* aliases for library clones and renames */ #define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL #define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL /* deprecated names: */ #define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL #define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT struct curl_httppost { struct curl_httppost *next; /* next entry in the list */ char *name; /* pointer to allocated name */ long namelength; /* length of name length */ char *contents; /* pointer to allocated data contents */ long contentslength; /* length of contents field, see also CURL_HTTPPOST_LARGE */ char *buffer; /* pointer to allocated buffer contents */ long bufferlength; /* length of buffer field */ char *contenttype; /* Content-Type */ struct curl_slist *contentheader; /* list of extra headers for this form */ struct curl_httppost *more; /* if one field name has more than one file, this link should link to following files */ long flags; /* as defined below */ /* specified content is a file name */ #define CURL_HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ #define CURL_HTTPPOST_READFILE (1<<1) /* name is only stored pointer do not free in formfree */ #define CURL_HTTPPOST_PTRNAME (1<<2) /* contents is only stored pointer do not free in formfree */ #define CURL_HTTPPOST_PTRCONTENTS (1<<3) /* upload file from buffer */ #define CURL_HTTPPOST_BUFFER (1<<4) /* upload file from pointer contents */ #define CURL_HTTPPOST_PTRBUFFER (1<<5) /* upload file contents by using the regular read callback to get the data and pass the given pointer as custom pointer */ #define CURL_HTTPPOST_CALLBACK (1<<6) /* use size in 'contentlen', added in 7.46.0 */ #define CURL_HTTPPOST_LARGE (1<<7) char *showfilename; /* The file name to show. If not set, the actual file name will be used (if this is a file part) */ void *userp; /* custom pointer used for HTTPPOST_CALLBACK posts */ curl_off_t contentlen; /* alternative length of contents field. Used if CURL_HTTPPOST_LARGE is set. Added in 7.46.0 */ }; /* This is a return code for the progress callback that, when returned, will signal libcurl to continue executing the default progress function */ #define CURL_PROGRESSFUNC_CONTINUE 0x10000001 /* This is the CURLOPT_PROGRESSFUNCTION callback prototype. It is now considered deprecated but was the only choice up until 7.31.0 */ typedef int (*curl_progress_callback)(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); /* This is the CURLOPT_XFERINFOFUNCTION callback prototype. It was introduced in 7.32.0, avoids the use of floating point numbers and provides more detailed information. */ typedef int (*curl_xferinfo_callback)(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); #ifndef CURL_MAX_READ_SIZE /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ #define CURL_MAX_READ_SIZE 524288 #endif #ifndef CURL_MAX_WRITE_SIZE /* Tests have proven that 20K is a very bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. We do the ifndef check to allow this value to easier be changed at build time for those who feel adventurous. The practical minimum is about 400 bytes since libcurl uses a buffer of this size as a scratch area (unrelated to network send operations). */ #define CURL_MAX_WRITE_SIZE 16384 #endif #ifndef CURL_MAX_HTTP_HEADER /* The only reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a never-ending header that will cause reallocs infinitely */ #define CURL_MAX_HTTP_HEADER (100*1024) #endif /* This is a magic return code for the write callback that, when returned, will signal libcurl to pause receiving on the current transfer. */ #define CURL_WRITEFUNC_PAUSE 0x10000001 typedef size_t (*curl_write_callback)(char *buffer, size_t size, size_t nitems, void *outstream); /* This callback will be called when a new resolver request is made */ typedef int (*curl_resolver_start_callback)(void *resolver_state, void *reserved, void *userdata); /* enumeration of file types */ typedef enum { CURLFILETYPE_FILE = 0, CURLFILETYPE_DIRECTORY, CURLFILETYPE_SYMLINK, CURLFILETYPE_DEVICE_BLOCK, CURLFILETYPE_DEVICE_CHAR, CURLFILETYPE_NAMEDPIPE, CURLFILETYPE_SOCKET, CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ CURLFILETYPE_UNKNOWN /* should never occur */ } curlfiletype; #define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) #define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) #define CURLFINFOFLAG_KNOWN_TIME (1<<2) #define CURLFINFOFLAG_KNOWN_PERM (1<<3) #define CURLFINFOFLAG_KNOWN_UID (1<<4) #define CURLFINFOFLAG_KNOWN_GID (1<<5) #define CURLFINFOFLAG_KNOWN_SIZE (1<<6) #define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) /* Information about a single file, used when doing FTP wildcard matching */ struct curl_fileinfo { char *filename; curlfiletype filetype; time_t time; /* always zero! */ unsigned int perm; int uid; int gid; curl_off_t size; long int hardlinks; struct { /* If some of these fields is not NULL, it is a pointer to b_data. */ char *time; char *perm; char *user; char *group; char *target; /* pointer to the target filename of a symlink */ } strings; unsigned int flags; /* used internally */ char *b_data; size_t b_size; size_t b_used; }; /* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ #define CURL_CHUNK_BGN_FUNC_OK 0 #define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ #define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ /* if splitting of data transfer is enabled, this callback is called before download of an individual chunk started. Note that parameter "remains" works only for FTP wildcard downloading (for now), otherwise is not used */ typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, void *ptr, int remains); /* return codes for CURLOPT_CHUNK_END_FUNCTION */ #define CURL_CHUNK_END_FUNC_OK 0 #define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ /* If splitting of data transfer is enabled this callback is called after download of an individual chunk finished. Note! After this callback was set then it have to be called FOR ALL chunks. Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. This is the reason why we don't need "transfer_info" parameter in this callback and we are not interested in "remains" parameter too. */ typedef long (*curl_chunk_end_callback)(void *ptr); /* return codes for FNMATCHFUNCTION */ #define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ #define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ #define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ /* callback type for wildcard downloading pattern matching. If the string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ typedef int (*curl_fnmatch_callback)(void *ptr, const char *pattern, const char *string); /* These are the return codes for the seek callbacks */ #define CURL_SEEKFUNC_OK 0 #define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ #define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so libcurl might try other means instead */ typedef int (*curl_seek_callback)(void *instream, curl_off_t offset, int origin); /* 'whence' */ /* This is a return code for the read callback that, when returned, will signal libcurl to immediately abort the current transfer. */ #define CURL_READFUNC_ABORT 0x10000000 /* This is a return code for the read callback that, when returned, will signal libcurl to pause sending data on the current transfer. */ #define CURL_READFUNC_PAUSE 0x10000001 /* Return code for when the trailing headers' callback has terminated without any errors*/ #define CURL_TRAILERFUNC_OK 0 /* Return code for when was an error in the trailing header's list and we want to abort the request */ #define CURL_TRAILERFUNC_ABORT 1 typedef size_t (*curl_read_callback)(char *buffer, size_t size, size_t nitems, void *instream); typedef int (*curl_trailer_callback)(struct curl_slist **list, void *userdata); typedef enum { CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ CURLSOCKTYPE_LAST /* never use */ } curlsocktype; /* The return code from the sockopt_callback can signal information back to libcurl: */ #define CURL_SOCKOPT_OK 0 #define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return CURLE_ABORTED_BY_CALLBACK */ #define CURL_SOCKOPT_ALREADY_CONNECTED 2 typedef int (*curl_sockopt_callback)(void *clientp, curl_socket_t curlfd, curlsocktype purpose); struct curl_sockaddr { int family; int socktype; int protocol; unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it turned really ugly and painful on the systems that lack this type */ struct sockaddr addr; }; typedef curl_socket_t (*curl_opensocket_callback)(void *clientp, curlsocktype purpose, struct curl_sockaddr *address); typedef int (*curl_closesocket_callback)(void *clientp, curl_socket_t item); typedef enum { CURLIOE_OK, /* I/O operation successful */ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ CURLIOE_FAILRESTART, /* failed to restart the read */ CURLIOE_LAST /* never use */ } curlioerr; typedef enum { CURLIOCMD_NOP, /* no operation */ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ CURLIOCMD_LAST /* never use */ } curliocmd; typedef curlioerr (*curl_ioctl_callback)(CURL *handle, int cmd, void *clientp); #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* * The following typedef's are signatures of malloc, free, realloc, strdup and * calloc respectively. Function pointers of these types can be passed to the * curl_global_init_mem() function to set user defined memory management * callback routines. */ typedef void *(*curl_malloc_callback)(size_t size); typedef void (*curl_free_callback)(void *ptr); typedef void *(*curl_realloc_callback)(void *ptr, size_t size); typedef char *(*curl_strdup_callback)(const char *str); typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); #define CURL_DID_MEMORY_FUNC_TYPEDEFS #endif /* the kind of data that is passed to information_callback*/ typedef enum { CURLINFO_TEXT = 0, CURLINFO_HEADER_IN, /* 1 */ CURLINFO_HEADER_OUT, /* 2 */ CURLINFO_DATA_IN, /* 3 */ CURLINFO_DATA_OUT, /* 4 */ CURLINFO_SSL_DATA_IN, /* 5 */ CURLINFO_SSL_DATA_OUT, /* 6 */ CURLINFO_END } curl_infotype; typedef int (*curl_debug_callback) (CURL *handle, /* the handle/transfer this concerns */ curl_infotype type, /* what kind of data */ char *data, /* points to the data */ size_t size, /* size of the data pointed to */ void *userptr); /* whatever the user please */ /* All possible error codes from all sorts of curl functions. Future versions may return other values, stay prepared. Always add new return codes last. Never *EVER* remove any. The return codes must remain the same! */ typedef enum { CURLE_OK = 0, CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ CURLE_FAILED_INIT, /* 2 */ CURLE_URL_MALFORMAT, /* 3 */ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for 7.17.0, reused in April 2011 for 7.21.5] */ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ CURLE_WEIRD_SERVER_REPLY, /* 8 */ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for 7.15.4, reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server [was obsoleted in August 2007 for 7.17.0, reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ CURLE_FTP_CANT_GET_HOST, /* 15 */ CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. [was obsoleted in August 2007 for 7.17.0, reused in July 2014 for 7.38.0] */ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ CURLE_PARTIAL_FILE, /* 18 */ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ CURLE_OBSOLETE20, /* 20 - NOT USED */ CURLE_QUOTE_ERROR, /* 21 - quote command failure */ CURLE_HTTP_RETURNED_ERROR, /* 22 */ CURLE_WRITE_ERROR, /* 23 */ CURLE_OBSOLETE24, /* 24 - NOT USED */ CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ CURLE_OUT_OF_MEMORY, /* 27 */ /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error instead of a memory allocation error if CURL_DOES_CONVERSIONS is defined */ CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ CURLE_OBSOLETE29, /* 29 - NOT USED */ CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ CURLE_OBSOLETE32, /* 32 - NOT USED */ CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ CURLE_HTTP_POST_ERROR, /* 34 */ CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ CURLE_FILE_COULDNT_READ_FILE, /* 37 */ CURLE_LDAP_CANNOT_BIND, /* 38 */ CURLE_LDAP_SEARCH_FAILED, /* 39 */ CURLE_OBSOLETE40, /* 40 - NOT USED */ CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ CURLE_ABORTED_BY_CALLBACK, /* 42 */ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ CURLE_OBSOLETE44, /* 44 - NOT USED */ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ CURLE_OBSOLETE46, /* 46 - NOT USED */ CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ CURLE_OBSOLETE50, /* 50 - NOT USED */ CURLE_OBSOLETE51, /* 51 - NOT USED */ CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as default */ CURLE_SEND_ERROR, /* 55 - failed sending network data */ CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ CURLE_OBSOLETE57, /* 57 - NOT IN USE */ CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint wasn't verified fine */ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind that failed */ CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not accepted and we failed to login */ CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ CURLE_TFTP_PERM, /* 69 - permission problem on server */ CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ CURLE_CONV_FAILED, /* 75 - conversion failed */ CURLE_CONV_REQD, /* 76 - caller must register conversion callbacks using curl_easy_setopt options CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPT_CONV_TO_NETWORK_FUNCTION, and CURLOPT_CONV_FROM_UTF8_FUNCTION */ CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing or wrong format */ CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ CURLE_SSH, /* 79 - error from the SSH layer, somewhat generic so the error message will be of interest when this has happened */ CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL connection */ CURLE_AGAIN, /* 81 - socket is not ready for send/recv, wait till it's ready and try again (Added in 7.18.2) */ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or wrong format (Added in 7.19.0) */ CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in 7.19.0) */ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the session will be queued */ CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not match */ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer */ CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from inside a callback */ CURLE_AUTH_ERROR, /* 94 - an authentication function returned an error */ CURLE_HTTP3, /* 95 - An HTTP/3 layer problem */ CURLE_QUIC_CONNECT_ERROR, /* 96 - QUIC connection error */ CURL_LAST /* never use! */ } CURLcode; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* Previously obsolete error code re-used in 7.38.0 */ #define CURLE_OBSOLETE16 CURLE_HTTP2 /* Previously obsolete error codes re-used in 7.24.0 */ #define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED #define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT /* compatibility with older names */ #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING #define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY /* The following were added in 7.62.0 */ #define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION /* The following were added in 7.21.5, April 2011 */ #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION /* The following were added in 7.17.1 */ /* These are scheduled to disappear by 2009 */ #define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION /* The following were added in 7.17.0 */ /* These are scheduled to disappear by 2009 */ #define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ #define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 #define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 #define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 #define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 #define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 #define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 #define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 #define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 #define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 #define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 #define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 #define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN #define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED #define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE #define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR #define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL #define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS #define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR #define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED /* The following were added earlier */ #define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT #define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR #define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED #define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME /* This was the error code 50 in 7.7.3 and a few earlier versions, this is no longer used by libcurl but is instead #defined here only to not make programs break */ #define CURLE_ALREADY_COMPLETE 99999 /* Provide defines for really old option names */ #define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ #define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ #define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA /* Since long deprecated options with no code in the lib that does anything with them. */ #define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 #define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 #endif /*!CURL_NO_OLDIES*/ /* This prototype applies to all conversion callbacks */ typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ void *ssl_ctx, /* actually an OpenSSL or WolfSSL SSL_CTX, or an mbedTLS mbedtls_ssl_config */ void *userptr); typedef enum { CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use CONNECT HTTP/1.1 */ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the host name rather than the IP address. added in 7.18.0 */ } curl_proxytype; /* this enum was added in 7.10 */ /* * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: * * CURLAUTH_NONE - No HTTP authentication * CURLAUTH_BASIC - HTTP Basic authentication (default) * CURLAUTH_DIGEST - HTTP Digest authentication * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) * CURLAUTH_NTLM - HTTP NTLM authentication * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper * CURLAUTH_BEARER - HTTP Bearer token authentication * CURLAUTH_ONLY - Use together with a single other type to force no * authentication or just that single type * CURLAUTH_ANY - All fine types set * CURLAUTH_ANYSAFE - All fine types except Basic */ #define CURLAUTH_NONE ((unsigned long)0) #define CURLAUTH_BASIC (((unsigned long)1)<<0) #define CURLAUTH_DIGEST (((unsigned long)1)<<1) #define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) /* Deprecated since the advent of CURLAUTH_NEGOTIATE */ #define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE /* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ #define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE #define CURLAUTH_NTLM (((unsigned long)1)<<3) #define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) #define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) #define CURLAUTH_BEARER (((unsigned long)1)<<6) #define CURLAUTH_ONLY (((unsigned long)1)<<31) #define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) #define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) #define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ #define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ #define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ #define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ #define CURLSSH_AUTH_HOST (1<<2) /* host key files */ #define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ #define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ #define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY #define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ #define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ #define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ #define CURL_ERROR_SIZE 256 enum curl_khtype { CURLKHTYPE_UNKNOWN, CURLKHTYPE_RSA1, CURLKHTYPE_RSA, CURLKHTYPE_DSS, CURLKHTYPE_ECDSA, CURLKHTYPE_ED25519 }; struct curl_khkey { const char *key; /* points to a zero-terminated string encoded with base64 if len is zero, otherwise to the "raw" data */ size_t len; enum curl_khtype keytype; }; /* this is the set of return values expected from the curl_sshkeycallback callback */ enum curl_khstat { CURLKHSTAT_FINE_ADD_TO_FILE, CURLKHSTAT_FINE, CURLKHSTAT_REJECT, /* reject the connection, return an error */ CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so this causes a CURLE_DEFER error but otherwise the connection will be left intact etc */ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ }; /* this is the set of status codes pass in to the callback */ enum curl_khmatch { CURLKHMATCH_OK, /* match */ CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ CURLKHMATCH_MISSING, /* no matching host/key found */ CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ }; typedef int (*curl_sshkeycallback) (CURL *easy, /* easy handle */ const struct curl_khkey *knownkey, /* known */ const struct curl_khkey *foundkey, /* found */ enum curl_khmatch, /* libcurl's view on the keys */ void *clientp); /* custom pointer passed from app */ /* parameter for the CURLOPT_USE_SSL option */ typedef enum { CURLUSESSL_NONE, /* do not attempt to use SSL */ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ CURLUSESSL_ALL, /* SSL for all communication or fail */ CURLUSESSL_LAST /* not an option, never use */ } curl_usessl; /* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ /* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the name of improving interoperability with older servers. Some SSL libraries have introduced work-arounds for this flaw but those work-arounds sometimes make the SSL communication fail. To regain functionality with those broken servers, a user can this way allow the vulnerability back. */ #define CURLSSLOPT_ALLOW_BEAST (1<<0) /* - NO_REVOKE tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. */ #define CURLSSLOPT_NO_REVOKE (1<<1) /* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain if possible. The OpenSSL backend has this ability. */ #define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) /* The default connection attempt delay in milliseconds for happy eyeballs. CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document this value, keep them in sync. */ #define CURL_HET_DEFAULT 200L /* The default connection upkeep interval in milliseconds. */ #define CURL_UPKEEP_INTERVAL_DEFAULT 60000L #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* Backwards compatibility with older names */ /* These are scheduled to disappear by 2009 */ #define CURLFTPSSL_NONE CURLUSESSL_NONE #define CURLFTPSSL_TRY CURLUSESSL_TRY #define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL #define CURLFTPSSL_ALL CURLUSESSL_ALL #define CURLFTPSSL_LAST CURLUSESSL_LAST #define curl_ftpssl curl_usessl #endif /*!CURL_NO_OLDIES*/ /* parameter for the CURLOPT_FTP_SSL_CCC option */ typedef enum { CURLFTPSSL_CCC_NONE, /* do not send CCC */ CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ CURLFTPSSL_CCC_LAST /* not an option, never use */ } curl_ftpccc; /* parameter for the CURLOPT_FTPSSLAUTH option */ typedef enum { CURLFTPAUTH_DEFAULT, /* let libcurl decide */ CURLFTPAUTH_SSL, /* use "AUTH SSL" */ CURLFTPAUTH_TLS, /* use "AUTH TLS" */ CURLFTPAUTH_LAST /* not an option, never use */ } curl_ftpauth; /* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ typedef enum { CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD again if MKD succeeded, for SFTP this does similar magic */ CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD again even if MKD failed! */ CURLFTP_CREATE_DIR_LAST /* not an option, never use */ } curl_ftpcreatedir; /* parameter for the CURLOPT_FTP_FILEMETHOD option */ typedef enum { CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ CURLFTPMETHOD_NOCWD, /* no CWD at all */ CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ CURLFTPMETHOD_LAST /* not an option, never use */ } curl_ftpmethod; /* bitmask defines for CURLOPT_HEADEROPT */ #define CURLHEADER_UNIFIED 0 #define CURLHEADER_SEPARATE (1<<0) /* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ #define CURLALTSVC_IMMEDIATELY (1<<0) #define CURLALTSVC_READONLYFILE (1<<2) #define CURLALTSVC_H1 (1<<3) #define CURLALTSVC_H2 (1<<4) #define CURLALTSVC_H3 (1<<5) /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ #define CURLPROTO_HTTP (1<<0) #define CURLPROTO_HTTPS (1<<1) #define CURLPROTO_FTP (1<<2) #define CURLPROTO_FTPS (1<<3) #define CURLPROTO_SCP (1<<4) #define CURLPROTO_SFTP (1<<5) #define CURLPROTO_TELNET (1<<6) #define CURLPROTO_LDAP (1<<7) #define CURLPROTO_LDAPS (1<<8) #define CURLPROTO_DICT (1<<9) #define CURLPROTO_FILE (1<<10) #define CURLPROTO_TFTP (1<<11) #define CURLPROTO_IMAP (1<<12) #define CURLPROTO_IMAPS (1<<13) #define CURLPROTO_POP3 (1<<14) #define CURLPROTO_POP3S (1<<15) #define CURLPROTO_SMTP (1<<16) #define CURLPROTO_SMTPS (1<<17) #define CURLPROTO_RTSP (1<<18) #define CURLPROTO_RTMP (1<<19) #define CURLPROTO_RTMPT (1<<20) #define CURLPROTO_RTMPE (1<<21) #define CURLPROTO_RTMPTE (1<<22) #define CURLPROTO_RTMPS (1<<23) #define CURLPROTO_RTMPTS (1<<24) #define CURLPROTO_GOPHER (1<<25) #define CURLPROTO_SMB (1<<26) #define CURLPROTO_SMBS (1<<27) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ #define CURLOPTTYPE_LONG 0 #define CURLOPTTYPE_OBJECTPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 /* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the string options from the header file */ #define CURLOPT(na,t,nu) na = t + nu /* handy aliases that make no run-time difference */ #define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT #define CURLOPTTYPE_SLISTPOINT CURLOPTTYPE_OBJECTPOINT /* * All CURLOPT_* values. */ typedef enum { /* This is the FILE * or void * the regular output should be written to. */ CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_OBJECTPOINT, 1), /* The full URL to get/put */ CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2), /* Port number to connect to, if other than default. */ CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3), /* Name of proxy to use. */ CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4), /* "user:password;options" to use when fetching. */ CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5), /* "user:password" to use with proxy. */ CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6), /* Range to get, specified as an ASCII string. */ CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7), /* not used */ /* Specified file stream to upload from (use as input): */ CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_OBJECTPOINT, 9), /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. */ CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10), /* Function that will be called to store the output (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11), /* Function that will be called to read the input (instead of fread). The * parameters will use fread() syntax, make sure to follow them. */ CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12), /* Time-out the read operation after this amount of seconds */ CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13), /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about * how large the file being sent really is. That allows better error * checking and better verifies that the upload was successful. -1 means * unknown size. * * For large file support, there is also a _LARGE version of the key * which takes an off_t type, allowing platforms with larger off_t * sizes to handle larger files. See below for INFILESIZE_LARGE. */ CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14), /* POST static input fields. */ CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15), /* Set the referrer page (needed by some CGIs) */ CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16), /* Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17), /* Set the User-Agent string (examined by some CGIs) */ CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18), /* If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. * You could i.e if you have a pretty high speed connection, abort if * it is less than 2000 bytes/sec during 20 seconds. */ /* Set the "low speed limit" */ CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19), /* Set the "low speed time" */ CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20), /* Set the continuation offset. * * Note there is also a _LARGE version of this key which uses * off_t types, allowing for large file offsets on platforms which * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. */ CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21), /* Set cookie in request: */ CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22), /* This points to a linked list of headers, struct curl_slist kind. This list is also used for RTSP (in spite of its name) */ CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23), /* This points to a linked list of post entries, struct curl_httppost */ CURLOPT(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24), /* name of the file keeping your private SSL-certificate */ CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25), /* password for the SSL or SSH private key */ CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26), /* send TYPE parameter? */ CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27), /* send linked-list of QUOTE commands */ CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28), /* send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified */ CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_OBJECTPOINT, 29), /* point to a file to read the initial cookies from, also enables "cookie awareness" */ CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31), /* What version to specifically try to use. See CURL_SSLVERSION defines below. */ CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_LONG, 32), /* What kind of HTTP time condition to use, see defines */ CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_LONG, 33), /* Time to use with the above condition. Specified in number of seconds since 1 Jan 1970 */ CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34), /* 35 = OBSOLETE */ /* Custom request, for customizing the get command like HTTP: DELETE, TRACE and others FTP: to use a different list command */ CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36), /* FILE handle to use instead of stderr */ CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37), /* 38 is not used */ /* send linked-list of post-transfer QUOTE commands */ CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39), /* OBSOLETE, do not use! */ CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40), /* talk a lot */ CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41), /* throw the header out too */ CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42), /* shut off the progress meter */ CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43), /* use HEAD to get http document */ CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44), /* no output on http error codes >= 400 */ CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45), /* this is an upload */ CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46), /* HTTP POST method */ CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47), /* bare names when listing directories */ CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48), /* Append instead of overwrite on upload! */ CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50), /* Specify whether to read the user+password from the .netrc or the URL. * This must be one of the CURL_NETRC_* enums below. */ CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_LONG, 51), /* use Location: Luke! */ CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52), /* transfer data in text/ASCII format */ CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53), /* HTTP PUT */ CURLOPT(CURLOPT_PUT, CURLOPTTYPE_LONG, 54), /* 55 = OBSOLETE */ /* DEPRECATED * Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ CURLOPT(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56), /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION callbacks */ CURLOPT(CURLOPT_PROGRESSDATA, CURLOPTTYPE_OBJECTPOINT, 57), #define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA /* We want the referrer field set automatically when following locations */ CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58), /* Port of the proxy, can be set in the proxy string as well with: "[host]:[port]" */ CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59), /* size of the POST input data, if strlen() is not good to use */ CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60), /* tunnel non-http operations through a HTTP proxy */ CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61), /* Set the interface string to use as outgoing network interface */ CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62), /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but doesn't match one of these, 'private' will be used. */ CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65), /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ /* Maximum number of http redirects to follow */ CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68), /* Pass a long set to 1 to get the date of the requested document (if possible)! Pass a zero to shut it off. */ CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69), /* This points to a linked list of telnet options */ CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70), /* Max amount of cached alive connections */ CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71), /* OBSOLETE, do not use! */ CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72), /* 73 = OBSOLETE */ /* Set to explicitly use a new connection for the upcoming transfer. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74), /* Set to explicitly forbid the upcoming transfer's connection to be re-used when done. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75), /* Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ CURLOPT(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76), /* Set to the Entropy Gathering Daemon socket pathname */ CURLOPT(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77), /* Time-out connect operations after this amount of seconds, if connects are OK within this time, then fine... This only aborts the connect phase. */ CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78), /* Function that will be called to store headers (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79), /* Set this to force the HTTP request to get back to GET. Only really usable if POST, PUT or a custom request have been used first. */ CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80), /* Set if we should verify the Common name from the peer certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches the * provided hostname. */ CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81), /* Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout. */ CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82), /* Specify which SSL ciphers to use */ CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83), /* Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_LONG, 84), /* Specifically switch on or off the FTP engine's use of the EPSV command. By default, that one will always be attempted before the more traditional PASV command. */ CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86), /* name of the file keeping your private SSL-key */ CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88), /* crypto engine for the SSL-sub system */ CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89), /* set the crypto engine for the SSL-sub system as default the param has no meaning... */ CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90), /* Non-zero value means to use the global dns cache */ /* DEPRECATED, do not use! */ CURLOPT(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91), /* DNS cache timeout */ CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92), /* send linked-list of pre-transfer QUOTE commands */ CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93), /* set the debug function */ CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94), /* set the data for the debug function */ CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_OBJECTPOINT, 95), /* mark this as start of a cookie session */ CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96), /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97), /* Instruct libcurl to use a smaller receive buffer */ CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98), /* Instruct libcurl to not use any signal/alarm handlers, even when using timeouts. This option is useful for multi-threaded applications. See libcurl-the-guide for more background information. */ CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99), /* Provide a CURLShare for mutexing non-ts data */ CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100), /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_LONG, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed. Before 7.21.6, this was known as CURLOPT_ENCODING */ CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102), /* Set pointer to private data */ CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103), /* Set aliases for HTTP 200 in the HTTP Response header */ CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104), /* Continue to send authentication (user+password) when following locations, even when hostname changed. This can potentially send off the name and password to whatever host the server decides. */ CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105), /* Specifically switch on or off the FTP engine's use of the EPRT command ( it also disables the LPRT attempt). By default, those ones will always be attempted before the good old traditional PORT command. */ CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_USERPWD. Note that setting multiple bits may cause extra network round-trips. */ CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_LONG, 107), /* Set the ssl context callback function, currently only for OpenSSL or WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument. The function must match the curl_ssl_ctx_callback prototype. */ CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108), /* Set the userdata for the ssl context callback function's third argument */ CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_OBJECTPOINT, 109), /* FTP Option that causes missing dirs to be created on the remote server. In 7.19.4 we introduced the convenience enums for this option using the CURLFTP_CREATE_DIR prefix. */ CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. Note that setting multiple bits may cause extra network round-trips. */ CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_LONG, 111), /* FTP option that changes the timeout, in seconds, associated with getting a response. This is different from transfer timeout time and essentially places a demand on the FTP server to acknowledge commands in a timely manner. */ CURLOPT(CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112), #define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to tell libcurl to resolve names to those IP versions only. This only has affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_LONG, 113), /* Set this option to limit the size of a file that will be downloaded from an HTTP or FTP server. Note there is also _LARGE version which adds large file support for platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114), /* See the comment for INFILESIZE above, but in short, specifies * the size of the file being uploaded. -1 means unknown. */ CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115), /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version * of this; look above for RESUME_FROM. */ CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116), /* Sets the maximum size of data that will be downloaded from * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. */ CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117), /* Set this option to the file name of your .netrc file you want libcurl to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118), /* Enable SSL/TLS for FTP, pick one of: CURLUSESSL_TRY - try using SSL, proceed anyway otherwise CURLUSESSL_CONTROL - SSL for the control connection or fail CURLUSESSL_ALL - SSL for all communication or fail */ CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_LONG, 119), /* The _LARGE version of the standard POSTFIELDSIZE option */ CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120), /* Enable/disable the TCP Nagle algorithm */ CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121), /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 123 OBSOLETE. Gone in 7.16.0 */ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 127 OBSOLETE. Gone in 7.16.0 */ /* 128 OBSOLETE. Gone in 7.16.0 */ /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option can be used to change libcurl's default action which is to first try "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK response has been received. Available parameters are: CURLFTPAUTH_DEFAULT - let libcurl decide CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL */ CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_LONG, 129), CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130), CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_OBJECTPOINT, 131), /* 132 OBSOLETE. Gone in 7.16.0 */ /* 133 OBSOLETE. Gone in 7.16.0 */ /* zero terminated string for pass on to the FTP server when asked for "account" info */ CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134), /* feed cookie into cookie engine */ CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135), /* ignore Content-Length */ CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136), /* Set to non-zero to skip the IP address received in a 227 PASV FTP server response. Typically used for FTP-SSL purposes but is not restricted to that. libcurl will then instead use the same IP address it used for the control connection. */ CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137), /* Select "file method" to use when doing FTP, see the curl_ftpmethod above. */ CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_LONG, 138), /* Local port number to bind the socket to */ CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139), /* Number of ports to try, including the first one set with LOCALPORT. Thus, setting it to 1 will make no additional attempts but the first. */ CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140), /* no transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET */ CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141), /* Function that will be called to convert from the network encoding (instead of using the iconv calls in libcurl) */ CURLOPT(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142), /* Function that will be called to convert to the network encoding (instead of using the iconv calls in libcurl) */ CURLOPT(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143), /* Function that will be called to convert from UTF8 (instead of using the iconv calls in libcurl) Note that this is used only for SSL certificate processing */ CURLOPT(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144), /* if the connection proceeds too quickly then need to slow it down */ /* limit-rate: maximum number of bytes per second to send or receive */ CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145), CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146), /* Pointer to command string to send if USER/PASS fails. */ CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147), /* callback function for setting socket options */ CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148), CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_OBJECTPOINT, 149), /* set to 0 to disable session ID re-use for this transfer, default is enabled (== 1) */ CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150), /* allowed SSH authentication methods */ CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_LONG, 151), /* Used by scp/sftp to do public/private key authentication */ CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152), CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153), /* Send CCC (Clear Command Channel) after authentication */ CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154), /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155), CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156), /* set to zero to disable the libcurl's decoding and thus pass the raw body data to the application even when it is encoded/compressed */ CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157), CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158), /* Permission used when creating new files and directories on the remote server for protocols that support it, SFTP/SCP/FILE */ CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159), CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160), /* Set the behaviour of POST when redirecting. Values must be set to one of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_LONG, 161), /* used by scp/sftp to verify the host's public key */ CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162), /* Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning CURL_SOCKET_BAD. The callback should have type curl_opensocket_callback */ CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163), CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 164), /* POST volatile input fields. */ CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165), /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166), /* Callback function for seeking in the input stream */ CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167), CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_OBJECTPOINT, 168), /* CRL file */ CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169), /* Issuer certificate */ CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170), /* (IPv6) Address scope */ CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171), /* Collect certificate chain info and allow it to get retrievable with CURLINFO_CERTINFO after the transfer is complete. */ CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172), /* "name" and "pwd" to use when fetching. */ CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173), CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174), /* "name" and "pwd" to use with Proxy when fetching. */ CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175), CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176), /* Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For example, local.com will match local.com and www.local.com, but NOT notlocal.com or www.notlocal.com. For compatibility with other implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177), /* block size for TFTP transfers */ CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178), /* Socks Service */ /* DEPRECATED, do not use! */ CURLOPT(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179), /* Socks Service */ CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180), /* set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ CURLOPT(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181), /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ CURLOPT(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182), /* set the SSH knownhost file name to use */ CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184), /* set the SSH host key callback custom pointer */ CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_OBJECTPOINT, 185), /* set the SMTP mail originator */ CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186), /* set the list of SMTP mail receiver(s) */ CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187), /* FTP: send PRET before PASV */ CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188), /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_LONG, 189), /* The RTSP session identifier */ CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190), /* The RTSP stream URI */ CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191), /* The Transport: header to use in RTSP requests */ CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192), /* Manually initialize the client RTSP CSeq for this handle */ CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193), /* Manually initialize the server RTSP CSeq for this handle */ CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194), /* The stream to pass to INTERLEAVEFUNCTION. */ CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_OBJECTPOINT, 195), /* Let the application define a custom write method for RTP data */ CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196), /* Turn on wildcard matching */ CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197), /* Directory matching callback called before downloading of an individual file (chunk) started */ CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198), /* Directory matching callback called after the file (chunk) was downloaded, or skipped */ CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199), /* Change match (fnmatch-like) callback for wildcard matching */ CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200), /* Let the application define custom chunk data pointer */ CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_OBJECTPOINT, 201), /* FNMATCH_FUNCTION user pointer */ CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_OBJECTPOINT, 202), /* send linked-list of name:port:address sets */ CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203), /* Set a username for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204), /* Set a password for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205), /* Set authentication type for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206), /* Set to 1 to enable the "TE:" header in HTTP requests to ask for compressed transfer-encoded responses. Set to 0 to disable the use of TE: in outgoing requests. The current default is 0, but it might change in a future libcurl release. libcurl will ask for the compressed methods it knows of, and if that isn't any, it will not ask for transfer-encoding at all even if this option is set to 1. */ CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207), /* Callback function for closing socket (instead of close(2)). The callback should have type curl_closesocket_callback */ CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208), CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 209), /* allow GSSAPI credential delegation */ CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_LONG, 210), /* Set the name servers to use for DNS resolution */ CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211), /* Time-out accept operations (currently for FTP only) after this amount of milliseconds. */ CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212), /* Set TCP keepalive */ CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213), /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214), CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215), /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_LONG, 216), /* Set the SMTP auth originator */ CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217), /* Enable/disable SASL initial response */ CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218), /* Function that will be called instead of the internal progress display * function. This function should be defined as the curl_xferinfo_callback * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219), /* The XOAUTH2 bearer token */ CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220), /* Set the interface string to use as outgoing network * interface for DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221), /* Set the local IPv4 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222), /* Set the local IPv6 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223), /* Set authentication options directly */ CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224), /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ CURLOPT(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225), /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226), /* Time to wait for a response to a HTTP request containing an * Expect: 100-continue header before sending the data anyway. */ CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227), /* This points to a linked list of headers used for proxy requests only, struct curl_slist kind */ CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228), /* Pass in a bitmask of "header options" */ CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_LONG, 229), /* The public key in DER form used to validate the peer public key this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230), /* Path to Unix domain socket */ CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231), /* Set if we should verify the certificate status. */ CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), /* Set if we should enable TLS false start. */ CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233), /* Do not squash dot-dot sequences */ CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234), /* Proxy Service Name */ CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235), /* Service Name */ CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236), /* Wait/don't wait for pipe/mutex to clarify */ CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237), /* Set the protocol used when curl is given a URL without a protocol */ CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238), /* Set stream weight, 1 - 256 (default is 16) */ CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239), /* Set stream dependency on another CURL handle */ CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240), /* Set E-xclusive stream dependency on another CURL handle */ CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241), /* Do not send any tftp option requests to the server */ CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242), /* Linked-list of host:port:connect-to-host:connect-to-port, overrides the URL's host:port (only for the network layer) */ CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243), /* Set TCP Fast Open */ CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244), /* Continue to send data if the server responds early with an * HTTP status code >= 300 */ CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245), /* The CApath or CAfile used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246), /* The CApath directory used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247), /* Set if we should verify the proxy in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248), /* Set if we should verify the Common name from the proxy certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches * the provided hostname. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249), /* What version to specifically try to use for proxy. See CURL_SSLVERSION defines below. */ CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_LONG, 250), /* Set a username for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251), /* Set a password for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252), /* Set authentication type for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253), /* name of the file keeping your private SSL-certificate for proxy */ CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for proxy */ CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255), /* name of the file keeping your private SSL-key for proxy */ CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for proxy */ CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257), /* password for the SSL private key for proxy */ CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258), /* Specify which SSL ciphers to use for proxy */ CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259), /* CRL file for proxy */ CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260), /* Enable/disable specific SSL features with a bitmask for proxy, see CURLSSLOPT_* */ CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261), /* Name of pre proxy to use. */ CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262), /* The public key in DER form used to validate the proxy public key this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263), /* Path to an abstract Unix domain socket */ CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264), /* Suppress proxy CONNECT response headers from user callbacks */ CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265), /* The request target, instead of extracted from the URL */ CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266), /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267), /* Enable/disable SSH compression */ CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268), /* Post MIME data. */ CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269), /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of seconds since 1 Jan 1970. */ CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270), /* Head start in milliseconds to give happy eyeballs. */ CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271), /* Function that will be called before a resolver request is made */ CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272), /* User data to pass to the resolver start callback. */ CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_OBJECTPOINT, 273), /* send HAProxy PROXY protocol header? */ CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274), /* shuffle addresses before use when DNS returns multiple */ CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275), /* Specify which TLS 1.3 ciphers suites to use */ CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276), CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277), /* Disallow specifying username/login in URL. */ CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278), /* DNS-over-HTTPS URL */ CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279), /* Preferred buffer size to use for uploads */ CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280), /* Time in ms between connection upkeep calls for long-lived connections. */ CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281), /* Specify URL using CURL URL API. */ CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282), /* add trailing data just after no more data is available */ CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283), /* pointer to be passed to HTTP_TRAILER_FUNCTION */ CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_OBJECTPOINT, 284), /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285), /* alt-svc control bitmask */ CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286), /* alt-svc cache file name to possibly read from/write to */ CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287), /* maximum age of a connection to consider it for reuse (in seconds) */ CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288), /* SASL authorisation identity */ CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289), /* allow RCPT TO command to fail for some recipients */ CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290), CURLOPT_LASTENTRY /* the last unused */ } CURLoption; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* Backwards compatibility with older names */ /* These are scheduled to disappear by 2011 */ /* This was added in version 7.19.1 */ #define CURLOPT_POST301 CURLOPT_POSTREDIR /* These are scheduled to disappear by 2009 */ /* The following were added in 7.17.0 */ #define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD #define CURLOPT_FTPAPPEND CURLOPT_APPEND #define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY #define CURLOPT_FTP_SSL CURLOPT_USE_SSL /* The following were added earlier */ #define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD #define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL #else /* This is set if CURL_NO_OLDIES is defined at compile-time */ #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ #endif /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host name resolves addresses using more than one IP protocol version, this option might be handy to force libcurl to use a specific IP version. */ #define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP versions that your system allows */ #define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ #define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ /* three convenient "aliases" that follow the name scheme better */ #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ enum { CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd like the library to choose the best possible for us! */ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 Upgrade */ CURL_HTTP_VERSION_3 = 30, /* Makes use of explicit HTTP/3 without fallback. Use CURLOPT_ALTSVC to enable HTTP/3 upgrade */ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; /* Convenience definition simple because the name of the version is HTTP/2 and not 2.0. The 2_0 version of the enum name was set while the version was still planned to be 2.0 and we stick to it for compatibility. */ #define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 /* * Public API enums for RTSP requests */ enum { CURL_RTSPREQ_NONE, /* first in list */ CURL_RTSPREQ_OPTIONS, CURL_RTSPREQ_DESCRIBE, CURL_RTSPREQ_ANNOUNCE, CURL_RTSPREQ_SETUP, CURL_RTSPREQ_PLAY, CURL_RTSPREQ_PAUSE, CURL_RTSPREQ_TEARDOWN, CURL_RTSPREQ_GET_PARAMETER, CURL_RTSPREQ_SET_PARAMETER, CURL_RTSPREQ_RECORD, CURL_RTSPREQ_RECEIVE, CURL_RTSPREQ_LAST /* last in list */ }; /* These enums are for use with the CURLOPT_NETRC option. */ enum CURL_NETRC_OPTION { CURL_NETRC_IGNORED, /* The .netrc will never be read. * This is the default. */ CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred * to one in the .netrc. */ CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. * Unless one is set programmatically, the .netrc * will be queried. */ CURL_NETRC_LAST }; enum { CURL_SSLVERSION_DEFAULT, CURL_SSLVERSION_TLSv1, /* TLS 1.x */ CURL_SSLVERSION_SSLv2, CURL_SSLVERSION_SSLv3, CURL_SSLVERSION_TLSv1_0, CURL_SSLVERSION_TLSv1_1, CURL_SSLVERSION_TLSv1_2, CURL_SSLVERSION_TLSv1_3, CURL_SSLVERSION_LAST /* never use, keep last */ }; enum { CURL_SSLVERSION_MAX_NONE = 0, CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), /* never use, keep last */ CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) }; enum CURL_TLSAUTH { CURL_TLSAUTH_NONE, CURL_TLSAUTH_SRP, CURL_TLSAUTH_LAST /* never use, keep last */ }; /* symbols to use with CURLOPT_POSTREDIR. CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ #define CURL_REDIR_GET_ALL 0 #define CURL_REDIR_POST_301 1 #define CURL_REDIR_POST_302 2 #define CURL_REDIR_POST_303 4 #define CURL_REDIR_POST_ALL \ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) typedef enum { CURL_TIMECOND_NONE, CURL_TIMECOND_IFMODSINCE, CURL_TIMECOND_IFUNMODSINCE, CURL_TIMECOND_LASTMOD, CURL_TIMECOND_LAST } curl_TimeCond; /* Special size_t value signaling a zero-terminated string. */ #define CURL_ZERO_TERMINATED ((size_t) -1) /* curl_strequal() and curl_strnequal() are subject for removal in a future release */ CURL_EXTERN int curl_strequal(const char *s1, const char *s2); CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); /* Mime/form handling support. */ typedef struct curl_mime_s curl_mime; /* Mime context. */ typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ /* * NAME curl_mime_init() * * DESCRIPTION * * Create a mime context and return its handle. The easy parameter is the * target handle. */ CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); /* * NAME curl_mime_free() * * DESCRIPTION * * release a mime handle and its substructures. */ CURL_EXTERN void curl_mime_free(curl_mime *mime); /* * NAME curl_mime_addpart() * * DESCRIPTION * * Append a new empty part to the given mime context and return a handle to * the created part. */ CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); /* * NAME curl_mime_name() * * DESCRIPTION * * Set mime/form part name. */ CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); /* * NAME curl_mime_filename() * * DESCRIPTION * * Set mime part remote file name. */ CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, const char *filename); /* * NAME curl_mime_type() * * DESCRIPTION * * Set mime part type. */ CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); /* * NAME curl_mime_encoder() * * DESCRIPTION * * Set mime data transfer encoder. */ CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding); /* * NAME curl_mime_data() * * DESCRIPTION * * Set mime part data source from memory data, */ CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize); /* * NAME curl_mime_filedata() * * DESCRIPTION * * Set mime part data source from named file. */ CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename); /* * NAME curl_mime_data_cb() * * DESCRIPTION * * Set mime part data source from callback function. */ CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, curl_read_callback readfunc, curl_seek_callback seekfunc, curl_free_callback freefunc, void *arg); /* * NAME curl_mime_subparts() * * DESCRIPTION * * Set mime part data source from subparts. */ CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts); /* * NAME curl_mime_headers() * * DESCRIPTION * * Set mime part headers. */ CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership); typedef enum { CURLFORM_NOTHING, /********* the first one is unused ************/ CURLFORM_COPYNAME, CURLFORM_PTRNAME, CURLFORM_NAMELENGTH, CURLFORM_COPYCONTENTS, CURLFORM_PTRCONTENTS, CURLFORM_CONTENTSLENGTH, CURLFORM_FILECONTENT, CURLFORM_ARRAY, CURLFORM_OBSOLETE, CURLFORM_FILE, CURLFORM_BUFFER, CURLFORM_BUFFERPTR, CURLFORM_BUFFERLENGTH, CURLFORM_CONTENTTYPE, CURLFORM_CONTENTHEADER, CURLFORM_FILENAME, CURLFORM_END, CURLFORM_OBSOLETE2, CURLFORM_STREAM, CURLFORM_CONTENTLEN, /* added in 7.46.0, provide a curl_off_t length */ CURLFORM_LASTENTRY /* the last unused */ } CURLformoption; /* structure to be used as parameter for CURLFORM_ARRAY */ struct curl_forms { CURLformoption option; const char *value; }; /* use this for multipart formpost building */ /* Returns code for curl_formadd() * * Returns: * CURL_FORMADD_OK on success * CURL_FORMADD_MEMORY if the FormInfo allocation fails * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form * CURL_FORMADD_NULL if a null pointer was given for a char * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated * CURL_FORMADD_MEMORY if some allocation for string copying failed. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array * ***************************************************************************/ typedef enum { CURL_FORMADD_OK, /* first, no error */ CURL_FORMADD_MEMORY, CURL_FORMADD_OPTION_TWICE, CURL_FORMADD_NULL, CURL_FORMADD_UNKNOWN_OPTION, CURL_FORMADD_INCOMPLETE, CURL_FORMADD_ILLEGAL_ARRAY, CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ CURL_FORMADD_LAST /* last */ } CURLFORMcode; /* * NAME curl_formadd() * * DESCRIPTION * * Pretty advanced function for building multi-part formposts. Each invoke * adds one part that together construct a full post. Then use * CURLOPT_HTTPPOST to send it off to libcurl. */ CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...); /* * callback function for curl_formget() * The void *arg pointer will be the one passed as second argument to * curl_formget(). * The character buffer passed to it must not be freed. * Should return the buffer length passed to it as the argument "len" on * success. */ typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); /* * NAME curl_formget() * * DESCRIPTION * * Serialize a curl_httppost struct built with curl_formadd(). * Accepts a void pointer as second argument which will be passed to * the curl_formget_callback function. * Returns 0 on success. */ CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append); /* * NAME curl_formfree() * * DESCRIPTION * * Free a multipart formpost previously built with curl_formadd(). */ CURL_EXTERN void curl_formfree(struct curl_httppost *form); /* * NAME curl_getenv() * * DESCRIPTION * * Returns a malloc()'ed string that MUST be curl_free()ed after usage is * complete. DEPRECATED - see lib/README.curlx */ CURL_EXTERN char *curl_getenv(const char *variable); /* * NAME curl_version() * * DESCRIPTION * * Returns a static ascii string of the libcurl version. */ CURL_EXTERN char *curl_version(void); /* * NAME curl_easy_escape() * * DESCRIPTION * * Escapes URL strings (converts all letters consider illegal in URLs to their * %XX versions). This function returns a new allocated string or NULL if an * error occurred. */ CURL_EXTERN char *curl_easy_escape(CURL *handle, const char *string, int length); /* the previous version: */ CURL_EXTERN char *curl_escape(const char *string, int length); /* * NAME curl_easy_unescape() * * DESCRIPTION * * Unescapes URL encoding in strings (converts all %XX codes to their 8bit * versions). This function returns a new allocated string or NULL if an error * occurred. * Conversion Note: On non-ASCII platforms the ASCII %XX codes are * converted into the host encoding. */ CURL_EXTERN char *curl_easy_unescape(CURL *handle, const char *string, int length, int *outlength); /* the previous version */ CURL_EXTERN char *curl_unescape(const char *string, int length); /* * NAME curl_free() * * DESCRIPTION * * Provided for de-allocation in the same translation unit that did the * allocation. Added in libcurl 7.10 */ CURL_EXTERN void curl_free(void *p); /* * NAME curl_global_init() * * DESCRIPTION * * curl_global_init() should be invoked exactly once for each application that * uses libcurl and before any call of other libcurl functions. * * This function is not thread-safe! */ CURL_EXTERN CURLcode curl_global_init(long flags); /* * NAME curl_global_init_mem() * * DESCRIPTION * * curl_global_init() or curl_global_init_mem() should be invoked exactly once * for each application that uses libcurl. This function can be used to * initialize libcurl and set user defined memory management callback * functions. Users can implement memory management routines to check for * memory leaks, check for mis-use of the curl library etc. User registered * callback routines with be invoked by this library instead of the system * memory management routines like malloc, free etc. */ CURL_EXTERN CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c); /* * NAME curl_global_cleanup() * * DESCRIPTION * * curl_global_cleanup() should be invoked exactly once for each application * that uses libcurl */ CURL_EXTERN void curl_global_cleanup(void); /* linked-list structure for the CURLOPT_QUOTE option (and other) */ struct curl_slist { char *data; struct curl_slist *next; }; /* * NAME curl_global_sslset() * * DESCRIPTION * * When built with multiple SSL backends, curl_global_sslset() allows to * choose one. This function can only be called once, and it must be called * *before* curl_global_init(). * * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The * backend can also be specified via the name parameter (passing -1 as id). * If both id and name are specified, the name will be ignored. If neither id * nor name are specified, the function will fail with * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the * NULL-terminated list of available backends. * * Upon success, the function returns CURLSSLSET_OK. * * If the specified SSL backend is not available, the function returns * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated * list of available SSL backends. * * The SSL backend can be set only once. If it has already been set, a * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. */ typedef struct { curl_sslbackend id; const char *name; } curl_ssl_backend; typedef enum { CURLSSLSET_OK = 0, CURLSSLSET_UNKNOWN_BACKEND, CURLSSLSET_TOO_LATE, CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ } CURLsslset; CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail); /* * NAME curl_slist_append() * * DESCRIPTION * * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, const char *); /* * NAME curl_slist_free_all() * * DESCRIPTION * * free a previously built curl_slist. */ CURL_EXTERN void curl_slist_free_all(struct curl_slist *); /* * NAME curl_getdate() * * DESCRIPTION * * Returns the time, in seconds since 1 Jan 1970 of the time string given in * the first argument. The time argument in the second parameter is unused * and should be set to NULL. */ CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); /* info about the certificate chain, only for OpenSSL, GnuTLS, Schannel, NSS and GSKit builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ struct curl_certinfo { int num_of_certs; /* number of certificates with information */ struct curl_slist **certinfo; /* for each index in this array, there's a linked list with textual information in the format "name: value" */ }; /* Information about the SSL library used and the respective internal SSL handle, which can be used to obtain further information regarding the connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ struct curl_tlssessioninfo { curl_sslbackend backend; void *internals; }; #define CURLINFO_STRING 0x100000 #define CURLINFO_LONG 0x200000 #define CURLINFO_DOUBLE 0x300000 #define CURLINFO_SLIST 0x400000 #define CURLINFO_PTR 0x400000 /* same as SLIST */ #define CURLINFO_SOCKET 0x500000 #define CURLINFO_OFF_T 0x600000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 typedef enum { CURLINFO_NONE, /* first, never use this */ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, CURLINFO_FILETIME = CURLINFO_LONG + 14, CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, CURLINFO_PRIVATE = CURLINFO_STRING + 21, CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, CURLINFO_CERTINFO = CURLINFO_PTR + 34, CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, CURLINFO_PROTOCOL = CURLINFO_LONG + 48, CURLINFO_SCHEME = CURLINFO_STRING + 49, /* Fill in new entries below here! */ /* Preferably these would be defined conditionally based on the sizeof curl_off_t being 64-bits */ CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, CURLINFO_RETRY_AFTER = CURLINFO_OFF_T + 57, CURLINFO_LASTONE = 57 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as CURLINFO_HTTP_CODE */ #define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE typedef enum { CURLCLOSEPOLICY_NONE, /* first, never use this */ CURLCLOSEPOLICY_OLDEST, CURLCLOSEPOLICY_LEAST_RECENTLY_USED, CURLCLOSEPOLICY_LEAST_TRAFFIC, CURLCLOSEPOLICY_SLOWEST, CURLCLOSEPOLICY_CALLBACK, CURLCLOSEPOLICY_LAST /* last, never use this */ } curl_closepolicy; #define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ #define CURL_GLOBAL_WIN32 (1<<1) #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_NOTHING 0 #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL #define CURL_GLOBAL_ACK_EINTR (1<<2) /***************************************************************************** * Setup defines, protos etc for the sharing stuff. */ /* Different data locks for a single share */ typedef enum { CURL_LOCK_DATA_NONE = 0, /* CURL_LOCK_DATA_SHARE is used internally to say that * the locking is just made to change the internal state of the share * itself. */ CURL_LOCK_DATA_SHARE, CURL_LOCK_DATA_COOKIE, CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_DATA_CONNECT, CURL_LOCK_DATA_PSL, CURL_LOCK_DATA_LAST } curl_lock_data; /* Different lock access types */ typedef enum { CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ CURL_LOCK_ACCESS_LAST /* never use */ } curl_lock_access; typedef void (*curl_lock_function)(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr); typedef void (*curl_unlock_function)(CURL *handle, curl_lock_data data, void *userptr); typedef enum { CURLSHE_OK, /* all is fine */ CURLSHE_BAD_OPTION, /* 1 */ CURLSHE_IN_USE, /* 2 */ CURLSHE_INVALID, /* 3 */ CURLSHE_NOMEM, /* 4 out of memory */ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ CURLSHE_LAST /* never use */ } CURLSHcode; typedef enum { CURLSHOPT_NONE, /* don't use */ CURLSHOPT_SHARE, /* specify a data type to share */ CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock callback functions */ CURLSHOPT_LAST /* never use */ } CURLSHoption; CURL_EXTERN CURLSH *curl_share_init(void); CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); /**************************************************************************** * Structures for querying information about the curl library at runtime. */ typedef enum { CURLVERSION_FIRST, CURLVERSION_SECOND, CURLVERSION_THIRD, CURLVERSION_FOURTH, CURLVERSION_FIFTH, CURLVERSION_SIXTH, CURLVERSION_LAST /* never actually use this */ } CURLversion; /* The 'CURLVERSION_NOW' is the symbolic name meant to be used by basically all programs ever that want to get version information. It is meant to be a built-in version number for what kind of struct the caller expects. If the struct ever changes, we redefine the NOW to another enum from above. */ #define CURLVERSION_NOW CURLVERSION_SIXTH typedef struct { CURLversion age; /* age of the returned struct */ const char *version; /* LIBCURL_VERSION */ unsigned int version_num; /* LIBCURL_VERSION_NUM */ const char *host; /* OS/host/cpu/machine when configured */ int features; /* bitmask, see defines below */ const char *ssl_version; /* human readable string */ long ssl_version_num; /* not used anymore, always 0 */ const char *libz_version; /* human readable string */ /* protocols is terminated by an entry with a NULL protoname */ const char * const *protocols; /* The fields below this were added in CURLVERSION_SECOND */ const char *ares; int ares_num; /* This field was added in CURLVERSION_THIRD */ const char *libidn; /* These field were added in CURLVERSION_FOURTH */ /* Same as '_libiconv_version' if built with HAVE_ICONV */ int iconv_ver_num; const char *libssh_version; /* human readable string */ /* These fields were added in CURLVERSION_FIFTH */ unsigned int brotli_ver_num; /* Numeric Brotli version (MAJOR << 24) | (MINOR << 12) | PATCH */ const char *brotli_version; /* human readable string. */ /* These fields were added in CURLVERSION_SIXTH */ unsigned int nghttp2_ver_num; /* Numeric nghttp2 version (MAJOR << 16) | (MINOR << 8) | PATCH */ const char *nghttp2_version; /* human readable string. */ const char *quic_version; /* human readable quic (+ HTTP/3) library + version or NULL */ } curl_version_info_data; #define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ #define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported (deprecated) */ #define CURL_VERSION_SSL (1<<2) /* SSL options are present */ #define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ #define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ #define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported (deprecated) */ #define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ #define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ #define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ #define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ #define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are supported */ #define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ #define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ #define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ #define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ #define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper is supported */ #define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ #define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ #define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ #define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ #define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used for cookie domain verification */ #define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ #define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ #define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ #define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ #define CURL_VERSION_HTTP3 (1<<25) /* HTTP3 support built-in */ #define CURL_VERSION_ESNI (1<<26) /* ESNI support */ /* * NAME curl_version_info() * * DESCRIPTION * * This function returns a pointer to a static copy of the version info * struct. See above. */ CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); /* * NAME curl_easy_strerror() * * DESCRIPTION * * The curl_easy_strerror function may be used to turn a CURLcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ CURL_EXTERN const char *curl_easy_strerror(CURLcode); /* * NAME curl_share_strerror() * * DESCRIPTION * * The curl_share_strerror function may be used to turn a CURLSHcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ CURL_EXTERN const char *curl_share_strerror(CURLSHcode); /* * NAME curl_easy_pause() * * DESCRIPTION * * The curl_easy_pause function pauses or unpauses transfers. Select the new * state by setting the bitmask, use the convenience defines below. * */ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); #define CURLPAUSE_RECV (1<<0) #define CURLPAUSE_RECV_CONT (0) #define CURLPAUSE_SEND (1<<2) #define CURLPAUSE_SEND_CONT (0) #define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) #define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) #ifdef __cplusplus } #endif /* unfortunately, the easy.h and multi.h include files need options and info stuff before they can be included! */ #include "easy.h" /* nothing in curl is fun without the easy stuff */ #include "multi.h" #include "urlapi.h" /* the typechecker doesn't work in C++ (yet) */ #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) #include "typecheck-gcc.h" #else #if defined(__STDC__) && (__STDC__ >= 1) /* This preprocessor magic that replaces a call with the exact same call is only done to make sure application authors pass exactly three arguments to these functions. */ #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) #define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) #endif /* __STDC__ >= 1 */ #endif /* gcc >= 4.3 && !__cplusplus */ #endif /* CURLINC_CURL_H */ davix-0.8.0/deps/curl/include/curl/curlver.h0000644000000000000000000000574514121063461017464 0ustar rootroot#ifndef CURLINC_CURLVER_H #define CURLINC_CURLVER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* This header file contains nothing but libcurl version info, generated by a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ #define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ #define LIBCURL_VERSION "7.69.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 #define LIBCURL_VERSION_MINOR 69 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: 0xXXYYZZ Where XX, YY and ZZ are the main version, release and patch numbers in hexadecimal (using 8 bits each). All three numbers are always represented using two digits. 1.2 would appear as "0x010200" while version 9.11.7 appears as "0x090b07". This 6-digit (24 bits) hexadecimal number does not show pre-release number, and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. Note: This define is the full hex number and _does not_ use the CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ #define LIBCURL_VERSION_NUM 0x074500 /* * This is the date and time when the full source package was created. The * timestamp is not stored in git, as the timestamp is properly set in the * tarballs by the maketgz script. * * The format of the date follows this template: * * "2007-11-23" */ #define LIBCURL_TIMESTAMP "[unreleased]" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) #endif /* CURLINC_CURLVER_H */ davix-0.8.0/deps/curl/include/curl/urlapi.h0000644000000000000000000001061314121063461017264 0ustar rootroot#ifndef CURLINC_URLAPI_H #define CURLINC_URLAPI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl.h" #ifdef __cplusplus extern "C" { #endif /* the error codes for the URL API */ typedef enum { CURLUE_OK, CURLUE_BAD_HANDLE, /* 1 */ CURLUE_BAD_PARTPOINTER, /* 2 */ CURLUE_MALFORMED_INPUT, /* 3 */ CURLUE_BAD_PORT_NUMBER, /* 4 */ CURLUE_UNSUPPORTED_SCHEME, /* 5 */ CURLUE_URLDECODE, /* 6 */ CURLUE_OUT_OF_MEMORY, /* 7 */ CURLUE_USER_NOT_ALLOWED, /* 8 */ CURLUE_UNKNOWN_PART, /* 9 */ CURLUE_NO_SCHEME, /* 10 */ CURLUE_NO_USER, /* 11 */ CURLUE_NO_PASSWORD, /* 12 */ CURLUE_NO_OPTIONS, /* 13 */ CURLUE_NO_HOST, /* 14 */ CURLUE_NO_PORT, /* 15 */ CURLUE_NO_QUERY, /* 16 */ CURLUE_NO_FRAGMENT /* 17 */ } CURLUcode; typedef enum { CURLUPART_URL, CURLUPART_SCHEME, CURLUPART_USER, CURLUPART_PASSWORD, CURLUPART_OPTIONS, CURLUPART_HOST, CURLUPART_PORT, CURLUPART_PATH, CURLUPART_QUERY, CURLUPART_FRAGMENT, CURLUPART_ZONEID /* added in 7.65.0 */ } CURLUPart; #define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ #define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, if the port number matches the default for the scheme */ #define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if missing */ #define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ #define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ #define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ #define CURLU_URLDECODE (1<<6) /* URL decode on get */ #define CURLU_URLENCODE (1<<7) /* URL encode on set */ #define CURLU_APPENDQUERY (1<<8) /* append a form style part */ #define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ #define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the scheme is unknown. */ typedef struct Curl_URL CURLU; /* * curl_url() creates a new CURLU handle and returns a pointer to it. * Must be freed with curl_url_cleanup(). */ CURL_EXTERN CURLU *curl_url(void); /* * curl_url_cleanup() frees the CURLU handle and related resources used for * the URL parsing. It will not free strings previously returned with the URL * API. */ CURL_EXTERN void curl_url_cleanup(CURLU *handle); /* * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new * handle must also be freed with curl_url_cleanup(). */ CURL_EXTERN CURLU *curl_url_dup(CURLU *in); /* * curl_url_get() extracts a specific part of the URL from a CURLU * handle. Returns error code. The returned pointer MUST be freed with * curl_free() afterwards. */ CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, char **part, unsigned int flags); /* * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns * error code. The passed in string will be copied. Passing a NULL instead of * a part string, clears that part. */ CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, const char *part, unsigned int flags); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif /* CURLINC_URLAPI_H */ davix-0.8.0/deps/curl/winbuild/0000755000000000000000000000000014121063461015043 5ustar rootrootdavix-0.8.0/deps/curl/winbuild/makedebug.cmd0000644000000000000000000000256414121063461017463 0ustar rootroot@echo off rem *************************************************************************** rem * _ _ ____ _ rem * Project ___| | | | _ \| | rem * / __| | | | |_) | | rem * | (__| |_| | _ <| |___ rem * \___|\___/|_| \_\_____| rem * rem * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. rem * rem * This software is licensed as described in the file COPYING, which rem * you should have received as part of this distribution. The terms rem * are also available at https://curl.haxx.se/docs/copyright.html. rem * rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell rem * copies of the Software, and permit persons to whom the Software is rem * furnished to do so, under the terms of the COPYING file. rem * rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY rem * KIND, either express or implied. rem * rem *************************************************************************** where.exe nmake.exe >nul 2>&1 IF %ERRORLEVEL% == 1 ( ECHO Error: Can't find `nmake.exe` - be sure to run this script from within a Developer Command-Prompt ECHO. ) ELSE ( nmake /f Makefile.vc mode=static DEBUG=yes GEN_PDB=yes IF %ERRORLEVEL% NEQ 0 ( ECHO "Error: Build Failed" ) ) davix-0.8.0/deps/curl/winbuild/BUILD.WINDOWS.txt0000644000000000000000000001447414121063461017606 0ustar rootrootBuilding with Visual C++, prerequisites ======================================= This document describes how to compile, build and install curl and libcurl from sources using the Visual C++ build tool. To build with VC++, you will of course have to first install VC++. The minimum required version of VC is 6 (part of Visual Studio 6). However using a more recent version is strongly recommended. VC++ is also part of the Windows Platform SDK. You do not have to install the full Visual Studio or Visual C++ if all you want is to build curl. The latest Platform SDK can be downloaded freely from: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive If you are building with VC6 then you will also need the February 2003 Edition of the Platform SDK which can be downloaded from: https://www.microsoft.com/en-us/download/details.aspx?id=12261 If you wish to support zlib, openssl, c-ares, ssh2, you will have to download them separately and copy them to the deps directory as shown below: somedirectory\ |_curl-src | |_winbuild | |_deps |_ lib |_ include |_ bin It is also possible to create the deps directory in some other random places and tell the Makefile its location using the WITH_DEVEL option. Building straight from git ========================== When you check out code git and build it, as opposed from a released source code archive, you need to first run the "buildconf.bat" batch file (present in the source code root directory) to set things up. Building with Visual C++ ======================== Open a Visual Studio Command prompt: Using the 'Developer Command Prompt for VS ' menu entry: where version is the Visual Studio version. The developer prompt at default uses the x86 mode. It is required to call Vcvarsall.bat to setup the prompt for the machine type you want, using Vcvarsall.bat. This type of command prompt may not exist in all Visual Studio versions. For more information, check: https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs https://docs.microsoft.com/en-us/cpp/build/how-to-enable-a-64-bit-visual-cpp-toolset-on-the-command-line Using the 'VS Command Prompt' menu entry: where version is the Visual Studio version, platform is e.g. x64 and type Native of Cross platform build. This type of command prompt may not exist in all Visual Studio versions. See also: https://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx Once you are in the console, go to the winbuild directory in the Curl sources: cd curl-src\winbuild Then you can call nmake /f Makefile.vc with the desired options (see below). The builds will be in the top src directory, builds\ directory, in a directory named using the options given to the nmake call. nmake /f Makefile.vc mode= where is one or many of: VC=<6,7,8,9,10,11,12,14,15> - VC versions WITH_DEVEL= - Paths for the development files (SSL, zlib, etc.) Defaults to sibbling directory deps: ../deps Libraries can be fetched at https://windows.php.net/downloads/php-sdk/deps/ Uncompress them into the deps folder. WITH_SSL= - Enable OpenSSL support, DLL or static WITH_NGHTTP2= - Enable HTTP/2 support, DLL or static WITH_MBEDTLS= - Enable mbedTLS support, DLL or static WITH_CARES= - Enable c-ares support, DLL or static WITH_ZLIB= - Enable zlib support, DLL or static WITH_SSH2= - Enable libSSH2 support, DLL or static WITH_PREFIX= - Where to install the build ENABLE_SSPI= - Enable SSPI support, defaults to yes ENABLE_IPV6= - Enable IPv6, defaults to yes ENABLE_IDN= - Enable use of Windows IDN APIs, defaults to yes Requires Windows Vista or later ENABLE_WINSSL= - Enable native Windows SSL support, defaults to yes GEN_PDB= - Generate Program Database (debug symbols for release build) DEBUG= - Debug builds MACHINE= - Target architecture (default is x86) CARES_PATH= - Custom path for c-ares MBEDTLS_PATH= - Custom path for mbedTLS NGHTTP2_PATH= - Custom path for nghttp2 SSH2_PATH= - Custom path for libSSH2 SSL_PATH= - Custom path for OpenSSL ZLIB_PATH= - Custom path for zlib Static linking of Microsoft's C RunTime (CRT): ============================================== If you are using mode=static nmake will create and link to the static build of libcurl but *not* the static CRT. If you must you can force nmake to link in the static CRT by passing RTLIBCFG=static. Typically you shouldn't use that option, and nmake will default to the DLL CRT. RTLIBCFG is rarely used and therefore rarely tested. When passing RTLIBCFG for a configuration that was already built but not with that option, or if the option was specified differently, you must destroy the build directory containing the configuration so that nmake can build it from scratch. Building your own application with a static libcurl =================================================== When building an application that uses the static libcurl library on Windows, you must define CURL_STATICLIB. Otherwise the linker will look for dynamic import symbols. Legacy Windows and SSL ====================== When you build curl using the build files in this directory the default SSL backend will be WinSSL (Windows SSPI, more specifically Schannel), the native SSL library that comes with the Windows OS. WinSSL in Windows <= XP is not able to connect to servers that no longer support the legacy handshakes and algorithms used by those versions. If you will be using curl in one of those earlier versions of Windows you should choose another SSL backend like OpenSSL. davix-0.8.0/deps/curl/winbuild/rundebug.cmd0000644000000000000000000000226314121063461017346 0ustar rootroot@echo off rem *************************************************************************** rem * _ _ ____ _ rem * Project ___| | | | _ \| | rem * / __| | | | |_) | | rem * | (__| |_| | _ <| |___ rem * \___|\___/|_| \_\_____| rem * rem * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. rem * rem * This software is licensed as described in the file COPYING, which rem * you should have received as part of this distribution. The terms rem * are also available at https://curl.haxx.se/docs/copyright.html. rem * rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell rem * copies of the Software, and permit persons to whom the Software is rem * furnished to do so, under the terms of the COPYING file. rem * rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY rem * KIND, either express or implied. rem * rem *************************************************************************** start cmd /k ..\builds\libcurl-vc-x86-debug-static-ipv6-sspi-winssl\bin\curl.exe https://wttr.in/seattledavix-0.8.0/deps/curl/winbuild/MakefileBuild.vc0000644000000000000000000004527214121063461020104 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1999 - 2018, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** ########################################################################### # # Makefile for building libcurl with MSVC 6 through to 15 # # Usage: see usage message below # Should be invoked from winbuild directory # Edit the paths and desired library name # SSL path is only required if you intend compiling # with SSL. # # This make file leaves the result either a .lib or .dll file # in the \lib directory. It should be called from the \lib # directory. # # An option would have been to allow the source directory to # be specified, but I saw no requirement. # # Another option would have been to leave the .lib and .dll # files in the "cfg" directory, but then the make file # in \src would need to be changed. # ############################################################## CFGSET=FALSE WINBUILD_DIR=`cd` # Utilities. # If a path is required that contains characters such as space, quote the path. MT = mt.exe RC = rc.exe ZIP = zip.exe # Allow changing C compiler via environment variable CC (default cl.exe) # This command macro is not set by default: https://msdn.microsoft.com/en-us/library/ms933742.aspx !If "$(CC)" == "" CC = cl.exe !Endif !IF "$(VC)"=="6" CC_NODEBUG = $(CC) /O2 /DNDEBUG CC_DEBUG = $(CC) /Od /Gm /Zi /D_DEBUG /GZ CFLAGS = /I. /I../lib /I../include /nologo /W4 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL !ELSE CC_NODEBUG = $(CC) /O2 /DNDEBUG CC_DEBUG = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd CFLAGS = /I. /I ../lib /I../include /nologo /W4 /EHsc /DWIN32 /FD /c /DBUILDING_LIBCURL !ENDIF LFLAGS = /nologo /machine:$(MACHINE) LNKDLL = link.exe /DLL # Use lib.exe instead of link.exe as link.exe /lib has the following bad habits: # - optimizing options like /opt:ref raises warnings (at least in Visual Studio 2015) # - all (including Windows) dependencies are aggregated (as static parts) # - link.exe /lib is not documented (anymore) at MSDN # Instead of id: just create an archive, that contains all objects LNKLIB = lib.exe CFLAGS_PDB = /Zi LFLAGS_PDB = /incremental:no /opt:ref,icf /DEBUG CFLAGS_LIBCURL_STATIC = /DCURL_STATICLIB WIN_LIBS = ws2_32.lib wldap32.lib advapi32.lib crypt32.lib BASE_NAME = libcurl BASE_NAME_DEBUG = $(BASE_NAME)_debug BASE_NAME_STATIC = $(BASE_NAME)_a BASE_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC)_debug LIB_NAME_STATIC = $(BASE_NAME_STATIC).lib LIB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).lib LIB_NAME_DLL = $(BASE_NAME).dll LIB_NAME_IMP = $(BASE_NAME).lib LIB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).dll LIB_NAME_IMP_DEBUG = $(BASE_NAME_DEBUG).lib PDB_NAME_STATIC = $(BASE_NAME_STATIC).pdb PDB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).pdb PDB_NAME_DLL = $(BASE_NAME).pdb PDB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).pdb # CURL Command section PROGRAM_NAME = curl.exe CURL_CFLAGS = /I../lib /I../include /nologo /W4 /EHsc /DWIN32 /FD /c CURL_LFLAGS = /out:$(DIRDIST)\bin\$(PROGRAM_NAME) /subsystem:console $(LFLAGS) CURL_RESFLAGS = /i../include ############################################################# ## Nothing more to do below this line! LIBCURL_SRC_DIR = ..\lib CURL_SRC_DIR = ..\src !IFNDEF WITH_DEVEL WITH_DEVEL = ../../deps !ENDIF DEVEL_INCLUDE= $(WITH_DEVEL)/include DEVEL_LIB = $(WITH_DEVEL)/lib !IF EXISTS("$(DEVEL_INCLUDE)") CFLAGS = $(CFLAGS) /I"$(DEVEL_INCLUDE)" !ENDIF !IF EXISTS("$(DEVEL_LIB)") LFLAGS = $(LFLAGS) "/LIBPATH:$(DEVEL_LIB)" !ENDIF !IFDEF SSL_PATH SSL_INC_DIR = $(SSL_PATH)\include SSL_LIB_DIR = $(SSL_PATH)\lib SSL_LFLAGS = $(SSL_LFLAGS) "/LIBPATH:$(SSL_LIB_DIR)" !ELSE SSL_INC_DIR=$(DEVEL_INCLUDE)\openssl SSL_LIB_DIR=$(DEVEL_LIB) !ENDIF !IF "$(WITH_SSL)"=="dll" || "$(WITH_SSL)"=="static" !IF EXISTS("$(SSL_LIB_DIR)\libssl.lib") SSL_LIBS = libssl.lib libcrypto.lib !ELSE SSL_LIBS = libeay32.lib ssleay32.lib !ENDIF USE_SSL = true SSL = $(WITH_SSL) !IF "$(WITH_SSL)"=="static" WIN_LIBS = $(WIN_LIBS) gdi32.lib user32.lib crypt32.lib !ENDIF !ENDIF !IFDEF USE_SSL SSL_CFLAGS = /DUSE_OPENSSL /I"$(SSL_INC_DIR)" !IF EXISTS("$(SSL_INC_DIR)\is_boringssl.h") SSL_CFLAGS = $(SSL_CFLAGS) /DHAVE_BORINGSSL !ENDIF !IF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="false" SSL_CFLAGS = $(SSL_CFLAGS) /DCURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG !ENDIF !ENDIF !IFDEF NGHTTP2_PATH NGHTTP2_INC_DIR = $(NGHTTP2_PATH)\include NGHTTP2_LIB_DIR = $(NGHTTP2_PATH)\lib NGHTTP2_LFLAGS = $(NGHTTP2_LFLAGS) "/LIBPATH:$(NGHTTP2_LIB_DIR)" !ELSE NGHTTP2_INC_DIR = $(DEVEL_INCLUDE) NGHTTP2_LIB_DIR = $(DEVEL_LIB) !ENDIF !IF "$(WITH_NGHTTP2)"=="dll" NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /I"$(NGHTTP2_INC_DIR)" NGHTTP2_LIBS = nghttp2.lib !ELSEIF "$(WITH_NGHTTP2)"=="static" NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /DNGHTTP2_STATICLIB /I"$(NGHTTP2_INC_DIR)" NGHTTP2_LIBS = nghttp2_static.lib !ENDIF !IFDEF MBEDTLS_PATH MBEDTLS_INC_DIR = $(MBEDTLS_PATH)\include MBEDTLS_LIB_DIR = $(MBEDTLS_PATH)\lib MBEDTLS_LFLAGS = $(MBEDTLS_LFLAGS) "/LIBPATH:$(MBEDTLS_LIB_DIR)" !ELSE MBEDTLS_INC_DIR = $(DEVEL_INCLUDE) MBEDTLS_LIB_DIR = $(DEVEL_LIB) !ENDIF !IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" USE_MBEDTLS = true MBEDTLS = $(WITH_MBEDTLS) MBEDTLS_CFLAGS = /DUSE_MBEDTLS /I"$(MBEDTLS_INC_DIR)" MBEDTLS_LIBS = mbedtls.lib mbedcrypto.lib mbedx509.lib !ENDIF !IFDEF CARES_PATH CARES_INC_DIR = $(CARES_PATH)\include CARES_LIB_DIR = $(CARES_PATH)\lib CARES_LFLAGS = $(CARES_LFLAGS) "/LIBPATH:$(CARES_LIB_DIR)" !ELSE CARES_INC_DIR = $(DEVEL_INCLUDE)/cares CARES_LIB_DIR = $(DEVEL_LIB) !ENDIF !IF "$(WITH_CARES)"=="dll" !IF "$(DEBUG)"=="yes" CARES_LIBS = caresd.lib !ELSE CARES_LIBS = cares.lib !ENDIF USE_CARES = true CARES = dll !ELSEIF "$(WITH_CARES)"=="static" !IF "$(DEBUG)"=="yes" CARES_LIBS = libcaresd.lib !ELSE CARES_LIBS = libcares.lib !ENDIF USE_CARES = true CARES = static !ENDIF !IFDEF USE_CARES CARES_CFLAGS = /DUSE_ARES /I"$(CARES_INC_DIR)" !IF "$(CARES)"=="static" CARES_CFLAGS = $(CARES_CFLAGS) /DCARES_STATICLIB !ENDIF !ENDIF !IFDEF ZLIB_PATH ZLIB_INC_DIR = $(ZLIB_PATH)\include ZLIB_LIB_DIR = $(ZLIB_PATH)\lib ZLIB_LFLAGS = $(ZLIB_LFLAGS) "/LIBPATH:$(ZLIB_LIB_DIR)" !ELSE ZLIB_INC_DIR = $(DEVEL_INCLUDE) ZLIB_LIB_DIR = $(DEVEL_LIB) !ENDIF # Depending on how zlib is built the libraries have different names, we # try to handle them all. !IF "$(WITH_ZLIB)"=="dll" !IF EXISTS("$(ZLIB_LIB_DIR)\zlibwapi.lib") ZLIB_LIBS = zlibwapi.lib ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI !ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zdll.lib") ZLIB_LIBS = zdll.lib !ELSE ZLIB_LIBS = zlib.lib !ENDIF USE_ZLIB = true ZLIB = dll !ELSEIF "$(WITH_ZLIB)"=="static" !IF EXISTS("$(ZLIB_LIB_DIR)\zlibstat.lib") ZLIB_LIBS = zlibstat.lib ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI !ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zlib.lib") ZLIB_LIBS = zlib.lib !ELSE ZLIB_LIBS = zlib_a.lib !ENDIF USE_ZLIB = true ZLIB = static !ENDIF !IFDEF USE_ZLIB ZLIB_CFLAGS = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ $(ADDITIONAL_ZLIB_CFLAGS) /I"$(ZLIB_INC_DIR)" !ENDIF !IFDEF SSH2_PATH SSH2_INC_DIR= $(SSH2_PATH)\include SSH2_LIB_DIR= $(SSH2_PATH)\lib SSH2_LFLAGS = $(SSH2_LFLAGS) "/LIBPATH:$(SSH2_LIB_DIR)" !ELSE SSH2_LIB_DIR= $(DEVEL_LIB) SSH2_INC_DIR= $(DEVEL_INCLUDE)/libssh2 !ENDIF !IF "$(WITH_SSH2)"=="dll" SSH2_LIBS = libssh2.lib USE_SSH2 = true SSH2 = dll !ELSEIF "$(WITH_SSH2)"=="static" # libssh2 NMakefile on Windows at default creates a static library without _a suffix !IF EXISTS("$(SSH2_LIB_DIR)\libssh2.lib") SSH2_LIBS = libssh2.lib !ELSE SSH2_LIBS = libssh2_a.lib !ENDIF WIN_LIBS = $(WIN_LIBS) user32.lib USE_SSH2 = true SSH2 = static !ENDIF !IFDEF USE_SSH2 SSH2_CFLAGS = /DHAVE_LIBSSH2 /DHAVE_LIBSSH2_H /DLIBSSH2_WIN32 /DLIBSSH2_LIBRARY /DUSE_LIBSSH2 SSH2_CFLAGS = $(SSH2_CFLAGS) /I$(SSH2_INC_DIR) !ENDIF !IFNDEF USE_IDN USE_IDN = true !ELSEIF "$(USE_IDN)"=="yes" USE_IDN = true !ENDIF !IF "$(USE_IDN)"=="true" IDN_CFLAGS = $(IDN_CFLAGS) /DUSE_WIN32_IDN /DWANT_IDN_PROTOTYPES WIN_LIBS = $(WIN_LIBS) Normaliz.lib !ENDIF !IFNDEF USE_IPV6 USE_IPV6 = true !ELSEIF "$(USE_IPV6)"=="yes" USE_IPV6 = true !ENDIF !IF "$(USE_IPV6)"=="true" IPV6_CFLAGS = $(IPV6_CFLAGS) /DUSE_IPV6 !ENDIF !IFNDEF USE_SSPI USE_SSPI = true !ELSEIF "$(USE_SSPI)"=="yes" USE_SSPI = true !ENDIF !IF "$(USE_SSPI)"=="true" SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_WINDOWS_SSPI !ENDIF !IFNDEF USE_WINSSL !IF "$(USE_SSL)"=="true" USE_WINSSL = false !ELSE USE_WINSSL = $(USE_SSPI) !ENDIF !ELSEIF "$(USE_WINSSL)"=="yes" USE_WINSSL = true !ENDIF !IF "$(USE_WINSSL)"=="true" !IF "$(USE_SSPI)"!="true" !ERROR cannot build with WinSSL without SSPI !ENDIF SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_SCHANNEL WIN_LIBS = $(WIN_LIBS) Crypt32.lib !ENDIF !IF "$(GEN_PDB)"=="yes" GEN_PDB = true !ENDIF !IFDEF EMBED_MANIFEST MANIFESTTOOL = $(MT) -manifest $(DIRDIST)\bin\$(PROGRAM_NAME).manifest -outputresource:$(DIRDIST)\bin\$(PROGRAM_NAME);1 !ELSE CURL_RC_FLAGS = $(CURL_RC_FLAGS) /dCURL_EMBED_MANIFEST !ENDIF # Runtime library configuration !IF "$(RTLIBCFG)"=="static" RTLIB = /MT RTLIB_DEBUG = /MTd !ELSE RTLIB = /MD RTLIB_DEBUG = /MDd !ENDIF !IF "$(MODE)"=="static" TARGET = $(LIB_NAME_STATIC) CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) AS_DLL = false CFGSET = true !ELSEIF "$(MODE)"=="dll" TARGET = $(LIB_NAME_DLL) CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) AS_DLL = true CFGSET = true !ENDIF !IF "$(CFGSET)" == "FALSE" !ERROR please choose a valid mode !ENDIF # CURL_XX macros are for the curl.exe command !IF "$(DEBUG)"=="yes" RC_FLAGS = /dDEBUGBUILD=1 /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc CURL_CC = $(CC_DEBUG) $(RTLIB_DEBUG) CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /dDEBUGBUILD=1 /Fo $@ $(CURL_SRC_DIR)\curl.rc !ELSE RC_FLAGS = /dDEBUGBUILD=0 /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc CURL_CC = $(CC_NODEBUG) $(RTLIB) CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /dDEBUGBUILD=0 /Fo $@ $(CURL_SRC_DIR)\curl.rc !ENDIF !IF "$(AS_DLL)" == "true" LNK = $(LNKDLL) $(LFLAGS) $(WIN_LIBS) /out:$(LIB_DIROBJ)\$(TARGET) !IF "$(DEBUG)"=="yes" TARGET = $(LIB_NAME_DLL_DEBUG) LNK = $(LNK) /DEBUG /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) PDB = $(PDB_NAME_DLL_DEBUG) CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) !ELSE TARGET = $(LIB_NAME_DLL) LNK = $(LNK) /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) PDB = $(PDB_NAME_DLL) CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) !ENDIF RESOURCE = $(LIB_DIROBJ)\libcurl.res # AS_DLL !ELSE !IF "$(DEBUG)"=="yes" TARGET = $(LIB_NAME_STATIC_DEBUG) PDB = $(PDB_NAME_STATIC_DEBUG) !ELSE TARGET = $(LIB_NAME_STATIC) PDB = $(PDB_NAME_STATIC) !ENDIF LNK = $(LNKLIB) /out:$(LIB_DIROBJ)\$(TARGET) CURL_CC = $(CURL_CC) $(CFLAGS_LIBCURL_STATIC) # AS_DLL !ENDIF !IF "$(USE_SSL)"=="true" CFLAGS = $(CFLAGS) $(SSL_CFLAGS) LFLAGS = $(LFLAGS) $(SSL_LFLAGS) $(SSL_LIBS) !ENDIF !IF "$(USE_MBEDTLS)"=="true" CFLAGS = $(CFLAGS) $(MBEDTLS_CFLAGS) LFLAGS = $(LFLAGS) $(MBEDTLS_LFLAGS) $(MBEDTLS_LIBS) !ENDIF !IF "$(USE_CARES)"=="true" CFLAGS = $(CFLAGS) $(CARES_CFLAGS) LFLAGS = $(LFLAGS) $(CARES_LFLAGS) $(CARES_LIBS) !ENDIF !IF "$(USE_ZLIB)"=="true" CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS) $(ZLIB_LIBS) !ENDIF !IF "$(USE_SSH2)"=="true" CFLAGS = $(CFLAGS) $(SSH2_CFLAGS) LFLAGS = $(LFLAGS) $(SSH2_LFLAGS) $(SSH2_LIBS) !ENDIF !IF "$(USE_IDN)"=="true" CFLAGS = $(CFLAGS) $(IDN_CFLAGS) !ENDIF !IF "$(USE_IPV6)"=="true" CFLAGS = $(CFLAGS) $(IPV6_CFLAGS) !ENDIF !IF "$(USE_SSPI)"=="true" CFLAGS = $(CFLAGS) $(SSPI_CFLAGS) !ENDIF !IF "$(USE_NGHTTP2)"=="true" CFLAGS = $(CFLAGS) $(NGHTTP2_CFLAGS) LFLAGS = $(LFLAGS) $(NGHTTP2_LFLAGS) $(NGHTTP2_LIBS) !ENDIF !IF "$(GEN_PDB)"=="true" CFLAGS = $(CFLAGS) $(CFLAGS_PDB) /Fd"$(LIB_DIROBJ)\$(PDB)" LFLAGS = $(LFLAGS) $(LFLAGS_PDB) !ENDIF !IF ( "$(USE_SSL)"=="true" && "$(USE_WINSSL)"=="true" ) \ || ( "$(USE_SSL)"=="true" && "$(USE_MBEDTLS)"=="true" ) \ || ( "$(USE_MBEDTLS)"=="true" && "$(USE_WINSSL)"=="true" ) CFLAGS = $(CFLAGS) /DCURL_WITH_MULTI_SSL !ENDIF !IF "$(USE_UNICODE)"=="true" CFLAGS = $(CFLAGS) /DUNICODE /D_UNICODE !ENDIF LIB_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl !IFDEF WITH_PREFIX DIRDIST = $(WITH_PREFIX) !ELSE DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ !ENDIF # # curl.exe # CURL_LINK = link.exe /incremental:no /libpath:"$(DIRDIST)\lib" !IF "$(CFGSET)" != "FALSE" # A mode was provided, so the library can be built. # !include CURL_OBJS.inc !include LIBCURL_OBJS.inc !IF "$(AS_DLL)" == "true" LIB_OBJS = $(LIBCURL_OBJS) $(RESOURCE) !ELSE LIB_OBJS = $(LIBCURL_OBJS) !ENDIF EXE_OBJS = $(CURL_OBJS) $(CURL_DIROBJ)\curl.res all : $(TARGET) $(PROGRAM_NAME) package: $(TARGET) @cd $(DIRDIST) @-$(ZIP) -9 -q -r ..\$(CONFIG_NAME_LIB).zip .>nul 2<&1 @cd $(MAKEDIR) $(TARGET): $(LIB_OBJS) $(LIB_DIROBJ) $(DIRDIST) @echo Using SSL: $(USE_SSL) @echo Using NGHTTP2: $(USE_NGHTTP2) @echo Using c-ares: $(USE_CARES) @echo Using SSH2: $(USE_SSH2) @echo Using ZLIB: $(USE_ZLIB) @echo Using IDN: $(USE_IDN) @echo Using IPv6: $(USE_IPV6) @echo Using SSPI: $(USE_SSPI) @echo Using WinSSL: $(USE_WINSSL) @echo CFLAGS: $(CFLAGS) @echo LFLAGS: $(LFLAGS) @echo GenPDB: $(GEN_PDB) @echo Debug: $(DEBUG) @echo Machine: $(MACHINE) $(LNK) $(LIB_OBJS) @echo Copying libs... @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL) $(DIRDIST)\bin\ /y >nul 2<&1 @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC) $(DIRDIST)\lib\ /y >nul 2<&1 @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) $(DIRDIST)\bin\ /y >nul 2<&1 @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) $(DIRDIST)\lib\ /y >nul 2<&1 @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP) $(DIRDIST)\lib\ /y >nul 2<&1 @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) $(DIRDIST)\lib >nul 2<&1 @-copy $(LIB_DIROBJ)\*.exp $(DIRDIST)\lib /y >nul 2<&1 @-copy $(LIB_DIROBJ)\*.pdb $(DIRDIST)\lib /y >nul 2<&1 @-copy ..\include\curl\*.h $(DIRDIST)\include\curl\ /y >nul 2<&1 $(LIB_OBJS): $(LIB_DIROBJ) $(DIRDIST) $(DIRDIST): @if not exist "$(DIRDIST)\bin" mkdir $(DIRDIST)\bin @if not exist "$(DIRDIST)\include" mkdir $(DIRDIST)\include @if not exist "$(DIRDIST)\include\curl" mkdir $(DIRDIST)\include\curl @if not exist "$(DIRDIST)\lib" mkdir $(DIRDIST)\lib $(LIB_DIROBJ): @if not exist "$(LIB_DIROBJ)" mkdir $(LIB_DIROBJ) @if not exist "$(LIB_DIROBJ)\vauth" mkdir $(LIB_DIROBJ)\vauth @if not exist "$(LIB_DIROBJ)\vtls" mkdir $(LIB_DIROBJ)\vtls @if not exist "$(LIB_DIROBJ)\vssh" mkdir $(LIB_DIROBJ)\vssh @if not exist "$(LIB_DIROBJ)\vquic" mkdir $(LIB_DIROBJ)\vquic $(CURL_DIROBJ): @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ) # we need a lib dir for the portability functions from libcurl # we use the .c directly here @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ)\lib .SUFFIXES: .c .obj .res {$(LIBCURL_SRC_DIR)\}.c{$(LIB_DIROBJ)\}.obj: $(CURL_CC) $(CFLAGS) /Fo"$@" $< {$(LIBCURL_SRC_DIR)\vauth\}.c{$(LIB_DIROBJ)\vauth\}.obj: $(CURL_CC) $(CFLAGS) /Fo"$@" $< {$(LIBCURL_SRC_DIR)\vtls\}.c{$(LIB_DIROBJ)\vtls\}.obj: $(CURL_CC) $(CFLAGS) /Fo"$@" $< {$(LIBCURL_SRC_DIR)\vssh\}.c{$(LIB_DIROBJ)\vssh\}.obj: $(CURL_CC) $(CFLAGS) /Fo"$@" $< {$(LIBCURL_SRC_DIR)\vquic\}.c{$(LIB_DIROBJ)\vquic\}.obj: $(CURL_CC) $(CFLAGS) /Fo"$@" $< $(LIB_DIROBJ)\libcurl.res: $(LIBCURL_SRC_DIR)\libcurl.rc $(RC) $(RC_FLAGS) # # curl.exe # !IF "$(MODE)"=="static" !IF "$(DEBUG)"=="yes" CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC_DEBUG) !ELSE CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) !ENDIF !ELSEIF "$(MODE)"=="dll" !IF "$(DEBUG)"=="yes" CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP_DEBUG) !ELSE CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) !ENDIF !ENDIF CURL_FROM_LIBCURL=$(CURL_DIROBJ)\tool_hugehelp.obj \ $(CURL_DIROBJ)\nonblock.obj \ $(CURL_DIROBJ)\strtoofft.obj \ $(CURL_DIROBJ)\warnless.obj \ $(CURL_DIROBJ)\curl_ctype.obj $(PROGRAM_NAME): $(CURL_DIROBJ) $(CURL_FROM_LIBCURL) $(EXE_OBJS) $(CURL_LINK) $(CURL_LFLAGS) $(CURL_LIBCURL_LIBNAME) $(WIN_LIBS) $(CURL_FROM_LIBCURL) $(EXE_OBJS) $(MANIFESTTOOL) {$(CURL_SRC_DIR)\}.c{$(CURL_DIROBJ)\}.obj: $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" $< $(CURL_DIROBJ)\tool_hugehelp.obj: $(CURL_SRC_DIR)\tool_hugehelp.c $(CURL_CC) $(CURL_CFLAGS) /Zm200 /Fo"$@" $(CURL_SRC_DIR)\tool_hugehelp.c $(CURL_DIROBJ)\nonblock.obj: ../lib/nonblock.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/nonblock.c $(CURL_DIROBJ)\strtoofft.obj: ../lib/strtoofft.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strtoofft.c $(CURL_DIROBJ)\warnless.obj: ../lib/warnless.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/warnless.c $(CURL_DIROBJ)\curl_ctype.obj: ../lib/curl_ctype.c $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curl_ctype.c $(CURL_DIROBJ)\curl.res: $(CURL_SRC_DIR)\curl.rc rc $(CURL_RC_FLAGS) !ENDIF # End of case where a config was provided. clean: @-erase /s *.dll 2> NUL @-erase /s *.exp 2> NUL @-erase /s *.idb 2> NUL @-erase /s *.lib 2> NUL @-erase /s *.obj 2> NUL @-erase /s *.pch 2> NUL @-erase /s *.pdb 2> NUL @-erase /s *.res 2> NUL @if exist $(LIB_DIROBJ) rd /s/q $(LIB_DIROBJ) @if exist $(CURL_DIROBJ)rd /s/q $(CURL_DIROBJ) @if exist $(DIRDIST) rd /s/q $(DIRDIST) davix-0.8.0/deps/curl/winbuild/gen_resp_file.bat0000755000000000000000000000234314121063461020341 0ustar rootroot@echo off rem *************************************************************************** rem * _ _ ____ _ rem * Project ___| | | | _ \| | rem * / __| | | | |_) | | rem * | (__| |_| | _ <| |___ rem * \___|\___/|_| \_\_____| rem * rem * Copyright (C) 2011 - 2019, Daniel Stenberg, , et al. rem * rem * This software is licensed as described in the file COPYING, which rem * you should have received as part of this distribution. The terms rem * are also available at https://curl.haxx.se/docs/copyright.html. rem * rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell rem * copies of the Software, and permit persons to whom the Software is rem * furnished to do so, under the terms of the COPYING file. rem * rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY rem * KIND, either express or implied. rem * rem *************************************************************************** if exist %OUTFILE% ( del %OUTFILE% ) echo %MACRO_NAME% = \> %OUTFILE% for %%i in (%*) do echo %DIROBJ%/%%i \>> %OUTFILE% echo. >> %OUTFILE% :END davix-0.8.0/deps/curl/winbuild/Makefile.vc0000644000000000000000000002114714121063461017117 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1999 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** !IF "$(MODE)"=="static" TARGET = $(LIB_NAME_STATIC) AS_DLL = false CFGSET=true !ELSEIF "$(MODE)"=="dll" TARGET = $(LIB_NAME_DLL) AS_DLL = true CFGSET=true !ELSE !MESSAGE Invalid mode: $(MODE) ####################### # Usage # !MESSAGE Usage: nmake /f Makefile.vc mode= !MESSAGE where is one or many of: !MESSAGE VC=<6,7,8,9,10,11,12,14,15> - VC versions !MESSAGE WITH_DEVEL= - Paths for the development files (SSL, zlib, etc.) !MESSAGE Defaults to curl's sibling directory deps: ../deps !MESSAGE Libraries can be fetched at https://windows.php.net/downloads/php-sdk/deps/ !MESSAGE Uncompress them into the deps folder. !MESSAGE WITH_PREFIX= - Installation directory path !MESSAGE Defaults to a configuration dependent (SSL, zlib, etc.) !MESSAGE directory inside curl's subdirectory builds: ./builds !MESSAGE Use backslashes as path separator !MESSAGE WITH_SSL= - Enable OpenSSL support, DLL or static !MESSAGE WITH_NGHTTP2= - Enable HTTP/2 support, DLL or static !MESSAGE WITH_CARES= - Enable c-ares support, DLL or static !MESSAGE WITH_ZLIB= - Enable zlib support, DLL or static !MESSAGE WITH_SSH2= - Enable libSSH2 support, DLL or static !MESSAGE WITH_MBEDTLS= - Enable mbedTLS support, DLL or static !MESSAGE ENABLE_IDN= - Enable use of Windows IDN APIs, defaults to yes !MESSAGE Requires Windows Vista or later !MESSAGE ENABLE_IPV6= - Enable IPv6, defaults to yes !MESSAGE ENABLE_SSPI= - Enable SSPI support, defaults to yes !MESSAGE ENABLE_WINSSL= - Enable native Windows SSL support, defaults to yes !MESSAGE ENABLE_OPENSSL_AUTO_LOAD_CONFIG= !MESSAGE - Whether the OpenSSL configuration will be loaded automatically, defaults to yes !MESSAGE ENABLE_UNICODE= - Enable UNICODE support, defaults to no !MESSAGE GEN_PDB= - Generate Program Database (debug symbols for release build) !MESSAGE DEBUG= - Debug builds !MESSAGE MACHINE= - Target architecture (default x64 on AMD64, x86 on others) !MESSAGE CARES_PATH= - Custom path for c-ares !MESSAGE MBEDTLS_PATH= - Custom path for mbedTLS !MESSAGE NGHTTP2_PATH= - Custom path for nghttp2 !MESSAGE SSH2_PATH= - Custom path for libSSH2 !MESSAGE SSL_PATH= - Custom path for OpenSSL !MESSAGE ZLIB_PATH= - Custom path for zlib !ERROR please choose a valid mode !ENDIF !INCLUDE "../lib/Makefile.inc" LIBCURL_OBJS=$(CSOURCES:.c=.obj) !INCLUDE "../src/Makefile.inc" # tool_hugehelp has a special rule CURL_OBJS=$(CURL_CFILES:tool_hugehelp.c=) CURL_OBJS=$(CURL_OBJS:.c=.obj) # backwards compatible check for USE_SSPI !IFDEF USE_SSPI ENABLE_SSPI = $(USE_SSPI) !ENDIF # default options !IFNDEF MACHINE # Note: nmake magically changes the value of PROCESSOR_ARCHITECTURE from "AMD64" # to "x86" when building in a 32 bit build environment on a 64 bit machine. !IF "$(PROCESSOR_ARCHITECTURE)"=="AMD64" MACHINE = x64 !ELSE MACHINE = x86 !ENDIF !ENDIF !IFNDEF ENABLE_IDN USE_IDN = true !ELSEIF "$(ENABLE_IDN)"=="yes" USE_IDN = true !ELSEIF "$(ENABLE_IDN)"=="no" USE_IDN = false !ENDIF !IFNDEF ENABLE_IPV6 USE_IPV6 = true !ELSEIF "$(ENABLE_IPV6)"=="yes" USE_IPV6 = true !ELSEIF "$(ENABLE_IPV6)"=="no" USE_IPV6 = false !ENDIF !IFNDEF ENABLE_SSPI USE_SSPI = true !ELSEIF "$(ENABLE_SSPI)"=="yes" USE_SSPI = true !ELSEIF "$(ENABLE_SSPI)"=="no" USE_SSPI = false !ENDIF !IFNDEF ENABLE_WINSSL !IF DEFINED(WITH_SSL) || DEFINED(WITH_MBEDTLS) USE_WINSSL = false !ELSE USE_WINSSL = $(USE_SSPI) !ENDIF !ELSEIF "$(ENABLE_WINSSL)"=="yes" USE_WINSSL = true !ELSEIF "$(ENABLE_WINSSL)"=="no" USE_WINSSL = false !ENDIF !IFNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true !ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="yes" !UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true !ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="no" !UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG ENABLE_OPENSSL_AUTO_LOAD_CONFIG = false !ENDIF !IFNDEF ENABLE_UNICODE USE_UNICODE = false !ELSEIF "$(ENABLE_UNICODE)"=="yes" USE_UNICODE = true !ELSEIF "$(ENABLE_UNICODE)"=="no" USE_UNICODE = false !ENDIF CONFIG_NAME_LIB = libcurl !IF "$(WITH_SSL)"=="dll" USE_SSL = true SSL = dll !ELSEIF "$(WITH_SSL)"=="static" USE_SSL = true SSL = static !ENDIF !IF "$(ENABLE_NGHTTP2)"=="yes" # compatibility bit, WITH_NGHTTP2 is the correct flag WITH_NGHTTP2 = dll USE_NGHTTP2 = true NGHTTP2 = dll !ELSEIF "$(WITH_NGHTTP2)"=="dll" USE_NGHTTP2 = true NGHTTP2 = dll !ELSEIF "$(WITH_NGHTTP2)"=="static" USE_NGHTTP2 = true NGHTTP2 = static !ENDIF !IFNDEF USE_NGHTTP2 USE_NGHTTP2 = false !ENDIF !IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" USE_MBEDTLS = true MBEDTLS = $(WITH_MBEDTLS) !ENDIF !IF "$(WITH_CARES)"=="dll" USE_CARES = true CARES = dll !ELSEIF "$(WITH_CARES)"=="static" USE_CARES = true CARES = static !ENDIF !IF "$(WITH_ZLIB)"=="dll" USE_ZLIB = true ZLIB = dll !ELSEIF "$(WITH_ZLIB)"=="static" USE_ZLIB = true ZLIB = static !ENDIF !IF "$(WITH_SSH2)"=="dll" USE_SSH2 = true SSH2 = dll !ELSEIF "$(WITH_SSH2)"=="static" USE_SSH2 = true SSH2 = static !ENDIF CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-vc$(VC)-$(MACHINE) !IF "$(DEBUG)"=="yes" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-debug !ELSE CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-release !ENDIF !IF "$(AS_DLL)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-dll !ELSE CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-static !ENDIF !IF "$(USE_SSL)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssl-$(SSL) !ENDIF !IF "$(USE_MBEDTLS)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-mbedtls-$(MBEDTLS) !ENDIF !IF "$(USE_CARES)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-cares-$(CARES) !ENDIF !IF "$(USE_ZLIB)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-zlib-$(ZLIB) !ENDIF !IF "$(USE_SSH2)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssh2-$(SSH2) !ENDIF !IF "$(USE_IPV6)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ipv6 !ENDIF !IF "$(USE_SSPI)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-sspi !ENDIF !IF "$(USE_WINSSL)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-winssl !ENDIF !IF "$(USE_NGHTTP2)"=="true" CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-nghttp2-$(NGHTTP2) !ENDIF !MESSAGE configuration name: $(CONFIG_NAME_LIB) BUILD_DIR=../builds/$(CONFIG_NAME_LIB) LIBCURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ $(MODE): @SET DIROBJ=$(LIBCURL_DIROBJ) @SET MACRO_NAME=LIBCURL_OBJS @SET OUTFILE=LIBCURL_OBJS.inc @CALL gen_resp_file.bat $(LIBCURL_OBJS) @SET DIROBJ=$(CURL_DIROBJ) @SET MACRO_NAME=CURL_OBJS @SET OUTFILE=CURL_OBJS.inc @CALL gen_resp_file.bat $(CURL_OBJS) @SET CONFIG_NAME_LIB=$(CONFIG_NAME_LIB) @SET MACHINE=$(MACHINE) @SET USE_NGHTTP2=$(USE_NGHTTP2) @SET USE_IDN=$(USE_IDN) @SET USE_IPV6=$(USE_IPV6) @SET USE_SSPI=$(USE_SSPI) @SET USE_WINSSL=$(USE_WINSSL) @SET USE_UNICODE=$(USE_UNICODE) # compatibility bit @SET WITH_NGHTTP2=$(WITH_NGHTTP2) @$(MAKE) /NOLOGO /F MakefileBuild.vc copy_from_lib: echo copying .c... FOR %%i IN ($(CURLX_CFILES:/=\)) DO copy %%i ..\src\ clean: $(MAKE) /NOLOGO /F MakefileBuild.vc $@ davix-0.8.0/deps/curl/COPYING0000644000000000000000000000210014121063461014252 0ustar rootrootCOPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2020, Daniel Stenberg, , and many contributors, see the THANKS file. All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. davix-0.8.0/deps/curl/.dir-locals.el0000644000000000000000000000043014121063461015654 0ustar rootroot;;; Directory Local Variables ;;; See Info node `(emacs) Directory Variables' for more information. ((nil . ((indent-tabs-mode . nil) (show-trailing-whitespace . t))) (c-mode . ((c-basic-offset . 2) )) (c++-mode . ((c-basic-offset . 2) )) ) davix-0.8.0/deps/curl/CMake/0000755000000000000000000000000014121063461014206 5ustar rootrootdavix-0.8.0/deps/curl/CMake/CurlTests.c0000644000000000000000000003063614121063461016312 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifdef TIME_WITH_SYS_TIME /* Time with sys/time test */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } #endif #ifdef HAVE_FCNTL_O_NONBLOCK /* headers for FCNTL_O_NONBLOCK test */ #include #include #include /* */ #if defined(sun) || defined(__sun__) || \ defined(__SUNPRO_C) || defined(__SUNPRO_CC) # if defined(__SVR4) || defined(__srv4__) # define PLATFORM_SOLARIS # else # define PLATFORM_SUNOS4 # endif #endif #if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX41) # define PLATFORM_AIX_V3 #endif /* */ #if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || defined(__BEOS__) #error "O_NONBLOCK does not work on this platform" #endif int main () { /* O_NONBLOCK source test */ int flags = 0; if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK)) return 1; return 0; } #endif /* tests for gethostbyaddr_r or gethostbyname_r */ #if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) # define _REENTRANT /* no idea whether _REENTRANT is always set, just invent a new flag */ # define TEST_GETHOSTBYFOO_REENTRANT #endif #if defined(HAVE_GETHOSTBYADDR_R_5) || \ defined(HAVE_GETHOSTBYADDR_R_7) || \ defined(HAVE_GETHOSTBYADDR_R_8) || \ defined(HAVE_GETHOSTBYNAME_R_3) || \ defined(HAVE_GETHOSTBYNAME_R_5) || \ defined(HAVE_GETHOSTBYNAME_R_6) || \ defined(TEST_GETHOSTBYFOO_REENTRANT) #include #include int main(void) { char *address = "example.com"; int length = 0; int type = 0; struct hostent h; int rc = 0; #if defined(HAVE_GETHOSTBYADDR_R_5) || \ defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \ \ defined(HAVE_GETHOSTBYNAME_R_3) || \ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) struct hostent_data hdata; #elif defined(HAVE_GETHOSTBYADDR_R_7) || \ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \ defined(HAVE_GETHOSTBYADDR_R_8) || \ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \ \ defined(HAVE_GETHOSTBYNAME_R_5) || \ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \ defined(HAVE_GETHOSTBYNAME_R_6) || \ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) char buffer[8192]; int h_errnop; struct hostent *hp; #endif #ifndef gethostbyaddr_r (void)gethostbyaddr_r; #endif #if defined(HAVE_GETHOSTBYADDR_R_5) || \ defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) rc = gethostbyaddr_r(address, length, type, &h, &hdata); (void)rc; #elif defined(HAVE_GETHOSTBYADDR_R_7) || \ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop); (void)hp; #elif defined(HAVE_GETHOSTBYADDR_R_8) || \ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop); (void)rc; #endif #if defined(HAVE_GETHOSTBYNAME_R_3) || \ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) rc = gethostbyname_r(address, &h, &hdata); #elif defined(HAVE_GETHOSTBYNAME_R_5) || \ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop); (void)hp; /* not used for test */ #elif defined(HAVE_GETHOSTBYNAME_R_6) || \ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT) rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop); #endif (void)length; (void)type; (void)rc; return 0; } #endif #ifdef HAVE_SOCKLEN_T #ifdef _WIN32 #include #else #include #include #endif int main () { if ((socklen_t *) 0) return 0; if (sizeof (socklen_t)) return 0; ; return 0; } #endif #ifdef HAVE_IN_ADDR_T #include #include #include int main () { if ((in_addr_t *) 0) return 0; if (sizeof (in_addr_t)) return 0; ; return 0; } #endif #ifdef HAVE_BOOL_T #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_STDBOOL_H #include #endif int main () { if (sizeof (bool *) ) return 0; ; return 0; } #endif #ifdef STDC_HEADERS #include #include #include #include int main() { return 0; } #endif #ifdef RETSIGTYPE_TEST #include #include #ifdef signal # undef signal #endif #ifdef __cplusplus extern "C" void (*signal (int, void (*)(int)))(int); #else void (*signal ()) (); #endif int main () { return 0; } #endif #ifdef HAVE_INET_NTOA_R_DECL #include typedef void (*func_type)(); int main() { #ifndef inet_ntoa_r func_type func; func = (func_type)inet_ntoa_r; (void)func; #endif return 0; } #endif #ifdef HAVE_INET_NTOA_R_DECL_REENTRANT #define _REENTRANT #include typedef void (*func_type)(); int main() { #ifndef inet_ntoa_r func_type func; func = (func_type)&inet_ntoa_r; (void)func; #endif return 0; } #endif #ifdef HAVE_GETADDRINFO #include #include #include int main(void) { struct addrinfo hints, *ai; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifndef getaddrinfo (void)getaddrinfo; #endif error = getaddrinfo("127.0.0.1", "8080", &hints, &ai); if (error) { return 1; } return 0; } #endif #ifdef HAVE_FILE_OFFSET_BITS #ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } #endif #ifdef HAVE_IOCTLSOCKET /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif int main () { /* ioctlsocket source code */ int socket; unsigned long flags = ioctlsocket(socket, FIONBIO, &flags); ; return 0; } #endif #ifdef HAVE_IOCTLSOCKET_CAMEL /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif int main () { /* IoctlSocket source code */ if(0 != IoctlSocket(0, 0, 0)) return 1; ; return 0; } #endif #ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif int main () { /* IoctlSocket source code */ long flags = 0; if(0 != ioctlsocket(0, FIONBIO, &flags)) return 1; ; return 0; } #endif #ifdef HAVE_IOCTLSOCKET_FIONBIO /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif int main () { int flags = 0; if(0 != ioctlsocket(0, FIONBIO, &flags)) return 1; ; return 0; } #endif #ifdef HAVE_IOCTL_FIONBIO /* headers for FIONBIO test */ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_STROPTS_H # include #endif int main () { int flags = 0; if(0 != ioctl(0, FIONBIO, &flags)) return 1; ; return 0; } #endif #ifdef HAVE_IOCTL_SIOCGIFADDR /* headers for FIONBIO test */ /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_STROPTS_H # include #endif #include int main () { struct ifreq ifr; if(0 != ioctl(0, SIOCGIFADDR, &ifr)) return 1; ; return 0; } #endif #ifdef HAVE_SETSOCKOPT_SO_NONBLOCK /* includes start */ #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # ifdef HAVE_WINSOCK2_H # include # else # ifdef HAVE_WINSOCK_H # include # endif # endif #endif /* includes start */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif /* includes end */ int main () { if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0)) return 1; ; return 0; } #endif #ifdef HAVE_GLIBC_STRERROR_R #include #include void check(char c) {} int main () { char buffer[1024]; /* This will not compile if strerror_r does not return a char* */ check(strerror_r(EACCES, buffer, sizeof(buffer))[0]); return 0; } #endif #ifdef HAVE_POSIX_STRERROR_R #include #include /* float, because a pointer can't be implicitly cast to float */ void check(float f) {} int main () { char buffer[1024]; /* This will not compile if strerror_r does not return an int */ check(strerror_r(EACCES, buffer, sizeof(buffer))); return 0; } #endif #ifdef HAVE_FSETXATTR_6 #include /* header from libc, not from libattr */ int main() { fsetxattr(0, 0, 0, 0, 0, 0); return 0; } #endif #ifdef HAVE_FSETXATTR_5 #include /* header from libc, not from libattr */ int main() { fsetxattr(0, 0, 0, 0, 0); return 0; } #endif #ifdef HAVE_CLOCK_GETTIME_MONOTONIC #include int main() { struct timespec ts = {0, 0}; clock_gettime(CLOCK_MONOTONIC, &ts); return 0; } #endif #ifdef HAVE_BUILTIN_AVAILABLE int main() { if(__builtin_available(macOS 10.12, *)) {} return 0; } #endif #ifdef HAVE_VARIADIC_MACROS_C99 #define c99_vmacro3(first, ...) fun3(first, __VA_ARGS__) #define c99_vmacro2(first, ...) fun2(first, __VA_ARGS__) int fun3(int arg1, int arg2, int arg3); int fun2(int arg1, int arg2); int fun3(int arg1, int arg2, int arg3) { return arg1 + arg2 + arg3; } int fun2(int arg1, int arg2) { return arg1 + arg2; } int main() { int res3 = c99_vmacro3(1, 2, 3); int res2 = c99_vmacro2(1, 2); (void)res3; (void)res2; return 0; } #endif #ifdef HAVE_VARIADIC_MACROS_GCC #define gcc_vmacro3(first, args...) fun3(first, args) #define gcc_vmacro2(first, args...) fun2(first, args) int fun3(int arg1, int arg2, int arg3); int fun2(int arg1, int arg2); int fun3(int arg1, int arg2, int arg3) { return arg1 + arg2 + arg3; } int fun2(int arg1, int arg2) { return arg1 + arg2; } int main() { int res3 = gcc_vmacro3(1, 2, 3); int res2 = gcc_vmacro2(1, 2); (void)res3; (void)res2; return 0; } #endif davix-0.8.0/deps/curl/CMake/CMakeConfigurableFile.in0000644000000000000000000000004214121063461020633 0ustar rootroot@CMAKE_CONFIGURABLE_FILE_CONTENT@ davix-0.8.0/deps/curl/CMake/FindBearSSL.cmake0000644000000000000000000000042114121063461017241 0ustar rootrootfind_path(BEARSSL_INCLUDE_DIRS bearssl.h) find_library(BEARSSL_LIBRARY bearssl) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(BEARSSL DEFAULT_MSG BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY) davix-0.8.0/deps/curl/CMake/FindLibSSH2.cmake0000644000000000000000000000141114121063461017154 0ustar rootroot# - Try to find the libssh2 library # Once done this will define # # LIBSSH2_FOUND - system has the libssh2 library # LIBSSH2_INCLUDE_DIR - the libssh2 include directory # LIBSSH2_LIBRARY - the libssh2 library name find_path(LIBSSH2_INCLUDE_DIR libssh2.h) find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2) if(LIBSSH2_INCLUDE_DIR) file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"") string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1" LIBSSH2_VERSION "${libssh2_version_str}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LibSSH2 REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR VERSION_VAR LIBSSH2_VERSION) mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY) davix-0.8.0/deps/curl/CMake/FindNGHTTP2.cmake0000644000000000000000000000065714121063461017107 0ustar rootrootinclude(FindPackageHandleStandardArgs) find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") find_library(NGHTTP2_LIBRARY NAMES nghttp2) find_package_handle_standard_args(NGHTTP2 FOUND_VAR NGHTTP2_FOUND REQUIRED_VARS NGHTTP2_LIBRARY NGHTTP2_INCLUDE_DIR ) set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR}) set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY}) mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES) davix-0.8.0/deps/curl/CMake/Utilities.cmake0000644000000000000000000000052014121063461017160 0ustar rootroot# File containing various utilities # Returns a list of arguments that evaluate to true function(count_true output_count_var) set(lst_len 0) foreach(option_var IN LISTS ARGN) if(${option_var}) math(EXPR lst_len "${lst_len} + 1") endif() endforeach() set(${output_count_var} ${lst_len} PARENT_SCOPE) endfunction() davix-0.8.0/deps/curl/CMake/FindGSS.cmake0000644000000000000000000002226514121063461016454 0ustar rootroot# - Try to find the GSS Kerberos library # Once done this will define # # GSS_ROOT_DIR - Set this variable to the root installation of GSS # # Read-Only variables: # GSS_FOUND - system has the Heimdal library # GSS_FLAVOUR - "MIT" or "Heimdal" if anything found. # GSS_INCLUDE_DIR - the Heimdal include directory # GSS_LIBRARIES - The libraries needed to use GSS # GSS_LINK_DIRECTORIES - Directories to add to linker search path # GSS_LINKER_FLAGS - Additional linker flags # GSS_COMPILER_FLAGS - Additional compiler flags # GSS_VERSION - This is set to version advertised by pkg-config or read from manifest. # In case the library is found but no version info available it'll be set to "unknown" set(_MIT_MODNAME mit-krb5-gssapi) set(_HEIMDAL_MODNAME heimdal-gssapi) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckTypeSize) set(_GSS_ROOT_HINTS "${GSS_ROOT_DIR}" "$ENV{GSS_ROOT_DIR}" ) # try to find library using system pkg-config if user didn't specify root dir if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") if(UNIX) find_package(PkgConfig QUIET) pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME}) list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}") elseif(WIN32) list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]") endif() endif() if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach. find_file(_GSS_CONFIGURE_SCRIPT NAMES "krb5-config" HINTS ${_GSS_ROOT_HINTS} PATH_SUFFIXES bin NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH ) # if not found in user-supplied directories, maybe system knows better find_file(_GSS_CONFIGURE_SCRIPT NAMES "krb5-config" PATH_SUFFIXES bin ) if(_GSS_CONFIGURE_SCRIPT) execute_process( COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi" OUTPUT_VARIABLE _GSS_CFLAGS RESULT_VARIABLE _GSS_CONFIGURE_FAILED OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "CFLAGS: ${_GSS_CFLAGS}") if(NOT _GSS_CONFIGURE_FAILED) # 0 means success # should also work in an odd case when multiple directories are given string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS) string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}") string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}") foreach(_flag ${_GSS_CFLAGS}) if(_flag MATCHES "^-I.*") string(REGEX REPLACE "^-I" "" _val "${_flag}") list(APPEND _GSS_INCLUDE_DIR "${_val}") else() list(APPEND _GSS_COMPILER_FLAGS "${_flag}") endif() endforeach() endif() execute_process( COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi" OUTPUT_VARIABLE _GSS_LIB_FLAGS RESULT_VARIABLE _GSS_CONFIGURE_FAILED OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}") if(NOT _GSS_CONFIGURE_FAILED) # 0 means success # this script gives us libraries and link directories. Blah. We have to deal with it. string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS) string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}") foreach(_flag ${_GSS_LIB_FLAGS}) if(_flag MATCHES "^-l.*") string(REGEX REPLACE "^-l" "" _val "${_flag}") list(APPEND _GSS_LIBRARIES "${_val}") elseif(_flag MATCHES "^-L.*") string(REGEX REPLACE "^-L" "" _val "${_flag}") list(APPEND _GSS_LINK_DIRECTORIES "${_val}") else() list(APPEND _GSS_LINKER_FLAGS "${_flag}") endif() endforeach() endif() execute_process( COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version" OUTPUT_VARIABLE _GSS_VERSION RESULT_VARIABLE _GSS_CONFIGURE_FAILED OUTPUT_STRIP_TRAILING_WHITESPACE ) # older versions may not have the "--version" parameter. In this case we just don't care. if(_GSS_CONFIGURE_FAILED) set(_GSS_VERSION 0) endif() execute_process( COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor" OUTPUT_VARIABLE _GSS_VENDOR RESULT_VARIABLE _GSS_CONFIGURE_FAILED OUTPUT_STRIP_TRAILING_WHITESPACE ) # older versions may not have the "--vendor" parameter. In this case we just don't care. if(_GSS_CONFIGURE_FAILED) set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter else() if(_GSS_VENDOR MATCHES ".*H|heimdal.*") set(GSS_FLAVOUR "Heimdal") else() set(GSS_FLAVOUR "MIT") endif() endif() else() # either there is no config script or we are on a platform that doesn't provide one (Windows?) find_path(_GSS_INCLUDE_DIR NAMES "gssapi/gssapi.h" HINTS ${_GSS_ROOT_HINTS} PATH_SUFFIXES include inc ) if(_GSS_INCLUDE_DIR) #jay, we've found something set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}") check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS) if(_GSS_HAVE_MIT_HEADERS) set(GSS_FLAVOUR "MIT") else() # prevent compiling the header - just check if we can include it set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D__ROKEN_H__") check_include_file( "roken.h" _GSS_HAVE_ROKEN_H) check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H) if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H) set(GSS_FLAVOUR "Heimdal") endif() set(CMAKE_REQUIRED_DEFINITIONS "") endif() else() # I'm not convinced if this is the right way but this is what autotools do at the moment find_path(_GSS_INCLUDE_DIR NAMES "gssapi.h" HINTS ${_GSS_ROOT_HINTS} PATH_SUFFIXES include inc ) if(_GSS_INCLUDE_DIR) set(GSS_FLAVOUR "Heimdal") endif() endif() # if we have headers, check if we can link libraries if(GSS_FLAVOUR) set(_GSS_LIBDIR_SUFFIXES "") set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS}) get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH) list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT}) if(WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64") if(GSS_FLAVOUR STREQUAL "MIT") set(_GSS_LIBNAME "gssapi64") else() set(_GSS_LIBNAME "libgssapi") endif() else() list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386") if(GSS_FLAVOUR STREQUAL "MIT") set(_GSS_LIBNAME "gssapi32") else() set(_GSS_LIBNAME "libgssapi") endif() endif() else() list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS if(GSS_FLAVOUR STREQUAL "MIT") set(_GSS_LIBNAME "gssapi_krb5") else() set(_GSS_LIBNAME "gssapi") endif() endif() find_library(_GSS_LIBRARIES NAMES ${_GSS_LIBNAME} HINTS ${_GSS_LIBDIR_HINTS} PATH_SUFFIXES ${_GSS_LIBDIR_SUFFIXES} ) endif() endif() else() if(_GSS_PKG_${_MIT_MODNAME}_VERSION) set(GSS_FLAVOUR "MIT") set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION) else() set(GSS_FLAVOUR "Heimdal") set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION) endif() endif() set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR}) set(GSS_LIBRARIES ${_GSS_LIBRARIES}) set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES}) set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS}) set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS}) set(GSS_VERSION ${_GSS_VERSION}) if(GSS_FLAVOUR) if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest") else() set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest") endif() if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}") file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$") string(REGEX MATCH "[0-9]\\.[^\"]+" GSS_VERSION "${heimdal_version_str}") endif() if(NOT GSS_VERSION) set(GSS_VERSION "Heimdal Unknown") endif() elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) if(WIN32 AND _MIT_VERSION) set(GSS_VERSION "${_MIT_VERSION}") else() set(GSS_VERSION "MIT Unknown") endif() endif() endif() include(FindPackageHandleStandardArgs) set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR) find_package_handle_standard_args(GSS REQUIRED_VARS ${_GSS_REQUIRED_VARS} VERSION_VAR GSS_VERSION FAIL_MESSAGE "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR" ) mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES) davix-0.8.0/deps/curl/CMake/CurlSymbolHiding.cmake0000644000000000000000000000442214121063461020430 0ustar rootrootinclude(CheckCSourceCompiles) option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) mark_as_advanced(CURL_HIDDEN_SYMBOLS) if(CURL_HIDDEN_SYMBOLS) set(SUPPORTS_SYMBOL_HIDING FALSE) if(CMAKE_C_COMPILER_ID MATCHES "Clang") set(SUPPORTS_SYMBOL_HIDING TRUE) set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") elseif(CMAKE_COMPILER_IS_GNUCC) if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4) # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact set(SUPPORTS_SYMBOL_HIDING TRUE) set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") endif() elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0) set(SUPPORTS_SYMBOL_HIDING TRUE) set(_SYMBOL_EXTERN "__global") set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden") elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0) # note: this should probably just check for version 9.1.045 but I'm not 100% sure # so let's do it the same way autotools do. set(SUPPORTS_SYMBOL_HIDING TRUE) set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") check_c_source_compiles("#include int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug) if(NOT _no_bug) set(SUPPORTS_SYMBOL_HIDING FALSE) set(_SYMBOL_EXTERN "") set(_CFLAG_SYMBOLS_HIDE "") endif() elseif(MSVC) set(SUPPORTS_SYMBOL_HIDING TRUE) endif() set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING}) elseif(MSVC) if(NOT CMAKE_VERSION VERSION_LESS 3.7) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) else() message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.") set(HIDES_CURL_PRIVATE_SYMBOLS TRUE) endif() else() set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) endif() set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE}) set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN}) davix-0.8.0/deps/curl/CMake/FindMbedTLS.cmake0000644000000000000000000000101414121063461017237 0ustar rootrootfind_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h) find_library(MBEDTLS_LIBRARY mbedtls) find_library(MBEDX509_LIBRARY mbedx509) find_library(MBEDCRYPTO_LIBRARY mbedcrypto) set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MBEDTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) davix-0.8.0/deps/curl/CMake/curl-config.cmake.in0000644000000000000000000000046114121063461020026 0ustar rootroot@PACKAGE_INIT@ include(CMakeFindDependencyMacro) if(@USE_OPENSSL@) find_dependency(OpenSSL @OPENSSL_VERSION_MAJOR@) endif() if(@USE_ZLIB@) find_dependency(ZLIB @ZLIB_VERSION_MAJOR@) endif() include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") check_required_components("@PROJECT_NAME@") davix-0.8.0/deps/curl/CMake/FindCARES.cmake0000644000000000000000000000121114121063461016641 0ustar rootroot# - Find c-ares # Find the c-ares includes and library # This module defines # CARES_INCLUDE_DIR, where to find ares.h, etc. # CARES_LIBRARIES, the libraries needed to use c-ares. # CARES_FOUND, If false, do not try to use c-ares. # also defined, but not for general use are # CARES_LIBRARY, where to find the c-ares library. find_path(CARES_INCLUDE_DIR ares.h) set(CARES_NAMES ${CARES_NAMES} cares) find_library(CARES_LIBRARY NAMES ${CARES_NAMES} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CARES REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR) mark_as_advanced( CARES_LIBRARY CARES_INCLUDE_DIR ) davix-0.8.0/deps/curl/CMake/FindBrotli.cmake0000644000000000000000000000101414121063461017240 0ustar rootrootinclude(FindPackageHandleStandardArgs) find_path(BROTLI_INCLUDE_DIR "brotli/decode.h") find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon) find_library(BROTLIDEC_LIBRARY NAMES brotlidec) find_package_handle_standard_args(BROTLI FOUND_VAR BROTLI_FOUND REQUIRED_VARS BROTLIDEC_LIBRARY BROTLICOMMON_LIBRARY BROTLI_INCLUDE_DIR FAIL_MESSAGE "Could NOT find BROTLI" ) set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR}) set(BROTLI_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY}) davix-0.8.0/deps/curl/CMake/FindNSS.cmake0000644000000000000000000000064414121063461016460 0ustar rootrootif(UNIX) find_package(PkgConfig QUIET) pkg_search_module(PC_NSS nss) endif() if(NOT PC_NSS_FOUND) return() endif() set(NSS_LIBRARIES ${PC_NSS_LINK_LIBRARIES}) set(NSS_INCLUDE_DIRS ${PC_NSS_INCLUDE_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(NSS REQUIRED_VARS NSS_LIBRARIES NSS_INCLUDE_DIRS VERSION_VAR PC_NSS_VERSION) mark_as_advanced(NSS_INCLUDE_DIRS NSS_LIBRARIES) davix-0.8.0/deps/curl/CMake/Platforms/0000755000000000000000000000000014121063461016155 5ustar rootrootdavix-0.8.0/deps/curl/CMake/Platforms/WindowsCache.cmake0000644000000000000000000000607614121063461021546 0ustar rootrootif(NOT UNIX) if(WIN32) set(HAVE_LIBDL 0) set(HAVE_LIBUCB 0) set(HAVE_LIBSOCKET 0) set(NOT_NEED_LIBNSL 0) set(HAVE_LIBNSL 0) set(HAVE_GETHOSTNAME 1) set(HAVE_LIBZ 0) set(HAVE_DLOPEN 0) set(HAVE_ALLOCA_H 0) set(HAVE_ARPA_INET_H 0) set(HAVE_DLFCN_H 0) set(HAVE_FCNTL_H 1) set(HAVE_INTTYPES_H 0) set(HAVE_IO_H 1) set(HAVE_MALLOC_H 1) set(HAVE_MEMORY_H 1) set(HAVE_NETDB_H 0) set(HAVE_NETINET_IF_ETHER_H 0) set(HAVE_NETINET_IN_H 0) set(HAVE_NET_IF_H 0) set(HAVE_PROCESS_H 1) set(HAVE_PWD_H 0) set(HAVE_SETJMP_H 1) set(HAVE_SGTTY_H 0) set(HAVE_SIGNAL_H 1) set(HAVE_SOCKIO_H 0) set(HAVE_STDINT_H 0) set(HAVE_STDLIB_H 1) set(HAVE_STRINGS_H 0) set(HAVE_STRING_H 1) set(HAVE_SYS_PARAM_H 0) set(HAVE_SYS_POLL_H 0) set(HAVE_SYS_SELECT_H 0) set(HAVE_SYS_SOCKET_H 0) set(HAVE_SYS_SOCKIO_H 0) set(HAVE_SYS_STAT_H 1) set(HAVE_SYS_TIME_H 0) set(HAVE_SYS_TYPES_H 1) set(HAVE_SYS_UTIME_H 1) set(HAVE_TERMIOS_H 0) set(HAVE_TERMIO_H 0) set(HAVE_TIME_H 1) set(HAVE_UNISTD_H 0) set(HAVE_UTIME_H 0) set(HAVE_X509_H 0) set(HAVE_ZLIB_H 0) set(HAVE_SIZEOF_LONG_DOUBLE 1) set(SIZEOF_LONG_DOUBLE 8) set(HAVE_SOCKET 1) set(HAVE_POLL 0) set(HAVE_SELECT 1) set(HAVE_STRDUP 1) set(HAVE_STRSTR 1) set(HAVE_STRTOK_R 0) set(HAVE_STRFTIME 1) set(HAVE_UNAME 0) set(HAVE_STRCASECMP 0) set(HAVE_STRICMP 1) set(HAVE_STRCMPI 1) set(HAVE_GETHOSTBYADDR 1) set(HAVE_GETTIMEOFDAY 0) set(HAVE_INET_ADDR 1) set(HAVE_INET_NTOA 1) set(HAVE_INET_NTOA_R 0) set(HAVE_TCGETATTR 0) set(HAVE_TCSETATTR 0) set(HAVE_PERROR 1) set(HAVE_CLOSESOCKET 1) set(HAVE_SETVBUF 0) set(HAVE_SIGSETJMP 0) set(HAVE_GETPASS_R 0) set(HAVE_STRLCAT 0) set(HAVE_GETPWUID 0) set(HAVE_GETEUID 0) set(HAVE_UTIME 1) set(HAVE_RAND_EGD 0) set(HAVE_RAND_SCREEN 0) set(HAVE_RAND_STATUS 0) set(HAVE_GMTIME_R 0) set(HAVE_LOCALTIME_R 0) set(HAVE_GETHOSTBYADDR_R 0) set(HAVE_GETHOSTBYNAME_R 0) set(HAVE_SIGNAL_FUNC 1) set(HAVE_SIGNAL_MACRO 0) set(HAVE_GETHOSTBYADDR_R_5 0) set(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0) set(HAVE_GETHOSTBYADDR_R_7 0) set(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0) set(HAVE_GETHOSTBYADDR_R_8 0) set(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0) set(HAVE_GETHOSTBYNAME_R_3 0) set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0) set(HAVE_GETHOSTBYNAME_R_5 0) set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0) set(HAVE_GETHOSTBYNAME_R_6 0) set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0) set(TIME_WITH_SYS_TIME 0) set(HAVE_O_NONBLOCK 0) set(HAVE_IN_ADDR_T 0) set(HAVE_INET_NTOA_R_DECL 0) set(HAVE_INET_NTOA_R_DECL_REENTRANT 0) if(ENABLE_IPV6) set(HAVE_GETADDRINFO 1) else() set(HAVE_GETADDRINFO 0) endif() set(STDC_HEADERS 1) set(RETSIGTYPE_TEST 1) set(HAVE_SIGACTION 0) set(HAVE_MACRO_SIGSETJMP 0) else() message("This file should be included on Windows platform only") endif() endif() davix-0.8.0/deps/curl/CMake/cmake_uninstall.cmake.in0000644000000000000000000000165614121063461020776 0ustar rootrootif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif() if(NOT DEFINED CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") endif() message(${CMAKE_INSTALL_PREFIX}) file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif() else() message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif() endforeach() davix-0.8.0/deps/curl/CMake/OtherTests.cmake0000644000000000000000000002245514121063461017324 0ustar rootrootinclude(CheckCSourceCompiles) # The begin of the sources (macros and includes) set(_source_epilogue "#undef inline") macro(add_header_include check header) if(${check}) set(_source_epilogue "${_source_epilogue}\n#include <${header}>") endif() endmacro() set(signature_call_conv) if(HAVE_WINDOWS_H) add_header_include(HAVE_WINSOCK2_H "winsock2.h") add_header_include(HAVE_WINDOWS_H "windows.h") add_header_include(HAVE_WINSOCK_H "winsock.h") set(_source_epilogue "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif") set(signature_call_conv "PASCAL") if(HAVE_LIBWS2_32) set(CMAKE_REQUIRED_LIBRARIES ws2_32) endif() else() add_header_include(HAVE_SYS_TYPES_H "sys/types.h") add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h") endif() set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) check_c_source_compiles("${_source_epilogue} int main(void) { recv(0, 0, 0, 0); return 0; }" curl_cv_recv) if(curl_cv_recv) if(NOT DEFINED curl_cv_func_recv_args OR curl_cv_func_recv_args STREQUAL "unknown") foreach(recv_retv "int" "ssize_t" ) foreach(recv_arg1 "SOCKET" "int" ) foreach(recv_arg2 "char *" "void *" ) foreach(recv_arg3 "int" "size_t" "socklen_t" "unsigned int") foreach(recv_arg4 "int" "unsigned int") if(NOT curl_cv_func_recv_done) unset(curl_cv_func_recv_test CACHE) check_c_source_compiles(" ${_source_epilogue} extern ${recv_retv} ${signature_call_conv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4}); int main(void) { ${recv_arg1} s=0; ${recv_arg2} buf=0; ${recv_arg3} len=0; ${recv_arg4} flags=0; ${recv_retv} res = recv(s, buf, len, flags); (void) res; return 0; }" curl_cv_func_recv_test) message(STATUS "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})") if(curl_cv_func_recv_test) set(curl_cv_func_recv_args "${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}") set(RECV_TYPE_ARG1 "${recv_arg1}") set(RECV_TYPE_ARG2 "${recv_arg2}") set(RECV_TYPE_ARG3 "${recv_arg3}") set(RECV_TYPE_ARG4 "${recv_arg4}") set(RECV_TYPE_RETV "${recv_retv}") set(HAVE_RECV 1) set(curl_cv_func_recv_done 1) endif() endif() endforeach() endforeach() endforeach() endforeach() endforeach() else() string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG1 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG2 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG3 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" RECV_TYPE_ARG4 "${curl_cv_func_recv_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}") endif() if(curl_cv_func_recv_args STREQUAL "unknown") message(FATAL_ERROR "Cannot find proper types to use for recv args") endif() else() message(FATAL_ERROR "Unable to link function recv") endif() set(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv") set(HAVE_RECV 1) check_c_source_compiles("${_source_epilogue} int main(void) { send(0, 0, 0, 0); return 0; }" curl_cv_send) if(curl_cv_send) if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown") foreach(send_retv "int" "ssize_t" ) foreach(send_arg1 "SOCKET" "int" "ssize_t" ) foreach(send_arg2 "const char *" "const void *" "void *" "char *") foreach(send_arg3 "int" "size_t" "socklen_t" "unsigned int") foreach(send_arg4 "int" "unsigned int") if(NOT curl_cv_func_send_done) unset(curl_cv_func_send_test CACHE) check_c_source_compiles(" ${_source_epilogue} extern ${send_retv} ${signature_call_conv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4}); int main(void) { ${send_arg1} s=0; ${send_arg2} buf=0; ${send_arg3} len=0; ${send_arg4} flags=0; ${send_retv} res = send(s, buf, len, flags); (void) res; return 0; }" curl_cv_func_send_test) message(STATUS "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})") if(curl_cv_func_send_test) string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}") string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}") set(curl_cv_func_send_args "${send_arg1},${send_arg2},${send_arg3},${send_arg4},${send_retv},${send_qual_arg2}") set(SEND_TYPE_ARG1 "${send_arg1}") set(SEND_TYPE_ARG2 "${send_arg2}") set(SEND_TYPE_ARG3 "${send_arg3}") set(SEND_TYPE_ARG4 "${send_arg4}") set(SEND_TYPE_RETV "${send_retv}") set(HAVE_SEND 1) set(curl_cv_func_send_done 1) endif() endif() endforeach() endforeach() endforeach() endforeach() endforeach() else() string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG1 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG2 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG3 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG4 "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" SEND_TYPE_RETV "${curl_cv_func_send_args}") string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" SEND_QUAL_ARG2 "${curl_cv_func_send_args}") endif() if("${curl_cv_func_send_args}" STREQUAL "unknown") message(FATAL_ERROR "Cannot find proper types to use for send args") endif() set(SEND_QUAL_ARG2 "const") else() message(FATAL_ERROR "Unable to link function send") endif() set(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send") set(HAVE_SEND 1) check_c_source_compiles("${_source_epilogue} int main(void) { int flag = MSG_NOSIGNAL; (void)flag; return 0; }" HAVE_MSG_NOSIGNAL) if(NOT HAVE_WINDOWS_H) add_header_include(HAVE_SYS_TIME_H "sys/time.h") add_header_include(TIME_WITH_SYS_TIME "time.h") add_header_include(HAVE_TIME_H "time.h") endif() check_c_source_compiles("${_source_epilogue} int main(void) { struct timeval ts; ts.tv_sec = 0; ts.tv_usec = 0; (void)ts; return 0; }" HAVE_STRUCT_TIMEVAL) set(HAVE_SIG_ATOMIC_T 1) set(CMAKE_REQUIRED_FLAGS) if(HAVE_SIGNAL_H) set(CMAKE_REQUIRED_FLAGS "-DHAVE_SIGNAL_H") set(CMAKE_EXTRA_INCLUDE_FILES "signal.h") endif() check_type_size("sig_atomic_t" SIZEOF_SIG_ATOMIC_T) if(HAVE_SIZEOF_SIG_ATOMIC_T) check_c_source_compiles(" #ifdef HAVE_SIGNAL_H # include #endif int main(void) { static volatile sig_atomic_t dummy = 0; (void)dummy; return 0; }" HAVE_SIG_ATOMIC_T_NOT_VOLATILE) if(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE) set(HAVE_SIG_ATOMIC_T_VOLATILE 1) endif() endif() if(HAVE_WINDOWS_H) set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h) else() set(CMAKE_EXTRA_INCLUDE_FILES) if(HAVE_SYS_SOCKET_H) set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) endif() endif() check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE) if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE) set(HAVE_STRUCT_SOCKADDR_STORAGE 1) endif() unset(CMAKE_TRY_COMPILE_TARGET_TYPE) if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) # if not cross-compilation... include(CheckCSourceRuns) set(CMAKE_REQUIRED_FLAGS "") if(HAVE_SYS_POLL_H) set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H") elseif(HAVE_POLL_H) set(CMAKE_REQUIRED_FLAGS "-DHAVE_POLL_H") endif() check_c_source_runs(" #include #include #ifdef HAVE_SYS_POLL_H # include #elif HAVE_POLL_H # include #endif int main(void) { if(0 != poll(0, 0, 10)) { return 1; /* fail */ } else { /* detect the 10.12 poll() breakage */ struct timeval before, after; int rc; size_t us; gettimeofday(&before, NULL); rc = poll(NULL, 0, 500); gettimeofday(&after, NULL); us = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec); if(us < 400000) { return 1; } } return 0; }" HAVE_POLL_FINE) endif() davix-0.8.0/deps/curl/CMake/Macros.cmake0000644000000000000000000000660514121063461016443 0ustar rootroot#File defines convenience macros for available feature testing # This macro checks if the symbol exists in the library and if it # does, it prepends library to the list. It is intended to be called # multiple times with a sequence of possibly dependent libraries in # order of least-to-most-dependent. Some libraries depend on others # to link correctly. macro(check_library_exists_concat LIBRARY SYMBOL VARIABLE) check_library_exists("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "${CMAKE_LIBRARY_PATH}" ${VARIABLE}) if(${VARIABLE}) set(CURL_LIBS ${LIBRARY} ${CURL_LIBS}) endif() endmacro() # Check if header file exists and add it to the list. # This macro is intended to be called multiple times with a sequence of # possibly dependent header files. Some headers depend on others to be # compiled correctly. macro(check_include_file_concat FILE VARIABLE) check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE}) if(${VARIABLE}) set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE}) set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}") endif() endmacro() # For other curl specific tests, use this macro. macro(curl_internal_test CURL_TEST) if(NOT DEFINED "${CURL_TEST}") set(MACRO_CHECK_FUNCTION_DEFINITIONS "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}") if(CMAKE_REQUIRED_LIBRARIES) set(CURL_TEST_ADD_LIBRARIES "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") endif() message(STATUS "Performing Curl Test ${CURL_TEST}") try_compile(${CURL_TEST} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} "${CURL_TEST_ADD_LIBRARIES}" OUTPUT_VARIABLE OUTPUT) if(${CURL_TEST}) set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}") message(STATUS "Performing Curl Test ${CURL_TEST} - Success") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Performing Curl Test ${CURL_TEST} passed with the following output:\n" "${OUTPUT}\n") else() message(STATUS "Performing Curl Test ${CURL_TEST} - Failed") set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Performing Curl Test ${CURL_TEST} failed with the following output:\n" "${OUTPUT}\n") endif() endif() endmacro() macro(curl_nroff_check) find_program(NROFF NAMES gnroff nroff) if(NROFF) # Need a way to write to stdin, this will do file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test") # Tests for a valid nroff option to generate a manpage foreach(_MANOPT "-man" "-mandoc") execute_process(COMMAND "${NROFF}" ${_MANOPT} OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" ERROR_QUIET) # Save the option if it was valid if(NROFF_MANOPT_OUTPUT) message("Found *nroff option: -- ${_MANOPT}") set(NROFF_MANOPT ${_MANOPT}) set(NROFF_USEFUL ON) break() endif() endforeach() # No need for the temporary file file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt") if(NOT NROFF_USEFUL) message(WARNING "Found no *nroff option to get plaintext from man pages") endif() else() message(WARNING "Found no *nroff program") endif() endmacro() davix-0.8.0/deps/curl/lib/0000755000000000000000000000000014121063461013774 5ustar rootrootdavix-0.8.0/deps/curl/lib/mk-ca-bundle.pl0000755000000000000000000005057714121063461016611 0ustar rootroot#!/usr/bin/env perl # *************************************************************************** # * _ _ ____ _ # * Project ___| | | | _ \| | # * / __| | | | |_) | | # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * # * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms # * are also available at https://curl.haxx.se/docs/copyright.html. # * # * You may opt to use, copy, modify, merge, publish, distribute and/or sell # * copies of the Software, and permit persons to whom the Software is # * furnished to do so, under the terms of the COPYING file. # * # * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # * KIND, either express or implied. # * # *************************************************************************** # This Perl script creates a fresh ca-bundle.crt file for use with libcurl. # It downloads certdata.txt from Mozilla's source tree (see URL below), # then parses certdata.txt and extracts CA Root Certificates into PEM format. # These are then processed with the OpenSSL commandline tool to produce the # final ca-bundle.crt file. # The script is based on the parse-certs script written by Roland Krikava. # This Perl script works on almost any platform since its only external # dependency is the OpenSSL commandline tool for optional text listing. # Hacked by Guenter Knauf. # use Encode; use Getopt::Std; use MIME::Base64; use strict; use warnings; use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); use List::Util; use Text::Wrap; use Time::Local; my $MOD_SHA = "Digest::SHA"; eval "require $MOD_SHA"; if ($@) { $MOD_SHA = "Digest::SHA::PurePerl"; eval "require $MOD_SHA"; } eval "require LWP::UserAgent"; my %urls = ( 'nss' => 'https://hg.mozilla.org/projects/nss/raw-file/default/lib/ckfw/builtins/certdata.txt', 'central' => 'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', 'beta' => 'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', 'release' => 'https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', ); $opt_d = 'release'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; my $version = '1.27'; $opt_w = 76; # default base64 encoded lines length # default cert types to include in the output (default is to include CAs which may issue SSL server certs) my $default_mozilla_trust_purposes = "SERVER_AUTH"; my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; $opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; my @valid_mozilla_trust_purposes = ( "DIGITAL_SIGNATURE", "NON_REPUDIATION", "KEY_ENCIPHERMENT", "DATA_ENCIPHERMENT", "KEY_AGREEMENT", "KEY_CERT_SIGN", "CRL_SIGN", "SERVER_AUTH", "CLIENT_AUTH", "CODE_SIGNING", "EMAIL_PROTECTION", "IPSEC_END_SYSTEM", "IPSEC_TUNNEL", "IPSEC_USER", "TIME_STAMPING", "STEP_UP_APPROVED" ); my @valid_mozilla_trust_levels = ( "TRUSTED_DELEGATOR", # CAs "NOT_TRUSTED", # Don't trust these certs. "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is otherwise ok. In other words, this should tell the app to ignore any other sources that claim this is a CA. "TRUSTED" # This cert is trusted, but only for itself and not for delegates (i.e. it is not a CA). ); my $default_signature_algorithms = $opt_s = "MD5"; my @valid_signature_algorithms = ( "MD5", "SHA1", "SHA256", "SHA384", "SHA512" ); $0 =~ s@.*(/|\\)@@; $Getopt::Std::STANDARD_HELP_VERSION = 1; getopts('bd:fhiklmnp:qs:tuvw:'); if(!defined($opt_d)) { # to make plain "-d" use not cause warnings, and actually still work $opt_d = 'release'; } # Use predefined URL or else custom URL specified on command line. my $url; if(defined($urls{$opt_d})) { $url = $urls{$opt_d}; if(!$opt_k && $url !~ /^https:\/\//i) { die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; } } else { $url = $opt_d; } my $curl = `curl -V`; if ($opt_i) { print ("=" x 78 . "\n"); print "Script Version : $version\n"; print "Perl Version : $]\n"; print "Operating System Name : $^O\n"; print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; print "Encode::Encoding.pm Version : ${Encode::Encoding::VERSION}\n"; print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); print ("=" x 78 . "\n"); } sub warning_message() { if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit print "Warning: Use of this script may pose some risk:\n"; print "\n"; print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; print " 2) Default to 'release', but more recent updates may be found in other trees\n"; print " 3) certdata.txt file format may change, lag time to update this script\n"; print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; print " 5) Mozilla apps use additional security checks aren't represented in certdata\n"; print " 6) Use of this script will make a security engineer grind his teeth and\n"; print " swear at you. ;)\n"; exit; } else { # Short Form Warning print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; } } sub HELP_MESSAGE() { print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; print "\t-b\tbackup an existing version of ca-bundle.crt\n"; print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; print "\t\t Valid names are:\n"; print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; print "\t-f\tforce rebuild even if certdata.txt is current\n"; print "\t-i\tprint version info about used modules\n"; print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; print "\t-l\tprint license info about certdata.txt\n"; print "\t-m\tinclude meta data in output\n"; print "\t-n\tno download of certdata.txt (to use existing)\n"; print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; print "\t\t Valid purposes are:\n"; print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; print "\t\t Valid levels are:\n"; print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; print "\t-q\tbe really quiet (no progress output at all)\n"; print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); print "\t\t Valid signature algorithms are:\n"; print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; print "\t-t\tinclude plain text listing of certificates\n"; print "\t-u\tunlink (remove) certdata.txt after processing\n"; print "\t-v\tbe verbose and print out processed CAs\n"; print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; exit; } sub VERSION_MESSAGE() { print "${0} version ${version} running Perl ${]} on ${^O}\n"; } warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); HELP_MESSAGE() if ($opt_h); sub report($@) { my $output = shift; print STDERR $output . "\n" unless $opt_q; } sub is_in_list($@) { my $target = shift; return defined(List::Util::first { $target eq $_ } @_); } # Parses $param_string as a case insensitive comma separated list with optional whitespace # validates that only allowed parameters are supplied sub parse_csv_param($$@) { my $description = shift; my $param_string = shift; my @valid_values = @_; my @values = map { s/^\s+//; # strip leading spaces s/\s+$//; # strip trailing spaces uc $_ # return the modified string as upper case } split( ',', $param_string ); # Find all values which are not in the list of valid values or "ALL" my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; if ( scalar(@invalid) > 0 ) { # Tell the user which parameters were invalid and print the standard help message which will exit print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; HELP_MESSAGE(); } @values = @valid_values if ( is_in_list("ALL",@values) ); return @values; } sub sha256 { my $result; if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; binmode(FILE); $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; close(FILE); } else { # Use OpenSSL command if Perl Digest::SHA modules not available $result = `"$openssl" dgst -r -sha256 "$_[0]"`; $result =~ s/^([0-9a-f]{64}) .+/$1/is; } return $result; } sub oldhash { my $hash = ""; open(C, "<$_[0]") || return 0; while() { chomp; if($_ =~ /^\#\# SHA256: (.*)/) { $hash = $1; last; } } close(C); return $hash; } if ( $opt_p !~ m/:/ ) { print "Error: Mozilla trust identifier list must include both purposes and levels\n"; HELP_MESSAGE(); } (my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); sub should_output_cert(%) { my %trust_purposes_by_level = @_; foreach my $level (@included_mozilla_trust_levels) { # for each level we want to output, see if any of our desired purposes are included return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); } return 0; } my $crt = $ARGV[0] || 'ca-bundle.crt'; (my $txt = $url) =~ s@(.*/|\?.*)@@g; my $stdout = $crt eq '-'; my $resp; my $fetched; my $oldhash = oldhash($crt); report "SHA256 of old file: $oldhash"; if(!$opt_n) { report "Downloading $txt ..."; # If we have an HTTPS URL then use curl if($url =~ /^https:\/\//i) { if($curl) { if($curl =~ /^Protocols:.* https( |$)/m) { report "Get certdata with curl!"; my $proto = !$opt_k ? "--proto =https" : ""; my $quiet = $opt_q ? "-s" : ""; my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`; if(!$? && @out && $out[0] == 200) { $fetched = 1; report "Downloaded $txt"; } else { report "Failed downloading via HTTPS with curl"; if(-e $txt && !unlink($txt)) { report "Failed to remove '$txt': $!"; } } } else { report "curl lacks https support"; } } else { report "curl not found"; } } # If nothing was fetched then use LWP if(!$fetched) { if($url =~ /^https:\/\//i) { report "Falling back to HTTP"; $url =~ s/^https:\/\//http:\/\//i; } if(!$opt_k) { report "URLs other than HTTPS are disabled by default, to enable use -k"; exit 1; } report "Get certdata with LWP!"; if(!defined(${LWP::UserAgent::VERSION})) { report "LWP is not available (LWP::UserAgent not found)"; exit 1; } my $ua = new LWP::UserAgent(agent => "$0/$version"); $ua->env_proxy(); $resp = $ua->mirror($url, $txt); if($resp && $resp->code eq '304') { report "Not modified"; exit 0 if -e $crt && !$opt_f; } else { $fetched = 1; report "Downloaded $txt"; } if(!$resp || $resp->code !~ /^(?:200|304)$/) { report "Unable to download latest data: " . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); exit 1 if -e $crt || ! -r $txt; } } } my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; my $datesrc = "as of"; if(!$filedate) { # mxr.mozilla.org gave us a time, hg.mozilla.org does not! $filedate = time(); $datesrc="downloaded on"; } # get the hash from the download file my $newhash= sha256($txt); if(!$opt_f && $oldhash eq $newhash) { report "Downloaded file identical to previous run\'s source file. Exiting"; if($opt_u && -e $txt && !unlink($txt)) { report "Failed to remove $txt: $!\n"; } exit; } report "SHA256 of new file: $newhash"; my $currentdate = scalar gmtime($filedate); my $format = $opt_t ? "plain text and " : ""; if( $stdout ) { open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; } else { open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; } print CRT <) { if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { print CRT; print if ($opt_l); while () { print CRT; print if ($opt_l); last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); } } elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { push @precert, $_; $valid = 1; next; } elsif(/^#|^\s*$/) { undef @precert; next; } chomp; # Example: # CKA_NSS_SERVER_DISTRUST_AFTER MULTILINE_OCTAL # \062\060\060\066\061\067\060\060\060\060\060\060\132 # END if (/^CKA_NSS_SERVER_DISTRUST_AFTER (CK_BBOOL CK_FALSE|MULTILINE_OCTAL)/) { if($1 eq "MULTILINE_OCTAL") { my @timestamp; while () { last if (/^END/); chomp; my @octets = split(/\\/); shift @octets; for (@octets) { push @timestamp, chr(oct); } } # A trailing Z in the timestamp signifies UTC if($timestamp[12] ne "Z") { report "distrust date stamp is not using UTC"; } # Example date: 200617000000Z # Means 2020-06-17 00:00:00 UTC my $distrustat = timegm($timestamp[10] . $timestamp[11], # second $timestamp[8] . $timestamp[9], # minute $timestamp[6] . $timestamp[7], # hour $timestamp[4] . $timestamp[5], # day ($timestamp[2] . $timestamp[3]) - 1, # month "20" . $timestamp[0] . $timestamp[1]); # year if(time >= $distrustat) { # not trusted anymore $skipnum++; report "Skipping: $caname is not trusted anymore" if ($opt_v); $valid = 0; } else { # still trusted } } next; } # this is a match for the start of a certificate if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { $start_of_cert = 1 } if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { $caname = $1; } my %trust_purposes_by_level; if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { $cka_value=""; while () { last if (/^END/); chomp; my @octets = split(/\\/); shift @octets; for (@octets) { $cka_value .= chr(oct); } } } if(/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/ && $valid) { # now scan the trust part to determine how we should trust this cert while () { last if (/^#/); if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; } else { push @{$trust_purposes_by_level{$2}}, $1; } } } if ( !should_output_cert(%trust_purposes_by_level) ) { $skipnum ++; report "Skipping: $caname" if ($opt_v); } else { my $data = $cka_value; $cka_value = ""; my $encoded = MIME::Base64::encode_base64($data, ''); $encoded =~ s/(.{1,${opt_w}})/$1\n/g; my $pem = "-----BEGIN CERTIFICATE-----\n" . $encoded . "-----END CERTIFICATE-----\n"; print CRT "\n$caname\n"; print CRT @precert if($opt_m); my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK | Encode::LEAVE_SRC)); if ($opt_t) { foreach my $key (keys %trust_purposes_by_level) { my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); $maxStringLength = List::Util::max( length($string), $maxStringLength ); print CRT $string . "\n"; } } print CRT ("=" x $maxStringLength . "\n"); if (!$opt_t) { print CRT $pem; } else { my $pipe = ""; foreach my $hash (@included_signature_algorithms) { $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; if (!$stdout) { $pipe .= " >> $crt.~"; close(CRT) or die "Couldn't close $crt.~: $!"; } open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; print TMP $pem; close(TMP) or die "Couldn't close openssl pipe: $!"; if (!$stdout) { open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; } } $pipe = "|$openssl x509 -text -inform PEM"; if (!$stdout) { $pipe .= " >> $crt.~"; close(CRT) or die "Couldn't close $crt.~: $!"; } open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; print TMP $pem; close(TMP) or die "Couldn't close openssl pipe: $!"; if (!$stdout) { open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; } } report "Parsing: $caname" if ($opt_v); $certnum ++; $start_of_cert = 0; } undef @precert; } } close(TXT) or die "Couldn't close $txt: $!\n"; close(CRT) or die "Couldn't close $crt.~: $!\n"; unless( $stdout ) { if ($opt_b && -e $crt) { my $bk = 1; while (-e "$crt.~${bk}~") { $bk++; } rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; } elsif( -e $crt ) { unlink( $crt ) or die "Failed to remove $crt: $!\n"; } rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; } if($opt_u && -e $txt && !unlink($txt)) { report "Failed to remove $txt: $!\n"; } report "Done ($certnum CA certs processed, $skipnum skipped)."; davix-0.8.0/deps/curl/lib/telnet.h0000644000000000000000000000227014121063461015441 0ustar rootroot#ifndef HEADER_CURL_TELNET_H #define HEADER_CURL_TELNET_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_TELNET extern const struct Curl_handler Curl_handler_telnet; #endif #endif /* HEADER_CURL_TELNET_H */ davix-0.8.0/deps/curl/lib/http2.c0000644000000000000000000022503314121063461015206 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGHTTP2 #include #include "urldata.h" #include "http2.h" #include "http.h" #include "sendf.h" #include "select.h" #include "curl_base64.h" #include "strcase.h" #include "multiif.h" #include "url.h" #include "connect.h" #include "strtoofft.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define H2_BUFSIZE 32768 #if (NGHTTP2_VERSION_NUM < 0x010c00) #error too old nghttp2 version, upgrade! #endif #ifdef CURL_DISABLE_VERBOSE_STRINGS #define nghttp2_session_callbacks_set_error_callback(x,y) #endif #if (NGHTTP2_VERSION_NUM >= 0x010c00) #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 #endif #define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */ #ifdef DEBUG_HTTP2 #define H2BUGF(x) x #else #define H2BUGF(x) do { } while(0) #endif static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err); static bool http2_connisdead(struct connectdata *conn); static int h2_session_send(struct Curl_easy *data, nghttp2_session *h2); static int h2_process_pending_input(struct connectdata *conn, struct http_conn *httpc, CURLcode *err); /* * Curl_http2_init_state() is called when the easy handle is created and * allows for HTTP/2 specific init of state. */ void Curl_http2_init_state(struct UrlState *state) { state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; } /* * Curl_http2_init_userset() is called when the easy handle is created and * allows for HTTP/2 specific user-set fields. */ void Curl_http2_init_userset(struct UserDefined *set) { set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; } static int http2_perform_getsock(const struct connectdata *conn, curl_socket_t *sock) { const struct http_conn *c = &conn->proto.httpc; struct SingleRequest *k = &conn->data->req; int bitmap = GETSOCK_BLANK; sock[0] = conn->sock[FIRSTSOCKET]; /* in a HTTP/2 connection we can basically always get a frame so we should always be ready for one */ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); /* we're still uploading or the HTTP/2 layer wants to send data */ if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || nghttp2_session_want_write(c->h2)) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; } static int http2_getsock(struct connectdata *conn, curl_socket_t *socks) { return http2_perform_getsock(conn, socks); } /* * http2_stream_free() free HTTP2 stream related data */ static void http2_stream_free(struct HTTP *http) { if(http) { Curl_add_buffer_free(&http->header_recvbuf); Curl_add_buffer_free(&http->trailer_recvbuf); for(; http->push_headers_used > 0; --http->push_headers_used) { free(http->push_headers[http->push_headers_used - 1]); } free(http->push_headers); http->push_headers = NULL; } } /* * Disconnects *a* connection used for HTTP/2. It might be an old one from the * connection cache and not the "main" one. Don't touch the easy handle! */ static CURLcode http2_disconnect(struct connectdata *conn, bool dead_connection) { struct http_conn *c = &conn->proto.httpc; (void)dead_connection; H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); nghttp2_session_del(c->h2); Curl_safefree(c->inbuf); H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); return CURLE_OK; } /* * The server may send us data at any point (e.g. PING frames). Therefore, * we cannot assume that an HTTP/2 socket is dead just because it is readable. * * Instead, if it is readable, run Curl_connalive() to peek at the socket * and distinguish between closed and data. */ static bool http2_connisdead(struct connectdata *conn) { int sval; bool dead = TRUE; if(conn->bits.close) return TRUE; sval = SOCKET_READABLE(conn->sock[FIRSTSOCKET], 0); if(sval == 0) { /* timeout */ dead = FALSE; } else if(sval & CURL_CSELECT_ERR) { /* socket is in an error state */ dead = TRUE; } else if(sval & CURL_CSELECT_IN) { /* readable with no error. could still be closed */ dead = !Curl_connalive(conn); if(!dead) { /* This happens before we've sent off a request and the connection is not in use by any other transfer, there shouldn't be any data here, only "protocol frames" */ CURLcode result; struct http_conn *httpc = &conn->proto.httpc; ssize_t nread = -1; if(httpc->recv_underlying) /* if called "too early", this pointer isn't setup yet! */ nread = ((Curl_recv *)httpc->recv_underlying)( conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); if(nread != -1) { infof(conn->data, "%d bytes stray data read before trying h2 connection\n", (int)nread); httpc->nread_inbuf = 0; httpc->inbuflen = nread; (void)h2_process_pending_input(conn, httpc, &result); } else /* the read failed so let's say this is dead anyway */ dead = TRUE; } } return dead; } static unsigned int http2_conncheck(struct connectdata *check, unsigned int checks_to_perform) { unsigned int ret_val = CONNRESULT_NONE; struct http_conn *c = &check->proto.httpc; int rc; bool send_frames = false; if(checks_to_perform & CONNCHECK_ISDEAD) { if(http2_connisdead(check)) ret_val |= CONNRESULT_DEAD; } if(checks_to_perform & CONNCHECK_KEEPALIVE) { struct curltime now = Curl_now(); timediff_t elapsed = Curl_timediff(now, check->keepalive); if(elapsed > check->upkeep_interval_ms) { /* Perform an HTTP/2 PING */ rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL); if(!rc) { /* Successfully added a PING frame to the session. Need to flag this so the frame is sent. */ send_frames = true; } else { failf(check->data, "nghttp2_submit_ping() failed: %s(%d)", nghttp2_strerror(rc), rc); } check->keepalive = now; } } if(send_frames) { rc = nghttp2_session_send(c->h2); if(rc) failf(check->data, "nghttp2_session_send() failed: %s(%d)", nghttp2_strerror(rc), rc); } return ret_val; } /* called from http_setup_conn */ void Curl_http2_setup_req(struct Curl_easy *data) { struct HTTP *http = data->req.protop; http->nread_header_recvbuf = 0; http->bodystarted = FALSE; http->status_code = -1; http->pausedata = NULL; http->pauselen = 0; http->closed = FALSE; http->close_handled = FALSE; http->mem = data->state.buffer; http->len = data->set.buffer_size; http->memlen = 0; } /* called from http_setup_conn */ void Curl_http2_setup_conn(struct connectdata *conn) { conn->proto.httpc.settings.max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS; conn->proto.httpc.error_code = NGHTTP2_NO_ERROR; } /* * HTTP2 handler interface. This isn't added to the general list of protocols * but will be used at run-time when the protocol is dynamically switched from * HTTP to HTTP2. */ static const struct Curl_handler Curl_handler_http2 = { "HTTP", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ http2_getsock, /* proto_getsock */ http2_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ http2_perform_getsock, /* perform_getsock */ http2_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_STREAM /* flags */ }; static const struct Curl_handler Curl_handler_http2_ssl = { "HTTPS", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ http2_getsock, /* proto_getsock */ http2_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ http2_perform_getsock, /* perform_getsock */ http2_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ http2_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; /* * Store nghttp2 version info in this buffer, Prefix with a space. Return * total length written. */ int Curl_http2_ver(char *p, size_t len) { nghttp2_info *h2 = nghttp2_version(0); return msnprintf(p, len, " nghttp2/%s", h2->version_str); } /* * The implementation of nghttp2_send_callback type. Here we write |data| with * size |length| to the network and return the number of bytes actually * written. See the documentation of nghttp2_send_callback for the details. */ static ssize_t send_callback(nghttp2_session *h2, const uint8_t *data, size_t length, int flags, void *userp) { struct connectdata *conn = (struct connectdata *)userp; struct http_conn *c = &conn->proto.httpc; ssize_t written; CURLcode result = CURLE_OK; (void)h2; (void)flags; if(!c->send_underlying) /* called before setup properly! */ return NGHTTP2_ERR_CALLBACK_FAILURE; written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET, data, length, &result); if(result == CURLE_AGAIN) { return NGHTTP2_ERR_WOULDBLOCK; } if(written == -1) { failf(conn->data, "Failed sending HTTP2 data"); return NGHTTP2_ERR_CALLBACK_FAILURE; } if(!written) return NGHTTP2_ERR_WOULDBLOCK; return written; } /* We pass a pointer to this struct in the push callback, but the contents of the struct are hidden from the user. */ struct curl_pushheaders { struct Curl_easy *data; const nghttp2_push_promise *frame; }; /* * push header access function. Only to be used from within the push callback */ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) { /* Verify that we got a good easy handle in the push header struct, mostly to detect rubbish input fast(er). */ if(!h || !GOOD_EASY_HANDLE(h->data)) return NULL; else { struct HTTP *stream = h->data->req.protop; if(num < stream->push_headers_used) return stream->push_headers[num]; } return NULL; } /* * push header access function. Only to be used from within the push callback */ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) { /* Verify that we got a good easy handle in the push header struct, mostly to detect rubbish input fast(er). Also empty header name is just a rubbish too. We have to allow ":" at the beginning of the header, but header == ":" must be rejected. If we have ':' in the middle of header, it could be matched in middle of the value, this is because we do prefix match.*/ if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || !strcmp(header, ":") || strchr(header + 1, ':')) return NULL; else { struct HTTP *stream = h->data->req.protop; size_t len = strlen(header); size_t i; for(i = 0; ipush_headers_used; i++) { if(!strncmp(header, stream->push_headers[i], len)) { /* sub-match, make sure that it is followed by a colon */ if(stream->push_headers[i][len] != ':') continue; return &stream->push_headers[i][len + 1]; } } } return NULL; } /* * This specific transfer on this connection has been "drained". */ static void drained_transfer(struct Curl_easy *data, struct http_conn *httpc) { DEBUGASSERT(httpc->drain_total >= data->state.drain); httpc->drain_total -= data->state.drain; data->state.drain = 0; } /* * Mark this transfer to get "drained". */ static void drain_this(struct Curl_easy *data, struct http_conn *httpc) { data->state.drain++; httpc->drain_total++; DEBUGASSERT(httpc->drain_total >= data->state.drain); } static struct Curl_easy *duphandle(struct Curl_easy *data) { struct Curl_easy *second = curl_easy_duphandle(data); if(second) { /* setup the request struct */ struct HTTP *http = calloc(1, sizeof(struct HTTP)); if(!http) { (void)Curl_close(&second); } else { second->req.protop = http; http->header_recvbuf = Curl_add_buffer_init(); if(!http->header_recvbuf) { free(http); (void)Curl_close(&second); } else { Curl_http2_setup_req(second); second->state.stream_weight = data->state.stream_weight; } } } return second; } static int push_promise(struct Curl_easy *data, struct connectdata *conn, const nghttp2_push_promise *frame) { int rv; H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", frame->promised_stream_id)); if(data->multi->push_cb) { struct HTTP *stream; struct HTTP *newstream; struct curl_pushheaders heads; CURLMcode rc; struct http_conn *httpc; size_t i; /* clone the parent */ struct Curl_easy *newhandle = duphandle(data); if(!newhandle) { infof(data, "failed to duplicate handle\n"); rv = 1; /* FAIL HARD */ goto fail; } heads.data = data; heads.frame = frame; /* ask the application */ H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); stream = data->req.protop; if(!stream) { failf(data, "Internal NULL stream!\n"); (void)Curl_close(&newhandle); rv = 1; goto fail; } Curl_set_in_callback(data, true); rv = data->multi->push_cb(data, newhandle, stream->push_headers_used, &heads, data->multi->push_userp); Curl_set_in_callback(data, false); /* free the headers again */ for(i = 0; ipush_headers_used; i++) free(stream->push_headers[i]); free(stream->push_headers); stream->push_headers = NULL; stream->push_headers_used = 0; if(rv) { /* denied, kill off the new handle again */ http2_stream_free(newhandle->req.protop); newhandle->req.protop = NULL; (void)Curl_close(&newhandle); goto fail; } newstream = newhandle->req.protop; newstream->stream_id = frame->promised_stream_id; newhandle->req.maxdownload = -1; newhandle->req.size = -1; /* approved, add to the multi handle and immediately switch to PERFORM state with the given connection !*/ rc = Curl_multi_add_perform(data->multi, newhandle, conn); if(rc) { infof(data, "failed to add handle to multi\n"); http2_stream_free(newhandle->req.protop); newhandle->req.protop = NULL; Curl_close(&newhandle); rv = 1; goto fail; } httpc = &conn->proto.httpc; rv = nghttp2_session_set_stream_user_data(httpc->h2, frame->promised_stream_id, newhandle); if(rv) { infof(data, "failed to set user_data for stream %d\n", frame->promised_stream_id); DEBUGASSERT(0); goto fail; } } else { H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); rv = 1; } fail: return rv; } /* * multi_connchanged() is called to tell that there is a connection in * this multi handle that has changed state (multiplexing become possible, the * number of allowed streams changed or similar), and a subsequent use of this * multi handle should move CONNECT_PEND handles back to CONNECT to have them * retry. */ static void multi_connchanged(struct Curl_multi *multi) { multi->recheckstate = TRUE; } static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct connectdata *conn = (struct connectdata *)userp; struct http_conn *httpc = &conn->proto.httpc; struct Curl_easy *data_s = NULL; struct HTTP *stream = NULL; int rv; size_t left, ncopy; int32_t stream_id = frame->hd.stream_id; CURLcode result; if(!stream_id) { /* stream ID zero is for connection-oriented stuff */ if(frame->hd.type == NGHTTP2_SETTINGS) { uint32_t max_conn = httpc->settings.max_concurrent_streams; H2BUGF(infof(conn->data, "Got SETTINGS\n")); httpc->settings.max_concurrent_streams = nghttp2_session_get_remote_settings( session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); httpc->settings.enable_push = nghttp2_session_get_remote_settings( session, NGHTTP2_SETTINGS_ENABLE_PUSH); H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", httpc->settings.max_concurrent_streams)); H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n", httpc->settings.enable_push?"TRUE":"false")); if(max_conn != httpc->settings.max_concurrent_streams) { /* only signal change if the value actually changed */ infof(conn->data, "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n", httpc->settings.max_concurrent_streams); multi_connchanged(conn->data->multi); } } return 0; } data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) { H2BUGF(infof(conn->data, "No Curl_easy associated with stream: %x\n", stream_id)); return 0; } stream = data_s->req.protop; if(!stream) { H2BUGF(infof(data_s, "No proto pointer for stream: %x\n", stream_id)); return NGHTTP2_ERR_CALLBACK_FAILURE; } H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", frame->hd.type, stream_id)); switch(frame->hd.type) { case NGHTTP2_DATA: /* If body started on this stream, then receiving DATA is illegal. */ if(!stream->bodystarted) { rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_PROTOCOL_ERROR); if(nghttp2_is_fatal(rv)) { return NGHTTP2_ERR_CALLBACK_FAILURE; } } break; case NGHTTP2_HEADERS: if(stream->bodystarted) { /* Only valid HEADERS after body started is trailer HEADERS. We buffer them in on_header callback. */ break; } /* nghttp2 guarantees that :status is received, and we store it to stream->status_code. Fuzzing has proven this can still be reached without status code having been set. */ if(stream->status_code == -1) return NGHTTP2_ERR_CALLBACK_FAILURE; /* Only final status code signals the end of header */ if(stream->status_code / 100 != 1) { stream->bodystarted = TRUE; stream->status_code = -1; } result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; ncopy = CURLMIN(stream->len, left); memcpy(&stream->mem[stream->memlen], stream->header_recvbuf->buffer + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n", ncopy, stream_id, stream->mem)); stream->len -= ncopy; stream->memlen += ncopy; drain_this(data_s, httpc); { /* get the pointer from userp again since it was re-assigned above */ struct connectdata *conn_s = (struct connectdata *)userp; /* if we receive data for another handle, wake that up */ if(conn_s->data != data_s) Curl_expire(data_s, 0, EXPIRE_RUN_NOW); } break; case NGHTTP2_PUSH_PROMISE: rv = push_promise(data_s, conn, &frame->push_promise); if(rv) { /* deny! */ rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); if(nghttp2_is_fatal(rv)) { return rv; } } break; default: H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n", frame->hd.type, stream_id)); break; } return 0; } static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *data, size_t len, void *userp) { struct HTTP *stream; struct Curl_easy *data_s; size_t nread; struct connectdata *conn = (struct connectdata *)userp; (void)session; (void)flags; (void)data; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ /* get the stream from the hash based on Stream ID */ data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) /* Receiving a Stream ID not in the hash should not happen, this is an internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; nread = CURLMIN(stream->len, len); memcpy(&stream->mem[stream->memlen], data, nread); stream->len -= nread; stream->memlen += nread; drain_this(data_s, &conn->proto.httpc); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) Curl_expire(data_s, 0, EXPIRE_RUN_NOW); H2BUGF(infof(data_s, "%zu data received for stream %u " "(%zu left in buffer %p, total %zu)\n", nread, stream_id, stream->len, stream->mem, stream->memlen)); if(nread < len) { stream->pausedata = data + nread; stream->pauselen = len - nread; H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer" ", stream %u\n", len - nread, stream_id)); data_s->conn->proto.httpc.pause_stream_id = stream_id; return NGHTTP2_ERR_PAUSE; } /* pause execution of nghttp2 if we received data for another handle in order to process them first. */ if(conn->data != data_s) { data_s->conn->proto.httpc.pause_stream_id = stream_id; return NGHTTP2_ERR_PAUSE; } return 0; } static int on_stream_close(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *userp) { struct Curl_easy *data_s; struct HTTP *stream; struct connectdata *conn = (struct connectdata *)userp; int rv; (void)session; (void)stream_id; if(stream_id) { struct http_conn *httpc; /* get the stream from the hash based on Stream ID, stream ID zero is for connection-oriented stuff */ data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) { /* We could get stream ID not in the hash. For example, if we decided to reject stream (e.g., PUSH_PROMISE). */ return 0; } H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", nghttp2_strerror(error_code), error_code, stream_id)); stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; stream->closed = TRUE; httpc = &conn->proto.httpc; drain_this(data_s, httpc); Curl_expire(data_s, 0, EXPIRE_RUN_NOW); httpc->error_code = error_code; /* remove the entry from the hash as the stream is now gone */ rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); if(rv) { infof(data_s, "http/2: failed to clear user_data for stream %d!\n", stream_id); DEBUGASSERT(0); } if(stream_id == httpc->pause_stream_id) { H2BUGF(infof(data_s, "Stopped the pause stream!\n")); httpc->pause_stream_id = 0; } H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id)); stream->stream_id = 0; /* cleared */ } return 0; } static int on_begin_headers(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct HTTP *stream; struct Curl_easy *data_s = NULL; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); if(!data_s) { return 0; } H2BUGF(infof(data_s, "on_begin_headers() was called\n")); if(frame->hd.type != NGHTTP2_HEADERS) { return 0; } stream = data_s->req.protop; if(!stream || !stream->bodystarted) { return 0; } if(!stream->trailer_recvbuf) { stream->trailer_recvbuf = Curl_add_buffer_init(); if(!stream->trailer_recvbuf) { return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } } return 0; } /* Decode HTTP status code. Returns -1 if no valid status code was decoded. */ static int decode_status_code(const uint8_t *value, size_t len) { int i; int res; if(len != 3) { return -1; } res = 0; for(i = 0; i < 3; ++i) { char c = value[i]; if(c < '0' || c > '9') { return -1; } res *= 10; res += c - '0'; } return res; } /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name, size_t namelen, const uint8_t *value, size_t valuelen, uint8_t flags, void *userp) { struct HTTP *stream; struct Curl_easy *data_s; int32_t stream_id = frame->hd.stream_id; struct connectdata *conn = (struct connectdata *)userp; CURLcode result; (void)flags; DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ /* get the stream from the hash based on Stream ID */ data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) /* Receiving a Stream ID not in the hash should not happen, this is an internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; stream = data_s->req.protop; if(!stream) { failf(data_s, "Internal NULL stream! 5\n"); return NGHTTP2_ERR_CALLBACK_FAILURE; } /* Store received PUSH_PROMISE headers to be used when the subsequent PUSH_PROMISE callback comes */ if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { char *h; if(!strcmp(":authority", (const char *)name)) { /* pseudo headers are lower case */ int rc = 0; char *check = aprintf("%s:%d", conn->host.name, conn->remote_port); if(!check) /* no memory */ return NGHTTP2_ERR_CALLBACK_FAILURE; if(!Curl_strcasecompare(check, (const char *)value) && ((conn->remote_port != conn->given->defport) || !Curl_strcasecompare(conn->host.name, (const char *)value))) { /* This is push is not for the same authority that was asked for in * the URL. RFC 7540 section 8.2 says: "A client MUST treat a * PUSH_PROMISE for which the server is not authoritative as a stream * error of type PROTOCOL_ERROR." */ (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_PROTOCOL_ERROR); rc = NGHTTP2_ERR_CALLBACK_FAILURE; } free(check); if(rc) return rc; } if(!stream->push_headers) { stream->push_headers_alloc = 10; stream->push_headers = malloc(stream->push_headers_alloc * sizeof(char *)); if(!stream->push_headers) return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; stream->push_headers_used = 0; } else if(stream->push_headers_used == stream->push_headers_alloc) { char **headp; stream->push_headers_alloc *= 2; headp = Curl_saferealloc(stream->push_headers, stream->push_headers_alloc * sizeof(char *)); if(!headp) { stream->push_headers = NULL; return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } stream->push_headers = headp; } h = aprintf("%s:%s", name, value); if(h) stream->push_headers[stream->push_headers_used++] = h; return 0; } if(stream->bodystarted) { /* This is trailer fields. */ /* 4 is for ": " and "\r\n". */ uint32_t n = (uint32_t)(namelen + valuelen + 4); H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, value)); result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n)); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; return 0; } if(namelen == sizeof(":status") - 1 && memcmp(":status", name, namelen) == 0) { /* nghttp2 guarantees :status is received first and only once, and value is 3 digits status code, and decode_status_code always succeeds. */ stream->status_code = decode_status_code(value, valuelen); DEBUGASSERT(stream->status_code != -1); result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* the space character after the status code is mandatory */ result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ if(conn->data != data_s) Curl_expire(data_s, 0, EXPIRE_RUN_NOW); H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", stream->status_code, data_s)); return 0; } /* nghttp2 guarantees that namelen > 0, and :status was already received, and this is not pseudo-header field . */ /* convert to a HTTP1-style header */ result = Curl_add_buffer(&stream->header_recvbuf, name, namelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ if(conn->data != data_s) Curl_expire(data_s, 0, EXPIRE_RUN_NOW); H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, value)); return 0; /* 0 is successful */ } static ssize_t data_source_read_callback(nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, uint32_t *data_flags, nghttp2_data_source *source, void *userp) { struct Curl_easy *data_s; struct HTTP *stream = NULL; size_t nread; (void)source; (void)userp; if(stream_id) { /* get the stream from the hash based on Stream ID, stream ID zero is for connection-oriented stuff */ data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) /* Receiving a Stream ID not in the hash should not happen, this is an internal error more than anything else! */ return NGHTTP2_ERR_CALLBACK_FAILURE; stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; } else return NGHTTP2_ERR_INVALID_ARGUMENT; nread = CURLMIN(stream->upload_len, length); if(nread > 0) { memcpy(buf, stream->upload_mem, nread); stream->upload_mem += nread; stream->upload_len -= nread; if(data_s->state.infilesize != -1) stream->upload_left -= nread; } if(stream->upload_left == 0) *data_flags = NGHTTP2_DATA_FLAG_EOF; else if(nread == 0) return NGHTTP2_ERR_DEFERRED; H2BUGF(infof(data_s, "data_source_read_callback: " "returns %zu bytes stream %u\n", nread, stream_id)); return nread; } #if !defined(CURL_DISABLE_VERBOSE_STRINGS) static int error_callback(nghttp2_session *session, const char *msg, size_t len, void *userp) { struct connectdata *conn = (struct connectdata *)userp; (void)session; infof(conn->data, "http2 error: %.*s\n", len, msg); return 0; } #endif static void populate_settings(struct connectdata *conn, struct http_conn *httpc) { nghttp2_settings_entry *iv = httpc->local_settings; DEBUGASSERT(conn->data); iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi); iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = HTTP2_HUGE_WINDOW_SIZE; iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; iv[2].value = conn->data->multi->push_cb != NULL; httpc->local_settings_num = 3; } void Curl_http2_done(struct Curl_easy *data, bool premature) { struct HTTP *http = data->req.protop; struct http_conn *httpc = &data->conn->proto.httpc; /* there might be allocated resources done before this got the 'h2' pointer setup */ if(http->header_recvbuf) { Curl_add_buffer_free(&http->header_recvbuf); Curl_add_buffer_free(&http->trailer_recvbuf); if(http->push_headers) { /* if they weren't used and then freed before */ for(; http->push_headers_used > 0; --http->push_headers_used) { free(http->push_headers[http->push_headers_used - 1]); } free(http->push_headers); http->push_headers = NULL; } } if(!httpc->h2) /* not HTTP/2 ? */ return; if(premature) { /* RST_STREAM */ if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, NGHTTP2_STREAM_CLOSED)) (void)nghttp2_session_send(httpc->h2); if(http->stream_id == httpc->pause_stream_id) { infof(data, "stopped the pause stream!\n"); httpc->pause_stream_id = 0; } } if(data->state.drain) drained_transfer(data, httpc); /* -1 means unassigned and 0 means cleared */ if(http->stream_id > 0) { int rv = nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); if(rv) { infof(data, "http/2: failed to clear user_data for stream %d!\n", http->stream_id); DEBUGASSERT(0); } http->stream_id = 0; } } /* * Initialize nghttp2 for a Curl connection */ static CURLcode http2_init(struct connectdata *conn) { if(!conn->proto.httpc.h2) { int rc; nghttp2_session_callbacks *callbacks; conn->proto.httpc.inbuf = malloc(H2_BUFSIZE); if(conn->proto.httpc.inbuf == NULL) return CURLE_OUT_OF_MEMORY; rc = nghttp2_session_callbacks_new(&callbacks); if(rc) { failf(conn->data, "Couldn't initialize nghttp2 callbacks!"); return CURLE_OUT_OF_MEMORY; /* most likely at least */ } /* nghttp2_send_callback */ nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); /* nghttp2_on_frame_recv_callback */ nghttp2_session_callbacks_set_on_frame_recv_callback (callbacks, on_frame_recv); /* nghttp2_on_data_chunk_recv_callback */ nghttp2_session_callbacks_set_on_data_chunk_recv_callback (callbacks, on_data_chunk_recv); /* nghttp2_on_stream_close_callback */ nghttp2_session_callbacks_set_on_stream_close_callback (callbacks, on_stream_close); /* nghttp2_on_begin_headers_callback */ nghttp2_session_callbacks_set_on_begin_headers_callback (callbacks, on_begin_headers); /* nghttp2_on_header_callback */ nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); /* The nghttp2 session is not yet setup, do it */ rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); nghttp2_session_callbacks_del(callbacks); if(rc) { failf(conn->data, "Couldn't initialize nghttp2!"); return CURLE_OUT_OF_MEMORY; /* most likely at least */ } } return CURLE_OK; } /* * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. */ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, struct connectdata *conn) { CURLcode result; ssize_t binlen; char *base64; size_t blen; struct SingleRequest *k = &conn->data->req; uint8_t *binsettings = conn->proto.httpc.binsettings; struct http_conn *httpc = &conn->proto.httpc; populate_settings(conn, httpc); /* this returns number of bytes it wrote */ binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, httpc->local_settings, httpc->local_settings_num); if(!binlen) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); Curl_add_buffer_free(&req); return CURLE_FAILED_INIT; } conn->proto.httpc.binlen = binlen; result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, &base64, &blen); if(result) { Curl_add_buffer_free(&req); return result; } result = Curl_add_bufferf(&req, "Connection: Upgrade, HTTP2-Settings\r\n" "Upgrade: %s\r\n" "HTTP2-Settings: %s\r\n", NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); free(base64); k->upgr101 = UPGR101_REQUESTED; return result; } /* * Returns nonzero if current HTTP/2 session should be closed. */ static int should_close_session(struct http_conn *httpc) { return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && !nghttp2_session_want_write(httpc->h2); } /* * h2_process_pending_input() processes pending input left in * httpc->inbuf. Then, call h2_session_send() to send pending data. * This function returns 0 if it succeeds, or -1 and error code will * be assigned to *err. */ static int h2_process_pending_input(struct connectdata *conn, struct http_conn *httpc, CURLcode *err) { ssize_t nread; char *inbuf; ssize_t rv; struct Curl_easy *data = conn->data; nread = httpc->inbuflen - httpc->nread_inbuf; inbuf = httpc->inbuf + httpc->nread_inbuf; rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); if(rv < 0) { failf(data, "h2_process_pending_input: nghttp2_session_mem_recv() returned " "%zd:%s\n", rv, nghttp2_strerror((int)rv)); *err = CURLE_RECV_ERROR; return -1; } if(nread == rv) { H2BUGF(infof(data, "h2_process_pending_input: All data in connection buffer " "processed\n")); httpc->inbuflen = 0; httpc->nread_inbuf = 0; } else { httpc->nread_inbuf += rv; H2BUGF(infof(data, "h2_process_pending_input: %zu bytes left in connection " "buffer\n", httpc->inbuflen - httpc->nread_inbuf)); } rv = h2_session_send(data, httpc->h2); if(rv != 0) { *err = CURLE_SEND_ERROR; return -1; } if(should_close_session(httpc)) { H2BUGF(infof(data, "h2_process_pending_input: nothing to do in this session\n")); if(httpc->error_code) *err = CURLE_HTTP2; else { /* not an error per se, but should still close the connection */ connclose(conn, "GOAWAY received"); *err = CURLE_OK; } return -1; } return 0; } /* * Called from transfer.c:done_sending when we stop uploading. */ CURLcode Curl_http2_done_sending(struct connectdata *conn) { CURLcode result = CURLE_OK; if((conn->handler == &Curl_handler_http2_ssl) || (conn->handler == &Curl_handler_http2)) { /* make sure this is only attempted for HTTP/2 transfers */ struct HTTP *stream = conn->data->req.protop; if(stream->upload_left) { /* If the stream still thinks there's data left to upload. */ struct http_conn *httpc = &conn->proto.httpc; nghttp2_session *h2 = httpc->h2; stream->upload_left = 0; /* DONE! */ /* resume sending here to trigger the callback to get called again so that it can signal EOF to nghttp2 */ (void)nghttp2_session_resume_data(h2, stream->stream_id); (void)h2_process_pending_input(conn, httpc, &result); } } return result; } static ssize_t http2_handle_stream_close(struct connectdata *conn, struct Curl_easy *data, struct HTTP *stream, CURLcode *err) { char *trailer_pos, *trailer_end; CURLcode result; struct http_conn *httpc = &conn->proto.httpc; if(httpc->pause_stream_id == stream->stream_id) { httpc->pause_stream_id = 0; } drained_transfer(data, httpc); if(httpc->pause_stream_id == 0) { if(h2_process_pending_input(conn, httpc, err) != 0) { return -1; } } DEBUGASSERT(data->state.drain == 0); /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(httpc->error_code == NGHTTP2_REFUSED_STREAM) { H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n", stream->stream_id)); connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */ data->state.refused_stream = TRUE; *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ return -1; } else if(httpc->error_code != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)", stream->stream_id, nghttp2_strerror(httpc->error_code), httpc->error_code); *err = CURLE_HTTP2_STREAM; return -1; } if(!stream->bodystarted) { failf(data, "HTTP/2 stream %d was closed cleanly, but before getting " " all response header fields, treated as error", stream->stream_id); *err = CURLE_HTTP2_STREAM; return -1; } if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { trailer_pos = stream->trailer_recvbuf->buffer; trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; for(; trailer_pos < trailer_end;) { uint32_t n; memcpy(&n, trailer_pos, sizeof(n)); trailer_pos += sizeof(n); result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); if(result) { *err = result; return -1; } trailer_pos += n + 1; } } stream->close_handled = TRUE; H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); return 0; } /* * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight * and dependency to the peer. It also stores the updated values in the state * struct. */ static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { struct HTTP *depstream = (data->set.stream_depends_on? data->set.stream_depends_on->req.protop:NULL); int32_t depstream_id = depstream? depstream->stream_id:0; nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, data->set.stream_depends_e); data->state.stream_weight = data->set.stream_weight; data->state.stream_depends_e = data->set.stream_depends_e; data->state.stream_depends_on = data->set.stream_depends_on; } /* * h2_session_send() checks if there's been an update in the priority / * dependency settings and if so it submits a PRIORITY frame with the updated * info. */ static int h2_session_send(struct Curl_easy *data, nghttp2_session *h2) { struct HTTP *stream = data->req.protop; if((data->set.stream_weight != data->state.stream_weight) || (data->set.stream_depends_e != data->state.stream_depends_e) || (data->set.stream_depends_on != data->state.stream_depends_on) ) { /* send new weight and/or dependency */ nghttp2_priority_spec pri_spec; int rv; h2_pri_spec(data, &pri_spec); H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n", stream->stream_id, data)); DEBUGASSERT(stream->stream_id != -1); rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id, &pri_spec); if(rv) return rv; } return nghttp2_session_send(h2); } static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { CURLcode result = CURLE_OK; ssize_t rv; ssize_t nread; struct http_conn *httpc = &conn->proto.httpc; struct Curl_easy *data = conn->data; struct HTTP *stream = data->req.protop; (void)sockindex; /* we always do HTTP2 on sockindex 0 */ if(should_close_session(httpc)) { H2BUGF(infof(data, "http2_recv: nothing to do in this session\n")); if(conn->bits.close) { /* already marked for closure, return OK and we're done */ *err = CURLE_OK; return 0; } *err = CURLE_HTTP2; return -1; } /* Nullify here because we call nghttp2_session_send() and they might refer to the old buffer. */ stream->upload_mem = NULL; stream->upload_len = 0; /* * At this point 'stream' is just in the Curl_easy the connection * identifies as its owner at this time. */ if(stream->bodystarted && stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { /* If there is body data pending for this stream to return, do that */ size_t left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; size_t ncopy = CURLMIN(len, left); memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", (int)ncopy)); return ncopy; } H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n", data, stream->stream_id, nghttp2_session_get_local_window_size(httpc->h2), nghttp2_session_get_stream_local_window_size(httpc->h2, stream->stream_id) )); if((data->state.drain) && stream->memlen) { H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", stream->memlen, stream->stream_id, stream->mem, mem)); if(mem != stream->mem) { /* if we didn't get the same buffer this time, we must move the data to the beginning */ memmove(mem, stream->mem, stream->memlen); stream->len = len - stream->memlen; stream->mem = mem; } if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) { /* We have paused nghttp2, but we have no pause data (see on_data_chunk_recv). */ httpc->pause_stream_id = 0; if(h2_process_pending_input(conn, httpc, &result) != 0) { *err = result; return -1; } } } else if(stream->pausedata) { DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); nread = CURLMIN(len, stream->pauselen); memcpy(mem, stream->pausedata, nread); stream->pausedata += nread; stream->pauselen -= nread; if(stream->pauselen == 0) { H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); httpc->pause_stream_id = 0; stream->pausedata = NULL; stream->pauselen = 0; /* When NGHTTP2_ERR_PAUSE is returned from data_source_read_callback, we might not process DATA frame fully. Calling nghttp2_session_mem_recv() again will continue to process DATA frame, but if there is no incoming frames, then we have to call it again with 0-length data. Without this, on_stream_close callback will not be called, and stream could be hanged. */ if(h2_process_pending_input(conn, httpc, &result) != 0) { *err = result; return -1; } } H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", nread, stream->stream_id)); return nread; } else if(httpc->pause_stream_id) { /* If a stream paused nghttp2_session_mem_recv previously, and has not processed all data, it still refers to the buffer in nghttp2_session. If we call nghttp2_session_mem_recv(), we may overwrite that buffer. To avoid that situation, just return here with CURLE_AGAIN. This could be busy loop since data in socket is not read. But it seems that usually streams are notified with its drain property, and socket is read again quickly. */ if(stream->closed) /* closed overrides paused */ return 0; H2BUGF(infof(data, "stream %x is paused, pause id: %x\n", stream->stream_id, httpc->pause_stream_id)); *err = CURLE_AGAIN; return -1; } else { char *inbuf; /* remember where to store incoming data for this stream and how big the buffer is */ stream->mem = mem; stream->len = len; stream->memlen = 0; if(httpc->inbuflen == 0) { nread = ((Curl_recv *)httpc->recv_underlying)( conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); if(nread == -1) { if(result != CURLE_AGAIN) failf(data, "Failed receiving HTTP2 data"); else if(stream->closed) /* received when the stream was already closed! */ return http2_handle_stream_close(conn, data, stream, err); *err = result; return -1; } if(nread == 0) { H2BUGF(infof(data, "end of stream\n")); *err = CURLE_OK; return 0; } H2BUGF(infof(data, "nread=%zd\n", nread)); httpc->inbuflen = nread; inbuf = httpc->inbuf; } else { nread = httpc->inbuflen - httpc->nread_inbuf; inbuf = httpc->inbuf + httpc->nread_inbuf; H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", nread)); } rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); if(nghttp2_is_fatal((int)rv)) { failf(data, "nghttp2_session_mem_recv() returned %zd:%s\n", rv, nghttp2_strerror((int)rv)); *err = CURLE_RECV_ERROR; return -1; } H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); if(nread == rv) { H2BUGF(infof(data, "All data in connection buffer processed\n")); httpc->inbuflen = 0; httpc->nread_inbuf = 0; } else { httpc->nread_inbuf += rv; H2BUGF(infof(data, "%zu bytes left in connection buffer\n", httpc->inbuflen - httpc->nread_inbuf)); } /* Always send pending frames in nghttp2 session, because nghttp2_session_mem_recv() may queue new frame */ rv = h2_session_send(data, httpc->h2); if(rv != 0) { *err = CURLE_SEND_ERROR; return -1; } if(should_close_session(httpc)) { H2BUGF(infof(data, "http2_recv: nothing to do in this session\n")); *err = CURLE_HTTP2; return -1; } } if(stream->memlen) { ssize_t retlen = stream->memlen; H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n", retlen, stream->stream_id)); stream->memlen = 0; if(httpc->pause_stream_id == stream->stream_id) { /* data for this stream is returned now, but this stream caused a pause already so we need it called again asap */ H2BUGF(infof(data, "Data returned for PAUSED stream %u\n", stream->stream_id)); } else if(!stream->closed) { drained_transfer(data, httpc); } else /* this stream is closed, trigger a another read ASAP to detect that */ Curl_expire(data, 0, EXPIRE_RUN_NOW); return retlen; } /* If this stream is closed, return 0 to signal the http routine to close the connection */ if(stream->closed) return 0; *err = CURLE_AGAIN; H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", stream->stream_id)); return -1; } /* Index where :authority header field will appear in request header field list. */ #define AUTHORITY_DST_IDX 3 /* USHRT_MAX is 65535 == 0xffff */ #define HEADER_OVERFLOW(x) \ (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen) /* * Check header memory for the token "trailers". * Parse the tokens as separated by comma and surrounded by whitespace. * Returns TRUE if found or FALSE if not. */ static bool contains_trailers(const char *p, size_t len) { const char *end = p + len; for(;;) { for(; p != end && (*p == ' ' || *p == '\t'); ++p) ; if(p == end || (size_t)(end - p) < sizeof("trailers") - 1) return FALSE; if(strncasecompare("trailers", p, sizeof("trailers") - 1)) { p += sizeof("trailers") - 1; for(; p != end && (*p == ' ' || *p == '\t'); ++p) ; if(p == end || *p == ',') return TRUE; } /* skip to next token */ for(; p != end && *p != ','; ++p) ; if(p == end) return FALSE; ++p; } } typedef enum { /* Send header to server */ HEADERINST_FORWARD, /* Don't send header to server */ HEADERINST_IGNORE, /* Discard header, and replace it with "te: trailers" */ HEADERINST_TE_TRAILERS } header_instruction; /* Decides how to treat given header field. */ static header_instruction inspect_header(const char *name, size_t namelen, const char *value, size_t valuelen) { switch(namelen) { case 2: if(!strncasecompare("te", name, namelen)) return HEADERINST_FORWARD; return contains_trailers(value, valuelen) ? HEADERINST_TE_TRAILERS : HEADERINST_IGNORE; case 7: return strncasecompare("upgrade", name, namelen) ? HEADERINST_IGNORE : HEADERINST_FORWARD; case 10: return (strncasecompare("connection", name, namelen) || strncasecompare("keep-alive", name, namelen)) ? HEADERINST_IGNORE : HEADERINST_FORWARD; case 16: return strncasecompare("proxy-connection", name, namelen) ? HEADERINST_IGNORE : HEADERINST_FORWARD; case 17: return strncasecompare("transfer-encoding", name, namelen) ? HEADERINST_IGNORE : HEADERINST_FORWARD; default: return HEADERINST_FORWARD; } } static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { /* * Currently, we send request in this function, but this function is also * used to send request body. It would be nice to add dedicated function for * request. */ int rv; struct http_conn *httpc = &conn->proto.httpc; struct HTTP *stream = conn->data->req.protop; nghttp2_nv *nva = NULL; size_t nheader; size_t i; size_t authority_idx; char *hdbuf = (char *)mem; char *end, *line_end; nghttp2_data_provider data_prd; int32_t stream_id; nghttp2_session *h2 = httpc->h2; nghttp2_priority_spec pri_spec; (void)sockindex; H2BUGF(infof(conn->data, "http2_send len=%zu\n", len)); if(stream->stream_id != -1) { if(stream->close_handled) { infof(conn->data, "stream %d closed\n", stream->stream_id); *err = CURLE_HTTP2_STREAM; return -1; } else if(stream->closed) { return http2_handle_stream_close(conn, conn->data, stream, err); } /* If stream_id != -1, we have dispatched request HEADERS, and now are going to send or sending request body in DATA frame */ stream->upload_mem = mem; stream->upload_len = len; rv = nghttp2_session_resume_data(h2, stream->stream_id); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; return -1; } rv = h2_session_send(conn->data, h2); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; return -1; } len -= stream->upload_len; /* Nullify here because we call nghttp2_session_send() and they might refer to the old buffer. */ stream->upload_mem = NULL; stream->upload_len = 0; if(should_close_session(httpc)) { H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); *err = CURLE_HTTP2; return -1; } if(stream->upload_left) { /* we are sure that we have more data to send here. Calling the following API will make nghttp2_session_want_write() return nonzero if remote window allows it, which then libcurl checks socket is writable or not. See http2_perform_getsock(). */ nghttp2_session_resume_data(h2, stream->stream_id); } H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len, stream->stream_id)); return len; } /* Calculate number of headers contained in [mem, mem + len) */ /* Here, we assume the curl http code generate *correct* HTTP header field block */ nheader = 0; for(i = 1; i < len; ++i) { if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { ++nheader; ++i; } } if(nheader < 2) goto fail; /* We counted additional 2 \r\n in the first and last line. We need 3 new headers: :method, :path and :scheme. Therefore we need one more space. */ nheader += 1; nva = malloc(sizeof(nghttp2_nv) * nheader); if(nva == NULL) { *err = CURLE_OUT_OF_MEMORY; return -1; } /* Extract :method, :path from request line We do line endings with CRLF so checking for CR is enough */ line_end = memchr(hdbuf, '\r', len); if(!line_end) goto fail; /* Method does not contain spaces */ end = memchr(hdbuf, ' ', line_end - hdbuf); if(!end || end == hdbuf) goto fail; nva[0].name = (unsigned char *)":method"; nva[0].namelen = strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; nva[0].valuelen = (size_t)(end - hdbuf); nva[0].flags = NGHTTP2_NV_FLAG_NONE; if(HEADER_OVERFLOW(nva[0])) { failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } hdbuf = end + 1; /* Path may contain spaces so scan backwards */ end = NULL; for(i = (size_t)(line_end - hdbuf); i; --i) { if(hdbuf[i - 1] == ' ') { end = &hdbuf[i - 1]; break; } } if(!end || end == hdbuf) goto fail; nva[1].name = (unsigned char *)":path"; nva[1].namelen = strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; nva[1].valuelen = (size_t)(end - hdbuf); nva[1].flags = NGHTTP2_NV_FLAG_NONE; if(HEADER_OVERFLOW(nva[1])) { failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } nva[2].name = (unsigned char *)":scheme"; nva[2].namelen = strlen((char *)nva[2].name); if(conn->handler->flags & PROTOPT_SSL) nva[2].value = (unsigned char *)"https"; else nva[2].value = (unsigned char *)"http"; nva[2].valuelen = strlen((char *)nva[2].value); nva[2].flags = NGHTTP2_NV_FLAG_NONE; if(HEADER_OVERFLOW(nva[2])) { failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } authority_idx = 0; i = 3; while(i < nheader) { size_t hlen; hdbuf = line_end + 2; /* check for next CR, but only within the piece of data left in the given buffer */ line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem)); if(!line_end || (line_end == hdbuf)) goto fail; /* header continuation lines are not supported */ if(*hdbuf == ' ' || *hdbuf == '\t') goto fail; for(end = hdbuf; end < line_end && *end != ':'; ++end) ; if(end == hdbuf || end == line_end) goto fail; hlen = end - hdbuf; if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].namelen = strlen((char *)nva[i].name); } else { nva[i].namelen = (size_t)(end - hdbuf); /* Lower case the header name for HTTP/2 */ Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen); nva[i].name = (unsigned char *)hdbuf; } hdbuf = end + 1; while(*hdbuf == ' ' || *hdbuf == '\t') ++hdbuf; end = line_end; switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, end - hdbuf)) { case HEADERINST_IGNORE: /* skip header fields prohibited by HTTP/2 specification. */ --nheader; continue; case HEADERINST_TE_TRAILERS: nva[i].value = (uint8_t*)"trailers"; nva[i].valuelen = sizeof("trailers") - 1; break; default: nva[i].value = (unsigned char *)hdbuf; nva[i].valuelen = (size_t)(end - hdbuf); } nva[i].flags = NGHTTP2_NV_FLAG_NONE; if(HEADER_OVERFLOW(nva[i])) { failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } ++i; } /* :authority must come before non-pseudo header fields */ if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { nghttp2_nv authority = nva[authority_idx]; for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { nva[i] = nva[i - 1]; } nva[i] = authority; } /* Warn stream may be rejected if cumulative length of headers is too large. It appears nghttp2 will not send a header frame larger than 64KB. */ #define MAX_ACC 60000 /* <64KB to account for some overhead */ { size_t acc = 0; for(i = 0; i < nheader; ++i) { acc += nva[i].namelen + nva[i].valuelen; H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", nva[i].namelen, nva[i].name, nva[i].valuelen, nva[i].value)); } if(acc > MAX_ACC) { infof(conn->data, "http2_send: Warning: The cumulative length of all " "headers exceeds %zu bytes and that could cause the " "stream to be rejected.\n", MAX_ACC); } } h2_pri_spec(conn->data, &pri_spec); switch(conn->data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: case HTTPREQ_PUT: if(conn->data->state.infilesize != -1) stream->upload_left = conn->data->state.infilesize; else /* data sending without specifying the data amount up front */ stream->upload_left = -1; /* unknown, but not zero */ data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, &data_prd, conn->data); break; default: stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, NULL, conn->data); } Curl_safefree(nva); if(stream_id < 0) { H2BUGF(infof(conn->data, "http2_send() send error\n")); *err = CURLE_SEND_ERROR; return -1; } infof(conn->data, "Using Stream ID: %x (easy handle %p)\n", stream_id, (void *)conn->data); stream->stream_id = stream_id; /* this does not call h2_session_send() since there can not have been any * priority upodate since the nghttp2_submit_request() call above */ rv = nghttp2_session_send(h2); if(rv != 0) { *err = CURLE_SEND_ERROR; return -1; } if(should_close_session(httpc)) { H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); *err = CURLE_HTTP2; return -1; } /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2 library calls data_source_read_callback. But only it found that no data available, so it deferred the DATA transmission. Which means that nghttp2_session_want_write() returns 0 on http2_perform_getsock(), which results that no writable socket check is performed. To workaround this, we issue nghttp2_session_resume_data() here to bring back DATA transmission from deferred state. */ nghttp2_session_resume_data(h2, stream->stream_id); return len; fail: free(nva); *err = CURLE_SEND_ERROR; return -1; } CURLcode Curl_http2_setup(struct connectdata *conn) { CURLcode result; struct http_conn *httpc = &conn->proto.httpc; struct HTTP *stream = conn->data->req.protop; stream->stream_id = -1; if(!stream->header_recvbuf) { stream->header_recvbuf = Curl_add_buffer_init(); if(!stream->header_recvbuf) return CURLE_OUT_OF_MEMORY; } if((conn->handler == &Curl_handler_http2_ssl) || (conn->handler == &Curl_handler_http2)) return CURLE_OK; /* already done */ if(conn->handler->flags & PROTOPT_SSL) conn->handler = &Curl_handler_http2_ssl; else conn->handler = &Curl_handler_http2; result = http2_init(conn); if(result) { Curl_add_buffer_free(&stream->header_recvbuf); return result; } infof(conn->data, "Using HTTP2, server supports multi-use\n"); stream->upload_left = 0; stream->upload_mem = NULL; stream->upload_len = 0; httpc->inbuflen = 0; httpc->nread_inbuf = 0; httpc->pause_stream_id = 0; httpc->drain_total = 0; conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 20; conn->bundle->multiuse = BUNDLE_MULTIPLEX; infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); multi_connchanged(conn->data->multi); return CURLE_OK; } CURLcode Curl_http2_switched(struct connectdata *conn, const char *mem, size_t nread) { CURLcode result; struct http_conn *httpc = &conn->proto.httpc; int rv; ssize_t nproc; struct Curl_easy *data = conn->data; struct HTTP *stream = conn->data->req.protop; result = Curl_http2_setup(conn); if(result) return result; httpc->recv_underlying = conn->recv[FIRSTSOCKET]; httpc->send_underlying = conn->send[FIRSTSOCKET]; conn->recv[FIRSTSOCKET] = http2_recv; conn->send[FIRSTSOCKET] = http2_send; if(conn->data->req.upgr101 == UPGR101_RECEIVED) { /* stream 1 is opened implicitly on upgrade */ stream->stream_id = 1; /* queue SETTINGS frame (again) */ rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, httpc->binlen, NULL); if(rv != 0) { failf(data, "nghttp2_session_upgrade() failed: %s(%d)", nghttp2_strerror(rv), rv); return CURLE_HTTP2; } rv = nghttp2_session_set_stream_user_data(httpc->h2, stream->stream_id, data); if(rv) { infof(data, "http/2: failed to set user_data for stream %d!\n", stream->stream_id); DEBUGASSERT(0); } } else { populate_settings(conn, httpc); /* stream ID is unknown at this point */ stream->stream_id = -1; rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, httpc->local_settings, httpc->local_settings_num); if(rv != 0) { failf(data, "nghttp2_submit_settings() failed: %s(%d)", nghttp2_strerror(rv), rv); return CURLE_HTTP2; } } rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0, HTTP2_HUGE_WINDOW_SIZE); if(rv != 0) { failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", nghttp2_strerror(rv), rv); return CURLE_HTTP2; } /* we are going to copy mem to httpc->inbuf. This is required since mem is part of buffer pointed by stream->mem, and callbacks called by nghttp2_session_mem_recv() will write stream specific data into stream->mem, overwriting data already there. */ if(H2_BUFSIZE < nread) { failf(data, "connection buffer size is too small to store data following " "HTTP Upgrade response header: buflen=%zu, datalen=%zu", H2_BUFSIZE, nread); return CURLE_HTTP2; } infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer" " after upgrade: len=%zu\n", nread); if(nread) memcpy(httpc->inbuf, mem, nread); httpc->inbuflen = nread; nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, httpc->inbuflen); if(nghttp2_is_fatal((int)nproc)) { failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", nghttp2_strerror((int)nproc), (int)nproc); return CURLE_HTTP2; } H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); if((ssize_t)nread == nproc) { httpc->inbuflen = 0; httpc->nread_inbuf = 0; } else { httpc->nread_inbuf += nproc; } /* Try to send some frames since we may read SETTINGS already. */ rv = h2_session_send(data, httpc->h2); if(rv != 0) { failf(data, "nghttp2_session_send() failed: %s(%d)", nghttp2_strerror(rv), rv); return CURLE_HTTP2; } if(should_close_session(httpc)) { H2BUGF(infof(data, "nghttp2_session_send(): nothing to do in this session\n")); return CURLE_HTTP2; } return CURLE_OK; } CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause) { DEBUGASSERT(data); DEBUGASSERT(data->conn); /* if it isn't HTTP/2, we're done */ if(!data->conn->proto.httpc.h2) return CURLE_OK; #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE else { struct HTTP *stream = data->req.protop; struct http_conn *httpc = &data->conn->proto.httpc; uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE; int rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, stream->stream_id, window); if(rv) { failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", nghttp2_strerror(rv), rv); return CURLE_HTTP2; } /* make sure the window update gets sent */ rv = h2_session_send(data, httpc->h2); if(rv) return CURLE_SEND_ERROR; DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n", window, stream->stream_id)); #ifdef DEBUGBUILD { /* read out the stream local window again */ uint32_t window2 = nghttp2_session_get_stream_local_window_size(httpc->h2, stream->stream_id); DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n", window2, stream->stream_id)); } #endif } #endif return CURLE_OK; } CURLcode Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, bool exclusive) { if(parent) { struct Curl_http2_dep **tail; struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep)); if(!dep) return CURLE_OUT_OF_MEMORY; dep->data = child; if(parent->set.stream_dependents && exclusive) { struct Curl_http2_dep *node = parent->set.stream_dependents; while(node) { node->data->set.stream_depends_on = child; node = node->next; } tail = &child->set.stream_dependents; while(*tail) tail = &(*tail)->next; DEBUGASSERT(!*tail); *tail = parent->set.stream_dependents; parent->set.stream_dependents = 0; } tail = &parent->set.stream_dependents; while(*tail) { (*tail)->data->set.stream_depends_e = FALSE; tail = &(*tail)->next; } DEBUGASSERT(!*tail); *tail = dep; } child->set.stream_depends_on = parent; child->set.stream_depends_e = exclusive; return CURLE_OK; } void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child) { struct Curl_http2_dep *last = 0; struct Curl_http2_dep *data = parent->set.stream_dependents; DEBUGASSERT(child->set.stream_depends_on == parent); while(data && data->data != child) { last = data; data = data->next; } DEBUGASSERT(data); if(data) { if(last) { last->next = data->next; } else { parent->set.stream_dependents = data->next; } free(data); } child->set.stream_depends_on = 0; child->set.stream_depends_e = FALSE; } void Curl_http2_cleanup_dependencies(struct Curl_easy *data) { while(data->set.stream_dependents) { struct Curl_easy *tmp = data->set.stream_dependents->data; Curl_http2_remove_child(data, tmp); if(data->set.stream_depends_on) Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE); } if(data->set.stream_depends_on) Curl_http2_remove_child(data->set.stream_depends_on, data); } /* Only call this function for a transfer that already got a HTTP/2 CURLE_HTTP2_STREAM error! */ bool Curl_h2_http_1_1_error(struct connectdata *conn) { struct http_conn *httpc = &conn->proto.httpc; return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED); } #else /* !USE_NGHTTP2 */ /* Satisfy external references even if http2 is not compiled in. */ #include char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) { (void) h; (void) num; return NULL; } char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) { (void) h; (void) header; return NULL; } #endif /* USE_NGHTTP2 */ davix-0.8.0/deps/curl/lib/rename.h0000644000000000000000000000222414121063461015414 0ustar rootroot#ifndef HEADER_CURL_RENAME_H #define HEADER_CURL_RENAME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ int Curl_rename(const char *oldpath, const char *newpath); #endif /* HEADER_CURL_RENAME_H */ davix-0.8.0/deps/curl/lib/Makefile.am0000644000000000000000000001242414121063461016033 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### AUTOMAKE_OPTIONS = foreign nostdinc CMAKE_DIST = CMakeLists.txt curl_config.h.cmake EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h \ config-plan9.h config-riscos.h config-mac.h curl_config.h.in \ makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \ makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \ config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \ config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl lib_LTLIBRARIES = libcurl.la if BUILD_UNITTESTS noinst_LTLIBRARIES = libcurlu.la else noinst_LTLIBRARIES = endif # This might hold -Werror CFLAGS += @CURL_CFLAG_EXTRAS@ # Specify our include paths here, and do it relative to $(top_srcdir) and # $(top_builddir), to ensure that these paths which belong to the library # being currently built and tested are searched before the library which # might possibly already be installed in the system. # # $(top_srcdir)/include is for libcurl's external include files # $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file # $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files # $(top_builddir)/ares is for in-tree c-ares's generated ares_build.h file # $(top_srcdir)/ares is for in-tree c-ares's external include files AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_builddir)/lib \ -I$(top_srcdir)/lib if USE_EMBEDDED_ARES AM_CPPFLAGS += -I$(top_builddir)/ares \ -I$(top_srcdir)/ares endif # Prevent LIBS from being used for all link targets LIBS = $(BLANK_AT_MAKETIME) VERSIONINFO=-version-info 10:0:6 # This flag accepts an argument of the form current[:revision[:age]]. So, # passing -version-info 3:12:1 sets current to 3, revision to 12, and age to # 1. # # Here's the simplified rule guide on how to change -version-info: # (current version is C:R:A) # # 1. if there are only source changes, use C:R+1:A # 2. if interfaces were added use C+1:0:A+1 # 3. if interfaces were removed, then use C+1:0:0 # # For the full guide on libcurl ABI rules, see docs/libcurl/ABI AM_CPPFLAGS += -DBUILDING_LIBCURL AM_LDFLAGS = AM_CFLAGS = libcurl_la_CPPFLAGS_EXTRA = libcurl_la_LDFLAGS_EXTRA = libcurl_la_CFLAGS_EXTRA = if CURL_LT_SHLIB_USE_VERSION_INFO libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) endif if CURL_LT_SHLIB_USE_NO_UNDEFINED libcurl_la_LDFLAGS_EXTRA += -no-undefined endif if CURL_LT_SHLIB_USE_MIMPURE_TEXT libcurl_la_LDFLAGS_EXTRA += -mimpure-text endif if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers else # if symbol-hiding is enabled, hide them! if DOING_CURL_SYMBOL_HIDING libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' endif endif if USE_CPPFLAG_CURL_STATICLIB libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB endif if DOING_CURL_SYMBOL_HIDING libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) endif libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) libcurlu_la_CFLAGS = $(AM_CFLAGS) # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) CHECKSRC = $(CS_$(V)) CS_0 = @echo " RUN " $@; CS_1 = CS_ = $(CS_0) checksrc: $(CHECKSRC)(@PERL@ $(srcdir)/checksrc.pl -D$(srcdir) -W$(srcdir)/curl_config.h \ $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch] $(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch]) if CURLDEBUG # for debug builds, we scan the sources on all regular make invokes all-local: checksrc endif # disable the tests that are mostly causing false positives TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet TIDY:=clang-tidy tidy: $(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H davix-0.8.0/deps/curl/lib/gopher.h0000644000000000000000000000227114121063461015433 0ustar rootroot#ifndef HEADER_CURL_GOPHER_H #define HEADER_CURL_GOPHER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_GOPHER extern const struct Curl_handler Curl_handler_gopher; #endif #endif /* HEADER_CURL_GOPHER_H */ davix-0.8.0/deps/curl/lib/ftp.h0000644000000000000000000001474714121063461014753 0ustar rootroot#ifndef HEADER_CURL_FTP_H #define HEADER_CURL_FTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "pingpong.h" #ifndef CURL_DISABLE_FTP extern const struct Curl_handler Curl_handler_ftp; #ifdef USE_SSL extern const struct Curl_handler Curl_handler_ftps; #endif CURLcode Curl_ftpsend(struct connectdata *, const char *cmd); CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, int *ftpcode); #endif /* CURL_DISABLE_FTP */ /**************************************************************************** * FTP unique setup ***************************************************************************/ typedef enum { FTP_STOP, /* do nothing state, stops the state machine */ FTP_WAIT220, /* waiting for the initial 220 response immediately after a connect */ FTP_AUTH, FTP_USER, FTP_PASS, FTP_ACCT, FTP_PBSZ, FTP_PROT, FTP_CCC, FTP_PWD, FTP_SYST, FTP_NAMEFMT, FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ FTP_RETR_PREQUOTE, FTP_STOR_PREQUOTE, FTP_POSTQUOTE, FTP_CWD, /* change dir */ FTP_MKD, /* if the dir didn't exist */ FTP_MDTM, /* to figure out the datestamp */ FTP_TYPE, /* to set type when doing a head-like request */ FTP_LIST_TYPE, /* set type when about to do a dir list */ FTP_RETR_TYPE, /* set type when about to RETR a file */ FTP_STOR_TYPE, /* set type when about to STOR a file */ FTP_SIZE, /* get the remote file's size for head-like request */ FTP_RETR_SIZE, /* get the remote file's size for RETR */ FTP_STOR_SIZE, /* get the size for STOR */ FTP_REST, /* when used to check if the server supports it in head-like */ FTP_RETR_REST, /* when asking for "resume" in for RETR */ FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */ FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */ FTP_PASV, /* generic state for PASV and EPSV, check count1 */ FTP_LIST, /* generic state for LIST, NLST or a custom list command */ FTP_RETR, FTP_STOR, /* generic state for STOR and APPE */ FTP_QUIT, FTP_LAST /* never used */ } ftpstate; struct ftp_parselist_data; /* defined later in ftplistparser.c */ struct ftp_wc { struct ftp_parselist_data *parser; struct { curl_write_callback write_function; FILE *file_descriptor; } backup; }; typedef enum { FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */ FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */ FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */ } curl_ftpfile; /* This FTP struct is used in the Curl_easy. All FTP data that is connection-oriented must be in FTP_conn to properly deal with the fact that perhaps the Curl_easy is changed between the times the connection is used. */ struct FTP { char *path; /* points to the urlpieces struct field */ char *pathalloc; /* if non-NULL a pointer to an allocated path */ /* transfer a file/body or not, done as a typedefed enum just to make debuggers display the full symbol and not just the numerical value */ curl_pp_transfer transfer; curl_off_t downloadsize; }; /* ftp_conn is used for struct connection-oriented data in the connectdata struct */ struct ftp_conn { struct pingpong pp; char *entrypath; /* the PWD reply when we logged on */ char **dirs; /* realloc()ed array for path components */ int dirdepth; /* number of entries used in the 'dirs' array */ char *file; /* url-decoded file name (or path) */ bool dont_check; /* Set to TRUE to prevent the final (post-transfer) file size and 226/250 status check. It should still read the line, just ignore the result. */ bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If the connection has timed out or been closed, this should be FALSE when it gets to Curl_ftp_quit() */ bool cwddone; /* if it has been determined that the proper CWD combo already has been done */ int cwdcount; /* number of CWD commands issued */ bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent caching the current directory */ bool wait_data_conn; /* this is set TRUE if data connection is waited */ char *prevpath; /* url-decoded conn->path from the previous transfer */ char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a and others (A/I or zero) */ int count1; /* general purpose counter for the state machine */ int count2; /* general purpose counter for the state machine */ int count3; /* general purpose counter for the state machine */ ftpstate state; /* always use ftp.c:state() to change state! */ ftpstate state_saved; /* transfer type saved to be reloaded after data connection is established */ curl_off_t retr_size_saved; /* Size of retrieved file saved */ char *server_os; /* The target server operating system. */ curl_off_t known_filesize; /* file size is different from -1, if wildcard LIST parsing was done and wc_statemach set it */ /* newhost is the (allocated) IP addr or host name to connect the data connection to */ char *newhost; /* this is the pair to connect the DATA... */ unsigned short newport; /* connection to */ }; #define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ #endif /* HEADER_CURL_FTP_H */ davix-0.8.0/deps/curl/lib/getinfo.h0000644000000000000000000000232514121063461015602 0ustar rootroot#ifndef HEADER_CURL_GETINFO_H #define HEADER_CURL_GETINFO_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); CURLcode Curl_initinfo(struct Curl_easy *data); #endif /* HEADER_CURL_GETINFO_H */ davix-0.8.0/deps/curl/lib/curl_sasl.c0000644000000000000000000005027614121063461016141 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2195 CRAM-MD5 authentication * RFC2617 Basic and Digest Access Authentication * RFC2831 DIGEST-MD5 authentication * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication * RFC6749 OAuth 2.0 Authorization Framework * RFC7628 A Set of SASL Mechanisms for OAuth * Draft LOGIN SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ !defined(CURL_DISABLE_POP3) #include #include "urldata.h" #include "curl_base64.h" #include "curl_md5.h" #include "vauth/vauth.h" #include "vtls/vtls.h" #include "curl_hmac.h" #include "curl_sasl.h" #include "warnless.h" #include "strtok.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Supported mechanisms */ static const struct { const char *name; /* Name */ size_t len; /* Name length */ unsigned int bit; /* Flag bit */ } mechtable[] = { { "LOGIN", 5, SASL_MECH_LOGIN }, { "PLAIN", 5, SASL_MECH_PLAIN }, { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 }, { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 }, { "GSSAPI", 6, SASL_MECH_GSSAPI }, { "EXTERNAL", 8, SASL_MECH_EXTERNAL }, { "NTLM", 4, SASL_MECH_NTLM }, { "XOAUTH2", 7, SASL_MECH_XOAUTH2 }, { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER }, { ZERO_NULL, 0, 0 } }; /* * Curl_sasl_cleanup() * * This is used to cleanup any libraries or curl modules used by the sasl * functions. * * Parameters: * * conn [in] - The connection data. * authused [in] - The authentication mechanism used. */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) { #if defined(USE_KERBEROS5) /* Cleanup the gssapi structure */ if(authused == SASL_MECH_GSSAPI) { Curl_auth_cleanup_gssapi(&conn->krb5); } #endif #if defined(USE_NTLM) /* Cleanup the NTLM structure */ if(authused == SASL_MECH_NTLM) { Curl_auth_cleanup_ntlm(&conn->ntlm); } #endif #if !defined(USE_KERBEROS5) && !defined(USE_NTLM) /* Reserved for future use */ (void)conn; (void)authused; #endif } /* * Curl_sasl_decode_mech() * * Convert a SASL mechanism name into a token. * * Parameters: * * ptr [in] - The mechanism string. * maxlen [in] - Maximum mechanism string length. * len [out] - If not NULL, effective name length. * * Returns the SASL mechanism token or 0 if no match. */ unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len) { unsigned int i; char c; for(i = 0; mechtable[i].name; i++) { if(maxlen >= mechtable[i].len && !memcmp(ptr, mechtable[i].name, mechtable[i].len)) { if(len) *len = mechtable[i].len; if(maxlen == mechtable[i].len) return mechtable[i].bit; c = ptr[mechtable[i].len]; if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_') return mechtable[i].bit; } } return 0; } /* * Curl_sasl_parse_url_auth_option() * * Parse the URL login options. */ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, const char *value, size_t len) { CURLcode result = CURLE_OK; size_t mechlen; if(!len) return CURLE_URL_MALFORMAT; if(sasl->resetprefs) { sasl->resetprefs = FALSE; sasl->prefmech = SASL_AUTH_NONE; } if(!strncmp(value, "*", len)) sasl->prefmech = SASL_AUTH_DEFAULT; else { unsigned int mechbit = Curl_sasl_decode_mech(value, len, &mechlen); if(mechbit && mechlen == len) sasl->prefmech |= mechbit; else result = CURLE_URL_MALFORMAT; } return result; } /* * Curl_sasl_init() * * Initializes the SASL structure. */ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) { sasl->params = params; /* Set protocol dependent parameters */ sasl->state = SASL_STOP; /* Not yet running */ sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ sasl->force_ir = FALSE; /* Respect external option */ } /* * state() * * This is the ONLY way to change SASL state! */ static void state(struct SASL *sasl, struct connectdata *conn, saslstate newstate) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[]={ "STOP", "PLAIN", "LOGIN", "LOGIN_PASSWD", "EXTERNAL", "CRAMMD5", "DIGESTMD5", "DIGESTMD5_RESP", "NTLM", "NTLM_TYPE2MSG", "GSSAPI", "GSSAPI_TOKEN", "GSSAPI_NO_DATA", "OAUTH2", "OAUTH2_RESP", "CANCEL", "FINAL", /* LAST */ }; if(sasl->state != newstate) infof(conn->data, "SASL %p state change from %s to %s\n", (void *)sasl, names[sasl->state], names[newstate]); #else (void) conn; #endif sasl->state = newstate; } /* * Curl_sasl_can_authenticate() * * Check if we have enough auth data and capabilities to authenticate. */ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) { /* Have credentials been provided? */ if(conn->bits.user_passwd) return TRUE; /* EXTERNAL can authenticate without a user name and/or password */ if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) return TRUE; return FALSE; } /* * Curl_sasl_start() * * Calculate the required login details for SASL authentication. */ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, bool force_ir, saslprogress *progress) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; unsigned int enabledmechs; const char *mech = NULL; char *resp = NULL; size_t len = 0; saslstate state1 = SASL_STOP; saslstate state2 = SASL_FINAL; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #if defined(USE_KERBEROS5) || defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : sasl->params->service; #endif const char *oauth_bearer = data->set.str[STRING_BEARER]; sasl->force_ir = force_ir; /* Latch for future use */ sasl->authused = 0; /* No mechanism used yet */ enabledmechs = sasl->authmechs & sasl->prefmech; *progress = SASL_IDLE; /* Calculate the supported authentication mechanism, by decreasing order of security, as well as the initial response where appropriate */ if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { mech = SASL_MECH_STRING_EXTERNAL; state1 = SASL_EXTERNAL; sasl->authused = SASL_MECH_EXTERNAL; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_external_message(data, conn->user, &resp, &len); } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && Curl_auth_user_contains_domain(conn->user)) { sasl->mutual_auth = FALSE; mech = SASL_MECH_STRING_GSSAPI; state1 = SASL_GSSAPI; state2 = SASL_GSSAPI_TOKEN; sasl->authused = SASL_MECH_GSSAPI; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, service, data->conn->host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); } else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if((enabledmechs & SASL_MECH_DIGEST_MD5) && Curl_auth_is_digest_supported()) { mech = SASL_MECH_STRING_DIGEST_MD5; state1 = SASL_DIGESTMD5; sasl->authused = SASL_MECH_DIGEST_MD5; } else if(enabledmechs & SASL_MECH_CRAM_MD5) { mech = SASL_MECH_STRING_CRAM_MD5; state1 = SASL_CRAMMD5; sasl->authused = SASL_MECH_CRAM_MD5; } else #endif #ifdef USE_NTLM if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { mech = SASL_MECH_STRING_NTLM; state1 = SASL_NTLM; state2 = SASL_NTLM_TYPE2MSG; sasl->authused = SASL_MECH_NTLM; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_ntlm_type1_message(data, conn->user, conn->passwd, service, hostname, &conn->ntlm, &resp, &len); } else #endif if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { mech = SASL_MECH_STRING_OAUTHBEARER; state1 = SASL_OAUTH2; state2 = SASL_OAUTH2_RESP; sasl->authused = SASL_MECH_OAUTHBEARER; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_oauth_bearer_message(data, conn->user, hostname, port, oauth_bearer, &resp, &len); } else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { mech = SASL_MECH_STRING_XOAUTH2; state1 = SASL_OAUTH2; sasl->authused = SASL_MECH_XOAUTH2; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_xoauth_bearer_message(data, conn->user, oauth_bearer, &resp, &len); } else if(enabledmechs & SASL_MECH_PLAIN) { mech = SASL_MECH_STRING_PLAIN; state1 = SASL_PLAIN; sasl->authused = SASL_MECH_PLAIN; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_plain_message(data, conn->sasl_authzid, conn->user, conn->passwd, &resp, &len); } else if(enabledmechs & SASL_MECH_LOGIN) { mech = SASL_MECH_STRING_LOGIN; state1 = SASL_LOGIN; state2 = SASL_LOGIN_PASSWD; sasl->authused = SASL_MECH_LOGIN; if(force_ir || data->set.sasl_ir) result = Curl_auth_create_login_message(data, conn->user, &resp, &len); } } if(!result && mech) { if(resp && sasl->params->maxirlen && strlen(mech) + len > sasl->params->maxirlen) { free(resp); resp = NULL; } result = sasl->params->sendauth(conn, mech, resp); if(!result) { *progress = SASL_INPROGRESS; state(sasl, conn, resp ? state2 : state1); } } free(resp); return result; } /* * Curl_sasl_continue() * * Continue the authentication. */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; saslstate newstate = SASL_FINAL; char *resp = NULL; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #if !defined(CURL_DISABLE_CRYPTO_AUTH) char *chlg = NULL; size_t chlglen = 0; #endif #if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : sasl->params->service; char *serverdata; #endif size_t len = 0; const char *oauth_bearer = data->set.str[STRING_BEARER]; *progress = SASL_INPROGRESS; if(sasl->state == SASL_FINAL) { if(code != sasl->params->finalcode) result = CURLE_LOGIN_DENIED; *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return result; } if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && code != sasl->params->contcode) { *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return CURLE_LOGIN_DENIED; } switch(sasl->state) { case SASL_STOP: *progress = SASL_DONE; return result; case SASL_PLAIN: result = Curl_auth_create_plain_message(data, conn->sasl_authzid, conn->user, conn->passwd, &resp, &len); break; case SASL_LOGIN: result = Curl_auth_create_login_message(data, conn->user, &resp, &len); newstate = SASL_LOGIN_PASSWD; break; case SASL_LOGIN_PASSWD: result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len); break; case SASL_EXTERNAL: result = Curl_auth_create_external_message(data, conn->user, &resp, &len); break; #ifndef CURL_DISABLE_CRYPTO_AUTH case SASL_CRAMMD5: sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen); if(!result) result = Curl_auth_create_cram_md5_message(data, chlg, conn->user, conn->passwd, &resp, &len); free(chlg); break; case SASL_DIGESTMD5: sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_create_digest_md5_message(data, serverdata, conn->user, conn->passwd, service, &resp, &len); newstate = SASL_DIGESTMD5_RESP; break; case SASL_DIGESTMD5_RESP: resp = strdup(""); if(!resp) result = CURLE_OUT_OF_MEMORY; break; #endif #ifdef USE_NTLM case SASL_NTLM: /* Create the type-1 message */ result = Curl_auth_create_ntlm_type1_message(data, conn->user, conn->passwd, service, hostname, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; case SASL_NTLM_TYPE2MSG: /* Decode the type-2 message */ sasl->params->getmessage(data->state.buffer, &serverdata); result = Curl_auth_decode_ntlm_type2_message(data, serverdata, &conn->ntlm); if(!result) result = Curl_auth_create_ntlm_type3_message(data, conn->user, conn->passwd, &conn->ntlm, &resp, &len); break; #endif #if defined(USE_KERBEROS5) case SASL_GSSAPI: result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, service, data->conn->host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); newstate = SASL_GSSAPI_TOKEN; break; case SASL_GSSAPI_TOKEN: sasl->params->getmessage(data->state.buffer, &serverdata); if(sasl->mutual_auth) { /* Decode the user token challenge and create the optional response message */ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, NULL, NULL, sasl->mutual_auth, serverdata, &conn->krb5, &resp, &len); newstate = SASL_GSSAPI_NO_DATA; } else /* Decode the security challenge and create the response message */ result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; case SASL_GSSAPI_NO_DATA: sasl->params->getmessage(data->state.buffer, &serverdata); /* Decode the security challenge and create the response message */ result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; #endif case SASL_OAUTH2: /* Create the authorisation message */ if(sasl->authused == SASL_MECH_OAUTHBEARER) { result = Curl_auth_create_oauth_bearer_message(data, conn->user, hostname, port, oauth_bearer, &resp, &len); /* Failures maybe sent by the server as continuations for OAUTHBEARER */ newstate = SASL_OAUTH2_RESP; } else result = Curl_auth_create_xoauth_bearer_message(data, conn->user, oauth_bearer, &resp, &len); break; case SASL_OAUTH2_RESP: /* The continuation is optional so check the response code */ if(code == sasl->params->finalcode) { /* Final response was received so we are done */ *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return result; } else if(code == sasl->params->contcode) { /* Acknowledge the continuation by sending a 0x01 response base64 encoded */ resp = strdup("AQ=="); if(!resp) result = CURLE_OUT_OF_MEMORY; break; } else { *progress = SASL_DONE; state(sasl, conn, SASL_STOP); return CURLE_LOGIN_DENIED; } case SASL_CANCEL: /* Remove the offending mechanism from the supported list */ sasl->authmechs ^= sasl->authused; /* Start an alternative SASL authentication */ result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); newstate = sasl->state; /* Use state from Curl_sasl_start() */ break; default: failf(data, "Unsupported SASL authentication mechanism"); result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ break; } switch(result) { case CURLE_BAD_CONTENT_ENCODING: /* Cancel dialog */ result = sasl->params->sendcont(conn, "*"); newstate = SASL_CANCEL; break; case CURLE_OK: if(resp) result = sasl->params->sendcont(conn, resp); break; default: newstate = SASL_STOP; /* Stop on error */ *progress = SASL_DONE; break; } free(resp); state(sasl, conn, newstate); return result; } #endif /* protocols are enabled that use SASL */ davix-0.8.0/deps/curl/lib/sendf.c0000644000000000000000000005766414121063461015261 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_LINUX_TCP_H #include #endif #include #include "urldata.h" #include "sendf.h" #include "connect.h" #include "vtls/vtls.h" #include "vssh/ssh.h" #include "easyif.h" #include "multiif.h" #include "non-ascii.h" #include "strerror.h" #include "select.h" #include "strdup.h" #include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifdef CURL_DO_LINEEND_CONV /* * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF * (\n), with special processing for CRLF sequences that are split between two * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new * size of the data is returned. */ static size_t convert_lineends(struct Curl_easy *data, char *startPtr, size_t size) { char *inPtr, *outPtr; /* sanity check */ if((startPtr == NULL) || (size < 1)) { return size; } if(data->state.prev_block_had_trailing_cr) { /* The previous block of incoming data had a trailing CR, which was turned into a LF. */ if(*startPtr == '\n') { /* This block of incoming data starts with the previous block's LF so get rid of it */ memmove(startPtr, startPtr + 1, size-1); size--; /* and it wasn't a bare CR but a CRLF conversion instead */ data->state.crlf_conversions++; } data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */ } /* find 1st CR, if any */ inPtr = outPtr = memchr(startPtr, '\r', size); if(inPtr) { /* at least one CR, now look for CRLF */ while(inPtr < (startPtr + size-1)) { /* note that it's size-1, so we'll never look past the last byte */ if(memcmp(inPtr, "\r\n", 2) == 0) { /* CRLF found, bump past the CR and copy the NL */ inPtr++; *outPtr = *inPtr; /* keep track of how many CRLFs we converted */ data->state.crlf_conversions++; } else { if(*inPtr == '\r') { /* lone CR, move LF instead */ *outPtr = '\n'; } else { /* not a CRLF nor a CR, just copy whatever it is */ *outPtr = *inPtr; } } outPtr++; inPtr++; } /* end of while loop */ if(inPtr < startPtr + size) { /* handle last byte */ if(*inPtr == '\r') { /* deal with a CR at the end of the buffer */ *outPtr = '\n'; /* copy a NL instead */ /* note that a CRLF might be split across two blocks */ data->state.prev_block_had_trailing_cr = TRUE; } else { /* copy last byte */ *outPtr = *inPtr; } outPtr++; } if(outPtr < startPtr + size) /* tidy up by null terminating the now shorter data */ *outPtr = '\0'; return (outPtr - startPtr); } return size; } #endif /* CURL_DO_LINEEND_CONV */ #ifdef USE_RECV_BEFORE_SEND_WORKAROUND bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) { struct postponed_data * const psnd = &(conn->postponed[sockindex]); return psnd->buffer && psnd->allocated_size && psnd->recv_size > psnd->recv_processed; } static void pre_receive_plain(struct connectdata *conn, int num) { const curl_socket_t sockfd = conn->sock[num]; struct postponed_data * const psnd = &(conn->postponed[num]); size_t bytestorecv = psnd->allocated_size - psnd->recv_size; /* WinSock will destroy unread received data if send() is failed. To avoid lossage of received data, recv() must be performed before every send() if any incoming data is available. However, skip this, if buffer is already full. */ if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 && conn->recv[num] == Curl_recv_plain && (!psnd->buffer || bytestorecv)) { const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD, CURL_SOCKET_BAD, 0); if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) { /* Have some incoming data */ if(!psnd->buffer) { /* Use buffer double default size for intermediate buffer */ psnd->allocated_size = 2 * conn->data->set.buffer_size; psnd->buffer = malloc(psnd->allocated_size); psnd->recv_size = 0; psnd->recv_processed = 0; #ifdef DEBUGBUILD psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */ #endif /* DEBUGBUILD */ bytestorecv = psnd->allocated_size; } if(psnd->buffer) { ssize_t recvedbytes; DEBUGASSERT(psnd->bindsock == sockfd); recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size, bytestorecv); if(recvedbytes > 0) psnd->recv_size += recvedbytes; } else psnd->allocated_size = 0; } } } static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf, size_t len) { struct postponed_data * const psnd = &(conn->postponed[num]); size_t copysize; if(!psnd->buffer) return 0; DEBUGASSERT(psnd->allocated_size > 0); DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); DEBUGASSERT(psnd->recv_processed <= psnd->recv_size); /* Check and process data that already received and storied in internal intermediate buffer */ if(psnd->recv_size > psnd->recv_processed) { DEBUGASSERT(psnd->bindsock == conn->sock[num]); copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed); memcpy(buf, psnd->buffer + psnd->recv_processed, copysize); psnd->recv_processed += copysize; } else copysize = 0; /* buffer was allocated, but nothing was received */ /* Free intermediate buffer if it has no unprocessed data */ if(psnd->recv_processed == psnd->recv_size) { free(psnd->buffer); psnd->buffer = NULL; psnd->allocated_size = 0; psnd->recv_size = 0; psnd->recv_processed = 0; #ifdef DEBUGBUILD psnd->bindsock = CURL_SOCKET_BAD; #endif /* DEBUGBUILD */ } return (ssize_t)copysize; } #else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ /* Use "do-nothing" macros instead of functions when workaround not used */ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) { (void)conn; (void)sockindex; return false; } #define pre_receive_plain(c,n) do {} while(0) #define get_pre_recved(c,n,b,l) 0 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ /* Curl_infof() is for info message along the way */ void Curl_infof(struct Curl_easy *data, const char *fmt, ...) { if(data && data->set.verbose) { va_list ap; size_t len; char print_buffer[2048 + 1]; va_start(ap, fmt); len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); /* * Indicate truncation of the input by replacing the last 3 characters * with "...", and transfer the newline over in case the format had one. */ if(len >= sizeof(print_buffer)) { len = strlen(fmt); if(fmt[--len] == '\n') msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n"); else msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "..."); } va_end(ap); len = strlen(print_buffer); Curl_debug(data, CURLINFO_TEXT, print_buffer, len); } } /* Curl_failf() is for messages stating why we failed. * The message SHALL NOT include any LF or CR. */ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) { if(data->set.verbose || data->set.errorbuffer) { va_list ap; size_t len; char error[CURL_ERROR_SIZE + 2]; va_start(ap, fmt); mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); len = strlen(error); if(data->set.errorbuffer && !data->state.errorbuf) { strcpy(data->set.errorbuffer, error); data->state.errorbuf = TRUE; /* wrote error string */ } if(data->set.verbose) { error[len] = '\n'; error[++len] = '\0'; Curl_debug(data, CURLINFO_TEXT, error, len); } va_end(ap); } } /* Curl_sendf() sends formatted data to the server */ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt, ...) { struct Curl_easy *data = conn->data; ssize_t bytes_written; size_t write_len; CURLcode result = CURLE_OK; char *s; char *sptr; va_list ap; va_start(ap, fmt); s = vaprintf(fmt, ap); /* returns an allocated string */ va_end(ap); if(!s) return CURLE_OUT_OF_MEMORY; /* failure */ bytes_written = 0; write_len = strlen(s); sptr = s; for(;;) { /* Write the buffer to the socket */ result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written); if(result) break; if(data->set.verbose) Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written); if((size_t)bytes_written != write_len) { /* if not all was written at once, we must advance the pointer, decrease the size left and try again! */ write_len -= bytes_written; sptr += bytes_written; } else break; } free(s); /* free the output string */ return result; } /* * Curl_write() is an internal write function that sends data to the * server. Works with plain sockets, SCP, SSL or kerberos. * * If the write would block (CURLE_AGAIN), we return CURLE_OK and * (*written == 0). Otherwise we return regular CURLcode value. */ CURLcode Curl_write(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written) { ssize_t bytes_written; CURLcode result = CURLE_OK; int num = (sockfd == conn->sock[SECONDARYSOCKET]); bytes_written = conn->send[num](conn, num, mem, len, &result); *written = bytes_written; if(bytes_written >= 0) /* we completely ignore the curlcode value when subzero is not returned */ return CURLE_OK; /* handle CURLE_AGAIN or a send failure */ switch(result) { case CURLE_AGAIN: *written = 0; return CURLE_OK; case CURLE_OK: /* general send failure */ return CURLE_SEND_ERROR; default: /* we got a specific curlcode, forward it */ return result; } } ssize_t Curl_send_plain(struct connectdata *conn, int num, const void *mem, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; ssize_t bytes_written; /* WinSock will destroy unread received data if send() is failed. To avoid lossage of received data, recv() must be performed before every send() if any incoming data is available. */ pre_receive_plain(conn, num); #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */ if(conn->bits.tcp_fastopen) { bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN, conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen); conn->bits.tcp_fastopen = FALSE; } else #endif bytes_written = swrite(sockfd, mem, len); *code = CURLE_OK; if(-1 == bytes_written) { int err = SOCKERRNO; if( #ifdef WSAEWOULDBLOCK /* This is how Windows does it */ (WSAEWOULDBLOCK == err) #else /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned due to its inability to send off data without blocking. We therefore treat both error codes the same here */ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) || (EINPROGRESS == err) #endif ) { /* this is just a case of EWOULDBLOCK */ bytes_written = 0; *code = CURLE_AGAIN; } else { char buffer[STRERROR_LEN]; failf(conn->data, "Send failure: %s", Curl_strerror(err, buffer, sizeof(buffer))); conn->data->state.os_errno = err; *code = CURLE_SEND_ERROR; } } return bytes_written; } /* * Curl_write_plain() is an internal write function that sends data to the * server using plain sockets only. Otherwise meant to have the exact same * proto as Curl_write() */ CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written) { ssize_t bytes_written; CURLcode result; int num = (sockfd == conn->sock[SECONDARYSOCKET]); bytes_written = Curl_send_plain(conn, num, mem, len, &result); *written = bytes_written; return result; } ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; ssize_t nread; /* Check and return data that already received and storied in internal intermediate buffer */ nread = get_pre_recved(conn, num, buf, len); if(nread > 0) { *code = CURLE_OK; return nread; } nread = sread(sockfd, buf, len); *code = CURLE_OK; if(-1 == nread) { int err = SOCKERRNO; if( #ifdef WSAEWOULDBLOCK /* This is how Windows does it */ (WSAEWOULDBLOCK == err) #else /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned due to its inability to send off data without blocking. We therefore treat both error codes the same here */ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) #endif ) { /* this is just a case of EWOULDBLOCK */ *code = CURLE_AGAIN; } else { char buffer[STRERROR_LEN]; failf(conn->data, "Recv failure: %s", Curl_strerror(err, buffer, sizeof(buffer))); conn->data->state.os_errno = err; *code = CURLE_RECV_ERROR; } } return nread; } static CURLcode pausewrite(struct Curl_easy *data, int type, /* what type of data */ const char *ptr, size_t len) { /* signalled to pause sending on this connection, but since we have data we want to send we need to dup it to save a copy for when the sending is again enabled */ struct SingleRequest *k = &data->req; struct UrlState *s = &data->state; char *dupl; unsigned int i; bool newtype = TRUE; /* If this transfers over HTTP/2, pause the stream! */ Curl_http2_stream_pause(data, TRUE); if(s->tempcount) { for(i = 0; i< s->tempcount; i++) { if(s->tempwrite[i].type == type) { /* data for this type exists */ newtype = FALSE; break; } } DEBUGASSERT(i < 3); } else i = 0; if(!newtype) { /* append new data to old data */ /* figure out the new size of the data to save */ size_t newlen = len + s->tempwrite[i].len; /* allocate the new memory area */ char *newptr = realloc(s->tempwrite[i].buf, newlen); if(!newptr) return CURLE_OUT_OF_MEMORY; /* copy the new data to the end of the new area */ memcpy(newptr + s->tempwrite[i].len, ptr, len); /* update the pointer and the size */ s->tempwrite[i].buf = newptr; s->tempwrite[i].len = newlen; len = newlen; /* for the debug output below */ } else { dupl = Curl_memdup(ptr, len); if(!dupl) return CURLE_OUT_OF_MEMORY; /* store this information in the state struct for later use */ s->tempwrite[i].buf = dupl; s->tempwrite[i].len = len; s->tempwrite[i].type = type; if(newtype) s->tempcount++; } /* mark the connection as RECV paused */ k->keepon |= KEEP_RECV_PAUSE; DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n", len, type)); return CURLE_OK; } /* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via * client write callback(s) and takes care of pause requests from the * callbacks. */ static CURLcode chop_write(struct connectdata *conn, int type, char *optr, size_t olen) { struct Curl_easy *data = conn->data; curl_write_callback writeheader = NULL; curl_write_callback writebody = NULL; char *ptr = optr; size_t len = olen; if(!len) return CURLE_OK; /* If reading is paused, append this data to the already held data for this type. */ if(data->req.keepon & KEEP_RECV_PAUSE) return pausewrite(data, type, ptr, len); /* Determine the callback(s) to use. */ if(type & CLIENTWRITE_BODY) writebody = data->set.fwrite_func; if((type & CLIENTWRITE_HEADER) && (data->set.fwrite_header || data->set.writeheader)) { /* * Write headers to the same callback or to the especially setup * header callback function (added after version 7.7.1). */ writeheader = data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func; } /* Chop data, write chunks. */ while(len) { size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE; if(writebody) { size_t wrote; Curl_set_in_callback(data, true); wrote = writebody(ptr, 1, chunklen, data->set.out); Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) { if(conn->handler->flags & PROTOPT_NONETWORK) { /* Protocols that work without network cannot be paused. This is actually only FILE:// just now, and it can't pause since the transfer isn't done using the "normal" procedure. */ failf(data, "Write callback asked for PAUSE when not supported!"); return CURLE_WRITE_ERROR; } return pausewrite(data, type, ptr, len); } if(wrote != chunklen) { failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen); return CURLE_WRITE_ERROR; } } ptr += chunklen; len -= chunklen; } if(writeheader) { size_t wrote; ptr = optr; len = olen; Curl_set_in_callback(data, true); wrote = writeheader(ptr, 1, len, data->set.writeheader); Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) /* here we pass in the HEADER bit only since if this was body as well then it was passed already and clearly that didn't trigger the pause, so this is saved for later with the HEADER bit only */ return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); if(wrote != len) { failf(data, "Failed writing header"); return CURLE_WRITE_ERROR; } } return CURLE_OK; } /* Curl_client_write() sends data to the write callback(s) The bit pattern defines to what "streams" to write to. Body and/or header. The defines are in sendf.h of course. If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the local character encoding. This is a problem and should be changed in the future to leave the original data alone. */ CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len) { struct Curl_easy *data = conn->data; if(0 == len) len = strlen(ptr); DEBUGASSERT(type <= 3); /* FTP data may need conversion. */ if((type & CLIENTWRITE_BODY) && (conn->handler->protocol & PROTO_FAMILY_FTP) && conn->proto.ftpc.transfertype == 'A') { /* convert from the network encoding */ CURLcode result = Curl_convert_from_network(data, ptr, len); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; #ifdef CURL_DO_LINEEND_CONV /* convert end-of-line markers */ len = convert_lineends(data, ptr, len); #endif /* CURL_DO_LINEEND_CONV */ } return chop_write(conn, type, ptr, len); } CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n) { ssize_t nread = sread(sockfd, buf, bytesfromsocket); if(-1 == nread) { const int err = SOCKERRNO; const bool return_error = #ifdef USE_WINSOCK WSAEWOULDBLOCK == err #else EWOULDBLOCK == err || EAGAIN == err || EINTR == err #endif ; *n = 0; /* no data returned */ if(return_error) return CURLE_AGAIN; return CURLE_RECV_ERROR; } *n = nread; return CURLE_OK; } /* * Internal read-from-socket function. This is meant to deal with plain * sockets, SSL sockets and kerberos sockets. * * Returns a regular CURLcode value. */ CURLcode Curl_read(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ char *buf, /* store read data here */ size_t sizerequested, /* max amount to read */ ssize_t *n) /* amount bytes read */ { CURLcode result = CURLE_RECV_ERROR; ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; struct Curl_easy *data = conn->data; /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets us use the correct ssl handle. */ int num = (sockfd == conn->sock[SECONDARYSOCKET]); *n = 0; /* reset amount to zero */ bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size); buffertofill = buf; nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result); if(nread < 0) return result; *n += nread; return CURLE_OK; } /* return 0 on success */ int Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size) { static const char s_infotype[CURLINFO_END][3] = { "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; int rc = 0; #ifdef CURL_DOES_CONVERSIONS char *buf = NULL; size_t conv_size = 0; switch(type) { case CURLINFO_HEADER_OUT: buf = Curl_memdup(ptr, size); if(!buf) return 1; conv_size = size; /* Special processing is needed for this block if it * contains both headers and data (separated by CRLFCRLF). * We want to convert just the headers, leaving the data as-is. */ if(size > 4) { size_t i; for(i = 0; i < size-4; i++) { if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) { /* convert everything through this CRLFCRLF but no further */ conv_size = i + 4; break; } } } Curl_convert_from_network(data, buf, conv_size); /* Curl_convert_from_network calls failf if unsuccessful */ /* we might as well continue even if it fails... */ ptr = buf; /* switch pointer to use my buffer instead */ break; default: /* leave everything else as-is */ break; } #endif /* CURL_DOES_CONVERSIONS */ if(data->set.fdebug) { Curl_set_in_callback(data, true); rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); Curl_set_in_callback(data, false); } else { switch(type) { case CURLINFO_TEXT: case CURLINFO_HEADER_OUT: case CURLINFO_HEADER_IN: fwrite(s_infotype[type], 2, 1, data->set.err); fwrite(ptr, size, 1, data->set.err); #ifdef CURL_DOES_CONVERSIONS if(size != conv_size) { /* we had untranslated data so we need an explicit newline */ fwrite("\n", 1, 1, data->set.err); } #endif break; default: /* nada */ break; } } #ifdef CURL_DOES_CONVERSIONS free(buf); #endif return rc; } davix-0.8.0/deps/curl/lib/curl_rtmp.c0000644000000000000000000002703214121063461016153 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. * Copyright (C) 2010, Howard Chu, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_LIBRTMP #include "curl_rtmp.h" #include "urldata.h" #include "nonblock.h" /* for curlx_nonblock */ #include "progress.h" /* for Curl_pgrsSetUploadSize */ #include "transfer.h" #include "warnless.h" #include #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #if defined(WIN32) && !defined(USE_LWIPSOCK) #define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) #define SET_RCVTIMEO(tv,s) int tv = s*1000 #elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) #define SET_RCVTIMEO(tv,s) int tv = s*1000 #else #define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} #endif #define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ static CURLcode rtmp_setup_connection(struct connectdata *conn); static CURLcode rtmp_do(struct connectdata *conn, bool *done); static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode rtmp_connect(struct connectdata *conn, bool *done); static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead); static Curl_recv rtmp_recv; static Curl_send rtmp_send; /* * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu */ const struct Curl_handler Curl_handler_rtmp = { "RTMP", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMP, /* defport */ CURLPROTO_RTMP, /* protocol */ PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpt = { "RTMPT", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMPT, /* defport */ CURLPROTO_RTMPT, /* protocol */ PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpe = { "RTMPE", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMP, /* defport */ CURLPROTO_RTMPE, /* protocol */ PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpte = { "RTMPTE", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMPT, /* defport */ CURLPROTO_RTMPTE, /* protocol */ PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmps = { "RTMPS", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMPS, /* defport */ CURLPROTO_RTMPS, /* protocol */ PROTOPT_NONE /* flags*/ }; const struct Curl_handler Curl_handler_rtmpts = { "RTMPTS", /* scheme */ rtmp_setup_connection, /* setup_connection */ rtmp_do, /* do_it */ rtmp_done, /* done */ ZERO_NULL, /* do_more */ rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_RTMPS, /* defport */ CURLPROTO_RTMPTS, /* protocol */ PROTOPT_NONE /* flags*/ }; static CURLcode rtmp_setup_connection(struct connectdata *conn) { RTMP *r = RTMP_Alloc(); if(!r) return CURLE_OUT_OF_MEMORY; RTMP_Init(r); RTMP_SetBufferMS(r, DEF_BUFTIME); if(!RTMP_SetupURL(r, conn->data->change.url)) { RTMP_Free(r); return CURLE_URL_MALFORMAT; } conn->proto.rtmp = r; return CURLE_OK; } static CURLcode rtmp_connect(struct connectdata *conn, bool *done) { RTMP *r = conn->proto.rtmp; SET_RCVTIMEO(tv, 10); r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET]; /* We have to know if it's a write before we send the * connect request packet */ if(conn->data->set.upload) r->Link.protocol |= RTMP_FEATURE_WRITE; /* For plain streams, use the buffer toggle trick to keep data flowing */ if(!(r->Link.lFlags & RTMP_LF_LIVE) && !(r->Link.protocol & RTMP_FEATURE_HTTP)) r->Link.lFlags |= RTMP_LF_BUFX; (void)curlx_nonblock(r->m_sb.sb_socket, FALSE); setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); if(!RTMP_Connect1(r, NULL)) return CURLE_FAILED_INIT; /* Clients must send a periodic BytesReceived report to the server */ r->m_bSendCounter = true; *done = TRUE; conn->recv[FIRSTSOCKET] = rtmp_recv; conn->send[FIRSTSOCKET] = rtmp_send; return CURLE_OK; } static CURLcode rtmp_do(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; RTMP *r = conn->proto.rtmp; if(!RTMP_ConnectStream(r, 0)) return CURLE_FAILED_INIT; if(conn->data->set.upload) { Curl_pgrsSetUploadSize(data, data->state.infilesize); Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); } else Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); *done = TRUE; return CURLE_OK; } static CURLcode rtmp_done(struct connectdata *conn, CURLcode status, bool premature) { (void)conn; /* unused */ (void)status; /* unused */ (void)premature; /* unused */ return CURLE_OK; } static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead_connection) { RTMP *r = conn->proto.rtmp; (void)dead_connection; if(r) { conn->proto.rtmp = NULL; RTMP_Close(r); RTMP_Free(r); } return CURLE_OK; } static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { RTMP *r = conn->proto.rtmp; ssize_t nread; (void)sockindex; /* unused */ nread = RTMP_Read(r, buf, curlx_uztosi(len)); if(nread < 0) { if(r->m_read.status == RTMP_READ_COMPLETE || r->m_read.status == RTMP_READ_EOF) { conn->data->req.size = conn->data->req.bytecount; nread = 0; } else *err = CURLE_RECV_ERROR; } return nread; } static ssize_t rtmp_send(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err) { RTMP *r = conn->proto.rtmp; ssize_t num; (void)sockindex; /* unused */ num = RTMP_Write(r, (char *)buf, curlx_uztosi(len)); if(num < 0) *err = CURLE_SEND_ERROR; return num; } #endif /* USE_LIBRTMP */ davix-0.8.0/deps/curl/lib/doh.h0000644000000000000000000000647514121063461014733 0ustar rootroot#ifndef HEADER_CURL_DOH_H #define HEADER_CURL_DOH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "urldata.h" #include "curl_addrinfo.h" #ifndef CURL_DISABLE_DOH /* * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name * and returns a 'Curl_addrinfo *' with the address information. */ Curl_addrinfo *Curl_doh(struct connectdata *conn, const char *hostname, int port, int *waitp); CURLcode Curl_doh_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns); int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks); typedef enum { DOH_OK, DOH_DNS_BAD_LABEL, /* 1 */ DOH_DNS_OUT_OF_RANGE, /* 2 */ DOH_DNS_LABEL_LOOP, /* 3 */ DOH_TOO_SMALL_BUFFER, /* 4 */ DOH_OUT_OF_MEM, /* 5 */ DOH_DNS_RDATA_LEN, /* 6 */ DOH_DNS_MALFORMAT, /* 7 */ DOH_DNS_BAD_RCODE, /* 8 - no such name */ DOH_DNS_UNEXPECTED_TYPE, /* 9 */ DOH_DNS_UNEXPECTED_CLASS, /* 10 */ DOH_NO_CONTENT, /* 11 */ DOH_DNS_BAD_ID, /* 12 */ DOH_DNS_NAME_TOO_LONG /* 13 */ } DOHcode; typedef enum { DNS_TYPE_A = 1, DNS_TYPE_NS = 2, DNS_TYPE_CNAME = 5, DNS_TYPE_AAAA = 28, DNS_TYPE_DNAME = 39 /* RFC6672 */ } DNStype; #define DOH_MAX_ADDR 24 #define DOH_MAX_CNAME 4 struct cnamestore { size_t len; /* length of cname */ char *alloc; /* allocated pointer */ size_t allocsize; /* allocated size */ }; struct dohaddr { int type; union { unsigned char v4[4]; /* network byte order */ unsigned char v6[16]; } ip; }; struct dohentry { unsigned int ttl; int numaddr; struct dohaddr addr[DOH_MAX_ADDR]; int numcname; struct cnamestore cname[DOH_MAX_CNAME]; }; #ifdef DEBUGBUILD DOHcode doh_encode(const char *host, DNStype dnstype, unsigned char *dnsp, /* buffer */ size_t len, /* buffer size */ size_t *olen); /* output length */ DOHcode doh_decode(unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d); void de_cleanup(struct dohentry *d); #endif #else /* if DOH is disabled */ #define Curl_doh(a,b,c,d) NULL #define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST #endif #endif /* HEADER_CURL_DOH_H */ davix-0.8.0/deps/curl/lib/rtsp.c0000644000000000000000000006161514121063461015141 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_RTSP #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "multiif.h" #include "http.h" #include "url.h" #include "progress.h" #include "rtsp.h" #include "strcase.h" #include "select.h" #include "connect.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1]))) #define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \ ((int)((unsigned char)((p)[3])))) /* protocol-specific functions set up to be called by the main engine */ static CURLcode rtsp_do(struct connectdata *conn, bool *done); static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode rtsp_connect(struct connectdata *conn, bool *done); static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead); static int rtsp_getsock_do(struct connectdata *conn, curl_socket_t *socks); /* * Parse and write out any available RTP data. * * nread: amount of data left after k->str. will be modified if RTP * data is parsed and k->str is moved up * readmore: whether or not the RTP parser needs more data right away */ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); static CURLcode rtsp_setup_connection(struct connectdata *conn); static unsigned int rtsp_conncheck(struct connectdata *check, unsigned int checks_to_perform); /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for the single socket to become writable only */ static int rtsp_getsock_do(struct connectdata *conn, curl_socket_t *socks) { /* write mode */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_WRITESOCK(0); } static CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len); /* * RTSP handler interface. */ const struct Curl_handler Curl_handler_rtsp = { "RTSP", /* scheme */ rtsp_setup_connection, /* setup_connection */ rtsp_do, /* do_it */ rtsp_done, /* done */ ZERO_NULL, /* do_more */ rtsp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ rtsp_getsock_do, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtsp_disconnect, /* disconnect */ rtsp_rtp_readwrite, /* readwrite */ rtsp_conncheck, /* connection_check */ PORT_RTSP, /* defport */ CURLPROTO_RTSP, /* protocol */ PROTOPT_NONE /* flags */ }; static CURLcode rtsp_setup_connection(struct connectdata *conn) { struct RTSP *rtsp; conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP)); if(!rtsp) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } /* * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not * want to block the application forever while receiving a stream. Therefore, * we cannot assume that an RTSP socket is dead just because it is readable. * * Instead, if it is readable, run Curl_connalive() to peek at the socket * and distinguish between closed and data. */ static bool rtsp_connisdead(struct connectdata *check) { int sval; bool ret_val = TRUE; sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); if(sval == 0) { /* timeout */ ret_val = FALSE; } else if(sval & CURL_CSELECT_ERR) { /* socket is in an error state */ ret_val = TRUE; } else if(sval & CURL_CSELECT_IN) { /* readable with no error. could still be closed */ ret_val = !Curl_connalive(check); } return ret_val; } /* * Function to check on various aspects of a connection. */ static unsigned int rtsp_conncheck(struct connectdata *check, unsigned int checks_to_perform) { unsigned int ret_val = CONNRESULT_NONE; if(checks_to_perform & CONNCHECK_ISDEAD) { if(rtsp_connisdead(check)) ret_val |= CONNRESULT_DEAD; } return ret_val; } static CURLcode rtsp_connect(struct connectdata *conn, bool *done) { CURLcode httpStatus; struct Curl_easy *data = conn->data; httpStatus = Curl_http_connect(conn, done); /* Initialize the CSeq if not already done */ if(data->state.rtsp_next_client_CSeq == 0) data->state.rtsp_next_client_CSeq = 1; if(data->state.rtsp_next_server_CSeq == 0) data->state.rtsp_next_server_CSeq = 1; conn->proto.rtspc.rtp_channel = -1; return httpStatus; } static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead) { (void) dead; Curl_safefree(conn->proto.rtspc.rtp_buf); return CURLE_OK; } static CURLcode rtsp_done(struct connectdata *conn, CURLcode status, bool premature) { struct Curl_easy *data = conn->data; struct RTSP *rtsp = data->req.protop; CURLcode httpStatus; /* Bypass HTTP empty-reply checks on receive */ if(data->set.rtspreq == RTSPREQ_RECEIVE) premature = TRUE; httpStatus = Curl_http_done(conn, status, premature); if(rtsp) { /* Check the sequence numbers */ long CSeq_sent = rtsp->CSeq_sent; long CSeq_recv = rtsp->CSeq_recv; if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) { failf(data, "The CSeq of this request %ld did not match the response %ld", CSeq_sent, CSeq_recv); return CURLE_RTSP_CSEQ_ERROR; } if(data->set.rtspreq == RTSPREQ_RECEIVE && (conn->proto.rtspc.rtp_channel == -1)) { infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv); } } return httpStatus; } static CURLcode rtsp_do(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; Curl_send_buffer *req_buffer; curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ const char *p_request = NULL; const char *p_session_id = NULL; const char *p_accept = NULL; const char *p_accept_encoding = NULL; const char *p_range = NULL; const char *p_referrer = NULL; const char *p_stream_uri = NULL; const char *p_transport = NULL; const char *p_uagent = NULL; const char *p_proxyuserpwd = NULL; const char *p_userpwd = NULL; *done = TRUE; rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq; rtsp->CSeq_recv = 0; /* Setup the 'p_request' pointer to the proper p_request string * Since all RTSP requests are included here, there is no need to * support custom requests like HTTP. **/ data->set.opt_no_body = TRUE; /* most requests don't contain a body */ switch(rtspreq) { default: failf(data, "Got invalid RTSP request"); return CURLE_BAD_FUNCTION_ARGUMENT; case RTSPREQ_OPTIONS: p_request = "OPTIONS"; break; case RTSPREQ_DESCRIBE: p_request = "DESCRIBE"; data->set.opt_no_body = FALSE; break; case RTSPREQ_ANNOUNCE: p_request = "ANNOUNCE"; break; case RTSPREQ_SETUP: p_request = "SETUP"; break; case RTSPREQ_PLAY: p_request = "PLAY"; break; case RTSPREQ_PAUSE: p_request = "PAUSE"; break; case RTSPREQ_TEARDOWN: p_request = "TEARDOWN"; break; case RTSPREQ_GET_PARAMETER: /* GET_PARAMETER's no_body status is determined later */ p_request = "GET_PARAMETER"; data->set.opt_no_body = FALSE; break; case RTSPREQ_SET_PARAMETER: p_request = "SET_PARAMETER"; break; case RTSPREQ_RECORD: p_request = "RECORD"; break; case RTSPREQ_RECEIVE: p_request = ""; /* Treat interleaved RTP as body*/ data->set.opt_no_body = FALSE; break; case RTSPREQ_LAST: failf(data, "Got invalid RTSP request: RTSPREQ_LAST"); return CURLE_BAD_FUNCTION_ARGUMENT; } if(rtspreq == RTSPREQ_RECEIVE) { Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); return result; } p_session_id = data->set.str[STRING_RTSP_SESSION_ID]; if(!p_session_id && (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", p_request); return CURLE_BAD_FUNCTION_ARGUMENT; } /* Stream URI. Default to server '*' if not specified */ if(data->set.str[STRING_RTSP_STREAM_URI]) { p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI]; } else { p_stream_uri = "*"; } /* Transport Header for SETUP requests */ p_transport = Curl_checkheaders(conn, "Transport"); if(rtspreq == RTSPREQ_SETUP && !p_transport) { /* New Transport: setting? */ if(data->set.str[STRING_RTSP_TRANSPORT]) { Curl_safefree(conn->allocptr.rtsp_transport); conn->allocptr.rtsp_transport = aprintf("Transport: %s\r\n", data->set.str[STRING_RTSP_TRANSPORT]); if(!conn->allocptr.rtsp_transport) return CURLE_OUT_OF_MEMORY; } else { failf(data, "Refusing to issue an RTSP SETUP without a Transport: header."); return CURLE_BAD_FUNCTION_ARGUMENT; } p_transport = conn->allocptr.rtsp_transport; } /* Accept Headers for DESCRIBE requests */ if(rtspreq == RTSPREQ_DESCRIBE) { /* Accept Header */ p_accept = Curl_checkheaders(conn, "Accept")? NULL:"Accept: application/sdp\r\n"; /* Accept-Encoding header */ if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; p_accept_encoding = conn->allocptr.accept_encoding; } } /* The User-Agent string might have been allocated in url.c already, because it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ if(Curl_checkheaders(conn, "User-Agent") && conn->allocptr.uagent) { Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = NULL; } else if(!Curl_checkheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) { p_uagent = conn->allocptr.uagent; } /* setup the authentication headers */ result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE); if(result) return result; p_proxyuserpwd = conn->allocptr.proxyuserpwd; p_userpwd = conn->allocptr.userpwd; /* Referrer */ Curl_safefree(conn->allocptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer")) conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); else conn->allocptr.ref = NULL; p_referrer = conn->allocptr.ref; /* * Range Header * Only applies to PLAY, PAUSE, RECORD * * Go ahead and use the Range stuff supplied for HTTP */ if(data->state.use_range && (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { /* Check to see if there is a range set in the custom headers */ if(!Curl_checkheaders(conn, "Range") && data->state.range) { Curl_safefree(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); p_range = conn->allocptr.rangeline; } } /* * Sanity check the custom headers */ if(Curl_checkheaders(conn, "CSeq")) { failf(data, "CSeq cannot be set as a custom header."); return CURLE_RTSP_CSEQ_ERROR; } if(Curl_checkheaders(conn, "Session")) { failf(data, "Session ID cannot be set as a custom header."); return CURLE_BAD_FUNCTION_ARGUMENT; } /* Initialize a dynamic send buffer */ req_buffer = Curl_add_buffer_init(); if(!req_buffer) return CURLE_OUT_OF_MEMORY; result = Curl_add_bufferf(&req_buffer, "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ "CSeq: %ld\r\n", /* CSeq */ p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; /* * Rather than do a normal alloc line, keep the session_id unformatted * to make comparison easier */ if(p_session_id) { result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id); if(result) return result; } /* * Shared HTTP-like options */ result = Curl_add_bufferf(&req_buffer, "%s" /* transport */ "%s" /* accept */ "%s" /* accept-encoding */ "%s" /* range */ "%s" /* referrer */ "%s" /* user-agent */ "%s" /* proxyuserpwd */ "%s" /* userpwd */ , p_transport ? p_transport : "", p_accept ? p_accept : "", p_accept_encoding ? p_accept_encoding : "", p_range ? p_range : "", p_referrer ? p_referrer : "", p_uagent ? p_uagent : "", p_proxyuserpwd ? p_proxyuserpwd : "", p_userpwd ? p_userpwd : ""); /* * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM * with basic and digest, it will be freed anyway by the next request */ Curl_safefree(conn->allocptr.userpwd); conn->allocptr.userpwd = NULL; if(result) return result; if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { result = Curl_add_timecondition(conn, req_buffer); if(result) return result; } result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; if(rtspreq == RTSPREQ_ANNOUNCE || rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { if(data->set.upload) { putsize = data->state.infilesize; data->set.httpreq = HTTPREQ_PUT; } else { postsize = (data->state.infilesize != -1)? data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); data->set.httpreq = HTTPREQ_POST; } if(putsize > 0 || postsize > 0) { /* As stated in the http comments, it is probably not wise to * actually set a custom Content-Length in the headers */ if(!Curl_checkheaders(conn, "Content-Length")) { result = Curl_add_bufferf(&req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", (data->set.upload ? putsize : postsize)); if(result) return result; } if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(&req_buffer, "Content-Type: text/parameters\r\n"); if(result) return result; } } if(rtspreq == RTSPREQ_ANNOUNCE) { if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(&req_buffer, "Content-Type: application/sdp\r\n"); if(result) return result; } } data->state.expect100header = FALSE; /* RTSP posts are simple/small */ } else if(rtspreq == RTSPREQ_GET_PARAMETER) { /* Check for an empty GET_PARAMETER (heartbeat) request */ data->set.httpreq = HTTPREQ_HEAD; data->set.opt_no_body = TRUE; } } /* RTSP never allows chunked transfer */ data->req.forbidchunk = TRUE; /* Finish the request buffer */ result = Curl_add_buffer(&req_buffer, "\r\n", 2); if(result) return result; if(postsize > 0) { result = Curl_add_buffer(&req_buffer, data->set.postfields, (size_t)postsize); if(result) return result; } /* issue the request */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) { failf(data, "Failed sending RTSP request"); return result; } Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1); /* Increment the CSeq on success */ data->state.rtsp_next_client_CSeq++; if(data->req.writebytecount) { /* if a request-body has been sent off, we make sure this progress is noted properly */ Curl_pgrsSetUploadCounter(data, data->req.writebytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; } return result; } static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore) { struct SingleRequest *k = &data->req; struct rtsp_conn *rtspc = &(conn->proto.rtspc); char *rtp; /* moving pointer to rtp data */ ssize_t rtp_dataleft; /* how much data left to parse in this round */ char *scratch; CURLcode result; if(rtspc->rtp_buf) { /* There was some leftover data the last time. Merge buffers */ char *newptr = Curl_saferealloc(rtspc->rtp_buf, rtspc->rtp_bufsize + *nread); if(!newptr) { rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return CURLE_OUT_OF_MEMORY; } rtspc->rtp_buf = newptr; memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread); rtspc->rtp_bufsize += *nread; rtp = rtspc->rtp_buf; rtp_dataleft = rtspc->rtp_bufsize; } else { /* Just parse the request buffer directly */ rtp = k->str; rtp_dataleft = *nread; } while((rtp_dataleft > 0) && (rtp[0] == '$')) { if(rtp_dataleft > 4) { int rtp_length; /* Parse the header */ /* The channel identifier immediately follows and is 1 byte */ rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp); /* The length is two bytes */ rtp_length = RTP_PKT_LENGTH(rtp); if(rtp_dataleft < rtp_length + 4) { /* Need more - incomplete payload*/ *readmore = TRUE; break; } /* We have the full RTP interleaved packet * Write out the header including the leading '$' */ DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", rtspc->rtp_channel, rtp_length)); result = rtp_client_write(conn, &rtp[0], rtp_length + 4); if(result) { failf(data, "Got an error writing an RTP packet"); *readmore = FALSE; Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return result; } /* Move forward in the buffer */ rtp_dataleft -= rtp_length + 4; rtp += rtp_length + 4; if(data->set.rtspreq == RTSPREQ_RECEIVE) { /* If we are in a passive receive, give control back * to the app as often as we can. */ k->keepon &= ~KEEP_RECV; } } else { /* Need more - incomplete header */ *readmore = TRUE; break; } } if(rtp_dataleft != 0 && rtp[0] == '$') { DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft, *readmore ? "(READMORE)" : "")); /* Store the incomplete RTP packet for a "rewind" */ scratch = malloc(rtp_dataleft); if(!scratch) { Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return CURLE_OUT_OF_MEMORY; } memcpy(scratch, rtp, rtp_dataleft); Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = scratch; rtspc->rtp_bufsize = rtp_dataleft; /* As far as the transfer is concerned, this data is consumed */ *nread = 0; return CURLE_OK; } /* Fix up k->str to point just after the last RTP packet */ k->str += *nread - rtp_dataleft; /* either all of the data has been read or... * rtp now points at the next byte to parse */ if(rtp_dataleft > 0) DEBUGASSERT(k->str[0] == rtp[0]); DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */ *nread = rtp_dataleft; /* If we get here, we have finished with the leftover/merge buffer */ Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return CURLE_OK; } static CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) { struct Curl_easy *data = conn->data; size_t wrote; curl_write_callback writeit; void *user_ptr; if(len == 0) { failf(data, "Cannot write a 0 size RTP packet."); return CURLE_WRITE_ERROR; } /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA pointer to write out the RTP data. */ if(data->set.fwrite_rtp) { writeit = data->set.fwrite_rtp; user_ptr = data->set.rtp_out; } else { writeit = data->set.fwrite_func; user_ptr = data->set.out; } Curl_set_in_callback(data, true); wrote = writeit(ptr, 1, len, user_ptr); Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) { failf(data, "Cannot pause RTP"); return CURLE_WRITE_ERROR; } if(wrote != len) { failf(data, "Failed writing RTP data"); return CURLE_WRITE_ERROR; } return CURLE_OK; } CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header) { struct Curl_easy *data = conn->data; long CSeq = 0; if(checkprefix("CSeq:", header)) { /* Store the received CSeq. Match is verified in rtsp_done */ int nc = sscanf(&header[4], ": %ld", &CSeq); if(nc == 1) { struct RTSP *rtsp = data->req.protop; rtsp->CSeq_recv = CSeq; /* mark the request */ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */ } else { failf(data, "Unable to read the CSeq header: [%s]", header); return CURLE_RTSP_CSEQ_ERROR; } } else if(checkprefix("Session:", header)) { char *start; /* Find the first non-space letter */ start = header + 8; while(*start && ISSPACE(*start)) start++; if(!*start) { failf(data, "Got a blank Session ID"); } else if(data->set.str[STRING_RTSP_SESSION_ID]) { /* If the Session ID is set, then compare */ if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], strlen(data->set.str[STRING_RTSP_SESSION_ID])) != 0) { failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", start, data->set.str[STRING_RTSP_SESSION_ID]); return CURLE_RTSP_SESSION_ERROR; } } else { /* If the Session ID is not set, and we find it in a response, then set * it. * * Allow any non whitespace content, up to the field separator or end of * line. RFC 2326 isn't 100% clear on the session ID and for example * gstreamer does url-encoded session ID's not covered by the standard. */ char *end = start; while(*end && *end != ';' && !ISSPACE(*end)) end++; /* Copy the id substring into a new buffer */ data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1); if(data->set.str[STRING_RTSP_SESSION_ID] == NULL) return CURLE_OUT_OF_MEMORY; memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start); (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0'; } } return CURLE_OK; } #endif /* CURL_DISABLE_RTSP */ davix-0.8.0/deps/curl/lib/http_ntlm.h0000644000000000000000000000304314121063461016156 0ustar rootroot#ifndef HEADER_CURL_HTTP_NTLM_H #define HEADER_CURL_HTTP_NTLM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* this is for ntlm header input */ CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, const char *header); /* this is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); void Curl_http_auth_cleanup_ntlm(struct connectdata *conn); #endif /* !CURL_DISABLE_HTTP && USE_NTLM */ #endif /* HEADER_CURL_HTTP_NTLM_H */ davix-0.8.0/deps/curl/lib/CMakeLists.txt0000644000000000000000000000646214121063461016544 0ustar rootrootset(LIB_NAME libcurl) if(BUILD_SHARED_LIBS) set(CURL_STATICLIB NO) else() set(CURL_STATICLIB YES) endif() # Use: # * CURL_STATICLIB configure_file(curl_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h) transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h ) if(MSVC) list(APPEND CSOURCES libcurl.rc) endif() # SET(CSOURCES # # memdebug.c -not used # # nwlib.c - Not used # # strtok.c - specify later # # strtoofft.c - specify later # ) # # if we have Kerberos 4, right now this is never on # #OPTION(CURL_KRB4 "Use Kerberos 4" OFF) # IF(CURL_KRB4) # SET(CSOURCES ${CSOURCES} # krb4.c # security.c # ) # ENDIF(CURL_KRB4) # #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF) # MARK_AS_ADVANCED(CURL_MALLOC_DEBUG) # IF(CURL_MALLOC_DEBUG) # SET(CSOURCES ${CSOURCES} # memdebug.c # ) # ENDIF(CURL_MALLOC_DEBUG) # # only build compat strtoofft if we need to # IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) # SET(CSOURCES ${CSOURCES} # strtoofft.c # ) # ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) # The rest of the build include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(USE_ARES) include_directories(${CARES_INCLUDE_DIR}) endif() add_library( ${LIB_NAME} ${HHEADERS} ${CSOURCES} ) if(MSVC AND NOT BUILD_SHARED_LIBS) set_target_properties(${LIB_NAME} PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) endif() if(NOT BUILD_SHARED_LIBS) set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB) endif() target_link_libraries(${LIB_NAME} ${CURL_LIBS}) if(WIN32) add_definitions(-D_USRDLL) endif() set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) if(HIDES_CURL_PRIVATE_SYMBOLS) set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) endif() # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") if(CURL_HAS_LTO) set_target_properties(${LIB_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) endif() if(WIN32) if(BUILD_SHARED_LIBS) # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib") endif() endif() target_include_directories(${LIB_NAME} INTERFACE $ $) install(TARGETS ${LIB_NAME} EXPORT ${TARGETS_EXPORT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) export(TARGETS ${LIB_NAME} APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake NAMESPACE CURL:: ) davix-0.8.0/deps/curl/lib/curlx.h0000644000000000000000000000640714121063461015311 0ustar rootroot#ifndef HEADER_CURL_CURLX_H #define HEADER_CURL_CURLX_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Defines protos and includes all header files that provide the curlx_* * functions. The curlx_* functions are not part of the libcurl API, but are * stand-alone functions whose sources can be built and linked by apps if need * be. */ #include /* this is still a public header file that provides the curl_mprintf() functions while they still are offered publicly. They will be made library- private one day */ #include "strcase.h" /* "strcase.h" provides the strcasecompare protos */ #include "strtoofft.h" /* "strtoofft.h" provides this function: curlx_strtoofft(), returns a curl_off_t number from a given string. */ #include "nonblock.h" /* "nonblock.h" provides curlx_nonblock() */ #include "warnless.h" /* "warnless.h" provides functions: curlx_ultous() curlx_ultouc() curlx_uztosi() */ /* Now setup curlx_ * names for the functions that are to become curlx_ and be removed from a future libcurl official API: curlx_getenv curlx_mprintf (and its variations) curlx_strcasecompare curlx_strncasecompare */ #define curlx_getenv curl_getenv #define curlx_mvsnprintf curl_mvsnprintf #define curlx_msnprintf curl_msnprintf #define curlx_maprintf curl_maprintf #define curlx_mvaprintf curl_mvaprintf #define curlx_msprintf curl_msprintf #define curlx_mprintf curl_mprintf #define curlx_mfprintf curl_mfprintf #define curlx_mvsprintf curl_mvsprintf #define curlx_mvprintf curl_mvprintf #define curlx_mvfprintf curl_mvfprintf #ifdef ENABLE_CURLX_PRINTF /* If this define is set, we define all "standard" printf() functions to use the curlx_* version instead. It makes the source code transparent and easier to understand/patch. Undefine them first. */ # undef printf # undef fprintf # undef sprintf # undef msnprintf # undef vprintf # undef vfprintf # undef vsprintf # undef mvsnprintf # undef aprintf # undef vaprintf # define printf curlx_mprintf # define fprintf curlx_mfprintf # define sprintf curlx_msprintf # define msnprintf curlx_msnprintf # define vprintf curlx_mvprintf # define vfprintf curlx_mvfprintf # define mvsnprintf curlx_mvsnprintf # define aprintf curlx_maprintf # define vaprintf curlx_mvaprintf #endif /* ENABLE_CURLX_PRINTF */ #endif /* HEADER_CURL_CURLX_H */ davix-0.8.0/deps/curl/lib/idn_win32.c0000644000000000000000000000721314121063461015737 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * IDN conversions using Windows kernel32 and normaliz libraries. */ #include "curl_setup.h" #ifdef USE_WIN32_IDN #include "curl_multibyte.h" #include "curl_memory.h" #include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" #ifdef WANT_IDN_PROTOTYPES # if defined(_SAL_VERSION) WINNORMALIZEAPI int WINAPI IdnToAscii(_In_ DWORD dwFlags, _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr, _In_ int cchUnicodeChar, _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr, _In_ int cchASCIIChar); WINNORMALIZEAPI int WINAPI IdnToUnicode(_In_ DWORD dwFlags, _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr, _In_ int cchASCIIChar, _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr, _In_ int cchUnicodeChar); # else WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, const WCHAR *lpUnicodeCharStr, int cchUnicodeChar, WCHAR *lpASCIICharStr, int cchASCIIChar); WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, const WCHAR *lpASCIICharStr, int cchASCIIChar, WCHAR *lpUnicodeCharStr, int cchUnicodeChar); # endif #endif #define IDN_MAX_LENGTH 255 bool curl_win32_idn_to_ascii(const char *in, char **out); bool curl_win32_ascii_to_idn(const char *in, char **out); bool curl_win32_idn_to_ascii(const char *in, char **out) { bool success = FALSE; wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); if(in_w) { wchar_t punycode[IDN_MAX_LENGTH]; int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); free(in_w); if(chars) { *out = Curl_convert_wchar_to_UTF8(punycode); if(*out) success = TRUE; } } return success; } bool curl_win32_ascii_to_idn(const char *in, char **out) { bool success = FALSE; wchar_t *in_w = Curl_convert_UTF8_to_wchar(in); if(in_w) { size_t in_len = wcslen(in_w) + 1; wchar_t unicode[IDN_MAX_LENGTH]; int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len), unicode, IDN_MAX_LENGTH); free(in_w); if(chars) { *out = Curl_convert_wchar_to_UTF8(unicode); if(*out) success = TRUE; } } return success; } #endif /* USE_WIN32_IDN */ davix-0.8.0/deps/curl/lib/socks.h0000644000000000000000000000553214121063461015274 0ustar rootroot#ifndef HEADER_CURL_SOCKS_H #define HEADER_CURL_SOCKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef CURL_DISABLE_PROXY #define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN #define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN #define Curl_SOCKS_getsock(x,y,z) 0 #else /* * Helper read-from-socket functions. Does the same as Curl_read() but it * blocks until all bytes amount of buffersize will be read. No more, no less. * * This is STUPID BLOCKING behavior */ int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, char *buf, ssize_t buffersize, ssize_t *n); int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock, int sockindex); /* * This function logs in to a SOCKS4(a) proxy and sends the specifics to the * final destination server. */ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, struct connectdata *conn, bool *done); /* * This function logs in to a SOCKS5 proxy and sends the specifics to the * final destination server. */ CURLcode Curl_SOCKS5(const char *proxy_name, const char *proxy_password, const char *hostname, int remote_port, int sockindex, struct connectdata *conn, bool *done); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* * This function handles the SOCKS5 GSS-API negotiation and initialisation */ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn); #endif #endif /* CURL_DISABLE_PROXY */ #endif /* HEADER_CURL_SOCKS_H */ davix-0.8.0/deps/curl/lib/http.h0000644000000000000000000002476514121063461015142 0ustar rootroot#ifndef HEADER_CURL_HTTP_H #define HEADER_CURL_HTTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_HTTP #ifdef USE_NGHTTP2 #include #endif extern const struct Curl_handler Curl_handler_http; #ifdef USE_SSL extern const struct Curl_handler Curl_handler_https; #endif /* Header specific functions */ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ char *Curl_copy_header_value(const char *header); char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader); /* ------------------------------------------------------------------------- */ /* * The add_buffer series of functions are used to build one large memory chunk * from repeated function invokes. Used so that the entire HTTP request can * be sent in one go. */ struct Curl_send_buffer { char *buffer; size_t size_max; size_t size_used; }; typedef struct Curl_send_buffer Curl_send_buffer; Curl_send_buffer *Curl_add_buffer_init(void); void Curl_add_buffer_free(Curl_send_buffer **inp); CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) WARN_UNUSED_RESULT; CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, size_t size) WARN_UNUSED_RESULT; CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, struct connectdata *conn, curl_off_t *bytes_written, size_t included_body_bytes, int socketindex); CURLcode Curl_add_timecondition(const struct connectdata *conn, Curl_send_buffer *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, Curl_send_buffer *req_buffer); CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, Curl_send_buffer **buffer, struct Curl_easy *handle); /* protocol-specific functions set up to be called by the main engine */ CURLcode Curl_http(struct connectdata *conn, bool *done); CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); CURLcode Curl_http_connect(struct connectdata *conn, bool *done); /* These functions are in http.c */ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, const char *auth); CURLcode Curl_http_auth_act(struct connectdata *conn); /* If only the PICKNONE bit is set, there has been a round-trip and we selected to use no auth at all. Ie, we actively select no auth, as opposed to not having one selected. The other CURLAUTH_* defines are present in the public curl/curl.h header. */ #define CURLAUTH_PICKNONE (1<<30) /* don't use auth */ /* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST data get included in the initial data chunk sent to the server. If the data is larger than this, it will automatically get split up in multiple system calls. This value used to be fairly big (100K), but we must take into account that if the server rejects the POST due for authentication reasons, this data will always be unconditionally sent and thus it may not be larger than can always be afforded to send twice. It must not be greater than 64K to work on VMS. */ #ifndef MAX_INITIAL_POST_SIZE #define MAX_INITIAL_POST_SIZE (64*1024) #endif /* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will * automatically add an "Expect: 100-continue" header in HTTP requests. When * the size is unknown, it will always add it. * */ #ifndef EXPECT_100_THRESHOLD #define EXPECT_100_THRESHOLD (1024*1024) #endif #endif /* CURL_DISABLE_HTTP */ #ifdef USE_NGHTTP3 struct h3out; /* see ngtcp2 */ #endif /**************************************************************************** * HTTP unique setup ***************************************************************************/ struct HTTP { curl_mimepart *sendit; curl_off_t postsize; /* off_t to handle large file sizes */ const char *postdata; const char *p_pragma; /* Pragma: string */ const char *p_accept; /* Accept: string */ /* For FORM posting */ curl_mimepart form; struct back { curl_read_callback fread_func; /* backup storage for fread pointer */ void *fread_in; /* backup storage for fread_in pointer */ const char *postdata; curl_off_t postsize; } backup; enum { HTTPSEND_NADA, /* init */ HTTPSEND_REQUEST, /* sending a request */ HTTPSEND_BODY, /* sending body */ HTTPSEND_LAST /* never use this */ } sending; #ifndef CURL_DISABLE_HTTP Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in one chunk, points to an allocated send_buffer struct */ #endif #ifdef USE_NGHTTP2 /*********** for HTTP/2 we store stream-local data here *************/ int32_t stream_id; /* stream we are interested in */ bool bodystarted; /* We store non-final and final response headers here, per-stream */ Curl_send_buffer *header_recvbuf; size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into upper layer */ Curl_send_buffer *trailer_recvbuf; int status_code; /* HTTP status code */ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ bool close_handled; /* TRUE if stream closure is handled by libcurl */ char **push_headers; /* allocated array */ size_t push_headers_used; /* number of entries filled in */ size_t push_headers_alloc; /* number of entries allocated */ #endif #if defined(USE_NGHTTP2) || defined(USE_NGHTTP3) bool closed; /* TRUE on HTTP2 stream close */ char *mem; /* points to a buffer in memory to store received data */ size_t len; /* size of the buffer 'mem' points to */ size_t memlen; /* size of data copied to mem */ #endif #if defined(USE_NGHTTP2) || defined(ENABLE_QUIC) /* fields used by both HTTP/2 and HTTP/3 */ const uint8_t *upload_mem; /* points to a buffer to read from */ size_t upload_len; /* size of the buffer 'upload_mem' points to */ curl_off_t upload_left; /* number of bytes left to upload */ #endif #ifdef ENABLE_QUIC /*********** for HTTP/3 we store stream-local data here *************/ int64_t stream3_id; /* stream we are interested in */ bool firstheader; /* FALSE until headers arrive */ bool firstbody; /* FALSE until body arrives */ bool h3req; /* FALSE until request is issued */ bool upload_done; #endif #ifdef USE_NGHTTP3 size_t unacked_window; struct h3out *h3out; /* per-stream buffers for upload */ char *overflow_buf; /* excess data received during a single Curl_read */ size_t overflow_buflen; /* amount of data currently in overflow_buf */ size_t overflow_bufsize; /* size of the overflow_buf allocation */ #endif }; #ifdef USE_NGHTTP2 /* h2 settings for this connection */ struct h2settings { uint32_t max_concurrent_streams; bool enable_push; }; #endif struct http_conn { #ifdef USE_NGHTTP2 #define H2_BINSETTINGS_LEN 80 nghttp2_session *h2; uint8_t binsettings[H2_BINSETTINGS_LEN]; size_t binlen; /* length of the binsettings data */ Curl_send *send_underlying; /* underlying send Curl_send callback */ Curl_recv *recv_underlying; /* underlying recv Curl_recv callback */ char *inbuf; /* buffer to receive data from underlying socket */ size_t inbuflen; /* number of bytes filled in inbuf */ size_t nread_inbuf; /* number of bytes read from in inbuf */ /* We need separate buffer for transmission and reception because we may call nghttp2_session_send() after the nghttp2_session_mem_recv() but mem buffer is still not full. In this case, we wrongly sends the content of mem buffer if we share them for both cases. */ int32_t pause_stream_id; /* stream ID which paused nghttp2_session_mem_recv */ size_t drain_total; /* sum of all stream's UrlState.drain */ /* this is a hash of all individual streams (Curl_easy structs) */ struct h2settings settings; /* list of settings that will be sent */ nghttp2_settings_entry local_settings[3]; size_t local_settings_num; uint32_t error_code; /* HTTP/2 error code */ #else int unused; /* prevent a compiler warning */ #endif }; CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading); /** * Curl_http_output_auth() setups the authentication headers for the * host/proxy and the correct authentication * method. conn->data->state.authdone is set to TRUE when authentication is * done. * * @param conn all information about the current connection * @param request pointer to the request keyword * @param path pointer to the requested path * @param proxytunnel boolean if this is the request setting up a "proxy * tunnel" * * @returns CURLcode */ CURLcode Curl_http_output_auth(struct connectdata *conn, const char *request, const char *path, bool proxytunnel); /* TRUE if this is the request setting up the proxy tunnel */ #endif /* HEADER_CURL_HTTP_H */ davix-0.8.0/deps/curl/lib/hostip.h0000644000000000000000000002027114121063461015455 0ustar rootroot#ifndef HEADER_CURL_HOSTIP_H #define HEADER_CURL_HOSTIP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "hash.h" #include "curl_addrinfo.h" #include "timeval.h" /* for timediff_t */ #include "asyn.h" #ifdef HAVE_SETJMP_H #include #endif #ifdef NETWARE #undef in_addr_t #define in_addr_t unsigned long #endif /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer * required for storing all possible aliases and IP numbers is according to * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes! */ #define CURL_HOSTENT_SIZE 9000 #define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this many seconds for a name resolve */ #define CURL_ASYNC_SUCCESS CURLE_OK struct addrinfo; struct hostent; struct Curl_easy; struct connectdata; /* * Curl_global_host_cache_init() initializes and sets up a global DNS cache. * Global DNS cache is general badness. Do not use. This will be removed in * a future version. Use the share interface instead! * * Returns a struct curl_hash pointer on success, NULL on failure. */ struct curl_hash *Curl_global_host_cache_init(void); struct Curl_dns_entry { Curl_addrinfo *addr; /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */ time_t timestamp; /* use-counter, use Curl_resolv_unlock to release reference */ long inuse; }; /* * Curl_resolv() returns an entry with the info for the specified host * and port. * * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after * use, or we'll leak memory! */ /* return codes */ enum resolve_t { CURLRESOLV_TIMEDOUT = -2, CURLRESOLV_ERROR = -1, CURLRESOLV_RESOLVED = 0, CURLRESOLV_PENDING = 1 }; enum resolve_t Curl_resolv(struct connectdata *conn, const char *hostname, int port, bool allowDOH, struct Curl_dns_entry **dnsentry); enum resolve_t Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **dnsentry, timediff_t timeoutms); #ifdef CURLRES_IPV6 /* * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ bool Curl_ipv6works(struct connectdata *conn); #else #define Curl_ipv6works(x) FALSE #endif /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ bool Curl_ipvalid(struct connectdata *conn); /* * Curl_getaddrinfo() is the generic low-level name resolve API within this * source file. There are several versions of this function - for different * name resolve layers (selected at build-time). They all take this same set * of arguments */ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp); /* unlock a previously resolved dns entry */ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns); /* init a new dns cache and return success */ int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct Curl_easy *data); /* Return # of addresses in a Curl_addrinfo struct */ int Curl_num_addresses(const Curl_addrinfo *addr); #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, GETNAMEINFO_TYPE_ARG2 salen, char *host, GETNAMEINFO_TYPE_ARG46 hostlen, char *serv, GETNAMEINFO_TYPE_ARG46 servlen, GETNAMEINFO_TYPE_ARG7 flags, int line, const char *source); #endif /* IPv4 threadsafe resolve function used for synch and asynch builds */ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect); /* * Curl_addrinfo_callback() is used when we build with any asynch specialty. * Handles end of async request processing. Inserts ai into hostcache when * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async * request completed whether successful or failed. */ CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, Curl_addrinfo *ai); /* * Curl_printable_address() returns a printable version of the 1st address * given in the 'ip' argument. The result will be stored in the buf that is * bufsize bytes big. */ const char *Curl_printable_address(const Curl_addrinfo *ip, char *buf, size_t bufsize); /* * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. * * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after * use, or we'll leak memory! */ struct Curl_dns_entry * Curl_fetch_addr(struct connectdata *conn, const char *hostname, int port); /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. * * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 #else #define CURL_INADDR_NONE INADDR_NONE #endif #ifdef HAVE_SIGSETJMP /* Forward-declaration of variable defined in hostip.c. Beware this * is a global and unique instance. This is used to store the return * address that we can jump back to from inside a signal handler. * This is not thread-safe stuff. */ extern sigjmp_buf curl_jmpenv; #endif /* * Function provided by the resolver backend to set DNS servers to use. */ CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers); /* * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf); /* * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4); /* * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6); /* * Clean off entries from the cache */ void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash); /* * Populate the cache with specified entries from CURLOPT_RESOLVE. */ CURLcode Curl_loadhostpairs(struct Curl_easy *data); CURLcode Curl_resolv_check(struct connectdata *conn, struct Curl_dns_entry **dns); int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *socks); #endif /* HEADER_CURL_HOSTIP_H */ davix-0.8.0/deps/curl/lib/tftp.c0000644000000000000000000012315714121063461015126 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_TFTP #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "tftp.h" #include "progress.h" #include "connect.h" #include "strerror.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" #include "strcase.h" #include "speedcheck.h" #include "select.h" #include "escape.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* RFC2348 allows the block size to be negotiated */ #define TFTP_BLKSIZE_DEFAULT 512 #define TFTP_BLKSIZE_MIN 8 #define TFTP_BLKSIZE_MAX 65464 #define TFTP_OPTION_BLKSIZE "blksize" /* from RFC2349: */ #define TFTP_OPTION_TSIZE "tsize" #define TFTP_OPTION_INTERVAL "timeout" typedef enum { TFTP_MODE_NETASCII = 0, TFTP_MODE_OCTET } tftp_mode_t; typedef enum { TFTP_STATE_START = 0, TFTP_STATE_RX, TFTP_STATE_TX, TFTP_STATE_FIN } tftp_state_t; typedef enum { TFTP_EVENT_NONE = -1, TFTP_EVENT_INIT = 0, TFTP_EVENT_RRQ = 1, TFTP_EVENT_WRQ = 2, TFTP_EVENT_DATA = 3, TFTP_EVENT_ACK = 4, TFTP_EVENT_ERROR = 5, TFTP_EVENT_OACK = 6, TFTP_EVENT_TIMEOUT } tftp_event_t; typedef enum { TFTP_ERR_UNDEF = 0, TFTP_ERR_NOTFOUND, TFTP_ERR_PERM, TFTP_ERR_DISKFULL, TFTP_ERR_ILLEGAL, TFTP_ERR_UNKNOWNID, TFTP_ERR_EXISTS, TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */ /* The remaining error codes are internal to curl */ TFTP_ERR_NONE = -100, TFTP_ERR_TIMEOUT, TFTP_ERR_NORESPONSE } tftp_error_t; typedef struct tftp_packet { unsigned char *data; } tftp_packet_t; typedef struct tftp_state_data { tftp_state_t state; tftp_mode_t mode; tftp_error_t error; tftp_event_t event; struct connectdata *conn; curl_socket_t sockfd; int retries; int retry_time; int retry_max; time_t start_time; time_t max_time; time_t rx_time; unsigned short block; struct Curl_sockaddr_storage local_addr; struct Curl_sockaddr_storage remote_addr; curl_socklen_t remote_addrlen; int rbytes; int sbytes; int blksize; int requested_blksize; tftp_packet_t rpacket; tftp_packet_t spacket; } tftp_state_data_t; /* Forward declarations */ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event); static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event); static CURLcode tftp_connect(struct connectdata *conn, bool *done); static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode tftp_do(struct connectdata *conn, bool *done); static CURLcode tftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode tftp_setup_connection(struct connectdata * conn); static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done); static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done); static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode tftp_translate_code(tftp_error_t error); /* * TFTP protocol handler. */ const struct Curl_handler Curl_handler_tftp = { "TFTP", /* scheme */ tftp_setup_connection, /* setup_connection */ tftp_do, /* do_it */ tftp_done, /* done */ ZERO_NULL, /* do_more */ tftp_connect, /* connect_it */ tftp_multi_statemach, /* connecting */ tftp_doing, /* doing */ tftp_getsock, /* proto_getsock */ tftp_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_TFTP, /* defport */ CURLPROTO_TFTP, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; /********************************************************** * * tftp_set_timeouts - * * Set timeouts based on state machine state. * Use user provided connect timeouts until DATA or ACK * packet is received, then use user-provided transfer timeouts * * **********************************************************/ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; timediff_t timeout_ms; bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); /* Compute drop-dead time */ timeout_ms = Curl_timeleft(state->conn->data, NULL, start); if(timeout_ms < 0) { /* time-out, bail out, go home */ failf(state->conn->data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } if(start) { maxtime = (time_t)(timeout_ms + 500) / 1000; state->max_time = state->start_time + maxtime; /* Set per-block timeout to total */ timeout = maxtime; /* Average restart after 5 seconds */ state->retry_max = (int)timeout/5; if(state->retry_max < 1) /* avoid division by zero below */ state->retry_max = 1; /* Compute the re-start interval to suit the timeout */ state->retry_time = (int)timeout/state->retry_max; if(state->retry_time<1) state->retry_time = 1; } else { if(timeout_ms > 0) maxtime = (time_t)(timeout_ms + 500) / 1000; else maxtime = 3600; state->max_time = state->start_time + maxtime; /* Set per-block timeout to total */ timeout = maxtime; /* Average reposting an ACK after 5 seconds */ state->retry_max = (int)timeout/5; } /* But bound the total number */ if(state->retry_max<3) state->retry_max = 3; if(state->retry_max>50) state->retry_max = 50; /* Compute the re-ACK interval to suit the timeout */ state->retry_time = (int)(timeout/state->retry_max); if(state->retry_time<1) state->retry_time = 1; infof(state->conn->data, "set timeouts for state %d; Total %ld, retry %d maxtry %d\n", (int)state->state, (long)(state->max_time-state->start_time), state->retry_time, state->retry_max); /* init RX time */ time(&state->rx_time); return CURLE_OK; } /********************************************************** * * tftp_set_send_first * * Event handler for the START state * **********************************************************/ static void setpacketevent(tftp_packet_t *packet, unsigned short num) { packet->data[0] = (unsigned char)(num >> 8); packet->data[1] = (unsigned char)(num & 0xff); } static void setpacketblock(tftp_packet_t *packet, unsigned short num) { packet->data[2] = (unsigned char)(num >> 8); packet->data[3] = (unsigned char)(num & 0xff); } static unsigned short getrpacketevent(const tftp_packet_t *packet) { return (unsigned short)((packet->data[0] << 8) | packet->data[1]); } static unsigned short getrpacketblock(const tftp_packet_t *packet) { return (unsigned short)((packet->data[2] << 8) | packet->data[3]); } static size_t Curl_strnlen(const char *string, size_t maxlen) { const char *end = memchr(string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } static const char *tftp_option_get(const char *buf, size_t len, const char **option, const char **value) { size_t loc; loc = Curl_strnlen(buf, len); loc++; /* NULL term */ if(loc >= len) return NULL; *option = buf; loc += Curl_strnlen(buf + loc, len-loc); loc++; /* NULL term */ if(loc > len) return NULL; *value = &buf[strlen(*option) + 1]; return &buf[loc]; } static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, const char *ptr, int len) { const char *tmp = ptr; struct Curl_easy *data = state->conn->data; /* if OACK doesn't contain blksize option, the default (512) must be used */ state->blksize = TFTP_BLKSIZE_DEFAULT; while(tmp < ptr + len) { const char *option, *value; tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value); if(tmp == NULL) { failf(data, "Malformed ACK packet, rejecting"); return CURLE_TFTP_ILLEGAL; } infof(data, "got option=(%s) value=(%s)\n", option, value); if(checkprefix(option, TFTP_OPTION_BLKSIZE)) { long blksize; blksize = strtol(value, NULL, 10); if(!blksize) { failf(data, "invalid blocksize value in OACK packet"); return CURLE_TFTP_ILLEGAL; } if(blksize > TFTP_BLKSIZE_MAX) { failf(data, "%s (%d)", "blksize is larger than max supported", TFTP_BLKSIZE_MAX); return CURLE_TFTP_ILLEGAL; } else if(blksize < TFTP_BLKSIZE_MIN) { failf(data, "%s (%d)", "blksize is smaller than min supported", TFTP_BLKSIZE_MIN); return CURLE_TFTP_ILLEGAL; } else if(blksize > state->requested_blksize) { /* could realloc pkt buffers here, but the spec doesn't call out * support for the server requesting a bigger blksize than the client * requests */ failf(data, "%s (%ld)", "server requested blksize larger than allocated", blksize); return CURLE_TFTP_ILLEGAL; } state->blksize = (int)blksize; infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK", state->blksize, "requested", state->requested_blksize); } else if(checkprefix(option, TFTP_OPTION_TSIZE)) { long tsize = 0; tsize = strtol(value, NULL, 10); infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize); /* tsize should be ignored on upload: Who cares about the size of the remote file? */ if(!data->set.upload) { if(!tsize) { failf(data, "invalid tsize -:%s:- value in OACK packet", value); return CURLE_TFTP_ILLEGAL; } Curl_pgrsSetDownloadSize(data, tsize); } } } return CURLE_OK; } static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize, char *buf, const char *option) { if(( strlen(option) + *csize + 1) > (size_t)state->blksize) return CURLE_TFTP_ILLEGAL; strcpy(buf, option); *csize += strlen(option) + 1; return CURLE_OK; } static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event) { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif state->state = TFTP_STATE_TX; result = tftp_set_timeouts(state); if(result) return result; return tftp_tx(state, event); } static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event) { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif state->state = TFTP_STATE_RX; result = tftp_set_timeouts(state); if(result) return result; return tftp_rx(state, event); } static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) { size_t sbytes; ssize_t senddata; const char *mode = "octet"; char *filename; struct Curl_easy *data = state->conn->data; CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ if(data->set.prefer_ascii) mode = "netascii"; switch(event) { case TFTP_EVENT_INIT: /* Send the first packet out */ case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */ /* Increment the retry counter, quit if over the limit */ state->retries++; if(state->retries>state->retry_max) { state->error = TFTP_ERR_NORESPONSE; state->state = TFTP_STATE_FIN; return result; } if(data->set.upload) { /* If we are uploading, send an WRQ */ setpacketevent(&state->spacket, TFTP_EVENT_WRQ); state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4; if(data->state.infilesize != -1) Curl_pgrsSetUploadSize(data, data->state.infilesize); } else { /* If we are downloading, send an RRQ */ setpacketevent(&state->spacket, TFTP_EVENT_RRQ); } /* As RFC3617 describes the separator slash is not actually part of the file name so we skip the always-present first letter of the path string. */ result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0, &filename, NULL, FALSE); if(result) return result; if(strlen(filename) > (state->blksize - strlen(mode) - 4)) { failf(data, "TFTP file name too long\n"); free(filename); return CURLE_TFTP_ILLEGAL; /* too long file name field */ } msnprintf((char *)state->spacket.data + 2, state->blksize, "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); /* optional addition of TFTP options */ if(!data->set.tftp_no_options) { char buf[64]; /* add tsize option */ if(data->set.upload && (data->state.infilesize != -1)) msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); else strcpy(buf, "0"); /* the destination is large enough */ result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, TFTP_OPTION_TSIZE); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, buf); /* add blksize option */ msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, TFTP_OPTION_BLKSIZE); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, buf); /* add timeout option */ msnprintf(buf, sizeof(buf), "%d", state->retry_time); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, TFTP_OPTION_INTERVAL); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, buf); if(result != CURLE_OK) { failf(data, "TFTP buffer too small for options"); free(filename); return CURLE_TFTP_ILLEGAL; } } /* the typecase for the 3rd argument is mostly for systems that do not have a size_t argument, like older unixes that want an 'int' */ senddata = sendto(state->sockfd, (void *)state->spacket.data, (SEND_TYPE_ARG3)sbytes, 0, state->conn->ip_addr->ai_addr, state->conn->ip_addr->ai_addrlen); if(senddata != (ssize_t)sbytes) { char buffer[STRERROR_LEN]; failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); } free(filename); break; case TFTP_EVENT_OACK: if(data->set.upload) { result = tftp_connect_for_tx(state, event); } else { result = tftp_connect_for_rx(state, event); } break; case TFTP_EVENT_ACK: /* Connected for transmit */ result = tftp_connect_for_tx(state, event); break; case TFTP_EVENT_DATA: /* Connected for receive */ result = tftp_connect_for_rx(state, event); break; case TFTP_EVENT_ERROR: state->state = TFTP_STATE_FIN; break; default: failf(state->conn->data, "tftp_send_first: internal error"); break; } return result; } /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit boundary */ #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff) /********************************************************** * * tftp_rx * * Event handler for the RX state * **********************************************************/ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) { ssize_t sbytes; int rblock; struct Curl_easy *data = state->conn->data; char buffer[STRERROR_LEN]; switch(event) { case TFTP_EVENT_DATA: /* Is this the block we expect? */ rblock = getrpacketblock(&state->rpacket); if(NEXT_BLOCKNUM(state->block) == rblock) { /* This is the expected block. Reset counters and ACK it. */ state->retries = 0; } else if(state->block == rblock) { /* This is the last recently received block again. Log it and ACK it again. */ infof(data, "Received last DATA packet block %d again.\n", rblock); } else { /* totally unexpected, just log it */ infof(data, "Received unexpected DATA packet block %d, expecting block %d\n", rblock, NEXT_BLOCKNUM(state->block)); break; } /* ACK this block. */ state->block = (unsigned short)rblock; setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes < 0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* Check if completed (That is, a less than full packet is received) */ if(state->rbytes < (ssize_t)state->blksize + 4) { state->state = TFTP_STATE_FIN; } else { state->state = TFTP_STATE_RX; } time(&state->rx_time); break; case TFTP_EVENT_OACK: /* ACK option acknowledgement so we can move on to data */ state->block = 0; state->retries = 0; setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes < 0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* we're ready to RX data */ state->state = TFTP_STATE_RX; time(&state->rx_time); break; case TFTP_EVENT_TIMEOUT: /* Increment the retry count and fail if over the limit */ state->retries++; infof(data, "Timeout waiting for block %d ACK. Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries); if(state->retries > state->retry_max) { state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; } else { /* Resend the previous ACK */ sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes<0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } } break; case TFTP_EVENT_ERROR: setpacketevent(&state->spacket, TFTP_EVENT_ERROR); setpacketblock(&state->spacket, state->block); (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* don't bother with the return code, but if the socket is still up we * should be a good TFTP client and let the server know we're done */ state->state = TFTP_STATE_FIN; break; default: failf(data, "%s", "tftp_rx: internal error"); return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for this */ } return CURLE_OK; } /********************************************************** * * tftp_tx * * Event handler for the TX state * **********************************************************/ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) { struct Curl_easy *data = state->conn->data; ssize_t sbytes; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; size_t cb; /* Bytes currently read */ char buffer[STRERROR_LEN]; switch(event) { case TFTP_EVENT_ACK: case TFTP_EVENT_OACK: if(event == TFTP_EVENT_ACK) { /* Ack the packet */ int rblock = getrpacketblock(&state->rpacket); if(rblock != state->block && /* There's a bug in tftpd-hpa that causes it to send us an ack for * 65535 when the block number wraps to 0. So when we're expecting * 0, also accept 65535. See * http://syslinux.zytor.com/archives/2010-September/015253.html * */ !(state->block == 0 && rblock == 65535)) { /* This isn't the expected block. Log it and up the retry counter */ infof(data, "Received ACK for block %d, expecting %d\n", rblock, state->block); state->retries++; /* Bail out if over the maximum */ if(state->retries>state->retry_max) { failf(data, "tftp_tx: giving up waiting for block %d ack", state->block); result = CURLE_SEND_ERROR; } else { /* Re-send the data packet */ sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); result = CURLE_SEND_ERROR; } } return result; } /* This is the expected packet. Reset the counters and send the next block */ time(&state->rx_time); state->block++; } else state->block = 1; /* first data block is 1 when using OACK */ state->retries = 0; setpacketevent(&state->spacket, TFTP_EVENT_DATA); setpacketblock(&state->spacket, state->block); if(state->block > 1 && state->sbytes < state->blksize) { state->state = TFTP_STATE_FIN; return CURLE_OK; } /* TFTP considers data block size < 512 bytes as an end of session. So * in some cases we must wait for additional data to build full (512 bytes) * data block. * */ state->sbytes = 0; state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4; do { result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, &cb); if(result) return result; state->sbytes += (int)cb; state->conn->data->req.upload_fromhere += cb; } while(state->sbytes < state->blksize && cb != 0); sbytes = sendto(state->sockfd, (void *) state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* Update the progress meter */ k->writebytecount += state->sbytes; Curl_pgrsSetUploadCounter(data, k->writebytecount); break; case TFTP_EVENT_TIMEOUT: /* Increment the retry counter and log the timeout */ state->retries++; infof(data, "Timeout waiting for block %d ACK. " " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries); /* Decide if we've had enough */ if(state->retries > state->retry_max) { state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; } else { /* Re-send the data packet */ sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes<0) { failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* since this was a re-send, we remain at the still byte position */ Curl_pgrsSetUploadCounter(data, k->writebytecount); } break; case TFTP_EVENT_ERROR: state->state = TFTP_STATE_FIN; setpacketevent(&state->spacket, TFTP_EVENT_ERROR); setpacketblock(&state->spacket, state->block); (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); /* don't bother with the return code, but if the socket is still up we * should be a good TFTP client and let the server know we're done */ state->state = TFTP_STATE_FIN; break; default: failf(data, "tftp_tx: internal error, event: %i", (int)(event)); break; } return result; } /********************************************************** * * tftp_translate_code * * Translate internal error codes to CURL error codes * **********************************************************/ static CURLcode tftp_translate_code(tftp_error_t error) { CURLcode result = CURLE_OK; if(error != TFTP_ERR_NONE) { switch(error) { case TFTP_ERR_NOTFOUND: result = CURLE_TFTP_NOTFOUND; break; case TFTP_ERR_PERM: result = CURLE_TFTP_PERM; break; case TFTP_ERR_DISKFULL: result = CURLE_REMOTE_DISK_FULL; break; case TFTP_ERR_UNDEF: case TFTP_ERR_ILLEGAL: result = CURLE_TFTP_ILLEGAL; break; case TFTP_ERR_UNKNOWNID: result = CURLE_TFTP_UNKNOWNID; break; case TFTP_ERR_EXISTS: result = CURLE_REMOTE_FILE_EXISTS; break; case TFTP_ERR_NOSUCHUSER: result = CURLE_TFTP_NOSUCHUSER; break; case TFTP_ERR_TIMEOUT: result = CURLE_OPERATION_TIMEDOUT; break; case TFTP_ERR_NORESPONSE: result = CURLE_COULDNT_CONNECT; break; default: result = CURLE_ABORTED_BY_CALLBACK; break; } } else result = CURLE_OK; return result; } /********************************************************** * * tftp_state_machine * * The tftp state machine event dispatcher * **********************************************************/ static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { CURLcode result = CURLE_OK; struct Curl_easy *data = state->conn->data; switch(state->state) { case TFTP_STATE_START: DEBUGF(infof(data, "TFTP_STATE_START\n")); result = tftp_send_first(state, event); break; case TFTP_STATE_RX: DEBUGF(infof(data, "TFTP_STATE_RX\n")); result = tftp_rx(state, event); break; case TFTP_STATE_TX: DEBUGF(infof(data, "TFTP_STATE_TX\n")); result = tftp_tx(state, event); break; case TFTP_STATE_FIN: infof(data, "%s\n", "TFTP finished"); break; default: DEBUGF(infof(data, "STATE: %d\n", state->state)); failf(data, "%s", "Internal state machine error"); result = CURLE_TFTP_ILLEGAL; break; } return result; } /********************************************************** * * tftp_disconnect * * The disconnect callback * **********************************************************/ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection) { tftp_state_data_t *state = conn->proto.tftpc; (void) dead_connection; /* done, free dynamically allocated pkt buffers */ if(state) { Curl_safefree(state->rpacket.data); Curl_safefree(state->spacket.data); free(state); } return CURLE_OK; } /********************************************************** * * tftp_connect * * The connect callback * **********************************************************/ static CURLcode tftp_connect(struct connectdata *conn, bool *done) { tftp_state_data_t *state; int blksize; int need_blksize; blksize = TFTP_BLKSIZE_DEFAULT; state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); if(!state) return CURLE_OUT_OF_MEMORY; /* alloc pkt buffers based on specified blksize */ if(conn->data->set.tftp_blksize) { blksize = (int)conn->data->set.tftp_blksize; if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN) return CURLE_TFTP_ILLEGAL; } need_blksize = blksize; /* default size is the fallback when no OACK is received */ if(need_blksize < TFTP_BLKSIZE_DEFAULT) need_blksize = TFTP_BLKSIZE_DEFAULT; if(!state->rpacket.data) { state->rpacket.data = calloc(1, need_blksize + 2 + 2); if(!state->rpacket.data) return CURLE_OUT_OF_MEMORY; } if(!state->spacket.data) { state->spacket.data = calloc(1, need_blksize + 2 + 2); if(!state->spacket.data) return CURLE_OUT_OF_MEMORY; } /* we don't keep TFTP connections up basically because there's none or very * little gain for UDP */ connclose(conn, "TFTP"); state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; state->state = TFTP_STATE_START; state->error = TFTP_ERR_NONE; state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */ state->requested_blksize = blksize; ((struct sockaddr *)&state->local_addr)->sa_family = (CURL_SA_FAMILY_T)(conn->ip_addr->ai_family); tftp_set_timeouts(state); if(!conn->bits.bound) { /* If not already bound, bind to any interface, random UDP port. If it is * reused or a custom local port was desired, this has already been done! * * We once used the size of the local_addr struct as the third argument * for bind() to better work with IPv6 or whatever size the struct could * have, but we learned that at least Tru64, AIX and IRIX *requires* the * size of that argument to match the exact size of a 'sockaddr_in' struct * when running IPv4-only. * * Therefore we use the size from the address we connected to, which we * assume uses the same IP version and thus hopefully this works for both * IPv4 and IPv6... */ int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, conn->ip_addr->ai_addrlen); if(rc) { char buffer[STRERROR_LEN]; failf(conn->data, "bind() failed; %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_COULDNT_CONNECT; } conn->bits.bound = TRUE; } Curl_pgrsStartNow(conn->data); *done = TRUE; return CURLE_OK; } /********************************************************** * * tftp_done * * The done callback * **********************************************************/ static CURLcode tftp_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; (void)status; /* unused */ (void)premature; /* not used */ if(Curl_pgrsDone(conn)) return CURLE_ABORTED_BY_CALLBACK; /* If we have encountered an error */ if(state) result = tftp_translate_code(state->error); return result; } /********************************************************** * * tftp_getsock * * The getsock callback * **********************************************************/ static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks) { socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_READSOCK(0); } /********************************************************** * * tftp_receive_packet * * Called once select fires and data is ready on the socket * **********************************************************/ static CURLcode tftp_receive_packet(struct connectdata *conn) { struct Curl_sockaddr_storage fromaddr; curl_socklen_t fromlen; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; struct SingleRequest *k = &data->req; /* Receive the packet */ fromlen = sizeof(fromaddr); state->rbytes = (int)recvfrom(state->sockfd, (void *)state->rpacket.data, state->blksize + 4, 0, (struct sockaddr *)&fromaddr, &fromlen); if(state->remote_addrlen == 0) { memcpy(&state->remote_addr, &fromaddr, fromlen); state->remote_addrlen = fromlen; } /* Sanity check packet length */ if(state->rbytes < 4) { failf(data, "Received too short packet"); /* Not a timeout, but how best to handle it? */ state->event = TFTP_EVENT_TIMEOUT; } else { /* The event is given by the TFTP packet time */ unsigned short event = getrpacketevent(&state->rpacket); state->event = (tftp_event_t)event; switch(state->event) { case TFTP_EVENT_DATA: /* Don't pass to the client empty or retransmitted packets */ if(state->rbytes > 4 && (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) { result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)state->rpacket.data + 4, state->rbytes-4); if(result) { tftp_state_machine(state, TFTP_EVENT_ERROR); return result; } k->bytecount += state->rbytes-4; Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount); } break; case TFTP_EVENT_ERROR: { unsigned short error = getrpacketblock(&state->rpacket); char *str = (char *)state->rpacket.data + 4; size_t strn = state->rbytes - 4; state->error = (tftp_error_t)error; if(Curl_strnlen(str, strn) < strn) infof(data, "TFTP error: %s\n", str); break; } case TFTP_EVENT_ACK: break; case TFTP_EVENT_OACK: result = tftp_parse_option_ack(state, (const char *)state->rpacket.data + 2, state->rbytes-2); if(result) return result; break; case TFTP_EVENT_RRQ: case TFTP_EVENT_WRQ: default: failf(data, "%s", "Internal error: Unexpected packet"); break; } /* Update the progress meter */ if(Curl_pgrsUpdate(conn)) { tftp_state_machine(state, TFTP_EVENT_ERROR); return CURLE_ABORTED_BY_CALLBACK; } } return result; } /********************************************************** * * tftp_state_timeout * * Check if timeouts have been reached * **********************************************************/ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) { time_t current; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; if(event) *event = TFTP_EVENT_NONE; time(¤t); if(current > state->max_time) { DEBUGF(infof(conn->data, "timeout: %ld > %ld\n", (long)current, (long)state->max_time)); state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; return 0; } if(current > state->rx_time + state->retry_time) { if(event) *event = TFTP_EVENT_TIMEOUT; time(&state->rx_time); /* update even though we received nothing */ } /* there's a typecast below here since 'time_t' may in fact be larger than 'long', but we estimate that a 'long' will still be able to hold number of seconds even if "only" 32 bit */ return (long)(state->max_time - current); } /********************************************************** * * tftp_multi_statemach * * Handle single RX socket event and return * **********************************************************/ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) { tftp_event_t event; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; long timeout_ms = tftp_state_timeout(conn, &event); *done = FALSE; if(timeout_ms <= 0) { failf(data, "TFTP response timeout"); return CURLE_OPERATION_TIMEDOUT; } if(event != TFTP_EVENT_NONE) { result = tftp_state_machine(state, event); if(result) return result; *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(data, -1, -1, FALSE, -1); } else { /* no timeouts to handle, check our socket */ int rc = SOCKET_READABLE(state->sockfd, 0); if(rc == -1) { /* bail out */ int error = SOCKERRNO; char buffer[STRERROR_LEN]; failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer))); state->event = TFTP_EVENT_ERROR; } else if(rc != 0) { result = tftp_receive_packet(conn); if(result) return result; result = tftp_state_machine(state, state->event); if(result) return result; *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(data, -1, -1, FALSE, -1); } /* if rc == 0, then select() timed out */ } return result; } /********************************************************** * * tftp_doing * * Called from multi.c while DOing * **********************************************************/ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result; result = tftp_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } else if(!result) { /* The multi code doesn't have this logic for the DOING state so we provide it for TFTP since it may do the entire transfer in this state. */ if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(conn->data, Curl_now()); } return result; } /********************************************************** * * tftp_peform * * Entry point for transfer from tftp_do, sarts state mach * **********************************************************/ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; *dophase_done = FALSE; result = tftp_state_machine(state, TFTP_EVENT_INIT); if((state->state == TFTP_STATE_FIN) || result) return result; tftp_multi_statemach(conn, dophase_done); if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); return result; } /********************************************************** * * tftp_do * * The do callback * * This callback initiates the TFTP transfer * **********************************************************/ static CURLcode tftp_do(struct connectdata *conn, bool *done) { tftp_state_data_t *state; CURLcode result; *done = FALSE; if(!conn->proto.tftpc) { result = tftp_connect(conn, done); if(result) return result; } state = (tftp_state_data_t *)conn->proto.tftpc; if(!state) return CURLE_TFTP_ILLEGAL; result = tftp_perform(conn, done); /* If tftp_perform() returned an error, use that for return code. If it was OK, see if tftp_translate_code() has an error. */ if(!result) /* If we have encountered an internal tftp error, translate it. */ result = tftp_translate_code(state->error); return result; } static CURLcode tftp_setup_connection(struct connectdata * conn) { struct Curl_easy *data = conn->data; char *type; conn->transport = TRNSPRT_UDP; /* TFTP URLs support an extension like ";mode=" that * we'll try to get now! */ type = strstr(data->state.up.path, ";mode="); if(!type) type = strstr(conn->host.rawalloc, ";mode="); if(type) { char command; *type = 0; /* it was in the middle of the hostname */ command = Curl_raw_toupper(type[6]); switch(command) { case 'A': /* ASCII mode */ case 'N': /* NETASCII mode */ data->set.prefer_ascii = TRUE; break; case 'O': /* octet mode */ case 'I': /* binary mode */ default: /* switch off ASCII */ data->set.prefer_ascii = FALSE; break; } } return CURLE_OK; } #endif davix-0.8.0/deps/curl/lib/easyif.h0000644000000000000000000000237614121063461015435 0ustar rootroot#ifndef HEADER_CURL_EASYIF_H #define HEADER_CURL_EASYIF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Prototypes for library-wide functions provided by easy.c */ #ifdef CURLDEBUG CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); #endif #endif /* HEADER_CURL_EASYIF_H */ davix-0.8.0/deps/curl/lib/mprintf.c0000644000000000000000000007335114121063461015630 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1999 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * * Purpose: * A merge of Bjorn Reese's format() function and Daniel's dsprintf() * 1.0. A full blooded printf() clone with full support for $ * everywhere (parameters, widths and precisions) including variabled * sized parameters (like doubles, long longs, long doubles and even * void * in 64-bit architectures). * * Current restrictions: * - Max 128 parameters * - No 'long double' support. * * If you ever want truly portable and good *printf() clones, the project that * took on from here is named 'Trio' and you find more details on the trio web * page at https://daniel.haxx.se/projects/trio/ */ #include "curl_setup.h" #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * If SIZEOF_SIZE_T has not been defined, default to the size of long. */ #ifdef HAVE_LONGLONG # define LONG_LONG_TYPE long long # define HAVE_LONG_LONG_TYPE #else # if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) # define LONG_LONG_TYPE __int64 # define HAVE_LONG_LONG_TYPE # else # undef LONG_LONG_TYPE # undef HAVE_LONG_LONG_TYPE # endif #endif /* * Non-ANSI integer extensions */ #if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \ (defined(__WATCOMC__) && defined(__386__)) || \ (defined(__POCC__) && defined(_MSC_VER)) || \ (defined(_WIN32_WCE)) || \ (defined(__MINGW32__)) || \ (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)) # define MP_HAVE_INT_EXTENSIONS #endif /* * Max integer data types that mprintf.c is capable */ #ifdef HAVE_LONG_LONG_TYPE # define mp_intmax_t LONG_LONG_TYPE # define mp_uintmax_t unsigned LONG_LONG_TYPE #else # define mp_intmax_t long # define mp_uintmax_t unsigned long #endif #define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should fit negative DBL_MAX (317 letters) */ #define MAX_PARAMETERS 128 /* lame static limit */ #ifdef __AMIGA__ # undef FORMAT_INT #endif /* Lower-case digits. */ static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; /* Upper-case digits. */ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; #define OUTCHAR(x) \ do{ \ if(stream((unsigned char)(x), (FILE *)data) != -1) \ done++; \ else \ return done; /* return immediately on failure */ \ } while(0) /* Data type to read from the arglist */ typedef enum { FORMAT_UNKNOWN = 0, FORMAT_STRING, FORMAT_PTR, FORMAT_INT, FORMAT_INTPTR, FORMAT_LONG, FORMAT_LONGLONG, FORMAT_DOUBLE, FORMAT_LONGDOUBLE, FORMAT_WIDTH /* For internal use */ } FormatType; /* conversion and display flags */ enum { FLAGS_NEW = 0, FLAGS_SPACE = 1<<0, FLAGS_SHOWSIGN = 1<<1, FLAGS_LEFT = 1<<2, FLAGS_ALT = 1<<3, FLAGS_SHORT = 1<<4, FLAGS_LONG = 1<<5, FLAGS_LONGLONG = 1<<6, FLAGS_LONGDOUBLE = 1<<7, FLAGS_PAD_NIL = 1<<8, FLAGS_UNSIGNED = 1<<9, FLAGS_OCTAL = 1<<10, FLAGS_HEX = 1<<11, FLAGS_UPPER = 1<<12, FLAGS_WIDTH = 1<<13, /* '*' or '*$' used */ FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */ FLAGS_PREC = 1<<15, /* precision was specified */ FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ FLAGS_CHAR = 1<<17, /* %c story */ FLAGS_FLOATE = 1<<18, /* %e or %E */ FLAGS_FLOATG = 1<<19 /* %g or %G */ }; typedef struct { FormatType type; int flags; long width; /* width OR width parameter number */ long precision; /* precision OR precision parameter number */ union { char *str; void *ptr; union { mp_intmax_t as_signed; mp_uintmax_t as_unsigned; } num; double dnum; } data; } va_stack_t; struct nsprintf { char *buffer; size_t length; size_t max; }; struct asprintf { char *buffer; /* allocated buffer */ size_t len; /* length of string */ size_t alloc; /* length of alloc */ int fail; /* (!= 0) if an alloc has failed and thus the output is not the complete data */ }; static long dprintf_DollarString(char *input, char **end) { int number = 0; while(ISDIGIT(*input)) { number *= 10; number += *input-'0'; input++; } if(number && ('$'==*input++)) { *end = input; return number; } return 0; } static bool dprintf_IsQualifierNoDollar(const char *fmt) { #if defined(MP_HAVE_INT_EXTENSIONS) if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) { return TRUE; } #endif switch(*fmt) { case '-': case '+': case ' ': case '#': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'h': case 'l': case 'L': case 'z': case 'q': case '*': case 'O': #if defined(MP_HAVE_INT_EXTENSIONS) case 'I': #endif return TRUE; default: return FALSE; } } /****************************************************************** * * Pass 1: * Create an index with the type of each parameter entry and its * value (may vary in size) * * Returns zero on success. * ******************************************************************/ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, va_list arglist) { char *fmt = (char *)format; int param_num = 0; long this_param; long width; long precision; int flags; long max_param = 0; long i; while(*fmt) { if(*fmt++ == '%') { if(*fmt == '%') { fmt++; continue; /* while */ } flags = FLAGS_NEW; /* Handle the positional case (N$) */ param_num++; this_param = dprintf_DollarString(fmt, &fmt); if(0 == this_param) /* we got no positional, get the next counter */ this_param = param_num; if(this_param > max_param) max_param = this_param; /* * The parameter with number 'i' should be used. Next, we need * to get SIZE and TYPE of the parameter. Add the information * to our array. */ width = 0; precision = 0; /* Handle the flags */ while(dprintf_IsQualifierNoDollar(fmt)) { #if defined(MP_HAVE_INT_EXTENSIONS) if(!strncmp(fmt, "I32", 3)) { flags |= FLAGS_LONG; fmt += 3; } else if(!strncmp(fmt, "I64", 3)) { flags |= FLAGS_LONGLONG; fmt += 3; } else #endif switch(*fmt++) { case ' ': flags |= FLAGS_SPACE; break; case '+': flags |= FLAGS_SHOWSIGN; break; case '-': flags |= FLAGS_LEFT; flags &= ~FLAGS_PAD_NIL; break; case '#': flags |= FLAGS_ALT; break; case '.': if('*' == *fmt) { /* The precision is picked from a specified parameter */ flags |= FLAGS_PRECPARAM; fmt++; param_num++; i = dprintf_DollarString(fmt, &fmt); if(i) precision = i; else precision = param_num; if(precision > max_param) max_param = precision; } else { flags |= FLAGS_PREC; precision = strtol(fmt, &fmt, 10); } break; case 'h': flags |= FLAGS_SHORT; break; #if defined(MP_HAVE_INT_EXTENSIONS) case 'I': #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; #endif break; #endif case 'l': if(flags & FLAGS_LONG) flags |= FLAGS_LONGLONG; else flags |= FLAGS_LONG; break; case 'L': flags |= FLAGS_LONGDOUBLE; break; case 'q': flags |= FLAGS_LONGLONG; break; case 'z': /* the code below generates a warning if -Wunreachable-code is used */ #if (SIZEOF_SIZE_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; #endif break; case 'O': #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) flags |= FLAGS_LONGLONG; #else flags |= FLAGS_LONG; #endif break; case '0': if(!(flags & FLAGS_LEFT)) flags |= FLAGS_PAD_NIL; /* FALLTHROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': flags |= FLAGS_WIDTH; width = strtol(fmt-1, &fmt, 10); break; case '*': /* Special case */ flags |= FLAGS_WIDTHPARAM; param_num++; i = dprintf_DollarString(fmt, &fmt); if(i) width = i; else width = param_num; if(width > max_param) max_param = width; break; default: break; } } /* switch */ /* Handle the specifier */ i = this_param - 1; if((i < 0) || (i >= MAX_PARAMETERS)) /* out of allowed range */ return 1; switch (*fmt) { case 'S': flags |= FLAGS_ALT; /* FALLTHROUGH */ case 's': vto[i].type = FORMAT_STRING; break; case 'n': vto[i].type = FORMAT_INTPTR; break; case 'p': vto[i].type = FORMAT_PTR; break; case 'd': case 'i': vto[i].type = FORMAT_INT; break; case 'u': vto[i].type = FORMAT_INT; flags |= FLAGS_UNSIGNED; break; case 'o': vto[i].type = FORMAT_INT; flags |= FLAGS_OCTAL; break; case 'x': vto[i].type = FORMAT_INT; flags |= FLAGS_HEX|FLAGS_UNSIGNED; break; case 'X': vto[i].type = FORMAT_INT; flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; break; case 'c': vto[i].type = FORMAT_INT; flags |= FLAGS_CHAR; break; case 'f': vto[i].type = FORMAT_DOUBLE; break; case 'e': vto[i].type = FORMAT_DOUBLE; flags |= FLAGS_FLOATE; break; case 'E': vto[i].type = FORMAT_DOUBLE; flags |= FLAGS_FLOATE|FLAGS_UPPER; break; case 'g': vto[i].type = FORMAT_DOUBLE; flags |= FLAGS_FLOATG; break; case 'G': vto[i].type = FORMAT_DOUBLE; flags |= FLAGS_FLOATG|FLAGS_UPPER; break; default: vto[i].type = FORMAT_UNKNOWN; break; } /* switch */ vto[i].flags = flags; vto[i].width = width; vto[i].precision = precision; if(flags & FLAGS_WIDTHPARAM) { /* we have the width specified from a parameter, so we make that parameter's info setup properly */ long k = width - 1; vto[i].width = k; vto[k].type = FORMAT_WIDTH; vto[k].flags = FLAGS_NEW; /* can't use width or precision of width! */ vto[k].width = 0; vto[k].precision = 0; } if(flags & FLAGS_PRECPARAM) { /* we have the precision specified from a parameter, so we make that parameter's info setup properly */ long k = precision - 1; vto[i].precision = k; vto[k].type = FORMAT_WIDTH; vto[k].flags = FLAGS_NEW; /* can't use width or precision of width! */ vto[k].width = 0; vto[k].precision = 0; } *endpos++ = fmt + 1; /* end of this sequence */ } } /* Read the arg list parameters into our data list */ for(i = 0; i$ sequence */ param = dprintf_DollarString(f, &f); if(!param) param = param_num; else --param; param_num++; /* increase this always to allow "%2$s %1$s %s" and then the third %s will pick the 3rd argument */ p = &vto[param]; /* pick up the specified width */ if(p->flags & FLAGS_WIDTHPARAM) { width = (long)vto[p->width].data.num.as_signed; param_num++; /* since the width is extracted from a parameter, we must skip that to get to the next one properly */ if(width < 0) { /* "A negative field width is taken as a '-' flag followed by a positive field width." */ width = -width; p->flags |= FLAGS_LEFT; p->flags &= ~FLAGS_PAD_NIL; } } else width = p->width; /* pick up the specified precision */ if(p->flags & FLAGS_PRECPARAM) { prec = (long)vto[p->precision].data.num.as_signed; param_num++; /* since the precision is extracted from a parameter, we must skip that to get to the next one properly */ if(prec < 0) /* "A negative precision is taken as if the precision were omitted." */ prec = -1; } else if(p->flags & FLAGS_PREC) prec = p->precision; else prec = -1; is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; switch(p->type) { case FORMAT_INT: num = p->data.num.as_unsigned; if(p->flags & FLAGS_CHAR) { /* Character. */ if(!(p->flags & FLAGS_LEFT)) while(--width > 0) OUTCHAR(' '); OUTCHAR((char) num); if(p->flags & FLAGS_LEFT) while(--width > 0) OUTCHAR(' '); break; } if(p->flags & FLAGS_OCTAL) { /* Octal unsigned integer. */ base = 8; goto unsigned_number; } else if(p->flags & FLAGS_HEX) { /* Hexadecimal unsigned integer. */ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; base = 16; goto unsigned_number; } else if(p->flags & FLAGS_UNSIGNED) { /* Decimal unsigned integer. */ base = 10; goto unsigned_number; } /* Decimal integer. */ base = 10; is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0; if(is_neg) { /* signed_num might fail to hold absolute negative minimum by 1 */ signed_num = p->data.num.as_signed + (mp_intmax_t)1; signed_num = -signed_num; num = (mp_uintmax_t)signed_num; num += (mp_uintmax_t)1; } goto number; unsigned_number: /* Unsigned number of base BASE. */ is_neg = 0; number: /* Number of base BASE. */ /* Supply a default precision if none was given. */ if(prec == -1) prec = 1; /* Put the number in WORK. */ w = workend; while(num > 0) { *w-- = digits[num % base]; num /= base; } width -= (long)(workend - w); prec -= (long)(workend - w); if(is_alt && base == 8 && prec <= 0) { *w-- = '0'; --width; } if(prec > 0) { width -= prec; while(prec-- > 0) *w-- = '0'; } if(is_alt && base == 16) width -= 2; if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) --width; if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) while(width-- > 0) OUTCHAR(' '); if(is_neg) OUTCHAR('-'); else if(p->flags & FLAGS_SHOWSIGN) OUTCHAR('+'); else if(p->flags & FLAGS_SPACE) OUTCHAR(' '); if(is_alt && base == 16) { OUTCHAR('0'); if(p->flags & FLAGS_UPPER) OUTCHAR('X'); else OUTCHAR('x'); } if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) while(width-- > 0) OUTCHAR('0'); /* Write the number. */ while(++w <= workend) { OUTCHAR(*w); } if(p->flags & FLAGS_LEFT) while(width-- > 0) OUTCHAR(' '); break; case FORMAT_STRING: /* String. */ { static const char null[] = "(nil)"; const char *str; size_t len; str = (char *) p->data.str; if(str == NULL) { /* Write null[] if there's space. */ if(prec == -1 || prec >= (long) sizeof(null) - 1) { str = null; len = sizeof(null) - 1; /* Disable quotes around (nil) */ p->flags &= (~FLAGS_ALT); } else { str = ""; len = 0; } } else if(prec != -1) len = (size_t)prec; else len = strlen(str); width -= (len > LONG_MAX) ? LONG_MAX : (long)len; if(p->flags & FLAGS_ALT) OUTCHAR('"'); if(!(p->flags&FLAGS_LEFT)) while(width-- > 0) OUTCHAR(' '); for(; len && *str; len--) OUTCHAR(*str++); if(p->flags&FLAGS_LEFT) while(width-- > 0) OUTCHAR(' '); if(p->flags & FLAGS_ALT) OUTCHAR('"'); } break; case FORMAT_PTR: /* Generic pointer. */ { void *ptr; ptr = (void *) p->data.ptr; if(ptr != NULL) { /* If the pointer is not NULL, write it as a %#x spec. */ base = 16; digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; is_alt = 1; num = (size_t) ptr; is_neg = 0; goto number; } else { /* Write "(nil)" for a nil pointer. */ static const char strnil[] = "(nil)"; const char *point; width -= (long)(sizeof(strnil) - 1); if(p->flags & FLAGS_LEFT) while(width-- > 0) OUTCHAR(' '); for(point = strnil; *point != '\0'; ++point) OUTCHAR(*point); if(! (p->flags & FLAGS_LEFT)) while(width-- > 0) OUTCHAR(' '); } } break; case FORMAT_DOUBLE: { char formatbuf[32]="%"; char *fptr = &formatbuf[1]; size_t left = sizeof(formatbuf)-strlen(formatbuf); int len; width = -1; if(p->flags & FLAGS_WIDTH) width = p->width; else if(p->flags & FLAGS_WIDTHPARAM) width = (long)vto[p->width].data.num.as_signed; prec = -1; if(p->flags & FLAGS_PREC) prec = p->precision; else if(p->flags & FLAGS_PRECPARAM) prec = (long)vto[p->precision].data.num.as_signed; if(p->flags & FLAGS_LEFT) *fptr++ = '-'; if(p->flags & FLAGS_SHOWSIGN) *fptr++ = '+'; if(p->flags & FLAGS_SPACE) *fptr++ = ' '; if(p->flags & FLAGS_ALT) *fptr++ = '#'; *fptr = 0; if(width >= 0) { if(width >= (long)sizeof(work)) width = sizeof(work)-1; /* RECURSIVE USAGE */ len = curl_msnprintf(fptr, left, "%ld", width); fptr += len; left -= len; } if(prec >= 0) { /* for each digit in the integer part, we can have one less precision */ size_t maxprec = sizeof(work) - 2; double val = p->data.dnum; while(val >= 10.0) { val /= 10; maxprec--; } if(prec > (long)maxprec) prec = (long)maxprec-1; /* RECURSIVE USAGE */ len = curl_msnprintf(fptr, left, ".%ld", prec); fptr += len; } if(p->flags & FLAGS_LONG) *fptr++ = 'l'; if(p->flags & FLAGS_FLOATE) *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e'); else if(p->flags & FLAGS_FLOATG) *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g'); else *fptr++ = 'f'; *fptr = 0; /* and a final zero termination */ /* NOTE NOTE NOTE!! Not all sprintf implementations return number of output characters */ (sprintf)(work, formatbuf, p->data.dnum); DEBUGASSERT(strlen(work) <= sizeof(work)); for(fptr = work; *fptr; fptr++) OUTCHAR(*fptr); } break; case FORMAT_INTPTR: /* Answer the count of characters written. */ #ifdef HAVE_LONG_LONG_TYPE if(p->flags & FLAGS_LONGLONG) *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done; else #endif if(p->flags & FLAGS_LONG) *(long *) p->data.ptr = (long)done; else if(!(p->flags & FLAGS_SHORT)) *(int *) p->data.ptr = (int)done; else *(short *) p->data.ptr = (short)done; break; default: break; } f = *end++; /* goto end of %-code */ } return done; } /* fputc() look-alike */ static int addbyter(int output, FILE *data) { struct nsprintf *infop = (struct nsprintf *)data; unsigned char outc = (unsigned char)output; if(infop->length < infop->max) { /* only do this if we haven't reached max length yet */ infop->buffer[0] = outc; /* store */ infop->buffer++; /* increase pointer */ infop->length++; /* we are now one byte larger */ return outc; /* fputc() returns like this on success */ } return -1; } int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list ap_save) { int retcode; struct nsprintf info; info.buffer = buffer; info.length = 0; info.max = maxlength; retcode = dprintf_formatf(&info, addbyter, format, ap_save); if((retcode != -1) && info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) /* we're at maximum, scrap the last letter */ info.buffer[-1] = 0; else info.buffer[0] = 0; } return retcode; } int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) { int retcode; va_list ap_save; /* argument pointer */ va_start(ap_save, format); retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save); va_end(ap_save); return retcode; } /* fputc() look-alike */ static int alloc_addbyter(int output, FILE *data) { struct asprintf *infop = (struct asprintf *)data; unsigned char outc = (unsigned char)output; if(!infop->buffer) { infop->buffer = malloc(32); if(!infop->buffer) { infop->fail = 1; return -1; /* fail */ } infop->alloc = 32; infop->len = 0; } else if(infop->len + 1 >= infop->alloc) { char *newptr = NULL; size_t newsize = infop->alloc*2; /* detect wrap-around or other overflow problems */ if(newsize > infop->alloc) newptr = realloc(infop->buffer, newsize); if(!newptr) { infop->fail = 1; return -1; /* fail */ } infop->buffer = newptr; infop->alloc = newsize; } infop->buffer[ infop->len ] = outc; infop->len++; return outc; /* fputc() returns like this on success */ } char *curl_maprintf(const char *format, ...) { va_list ap_save; /* argument pointer */ int retcode; struct asprintf info; info.buffer = NULL; info.len = 0; info.alloc = 0; info.fail = 0; va_start(ap_save, format); retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); va_end(ap_save); if((-1 == retcode) || info.fail) { if(info.alloc) free(info.buffer); return NULL; } if(info.alloc) { info.buffer[info.len] = 0; /* we terminate this with a zero byte */ return info.buffer; } return strdup(""); } char *curl_mvaprintf(const char *format, va_list ap_save) { int retcode; struct asprintf info; info.buffer = NULL; info.len = 0; info.alloc = 0; info.fail = 0; retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); if((-1 == retcode) || info.fail) { if(info.alloc) free(info.buffer); return NULL; } if(info.alloc) { info.buffer[info.len] = 0; /* we terminate this with a zero byte */ return info.buffer; } return strdup(""); } static int storebuffer(int output, FILE *data) { char **buffer = (char **)data; unsigned char outc = (unsigned char)output; **buffer = outc; (*buffer)++; return outc; /* act like fputc() ! */ } int curl_msprintf(char *buffer, const char *format, ...) { va_list ap_save; /* argument pointer */ int retcode; va_start(ap_save, format); retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); va_end(ap_save); *buffer = 0; /* we terminate this with a zero byte */ return retcode; } int curl_mprintf(const char *format, ...) { int retcode; va_list ap_save; /* argument pointer */ va_start(ap_save, format); retcode = dprintf_formatf(stdout, fputc, format, ap_save); va_end(ap_save); return retcode; } int curl_mfprintf(FILE *whereto, const char *format, ...) { int retcode; va_list ap_save; /* argument pointer */ va_start(ap_save, format); retcode = dprintf_formatf(whereto, fputc, format, ap_save); va_end(ap_save); return retcode; } int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) { int retcode; retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); *buffer = 0; /* we terminate this with a zero byte */ return retcode; } int curl_mvprintf(const char *format, va_list ap_save) { return dprintf_formatf(stdout, fputc, format, ap_save); } int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) { return dprintf_formatf(whereto, fputc, format, ap_save); } davix-0.8.0/deps/curl/lib/arpa_telnet.h0000644000000000000000000000776114121063461016456 0ustar rootroot#ifndef HEADER_CURL_ARPA_TELNET_H #define HEADER_CURL_ARPA_TELNET_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_TELNET /* * Telnet option defines. Add more here if in need. */ #define CURL_TELOPT_BINARY 0 /* binary 8bit data */ #define CURL_TELOPT_ECHO 1 /* just echo! */ #define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */ #define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ #define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ #define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */ #define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ #define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */ #define CURL_NEW_ENV_VAR 0 #define CURL_NEW_ENV_VALUE 1 #ifndef CURL_DISABLE_VERBOSE_STRINGS /* * The telnet options represented as strings */ static const char * const telnetoptions[]= { "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS", "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON" }; #endif #define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON #define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM) #define CURL_TELOPT(x) telnetoptions[x] #define CURL_NTELOPTS 40 /* * First some defines */ #define CURL_xEOF 236 /* End Of File */ #define CURL_SE 240 /* Sub negotiation End */ #define CURL_NOP 241 /* No OPeration */ #define CURL_DM 242 /* Data Mark */ #define CURL_GA 249 /* Go Ahead, reverse the line */ #define CURL_SB 250 /* SuBnegotiation */ #define CURL_WILL 251 /* Our side WILL use this option */ #define CURL_WONT 252 /* Our side WON'T use this option */ #define CURL_DO 253 /* DO use this option! */ #define CURL_DONT 254 /* DON'T use this option! */ #define CURL_IAC 255 /* Interpret As Command */ #ifndef CURL_DISABLE_VERBOSE_STRINGS /* * Then those numbers represented as strings: */ static const char * const telnetcmds[]= { "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC" }; #endif #define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */ #define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */ #define CURL_TELQUAL_IS 0 #define CURL_TELQUAL_SEND 1 #define CURL_TELQUAL_INFO 2 #define CURL_TELQUAL_NAME 3 #define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \ ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) ) #define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM] #endif /* CURL_DISABLE_TELNET */ #endif /* HEADER_CURL_ARPA_TELNET_H */ davix-0.8.0/deps/curl/lib/vauth/0000755000000000000000000000000014121063461015123 5ustar rootrootdavix-0.8.0/deps/curl/lib/vauth/spnego_sspi.c0000644000000000000000000002735214121063461017631 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC4178 Simple and Protected GSS-API Negotiation Mechanism * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO) #include #include "vauth/vauth.h" #include "urldata.h" #include "curl_base64.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" #include "strerror.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_spnego_supported() * * This is used to evaluate if SPNEGO (Negotiate) is supported. * * Parameters: None * * Returns TRUE if Negotiate is supported by Windows SSPI. */ bool Curl_auth_is_spnego_supported(void) { PSecPkgInfo SecurityPackage; SECURITY_STATUS status; /* Query the security package for Negotiate */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NEGOTIATE), &SecurityPackage); /* Release the package buffer as it is not required anymore */ if(status == SEC_E_OK) { s_pSecFn->FreeContextBuffer(SecurityPackage); } return (status == SEC_E_OK ? TRUE : FALSE); } /* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge * message. * * Parameters: * * data [in] - The session handle. * user [in] - The user name in the format User or Domain\User. * password [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * chlg64 [in] - The optional base64 encoded challenge message. * nego [in/out] - The Negotiate data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *password, const char *service, const char *host, const char *chlg64, struct negotiatedata *nego) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; PSecPkgInfo SecurityPackage; SecBuffer chlg_buf[2]; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif if(nego->context && nego->status == SEC_E_OK) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_auth_cleanup_spnego(nego); return CURLE_LOGIN_DENIED; } if(!nego->spn) { /* Generate our SPN */ nego->spn = Curl_auth_build_spn(service, host, NULL); if(!nego->spn) return CURLE_OUT_OF_MEMORY; } if(!nego->output_token) { /* Query the security package for Negotiate */ nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NEGOTIATE), &SecurityPackage); if(nego->status != SEC_E_OK) return CURLE_NOT_BUILT_IN; nego->token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our output buffer */ nego->output_token = malloc(nego->token_max); if(!nego->output_token) return CURLE_OUT_OF_MEMORY; } if(!nego->credentials) { /* Do we have credentials to use or are we using single sign-on? */ if(user && *user) { /* Populate our identity structure */ result = Curl_create_sspi_identity(user, password, &nego->identity); if(result) return result; /* Allow proper cleanup of the identity structure */ nego->p_identity = &nego->identity; } else /* Use the current Windows user */ nego->p_identity = NULL; /* Allocate our credentials handle */ nego->credentials = calloc(1, sizeof(CredHandle)); if(!nego->credentials) return CURLE_OUT_OF_MEMORY; /* Acquire our credentials handle */ nego->status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)TEXT(SP_NAME_NEGOTIATE), SECPKG_CRED_OUTBOUND, NULL, nego->p_identity, NULL, NULL, nego->credentials, &expiry); if(nego->status != SEC_E_OK) return CURLE_AUTH_ERROR; /* Allocate our new context handle */ nego->context = calloc(1, sizeof(CtxtHandle)); if(!nego->context) return CURLE_OUT_OF_MEMORY; } if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "SPNEGO handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf[0]; chlg_buf[0].BufferType = SECBUFFER_TOKEN; chlg_buf[0].pvBuffer = chlg; chlg_buf[0].cbBuffer = curlx_uztoul(chlglen); #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS /* ssl context comes from Schannel. * When extended protection is used in IIS server, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. * https://docs.microsoft.com/en-us/security-updates * /SecurityAdvisories/2009/973811 */ if(nego->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; SecPkgContext_Bindings pkgBindings; pkgBindings.Bindings = &channelBindings; nego->status = s_pSecFn->QueryContextAttributes( nego->sslContext, SECPKG_ATTR_ENDPOINT_BINDINGS, &pkgBindings ); if(nego->status == SEC_E_OK) { chlg_desc.cBuffers++; chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; chlg_buf[1].cbBuffer = pkgBindings.BindingsLength; chlg_buf[1].pvBuffer = pkgBindings.Bindings; } } #endif } /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = nego->output_token; resp_buf.cbBuffer = curlx_uztoul(nego->token_max); /* Generate our challenge-response message */ nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials, chlg ? nego->context : NULL, nego->spn, ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, nego->context, &resp_desc, &attrs, &expiry); /* Free the decoded challenge as it is not required anymore */ free(chlg); if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "InitializeSecurityContext failed: %s", Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } if(nego->status == SEC_I_COMPLETE_NEEDED || nego->status == SEC_I_COMPLETE_AND_CONTINUE) { nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc); if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "CompleteAuthToken failed: %s", Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } } nego->output_token_length = resp_buf.cbBuffer; return result; } /* * Curl_auth_create_spnego_message() * * This is used to generate an already encoded SPNEGO (Negotiate) response * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * nego [in/out] - The Negotiate data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen) { CURLcode result; /* Base64 encode the already generated response */ result = Curl_base64_encode(data, (const char *) nego->output_token, nego->output_token_length, outptr, outlen); if(result) return result; if(!*outptr || !*outlen) { free(*outptr); return CURLE_REMOTE_ACCESS_DENIED; } return CURLE_OK; } /* * Curl_auth_cleanup_spnego() * * This is used to clean up the SPNEGO (Negotiate) specific data. * * Parameters: * * nego [in/out] - The Negotiate data struct being cleaned up. * */ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) { /* Free our security context */ if(nego->context) { s_pSecFn->DeleteSecurityContext(nego->context); free(nego->context); nego->context = NULL; } /* Free our credentials handle */ if(nego->credentials) { s_pSecFn->FreeCredentialsHandle(nego->credentials); free(nego->credentials); nego->credentials = NULL; } /* Free our identity */ Curl_sspi_free_identity(nego->p_identity); nego->p_identity = NULL; /* Free the SPN and output token */ Curl_safefree(nego->spn); Curl_safefree(nego->output_token); /* Reset any variables */ nego->status = 0; nego->token_max = 0; nego->noauthpersist = FALSE; nego->havenoauthpersist = FALSE; nego->havenegdata = FALSE; nego->havemultiplerequests = FALSE; } #endif /* USE_WINDOWS_SSPI && USE_SPNEGO */ davix-0.8.0/deps/curl/lib/vauth/digest_sspi.c0000644000000000000000000005076114121063461017615 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2016, Steve Holme, . * Copyright (C) 2015 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2831 DIGEST-MD5 authentication * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH) #include #include "vauth/vauth.h" #include "vauth/digest.h" #include "urldata.h" #include "curl_base64.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" #include "strdup.h" #include "strcase.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_digest_supported() * * This is used to evaluate if DIGEST is supported. * * Parameters: None * * Returns TRUE if DIGEST is supported by Windows SSPI. */ bool Curl_auth_is_digest_supported(void) { PSecPkgInfo SecurityPackage; SECURITY_STATUS status; /* Query the security package for Digest */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), &SecurityPackage); /* Release the package buffer as it is not required anymore */ if(status == SEC_E_OK) { s_pSecFn->FreeContextBuffer(SecurityPackage); } return (status == SEC_E_OK ? TRUE : FALSE); } /* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message * ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - The base64 encoded challenge message. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, const char *service, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; TCHAR *spn = NULL; size_t chlglen = 0; size_t token_max = 0; unsigned char *input_token = NULL; unsigned char *output_token = NULL; CredHandle credentials; CtxtHandle context; PSecPkgInfo SecurityPackage; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Decode the base-64 encoded challenge message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &input_token, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!input_token) { infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Query the security package for DigestSSP */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), &SecurityPackage); if(status != SEC_E_OK) { free(input_token); return CURLE_NOT_BUILT_IN; } token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our response buffer */ output_token = malloc(token_max); if(!output_token) { free(input_token); return CURLE_OUT_OF_MEMORY; } /* Generate our SPN */ spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); if(!spn) { free(output_token); free(input_token); return CURLE_OUT_OF_MEMORY; } if(userp && *userp) { /* Populate our identity structure */ result = Curl_create_sspi_identity(userp, passwdp, &identity); if(result) { free(spn); free(output_token); free(input_token); return result; } /* Allow proper cleanup of the identity structure */ p_identity = &identity; } else /* Use the current Windows user */ p_identity = NULL; /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_DIGEST), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, &credentials, &expiry); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); free(spn); free(output_token); free(input_token); return CURLE_LOGIN_DENIED; } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf; chlg_buf.BufferType = SECBUFFER_TOKEN; chlg_buf.pvBuffer = input_token; chlg_buf.cbBuffer = curlx_uztoul(chlglen); /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = output_token; resp_buf.cbBuffer = curlx_uztoul(token_max); /* Generate our response message */ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, 0, 0, 0, &chlg_desc, 0, &context, &resp_desc, &attrs, &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { s_pSecFn->FreeCredentialsHandle(&credentials); Curl_sspi_free_identity(p_identity); free(spn); free(output_token); free(input_token); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, outptr, outlen); /* Free our handles */ s_pSecFn->DeleteSecurityContext(&context); s_pSecFn->FreeCredentialsHandle(&credentials); /* Free the identity structure */ Curl_sspi_free_identity(p_identity); /* Free the SPN */ free(spn); /* Free the response buffer */ free(output_token); /* Free the decoded challenge message */ free(input_token); return result; } /* * Curl_override_sspi_http_realm() * * This is used to populate the domain in a SSPI identity structure * The realm is extracted from the challenge message and used as the * domain if it is not already explicitly set. * * Parameters: * * chlg [in] - The challenge message. * identity [in/out] - The identity structure. * * Returns CURLE_OK on success. */ CURLcode Curl_override_sspi_http_realm(const char *chlg, SEC_WINNT_AUTH_IDENTITY *identity) { xcharp_u domain, dup_domain; /* If domain is blank or unset, check challenge message for realm */ if(!identity->Domain || !identity->DomainLength) { for(;;) { char value[DIGEST_MAX_VALUE_LENGTH]; char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ while(*chlg && ISSPACE(*chlg)) chlg++; /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { if(strcasecompare(value, "realm")) { /* Setup identity's domain and length */ domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); if(!domain.tchar_ptr) return CURLE_OUT_OF_MEMORY; dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); if(!dup_domain.tchar_ptr) { Curl_unicodefree(domain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } free(identity->Domain); identity->Domain = dup_domain.tbyte_ptr; identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); dup_domain.tchar_ptr = NULL; Curl_unicodefree(domain.tchar_ptr); } else { /* Unknown specifier, ignore it! */ } } else break; /* We're done here */ /* Pass all additional spaces here */ while(*chlg && ISSPACE(*chlg)) chlg++; /* Allow the list to be comma-separated */ if(',' == *chlg) chlg++; } } return CURLE_OK; } /* * Curl_auth_decode_digest_http_message() * * This is used to decode a HTTP DIGEST challenge message into the separate * attributes. * * Parameters: * * chlg [in] - The challenge message. * digest [in/out] - The digest data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, struct digestdata *digest) { size_t chlglen = strlen(chlg); /* We had an input token before so if there's another one now that means we provided bad credentials in the previous request or it's stale. */ if(digest->input_token) { bool stale = false; const char *p = chlg; /* Check for the 'stale' directive */ for(;;) { char value[DIGEST_MAX_VALUE_LENGTH]; char content[DIGEST_MAX_CONTENT_LENGTH]; while(*p && ISSPACE(*p)) p++; if(!Curl_auth_digest_get_pair(p, value, content, &p)) break; if(strcasecompare(value, "stale") && strcasecompare(content, "true")) { stale = true; break; } while(*p && ISSPACE(*p)) p++; if(',' == *p) p++; } if(stale) Curl_auth_digest_cleanup(digest); else return CURLE_LOGIN_DENIED; } /* Store the challenge for use later */ digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); if(!digest->input_token) return CURLE_OUT_OF_MEMORY; digest->input_token_len = chlglen; return CURLE_OK; } /* * Curl_auth_create_digest_http_message() * * This is used to generate a HTTP DIGEST response message ready for sending * to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * request [in] - The HTTP request. * uripath [in] - The path of the HTTP uri. * digest [in/out] - The digest data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, const unsigned char *uripath, struct digestdata *digest, char **outptr, size_t *outlen) { size_t token_max; char *resp; BYTE *output_token; size_t output_token_len = 0; PSecPkgInfo SecurityPackage; SecBuffer chlg_buf[5]; SecBufferDesc chlg_desc; SECURITY_STATUS status; (void) data; /* Query the security package for DigestSSP */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), &SecurityPackage); if(status != SEC_E_OK) return CURLE_NOT_BUILT_IN; token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate the output buffer according to the max token size as indicated by the security package */ output_token = malloc(token_max); if(!output_token) { return CURLE_OUT_OF_MEMORY; } /* If the user/passwd that was used to make the identity for http_context has changed then delete that context. */ if((userp && !digest->user) || (!userp && digest->user) || (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || (userp && digest->user && strcmp(userp, digest->user)) || (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { if(digest->http_context) { s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); } Curl_safefree(digest->user); Curl_safefree(digest->passwd); } if(digest->http_context) { chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 5; chlg_desc.pBuffers = chlg_buf; chlg_buf[0].BufferType = SECBUFFER_TOKEN; chlg_buf[0].pvBuffer = NULL; chlg_buf[0].cbBuffer = 0; chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; chlg_buf[1].pvBuffer = (void *) request; chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; chlg_buf[2].pvBuffer = (void *) uripath; chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; chlg_buf[3].pvBuffer = NULL; chlg_buf[3].cbBuffer = 0; chlg_buf[4].BufferType = SECBUFFER_PADDING; chlg_buf[4].pvBuffer = output_token; chlg_buf[4].cbBuffer = curlx_uztoul(token_max); status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); if(status == SEC_E_OK) output_token_len = chlg_buf[4].cbBuffer; else { /* delete the context so a new one can be made */ infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n", (long)status); s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); } } if(!digest->http_context) { CredHandle credentials; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; SecBuffer resp_buf; SecBufferDesc resp_desc; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ TCHAR *spn; /* free the copy of user/passwd used to make the previous identity */ Curl_safefree(digest->user); Curl_safefree(digest->passwd); if(userp && *userp) { /* Populate our identity structure */ if(Curl_create_sspi_identity(userp, passwdp, &identity)) { free(output_token); return CURLE_OUT_OF_MEMORY; } /* Populate our identity domain */ if(Curl_override_sspi_http_realm((const char *) digest->input_token, &identity)) { free(output_token); return CURLE_OUT_OF_MEMORY; } /* Allow proper cleanup of the identity structure */ p_identity = &identity; } else /* Use the current Windows user */ p_identity = NULL; if(userp) { digest->user = strdup(userp); if(!digest->user) { free(output_token); return CURLE_OUT_OF_MEMORY; } } if(passwdp) { digest->passwd = strdup(passwdp); if(!digest->passwd) { free(output_token); Curl_safefree(digest->user); return CURLE_OUT_OF_MEMORY; } } /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_DIGEST), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, &credentials, &expiry); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); free(output_token); return CURLE_LOGIN_DENIED; } /* Setup the challenge "input" security buffer if present */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 3; chlg_desc.pBuffers = chlg_buf; chlg_buf[0].BufferType = SECBUFFER_TOKEN; chlg_buf[0].pvBuffer = digest->input_token; chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; chlg_buf[1].pvBuffer = (void *) request; chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; chlg_buf[2].pvBuffer = NULL; chlg_buf[2].cbBuffer = 0; /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = output_token; resp_buf.cbBuffer = curlx_uztoul(token_max); spn = Curl_convert_UTF8_to_tchar((char *) uripath); if(!spn) { s_pSecFn->FreeCredentialsHandle(&credentials); Curl_sspi_free_identity(p_identity); free(output_token); return CURLE_OUT_OF_MEMORY; } /* Allocate our new context handle */ digest->http_context = calloc(1, sizeof(CtxtHandle)); if(!digest->http_context) return CURLE_OUT_OF_MEMORY; /* Generate our response message */ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, ISC_REQ_USE_HTTP_STYLE, 0, 0, &chlg_desc, 0, digest->http_context, &resp_desc, &attrs, &expiry); Curl_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { s_pSecFn->FreeCredentialsHandle(&credentials); Curl_sspi_free_identity(p_identity); free(output_token); Curl_safefree(digest->http_context); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } output_token_len = resp_buf.cbBuffer; s_pSecFn->FreeCredentialsHandle(&credentials); Curl_sspi_free_identity(p_identity); } resp = malloc(output_token_len + 1); if(!resp) { free(output_token); return CURLE_OUT_OF_MEMORY; } /* Copy the generated response */ memcpy(resp, output_token, output_token_len); resp[output_token_len] = 0; /* Return the response */ *outptr = resp; *outlen = output_token_len; /* Free the response buffer */ free(output_token); return CURLE_OK; } /* * Curl_auth_digest_cleanup() * * This is used to clean up the digest specific data. * * Parameters: * * digest [in/out] - The digest data struct being cleaned up. * */ void Curl_auth_digest_cleanup(struct digestdata *digest) { /* Free the input token */ Curl_safefree(digest->input_token); /* Reset any variables */ digest->input_token_len = 0; /* Delete security context */ if(digest->http_context) { s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); } /* Free the copy of user/passwd used to make the identity for http_context */ Curl_safefree(digest->user); Curl_safefree(digest->passwd); } #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/vauth/krb5_sspi.c0000644000000000000000000004132414121063461017174 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5) #include #include "vauth/vauth.h" #include "urldata.h" #include "curl_base64.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_gssapi_supported() * * This is used to evaluate if GSSAPI (Kerberos V5) is supported. * * Parameters: None * * Returns TRUE if Kerberos V5 is supported by Windows SSPI. */ bool Curl_auth_is_gssapi_supported(void) { PSecPkgInfo SecurityPackage; SECURITY_STATUS status; /* Query the security package for Kerberos */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_KERBEROS), &SecurityPackage); /* Release the package buffer as it is not required anymore */ if(status == SEC_E_OK) { s_pSecFn->FreeContextBuffer(SecurityPackage); } return (status == SEC_E_OK ? TRUE : FALSE); } /* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * mutual_auth [in] - Flag specifying whether or not mutual authentication * is enabled. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *host, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; CtxtHandle context; PSecPkgInfo SecurityPackage; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->spn) { /* Generate our SPN */ krb5->spn = Curl_auth_build_spn(service, host, NULL); if(!krb5->spn) return CURLE_OUT_OF_MEMORY; } if(!krb5->output_token) { /* Query the security package for Kerberos */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_KERBEROS), &SecurityPackage); if(status != SEC_E_OK) { return CURLE_NOT_BUILT_IN; } krb5->token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our response buffer */ krb5->output_token = malloc(krb5->token_max); if(!krb5->output_token) return CURLE_OUT_OF_MEMORY; } if(!krb5->credentials) { /* Do we have credentials to use or are we using single sign-on? */ if(userp && *userp) { /* Populate our identity structure */ result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); if(result) return result; /* Allow proper cleanup of the identity structure */ krb5->p_identity = &krb5->identity; } else /* Use the current Windows user */ krb5->p_identity = NULL; /* Allocate our credentials handle */ krb5->credentials = calloc(1, sizeof(CredHandle)); if(!krb5->credentials) return CURLE_OUT_OF_MEMORY; /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_KERBEROS), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, krb5->credentials, &expiry); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; /* Allocate our new context handle */ krb5->context = calloc(1, sizeof(CtxtHandle)); if(!krb5->context) return CURLE_OUT_OF_MEMORY; } if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf; chlg_buf.BufferType = SECBUFFER_TOKEN; chlg_buf.pvBuffer = chlg; chlg_buf.cbBuffer = curlx_uztoul(chlglen); } /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = krb5->output_token; resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); /* Generate our challenge-response message */ status = s_pSecFn->InitializeSecurityContext(krb5->credentials, chlg ? krb5->context : NULL, krb5->spn, (mutual_auth ? ISC_REQ_MUTUAL_AUTH : 0), 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, &context, &resp_desc, &attrs, &expiry); /* Free the decoded challenge as it is not required anymore */ free(chlg); if(status == SEC_E_INSUFFICIENT_MEMORY) { return CURLE_OUT_OF_MEMORY; } if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { return CURLE_AUTH_ERROR; } if(memcmp(&context, krb5->context, sizeof(context))) { s_pSecFn->DeleteSecurityContext(krb5->context); memcpy(krb5->context, &context, sizeof(context)); } if(resp_buf.cbBuffer) { /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer, resp_buf.cbBuffer, outptr, outlen); } else if(mutual_auth) { *outptr = strdup(""); if(!*outptr) result = CURLE_OUT_OF_MEMORY; } return result; } /* * Curl_auth_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t offset = 0; size_t chlglen = 0; size_t messagelen = 0; size_t appdatalen = 0; unsigned char *chlg = NULL; unsigned char *trailer = NULL; unsigned char *message = NULL; unsigned char *padding = NULL; unsigned char *appdata = NULL; SecBuffer input_buf[2]; SecBuffer wrap_buf[3]; SecBufferDesc input_desc; SecBufferDesc wrap_desc; unsigned long indata = 0; unsigned long outdata = 0; unsigned long qop = 0; unsigned long sec_layer = 0; unsigned long max_size = 0; SecPkgContext_Sizes sizes; SecPkgCredentials_Names names; SECURITY_STATUS status; char *user_name; /* Decode the base-64 encoded input message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty security message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Get our response size information */ status = s_pSecFn->QueryContextAttributes(krb5->context, SECPKG_ATTR_SIZES, &sizes); if(status != SEC_E_OK) { free(chlg); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } /* Get the fully qualified username back from the context */ status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, SECPKG_CRED_ATTR_NAMES, &names); if(status != SEC_E_OK) { free(chlg); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } /* Setup the "input" security buffer */ input_desc.ulVersion = SECBUFFER_VERSION; input_desc.cBuffers = 2; input_desc.pBuffers = input_buf; input_buf[0].BufferType = SECBUFFER_STREAM; input_buf[0].pvBuffer = chlg; input_buf[0].cbBuffer = curlx_uztoul(chlglen); input_buf[1].BufferType = SECBUFFER_DATA; input_buf[1].pvBuffer = NULL; input_buf[1].cbBuffer = 0; /* Decrypt the inbound challenge and obtain the qop */ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); if(status != SEC_E_OK) { infof(data, "GSSAPI handshake failure (empty security message)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(input_buf[1].cbBuffer != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Copy the data out and free the challenge as it is not required anymore */ memcpy(&indata, input_buf[1].pvBuffer, 4); s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); free(chlg); /* Extract the security layer */ sec_layer = indata & 0x000000FF; if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Extract the maximum message size the server can receive */ max_size = ntohl(indata & 0xFFFFFF00); if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server our receive buffer is zero. */ max_size = 0; } /* Allocate the trailer */ trailer = malloc(sizes.cbSecurityTrailer); if(!trailer) return CURLE_OUT_OF_MEMORY; /* Convert the user name to UTF8 when operating with Unicode */ user_name = Curl_convert_tchar_to_UTF8(names.sUserName); if(!user_name) { free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate our message */ messagelen = sizeof(outdata) + strlen(user_name) + 1; message = malloc(messagelen); if(!message) { free(trailer); Curl_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; memcpy(message, &outdata, sizeof(outdata)); strcpy((char *) message + sizeof(outdata), user_name); Curl_unicodefree(user_name); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); if(!padding) { free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Setup the "authentication data" security buffer */ wrap_desc.ulVersion = SECBUFFER_VERSION; wrap_desc.cBuffers = 3; wrap_desc.pBuffers = wrap_buf; wrap_buf[0].BufferType = SECBUFFER_TOKEN; wrap_buf[0].pvBuffer = trailer; wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; wrap_buf[1].BufferType = SECBUFFER_DATA; wrap_buf[1].pvBuffer = message; wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); wrap_buf[2].BufferType = SECBUFFER_PADDING; wrap_buf[2].pvBuffer = padding; wrap_buf[2].cbBuffer = sizes.cbBlockSize; /* Encrypt the data */ status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, &wrap_desc, 0); if(status != SEC_E_OK) { free(padding); free(message); free(trailer); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } /* Allocate the encryption (wrap) buffer */ appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + wrap_buf[2].cbBuffer; appdata = malloc(appdatalen); if(!appdata) { free(padding); free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Populate the encryption buffer */ memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); offset += wrap_buf[0].cbBuffer; memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); offset += wrap_buf[1].cbBuffer; memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr, outlen); /* Free all of our local buffers */ free(appdata); free(padding); free(message); free(trailer); return result; } /* * Curl_auth_cleanup_gssapi() * * This is used to clean up the GSSAPI (Kerberos V5) specific data. * * Parameters: * * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5) { /* Free our security context */ if(krb5->context) { s_pSecFn->DeleteSecurityContext(krb5->context); free(krb5->context); krb5->context = NULL; } /* Free our credentials handle */ if(krb5->credentials) { s_pSecFn->FreeCredentialsHandle(krb5->credentials); free(krb5->credentials); krb5->credentials = NULL; } /* Free our identity */ Curl_sspi_free_identity(krb5->p_identity); krb5->p_identity = NULL; /* Free the SPN and output token */ Curl_safefree(krb5->spn); Curl_safefree(krb5->output_token); /* Reset any variables */ krb5->token_max = 0; } #endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/ davix-0.8.0/deps/curl/lib/vauth/oauth2.c0000644000000000000000000001011614121063461016470 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC6749 OAuth 2.0 Authorization Framework * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ !defined(CURL_DISABLE_POP3) #include #include "urldata.h" #include "vauth/vauth.h" #include "curl_base64.h" #include "warnless.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_create_oauth_bearer_message() * * This is used to generate an already encoded OAuth 2.0 message ready for * sending to the recipient. * * Parameters: * * data[in] - The session handle. * user[in] - The user name. * host[in] - The host name. * port[in] - The port(when not Port 80). * bearer[in] - The bearer token. * outptr[in / out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen[out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *user, const char *host, const long port, const char *bearer, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; char *oauth = NULL; /* Generate the message */ if(port == 0 || port == 80) oauth = aprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host, bearer); else oauth = aprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, host, port, bearer); if(!oauth) return CURLE_OUT_OF_MEMORY; /* Base64 encode the reply */ result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); free(oauth); return result; } /* * Curl_auth_create_xoauth_bearer_message() * * This is used to generate an already encoded XOAuth 2.0 message ready for * sending to the recipient. * * Parameters: * * data[in] - The session handle. * user[in] - The user name. * bearer[in] - The bearer token. * outptr[in / out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen[out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data, const char *user, const char *bearer, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; /* Generate the message */ char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); if(!xoauth) return CURLE_OUT_OF_MEMORY; /* Base64 encode the reply */ result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen); free(xoauth); return result; } #endif /* disabled, no users */ davix-0.8.0/deps/curl/lib/vauth/vauth.c0000644000000000000000000001047614121063461016426 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "vauth.h" #include "curl_multibyte.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_build_spn() * * This is used to build a SPN string in the following formats: * * service/host@realm (Not currently used) * service/host (Not used by GSS-API) * service@realm (Not used by Windows SSPI) * * Parameters: * * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * realm [in] - The realm. * * Returns a pointer to the newly allocated SPN. */ #if !defined(USE_WINDOWS_SSPI) char *Curl_auth_build_spn(const char *service, const char *host, const char *realm) { char *spn = NULL; /* Generate our SPN */ if(host && realm) spn = aprintf("%s/%s@%s", service, host, realm); else if(host) spn = aprintf("%s/%s", service, host); else if(realm) spn = aprintf("%s@%s", service, realm); /* Return our newly allocated SPN */ return spn; } #else TCHAR *Curl_auth_build_spn(const char *service, const char *host, const char *realm) { char *utf8_spn = NULL; TCHAR *tchar_spn = NULL; (void) realm; /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather than doing this ourselves but the first is only available in Windows XP and Windows Server 2003 and the latter is only available in Windows 2000 but not Windows95/98/ME or Windows NT4.0 unless the Active Directory Client Extensions are installed. As such it is far simpler for us to formulate the SPN instead. */ /* Generate our UTF8 based SPN */ utf8_spn = aprintf("%s/%s", service, host); if(!utf8_spn) { return NULL; } /* Allocate our TCHAR based SPN */ tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); if(!tchar_spn) { free(utf8_spn); return NULL; } /* Release the UTF8 variant when operating with Unicode */ Curl_unicodefree(utf8_spn); /* Return our newly allocated SPN */ return tchar_spn; } #endif /* USE_WINDOWS_SSPI */ /* * Curl_auth_user_contains_domain() * * This is used to test if the specified user contains a Windows domain name as * follows: * * Domain\User (Down-level Logon Name) * Domain/User (curl Down-level format - for compatibility with existing code) * User@Domain (User Principal Name) * * Note: The user name may be empty when using a GSS-API library or Windows * SSPI as the user and domain are either obtained from the credentials cache * when using GSS-API or via the currently logged in user's credentials when * using Windows SSPI. * * Parameters: * * user [in] - The user name. * * Returns TRUE on success; otherwise FALSE. */ bool Curl_auth_user_contains_domain(const char *user) { bool valid = FALSE; if(user && *user) { /* Check we have a domain name or UPN present */ char *p = strpbrk(user, "\\/@"); valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : FALSE); } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) else /* User and domain are obtained from the GSS-API credentials cache or the currently logged in user from Windows */ valid = TRUE; #endif return valid; } davix-0.8.0/deps/curl/lib/vauth/spnego_gssapi.c0000644000000000000000000002054514121063461020136 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC4178 Simple and Protected GSS-API Negotiation Mechanism * ***************************************************************************/ #include "curl_setup.h" #if defined(HAVE_GSSAPI) && defined(USE_SPNEGO) #include #include "vauth/vauth.h" #include "urldata.h" #include "curl_base64.h" #include "curl_gssapi.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_spnego_supported() * * This is used to evaluate if SPNEGO (Negotiate) is supported. * * Parameters: None * * Returns TRUE if Negotiate supported by the GSS-API library. */ bool Curl_auth_is_spnego_supported(void) { return TRUE; } /* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge * message. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * chlg64 [in] - The optional base64 encoded challenge message. * nego [in/out] - The Negotiate data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *password, const char *service, const char *host, const char *chlg64, struct negotiatedata *nego) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; OM_uint32 major_status; OM_uint32 minor_status; OM_uint32 unused_status; gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; (void) user; (void) password; if(nego->context && nego->status == GSS_S_COMPLETE) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_auth_cleanup_spnego(nego); return CURLE_LOGIN_DENIED; } if(!nego->spn) { /* Generate our SPN */ char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) return CURLE_OUT_OF_MEMORY; /* Populate the SPN structure */ spn_token.value = spn; spn_token.length = strlen(spn); /* Import the SPN */ major_status = gss_import_name(&minor_status, &spn_token, GSS_C_NT_HOSTBASED_SERVICE, &nego->spn); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_import_name() failed: ", major_status, minor_status); free(spn); return CURLE_AUTH_ERROR; } free(spn); } if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "SPNEGO handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ input_token.value = chlg; input_token.length = chlglen; } /* Generate our challenge-response message */ major_status = Curl_gss_init_sec_context(data, &minor_status, &nego->context, nego->spn, &Curl_spnego_mech_oid, GSS_C_NO_CHANNEL_BINDINGS, &input_token, &output_token, TRUE, NULL); /* Free the decoded challenge as it is not required anymore */ Curl_safefree(input_token.value); nego->status = major_status; if(GSS_ERROR(major_status)) { if(output_token.value) gss_release_buffer(&unused_status, &output_token); Curl_gss_log_error(data, "gss_init_sec_context() failed: ", major_status, minor_status); return CURLE_AUTH_ERROR; } if(!output_token.value || !output_token.length) { if(output_token.value) gss_release_buffer(&unused_status, &output_token); return CURLE_AUTH_ERROR; } /* Free previous token */ if(nego->output_token.length && nego->output_token.value) gss_release_buffer(&unused_status, &nego->output_token); nego->output_token = output_token; return CURLE_OK; } /* * Curl_auth_create_spnego_message() * * This is used to generate an already encoded SPNEGO (Negotiate) response * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * nego [in/out] - The Negotiate data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen) { CURLcode result; OM_uint32 minor_status; /* Base64 encode the already generated response */ result = Curl_base64_encode(data, nego->output_token.value, nego->output_token.length, outptr, outlen); if(result) { gss_release_buffer(&minor_status, &nego->output_token); nego->output_token.value = NULL; nego->output_token.length = 0; return result; } if(!*outptr || !*outlen) { gss_release_buffer(&minor_status, &nego->output_token); nego->output_token.value = NULL; nego->output_token.length = 0; return CURLE_REMOTE_ACCESS_DENIED; } return CURLE_OK; } /* * Curl_auth_cleanup_spnego() * * This is used to clean up the SPNEGO (Negotiate) specific data. * * Parameters: * * nego [in/out] - The Negotiate data struct being cleaned up. * */ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) { OM_uint32 minor_status; /* Free our security context */ if(nego->context != GSS_C_NO_CONTEXT) { gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); nego->context = GSS_C_NO_CONTEXT; } /* Free the output token */ if(nego->output_token.value) { gss_release_buffer(&minor_status, &nego->output_token); nego->output_token.value = NULL; nego->output_token.length = 0; } /* Free the SPN */ if(nego->spn != GSS_C_NO_NAME) { gss_release_name(&minor_status, &nego->spn); nego->spn = GSS_C_NO_NAME; } /* Reset any variables */ nego->status = 0; nego->noauthpersist = FALSE; nego->havenoauthpersist = FALSE; nego->havenegdata = FALSE; nego->havemultiplerequests = FALSE; } #endif /* HAVE_GSSAPI && USE_SPNEGO */ davix-0.8.0/deps/curl/lib/vauth/vauth.h0000644000000000000000000002326114121063461016427 0ustar rootroot#ifndef HEADER_CURL_VAUTH_H #define HEADER_CURL_VAUTH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include struct Curl_easy; #if !defined(CURL_DISABLE_CRYPTO_AUTH) struct digestdata; #endif #if defined(USE_NTLM) struct ntlmdata; #endif #if defined(USE_KERBEROS5) struct kerberos5data; #endif #if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) struct negotiatedata; #endif #if defined(USE_WINDOWS_SSPI) #define GSS_ERROR(status) ((status) & 0x80000000) #endif /* This is used to build a SPN string */ #if !defined(USE_WINDOWS_SSPI) char *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #else TCHAR *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #endif /* This is used to test if the user contains a Windows domain name */ bool Curl_auth_user_contains_domain(const char *user); /* This is used to generate a base64 encoded PLAIN cleartext message */ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *authzid, const char *authcid, const char *passwd, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded LOGIN cleartext message */ CURLcode Curl_auth_create_login_message(struct Curl_easy *data, const char *valuep, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded EXTERNAL cleartext message */ CURLcode Curl_auth_create_external_message(struct Curl_easy *data, const char *user, char **outptr, size_t *outlen); #if !defined(CURL_DISABLE_CRYPTO_AUTH) /* This is used to decode a CRAM-MD5 challenge message */ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, size_t *outlen); /* This is used to generate a CRAM-MD5 response message */ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *chlg, const char *userp, const char *passwdp, char **outptr, size_t *outlen); /* This is used to evaluate if DIGEST is supported */ bool Curl_auth_is_digest_supported(void); /* This is used to generate a base64 encoded DIGEST-MD5 response message */ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, const char *service, char **outptr, size_t *outlen); /* This is used to decode a HTTP DIGEST challenge message */ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, struct digestdata *digest); /* This is used to generate a HTTP DIGEST response message */ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, const unsigned char *uri, struct digestdata *digest, char **outptr, size_t *outlen); /* This is used to clean up the digest specific data */ void Curl_auth_digest_cleanup(struct digestdata *digest); #endif /* !CURL_DISABLE_CRYPTO_AUTH */ #if defined(USE_NTLM) /* This is used to evaluate if NTLM is supported */ bool Curl_auth_is_ntlm_supported(void); /* This is used to generate a base64 encoded NTLM type-1 message */ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *host, struct ntlmdata *ntlm, char **outptr, size_t *outlen); /* This is used to decode a base64 encoded NTLM type-2 message */ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm); /* This is used to generate a base64 encoded NTLM type-3 message */ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen); /* This is used to clean up the NTLM specific data */ void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm); #endif /* USE_NTLM */ /* This is used to generate a base64 encoded OAuth 2.0 message */ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *user, const char *host, const long port, const char *bearer, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded XOAuth 2.0 message */ CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data, const char *user, const char *bearer, char **outptr, size_t *outlen); #if defined(USE_KERBEROS5) /* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ bool Curl_auth_is_gssapi_supported(void); /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *host, const bool mutual, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security token message */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *input, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to clean up the GSSAPI specific data */ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ #if defined(USE_SPNEGO) /* This is used to evaluate if SPNEGO (Negotiate) is supported */ bool Curl_auth_is_spnego_supported(void); /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge message */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *passwood, const char *service, const char *host, const char *chlg64, struct negotiatedata *nego); /* This is used to generate a base64 encoded SPNEGO (Negotiate) response message */ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen); /* This is used to clean up the SPNEGO specifiec data */ void Curl_auth_cleanup_spnego(struct negotiatedata *nego); #endif /* USE_SPNEGO */ #endif /* HEADER_CURL_VAUTH_H */ davix-0.8.0/deps/curl/lib/vauth/digest.c0000644000000000000000000007454114121063461016561 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2831 DIGEST-MD5 authentication * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_CRYPTO_AUTH) #include #include "vauth/vauth.h" #include "vauth/digest.h" #include "urldata.h" #include "curl_base64.h" #include "curl_hmac.h" #include "curl_md5.h" #include "curl_sha256.h" #include "vtls/vtls.h" #include "warnless.h" #include "strtok.h" #include "strcase.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #include "curl_printf.h" #include "rand.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" #if !defined(USE_WINDOWS_SSPI) #define DIGEST_QOP_VALUE_AUTH (1 << 0) #define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) #define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) #define DIGEST_QOP_VALUE_STRING_AUTH "auth" #define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" /* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. It converts digest text to ASCII so the MD5 will be correct for what ultimately goes over the network. */ #define CURL_OUTPUT_DIGEST_CONV(a, b) \ result = Curl_convert_to_network(a, b, strlen(b)); \ if(result) { \ free(b); \ return result; \ } #endif /* !USE_WINDOWS_SSPI */ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, const char **endptr) { int c; bool starts_with_quote = FALSE; bool escape = FALSE; for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);) *value++ = *str++; *value = 0; if('=' != *str++) /* eek, no match */ return FALSE; if('\"' == *str) { /* This starts with a quote so it must end with one as well! */ str++; starts_with_quote = TRUE; } for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { switch(*str) { case '\\': if(!escape) { /* possibly the start of an escaped quote */ escape = TRUE; *content++ = '\\'; /* Even though this is an escape character, we still store it as-is in the target buffer */ continue; } break; case ',': if(!starts_with_quote) { /* This signals the end of the content if we didn't get a starting quote and then we do "sloppy" parsing */ c = 0; /* the end */ continue; } break; case '\r': case '\n': /* end of string */ c = 0; continue; case '\"': if(!escape && starts_with_quote) { /* end of string */ c = 0; continue; } break; } escape = FALSE; *content++ = *str; } *content = 0; *endptr = str; return TRUE; } #if !defined(USE_WINDOWS_SSPI) /* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ unsigned char *dest) /* 33 bytes */ { int i; for(i = 0; i < 16; i++) msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Convert sha256 chunk to RFC7616 -suitable ascii string*/ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ unsigned char *dest) /* 65 bytes */ { int i; for(i = 0; i < 32; i++) msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Perform quoted-string escaping as described in RFC2616 and its errata */ static char *auth_digest_string_quoted(const char *source) { char *dest; const char *s = source; size_t n = 1; /* null terminator */ /* Calculate size needed */ while(*s) { ++n; if(*s == '"' || *s == '\\') { ++n; } ++s; } dest = malloc(n); if(dest) { char *d = dest; s = source; while(*s) { if(*s == '"' || *s == '\\') { *d++ = '\\'; } *d++ = *s++; } *d = 0; } return dest; } /* Retrieves the value for a corresponding key from the challenge string * returns TRUE if the key could be found, FALSE if it does not exists */ static bool auth_digest_get_key_value(const char *chlg, const char *key, char *value, size_t max_val_len, char end_char) { char *find_pos; size_t i; find_pos = strstr(chlg, key); if(!find_pos) return FALSE; find_pos += strlen(key); for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) value[i] = *find_pos++; value[i] = '\0'; return TRUE; } static CURLcode auth_digest_get_qop_values(const char *options, int *value) { char *tmp; char *token; char *tok_buf = NULL; /* Initialise the output */ *value = 0; /* Tokenise the list of qop values. Use a temporary clone of the buffer since strtok_r() ruins it. */ tmp = strdup(options); if(!tmp) return CURLE_OUT_OF_MEMORY; token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) *value |= DIGEST_QOP_VALUE_AUTH; else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) *value |= DIGEST_QOP_VALUE_AUTH_INT; else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) *value |= DIGEST_QOP_VALUE_AUTH_CONF; token = strtok_r(NULL, ",", &tok_buf); } free(tmp); return CURLE_OK; } /* * auth_decode_digest_md5_message() * * This is used internally to decode an already encoded DIGEST-MD5 challenge * message into the separate attributes. * * Parameters: * * chlg64 [in] - The base64 encoded challenge message. * nonce [in/out] - The buffer where the nonce will be stored. * nlen [in] - The length of the nonce buffer. * realm [in/out] - The buffer where the realm will be stored. * rlen [in] - The length of the realm buffer. * alg [in/out] - The buffer where the algorithm will be stored. * alen [in] - The length of the algorithm buffer. * qop [in/out] - The buffer where the qop-options will be stored. * qlen [in] - The length of the qop buffer. * * Returns CURLE_OK on success. */ static CURLcode auth_decode_digest_md5_message(const char *chlg64, char *nonce, size_t nlen, char *realm, size_t rlen, char *alg, size_t alen, char *qop, size_t qlen) { CURLcode result = CURLE_OK; unsigned char *chlg = NULL; size_t chlglen = 0; size_t chlg64len = strlen(chlg64); /* Decode the base-64 encoded challenge message */ if(chlg64len && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) return CURLE_BAD_CONTENT_ENCODING; /* Retrieve nonce string from the challenge */ if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen, '\"')) { free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Retrieve realm string from the challenge */ if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen, '\"')) { /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ strcpy(realm, ""); } /* Retrieve algorithm string from the challenge */ if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) { free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Retrieve qop-options string from the challenge */ if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) { free(chlg); return CURLE_BAD_CONTENT_ENCODING; } free(chlg); return CURLE_OK; } /* * Curl_auth_is_digest_supported() * * This is used to evaluate if DIGEST is supported. * * Parameters: None * * Returns TRUE as DIGEST as handled by libcurl. */ bool Curl_auth_is_digest_supported(void) { return TRUE; } /* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message * ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - The base64 encoded challenge message. * userp [in] - The user name. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, const char *service, char **outptr, size_t *outlen) { size_t i; MD5_context *ctxt; char *response = NULL; unsigned char digest[MD5_DIGEST_LEN]; char HA1_hex[2 * MD5_DIGEST_LEN + 1]; char HA2_hex[2 * MD5_DIGEST_LEN + 1]; char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; char nonce[64]; char realm[128]; char algorithm[64]; char qop_options[64]; int qop_values; char cnonce[33]; char nonceCount[] = "00000001"; char method[] = "AUTHENTICATE"; char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; char *spn = NULL; /* Decode the challenge message */ CURLcode result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), realm, sizeof(realm), algorithm, sizeof(algorithm), qop_options, sizeof(qop_options)); if(result) return result; /* We only support md5 sessions */ if(strcmp(algorithm, "md5-sess") != 0) return CURLE_BAD_CONTENT_ENCODING; /* Get the qop-values from the qop-options */ result = auth_digest_get_qop_values(qop_options, &qop_values); if(result) return result; /* We only support auth quality-of-protection */ if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) return CURLE_BAD_CONTENT_ENCODING; /* Generate 32 random hex chars, 32 bytes + 1 zero termination */ result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce)); if(result) return result; /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) return CURLE_OUT_OF_MEMORY; Curl_MD5_update(ctxt, (const unsigned char *) userp, curlx_uztoui(strlen(userp))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) realm, curlx_uztoui(strlen(realm))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) passwdp, curlx_uztoui(strlen(passwdp))); Curl_MD5_final(ctxt, digest); ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) return CURLE_OUT_OF_MEMORY; Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) nonce, curlx_uztoui(strlen(nonce))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) cnonce, curlx_uztoui(strlen(cnonce))); Curl_MD5_final(ctxt, digest); /* Convert calculated 16 octet hex into 32 bytes string */ for(i = 0; i < MD5_DIGEST_LEN; i++) msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); /* Generate our SPN */ spn = Curl_auth_build_spn(service, realm, NULL); if(!spn) return CURLE_OUT_OF_MEMORY; /* Calculate H(A2) */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) { free(spn); return CURLE_OUT_OF_MEMORY; } Curl_MD5_update(ctxt, (const unsigned char *) method, curlx_uztoui(strlen(method))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) spn, curlx_uztoui(strlen(spn))); Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); /* Now calculate the response hash */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) { free(spn); return CURLE_OUT_OF_MEMORY; } Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) nonce, curlx_uztoui(strlen(nonce))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, curlx_uztoui(strlen(nonceCount))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) cnonce, curlx_uztoui(strlen(cnonce))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) qop, curlx_uztoui(strlen(qop))); Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); /* Generate the response */ response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," "qop=%s", userp, realm, nonce, cnonce, nonceCount, spn, resp_hash_hex, qop); free(spn); if(!response) return CURLE_OUT_OF_MEMORY; /* Base64 encode the response */ result = Curl_base64_encode(data, response, 0, outptr, outlen); free(response); return result; } /* * Curl_auth_decode_digest_http_message() * * This is used to decode a HTTP DIGEST challenge message into the separate * attributes. * * Parameters: * * chlg [in] - The challenge message. * digest [in/out] - The digest data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, struct digestdata *digest) { bool before = FALSE; /* got a nonce before */ bool foundAuth = FALSE; bool foundAuthInt = FALSE; char *token = NULL; char *tmp = NULL; /* If we already have received a nonce, keep that in mind */ if(digest->nonce) before = TRUE; /* Clean up any former leftovers and initialise to defaults */ Curl_auth_digest_cleanup(digest); for(;;) { char value[DIGEST_MAX_VALUE_LENGTH]; char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ while(*chlg && ISSPACE(*chlg)) chlg++; /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { if(strcasecompare(value, "nonce")) { free(digest->nonce); digest->nonce = strdup(content); if(!digest->nonce) return CURLE_OUT_OF_MEMORY; } else if(strcasecompare(value, "stale")) { if(strcasecompare(content, "true")) { digest->stale = TRUE; digest->nc = 1; /* we make a new nonce now */ } } else if(strcasecompare(value, "realm")) { free(digest->realm); digest->realm = strdup(content); if(!digest->realm) return CURLE_OUT_OF_MEMORY; } else if(strcasecompare(value, "opaque")) { free(digest->opaque); digest->opaque = strdup(content); if(!digest->opaque) return CURLE_OUT_OF_MEMORY; } else if(strcasecompare(value, "qop")) { char *tok_buf = NULL; /* Tokenize the list and choose auth if possible, use a temporary clone of the buffer since strtok_r() ruins it */ tmp = strdup(content); if(!tmp) return CURLE_OUT_OF_MEMORY; token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { foundAuthInt = TRUE; } token = strtok_r(NULL, ",", &tok_buf); } free(tmp); /* Select only auth or auth-int. Otherwise, ignore */ if(foundAuth) { free(digest->qop); digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); if(!digest->qop) return CURLE_OUT_OF_MEMORY; } else if(foundAuthInt) { free(digest->qop); digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); if(!digest->qop) return CURLE_OUT_OF_MEMORY; } } else if(strcasecompare(value, "algorithm")) { free(digest->algorithm); digest->algorithm = strdup(content); if(!digest->algorithm) return CURLE_OUT_OF_MEMORY; if(strcasecompare(content, "MD5-sess")) digest->algo = CURLDIGESTALGO_MD5SESS; else if(strcasecompare(content, "MD5")) digest->algo = CURLDIGESTALGO_MD5; else if(strcasecompare(content, "SHA-256")) digest->algo = CURLDIGESTALGO_SHA256; else if(strcasecompare(content, "SHA-256-SESS")) digest->algo = CURLDIGESTALGO_SHA256SESS; else if(strcasecompare(content, "SHA-512-256")) digest->algo = CURLDIGESTALGO_SHA512_256; else if(strcasecompare(content, "SHA-512-256-SESS")) digest->algo = CURLDIGESTALGO_SHA512_256SESS; else return CURLE_BAD_CONTENT_ENCODING; } else if(strcasecompare(value, "userhash")) { if(strcasecompare(content, "true")) { digest->userhash = TRUE; } } else { /* Unknown specifier, ignore it! */ } } else break; /* We're done here */ /* Pass all additional spaces here */ while(*chlg && ISSPACE(*chlg)) chlg++; /* Allow the list to be comma-separated */ if(',' == *chlg) chlg++; } /* We had a nonce since before, and we got another one now without 'stale=true'. This means we provided bad credentials in the previous request */ if(before && !digest->stale) return CURLE_BAD_CONTENT_ENCODING; /* We got this header without a nonce, that's a bad Digest line! */ if(!digest->nonce) return CURLE_BAD_CONTENT_ENCODING; return CURLE_OK; } /* * auth_create_digest_http_message() * * This is used to generate a HTTP DIGEST response message ready for sending * to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name. * passwdp [in] - The user's password. * request [in] - The HTTP request. * uripath [in] - The path of the HTTP uri. * digest [in/out] - The digest data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ static CURLcode auth_create_digest_http_message( struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, const unsigned char *uripath, struct digestdata *digest, char **outptr, size_t *outlen, void (*convert_to_ascii)(unsigned char *, unsigned char *), void (*hash)(unsigned char *, const unsigned char *, const size_t)) { CURLcode result; unsigned char hashbuf[32]; /* 32 bytes/256 bits */ unsigned char request_digest[65]; unsigned char ha1[65]; /* 64 digits and 1 zero byte */ unsigned char ha2[65]; /* 64 digits and 1 zero byte */ char userh[65]; char *cnonce = NULL; size_t cnonce_sz = 0; char *userp_quoted; char *response = NULL; char *hashthis = NULL; char *tmp = NULL; if(!digest->nc) digest->nc = 1; if(!digest->cnonce) { char cnoncebuf[33]; result = Curl_rand_hex(data, (unsigned char *)cnoncebuf, sizeof(cnoncebuf)); if(result) return result; result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce, &cnonce_sz); if(result) return result; digest->cnonce = cnonce; } if(digest->userhash) { hashthis = aprintf("%s:%s", userp, digest->realm); if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, (unsigned char *)userh); } /* If the algorithm is "MD5" or unspecified (which then defaults to MD5): A1 = unq(username-value) ":" unq(realm-value) ":" passwd If the algorithm is "MD5-sess" then: A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":" unq(nonce-value) ":" unq(cnonce-value) */ hashthis = aprintf("%s:%s:%s", digest->userhash ? userh : userp, digest->realm, passwdp); if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, ha1); if(digest->algo == CURLDIGESTALGO_MD5SESS || digest->algo == CURLDIGESTALGO_SHA256SESS || digest->algo == CURLDIGESTALGO_SHA512_256SESS) { /* nonce and cnonce are OUTSIDE the hash */ tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); if(!tmp) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */ hash(hashbuf, (unsigned char *) tmp, strlen(tmp)); free(tmp); convert_to_ascii(hashbuf, ha1); } /* If the "qop" directive's value is "auth" or is unspecified, then A2 is: A2 = Method ":" digest-uri-value If the "qop" value is "auth-int", then A2 is: A2 = Method ":" digest-uri-value ":" H(entity-body) (The "Method" value is the HTTP request method as specified in section 5.1.1 of RFC 2616) */ hashthis = aprintf("%s:%s", request, uripath); if(!hashthis) return CURLE_OUT_OF_MEMORY; if(digest->qop && strcasecompare(digest->qop, "auth-int")) { /* We don't support auth-int for PUT or POST */ char hashed[65]; char *hashthis2; hash(hashbuf, (const unsigned char *)"", 0); convert_to_ascii(hashbuf, (unsigned char *)hashed); hashthis2 = aprintf("%s:%s", hashthis, hashed); free(hashthis); hashthis = hashthis2; } if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, ha2); if(digest->qop) { hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc, digest->cnonce, digest->qop, ha2); } else { hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2); } if(!hashthis) return CURLE_OUT_OF_MEMORY; CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis)); free(hashthis); convert_to_ascii(hashbuf, request_digest); /* For test case 64 (snooped from a Mozilla 1.3a request) Authorization: Digest username="testuser", realm="testrealm", \ nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" Digest parameters are all quoted strings. Username which is provided by the user will need double quotes and backslashes within it escaped. For the other fields, this shouldn't be an issue. realm, nonce, and opaque are copied as is from the server, escapes and all. cnonce is generated with web-safe characters. uri is already percent encoded. nc is 8 hex characters. algorithm and qop with standard values only contain web-safe characters. */ userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp); if(!userp_quoted) return CURLE_OUT_OF_MEMORY; if(digest->qop) { response = aprintf("username=\"%s\", " "realm=\"%s\", " "nonce=\"%s\", " "uri=\"%s\", " "cnonce=\"%s\", " "nc=%08x, " "qop=%s, " "response=\"%s\"", userp_quoted, digest->realm, digest->nonce, uripath, digest->cnonce, digest->nc, digest->qop, request_digest); if(strcasecompare(digest->qop, "auth")) digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded which tells to the server how many times you are using the same nonce in the qop=auth mode */ } else { response = aprintf("username=\"%s\", " "realm=\"%s\", " "nonce=\"%s\", " "uri=\"%s\", " "response=\"%s\"", userp_quoted, digest->realm, digest->nonce, uripath, request_digest); } free(userp_quoted); if(!response) return CURLE_OUT_OF_MEMORY; /* Add the optional fields */ if(digest->opaque) { /* Append the opaque */ tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; response = tmp; } if(digest->algorithm) { /* Append the algorithm */ tmp = aprintf("%s, algorithm=%s", response, digest->algorithm); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; response = tmp; } if(digest->userhash) { /* Append the userhash */ tmp = aprintf("%s, userhash=true", response); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; response = tmp; } /* Return the output */ *outptr = response; *outlen = strlen(response); return CURLE_OK; } /* * Curl_auth_create_digest_http_message() * * This is used to generate a HTTP DIGEST response message ready for sending * to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name. * passwdp [in] - The user's password. * request [in] - The HTTP request. * uripath [in] - The path of the HTTP uri. * digest [in/out] - The digest data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, const unsigned char *uripath, struct digestdata *digest, char **outptr, size_t *outlen) { switch(digest->algo) { case CURLDIGESTALGO_MD5: case CURLDIGESTALGO_MD5SESS: return auth_create_digest_http_message(data, userp, passwdp, request, uripath, digest, outptr, outlen, auth_digest_md5_to_ascii, Curl_md5it); case CURLDIGESTALGO_SHA256: case CURLDIGESTALGO_SHA256SESS: case CURLDIGESTALGO_SHA512_256: case CURLDIGESTALGO_SHA512_256SESS: return auth_create_digest_http_message(data, userp, passwdp, request, uripath, digest, outptr, outlen, auth_digest_sha256_to_ascii, Curl_sha256it); default: return CURLE_UNSUPPORTED_PROTOCOL; } } /* * Curl_auth_digest_cleanup() * * This is used to clean up the digest specific data. * * Parameters: * * digest [in/out] - The digest data struct being cleaned up. * */ void Curl_auth_digest_cleanup(struct digestdata *digest) { Curl_safefree(digest->nonce); Curl_safefree(digest->cnonce); Curl_safefree(digest->realm); Curl_safefree(digest->opaque); Curl_safefree(digest->qop); Curl_safefree(digest->algorithm); digest->nc = 0; digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ digest->stale = FALSE; /* default means normal, not stale */ digest->userhash = FALSE; } #endif /* !USE_WINDOWS_SSPI */ #endif /* CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/vauth/cleartext.c0000644000000000000000000001231114121063461017260 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC4616 PLAIN authentication * Draft LOGIN SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \ !defined(CURL_DISABLE_POP3) #include #include "urldata.h" #include "vauth/vauth.h" #include "curl_base64.h" #include "curl_md5.h" #include "warnless.h" #include "strtok.h" #include "sendf.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_create_plain_message() * * This is used to generate an already encoded PLAIN message ready * for sending to the recipient. * * Parameters: * * data [in] - The session handle. * authzid [in] - The authorization identity. * authcid [in] - The authentication identity. * passwd [in] - The password. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *authzid, const char *authcid, const char *passwd, char **outptr, size_t *outlen) { CURLcode result; char *plainauth; size_t zlen; size_t clen; size_t plen; size_t plainlen; *outlen = 0; *outptr = NULL; zlen = (authzid == NULL ? 0 : strlen(authzid)); clen = strlen(authcid); plen = strlen(passwd); /* Compute binary message length. Check for overflows. */ if(((zlen + clen) > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2))) return CURLE_OUT_OF_MEMORY; plainlen = zlen + clen + plen + 2; plainauth = malloc(plainlen); if(!plainauth) return CURLE_OUT_OF_MEMORY; /* Calculate the reply */ if(zlen != 0) memcpy(plainauth, authzid, zlen); plainauth[zlen] = '\0'; memcpy(plainauth + zlen + 1, authcid, clen); plainauth[zlen + clen + 1] = '\0'; memcpy(plainauth + zlen + clen + 2, passwd, plen); /* Base64 encode the reply */ result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen); free(plainauth); return result; } /* * Curl_auth_create_login_message() * * This is used to generate an already encoded LOGIN message containing the * user name or password ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * valuep [in] - The user name or user's password. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_login_message(struct Curl_easy *data, const char *valuep, char **outptr, size_t *outlen) { size_t vlen = strlen(valuep); if(!vlen) { /* Calculate an empty reply */ *outptr = strdup("="); if(*outptr) { *outlen = (size_t) 1; return CURLE_OK; } *outlen = 0; return CURLE_OUT_OF_MEMORY; } /* Base64 encode the value */ return Curl_base64_encode(data, valuep, vlen, outptr, outlen); } /* * Curl_auth_create_external_message() * * This is used to generate an already encoded EXTERNAL message containing * the user name ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * user [in] - The user name. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_external_message(struct Curl_easy *data, const char *user, char **outptr, size_t *outlen) { /* This is the same formatting as the login message */ return Curl_auth_create_login_message(data, user, outptr, outlen); } #endif /* if no users */ davix-0.8.0/deps/curl/lib/vauth/ntlm.c0000644000000000000000000006671314121063461016256 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) /* * NTLM details: * * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 #include "urldata.h" #include "non-ascii.h" #include "sendf.h" #include "curl_base64.h" #include "curl_ntlm_core.h" #include "curl_gethostname.h" #include "curl_multibyte.h" #include "curl_md5.h" #include "warnless.h" #include "rand.h" #include "vtls/vtls.h" /* SSL backend-specific #if branches in this file must be kept in the order documented in curl_ntlm_core. */ #if defined(NTLM_NEEDS_NSS_INIT) #include "vtls/nssg.h" /* for Curl_nss_force_init() */ #endif #define BUILDING_CURL_NTLM_MSGS_C #include "vauth/vauth.h" #include "vauth/ntlm.h" #include "curl_endian.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* "NTLMSSP" signature is always in ASCII regardless of the platform */ #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)) #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \ ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff)) #if DEBUG_ME # define DEBUG_OUT(x) x static void ntlm_print_flags(FILE *handle, unsigned long flags) { if(flags & NTLMFLAG_NEGOTIATE_UNICODE) fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); if(flags & NTLMFLAG_NEGOTIATE_OEM) fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); if(flags & NTLMFLAG_REQUEST_TARGET) fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); if(flags & (1<<3)) fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); if(flags & NTLMFLAG_NEGOTIATE_SIGN) fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); if(flags & NTLMFLAG_NEGOTIATE_SEAL) fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); if(flags & NTLMFLAG_NEGOTIATE_NETWARE) fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); if(flags & (1<<10)) fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); if(flags & NTLMFLAG_TARGET_TYPE_SERVER) fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); if(flags & NTLMFLAG_TARGET_TYPE_SHARE) fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); if(flags & (1<<24)) fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); if(flags & (1<<25)) fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); if(flags & (1<<26)) fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); if(flags & (1<<27)) fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); if(flags & (1<<28)) fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); if(flags & NTLMFLAG_NEGOTIATE_128) fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); if(flags & NTLMFLAG_NEGOTIATE_56) fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); } static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) { const char *p = buf; (void) handle; fprintf(stderr, "0x"); while(len-- > 0) fprintf(stderr, "%02.2x", (unsigned int)*p++); } #else # define DEBUG_OUT(x) Curl_nop_stmt #endif /* * ntlm_decode_type2_target() * * This is used to decode the "target info" in the NTLM type-2 message * received. * * Parameters: * * data [in] - The session handle. * buffer [in] - The decoded type-2 message. * size [in] - The input buffer size, at least 32 bytes. * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, unsigned char *buffer, size_t size, struct ntlmdata *ntlm) { unsigned short target_info_len = 0; unsigned int target_info_offset = 0; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif if(size >= 48) { target_info_len = Curl_read16_le(&buffer[40]); target_info_offset = Curl_read32_le(&buffer[44]); if(target_info_len > 0) { if((target_info_offset >= size) || ((target_info_offset + target_info_len) > size) || (target_info_offset < 48)) { infof(data, "NTLM handshake failure (bad type-2 message). " "Target Info Offset Len is set incorrect by the peer\n"); return CURLE_BAD_CONTENT_ENCODING; } ntlm->target_info = malloc(target_info_len); if(!ntlm->target_info) return CURLE_OUT_OF_MEMORY; memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len); } } ntlm->target_info_len = target_info_len; return CURLE_OK; } /* NTLM message structure notes: A 'short' is a 'network short', a little-endian 16-bit unsigned value. A 'long' is a 'network long', a little-endian, 32-bit unsigned value. A 'security buffer' represents a triplet used to point to a buffer, consisting of two shorts and one long: 1. A 'short' containing the length of the buffer content in bytes. 2. A 'short' containing the allocated space for the buffer in bytes. 3. A 'long' containing the offset to the start of the buffer in bytes, from the beginning of the NTLM message. */ /* * Curl_auth_is_ntlm_supported() * * This is used to evaluate if NTLM is supported. * * Parameters: None * * Returns TRUE as NTLM as handled by libcurl. */ bool Curl_auth_is_ntlm_supported(void) { return TRUE; } /* * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message * is first decoded from a base64 string into a raw NTLM message and checked * for validity before the appropriate data for creating a type-3 message is * written to the given NTLM data structure. * * Parameters: * * data [in] - The session handle. * type2msg [in] - The base64 encoded type-2 message. * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; /* NTLM type-2 message structure: Index Description Content 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) 8 NTLM Message Type long (0x02000000) 12 Target Name security buffer 20 Flags long 24 Challenge 8 bytes (32) Context 8 bytes (two consecutive longs) (*) (40) Target Information security buffer (*) (48) OS Version Structure 8 bytes (*) 32 (48) (56) Start of data block (*) (*) -> Optional */ CURLcode result = CURLE_OK; unsigned char *type2 = NULL; size_t type2_len = 0; #if defined(NTLM_NEEDS_NSS_INIT) /* Make sure the crypto backend is initialized */ result = Curl_nss_force_init(data); if(result) return result; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) (void)data; #endif /* Decode the base-64 encoded type-2 message */ if(strlen(type2msg) && *type2msg != '=') { result = Curl_base64_decode(type2msg, &type2, &type2_len); if(result) return result; } /* Ensure we have a valid type-2 message */ if(!type2) { infof(data, "NTLM handshake failure (empty type-2 message)\n"); return CURLE_BAD_CONTENT_ENCODING; } ntlm->flags = 0; if((type2_len < 32) || (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { /* This was not a good enough type-2 message */ free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); return CURLE_BAD_CONTENT_ENCODING; } ntlm->flags = Curl_read32_le(&type2[20]); memcpy(ntlm->nonce, &type2[24], 8); if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { result = ntlm_decode_type2_target(data, type2, type2_len, ntlm); if(result) { free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); return result; } } DEBUG_OUT({ fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); ntlm_print_flags(stderr, ntlm->flags); fprintf(stderr, "\n nonce="); ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); fprintf(stderr, "\n****\n"); fprintf(stderr, "**** Header %s\n ", header); }); free(type2); return result; } /* copy the source to the destination and fill in zeroes in every other destination byte! */ static void unicodecpy(unsigned char *dest, const char *src, size_t length) { size_t i; for(i = 0; i < length; i++) { dest[2 * i] = (unsigned char)src[i]; dest[2 * i + 1] = '\0'; } } /* * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for * sending to the recipient using the appropriate compile time crypto API. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *hostname, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { /* NTLM type-1 message structure: Index Description Content 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) 8 NTLM Message Type long (0x01000000) 12 Flags long (16) Supplied Domain security buffer (*) (24) Supplied Workstation security buffer (*) (32) OS Version Structure 8 bytes (*) (32) (40) Start of data block (*) (*) -> Optional */ size_t size; unsigned char ntlmbuf[NTLM_BUFSIZE]; const char *host = ""; /* empty */ const char *domain = ""; /* empty */ size_t hostlen = 0; size_t domlen = 0; size_t hostoff = 0; size_t domoff = hostoff + hostlen; /* This is 0: remember that host and domain are empty */ (void)userp; (void)passwdp; (void)service, (void)hostname, /* Clean up any former leftovers and initialise to defaults */ Curl_auth_cleanup_ntlm(ntlm); #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY #else #define NTLM2FLAG 0 #endif msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, NTLMSSP_SIGNATURE "%c" "\x01%c%c%c" /* 32-bit type = 1 */ "%c%c%c%c" /* 32-bit NTLM flag field */ "%c%c" /* domain length */ "%c%c" /* domain allocated space */ "%c%c" /* domain name offset */ "%c%c" /* 2 zeroes */ "%c%c" /* host length */ "%c%c" /* host allocated space */ "%c%c" /* host name offset */ "%c%c" /* 2 zeroes */ "%s" /* host name */ "%s", /* domain string */ 0, /* trailing zero */ 0, 0, 0, /* part of type-1 long */ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | NTLMFLAG_REQUEST_TARGET | NTLMFLAG_NEGOTIATE_NTLM_KEY | NTLM2FLAG | NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), SHORTPAIR(domlen), SHORTPAIR(domlen), SHORTPAIR(domoff), 0, 0, SHORTPAIR(hostlen), SHORTPAIR(hostlen), SHORTPAIR(hostoff), 0, 0, host, /* this is empty */ domain /* this is empty */); /* Initial packet length */ size = 32 + hostlen + domlen; DEBUG_OUT({ fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " "0x%08.8x ", LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | NTLMFLAG_REQUEST_TARGET | NTLMFLAG_NEGOTIATE_NTLM_KEY | NTLM2FLAG | NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), NTLMFLAG_NEGOTIATE_OEM | NTLMFLAG_REQUEST_TARGET | NTLMFLAG_NEGOTIATE_NTLM_KEY | NTLM2FLAG | NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); ntlm_print_flags(stderr, NTLMFLAG_NEGOTIATE_OEM | NTLMFLAG_REQUEST_TARGET | NTLMFLAG_NEGOTIATE_NTLM_KEY | NTLM2FLAG | NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); fprintf(stderr, "\n****\n"); }); /* Return with binary blob encoded into base64 */ return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); } /* * Curl_auth_create_ntlm_type3_message() * * This is used to generate an already encoded NTLM type-3 message ready for * sending to the recipient using the appropriate compile time crypto API. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { /* NTLM type-3 message structure: Index Description Content 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) 8 NTLM Message Type long (0x03000000) 12 LM/LMv2 Response security buffer 20 NTLM/NTLMv2 Response security buffer 28 Target Name security buffer 36 User Name security buffer 44 Workstation Name security buffer (52) Session Key security buffer (*) (60) Flags long (*) (64) OS Version Structure 8 bytes (*) 52 (64) (72) Start of data block (*) -> Optional */ CURLcode result = CURLE_OK; size_t size; unsigned char ntlmbuf[NTLM_BUFSIZE]; int lmrespoff; unsigned char lmresp[24]; /* fixed-size */ #ifdef USE_NTRESPONSES int ntrespoff; unsigned int ntresplen = 24; unsigned char ntresp[24]; /* fixed-size */ unsigned char *ptr_ntresp = &ntresp[0]; unsigned char *ntlmv2resp = NULL; #endif bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; char host[HOSTNAME_MAX + 1] = ""; const char *user; const char *domain = ""; size_t hostoff = 0; size_t useroff = 0; size_t domoff = 0; size_t hostlen = 0; size_t userlen = 0; size_t domlen = 0; user = strchr(userp, '\\'); if(!user) user = strchr(userp, '/'); if(user) { domain = userp; domlen = (user - domain); user++; } else user = userp; userlen = strlen(user); /* Get the machine's un-qualified host name as NTLM doesn't like the fully qualified domain name */ if(Curl_gethostname(host, sizeof(host))) { infof(data, "gethostname() failed, continuing without!\n"); hostlen = 0; } else { hostlen = strlen(host); } #if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2) if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { unsigned char ntbuffer[0x18]; unsigned char entropy[8]; unsigned char ntlmv2hash[0x18]; result = Curl_rand(data, entropy, 8); if(result) return result; result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen, ntbuffer, ntlmv2hash); if(result) return result; /* LMv2 response */ result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy, &ntlm->nonce[0], lmresp); if(result) return result; /* NTLMv2 response */ result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy, ntlm, &ntlmv2resp, &ntresplen); if(result) return result; ptr_ntresp = ntlmv2resp; } else #endif #if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) { unsigned char ntbuffer[0x18]; unsigned char tmp[0x18]; unsigned char md5sum[MD5_DIGEST_LENGTH]; unsigned char entropy[8]; /* Need to create 8 bytes random data */ result = Curl_rand(data, entropy, 8); if(result) return result; /* 8 bytes random data as challenge in lmresp */ memcpy(lmresp, entropy, 8); /* Pad with zeros */ memset(lmresp + 8, 0, 0x10); /* Fill tmp with challenge(nonce?) + entropy */ memcpy(tmp, &ntlm->nonce[0], 8); memcpy(tmp + 8, entropy, 8); Curl_md5it(md5sum, tmp, 16); /* We shall only use the first 8 bytes of md5sum, but the des code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); /* End of NTLM2 Session code */ /* NTLM v2 session security is a misnomer because it is not NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2 */ } else #endif { #ifdef USE_NTRESPONSES unsigned char ntbuffer[0x18]; #endif unsigned char lmbuffer[0x18]; #ifdef USE_NTRESPONSES result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); #endif result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); if(result) return result; Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ } if(unicode) { domlen = domlen * 2; userlen = userlen * 2; hostlen = hostlen * 2; } lmrespoff = 64; /* size of the message header */ #ifdef USE_NTRESPONSES ntrespoff = lmrespoff + 0x18; domoff = ntrespoff + ntresplen; #else domoff = lmrespoff + 0x18; #endif useroff = domoff + domlen; hostoff = useroff + userlen; /* Create the big type-3 message binary blob */ size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, NTLMSSP_SIGNATURE "%c" "\x03%c%c%c" /* 32-bit type = 3 */ "%c%c" /* LanManager length */ "%c%c" /* LanManager allocated space */ "%c%c" /* LanManager offset */ "%c%c" /* 2 zeroes */ "%c%c" /* NT-response length */ "%c%c" /* NT-response allocated space */ "%c%c" /* NT-response offset */ "%c%c" /* 2 zeroes */ "%c%c" /* domain length */ "%c%c" /* domain allocated space */ "%c%c" /* domain name offset */ "%c%c" /* 2 zeroes */ "%c%c" /* user length */ "%c%c" /* user allocated space */ "%c%c" /* user offset */ "%c%c" /* 2 zeroes */ "%c%c" /* host length */ "%c%c" /* host allocated space */ "%c%c" /* host offset */ "%c%c" /* 2 zeroes */ "%c%c" /* session key length (unknown purpose) */ "%c%c" /* session key allocated space (unknown purpose) */ "%c%c" /* session key offset (unknown purpose) */ "%c%c" /* 2 zeroes */ "%c%c%c%c", /* flags */ /* domain string */ /* user string */ /* host string */ /* LanManager response */ /* NT response */ 0, /* zero termination */ 0, 0, 0, /* type-3 long, the 24 upper bits */ SHORTPAIR(0x18), /* LanManager response length, twice */ SHORTPAIR(0x18), SHORTPAIR(lmrespoff), 0x0, 0x0, #ifdef USE_NTRESPONSES SHORTPAIR(ntresplen), /* NT-response length, twice */ SHORTPAIR(ntresplen), SHORTPAIR(ntrespoff), 0x0, 0x0, #else 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, #endif SHORTPAIR(domlen), SHORTPAIR(domlen), SHORTPAIR(domoff), 0x0, 0x0, SHORTPAIR(userlen), SHORTPAIR(userlen), SHORTPAIR(useroff), 0x0, 0x0, SHORTPAIR(hostlen), SHORTPAIR(hostlen), SHORTPAIR(hostoff), 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, LONGQUARTET(ntlm->flags)); DEBUGASSERT(size == 64); DEBUGASSERT(size == (size_t)lmrespoff); /* We append the binary hashes */ if(size < (NTLM_BUFSIZE - 0x18)) { memcpy(&ntlmbuf[size], lmresp, 0x18); size += 0x18; } DEBUG_OUT({ fprintf(stderr, "**** TYPE3 header lmresp="); ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); }); #ifdef USE_NTRESPONSES /* ntresplen + size should not be risking an integer overflow here */ if(ntresplen + size > sizeof(ntlmbuf)) { failf(data, "incoming NTLM message too big"); return CURLE_OUT_OF_MEMORY; } DEBUGASSERT(size == (size_t)ntrespoff); memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); size += ntresplen; DEBUG_OUT({ fprintf(stderr, "\n ntresp="); ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); }); free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ #endif DEBUG_OUT({ fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", LONGQUARTET(ntlm->flags), ntlm->flags); ntlm_print_flags(stderr, ntlm->flags); fprintf(stderr, "\n****\n"); }); /* Make sure that the domain, user and host strings fit in the buffer before we copy them there. */ if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { failf(data, "user + domain + host name too big"); return CURLE_OUT_OF_MEMORY; } DEBUGASSERT(size == domoff); if(unicode) unicodecpy(&ntlmbuf[size], domain, domlen / 2); else memcpy(&ntlmbuf[size], domain, domlen); size += domlen; DEBUGASSERT(size == useroff); if(unicode) unicodecpy(&ntlmbuf[size], user, userlen / 2); else memcpy(&ntlmbuf[size], user, userlen); size += userlen; DEBUGASSERT(size == hostoff); if(unicode) unicodecpy(&ntlmbuf[size], host, hostlen / 2); else memcpy(&ntlmbuf[size], host, hostlen); size += hostlen; /* Convert domain, user, and host to ASCII but leave the rest as-is */ result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], size - domoff); if(result) return CURLE_CONV_FAILED; /* Return with binary blob encoded into base64 */ result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen); Curl_auth_cleanup_ntlm(ntlm); return result; } /* * Curl_auth_cleanup_ntlm() * * This is used to clean up the NTLM specific data. * * Parameters: * * ntlm [in/out] - The NTLM data struct being cleaned up. * */ void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) { /* Free the target info */ Curl_safefree(ntlm->target_info); /* Reset any variables */ ntlm->target_info_len = 0; } #endif /* USE_NTLM && !USE_WINDOWS_SSPI */ davix-0.8.0/deps/curl/lib/vauth/krb5_gssapi.c0000644000000000000000000003141514121063461017504 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2019, Steve Holme, . * Copyright (C) 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5) #include #include "vauth/vauth.h" #include "curl_sasl.h" #include "urldata.h" #include "curl_base64.h" #include "curl_gssapi.h" #include "sendf.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_gssapi_supported() * * This is used to evaluate if GSSAPI (Kerberos V5) is supported. * * Parameters: None * * Returns TRUE if Kerberos V5 is supported by the GSS-API library. */ bool Curl_auth_is_gssapi_supported(void) { return TRUE; } /* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in[ - The host name. * mutual_auth [in] - Flag specifying whether or not mutual authentication * is enabled. * chlg64 [in] - Pointer to the optional base64 encoded challenge * message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *host, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; OM_uint32 major_status; OM_uint32 minor_status; OM_uint32 unused_status; gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; (void) userp; (void) passwdp; if(!krb5->spn) { /* Generate our SPN */ char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) return CURLE_OUT_OF_MEMORY; /* Populate the SPN structure */ spn_token.value = spn; spn_token.length = strlen(spn); /* Import the SPN */ major_status = gss_import_name(&minor_status, &spn_token, GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_import_name() failed: ", major_status, minor_status); free(spn); return CURLE_AUTH_ERROR; } free(spn); } if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ input_token.value = chlg; input_token.length = chlglen; } major_status = Curl_gss_init_sec_context(data, &minor_status, &krb5->context, krb5->spn, &Curl_krb5_mech_oid, GSS_C_NO_CHANNEL_BINDINGS, &input_token, &output_token, mutual_auth, NULL); /* Free the decoded challenge as it is not required anymore */ free(input_token.value); if(GSS_ERROR(major_status)) { if(output_token.value) gss_release_buffer(&unused_status, &output_token); Curl_gss_log_error(data, "gss_init_sec_context() failed: ", major_status, minor_status); return CURLE_AUTH_ERROR; } if(output_token.value && output_token.length) { /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) output_token.value, output_token.length, outptr, outlen); gss_release_buffer(&unused_status, &output_token); } else if(mutual_auth) { *outptr = strdup(""); if(!*outptr) result = CURLE_OUT_OF_MEMORY; } return result; } /* * Curl_auth_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - Pointer to the optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; size_t messagelen = 0; unsigned char *chlg = NULL; unsigned char *message = NULL; OM_uint32 major_status; OM_uint32 minor_status; OM_uint32 unused_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; unsigned int indata = 0; unsigned int outdata = 0; gss_qop_t qop = GSS_C_QOP_DEFAULT; unsigned int sec_layer = 0; unsigned int max_size = 0; gss_name_t username = GSS_C_NO_NAME; gss_buffer_desc username_token; /* Decode the base-64 encoded input message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty security message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Get the fully qualified username back from the context */ major_status = gss_inquire_context(&minor_status, krb5->context, &username, NULL, NULL, NULL, NULL, NULL, NULL); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_inquire_context() failed: ", major_status, minor_status); free(chlg); return CURLE_AUTH_ERROR; } /* Convert the username from internal format to a displayable token */ major_status = gss_display_name(&minor_status, username, &username_token, NULL); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_display_name() failed: ", major_status, minor_status); free(chlg); return CURLE_AUTH_ERROR; } /* Setup the challenge "input" security buffer */ input_token.value = chlg; input_token.length = chlglen; /* Decrypt the inbound challenge and obtain the qop */ major_status = gss_unwrap(&minor_status, krb5->context, &input_token, &output_token, NULL, &qop); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_unwrap() failed: ", major_status, minor_status); gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(output_token.length != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Copy the data out and free the challenge as it is not required anymore */ memcpy(&indata, output_token.value, 4); gss_release_buffer(&unused_status, &output_token); free(chlg); /* Extract the security layer */ sec_layer = indata & 0x000000FF; if(!(sec_layer & GSSAUTH_P_NONE)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } /* Extract the maximum message size the server can receive */ max_size = ntohl(indata & 0xFFFFFF00); if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server our receive buffer is zero. */ max_size = 0; } /* Allocate our message */ messagelen = sizeof(outdata) + username_token.length + 1; message = malloc(messagelen); if(!message) { gss_release_buffer(&unused_status, &username_token); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; memcpy(message, &outdata, sizeof(outdata)); memcpy(message + sizeof(outdata), username_token.value, username_token.length); message[messagelen - 1] = '\0'; /* Free the username token as it is not required anymore */ gss_release_buffer(&unused_status, &username_token); /* Setup the "authentication data" security buffer */ input_token.value = message; input_token.length = messagelen; /* Encrypt the data */ major_status = gss_wrap(&minor_status, krb5->context, 0, GSS_C_QOP_DEFAULT, &input_token, NULL, &output_token); if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_wrap() failed: ", major_status, minor_status); free(message); return CURLE_AUTH_ERROR; } /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) output_token.value, output_token.length, outptr, outlen); /* Free the output buffer */ gss_release_buffer(&unused_status, &output_token); /* Free the message buffer */ free(message); return result; } /* * Curl_auth_cleanup_gssapi() * * This is used to clean up the GSSAPI (Kerberos V5) specific data. * * Parameters: * * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5) { OM_uint32 minor_status; /* Free our security context */ if(krb5->context != GSS_C_NO_CONTEXT) { gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); krb5->context = GSS_C_NO_CONTEXT; } /* Free the SPN */ if(krb5->spn != GSS_C_NO_NAME) { gss_release_name(&minor_status, &krb5->spn); krb5->spn = GSS_C_NO_NAME; } } #endif /* HAVE_GSSAPI && USE_KERBEROS5 */ davix-0.8.0/deps/curl/lib/vauth/ntlm.h0000644000000000000000000001264514121063461016256 0ustar rootroot#ifndef HEADER_VAUTH_NTLM_H #define HEADER_VAUTH_NTLM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NTLM /* NTLM buffer fixed size, large enough for long user + host + domain */ #define NTLM_BUFSIZE 1024 /* Stuff only required for curl_ntlm_msgs.c */ #ifdef BUILDING_CURL_NTLM_MSGS_C /* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) /* Indicates that Unicode strings are supported for use in security buffer data. */ #define NTLMFLAG_NEGOTIATE_OEM (1<<1) /* Indicates that OEM strings are supported for use in security buffer data. */ #define NTLMFLAG_REQUEST_TARGET (1<<2) /* Requests that the server's authentication realm be included in the Type 2 message. */ /* unknown (1<<3) */ #define NTLMFLAG_NEGOTIATE_SIGN (1<<4) /* Specifies that authenticated communication between the client and server should carry a digital signature (message integrity). */ #define NTLMFLAG_NEGOTIATE_SEAL (1<<5) /* Specifies that authenticated communication between the client and server should be encrypted (message confidentiality). */ #define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6) /* Indicates that datagram authentication is being used. */ #define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7) /* Indicates that the LAN Manager session key should be used for signing and sealing authenticated communications. */ #define NTLMFLAG_NEGOTIATE_NETWARE (1<<8) /* unknown purpose */ #define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9) /* Indicates that NTLM authentication is being used. */ /* unknown (1<<10) */ #define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11) /* Sent by the client in the Type 3 message to indicate that an anonymous context has been established. This also affects the response fields. */ #define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12) /* Sent by the client in the Type 1 message to indicate that a desired authentication realm is included in the message. */ #define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13) /* Sent by the client in the Type 1 message to indicate that the client workstation's name is included in the message. */ #define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14) /* Sent by the server to indicate that the server and client are on the same machine. Implies that the client may use a pre-established local security context rather than responding to the challenge. */ #define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15) /* Indicates that authenticated communication between the client and server should be signed with a "dummy" signature. */ #define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16) /* Sent by the server in the Type 2 message to indicate that the target authentication realm is a domain. */ #define NTLMFLAG_TARGET_TYPE_SERVER (1<<17) /* Sent by the server in the Type 2 message to indicate that the target authentication realm is a server. */ #define NTLMFLAG_TARGET_TYPE_SHARE (1<<18) /* Sent by the server in the Type 2 message to indicate that the target authentication realm is a share. Presumably, this is for share-level authentication. Usage is unclear. */ #define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19) /* Indicates that the NTLM2 signing and sealing scheme should be used for protecting authenticated communications. */ #define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20) /* unknown purpose */ #define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21) /* unknown purpose */ #define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22) /* unknown purpose */ #define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23) /* Sent by the server in the Type 2 message to indicate that it is including a Target Information block in the message. */ /* unknown (1<24) */ /* unknown (1<25) */ /* unknown (1<26) */ /* unknown (1<27) */ /* unknown (1<28) */ #define NTLMFLAG_NEGOTIATE_128 (1<<29) /* Indicates that 128-bit encryption is supported. */ #define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30) /* Indicates that the client will provide an encrypted master key in the "Session Key" field of the Type 3 message. */ #define NTLMFLAG_NEGOTIATE_56 (1<<31) /* Indicates that 56-bit encryption is supported. */ #endif /* BUILDING_CURL_NTLM_MSGS_C */ #endif /* USE_NTLM */ #endif /* HEADER_VAUTH_NTLM_H */ davix-0.8.0/deps/curl/lib/vauth/ntlm_sspi.c0000644000000000000000000003047414121063461017307 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM) #include #include "vauth/vauth.h" #include "urldata.h" #include "curl_base64.h" #include "curl_ntlm_core.h" #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_is_ntlm_supported() * * This is used to evaluate if NTLM is supported. * * Parameters: None * * Returns TRUE if NTLM is supported by Windows SSPI. */ bool Curl_auth_is_ntlm_supported(void) { PSecPkgInfo SecurityPackage; SECURITY_STATUS status; /* Query the security package for NTLM */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), &SecurityPackage); /* Release the package buffer as it is not required anymore */ if(status == SEC_E_OK) { s_pSecFn->FreeContextBuffer(SecurityPackage); } return (status == SEC_E_OK ? TRUE : FALSE); } /* * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for * sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, const char *host, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { PSecPkgInfo SecurityPackage; SecBuffer type_1_buf; SecBufferDesc type_1_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Clean up any former leftovers and initialise to defaults */ Curl_auth_cleanup_ntlm(ntlm); /* Query the security package for NTLM */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), &SecurityPackage); if(status != SEC_E_OK) return CURLE_NOT_BUILT_IN; ntlm->token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our output buffer */ ntlm->output_token = malloc(ntlm->token_max); if(!ntlm->output_token) return CURLE_OUT_OF_MEMORY; if(userp && *userp) { CURLcode result; /* Populate our identity structure */ result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); if(result) return result; /* Allow proper cleanup of the identity structure */ ntlm->p_identity = &ntlm->identity; } else /* Use the current Windows user */ ntlm->p_identity = NULL; /* Allocate our credentials handle */ ntlm->credentials = calloc(1, sizeof(CredHandle)); if(!ntlm->credentials) return CURLE_OUT_OF_MEMORY; /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_NTLM), SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, NULL, NULL, ntlm->credentials, &expiry); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; /* Allocate our new context handle */ ntlm->context = calloc(1, sizeof(CtxtHandle)); if(!ntlm->context) return CURLE_OUT_OF_MEMORY; ntlm->spn = Curl_auth_build_spn(service, host, NULL); if(!ntlm->spn) return CURLE_OUT_OF_MEMORY; /* Setup the type-1 "output" security buffer */ type_1_desc.ulVersion = SECBUFFER_VERSION; type_1_desc.cBuffers = 1; type_1_desc.pBuffers = &type_1_buf; type_1_buf.BufferType = SECBUFFER_TOKEN; type_1_buf.pvBuffer = ntlm->output_token; type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); /* Generate our type-1 message */ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, ntlm->spn, 0, 0, SECURITY_NETWORK_DREP, NULL, 0, ntlm->context, &type_1_desc, &attrs, &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); else if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) return CURLE_AUTH_ERROR; /* Base64 encode the response */ return Curl_base64_encode(data, (char *) ntlm->output_token, type_1_buf.cbBuffer, outptr, outlen); } /* * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. * * Parameters: * * data [in] - The session handle. * type2msg [in] - The base64 encoded type-2 message. * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { CURLcode result = CURLE_OK; unsigned char *type2 = NULL; size_t type2_len = 0; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif /* Decode the base-64 encoded type-2 message */ if(strlen(type2msg) && *type2msg != '=') { result = Curl_base64_decode(type2msg, &type2, &type2_len); if(result) return result; } /* Ensure we have a valid type-2 message */ if(!type2) { infof(data, "NTLM handshake failure (empty type-2 message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Simply store the challenge for use later */ ntlm->input_token = type2; ntlm->input_token_len = type2_len; return result; } /* * Curl_auth_create_ntlm_type3_message() * Curl_auth_create_ntlm_type3_message() * * This is used to generate an already encoded NTLM type-3 message ready for * sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; SecBuffer type_2_bufs[2]; SecBuffer type_3_buf; SecBufferDesc type_2_desc; SecBufferDesc type_3_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ (void) passwdp; (void) userp; /* Setup the type-2 "input" security buffer */ type_2_desc.ulVersion = SECBUFFER_VERSION; type_2_desc.cBuffers = 1; type_2_desc.pBuffers = &type_2_bufs[0]; type_2_bufs[0].BufferType = SECBUFFER_TOKEN; type_2_bufs[0].pvBuffer = ntlm->input_token; type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len); #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS /* ssl context comes from schannel. * When extended protection is used in IIS server, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. * https://docs.microsoft.com/en-us/security-updates * /SecurityAdvisories/2009/973811 */ if(ntlm->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; SecPkgContext_Bindings pkgBindings; pkgBindings.Bindings = &channelBindings; status = s_pSecFn->QueryContextAttributes( ntlm->sslContext, SECPKG_ATTR_ENDPOINT_BINDINGS, &pkgBindings ); if(status == SEC_E_OK) { type_2_desc.cBuffers++; type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength; type_2_bufs[1].pvBuffer = pkgBindings.Bindings; } } #endif /* Setup the type-3 "output" security buffer */ type_3_desc.ulVersion = SECBUFFER_VERSION; type_3_desc.cBuffers = 1; type_3_desc.pBuffers = &type_3_buf; type_3_buf.BufferType = SECBUFFER_TOKEN; type_3_buf.pvBuffer = ntlm->output_token; type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); /* Generate our type-3 message */ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, ntlm->context, ntlm->spn, 0, 0, SECURITY_NETWORK_DREP, &type_2_desc, 0, ntlm->context, &type_3_desc, &attrs, &expiry); if(status != SEC_E_OK) { infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", status); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; } /* Base64 encode the response */ result = Curl_base64_encode(data, (char *) ntlm->output_token, type_3_buf.cbBuffer, outptr, outlen); Curl_auth_cleanup_ntlm(ntlm); return result; } /* * Curl_auth_cleanup_ntlm() * * This is used to clean up the NTLM specific data. * * Parameters: * * ntlm [in/out] - The NTLM data struct being cleaned up. * */ void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm) { /* Free our security context */ if(ntlm->context) { s_pSecFn->DeleteSecurityContext(ntlm->context); free(ntlm->context); ntlm->context = NULL; } /* Free our credentials handle */ if(ntlm->credentials) { s_pSecFn->FreeCredentialsHandle(ntlm->credentials); free(ntlm->credentials); ntlm->credentials = NULL; } /* Free our identity */ Curl_sspi_free_identity(ntlm->p_identity); ntlm->p_identity = NULL; /* Free the input and output tokens */ Curl_safefree(ntlm->input_token); Curl_safefree(ntlm->output_token); /* Reset any variables */ ntlm->token_max = 0; Curl_safefree(ntlm->spn); } #endif /* USE_WINDOWS_SSPI && USE_NTLM */ davix-0.8.0/deps/curl/lib/vauth/digest.h0000644000000000000000000000316614121063461016561 0ustar rootroot#ifndef HEADER_CURL_DIGEST_H #define HEADER_CURL_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #if !defined(CURL_DISABLE_CRYPTO_AUTH) #define DIGEST_MAX_VALUE_LENGTH 256 #define DIGEST_MAX_CONTENT_LENGTH 1024 enum { CURLDIGESTALGO_MD5, CURLDIGESTALGO_MD5SESS, CURLDIGESTALGO_SHA256, CURLDIGESTALGO_SHA256SESS, CURLDIGESTALGO_SHA512_256, CURLDIGESTALGO_SHA512_256SESS }; /* This is used to extract the realm from a challenge message */ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, const char **endptr); #endif #endif /* HEADER_CURL_DIGEST_H */ davix-0.8.0/deps/curl/lib/vauth/cram.c0000644000000000000000000001045214121063461016213 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2195 CRAM-MD5 authentication * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_CRYPTO_AUTH) #include #include "urldata.h" #include "vauth/vauth.h" #include "curl_base64.h" #include "curl_hmac.h" #include "curl_md5.h" #include "warnless.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Curl_auth_decode_cram_md5_message() * * This is used to decode an already encoded CRAM-MD5 challenge message. * * Parameters: * * chlg64 [in] - The base64 encoded challenge message. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlg64len = strlen(chlg64); *outptr = NULL; *outlen = 0; /* Decode the challenge if necessary */ if(chlg64len && *chlg64 != '=') result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); return result; } /* * Curl_auth_create_cram_md5_message() * * This is used to generate an already encoded CRAM-MD5 response message ready * for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg [in] - The challenge. * userp [in] - The user name. * passwdp [in] - The user's password. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *chlg, const char *userp, const char *passwdp, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; HMAC_context *ctxt; unsigned char digest[MD5_DIGEST_LEN]; char *response; if(chlg) chlglen = strlen(chlg); /* Compute the digest using the password as the key */ ctxt = Curl_HMAC_init(Curl_HMAC_MD5, (const unsigned char *) passwdp, curlx_uztoui(strlen(passwdp))); if(!ctxt) return CURLE_OUT_OF_MEMORY; /* Update the digest with the given challenge */ if(chlglen > 0) Curl_HMAC_update(ctxt, (const unsigned char *) chlg, curlx_uztoui(chlglen)); /* Finalise the digest */ Curl_HMAC_final(ctxt, digest); /* Generate the response */ response = aprintf( "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", userp, digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]); if(!response) return CURLE_OUT_OF_MEMORY; /* Base64 encode the response */ result = Curl_base64_encode(data, response, 0, outptr, outlen); free(response); return result; } #endif /* !CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/formdata.c0000644000000000000000000007230114121063461015740 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "formdata.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include #endif #include "urldata.h" /* for struct Curl_easy */ #include "mime.h" #include "non-ascii.h" #include "vtls/vtls.h" #include "strcase.h" #include "sendf.h" #include "strdup.h" #include "rand.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER /*************************************************************************** * * AddHttpPost() * * Adds a HttpPost structure to the list, if parent_post is given becomes * a subpost of parent_post instead of a direct list element. * * Returns newly allocated HttpPost on success and NULL if malloc failed. * ***************************************************************************/ static struct curl_httppost * AddHttpPost(char *name, size_t namelength, char *value, curl_off_t contentslength, char *buffer, size_t bufferlength, char *contenttype, long flags, struct curl_slist *contentHeader, char *showfilename, char *userp, struct curl_httppost *parent_post, struct curl_httppost **httppost, struct curl_httppost **last_post) { struct curl_httppost *post; post = calloc(1, sizeof(struct curl_httppost)); if(post) { post->name = name; post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); post->contents = value; post->contentlen = contentslength; post->buffer = buffer; post->bufferlength = (long)bufferlength; post->contenttype = contenttype; post->contentheader = contentHeader; post->showfilename = showfilename; post->userp = userp; post->flags = flags | CURL_HTTPPOST_LARGE; } else return NULL; if(parent_post) { /* now, point our 'more' to the original 'more' */ post->more = parent_post->more; /* then move the original 'more' to point to ourselves */ parent_post->more = post; } else { /* make the previous point to this */ if(*last_post) (*last_post)->next = post; else (*httppost) = post; (*last_post) = post; } return post; } /*************************************************************************** * * AddFormInfo() * * Adds a FormInfo structure to the list presented by parent_form_info. * * Returns newly allocated FormInfo on success and NULL if malloc failed/ * parent_form_info is NULL. * ***************************************************************************/ static FormInfo * AddFormInfo(char *value, char *contenttype, FormInfo *parent_form_info) { FormInfo *form_info; form_info = calloc(1, sizeof(struct FormInfo)); if(form_info) { if(value) form_info->value = value; if(contenttype) form_info->contenttype = contenttype; form_info->flags = HTTPPOST_FILENAME; } else return NULL; if(parent_form_info) { /* now, point our 'more' to the original 'more' */ form_info->more = parent_form_info->more; /* then move the original 'more' to point to ourselves */ parent_form_info->more = form_info; } return form_info; } /*************************************************************************** * * FormAdd() * * Stores a formpost parameter and builds the appropriate linked list. * * Has two principal functionalities: using files and byte arrays as * post parts. Byte arrays are either copied or just the pointer is stored * (as the user requests) while for files only the filename and not the * content is stored. * * While you may have only one byte array for each name, multiple filenames * are allowed (and because of this feature CURLFORM_END is needed after * using CURLFORM_FILE). * * Examples: * * Simple name/value pair with copied contents: * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); * * name/value pair where only the content pointer is remembered: * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) * * storing a filename (CONTENTTYPE is optional!): * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", * CURLFORM_END); * * storing multiple filenames: * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); * * Returns: * CURL_FORMADD_OK on success * CURL_FORMADD_MEMORY if the FormInfo allocation fails * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form * CURL_FORMADD_NULL if a null pointer was given for a char * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated * CURL_FORMADD_MEMORY if some allocation for string copying failed. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array * ***************************************************************************/ static CURLFORMcode FormAdd(struct curl_httppost **httppost, struct curl_httppost **last_post, va_list params) { FormInfo *first_form, *current_form, *form = NULL; CURLFORMcode return_value = CURL_FORMADD_OK; const char *prevtype = NULL; struct curl_httppost *post = NULL; CURLformoption option; struct curl_forms *forms = NULL; char *array_value = NULL; /* value read from an array */ /* This is a state variable, that if TRUE means that we're parsing an array that we got passed to us. If FALSE we're parsing the input va_list arguments. */ bool array_state = FALSE; /* * We need to allocate the first struct to fill in. */ first_form = calloc(1, sizeof(struct FormInfo)); if(!first_form) return CURL_FORMADD_MEMORY; current_form = first_form; /* * Loop through all the options set. Break if we have an error to report. */ while(return_value == CURL_FORMADD_OK) { /* first see if we have more parts of the array param */ if(array_state && forms) { /* get the upcoming option from the given array */ option = forms->option; array_value = (char *)forms->value; forms++; /* advance this to next entry */ if(CURLFORM_END == option) { /* end of array state */ array_state = FALSE; continue; } } else { /* This is not array-state, get next option */ option = va_arg(params, CURLformoption); if(CURLFORM_END == option) break; } switch(option) { case CURLFORM_ARRAY: if(array_state) /* we don't support an array from within an array */ return_value = CURL_FORMADD_ILLEGAL_ARRAY; else { forms = va_arg(params, struct curl_forms *); if(forms) array_state = TRUE; else return_value = CURL_FORMADD_NULL; } break; /* * Set the Name property. */ case CURLFORM_PTRNAME: #ifdef CURL_DOES_CONVERSIONS /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy * the data in all cases so that we'll have safe memory for the eventual * conversion. */ #else current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ #endif /* FALLTHROUGH */ case CURLFORM_COPYNAME: if(current_form->name) return_value = CURL_FORMADD_OPTION_TWICE; else { char *name = array_state? array_value:va_arg(params, char *); if(name) current_form->name = name; /* store for the moment */ else return_value = CURL_FORMADD_NULL; } break; case CURLFORM_NAMELENGTH: if(current_form->namelength) return_value = CURL_FORMADD_OPTION_TWICE; else current_form->namelength = array_state?(size_t)array_value:(size_t)va_arg(params, long); break; /* * Set the contents property. */ case CURLFORM_PTRCONTENTS: current_form->flags |= HTTPPOST_PTRCONTENTS; /* FALLTHROUGH */ case CURLFORM_COPYCONTENTS: if(current_form->value) return_value = CURL_FORMADD_OPTION_TWICE; else { char *value = array_state?array_value:va_arg(params, char *); if(value) current_form->value = value; /* store for the moment */ else return_value = CURL_FORMADD_NULL; } break; case CURLFORM_CONTENTSLENGTH: current_form->contentslength = array_state?(size_t)array_value:(size_t)va_arg(params, long); break; case CURLFORM_CONTENTLEN: current_form->flags |= CURL_HTTPPOST_LARGE; current_form->contentslength = array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); break; /* Get contents from a given file name */ case CURLFORM_FILECONTENT: if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) return_value = CURL_FORMADD_OPTION_TWICE; else { const char *filename = array_state? array_value:va_arg(params, char *); if(filename) { current_form->value = strdup(filename); if(!current_form->value) return_value = CURL_FORMADD_MEMORY; else { current_form->flags |= HTTPPOST_READFILE; current_form->value_alloc = TRUE; } } else return_value = CURL_FORMADD_NULL; } break; /* We upload a file */ case CURLFORM_FILE: { const char *filename = array_state?array_value: va_arg(params, char *); if(current_form->value) { if(current_form->flags & HTTPPOST_FILENAME) { if(filename) { char *fname = strdup(filename); if(!fname) return_value = CURL_FORMADD_MEMORY; else { form = AddFormInfo(fname, NULL, current_form); if(!form) { free(fname); return_value = CURL_FORMADD_MEMORY; } else { form->value_alloc = TRUE; current_form = form; form = NULL; } } } else return_value = CURL_FORMADD_NULL; } else return_value = CURL_FORMADD_OPTION_TWICE; } else { if(filename) { current_form->value = strdup(filename); if(!current_form->value) return_value = CURL_FORMADD_MEMORY; else { current_form->flags |= HTTPPOST_FILENAME; current_form->value_alloc = TRUE; } } else return_value = CURL_FORMADD_NULL; } break; } case CURLFORM_BUFFERPTR: current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; if(current_form->buffer) return_value = CURL_FORMADD_OPTION_TWICE; else { char *buffer = array_state?array_value:va_arg(params, char *); if(buffer) { current_form->buffer = buffer; /* store for the moment */ current_form->value = buffer; /* make it non-NULL to be accepted as fine */ } else return_value = CURL_FORMADD_NULL; } break; case CURLFORM_BUFFERLENGTH: if(current_form->bufferlength) return_value = CURL_FORMADD_OPTION_TWICE; else current_form->bufferlength = array_state?(size_t)array_value:(size_t)va_arg(params, long); break; case CURLFORM_STREAM: current_form->flags |= HTTPPOST_CALLBACK; if(current_form->userp) return_value = CURL_FORMADD_OPTION_TWICE; else { char *userp = array_state?array_value:va_arg(params, char *); if(userp) { current_form->userp = userp; current_form->value = userp; /* this isn't strictly true but we derive a value from this later on and we need this non-NULL to be accepted as a fine form part */ } else return_value = CURL_FORMADD_NULL; } break; case CURLFORM_CONTENTTYPE: { const char *contenttype = array_state?array_value:va_arg(params, char *); if(current_form->contenttype) { if(current_form->flags & HTTPPOST_FILENAME) { if(contenttype) { char *type = strdup(contenttype); if(!type) return_value = CURL_FORMADD_MEMORY; else { form = AddFormInfo(NULL, type, current_form); if(!form) { free(type); return_value = CURL_FORMADD_MEMORY; } else { form->contenttype_alloc = TRUE; current_form = form; form = NULL; } } } else return_value = CURL_FORMADD_NULL; } else return_value = CURL_FORMADD_OPTION_TWICE; } else { if(contenttype) { current_form->contenttype = strdup(contenttype); if(!current_form->contenttype) return_value = CURL_FORMADD_MEMORY; else current_form->contenttype_alloc = TRUE; } else return_value = CURL_FORMADD_NULL; } break; } case CURLFORM_CONTENTHEADER: { /* this "cast increases required alignment of target type" but we consider it OK anyway */ struct curl_slist *list = array_state? (struct curl_slist *)(void *)array_value: va_arg(params, struct curl_slist *); if(current_form->contentheader) return_value = CURL_FORMADD_OPTION_TWICE; else current_form->contentheader = list; break; } case CURLFORM_FILENAME: case CURLFORM_BUFFER: { const char *filename = array_state?array_value: va_arg(params, char *); if(current_form->showfilename) return_value = CURL_FORMADD_OPTION_TWICE; else { current_form->showfilename = strdup(filename); if(!current_form->showfilename) return_value = CURL_FORMADD_MEMORY; else current_form->showfilename_alloc = TRUE; } break; } default: return_value = CURL_FORMADD_UNKNOWN_OPTION; break; } } if(CURL_FORMADD_OK != return_value) { /* On error, free allocated fields for all nodes of the FormInfo linked list without deallocating nodes. List nodes are deallocated later on */ FormInfo *ptr; for(ptr = first_form; ptr != NULL; ptr = ptr->more) { if(ptr->name_alloc) { Curl_safefree(ptr->name); ptr->name_alloc = FALSE; } if(ptr->value_alloc) { Curl_safefree(ptr->value); ptr->value_alloc = FALSE; } if(ptr->contenttype_alloc) { Curl_safefree(ptr->contenttype); ptr->contenttype_alloc = FALSE; } if(ptr->showfilename_alloc) { Curl_safefree(ptr->showfilename); ptr->showfilename_alloc = FALSE; } } } if(CURL_FORMADD_OK == return_value) { /* go through the list, check for completeness and if everything is * alright add the HttpPost item otherwise set return_value accordingly */ post = NULL; for(form = first_form; form != NULL; form = form->more) { if(((!form->name || !form->value) && !post) || ( (form->contentslength) && (form->flags & HTTPPOST_FILENAME) ) || ( (form->flags & HTTPPOST_FILENAME) && (form->flags & HTTPPOST_PTRCONTENTS) ) || ( (!form->buffer) && (form->flags & HTTPPOST_BUFFER) && (form->flags & HTTPPOST_PTRBUFFER) ) || ( (form->flags & HTTPPOST_READFILE) && (form->flags & HTTPPOST_PTRCONTENTS) ) ) { return_value = CURL_FORMADD_INCOMPLETE; break; } if(((form->flags & HTTPPOST_FILENAME) || (form->flags & HTTPPOST_BUFFER)) && !form->contenttype) { char *f = (form->flags & HTTPPOST_BUFFER)? form->showfilename : form->value; char const *type; type = Curl_mime_contenttype(f); if(!type) type = prevtype; if(!type) type = FILE_CONTENTTYPE_DEFAULT; /* our contenttype is missing */ form->contenttype = strdup(type); if(!form->contenttype) { return_value = CURL_FORMADD_MEMORY; break; } form->contenttype_alloc = TRUE; } if(form->name && form->namelength) { /* Name should not contain nul bytes. */ size_t i; for(i = 0; i < form->namelength; i++) if(!form->name[i]) { return_value = CURL_FORMADD_NULL; break; } if(return_value != CURL_FORMADD_OK) break; } if(!(form->flags & HTTPPOST_PTRNAME) && (form == first_form) ) { /* Note that there's small risk that form->name is NULL here if the app passed in a bad combo, so we better check for that first. */ if(form->name) { /* copy name (without strdup; possibly not nul-terminated) */ form->name = Curl_memdup(form->name, form->namelength? form->namelength: strlen(form->name) + 1); } if(!form->name) { return_value = CURL_FORMADD_MEMORY; break; } form->name_alloc = TRUE; } if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | HTTPPOST_CALLBACK)) && form->value) { /* copy value (without strdup; possibly contains null characters) */ size_t clen = (size_t) form->contentslength; if(!clen) clen = strlen(form->value) + 1; form->value = Curl_memdup(form->value, clen); if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; } form->value_alloc = TRUE; } post = AddHttpPost(form->name, form->namelength, form->value, form->contentslength, form->buffer, form->bufferlength, form->contenttype, form->flags, form->contentheader, form->showfilename, form->userp, post, httppost, last_post); if(!post) { return_value = CURL_FORMADD_MEMORY; break; } if(form->contenttype) prevtype = form->contenttype; } if(CURL_FORMADD_OK != return_value) { /* On error, free allocated fields for nodes of the FormInfo linked list which are not already owned by the httppost linked list without deallocating nodes. List nodes are deallocated later on */ FormInfo *ptr; for(ptr = form; ptr != NULL; ptr = ptr->more) { if(ptr->name_alloc) { Curl_safefree(ptr->name); ptr->name_alloc = FALSE; } if(ptr->value_alloc) { Curl_safefree(ptr->value); ptr->value_alloc = FALSE; } if(ptr->contenttype_alloc) { Curl_safefree(ptr->contenttype); ptr->contenttype_alloc = FALSE; } if(ptr->showfilename_alloc) { Curl_safefree(ptr->showfilename); ptr->showfilename_alloc = FALSE; } } } } /* Always deallocate FormInfo linked list nodes without touching node fields given that these have either been deallocated or are owned now by the httppost linked list */ while(first_form) { FormInfo *ptr = first_form->more; free(first_form); first_form = ptr; } return return_value; } /* * curl_formadd() is a public API to add a section to the multipart formpost. * * @unittest: 1308 */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...) { va_list arg; CURLFORMcode result; va_start(arg, last_post); result = FormAdd(httppost, last_post, arg); va_end(arg); return result; } /* * curl_formget() * Serialize a curl_httppost struct. * Returns 0 on success. * * @unittest: 1308 */ int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { CURLcode result; curl_mimepart toppart; Curl_mime_initpart(&toppart, NULL); /* default form is empty */ result = Curl_getformdata(NULL, &toppart, form, NULL); if(!result) result = Curl_mime_prepare_headers(&toppart, "multipart/form-data", NULL, MIMESTRATEGY_FORM); while(!result) { char buffer[8192]; size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart); if(!nread) break; switch(nread) { default: if(append(arg, buffer, nread) != nread) result = CURLE_READ_ERROR; break; case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: break; } } Curl_mime_cleanpart(&toppart); return (int) result; } /* * curl_formfree() is an external function to free up a whole form post * chain */ void curl_formfree(struct curl_httppost *form) { struct curl_httppost *next; if(!form) /* no form to free, just get out of this */ return; do { next = form->next; /* the following form line */ /* recurse to sub-contents */ curl_formfree(form->more); if(!(form->flags & HTTPPOST_PTRNAME)) free(form->name); /* free the name */ if(!(form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) ) free(form->contents); /* free the contents */ free(form->contenttype); /* free the content type */ free(form->showfilename); /* free the faked file name */ free(form); /* free the struct */ form = next; } while(form); /* continue */ } /* Set mime part name, taking care of non nul-terminated name string. */ static CURLcode setname(curl_mimepart *part, const char *name, size_t len) { char *zname; CURLcode res; if(!name || !len) return curl_mime_name(part, name); zname = malloc(len + 1); if(!zname) return CURLE_OUT_OF_MEMORY; memcpy(zname, name, len); zname[len] = '\0'; res = curl_mime_name(part, zname); free(zname); return res; } /* * Curl_getformdata() converts a linked list of "meta data" into a mime * structure. The input list is in 'post', while the output is stored in * mime part at '*finalform'. * * This function will not do a failf() for the potential memory failures but * should for all other errors it spots. Just note that this function MAY get * a NULL pointer in the 'data' argument. */ CURLcode Curl_getformdata(struct Curl_easy *data, curl_mimepart *finalform, struct curl_httppost *post, curl_read_callback fread_func) { CURLcode result = CURLE_OK; curl_mime *form = NULL; curl_mimepart *part; struct curl_httppost *file; Curl_mime_cleanpart(finalform); /* default form is empty */ if(!post) return result; /* no input => no output! */ form = curl_mime_init(data); if(!form) result = CURLE_OUT_OF_MEMORY; if(!result) result = curl_mime_subparts(finalform, form); /* Process each top part. */ for(; !result && post; post = post->next) { /* If we have more than a file here, create a mime subpart and fill it. */ curl_mime *multipart = form; if(post->more) { part = curl_mime_addpart(form); if(!part) result = CURLE_OUT_OF_MEMORY; if(!result) result = setname(part, post->name, post->namelength); if(!result) { multipart = curl_mime_init(data); if(!multipart) result = CURLE_OUT_OF_MEMORY; } if(!result) result = curl_mime_subparts(part, multipart); } /* Generate all the part contents. */ for(file = post; !result && file; file = file->more) { /* Create the part. */ part = curl_mime_addpart(multipart); if(!part) result = CURLE_OUT_OF_MEMORY; /* Set the headers. */ if(!result) result = curl_mime_headers(part, file->contentheader, 0); /* Set the content type. */ if(!result && file->contenttype) result = curl_mime_type(part, file->contenttype); /* Set field name. */ if(!result && !post->more) result = setname(part, post->name, post->namelength); /* Process contents. */ if(!result) { curl_off_t clen = post->contentslength; if(post->flags & CURL_HTTPPOST_LARGE) clen = post->contentlen; if(!clen) clen = -1; if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) { if(!strcmp(file->contents, "-")) { /* There are a few cases where the code below won't work; in particular, freopen(stdin) by the caller is not guaranteed to result as expected. This feature has been kept for backward compatibility: use of "-" pseudo file name should be avoided. */ result = curl_mime_data_cb(part, (curl_off_t) -1, (curl_read_callback) fread, CURLX_FUNCTION_CAST(curl_seek_callback, fseek), NULL, (void *) stdin); } else result = curl_mime_filedata(part, file->contents); if(!result && (post->flags & HTTPPOST_READFILE)) result = curl_mime_filename(part, NULL); } else if(post->flags & HTTPPOST_BUFFER) result = curl_mime_data(part, post->buffer, post->bufferlength? post->bufferlength: -1); else if(post->flags & HTTPPOST_CALLBACK) /* the contents should be read with the callback and the size is set with the contentslength */ result = curl_mime_data_cb(part, clen, fread_func, NULL, NULL, post->userp); else { result = curl_mime_data(part, post->contents, (ssize_t) clen); #ifdef CURL_DOES_CONVERSIONS /* Convert textual contents now. */ if(!result && data && part->datasize) result = Curl_convert_to_network(data, part->data, part->datasize); #endif } } /* Set fake file name. */ if(!result && post->showfilename) if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER | HTTPPOST_CALLBACK))) result = curl_mime_filename(part, post->showfilename); } } if(result) Curl_mime_cleanpart(finalform); return result; } #else /* if disabled */ CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...) { (void)httppost; (void)last_post; return CURL_FORMADD_DISABLED; } int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { (void) form; (void) arg; (void) append; return CURL_FORMADD_DISABLED; } void curl_formfree(struct curl_httppost *form) { (void)form; /* does nothing HTTP is disabled */ } #endif /* if disabled */ davix-0.8.0/deps/curl/lib/select.h0000644000000000000000000000607314121063461015432 0ustar rootroot#ifndef HEADER_CURL_SELECT_H #define HEADER_CURL_SELECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_POLL_H #include #elif defined(HAVE_SYS_POLL_H) #include #endif /* * Definition of pollfd struct and constants for platforms lacking them. */ #if !defined(HAVE_STRUCT_POLLFD) && \ !defined(HAVE_SYS_POLL_H) && \ !defined(HAVE_POLL_H) && \ !defined(POLLIN) #define POLLIN 0x01 #define POLLPRI 0x02 #define POLLOUT 0x04 #define POLLERR 0x08 #define POLLHUP 0x10 #define POLLNVAL 0x20 struct pollfd { curl_socket_t fd; short events; short revents; }; #endif #ifndef POLLRDNORM #define POLLRDNORM POLLIN #endif #ifndef POLLWRNORM #define POLLWRNORM POLLOUT #endif #ifndef POLLRDBAND #define POLLRDBAND POLLPRI #endif /* there are three CSELECT defines that are defined in the public header that are exposed to users, but this *IN2 bit is only ever used internally and therefore defined here */ #define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1) int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, time_t timeout_ms); #define SOCKET_READABLE(x,z) \ Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, (time_t)z) #define SOCKET_WRITABLE(x,z) \ Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, (time_t)z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); int Curl_wait_ms(int timeout_ms); #ifdef TPF int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, fd_set* excepts, struct timeval* tv); #endif /* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which unfortunately makes it impossible for us to easily check if they're valid */ #if defined(USE_WINSOCK) || defined(TPF) #define VALID_SOCK(x) 1 #define VERIFY_SOCK(x) Curl_nop_stmt #else #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) #define VERIFY_SOCK(x) do { \ if(!VALID_SOCK(x)) { \ SET_SOCKERRNO(EINVAL); \ return -1; \ } \ } while(0) #endif #endif /* HEADER_CURL_SELECT_H */ davix-0.8.0/deps/curl/lib/firefox-db2pem.sh0000644000000000000000000000354214121063461017145 0ustar rootroot#!/bin/sh # *************************************************************************** # * _ _ ____ _ # * Project ___| | | | _ \| | # * / __| | | | |_) | | # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * # * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms # * are also available at https://curl.haxx.se/docs/copyright.html. # * # * You may opt to use, copy, modify, merge, publish, distribute and/or sell # * copies of the Software, and permit persons to whom the Software is # * furnished to do so, under the terms of the COPYING file. # * # * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # * KIND, either express or implied. # * # *************************************************************************** # This shell script creates a fresh ca-bundle.crt file for use with libcurl. # It extracts all ca certs it finds in the local Firefox database and converts # them all into PEM format. # db=`ls -1d $HOME/.mozilla/firefox/*default*` out=$1 if test -z "$out"; then out="ca-bundle.crt" # use a sensible default fi currentdate=`date` cat >$out <> $out davix-0.8.0/deps/curl/lib/curl_sec.h0000644000000000000000000000356214121063461015752 0ustar rootroot#ifndef HEADER_CURL_SECURITY_H #define HEADER_CURL_SECURITY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ struct Curl_sec_client_mech { const char *name; size_t size; int (*init)(void *); int (*auth)(void *, struct connectdata *); void (*end)(void *); int (*check_prot)(void *, int); int (*overhead)(void *, int, int); int (*encode)(void *, const void *, int, int, void **); int (*decode)(void *, void *, int, int, struct connectdata *); }; #define AUTH_OK 0 #define AUTH_CONTINUE 1 #define AUTH_ERROR 2 #ifdef HAVE_GSSAPI int Curl_sec_read_msg(struct connectdata *conn, char *, enum protection_level); void Curl_sec_end(struct connectdata *); CURLcode Curl_sec_login(struct connectdata *); int Curl_sec_request_prot(struct connectdata *conn, const char *level); extern struct Curl_sec_client_mech Curl_krb5_client_mech; #endif #endif /* HEADER_CURL_SECURITY_H */ davix-0.8.0/deps/curl/lib/system_win32.c0000644000000000000000000003163314121063461016514 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2016 - 2020, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(WIN32) #include #include "system_win32.h" #include "curl_sspi.h" #include "warnless.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" LARGE_INTEGER Curl_freq; bool Curl_isVistaOrGreater; /* Handle of iphlpapp.dll */ static HMODULE s_hIpHlpApiDll = NULL; /* Pointer to the if_nametoindex function */ IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL; /* Curl_win32_init() performs win32 global initialization */ CURLcode Curl_win32_init(long flags) { /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which is just for Winsock at the moment. Any required win32 initialization should take place after this block. */ if(flags & CURL_GLOBAL_WIN32) { #ifdef USE_WINSOCK WORD wVersionRequested; WSADATA wsaData; int res; #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2) #error IPV6_requires_winsock2 #endif wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK); res = WSAStartup(wVersionRequested, &wsaData); if(res != 0) /* Tell the user that we couldn't find a usable */ /* winsock.dll. */ return CURLE_FAILED_INIT; /* Confirm that the Windows Sockets DLL supports what we need.*/ /* Note that if the DLL supports versions greater */ /* than wVersionRequested, it will still return */ /* wVersionRequested in wVersion. wHighVersion contains the */ /* highest supported version. */ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { /* Tell the user that we couldn't find a usable */ /* winsock.dll. */ WSACleanup(); return CURLE_FAILED_INIT; } /* The Windows Sockets DLL is acceptable. Proceed. */ #elif defined(USE_LWIPSOCK) lwip_init(); #endif } /* CURL_GLOBAL_WIN32 */ #ifdef USE_WINDOWS_SSPI { CURLcode result = Curl_sspi_global_init(); if(result) return result; } #endif s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll")); if(s_hIpHlpApiDll) { /* Get the address of the if_nametoindex function */ IF_NAMETOINDEX_FN pIfNameToIndex = CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN, (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex"))); if(pIfNameToIndex) Curl_if_nametoindex = pIfNameToIndex; } if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { Curl_isVistaOrGreater = TRUE; } else Curl_isVistaOrGreater = FALSE; QueryPerformanceFrequency(&Curl_freq); return CURLE_OK; } /* Curl_win32_cleanup() is the opposite of Curl_win32_init() */ void Curl_win32_cleanup(long init_flags) { if(s_hIpHlpApiDll) { FreeLibrary(s_hIpHlpApiDll); s_hIpHlpApiDll = NULL; Curl_if_nametoindex = NULL; } #ifdef USE_WINDOWS_SSPI Curl_sspi_global_cleanup(); #endif if(init_flags & CURL_GLOBAL_WIN32) { #ifdef USE_WINSOCK WSACleanup(); #endif } } #if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 #endif #if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif /* We use our own typedef here since some headers might lack these */ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); /* See function definitions in winbase.h */ #ifdef UNICODE # ifdef _WIN32_WCE # define LOADLIBARYEX L"LoadLibraryExW" # else # define LOADLIBARYEX "LoadLibraryExW" # endif #else # define LOADLIBARYEX "LoadLibraryExA" #endif /* * Curl_verify_windows_version() * * This is used to verify if we are running on a specific windows version. * * Parameters: * * majorVersion [in] - The major version number. * minorVersion [in] - The minor version number. * platform [in] - The optional platform identifier. * condition [in] - The test condition used to specifier whether we are * checking a version less then, equal to or greater than * what is specified in the major and minor version * numbers. * * Returns TRUE if matched; otherwise FALSE. */ bool Curl_verify_windows_version(const unsigned int majorVersion, const unsigned int minorVersion, const PlatformIdentifier platform, const VersionCondition condition) { bool matched = FALSE; #if defined(CURL_WINDOWS_APP) /* We have no way to determine the Windows version from Windows apps, so let's assume we're running on the target Windows version. */ const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); const WORD targetVersion = (WORD)_WIN32_WINNT; switch(condition) { case VERSION_LESS_THAN: matched = targetVersion < fullVersion; break; case VERSION_LESS_THAN_EQUAL: matched = targetVersion <= fullVersion; break; case VERSION_EQUAL: matched = targetVersion == fullVersion; break; case VERSION_GREATER_THAN_EQUAL: matched = targetVersion >= fullVersion; break; case VERSION_GREATER_THAN: matched = targetVersion > fullVersion; break; } if(matched && (platform == PLATFORM_WINDOWS)) { /* we're always running on PLATFORM_WINNT */ matched = FALSE; } #elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ (_WIN32_WINNT < _WIN32_WINNT_WIN2K) OSVERSIONINFO osver; memset(&osver, 0, sizeof(osver)); osver.dwOSVersionInfoSize = sizeof(osver); /* Find out Windows version */ if(GetVersionEx(&osver)) { /* Verify the Operating System version number */ switch(condition) { case VERSION_LESS_THAN: if(osver.dwMajorVersion < majorVersion || (osver.dwMajorVersion == majorVersion && osver.dwMinorVersion < minorVersion)) matched = TRUE; break; case VERSION_LESS_THAN_EQUAL: if(osver.dwMajorVersion < majorVersion || (osver.dwMajorVersion == majorVersion && osver.dwMinorVersion <= minorVersion)) matched = TRUE; break; case VERSION_EQUAL: if(osver.dwMajorVersion == majorVersion && osver.dwMinorVersion == minorVersion) matched = TRUE; break; case VERSION_GREATER_THAN_EQUAL: if(osver.dwMajorVersion > majorVersion || (osver.dwMajorVersion == majorVersion && osver.dwMinorVersion >= minorVersion)) matched = TRUE; break; case VERSION_GREATER_THAN: if(osver.dwMajorVersion > majorVersion || (osver.dwMajorVersion == majorVersion && osver.dwMinorVersion > minorVersion)) matched = TRUE; break; } /* Verify the platform identifier (if necessary) */ if(matched) { switch(platform) { case PLATFORM_WINDOWS: if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) matched = FALSE; break; case PLATFORM_WINNT: if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) matched = FALSE; default: /* like platform == PLATFORM_DONT_CARE */ break; } } } #else ULONGLONG cm = 0; OSVERSIONINFOEX osver; BYTE majorCondition; BYTE minorCondition; BYTE spMajorCondition; BYTE spMinorCondition; switch(condition) { case VERSION_LESS_THAN: majorCondition = VER_LESS; minorCondition = VER_LESS; spMajorCondition = VER_LESS_EQUAL; spMinorCondition = VER_LESS_EQUAL; break; case VERSION_LESS_THAN_EQUAL: majorCondition = VER_LESS_EQUAL; minorCondition = VER_LESS_EQUAL; spMajorCondition = VER_LESS_EQUAL; spMinorCondition = VER_LESS_EQUAL; break; case VERSION_EQUAL: majorCondition = VER_EQUAL; minorCondition = VER_EQUAL; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; case VERSION_GREATER_THAN_EQUAL: majorCondition = VER_GREATER_EQUAL; minorCondition = VER_GREATER_EQUAL; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; case VERSION_GREATER_THAN: majorCondition = VER_GREATER; minorCondition = VER_GREATER; spMajorCondition = VER_GREATER_EQUAL; spMinorCondition = VER_GREATER_EQUAL; break; default: return FALSE; } memset(&osver, 0, sizeof(osver)); osver.dwOSVersionInfoSize = sizeof(osver); osver.dwMajorVersion = majorVersion; osver.dwMinorVersion = minorVersion; if(platform == PLATFORM_WINDOWS) osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; else if(platform == PLATFORM_WINNT) osver.dwPlatformId = VER_PLATFORM_WIN32_NT; cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); if(platform != PLATFORM_DONT_CARE) cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), cm)) matched = TRUE; #endif return matched; } /* * Curl_load_library() * * This is used to dynamically load DLLs using the most secure method available * for the version of Windows that we are running on. * * Parameters: * * filename [in] - The filename or full path of the DLL to load. If only the * filename is passed then the DLL will be loaded from the * Windows system directory. * * Returns the handle of the module on success; otherwise NULL. */ HMODULE Curl_load_library(LPCTSTR filename) { #ifndef CURL_WINDOWS_APP HMODULE hModule = NULL; LOADLIBRARYEX_FN pLoadLibraryEx = NULL; /* Get a handle to kernel32 so we can access it's functions at runtime */ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32")); if(!hKernel32) return NULL; /* Attempt to find LoadLibraryEx() which is only available on Windows 2000 and above */ pLoadLibraryEx = CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN, (GetProcAddress(hKernel32, LOADLIBARYEX))); /* Detect if there's already a path in the filename and load the library if there is. Note: Both back slashes and forward slashes have been supported since the earlier days of DOS at an API level although they are not supported by command prompt */ if(_tcspbrk(filename, TEXT("\\/"))) { /** !checksrc! disable BANNEDFUNC 1 **/ hModule = pLoadLibraryEx ? pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : LoadLibrary(filename); } /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only supported on Windows Vista, Windows Server 2008, Windows 7 and Windows Server 2008 R2 with this patch or natively on Windows 8 and above */ else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) { /* Load the DLL from the Windows system directory */ hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); } else { /* Attempt to get the Windows system path */ UINT systemdirlen = GetSystemDirectory(NULL, 0); if(systemdirlen) { /* Allocate space for the full DLL path (Room for the null terminator is included in systemdirlen) */ size_t filenamelen = _tcslen(filename); TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); if(path && GetSystemDirectory(path, systemdirlen)) { /* Calculate the full DLL path */ _tcscpy(path + _tcslen(path), TEXT("\\")); _tcscpy(path + _tcslen(path), filename); /* Load the DLL from the Windows system directory */ /** !checksrc! disable BANNEDFUNC 1 **/ hModule = pLoadLibraryEx ? pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : LoadLibrary(path); } free(path); } } return hModule; #else /* the Universal Windows Platform (UWP) can't do this */ (void)filename; return NULL; #endif } #endif /* WIN32 */ davix-0.8.0/deps/curl/lib/x509asn1.h0000644000000000000000000001131014121063461015431 0ustar rootroot#ifndef HEADER_CURL_X509ASN1_H #define HEADER_CURL_X509ASN1_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ defined(USE_WOLFSSL) || defined(USE_SCHANNEL) #include "urldata.h" /* * Constants. */ /* Largest supported ASN.1 structure. */ #define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */ /* ASN.1 classes. */ #define CURL_ASN1_UNIVERSAL 0 #define CURL_ASN1_APPLICATION 1 #define CURL_ASN1_CONTEXT_SPECIFIC 2 #define CURL_ASN1_PRIVATE 3 /* ASN.1 types. */ #define CURL_ASN1_BOOLEAN 1 #define CURL_ASN1_INTEGER 2 #define CURL_ASN1_BIT_STRING 3 #define CURL_ASN1_OCTET_STRING 4 #define CURL_ASN1_NULL 5 #define CURL_ASN1_OBJECT_IDENTIFIER 6 #define CURL_ASN1_OBJECT_DESCRIPTOR 7 #define CURL_ASN1_INSTANCE_OF 8 #define CURL_ASN1_REAL 9 #define CURL_ASN1_ENUMERATED 10 #define CURL_ASN1_EMBEDDED 11 #define CURL_ASN1_UTF8_STRING 12 #define CURL_ASN1_RELATIVE_OID 13 #define CURL_ASN1_SEQUENCE 16 #define CURL_ASN1_SET 17 #define CURL_ASN1_NUMERIC_STRING 18 #define CURL_ASN1_PRINTABLE_STRING 19 #define CURL_ASN1_TELETEX_STRING 20 #define CURL_ASN1_VIDEOTEX_STRING 21 #define CURL_ASN1_IA5_STRING 22 #define CURL_ASN1_UTC_TIME 23 #define CURL_ASN1_GENERALIZED_TIME 24 #define CURL_ASN1_GRAPHIC_STRING 25 #define CURL_ASN1_VISIBLE_STRING 26 #define CURL_ASN1_GENERAL_STRING 27 #define CURL_ASN1_UNIVERSAL_STRING 28 #define CURL_ASN1_CHARACTER_STRING 29 #define CURL_ASN1_BMP_STRING 30 /* * Types. */ /* ASN.1 parsed element. */ typedef struct { const char * header; /* Pointer to header byte. */ const char * beg; /* Pointer to element data. */ const char * end; /* Pointer to 1st byte after element. */ unsigned char class; /* ASN.1 element class. */ unsigned char tag; /* ASN.1 element tag. */ bool constructed; /* Element is constructed. */ } curl_asn1Element; /* ASN.1 OID table entry. */ typedef struct { const char * numoid; /* Dotted-numeric OID. */ const char * textoid; /* OID name. */ } curl_OID; /* X509 certificate: RFC 5280. */ typedef struct { curl_asn1Element certificate; curl_asn1Element version; curl_asn1Element serialNumber; curl_asn1Element signatureAlgorithm; curl_asn1Element signature; curl_asn1Element issuer; curl_asn1Element notBefore; curl_asn1Element notAfter; curl_asn1Element subject; curl_asn1Element subjectPublicKeyInfo; curl_asn1Element subjectPublicKeyAlgorithm; curl_asn1Element subjectPublicKey; curl_asn1Element issuerUniqueID; curl_asn1Element subjectUniqueID; curl_asn1Element extensions; } curl_X509certificate; /* * Prototypes. */ const char *Curl_getASN1Element(curl_asn1Element *elem, const char *beg, const char *end); const char *Curl_ASN1tostr(curl_asn1Element *elem, int type); const char *Curl_DNtostr(curl_asn1Element *dn); int Curl_parseX509(curl_X509certificate *cert, const char *beg, const char *end); CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, const char *beg, const char *end); CURLcode Curl_verifyhost(struct connectdata *conn, const char *beg, const char *end); #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */ #endif /* HEADER_CURL_X509ASN1_H */ davix-0.8.0/deps/curl/lib/curl_md5.h0000644000000000000000000000475014121063461015665 0ustar rootroot#ifndef HEADER_CURL_MD5_H #define HEADER_CURL_MD5_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH #include "curl_hmac.h" #define MD5_DIGEST_LEN 16 typedef void (* Curl_MD5_init_func)(void *context); typedef void (* Curl_MD5_update_func)(void *context, const unsigned char *data, unsigned int len); typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context); typedef struct { Curl_MD5_init_func md5_init_func; /* Initialize context procedure */ Curl_MD5_update_func md5_update_func; /* Update context with data */ Curl_MD5_final_func md5_final_func; /* Get final result procedure */ unsigned int md5_ctxtsize; /* Context structure size */ unsigned int md5_resultlen; /* Result length (bytes) */ } MD5_params; typedef struct { const MD5_params *md5_hash; /* Hash function definition */ void *md5_hashctx; /* Hash function context */ } MD5_context; extern const MD5_params Curl_DIGEST_MD5[1]; extern const HMAC_params Curl_HMAC_MD5[1]; void Curl_md5it(unsigned char *output, const unsigned char *input, const size_t len); MD5_context * Curl_MD5_init(const MD5_params *md5params); CURLcode Curl_MD5_update(MD5_context *context, const unsigned char *data, unsigned int len); CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result); #endif #endif /* HEADER_CURL_MD5_H */ davix-0.8.0/deps/curl/lib/http2.h0000644000000000000000000000645214121063461015215 0ustar rootroot#ifndef HEADER_CURL_HTTP2_H #define HEADER_CURL_HTTP2_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGHTTP2 #include "http.h" /* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting from the peer */ #define DEFAULT_MAX_CONCURRENT_STREAMS 13 /* * Store nghttp2 version info in this buffer, Prefix with a space. Return * total length written. */ int Curl_http2_ver(char *p, size_t len); const char *Curl_http2_strerror(uint32_t err); CURLcode Curl_http2_init(struct connectdata *conn); void Curl_http2_init_state(struct UrlState *state); void Curl_http2_init_userset(struct UserDefined *set); CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, struct connectdata *conn); CURLcode Curl_http2_setup(struct connectdata *conn); CURLcode Curl_http2_switched(struct connectdata *conn, const char *data, size_t nread); /* called from http_setup_conn */ void Curl_http2_setup_conn(struct connectdata *conn); void Curl_http2_setup_req(struct Curl_easy *data); void Curl_http2_done(struct Curl_easy *data, bool premature); CURLcode Curl_http2_done_sending(struct connectdata *conn); CURLcode Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, bool exclusive); void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child); void Curl_http2_cleanup_dependencies(struct Curl_easy *data); CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause); /* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */ bool Curl_h2_http_1_1_error(struct connectdata *conn); #else /* USE_NGHTTP2 */ #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_setup_conn(x) Curl_nop_stmt #define Curl_http2_setup_req(x) #define Curl_http2_init_state(x) #define Curl_http2_init_userset(x) #define Curl_http2_done(x,y) #define Curl_http2_done_sending(x) #define Curl_http2_add_child(x, y, z) #define Curl_http2_remove_child(x, y) #define Curl_http2_cleanup_dependencies(x) #define Curl_http2_stream_pause(x, y) #define Curl_h2_http_1_1_error(x) 0 #endif #endif /* HEADER_CURL_HTTP2_H */ davix-0.8.0/deps/curl/lib/version.c0000644000000000000000000002515414121063461015634 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "vtls/vtls.h" #include "http2.h" #include "vssh/ssh.h" #include "quic.h" #include "curl_printf.h" #ifdef USE_ARES # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(__SYMBIAN32__)) # define CARES_STATICLIB # endif # include #endif #ifdef USE_LIBIDN2 #include #endif #ifdef USE_LIBPSL #include #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #include #endif #ifdef USE_LIBRTMP #include #endif #ifdef HAVE_ZLIB_H #include #ifdef __SYMBIAN32__ /* zlib pollutes the namespace with this definition */ #undef WIN32 #endif #endif #ifdef HAVE_BROTLI #include #endif void Curl_version_init(void); /* For thread safety purposes this function is called by global_init so that the static data in both version functions is initialized. */ void Curl_version_init(void) { curl_version(); curl_version_info(CURLVERSION_NOW); } #ifdef HAVE_BROTLI static size_t brotli_version(char *buf, size_t bufsz) { uint32_t brotli_version = BrotliDecoderVersion(); unsigned int major = brotli_version >> 24; unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; unsigned int patch = brotli_version & 0x00000FFF; return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch); } #endif char *curl_version(void) { static bool initialized; static char version[250]; char *ptr = version; size_t len; size_t left = sizeof(version); if(initialized) return version; strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION); len = strlen(ptr); left -= len; ptr += len; len = Curl_ssl_version(ptr + 1, left - 1); if(len > 0) { *ptr = ' '; left -= ++len; ptr += len; } #ifdef HAVE_LIBZ len = msnprintf(ptr, left, " zlib/%s", zlibVersion()); left -= len; ptr += len; #endif #ifdef HAVE_BROTLI len = msnprintf(ptr, left, "%s", " brotli/"); left -= len; ptr += len; len = brotli_version(ptr, left); left -= len; ptr += len; #endif #ifdef USE_ARES /* this function is only present in c-ares, not in the original ares */ len = msnprintf(ptr, left, " c-ares/%s", ares_version(NULL)); left -= len; ptr += len; #endif #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { len = msnprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); left -= len; ptr += len; } #endif #ifdef USE_LIBPSL len = msnprintf(ptr, left, " libpsl/%s", psl_get_version()); left -= len; ptr += len; #endif #ifdef USE_WIN32_IDN len = msnprintf(ptr, left, " WinIDN"); left -= len; ptr += len; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION len = msnprintf(ptr, left, " iconv/%d.%d", _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255); #else /* version unknown */ len = msnprintf(ptr, left, " iconv"); #endif /* _LIBICONV_VERSION */ left -= len; ptr += len; #endif #ifdef USE_SSH if(left) { *ptr++=' '; left--; } len = Curl_ssh_version(ptr, left); left -= len; ptr += len; #endif #ifdef USE_NGHTTP2 len = Curl_http2_ver(ptr, left); left -= len; ptr += len; #endif #ifdef ENABLE_QUIC len = Curl_quic_ver(ptr, left); left -= len; ptr += len; #endif #ifdef USE_LIBRTMP { char suff[2]; if(RTMP_LIB_VERSION & 0xff) { suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; suff[1] = '\0'; } else suff[0] = '\0'; msnprintf(ptr, left, " librtmp/%d.%d%s", RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, suff); /* If another lib version is added below this one, this code would also have to do: len = what msnprintf() returned left -= len; ptr += len; */ } #endif /* Silent scan-build even if librtmp is not enabled. */ (void) left; (void) ptr; initialized = true; return version; } /* data for curl_version_info Keep the list sorted alphabetically. It is also written so that each protocol line has its own #if line to make things easier on the eye. */ static const char * const protocols[] = { #ifndef CURL_DISABLE_DICT "dict", #endif #ifndef CURL_DISABLE_FILE "file", #endif #ifndef CURL_DISABLE_FTP "ftp", #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) "ftps", #endif #ifndef CURL_DISABLE_GOPHER "gopher", #endif #ifndef CURL_DISABLE_HTTP "http", #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) "https", #endif #ifndef CURL_DISABLE_IMAP "imap", #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) "imaps", #endif #ifndef CURL_DISABLE_LDAP "ldap", #if !defined(CURL_DISABLE_LDAPS) && \ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) "ldaps", #endif #endif #ifndef CURL_DISABLE_POP3 "pop3", #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) "pop3s", #endif #ifdef USE_LIBRTMP "rtmp", #endif #ifndef CURL_DISABLE_RTSP "rtsp", #endif #if defined(USE_SSH) && !defined(USE_WOLFSSH) "scp", #endif #ifdef USE_SSH "sftp", #endif #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ (CURL_SIZEOF_CURL_OFF_T > 4) && \ (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) "smb", # ifdef USE_SSL "smbs", # endif #endif #ifndef CURL_DISABLE_SMTP "smtp", #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) "smtps", #endif #ifndef CURL_DISABLE_TELNET "telnet", #endif #ifndef CURL_DISABLE_TFTP "tftp", #endif NULL }; static curl_version_info_data version_info = { CURLVERSION_NOW, LIBCURL_VERSION, LIBCURL_VERSION_NUM, OS, /* as found by configure or set by hand at build-time */ 0 /* features is 0 by default */ #ifdef ENABLE_IPV6 | CURL_VERSION_IPV6 #endif #ifdef USE_SSL | CURL_VERSION_SSL #endif #ifdef USE_NTLM | CURL_VERSION_NTLM #endif #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) | CURL_VERSION_NTLM_WB #endif #ifdef USE_SPNEGO | CURL_VERSION_SPNEGO #endif #ifdef USE_KERBEROS5 | CURL_VERSION_KERBEROS5 #endif #ifdef HAVE_GSSAPI | CURL_VERSION_GSSAPI #endif #ifdef USE_WINDOWS_SSPI | CURL_VERSION_SSPI #endif #ifdef HAVE_LIBZ | CURL_VERSION_LIBZ #endif #ifdef DEBUGBUILD | CURL_VERSION_DEBUG #endif #ifdef CURLDEBUG | CURL_VERSION_CURLDEBUG #endif #ifdef CURLRES_ASYNCH | CURL_VERSION_ASYNCHDNS #endif #if (CURL_SIZEOF_CURL_OFF_T > 4) && \ ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) | CURL_VERSION_LARGEFILE #endif #if defined(CURL_DOES_CONVERSIONS) | CURL_VERSION_CONV #endif #if defined(USE_TLS_SRP) | CURL_VERSION_TLSAUTH_SRP #endif #if defined(USE_NGHTTP2) | CURL_VERSION_HTTP2 #endif #if defined(ENABLE_QUIC) | CURL_VERSION_HTTP3 #endif #if defined(USE_UNIX_SOCKETS) | CURL_VERSION_UNIX_SOCKETS #endif #if defined(USE_LIBPSL) | CURL_VERSION_PSL #endif #if defined(CURL_WITH_MULTI_SSL) | CURL_VERSION_MULTI_SSL #endif #if defined(HAVE_BROTLI) | CURL_VERSION_BROTLI #endif #if defined(USE_ALTSVC) | CURL_VERSION_ALTSVC #endif #ifdef USE_ESNI | CURL_VERSION_ESNI #endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ NULL, /* zlib_version */ protocols, NULL, /* c-ares version */ 0, /* c-ares version numerical */ NULL, /* libidn version */ 0, /* iconv version */ NULL, /* ssh lib version */ 0, /* brotli_ver_num */ NULL, /* brotli version */ 0, /* nghttp2 version number */ NULL, /* nghttp2 version string */ NULL /* quic library string */ }; curl_version_info_data *curl_version_info(CURLversion stamp) { static bool initialized; #if defined(USE_SSH) static char ssh_buffer[80]; #endif #ifdef USE_SSL #ifdef CURL_WITH_MULTI_SSL static char ssl_buffer[200]; #else static char ssl_buffer[80]; #endif #endif #ifdef HAVE_BROTLI static char brotli_buffer[80]; #endif if(initialized) return &version_info; #ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); version_info.ssl_version = ssl_buffer; if(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY) version_info.features |= CURL_VERSION_HTTPS_PROXY; else version_info.features &= ~CURL_VERSION_HTTPS_PROXY; #endif #ifdef HAVE_LIBZ version_info.libz_version = zlibVersion(); /* libz left NULL if non-existing */ #endif #ifdef USE_ARES { int aresnum; version_info.ares = ares_version(&aresnum); version_info.ares_num = aresnum; } #endif #ifdef USE_LIBIDN2 /* This returns a version string if we use the given version or later, otherwise it returns NULL */ version_info.libidn = idn2_check_version(IDN2_VERSION); if(version_info.libidn) version_info.features |= CURL_VERSION_IDN; #elif defined(USE_WIN32_IDN) version_info.features |= CURL_VERSION_IDN; #endif #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS) #ifdef _LIBICONV_VERSION version_info.iconv_ver_num = _LIBICONV_VERSION; #else /* version unknown */ version_info.iconv_ver_num = -1; #endif /* _LIBICONV_VERSION */ #endif #if defined(USE_SSH) Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer)); version_info.libssh_version = ssh_buffer; #endif #ifdef HAVE_BROTLI version_info.brotli_ver_num = BrotliDecoderVersion(); brotli_version(brotli_buffer, sizeof(brotli_buffer)); version_info.brotli_version = brotli_buffer; #endif #ifdef USE_NGHTTP2 { nghttp2_info *h2 = nghttp2_version(0); version_info.nghttp2_ver_num = h2->version_num; version_info.nghttp2_version = h2->version_str; } #endif #ifdef ENABLE_QUIC { static char quicbuffer[80]; Curl_quic_ver(quicbuffer, sizeof(quicbuffer)); version_info.quic_version = quicbuffer; } #endif (void)stamp; /* avoid compiler warnings, we don't use this */ initialized = true; return &version_info; } davix-0.8.0/deps/curl/lib/curl_gssapi.c0000644000000000000000000001056714121063461016464 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2011 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_GSSAPI #include "curl_gssapi.h" #include "sendf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes }; static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; OM_uint32 Curl_gss_init_sec_context( struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, gss_OID mech_type, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, OM_uint32 *ret_flags) { OM_uint32 req_flags = GSS_C_REPLAY_FLAG; if(mutual_auth) req_flags |= GSS_C_MUTUAL_FLAG; if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { #ifdef GSS_C_DELEG_POLICY_FLAG req_flags |= GSS_C_DELEG_POLICY_FLAG; #else infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " "compiled in\n"); #endif } if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) req_flags |= GSS_C_DELEG_FLAG; return gss_init_sec_context(minor_status, GSS_C_NO_CREDENTIAL, /* cred_handle */ context, target_name, mech_type, req_flags, 0, /* time_req */ input_chan_bindings, input_token, NULL, /* actual_mech_type */ output_token, ret_flags, NULL /* time_rec */); } #define GSS_LOG_BUFFER_LEN 1024 static size_t display_gss_error(OM_uint32 status, int type, char *buf, size_t len) { OM_uint32 maj_stat; OM_uint32 min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; do { maj_stat = gss_display_status(&min_stat, status, type, GSS_C_NO_OID, &msg_ctx, &status_string); if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, "%.*s. ", (int)status_string.length, (char *)status_string.value); } gss_release_buffer(&min_stat, &status_string); } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); return len; } /* * Curl_gss_log_error() * * This is used to log a GSS-API error status. * * Parameters: * * data [in] - The session handle. * prefix [in] - The prefix of the log message. * major [in] - The major status code. * minor [in] - The minor status code. */ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, OM_uint32 major, OM_uint32 minor) { char buf[GSS_LOG_BUFFER_LEN]; size_t len = 0; if(major != GSS_S_FAILURE) len = display_gss_error(major, GSS_C_GSS_CODE, buf, len); display_gss_error(minor, GSS_C_MECH_CODE, buf, len); infof(data, "%s%s\n", prefix, buf); } #endif /* HAVE_GSSAPI */ davix-0.8.0/deps/curl/lib/wildcard.h0000644000000000000000000000451014121063461015736 0ustar rootroot#ifndef HEADER_CURL_WILDCARD_H #define HEADER_CURL_WILDCARD_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #include "llist.h" /* list of wildcard process states */ typedef enum { CURLWC_CLEAR = 0, CURLWC_INIT = 1, CURLWC_MATCHING, /* library is trying to get list of addresses for downloading */ CURLWC_DOWNLOADING, CURLWC_CLEAN, /* deallocate resources and reset settings */ CURLWC_SKIP, /* skip over concrete file */ CURLWC_ERROR, /* error cases */ CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop will end */ } curl_wildcard_states; typedef void (*curl_wildcard_dtor)(void *ptr); /* struct keeping information about wildcard download process */ struct WildcardData { curl_wildcard_states state; char *path; /* path to the directory, where we trying wildcard-match */ char *pattern; /* wildcard pattern */ struct curl_llist filelist; /* llist with struct Curl_fileinfo */ void *protdata; /* pointer to protocol specific temporary data */ curl_wildcard_dtor dtor; void *customptr; /* for CURLOPT_CHUNK_DATA pointer */ }; CURLcode Curl_wildcard_init(struct WildcardData *wc); void Curl_wildcard_dtor(struct WildcardData *wc); struct Curl_easy; #else /* FTP is disabled */ #define Curl_wildcard_dtor(x) #endif #endif /* HEADER_CURL_WILDCARD_H */ davix-0.8.0/deps/curl/lib/gopher.c0000644000000000000000000001247014121063461015430 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_GOPHER #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "progress.h" #include "gopher.h" #include "select.h" #include "strdup.h" #include "url.h" #include "escape.h" #include "warnless.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * Forward declarations. */ static CURLcode gopher_do(struct connectdata *conn, bool *done); /* * Gopher protocol handler. * This is also a nice simple template to build off for simple * connect-command-download protocols. */ const struct Curl_handler Curl_handler_gopher = { "GOPHER", /* scheme */ ZERO_NULL, /* setup_connection */ gopher_do, /* do_it */ ZERO_NULL, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_GOPHER, /* defport */ CURLPROTO_GOPHER, /* protocol */ PROTOPT_NONE /* flags */ }; static CURLcode gopher_do(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; char *gopherpath; char *path = data->state.up.path; char *query = data->state.up.query; char *sel = NULL; char *sel_org = NULL; ssize_t amount, k; size_t len; *done = TRUE; /* unconditionally */ /* path is guaranteed non-NULL */ DEBUGASSERT(path); if(query) gopherpath = aprintf("%s?%s", path, query); else gopherpath = strdup(path); if(!gopherpath) return CURLE_OUT_OF_MEMORY; /* Create selector. Degenerate cases: / and /1 => convert to "" */ if(strlen(gopherpath) <= 2) { sel = (char *)""; len = strlen(sel); free(gopherpath); } else { char *newp; /* Otherwise, drop / and the first character (i.e., item type) ... */ newp = gopherpath; newp += 2; /* ... and finally unescape */ result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); free(gopherpath); if(result) return result; sel_org = sel; } /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is sent, which could be sizeable with long selectors. */ k = curlx_uztosz(len); for(;;) { result = Curl_write(conn, sockfd, sel, k, &amount); if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); if(result) break; k -= amount; sel += amount; if(k < 1) break; /* but it did write it all */ } else break; /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't possible to send now will be sent in the doing function repeatedly until the entire request is sent. Wait a while for the socket to be writable. Note that this doesn't acknowledge the timeout. */ if(SOCKET_WRITABLE(sockfd, 100) < 0) { result = CURLE_SEND_ERROR; break; } } free(sel_org); if(!result) /* We can use Curl_sendf to send the terminal \r\n relatively safely and save allocing another string/doing another _write loop. */ result = Curl_sendf(sockfd, conn, "\r\n"); if(result) { failf(data, "Failed sending Gopher request"); return result; } result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2); if(result) return result; Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); return CURLE_OK; } #endif /*CURL_DISABLE_GOPHER*/ davix-0.8.0/deps/curl/lib/vssh/0000755000000000000000000000000014121063461014757 5ustar rootrootdavix-0.8.0/deps/curl/lib/vssh/wolfssh.h0000644000000000000000000000222714121063461016620 0ustar rootroot#ifndef HEADER_CURL_WOLFSSH_H #define HEADER_CURL_WOLFSSH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ extern const struct Curl_handler Curl_handler_sftp; #endif /* HEADER_CURL_WOLFSSH_H */ davix-0.8.0/deps/curl/lib/vssh/libssh2.c0000644000000000000000000033534114121063461016502 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* #define CURL_LIBSSH2_DEBUG */ #include "curl_setup.h" #ifdef USE_LIBSSH2 #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "ssh.h" #include "url.h" #include "speedcheck.h" #include "getinfo.h" #include "strdup.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "inet_ntop.h" #include "parsedate.h" /* for the week day and month names */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "strtoofft.h" #include "multiif.h" #include "select.h" #include "warnless.h" #include "curl_path.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if LIBSSH2_VERSION_NUM >= 0x010206 /* libssh2_sftp_statvfs and friends were added in 1.2.6 */ #define HAS_STATVFS_SUPPORT 1 #endif #define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s)) #define sftp_libssh2_realpath(s,p,t,m) \ libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \ (t), (m), LIBSSH2_SFTP_REALPATH) /* Local functions: */ static const char *sftp_libssh2_strerror(int err); static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn); static CURLcode ssh_connect(struct connectdata *conn, bool *done); static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done); static CURLcode ssh_do(struct connectdata *conn, bool *done); static CURLcode scp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode sftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode sftp_disconnect(struct connectdata *conn, bool dead); static CURLcode sftp_perform(struct connectdata *conn, bool *connected, bool *dophase_done); static int ssh_getsock(struct connectdata *conn, curl_socket_t *sock); static int ssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock); static CURLcode ssh_setup_connection(struct connectdata *conn); /* * SCP protocol handler. */ const struct Curl_handler Curl_handler_scp = { "SCP", /* scheme */ ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ scp_done, /* done */ ZERO_NULL, /* do_more */ ssh_connect, /* connect_it */ ssh_multi_statemach, /* connecting */ scp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SCP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; /* * SFTP protocol handler. */ const struct Curl_handler Curl_handler_sftp = { "SFTP", /* scheme */ ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ sftp_done, /* done */ ZERO_NULL, /* do_more */ ssh_connect, /* connect_it */ ssh_multi_statemach, /* connecting */ sftp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SFTP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; static void kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) { struct connectdata *conn = (struct connectdata *)*abstract; #ifdef CURL_LIBSSH2_DEBUG fprintf(stderr, "name=%s\n", name); fprintf(stderr, "name_len=%d\n", name_len); fprintf(stderr, "instruction=%s\n", instruction); fprintf(stderr, "instruction_len=%d\n", instruction_len); fprintf(stderr, "num_prompts=%d\n", num_prompts); #else (void)name; (void)name_len; (void)instruction; (void)instruction_len; #endif /* CURL_LIBSSH2_DEBUG */ if(num_prompts == 1) { responses[0].text = strdup(conn->passwd); responses[0].length = curlx_uztoui(strlen(conn->passwd)); } (void)prompts; (void)abstract; } /* kbd_callback */ static CURLcode sftp_libssh2_error_to_CURLE(int err) { switch(err) { case LIBSSH2_FX_OK: return CURLE_OK; case LIBSSH2_FX_NO_SUCH_FILE: case LIBSSH2_FX_NO_SUCH_PATH: return CURLE_REMOTE_FILE_NOT_FOUND; case LIBSSH2_FX_PERMISSION_DENIED: case LIBSSH2_FX_WRITE_PROTECT: case LIBSSH2_FX_LOCK_CONFlICT: return CURLE_REMOTE_ACCESS_DENIED; case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: case LIBSSH2_FX_QUOTA_EXCEEDED: return CURLE_REMOTE_DISK_FULL; case LIBSSH2_FX_FILE_ALREADY_EXISTS: return CURLE_REMOTE_FILE_EXISTS; case LIBSSH2_FX_DIR_NOT_EMPTY: return CURLE_QUOTE_ERROR; default: break; } return CURLE_SSH; } static CURLcode libssh2_session_error_to_CURLE(int err) { switch(err) { /* Ordered by order of appearance in libssh2.h */ case LIBSSH2_ERROR_NONE: return CURLE_OK; /* This is the error returned by libssh2_scp_recv2 * on unknown file */ case LIBSSH2_ERROR_SCP_PROTOCOL: return CURLE_REMOTE_FILE_NOT_FOUND; case LIBSSH2_ERROR_SOCKET_NONE: return CURLE_COULDNT_CONNECT; case LIBSSH2_ERROR_ALLOC: return CURLE_OUT_OF_MEMORY; case LIBSSH2_ERROR_SOCKET_SEND: return CURLE_SEND_ERROR; case LIBSSH2_ERROR_HOSTKEY_INIT: case LIBSSH2_ERROR_HOSTKEY_SIGN: case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: return CURLE_PEER_FAILED_VERIFICATION; case LIBSSH2_ERROR_PASSWORD_EXPIRED: return CURLE_LOGIN_DENIED; case LIBSSH2_ERROR_SOCKET_TIMEOUT: case LIBSSH2_ERROR_TIMEOUT: return CURLE_OPERATION_TIMEDOUT; case LIBSSH2_ERROR_EAGAIN: return CURLE_AGAIN; } return CURLE_SSH; } static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) { (void)abstract; /* arg not used */ return malloc(count); } static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) { (void)abstract; /* arg not used */ return realloc(ptr, count); } static LIBSSH2_FREE_FUNC(my_libssh2_free) { (void)abstract; /* arg not used */ if(ptr) /* ssh2 agent sometimes call free with null ptr */ free(ptr); } /* * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ static void state(struct connectdata *conn, sshstate nowstate) { struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { "SSH_STOP", "SSH_INIT", "SSH_S_STARTUP", "SSH_HOSTKEY", "SSH_AUTHLIST", "SSH_AUTH_PKEY_INIT", "SSH_AUTH_PKEY", "SSH_AUTH_PASS_INIT", "SSH_AUTH_PASS", "SSH_AUTH_AGENT_INIT", "SSH_AUTH_AGENT_LIST", "SSH_AUTH_AGENT", "SSH_AUTH_HOST_INIT", "SSH_AUTH_HOST", "SSH_AUTH_KEY_INIT", "SSH_AUTH_KEY", "SSH_AUTH_GSSAPI", "SSH_AUTH_DONE", "SSH_SFTP_INIT", "SSH_SFTP_REALPATH", "SSH_SFTP_QUOTE_INIT", "SSH_SFTP_POSTQUOTE_INIT", "SSH_SFTP_QUOTE", "SSH_SFTP_NEXT_QUOTE", "SSH_SFTP_QUOTE_STAT", "SSH_SFTP_QUOTE_SETSTAT", "SSH_SFTP_QUOTE_SYMLINK", "SSH_SFTP_QUOTE_MKDIR", "SSH_SFTP_QUOTE_RENAME", "SSH_SFTP_QUOTE_RMDIR", "SSH_SFTP_QUOTE_UNLINK", "SSH_SFTP_QUOTE_STATVFS", "SSH_SFTP_GETINFO", "SSH_SFTP_FILETIME", "SSH_SFTP_TRANS_INIT", "SSH_SFTP_UPLOAD_INIT", "SSH_SFTP_CREATE_DIRS_INIT", "SSH_SFTP_CREATE_DIRS", "SSH_SFTP_CREATE_DIRS_MKDIR", "SSH_SFTP_READDIR_INIT", "SSH_SFTP_READDIR", "SSH_SFTP_READDIR_LINK", "SSH_SFTP_READDIR_BOTTOM", "SSH_SFTP_READDIR_DONE", "SSH_SFTP_DOWNLOAD_INIT", "SSH_SFTP_DOWNLOAD_STAT", "SSH_SFTP_CLOSE", "SSH_SFTP_SHUTDOWN", "SSH_SCP_TRANS_INIT", "SSH_SCP_UPLOAD_INIT", "SSH_SCP_DOWNLOAD_INIT", "SSH_SCP_DOWNLOAD", "SSH_SCP_DONE", "SSH_SCP_SEND_EOF", "SSH_SCP_WAIT_EOF", "SSH_SCP_WAIT_CLOSE", "SSH_SCP_CHANNEL_FREE", "SSH_SESSION_DISCONNECT", "SSH_SESSION_FREE", "QUIT" }; /* a precaution to make sure the lists are in sync */ DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); if(sshc->state != nowstate) { infof(conn->data, "SFTP %p state change from %s to %s\n", (void *)sshc, names[sshc->state], names[nowstate]); } #endif sshc->state = nowstate; } #ifdef HAVE_LIBSSH2_KNOWNHOST_API static int sshkeycallback(struct Curl_easy *easy, const struct curl_khkey *knownkey, /* known */ const struct curl_khkey *foundkey, /* found */ enum curl_khmatch match, void *clientp) { (void)easy; (void)knownkey; (void)foundkey; (void)clientp; /* we only allow perfect matches, and we reject everything else */ return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE; } #endif /* * Earlier libssh2 versions didn't have the ability to seek to 64bit positions * with 32bit size_t. */ #ifdef HAVE_LIBSSH2_SFTP_SEEK64 #define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y) #else #define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y) #endif /* * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit * architectures so we check of the necessary function is present. */ #ifndef HAVE_LIBSSH2_SCP_SEND64 #define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0) #else #define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \ (libssh2_uint64_t)d, 0, 0) #endif /* * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64. */ #ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE #define libssh2_session_startup(x,y) libssh2_session_handshake(x,y) #endif static CURLcode ssh_knownhost(struct connectdata *conn) { CURLcode result = CURLE_OK; #ifdef HAVE_LIBSSH2_KNOWNHOST_API struct Curl_easy *data = conn->data; if(data->set.str[STRING_SSH_KNOWNHOSTS]) { /* we're asked to verify the host against a file */ struct ssh_conn *sshc = &conn->proto.sshc; int rc; int keytype; size_t keylen; const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, &keylen, &keytype); int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE; int keybit = 0; if(remotekey) { /* * A subject to figure out is what host name we need to pass in here. * What host name does OpenSSH store in its file if an IDN name is * used? */ struct libssh2_knownhost *host; enum curl_khmatch keymatch; curl_sshkeycallback func = data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; struct curl_khkey knownkey; struct curl_khkey *knownkeyp = NULL; struct curl_khkey foundkey; switch(keytype) { case LIBSSH2_HOSTKEY_TYPE_RSA: keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA; break; case LIBSSH2_HOSTKEY_TYPE_DSS: keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS; break; #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; break; #endif #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; break; #endif #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; break; #endif #ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 case LIBSSH2_HOSTKEY_TYPE_ED25519: keybit = LIBSSH2_KNOWNHOST_KEY_ED25519; break; #endif default: infof(data, "unsupported key type, can't check knownhosts!\n"); keybit = 0; break; } if(!keybit) /* no check means failure! */ rc = CURLKHSTAT_REJECT; else { #ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP keycheck = libssh2_knownhost_checkp(sshc->kh, conn->host.name, (conn->remote_port != PORT_SSH)? conn->remote_port:-1, remotekey, keylen, LIBSSH2_KNOWNHOST_TYPE_PLAIN| LIBSSH2_KNOWNHOST_KEYENC_RAW| keybit, &host); #else keycheck = libssh2_knownhost_check(sshc->kh, conn->host.name, remotekey, keylen, LIBSSH2_KNOWNHOST_TYPE_PLAIN| LIBSSH2_KNOWNHOST_KEYENC_RAW| keybit, &host); #endif infof(data, "SSH host check: %d, key: %s\n", keycheck, (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)? host->key:""); /* setup 'knownkey' */ if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { knownkey.key = host->key; knownkey.len = 0; knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? CURLKHTYPE_RSA : CURLKHTYPE_DSS; knownkeyp = &knownkey; } /* setup 'foundkey' */ foundkey.key = remotekey; foundkey.len = keylen; foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? CURLKHTYPE_RSA : CURLKHTYPE_DSS; /* * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the * curl_khmatch enum are ever modified, we need to introduce a * translation table here! */ keymatch = (enum curl_khmatch)keycheck; /* Ask the callback how to behave */ Curl_set_in_callback(data, true); rc = func(data, knownkeyp, /* from the knownhosts file */ &foundkey, /* from the remote host */ keymatch, data->set.ssh_keyfunc_userp); Curl_set_in_callback(data, false); } } else /* no remotekey means failure! */ rc = CURLKHSTAT_REJECT; switch(rc) { default: /* unknown return codes will equal reject */ /* FALLTHROUGH */ case CURLKHSTAT_REJECT: state(conn, SSH_SESSION_FREE); /* FALLTHROUGH */ case CURLKHSTAT_DEFER: /* DEFER means bail out but keep the SSH_HOSTKEY state */ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; break; case CURLKHSTAT_FINE: case CURLKHSTAT_FINE_ADD_TO_FILE: /* proceed */ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { /* the found host+key didn't match but has been told to be fine anyway so we add it in memory */ int addrc = libssh2_knownhost_add(sshc->kh, conn->host.name, NULL, remotekey, keylen, LIBSSH2_KNOWNHOST_TYPE_PLAIN| LIBSSH2_KNOWNHOST_KEYENC_RAW| keybit, NULL); if(addrc) infof(data, "Warning adding the known host %s failed!\n", conn->host.name); else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) { /* now we write the entire in-memory list of known hosts to the known_hosts file */ int wrc = libssh2_knownhost_writefile(sshc->kh, data->set.str[STRING_SSH_KNOWNHOSTS], LIBSSH2_KNOWNHOST_FILE_OPENSSH); if(wrc) { infof(data, "Warning, writing %s failed!\n", data->set.str[STRING_SSH_KNOWNHOSTS]); } } } break; } } #else /* HAVE_LIBSSH2_KNOWNHOST_API */ (void)conn; #endif return result; } static CURLcode ssh_check_fingerprint(struct connectdata *conn) { struct ssh_conn *sshc = &conn->proto.sshc; struct Curl_easy *data = conn->data; const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; char md5buffer[33]; const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session, LIBSSH2_HOSTKEY_HASH_MD5); if(fingerprint) { /* The fingerprint points to static storage (!), don't free() it. */ int i; for(i = 0; i < 16; i++) msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); infof(data, "SSH MD5 fingerprint: %s\n", md5buffer); } /* Before we authenticate we check the hostkey's MD5 fingerprint * against a known fingerprint, if available. */ if(pubkey_md5 && strlen(pubkey_md5) == 32) { if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { if(fingerprint) failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " "Remote %s is not equal to %s", md5buffer, pubkey_md5); else failf(data, "Denied establishing ssh session: md5 fingerprint not available"); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } infof(data, "MD5 checksum match!\n"); /* as we already matched, we skip the check for known hosts */ return CURLE_OK; } return ssh_knownhost(conn); } /* * ssh_force_knownhost_key_type() will check the known hosts file and try to * force a specific public key type from the server if an entry is found. */ static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn) { CURLcode result = CURLE_OK; #ifdef HAVE_LIBSSH2_KNOWNHOST_API #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 static const char * const hostkey_method_ssh_ed25519 = "ssh-ed25519"; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 static const char * const hostkey_method_ssh_ecdsa_521 = "ecdsa-sha2-nistp521"; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 static const char * const hostkey_method_ssh_ecdsa_384 = "ecdsa-sha2-nistp384"; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 static const char * const hostkey_method_ssh_ecdsa_256 = "ecdsa-sha2-nistp256"; #endif static const char * const hostkey_method_ssh_rsa = "ssh-rsa"; static const char * const hostkey_method_ssh_dss = "ssh-dss"; const char *hostkey_method = NULL; struct ssh_conn *sshc = &conn->proto.sshc; struct Curl_easy *data = conn->data; struct libssh2_knownhost* store = NULL; const char *kh_name_end = NULL; size_t kh_name_size = 0; int port = 0; bool found = false; if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { /* lets try to find our host in the known hosts file */ while(!libssh2_knownhost_get(sshc->kh, &store, store)) { /* For non-standard ports, the name will be enclosed in */ /* square brackets, followed by a colon and the port */ if(store->name[0] == '[') { kh_name_end = strstr(store->name, "]:"); if(!kh_name_end) { infof(data, "Invalid host pattern %s in %s\n", store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); continue; } port = atoi(kh_name_end + 2); if(kh_name_end && (port == conn->remote_port)) { kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end); if(strncmp(store->name + 1, conn->host.name, kh_name_size) == 0) { found = true; break; } } } else if(strcmp(store->name, conn->host.name) == 0) { found = true; break; } } if(found) { infof(data, "Found host %s in %s\n", store->name, data->set.str[STRING_SSH_KNOWNHOSTS]); switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 case LIBSSH2_KNOWNHOST_KEY_ED25519: hostkey_method = hostkey_method_ssh_ed25519; break; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: hostkey_method = hostkey_method_ssh_ecdsa_521; break; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: hostkey_method = hostkey_method_ssh_ecdsa_384; break; #endif #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: hostkey_method = hostkey_method_ssh_ecdsa_256; break; #endif case LIBSSH2_KNOWNHOST_KEY_SSHRSA: hostkey_method = hostkey_method_ssh_rsa; break; case LIBSSH2_KNOWNHOST_KEY_SSHDSS: hostkey_method = hostkey_method_ssh_dss; break; case LIBSSH2_KNOWNHOST_KEY_RSA1: failf(data, "Found host key type RSA1 which is not supported\n"); return CURLE_SSH; default: failf(data, "Unknown host key type: %i\n", (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK)); return CURLE_SSH; } infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method); result = libssh2_session_error_to_CURLE( libssh2_session_method_pref( sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method)); } else { infof(data, "Did not find host %s in %s\n", conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); } } #endif /* HAVE_LIBSSH2_KNOWNHOST_API */ return result; } /* * ssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN * meaning it wants to be called again when the socket is ready */ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SSHPROTO *sftp_scp = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; char *new_readdir_line; int rc = LIBSSH2_ERROR_NONE; int err; int seekerr = CURL_SEEKFUNC_OK; *block = 0; /* we're not blocking by default */ do { switch(sshc->state) { case SSH_INIT: sshc->secondCreateDirs = 0; sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_OK; /* Set libssh2 to non-blocking, since everything internally is non-blocking */ libssh2_session_set_blocking(sshc->ssh_session, 0); result = ssh_force_knownhost_key_type(conn); if(result) { state(conn, SSH_SESSION_FREE); break; } state(conn, SSH_S_STARTUP); /* FALLTHROUGH */ case SSH_S_STARTUP: rc = libssh2_session_startup(sshc->ssh_session, (int)sock); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_FAILED_INIT; break; } state(conn, SSH_HOSTKEY); /* FALLTHROUGH */ case SSH_HOSTKEY: /* * Before we authenticate we should check the hostkey's fingerprint * against our known hosts. How that is handled (reading from file, * whatever) is up to us. */ result = ssh_check_fingerprint(conn); if(!result) state(conn, SSH_AUTHLIST); /* ssh_check_fingerprint sets state appropriately on error */ break; case SSH_AUTHLIST: /* * Figure out authentication methods * NB: As soon as we have provided a username to an openssh server we * must never change it later. Thus, always specify the correct username * here, even though the libssh2 docs kind of indicate that it should be * possible to get a 'generic' list (not user-specific) of authentication * methods, presumably with a blank username. That won't work in my * experience. * So always specify it here. */ sshc->authlist = libssh2_userauth_list(sshc->ssh_session, conn->user, curlx_uztoui(strlen(conn->user))); if(!sshc->authlist) { if(libssh2_userauth_authenticated(sshc->ssh_session)) { sshc->authed = TRUE; infof(data, "SSH user accepted with no authentication\n"); state(conn, SSH_AUTH_DONE); break; } err = libssh2_session_last_errno(sshc->ssh_session); if(err == LIBSSH2_ERROR_EAGAIN) rc = LIBSSH2_ERROR_EAGAIN; else { state(conn, SSH_SESSION_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(err); } break; } infof(data, "SSH authentication methods available: %s\n", sshc->authlist); state(conn, SSH_AUTH_PKEY_INIT); break; case SSH_AUTH_PKEY_INIT: /* * Check the supported auth types in the order I feel is most secure * with the requested type of authentication */ sshc->authed = FALSE; if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && (strstr(sshc->authlist, "publickey") != NULL)) { bool out_of_memory = FALSE; sshc->rsa_pub = sshc->rsa = NULL; if(data->set.str[STRING_SSH_PRIVATE_KEY]) sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); else { /* To ponder about: should really the lib be messing about with the HOME environment variable etc? */ char *home = curl_getenv("HOME"); /* If no private key file is specified, try some common paths. */ if(home) { /* Try ~/.ssh first. */ sshc->rsa = aprintf("%s/.ssh/id_rsa", home); if(!sshc->rsa) out_of_memory = TRUE; else if(access(sshc->rsa, R_OK) != 0) { Curl_safefree(sshc->rsa); sshc->rsa = aprintf("%s/.ssh/id_dsa", home); if(!sshc->rsa) out_of_memory = TRUE; else if(access(sshc->rsa, R_OK) != 0) { Curl_safefree(sshc->rsa); } } free(home); } if(!out_of_memory && !sshc->rsa) { /* Nothing found; try the current dir. */ sshc->rsa = strdup("id_rsa"); if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { Curl_safefree(sshc->rsa); sshc->rsa = strdup("id_dsa"); if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { Curl_safefree(sshc->rsa); /* Out of guesses. Set to the empty string to avoid * surprising info messages. */ sshc->rsa = strdup(""); } } } } /* * Unless the user explicitly specifies a public key file, let * libssh2 extract the public key from the private key file. * This is done by simply passing sshc->rsa_pub = NULL. */ if(data->set.str[STRING_SSH_PUBLIC_KEY] /* treat empty string the same way as NULL */ && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); if(!sshc->rsa_pub) out_of_memory = TRUE; } if(out_of_memory || sshc->rsa == NULL) { Curl_safefree(sshc->rsa); Curl_safefree(sshc->rsa_pub); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } sshc->passphrase = data->set.ssl.key_passwd; if(!sshc->passphrase) sshc->passphrase = ""; if(sshc->rsa_pub) infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); infof(data, "Using SSH private key file '%s'\n", sshc->rsa); state(conn, SSH_AUTH_PKEY); } else { state(conn, SSH_AUTH_PASS_INIT); } break; case SSH_AUTH_PKEY: /* The function below checks if the files exists, no need to stat() here. */ rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session, conn->user, curlx_uztoui( strlen(conn->user)), sshc->rsa_pub, sshc->rsa, sshc->passphrase); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } Curl_safefree(sshc->rsa_pub); Curl_safefree(sshc->rsa); if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized SSH public key authentication\n"); state(conn, SSH_AUTH_DONE); } else { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "SSH public key authentication failed: %s\n", err_msg); state(conn, SSH_AUTH_PASS_INIT); rc = 0; /* clear rc and continue */ } break; case SSH_AUTH_PASS_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) && (strstr(sshc->authlist, "password") != NULL)) { state(conn, SSH_AUTH_PASS); } else { state(conn, SSH_AUTH_HOST_INIT); rc = 0; /* clear rc and continue */ } break; case SSH_AUTH_PASS: rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user, curlx_uztoui(strlen(conn->user)), conn->passwd, curlx_uztoui(strlen(conn->passwd)), NULL); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized password authentication\n"); state(conn, SSH_AUTH_DONE); } else { state(conn, SSH_AUTH_HOST_INIT); rc = 0; /* clear rc and continue */ } break; case SSH_AUTH_HOST_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) && (strstr(sshc->authlist, "hostbased") != NULL)) { state(conn, SSH_AUTH_HOST); } else { state(conn, SSH_AUTH_AGENT_INIT); } break; case SSH_AUTH_HOST: state(conn, SSH_AUTH_AGENT_INIT); break; case SSH_AUTH_AGENT_INIT: #ifdef HAVE_LIBSSH2_AGENT_API if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) && (strstr(sshc->authlist, "publickey") != NULL)) { /* Connect to the ssh-agent */ /* The agent could be shared by a curl thread i believe but nothing obvious as keys can be added/removed at any time */ if(!sshc->ssh_agent) { sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session); if(!sshc->ssh_agent) { infof(data, "Could not create agent object\n"); state(conn, SSH_AUTH_KEY_INIT); break; } } rc = libssh2_agent_connect(sshc->ssh_agent); if(rc == LIBSSH2_ERROR_EAGAIN) break; if(rc < 0) { infof(data, "Failure connecting to agent\n"); state(conn, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT_LIST); } } else #endif /* HAVE_LIBSSH2_AGENT_API */ state(conn, SSH_AUTH_KEY_INIT); break; case SSH_AUTH_AGENT_LIST: #ifdef HAVE_LIBSSH2_AGENT_API rc = libssh2_agent_list_identities(sshc->ssh_agent); if(rc == LIBSSH2_ERROR_EAGAIN) break; if(rc < 0) { infof(data, "Failure requesting identities to agent\n"); state(conn, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT); sshc->sshagent_prev_identity = NULL; } #endif break; case SSH_AUTH_AGENT: #ifdef HAVE_LIBSSH2_AGENT_API /* as prev_identity evolves only after an identity user auth finished we can safely request it again as long as EAGAIN is returned here or by libssh2_agent_userauth */ rc = libssh2_agent_get_identity(sshc->ssh_agent, &sshc->sshagent_identity, sshc->sshagent_prev_identity); if(rc == LIBSSH2_ERROR_EAGAIN) break; if(rc == 0) { rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user, sshc->sshagent_identity); if(rc < 0) { if(rc != LIBSSH2_ERROR_EAGAIN) { /* tried and failed? go to next identity */ sshc->sshagent_prev_identity = sshc->sshagent_identity; } break; } } if(rc < 0) infof(data, "Failure requesting identities to agent\n"); else if(rc == 1) infof(data, "No identity would match\n"); if(rc == LIBSSH2_ERROR_NONE) { sshc->authed = TRUE; infof(data, "Agent based authentication successful\n"); state(conn, SSH_AUTH_DONE); } else { state(conn, SSH_AUTH_KEY_INIT); rc = 0; /* clear rc and continue */ } #endif break; case SSH_AUTH_KEY_INIT: if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) { state(conn, SSH_AUTH_KEY); } else { state(conn, SSH_AUTH_DONE); } break; case SSH_AUTH_KEY: /* Authentication failed. Continue with keyboard-interactive now. */ rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session, conn->user, curlx_uztoui( strlen(conn->user)), &kbd_callback); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized keyboard interactive authentication\n"); } state(conn, SSH_AUTH_DONE); break; case SSH_AUTH_DONE: if(!sshc->authed) { failf(data, "Authentication failure"); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_LOGIN_DENIED; break; } /* * At this point we have an authenticated ssh session. */ infof(data, "Authentication complete\n"); Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */ conn->sockfd = sock; conn->writesockfd = CURL_SOCKET_BAD; if(conn->handler->protocol == CURLPROTO_SFTP) { state(conn, SSH_SFTP_INIT); break; } infof(data, "SSH CONNECT phase done\n"); state(conn, SSH_STOP); break; case SSH_SFTP_INIT: /* * Start the libssh2 sftp session */ sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session); if(!sshc->sftp_session) { char *err_msg = NULL; if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); failf(data, "Failure initializing sftp session: %s", err_msg); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_FAILED_INIT; break; } state(conn, SSH_SFTP_REALPATH); break; case SSH_SFTP_REALPATH: { char tempHome[PATH_MAX]; /* * Get the "home" directory */ rc = sftp_libssh2_realpath(sshc->sftp_session, ".", tempHome, PATH_MAX-1); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc > 0) { /* It seems that this string is not always NULL terminated */ tempHome[rc] = '\0'; sshc->homedir = strdup(tempHome); if(!sshc->homedir) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } conn->data->state.most_recent_ftp_entrypath = sshc->homedir; } else { /* Return the error type */ err = sftp_libssh2_last_error(sshc->sftp_session); if(err) result = sftp_libssh2_error_to_CURLE(err); else /* in this case, the error wasn't in the SFTP level but for example a time-out or similar */ result = CURLE_SSH; sshc->actualcode = result; DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, (int)result)); state(conn, SSH_STOP); break; } } /* This is the last step in the SFTP connect phase. Do note that while we get the homedir here, we get the "workingpath" in the DO action since the homedir will remain the same between request but the working path will not. */ DEBUGF(infof(data, "SSH CONNECT phase done\n")); state(conn, SSH_STOP); break; case SSH_SFTP_QUOTE_INIT: result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path); if(result) { sshc->actualcode = result; state(conn, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands\n"); sshc->quote_item = data->set.quote; state(conn, SSH_SFTP_QUOTE); } else { state(conn, SSH_SFTP_GETINFO); } break; case SSH_SFTP_POSTQUOTE_INIT: if(data->set.postquote) { infof(data, "Sending quote commands\n"); sshc->quote_item = data->set.postquote; state(conn, SSH_SFTP_QUOTE); } else { state(conn, SSH_STOP); } break; case SSH_SFTP_QUOTE: /* Send any quote commands */ { const char *cp; /* * Support some of the "FTP" commands * * 'sshc->quote_item' is already verified to be non-NULL before it * switched to this state. */ char *cmd = sshc->quote_item->data; sshc->acceptfail = FALSE; /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command is successful, whatever the server reponds. */ if(cmd[0] == '*') { cmd++; sshc->acceptfail = TRUE; } if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", sftp_scp->path); if(!tmp) { result = CURLE_OUT_OF_MEMORY; state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; break; } if(data->set.verbose) { Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4); Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); } /* this sends an FTP-like "header" to the header callback so that the current directory can be read very similar to how it is read when using ordinary FTP. */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } else state(conn, SSH_SFTP_NEXT_QUOTE); break; } { /* * the arguments following the command must be separated from the * command with a space so we can check for it unconditionally */ cp = strchr(cmd, ' '); if(cp == NULL) { failf(data, "Syntax error in SFTP command. Supply parameter(s)!"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } /* * also, every command takes at least one argument so we get that * first argument right now */ result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error: Bad first parameter"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } /* * SFTP is a binary protocol, so we don't send text commands * to the server. Instead, we scan for commands used by * OpenSSH's sftp program and call the appropriate libssh2 * functions. */ if(strncasecompare(cmd, "chgrp ", 6) || strncasecompare(cmd, "chmod ", 6) || strncasecompare(cmd, "chown ", 6) ) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ /* get the destination */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in chgrp/chmod/chown: " "Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); state(conn, SSH_SFTP_QUOTE_STAT); break; } if(strncasecompare(cmd, "ln ", 3) || strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in ln/symlink: Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } state(conn, SSH_SFTP_QUOTE_SYMLINK); break; } else if(strncasecompare(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); break; } else if(strncasecompare(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in rename: Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; break; } state(conn, SSH_SFTP_QUOTE_RENAME); break; } else if(strncasecompare(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); break; } else if(strncasecompare(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); break; } #ifdef HAS_STATVFS_SUPPORT else if(strncasecompare(cmd, "statvfs ", 8)) { state(conn, SSH_SFTP_QUOTE_STATVFS); break; } #endif failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } break; case SSH_SFTP_NEXT_QUOTE: Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); sshc->quote_item = sshc->quote_item->next; if(sshc->quote_item) { state(conn, SSH_SFTP_QUOTE); } else { if(sshc->nextstate != SSH_NO_STATE) { state(conn, sshc->nextstate); sshc->nextstate = SSH_NO_STATE; } else { state(conn, SSH_SFTP_GETINFO); } } break; case SSH_SFTP_QUOTE_STAT: { char *cmd = sshc->quote_item->data; sshc->acceptfail = FALSE; /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command is successful, whatever the server reponds. */ if(cmd[0] == '*') { cmd++; sshc->acceptfail = TRUE; } if(!strncasecompare(cmd, "chmod", 5)) { /* Since chown and chgrp only set owner OR group but libssh2 wants to * set them both at once, we need to obtain the current ownership * first. This takes an extra protocol round trip. */ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_STAT, &sshc->quote_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to get SFTP stats failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } /* Now set the new attributes... */ if(strncasecompare(cmd, "chgrp", 5)) { sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } else if(strncasecompare(cmd, "chmod", 5)) { sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; /* permissions are octal */ if(sshc->quote_attrs.permissions == 0 && !ISDIGIT(sshc->quote_path1[0])) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chmod permissions not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } else if(strncasecompare(cmd, "chown", 5)) { sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } } /* Now send the completed structure... */ state(conn, SSH_SFTP_QUOTE_SETSTAT); break; } case SSH_SFTP_QUOTE_SETSTAT: rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_SETSTAT, &sshc->quote_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_SYMLINK: rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1)), sshc->quote_path2, curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_SYMLINK); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_MKDIR: rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1)), data->set.new_directory_perms); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RENAME: rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1)), sshc->quote_path2, curlx_uztoui(strlen(sshc->quote_path2)), LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "rename command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RMDIR: rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1))); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_UNLINK: rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1))); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; #ifdef HAS_STATVFS_SUPPORT case SSH_SFTP_QUOTE_STATVFS: { LIBSSH2_SFTP_STATVFS statvfs; rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, curlx_uztoui(strlen(sshc->quote_path1)), &statvfs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } else if(rc == 0) { char *tmp = aprintf("statvfs:\n" "f_bsize: %llu\n" "f_frsize: %llu\n" "f_blocks: %llu\n" "f_bfree: %llu\n" "f_bavail: %llu\n" "f_files: %llu\n" "f_ffree: %llu\n" "f_favail: %llu\n" "f_fsid: %llu\n" "f_flag: %llu\n" "f_namemax: %llu\n", statvfs.f_bsize, statvfs.f_frsize, statvfs.f_blocks, statvfs.f_bfree, statvfs.f_bavail, statvfs.f_files, statvfs.f_ffree, statvfs.f_favail, statvfs.f_fsid, statvfs.f_flag, statvfs.f_namemax); if(!tmp) { result = CURLE_OUT_OF_MEMORY; state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; break; } result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } } state(conn, SSH_SFTP_NEXT_QUOTE); break; } #endif case SSH_SFTP_GETINFO: { if(data->set.get_filetime) { state(conn, SSH_SFTP_FILETIME); } else { state(conn, SSH_SFTP_TRANS_INIT); } break; } case SSH_SFTP_FILETIME: { LIBSSH2_SFTP_ATTRIBUTES attrs; rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_SFTP_STAT, &attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc == 0) { data->info.filetime = attrs.mtime; } state(conn, SSH_SFTP_TRANS_INIT); break; } case SSH_SFTP_TRANS_INIT: if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); else { if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') state(conn, SSH_SFTP_READDIR_INIT); else state(conn, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: { unsigned long flags; /* * NOTE!!! libssh2 requires that the destination path is a full path * that includes the destination file and name OR ends in a "/" * If this is not done the destination file will be named the * same name as the last directory in the path. */ if(data->state.resume_from != 0) { LIBSSH2_SFTP_ATTRIBUTES attrs; if(data->state.resume_from < 0) { rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_SFTP_STAT, &attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc) { data->state.resume_from = 0; } else { curl_off_t size = attrs.filesize; if(size < 0) { failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } data->state.resume_from = attrs.filesize; } } } if(data->set.ftp_append) /* Try to open for append, but create if nonexisting */ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND; else if(data->state.resume_from > 0) /* If we have restart position then open for append */ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND; else /* Clear file before writing (normal behaviour) */ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC; sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), flags, data->set.new_file_perms, LIBSSH2_SFTP_OPENFILE); if(!sshc->sftp_handle) { rc = libssh2_session_last_errno(sshc->ssh_session); if(LIBSSH2_ERROR_EAGAIN == rc) break; if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) /* only when there was an SFTP protocol error can we extract the sftp error! */ err = sftp_libssh2_last_error(sshc->sftp_session); else err = -1; /* not an sftp error at all */ if(sshc->secondCreateDirs) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = err>= LIBSSH2_FX_OK? sftp_libssh2_error_to_CURLE(err):CURLE_SSH; failf(data, "Creating the dir/file failed: %s", sftp_libssh2_strerror(err)); break; } if(((err == LIBSSH2_FX_NO_SUCH_FILE) || (err == LIBSSH2_FX_FAILURE) || (err == LIBSSH2_FX_NO_SUCH_PATH)) && (data->set.ftp_create_missing_dirs && (strlen(sftp_scp->path) > 1))) { /* try to create the path remotely */ rc = 0; /* clear rc and continue */ sshc->secondCreateDirs = 1; state(conn, SSH_SFTP_CREATE_DIRS_INIT); break; } state(conn, SSH_SFTP_CLOSE); sshc->actualcode = err>= LIBSSH2_FX_OK? sftp_libssh2_error_to_CURLE(err):CURLE_SSH; if(!sshc->actualcode) { /* Sometimes, for some reason libssh2_sftp_last_error() returns zero even though libssh2_sftp_open() failed previously! We need to work around that! */ sshc->actualcode = CURLE_SSH; err = -1; } failf(data, "Upload failed: %s (%d/%d)", err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", err, rc); break; } /* If we have a restart point then we need to seek to the correct position. */ if(data->state.resume_from > 0) { /* Let's read off the proper amount of bytes from the input. */ if(conn->seek_func) { Curl_set_in_callback(data, true); seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, SEEK_SET); Curl_set_in_callback(data, false); } if(seekerr != CURL_SEEKFUNC_OK) { curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { size_t readthisamountnow = (data->state.resume_from - passed > data->set.buffer_size) ? (size_t)data->set.buffer_size : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread; Curl_set_in_callback(data, true); actuallyread = data->state.fread_func(data->state.buffer, 1, readthisamountnow, data->state.in); Curl_set_in_callback(data, false); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Failed to read data"); return CURLE_FTP_COULDNT_USE_REST; } } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize > 0) { data->state.infilesize -= data->state.resume_from; data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); } if(data->state.infilesize > 0) { data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; if(result) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { /* store this original bitmask setup to use later on if we can't figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 sftp send function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ Curl_expire(data, 0, EXPIRE_RUN_NOW); state(conn, SSH_STOP); } break; } case SSH_SFTP_CREATE_DIRS_INIT: if(strlen(sftp_scp->path) > 1) { sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */ state(conn, SSH_SFTP_CREATE_DIRS); } else { state(conn, SSH_SFTP_UPLOAD_INIT); } break; case SSH_SFTP_CREATE_DIRS: sshc->slash_pos = strchr(sshc->slash_pos, '/'); if(sshc->slash_pos) { *sshc->slash_pos = 0; infof(data, "Creating directory '%s'\n", sftp_scp->path); state(conn, SSH_SFTP_CREATE_DIRS_MKDIR); break; } state(conn, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: /* 'mode' - parameter is preliminary - default to 0644 */ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), data->set.new_directory_perms); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } *sshc->slash_pos = '/'; ++sshc->slash_pos; if(rc < 0) { /* * Abort if failure wasn't that the dir already exists or the * permission was denied (creation might succeed further down the * path) - retry on unspecific FAILURE also */ err = sftp_libssh2_last_error(sshc->sftp_session); if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) && (err != LIBSSH2_FX_FAILURE) && (err != LIBSSH2_FX_PERMISSION_DENIED)) { result = sftp_libssh2_error_to_CURLE(err); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result?result:CURLE_SSH; break; } rc = 0; /* clear rc and continue */ } state(conn, SSH_SFTP_CREATE_DIRS); break; case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->set.opt_no_body) { state(conn, SSH_STOP); break; } /* * This is a directory that we are trying to get, so produce a directory * listing */ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui( strlen(sftp_scp->path)), 0, 0, LIBSSH2_SFTP_OPENDIR); if(!sshc->sftp_handle) { if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } err = sftp_libssh2_last_error(sshc->sftp_session); failf(data, "Could not open directory for reading: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); result = sftp_libssh2_error_to_CURLE(err); sshc->actualcode = result?result:CURLE_SSH; break; } sshc->readdir_filename = malloc(PATH_MAX + 1); if(!sshc->readdir_filename) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } sshc->readdir_longentry = malloc(PATH_MAX + 1); if(!sshc->readdir_longentry) { Curl_safefree(sshc->readdir_filename); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } state(conn, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR: rc = libssh2_sftp_readdir_ex(sshc->sftp_handle, sshc->readdir_filename, PATH_MAX, sshc->readdir_longentry, PATH_MAX, &sshc->readdir_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc > 0) { sshc->readdir_len = (size_t) rc; sshc->readdir_filename[sshc->readdir_len] = '\0'; if(data->set.ftp_list_only) { char *tmpLine; tmpLine = aprintf("%s\n", sshc->readdir_filename); if(tmpLine == NULL) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } result = Curl_client_write(conn, CLIENTWRITE_BODY, tmpLine, sshc->readdir_len + 1); free(tmpLine); if(result) { state(conn, SSH_STOP); break; } /* since this counts what we send to the client, we include the newline in this counter */ data->req.bytecount += sshc->readdir_len + 1; /* output debug output if that is requested */ if(data->set.verbose) { Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename, sshc->readdir_len); } } else { sshc->readdir_currLen = strlen(sshc->readdir_longentry); sshc->readdir_totalLen = 80 + sshc->readdir_currLen; sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); if(!sshc->readdir_line) { Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } memcpy(sshc->readdir_line, sshc->readdir_longentry, sshc->readdir_currLen); if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)) { sshc->readdir_linkPath = malloc(PATH_MAX + 1); if(sshc->readdir_linkPath == NULL) { Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path, sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_LINK); break; } state(conn, SSH_SFTP_READDIR_BOTTOM); break; } } else if(rc == 0) { Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_READDIR_DONE); break; } else if(rc < 0) { err = sftp_libssh2_last_error(sshc->sftp_session); result = sftp_libssh2_error_to_CURLE(err); sshc->actualcode = result?result:CURLE_SSH; failf(data, "Could not open remote file for reading: %s :: %d", sftp_libssh2_strerror(err), libssh2_session_last_errno(sshc->ssh_session)); Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); break; } break; case SSH_SFTP_READDIR_LINK: rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->readdir_linkPath, curlx_uztoui(strlen(sshc->readdir_linkPath)), sshc->readdir_filename, PATH_MAX, LIBSSH2_SFTP_READLINK); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } sshc->readdir_len = (size_t) rc; Curl_safefree(sshc->readdir_linkPath); /* get room for the filename and extra output */ sshc->readdir_totalLen += 4 + sshc->readdir_len; new_readdir_line = Curl_saferealloc(sshc->readdir_line, sshc->readdir_totalLen); if(!new_readdir_line) { sshc->readdir_line = NULL; Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } sshc->readdir_line = new_readdir_line; sshc->readdir_currLen += msnprintf(sshc->readdir_line + sshc->readdir_currLen, sshc->readdir_totalLen - sshc->readdir_currLen, " -> %s", sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_BOTTOM); break; case SSH_SFTP_READDIR_BOTTOM: sshc->readdir_currLen += msnprintf(sshc->readdir_line + sshc->readdir_currLen, sshc->readdir_totalLen - sshc->readdir_currLen, "\n"); result = Curl_client_write(conn, CLIENTWRITE_BODY, sshc->readdir_line, sshc->readdir_currLen); if(!result) { /* output debug output if that is requested */ if(data->set.verbose) { Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line, sshc->readdir_currLen); } data->req.bytecount += sshc->readdir_currLen; } Curl_safefree(sshc->readdir_line); if(result) { state(conn, SSH_STOP); } else state(conn, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR_DONE: if(libssh2_sftp_closedir(sshc->sftp_handle) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } sshc->sftp_handle = NULL; Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); state(conn, SSH_STOP); break; case SSH_SFTP_DOWNLOAD_INIT: /* * Work on getting the specified file */ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_FXF_READ, data->set.new_file_perms, LIBSSH2_SFTP_OPENFILE); if(!sshc->sftp_handle) { if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } err = sftp_libssh2_last_error(sshc->sftp_session); failf(data, "Could not open remote file for reading: %s", sftp_libssh2_strerror(err)); state(conn, SSH_SFTP_CLOSE); result = sftp_libssh2_error_to_CURLE(err); sshc->actualcode = result?result:CURLE_SSH; break; } state(conn, SSH_SFTP_DOWNLOAD_STAT); break; case SSH_SFTP_DOWNLOAD_STAT: { LIBSSH2_SFTP_ATTRIBUTES attrs; rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, curlx_uztoui(strlen(sftp_scp->path)), LIBSSH2_SFTP_STAT, &attrs); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc || !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || (attrs.filesize == 0)) { /* * libssh2_sftp_open() didn't return an error, so maybe the server * just doesn't support stat() * OR the server doesn't return a file size with a stat() * OR file size is 0 */ data->req.size = -1; data->req.maxdownload = -1; Curl_pgrsSetDownloadSize(data, -1); } else { curl_off_t size = attrs.filesize; if(size < 0) { failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } if(conn->data->state.use_range) { curl_off_t from, to; char *ptr; char *ptr2; CURLofft to_t; CURLofft from_t; from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ || (to >= size)) { to = size - 1; } if(from_t) { /* from is relative to end of file */ from = size - to; to = size - 1; } if(from > size) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } if(from > to) { from = to; size = 0; } else { size = to - from + 1; } SFTP_SEEK(conn->proto.sshc.sftp_handle, from); } data->req.size = size; data->req.maxdownload = size; Curl_pgrsSetDownloadSize(data, size); } /* We can resume if we can seek to the resume position */ if(data->state.resume_from) { if(data->state.resume_from < 0) { /* We're supposed to download the last abs(from) bytes */ if((curl_off_t)attrs.filesize < -data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } /* download from where? */ data->state.resume_from += attrs.filesize; } else { if((curl_off_t)attrs.filesize < data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, attrs.filesize); return CURLE_BAD_DOWNLOAD_RESUME; } } /* Now store the number of bytes we are expected to download */ data->req.size = attrs.filesize - data->state.resume_from; data->req.maxdownload = attrs.filesize - data->state.resume_from; Curl_pgrsSetDownloadSize(data, attrs.filesize - data->state.resume_from); SFTP_SEEK(sshc->sftp_handle, data->state.resume_from); } } /* Setup the actual download */ if(data->req.size == 0) { /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); infof(data, "File already completely downloaded\n"); state(conn, SSH_STOP); break; } Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { state(conn, SSH_STOP); } break; case SSH_SFTP_CLOSE: if(sshc->sftp_handle) { rc = libssh2_sftp_close(sshc->sftp_handle); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg); } sshc->sftp_handle = NULL; } Curl_safefree(sftp_scp->path); DEBUGF(infof(data, "SFTP DONE done\n")); /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT After nextstate is executed, the control should come back to SSH_SFTP_CLOSE to pass the correct result back */ if(sshc->nextstate != SSH_NO_STATE && sshc->nextstate != SSH_SFTP_CLOSE) { state(conn, sshc->nextstate); sshc->nextstate = SSH_SFTP_CLOSE; } else { state(conn, SSH_STOP); result = sshc->actualcode; } break; case SSH_SFTP_SHUTDOWN: /* during times we get here due to a broken transfer and then the sftp_handle might not have been taken down so make sure that is done before we proceed */ if(sshc->sftp_handle) { rc = libssh2_sftp_close(sshc->sftp_handle); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg); } sshc->sftp_handle = NULL; } if(sshc->sftp_session) { rc = libssh2_sftp_shutdown(sshc->sftp_session); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { infof(data, "Failed to stop libssh2 sftp subsystem\n"); } sshc->sftp_session = NULL; } Curl_safefree(sshc->homedir); conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_DISCONNECT); break; case SSH_SCP_TRANS_INIT: result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path); if(result) { sshc->actualcode = result; state(conn, SSH_STOP); break; } if(data->set.upload) { if(data->state.infilesize < 0) { failf(data, "SCP requires a known file size for upload"); sshc->actualcode = CURLE_UPLOAD_FAILED; state(conn, SSH_SCP_CHANNEL_FREE); break; } state(conn, SSH_SCP_UPLOAD_INIT); } else { state(conn, SSH_SCP_DOWNLOAD_INIT); } break; case SSH_SCP_UPLOAD_INIT: /* * libssh2 requires that the destination path is a full path that * includes the destination file and name OR ends in a "/" . If this is * not done the destination file will be named the same name as the last * directory in the path. */ sshc->ssh_channel = SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms, data->state.infilesize); if(!sshc->ssh_channel) { int ssh_err; char *err_msg = NULL; if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0)); failf(conn->data, "%s", err_msg); state(conn, SSH_SCP_CHANNEL_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); /* Map generic errors to upload failed */ if(sshc->actualcode == CURLE_SSH || sshc->actualcode == CURLE_REMOTE_FILE_NOT_FOUND) sshc->actualcode = CURLE_UPLOAD_FAILED; break; } /* upload data */ Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; if(result) { state(conn, SSH_SCP_CHANNEL_FREE); sshc->actualcode = result; } else { /* store this original bitmask setup to use later on if we can't figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 scp send function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_OUT; state(conn, SSH_STOP); } break; case SSH_SCP_DOWNLOAD_INIT: { curl_off_t bytecount; /* * We must check the remote file; if it is a directory no values will * be set in sb */ /* * If support for >2GB files exists, use it. */ /* get a fresh new channel from the ssh layer */ #if LIBSSH2_VERSION_NUM < 0x010700 struct stat sb; memset(&sb, 0, sizeof(struct stat)); sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, sftp_scp->path, &sb); #else libssh2_struct_stat sb; memset(&sb, 0, sizeof(libssh2_struct_stat)); sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, sftp_scp->path, &sb); #endif if(!sshc->ssh_channel) { int ssh_err; char *err_msg = NULL; if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0)); failf(conn->data, "%s", err_msg); state(conn, SSH_SCP_CHANNEL_FREE); sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); break; } /* download data */ bytecount = (curl_off_t)sb.st_size; data->req.maxdownload = (curl_off_t)sb.st_size; Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { state(conn, SSH_SCP_CHANNEL_FREE); sshc->actualcode = result; } else state(conn, SSH_STOP); } break; case SSH_SCP_DONE: if(data->set.upload) state(conn, SSH_SCP_SEND_EOF); else state(conn, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_SEND_EOF: if(sshc->ssh_channel) { rc = libssh2_channel_send_eof(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to send libssh2 channel EOF: %d %s\n", rc, err_msg); } } state(conn, SSH_SCP_WAIT_EOF); break; case SSH_SCP_WAIT_EOF: if(sshc->ssh_channel) { rc = libssh2_channel_wait_eof(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg); } } state(conn, SSH_SCP_WAIT_CLOSE); break; case SSH_SCP_WAIT_CLOSE: if(sshc->ssh_channel) { rc = libssh2_channel_wait_closed(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Channel failed to close: %d %s\n", rc, err_msg); } } state(conn, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_CHANNEL_FREE: if(sshc->ssh_channel) { rc = libssh2_channel_free(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to free libssh2 scp subsystem: %d %s\n", rc, err_msg); } sshc->ssh_channel = NULL; } DEBUGF(infof(data, "SCP DONE phase complete\n")); #if 0 /* PREV */ state(conn, SSH_SESSION_DISCONNECT); #endif state(conn, SSH_STOP); result = sshc->actualcode; break; case SSH_SESSION_DISCONNECT: /* during weird times when we've been prematurely aborted, the channel is still alive when we reach this state and we MUST kill the channel properly first */ if(sshc->ssh_channel) { rc = libssh2_channel_free(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to free libssh2 scp subsystem: %d %s\n", rc, err_msg); } sshc->ssh_channel = NULL; } if(sshc->ssh_session) { rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown"); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to disconnect libssh2 session: %d %s\n", rc, err_msg); } } Curl_safefree(sshc->homedir); conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_FREE); break; case SSH_SESSION_FREE: #ifdef HAVE_LIBSSH2_KNOWNHOST_API if(sshc->kh) { libssh2_knownhost_free(sshc->kh); sshc->kh = NULL; } #endif #ifdef HAVE_LIBSSH2_AGENT_API if(sshc->ssh_agent) { rc = libssh2_agent_disconnect(sshc->ssh_agent); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to disconnect from libssh2 agent: %d %s\n", rc, err_msg); } libssh2_agent_free(sshc->ssh_agent); sshc->ssh_agent = NULL; /* NB: there is no need to free identities, they are part of internal agent stuff */ sshc->sshagent_identity = NULL; sshc->sshagent_prev_identity = NULL; } #endif if(sshc->ssh_session) { rc = libssh2_session_free(sshc->ssh_session); if(rc == LIBSSH2_ERROR_EAGAIN) { break; } if(rc < 0) { char *err_msg = NULL; (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0); infof(data, "Failed to free libssh2 session: %d %s\n", rc, err_msg); } sshc->ssh_session = NULL; } /* worst-case scenario cleanup */ DEBUGASSERT(sshc->ssh_session == NULL); DEBUGASSERT(sshc->ssh_channel == NULL); DEBUGASSERT(sshc->sftp_session == NULL); DEBUGASSERT(sshc->sftp_handle == NULL); #ifdef HAVE_LIBSSH2_KNOWNHOST_API DEBUGASSERT(sshc->kh == NULL); #endif #ifdef HAVE_LIBSSH2_AGENT_API DEBUGASSERT(sshc->ssh_agent == NULL); #endif Curl_safefree(sshc->rsa_pub); Curl_safefree(sshc->rsa); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->homedir); Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshc->readdir_line); Curl_safefree(sshc->readdir_linkPath); /* the code we are about to return */ result = sshc->actualcode; memset(sshc, 0, sizeof(struct ssh_conn)); connclose(conn, "SSH session free"); sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); break; case SSH_QUIT: /* fallthrough, just stop! */ default: /* internal error */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); break; } } while(!rc && (sshc->state != SSH_STOP)); if(rc == LIBSSH2_ERROR_EAGAIN) { /* we would block, we need to wait for the socket to be ready (in the right direction too)! */ *block = TRUE; } return result; } /* called by the multi interface to figure out what socket(s) to wait for and for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ static int ssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock) { #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION int bitmap = GETSOCK_BLANK; sock[0] = conn->sock[FIRSTSOCKET]; if(conn->waitfor & KEEP_RECV) bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); if(conn->waitfor & KEEP_SEND) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; #else /* if we don't know the direction we can use the generic *_getsock() function even for the protocol_connect and doing states */ return Curl_single_getsock(conn, sock); #endif } /* Generic function called by the multi interface to figure out what socket(s) to wait for and for what actions during the DOING and PROTOCONNECT states*/ static int ssh_getsock(struct connectdata *conn, curl_socket_t *sock) { #ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION (void)conn; (void)sock; /* if we don't know any direction we can just play along as we used to and not provide any sensible info */ return GETSOCK_BLANK; #else /* if we know the direction we can use the generic *_getsock() function even for the protocol_connect and doing states */ return ssh_perform_getsock(conn, sock); #endif } #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION /* * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this * function is used to figure out in what direction and stores this info so * that the multi interface can take advantage of it. Make sure to call this * function in all cases so that when it _doesn't_ return EAGAIN we can * restore the default wait bits. */ static void ssh_block2waitfor(struct connectdata *conn, bool block) { struct ssh_conn *sshc = &conn->proto.sshc; int dir = 0; if(block) { dir = libssh2_session_block_directions(sshc->ssh_session); if(dir) { /* translate the libssh2 define bits into our own bit defines */ conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); } } if(!dir) /* It didn't block or libssh2 didn't reveal in which direction, put back the original set */ conn->waitfor = sshc->orig_waitfor; } #else /* no libssh2 directional support so we simply don't know */ #define ssh_block2waitfor(x,y) Curl_nop_stmt #endif /* called repeatedly until done from multi.c */ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ do { result = ssh_statemach_act(conn, &block); *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then try again */ } while(!result && !*done && !block); ssh_block2waitfor(conn, block); return result; } static CURLcode ssh_block_statemach(struct connectdata *conn, bool disconnect) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; while((sshc->state != SSH_STOP) && !result) { bool block; timediff_t left = 1000; struct curltime now = Curl_now(); result = ssh_statemach_act(conn, &block); if(result) break; if(!disconnect) { if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; result = Curl_speedcheck(data, now); if(result) break; left = Curl_timeleft(data, NULL, FALSE); if(left < 0) { failf(data, "Operation timed out"); return CURLE_OPERATION_TIMEDOUT; } } #ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION if(block) { int dir = libssh2_session_block_directions(sshc->ssh_session); curl_socket_t sock = conn->sock[FIRSTSOCKET]; curl_socket_t fd_read = CURL_SOCKET_BAD; curl_socket_t fd_write = CURL_SOCKET_BAD; if(LIBSSH2_SESSION_BLOCK_INBOUND & dir) fd_read = sock; if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) fd_write = sock; /* wait for the socket to become ready */ (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, left>1000?1000:(time_t)left); } #endif } return result; } /* * SSH setup and connection */ static CURLcode ssh_setup_connection(struct connectdata *conn) { struct SSHPROTO *ssh; conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static Curl_recv scp_recv, sftp_recv; static Curl_send scp_send, sftp_send; /* * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to * do protocol-specific actions at connect-time. */ static CURLcode ssh_connect(struct connectdata *conn, bool *done) { #ifdef CURL_LIBSSH2_DEBUG curl_socket_t sock; #endif struct ssh_conn *ssh; CURLcode result; struct Curl_easy *data = conn->data; /* initialize per-handle data if not already */ if(!data->req.protop) ssh_setup_connection(conn); /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "SSH default"); if(conn->handler->protocol & CURLPROTO_SCP) { conn->recv[FIRSTSOCKET] = scp_recv; conn->send[FIRSTSOCKET] = scp_send; } else { conn->recv[FIRSTSOCKET] = sftp_recv; conn->send[FIRSTSOCKET] = sftp_send; } ssh = &conn->proto.sshc; #ifdef CURL_LIBSSH2_DEBUG if(conn->user) { infof(data, "User: %s\n", conn->user); } if(conn->passwd) { infof(data, "Password: %s\n", conn->passwd); } sock = conn->sock[FIRSTSOCKET]; #endif /* CURL_LIBSSH2_DEBUG */ ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, my_libssh2_free, my_libssh2_realloc, conn); if(ssh->ssh_session == NULL) { failf(data, "Failure initialising ssh session"); return CURLE_FAILED_INIT; } if(data->set.ssh_compression) { #if LIBSSH2_VERSION_NUM >= 0x010208 if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0) #endif infof(data, "Failed to enable compression for ssh session\n"); } #ifdef HAVE_LIBSSH2_KNOWNHOST_API if(data->set.str[STRING_SSH_KNOWNHOSTS]) { int rc; ssh->kh = libssh2_knownhost_init(ssh->ssh_session); if(!ssh->kh) { libssh2_session_free(ssh->ssh_session); return CURLE_FAILED_INIT; } /* read all known hosts from there */ rc = libssh2_knownhost_readfile(ssh->kh, data->set.str[STRING_SSH_KNOWNHOSTS], LIBSSH2_KNOWNHOST_FILE_OPENSSH); if(rc < 0) infof(data, "Failed to read known hosts from %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]); } #endif /* HAVE_LIBSSH2_KNOWNHOST_API */ #ifdef CURL_LIBSSH2_DEBUG libssh2_trace(ssh->ssh_session, ~0); infof(data, "SSH socket: %d\n", (int)sock); #endif /* CURL_LIBSSH2_DEBUG */ state(conn, SSH_INIT); result = ssh_multi_statemach(conn, done); return result; } /* *********************************************************************** * * scp_perform() * * This is the actual DO function for SCP. Get a file according to * the options previously setup. */ static CURLcode scp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ state(conn, SSH_SCP_TRANS_INIT); /* run the state-machine */ result = ssh_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* called from multi.c while DOing */ static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result; result = ssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* * The DO function is generic for both protocols. There was previously two * separate ones but this way means less duplicated code. */ static CURLcode ssh_do(struct connectdata *conn, bool *done) { CURLcode result; bool connected = 0; struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ data->req.size = -1; /* make sure this is unknown at this point */ sshc->actualcode = CURLE_OK; /* reset error code */ sshc->secondCreateDirs = 0; /* reset the create dir attempt state variable */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); if(conn->handler->protocol & CURLPROTO_SCP) result = scp_perform(conn, &connected, done); else result = sftp_perform(conn, &connected, done); return result; } /* BLOCKING, but the function is using the state machine so the only reason this is still blocking is that the multi interface code has no support for disconnecting operations that takes a while */ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; struct ssh_conn *ssh = &conn->proto.sshc; (void) dead_connection; if(ssh->ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SESSION_DISCONNECT); result = ssh_block_statemach(conn, TRUE); } return result; } /* generic done function for both SCP and SFTP called from their specific done functions */ static CURLcode ssh_done(struct connectdata *conn, CURLcode status) { CURLcode result = CURLE_OK; struct SSHPROTO *sftp_scp = conn->data->req.protop; if(!status) { /* run the state-machine */ result = ssh_block_statemach(conn, FALSE); } else result = status; if(sftp_scp) Curl_safefree(sftp_scp->path); if(Curl_pgrsDone(conn)) return CURLE_ABORTED_BY_CALLBACK; conn->data->req.keepon = 0; /* clear all bits */ return result; } static CURLcode scp_done(struct connectdata *conn, CURLcode status, bool premature) { (void)premature; /* not used */ if(!status) state(conn, SSH_SCP_DONE); return ssh_done(conn, status); } static ssize_t scp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { ssize_t nwrite; (void)sockindex; /* we only support SCP on the fixed known primary socket */ /* libssh2_channel_write() returns int! */ nwrite = (ssize_t) libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len); ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); if(nwrite == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nwrite = 0; } else if(nwrite < LIBSSH2_ERROR_NONE) { *err = libssh2_session_error_to_CURLE((int)nwrite); nwrite = -1; } return nwrite; } static ssize_t scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { ssize_t nread; (void)sockindex; /* we only support SCP on the fixed known primary socket */ /* libssh2_channel_read() returns int */ nread = (ssize_t) libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len); ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nread = -1; } return nread; } /* * =============== SFTP =============== */ /* *********************************************************************** * * sftp_perform() * * This is the actual DO function for SFTP. Get a file/directory according to * the options previously setup. */ static CURLcode sftp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ state(conn, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = ssh_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* called from multi.c while DOing */ static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = ssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* BLOCKING, but the function is using the state machine so the only reason this is still blocking is that the multi interface code has no support for disconnecting operations that takes a while */ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; (void) dead_connection; DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); result = ssh_block_statemach(conn, TRUE); } DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); return result; } static CURLcode sftp_done(struct connectdata *conn, CURLcode status, bool premature) { struct ssh_conn *sshc = &conn->proto.sshc; if(!status) { /* Post quote commands are executed after the SFTP_CLOSE state to avoid errors that could happen due to open file handles during POSTQUOTE operation */ if(!premature && conn->data->set.postquote && !conn->bits.retry) sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; state(conn, SSH_SFTP_CLOSE); } return ssh_done(conn, status); } /* return number of sent bytes */ static ssize_t sftp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14 but is changed to ssize_t in 0.15. These days we don't support libssh2 0.15*/ (void)sockindex; nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len); ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); if(nwrite == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nwrite = 0; } else if(nwrite < LIBSSH2_ERROR_NONE) { *err = libssh2_session_error_to_CURLE((int)nwrite); nwrite = -1; } return nwrite; } /* * Return number of received (decrypted) bytes * or <0 on error */ static ssize_t sftp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { ssize_t nread; (void)sockindex; nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len); ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); if(nread == LIBSSH2_ERROR_EAGAIN) { *err = CURLE_AGAIN; nread = -1; } else if(nread < 0) { *err = libssh2_session_error_to_CURLE((int)nread); } return nread; } static const char *sftp_libssh2_strerror(int err) { switch(err) { case LIBSSH2_FX_NO_SUCH_FILE: return "No such file or directory"; case LIBSSH2_FX_PERMISSION_DENIED: return "Permission denied"; case LIBSSH2_FX_FAILURE: return "Operation failed"; case LIBSSH2_FX_BAD_MESSAGE: return "Bad message from SFTP server"; case LIBSSH2_FX_NO_CONNECTION: return "Not connected to SFTP server"; case LIBSSH2_FX_CONNECTION_LOST: return "Connection to SFTP server lost"; case LIBSSH2_FX_OP_UNSUPPORTED: return "Operation not supported by SFTP server"; case LIBSSH2_FX_INVALID_HANDLE: return "Invalid handle"; case LIBSSH2_FX_NO_SUCH_PATH: return "No such file or directory"; case LIBSSH2_FX_FILE_ALREADY_EXISTS: return "File already exists"; case LIBSSH2_FX_WRITE_PROTECT: return "File is write protected"; case LIBSSH2_FX_NO_MEDIA: return "No media"; case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: return "Disk full"; case LIBSSH2_FX_QUOTA_EXCEEDED: return "User quota exceeded"; case LIBSSH2_FX_UNKNOWN_PRINCIPLE: return "Unknown principle"; case LIBSSH2_FX_LOCK_CONFlICT: return "File lock conflict"; case LIBSSH2_FX_DIR_NOT_EMPTY: return "Directory not empty"; case LIBSSH2_FX_NOT_A_DIRECTORY: return "Not a directory"; case LIBSSH2_FX_INVALID_FILENAME: return "Invalid filename"; case LIBSSH2_FX_LINK_LOOP: return "Link points to itself"; } return "Unknown error in libssh2"; } CURLcode Curl_ssh_init(void) { #ifdef HAVE_LIBSSH2_INIT if(libssh2_init(0)) { DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); return CURLE_FAILED_INIT; } #endif return CURLE_OK; } void Curl_ssh_cleanup(void) { #ifdef HAVE_LIBSSH2_EXIT (void)libssh2_exit(); #endif } size_t Curl_ssh_version(char *buffer, size_t buflen) { return msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION); } #endif /* USE_LIBSSH2 */ davix-0.8.0/deps/curl/lib/vssh/libssh.c0000644000000000000000000024350114121063461016414 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2017 - 2020 Red Hat, Inc. * * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek, * Robert Kolcun, Andreas Schneider * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_LIBSSH #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "ssh.h" #include "url.h" #include "speedcheck.h" #include "getinfo.h" #include "strdup.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "inet_ntop.h" #include "parsedate.h" /* for the week day and month names */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "strtoofft.h" #include "multiif.h" #include "select.h" #include "warnless.h" /* for permission and open flags */ #include #include #include #include /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #include "curl_path.h" /* A recent macro provided by libssh. Or make our own. */ #ifndef SSH_STRING_FREE_CHAR #define SSH_STRING_FREE_CHAR(x) \ do { \ if(x) { \ ssh_string_free_char(x); \ x = NULL; \ } \ } while(0) #endif /* Local functions: */ static CURLcode myssh_connect(struct connectdata *conn, bool *done); static CURLcode myssh_multi_statemach(struct connectdata *conn, bool *done); static CURLcode myssh_do_it(struct connectdata *conn, bool *done); static CURLcode scp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode sftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode sftp_disconnect(struct connectdata *conn, bool dead); static CURLcode sftp_perform(struct connectdata *conn, bool *connected, bool *dophase_done); static void sftp_quote(struct connectdata *conn); static void sftp_quote_stat(struct connectdata *conn); static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock); static int myssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock); static CURLcode myssh_setup_connection(struct connectdata *conn); /* * SCP protocol handler. */ const struct Curl_handler Curl_handler_scp = { "SCP", /* scheme */ myssh_setup_connection, /* setup_connection */ myssh_do_it, /* do_it */ scp_done, /* done */ ZERO_NULL, /* do_more */ myssh_connect, /* connect_it */ myssh_multi_statemach, /* connecting */ scp_doing, /* doing */ myssh_getsock, /* proto_getsock */ myssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ myssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SCP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; /* * SFTP protocol handler. */ const struct Curl_handler Curl_handler_sftp = { "SFTP", /* scheme */ myssh_setup_connection, /* setup_connection */ myssh_do_it, /* do_it */ sftp_done, /* done */ ZERO_NULL, /* do_more */ myssh_connect, /* connect_it */ myssh_multi_statemach, /* connecting */ sftp_doing, /* doing */ myssh_getsock, /* proto_getsock */ myssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ myssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SFTP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; static CURLcode sftp_error_to_CURLE(int err) { switch(err) { case SSH_FX_OK: return CURLE_OK; case SSH_FX_NO_SUCH_FILE: case SSH_FX_NO_SUCH_PATH: return CURLE_REMOTE_FILE_NOT_FOUND; case SSH_FX_PERMISSION_DENIED: case SSH_FX_WRITE_PROTECT: return CURLE_REMOTE_ACCESS_DENIED; case SSH_FX_FILE_ALREADY_EXISTS: return CURLE_REMOTE_FILE_EXISTS; default: break; } return CURLE_SSH; } #ifndef DEBUGBUILD #define state(x,y) mystate(x,y) #else #define state(x,y) mystate(x,y, __LINE__) #endif /* * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ static void mystate(struct connectdata *conn, sshstate nowstate #ifdef DEBUGBUILD , int lineno #endif ) { struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char *const names[] = { "SSH_STOP", "SSH_INIT", "SSH_S_STARTUP", "SSH_HOSTKEY", "SSH_AUTHLIST", "SSH_AUTH_PKEY_INIT", "SSH_AUTH_PKEY", "SSH_AUTH_PASS_INIT", "SSH_AUTH_PASS", "SSH_AUTH_AGENT_INIT", "SSH_AUTH_AGENT_LIST", "SSH_AUTH_AGENT", "SSH_AUTH_HOST_INIT", "SSH_AUTH_HOST", "SSH_AUTH_KEY_INIT", "SSH_AUTH_KEY", "SSH_AUTH_GSSAPI", "SSH_AUTH_DONE", "SSH_SFTP_INIT", "SSH_SFTP_REALPATH", "SSH_SFTP_QUOTE_INIT", "SSH_SFTP_POSTQUOTE_INIT", "SSH_SFTP_QUOTE", "SSH_SFTP_NEXT_QUOTE", "SSH_SFTP_QUOTE_STAT", "SSH_SFTP_QUOTE_SETSTAT", "SSH_SFTP_QUOTE_SYMLINK", "SSH_SFTP_QUOTE_MKDIR", "SSH_SFTP_QUOTE_RENAME", "SSH_SFTP_QUOTE_RMDIR", "SSH_SFTP_QUOTE_UNLINK", "SSH_SFTP_QUOTE_STATVFS", "SSH_SFTP_GETINFO", "SSH_SFTP_FILETIME", "SSH_SFTP_TRANS_INIT", "SSH_SFTP_UPLOAD_INIT", "SSH_SFTP_CREATE_DIRS_INIT", "SSH_SFTP_CREATE_DIRS", "SSH_SFTP_CREATE_DIRS_MKDIR", "SSH_SFTP_READDIR_INIT", "SSH_SFTP_READDIR", "SSH_SFTP_READDIR_LINK", "SSH_SFTP_READDIR_BOTTOM", "SSH_SFTP_READDIR_DONE", "SSH_SFTP_DOWNLOAD_INIT", "SSH_SFTP_DOWNLOAD_STAT", "SSH_SFTP_CLOSE", "SSH_SFTP_SHUTDOWN", "SSH_SCP_TRANS_INIT", "SSH_SCP_UPLOAD_INIT", "SSH_SCP_DOWNLOAD_INIT", "SSH_SCP_DOWNLOAD", "SSH_SCP_DONE", "SSH_SCP_SEND_EOF", "SSH_SCP_WAIT_EOF", "SSH_SCP_WAIT_CLOSE", "SSH_SCP_CHANNEL_FREE", "SSH_SESSION_DISCONNECT", "SSH_SESSION_FREE", "QUIT" }; if(sshc->state != nowstate) { infof(conn->data, "SSH %p state change from %s to %s (line %d)\n", (void *) sshc, names[sshc->state], names[nowstate], lineno); } #endif sshc->state = nowstate; } /* Multiple options: * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5 * hash (90s style auth, not sure we should have it here) * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE * is returned by it. * 3. none of the above. We only accept if it is present on known hosts. * * Returns SSH_OK or SSH_ERROR. */ static int myssh_is_known(struct connectdata *conn) { int rc; struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; ssh_key pubkey; size_t hlen; unsigned char *hash = NULL; char *found_base64 = NULL; char *known_base64 = NULL; int vstate; enum curl_khmatch keymatch; struct curl_khkey foundkey; struct curl_khkey *knownkeyp = NULL; curl_sshkeycallback func = data->set.ssh_keyfunc; #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) struct ssh_knownhosts_entry *knownhostsentry = NULL; struct curl_khkey knownkey; #endif #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey); #else rc = ssh_get_publickey(sshc->ssh_session, &pubkey); #endif if(rc != SSH_OK) return rc; if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) { rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hlen); if(rc != SSH_OK) goto cleanup; if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) || memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) { rc = SSH_ERROR; goto cleanup; } rc = SSH_OK; goto cleanup; } if(data->set.ssl.primary.verifyhost != TRUE) { rc = SSH_OK; goto cleanup; } #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) /* Get the known_key from the known hosts file */ vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session, &knownhostsentry); /* Case an entry was found in a known hosts file */ if(knownhostsentry) { if(knownhostsentry->publickey) { rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey, &known_base64); if(rc != SSH_OK) { goto cleanup; } knownkey.key = known_base64; knownkey.len = strlen(known_base64); switch(ssh_key_type(knownhostsentry->publickey)) { case SSH_KEYTYPE_RSA: knownkey.keytype = CURLKHTYPE_RSA; break; case SSH_KEYTYPE_RSA1: knownkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: knownkey.keytype = CURLKHTYPE_ECDSA; break; case SSH_KEYTYPE_ED25519: knownkey.keytype = CURLKHTYPE_ED25519; break; case SSH_KEYTYPE_DSS: knownkey.keytype = CURLKHTYPE_DSS; break; default: rc = SSH_ERROR; goto cleanup; } knownkeyp = &knownkey; } } switch(vstate) { case SSH_KNOWN_HOSTS_OK: keymatch = CURLKHMATCH_OK; break; case SSH_KNOWN_HOSTS_OTHER: /* fallthrough */ case SSH_KNOWN_HOSTS_NOT_FOUND: /* fallthrough */ case SSH_KNOWN_HOSTS_UNKNOWN: /* fallthrough */ case SSH_KNOWN_HOSTS_ERROR: keymatch = CURLKHMATCH_MISSING; break; default: keymatch = CURLKHMATCH_MISMATCH; break; } #else vstate = ssh_is_server_known(sshc->ssh_session); switch(vstate) { case SSH_SERVER_KNOWN_OK: keymatch = CURLKHMATCH_OK; break; case SSH_SERVER_FILE_NOT_FOUND: /* fallthrough */ case SSH_SERVER_NOT_KNOWN: keymatch = CURLKHMATCH_MISSING; break; default: keymatch = CURLKHMATCH_MISMATCH; break; } #endif if(func) { /* use callback to determine action */ rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64); if(rc != SSH_OK) goto cleanup; foundkey.key = found_base64; foundkey.len = strlen(found_base64); switch(ssh_key_type(pubkey)) { case SSH_KEYTYPE_RSA: foundkey.keytype = CURLKHTYPE_RSA; break; case SSH_KEYTYPE_RSA1: foundkey.keytype = CURLKHTYPE_RSA1; break; case SSH_KEYTYPE_ECDSA: foundkey.keytype = CURLKHTYPE_ECDSA; break; #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0) case SSH_KEYTYPE_ED25519: foundkey.keytype = CURLKHTYPE_ED25519; break; #endif case SSH_KEYTYPE_DSS: foundkey.keytype = CURLKHTYPE_DSS; break; default: rc = SSH_ERROR; goto cleanup; } Curl_set_in_callback(data, true); rc = func(data, knownkeyp, /* from the knownhosts file */ &foundkey, /* from the remote host */ keymatch, data->set.ssh_keyfunc_userp); Curl_set_in_callback(data, false); switch(rc) { case CURLKHSTAT_FINE_ADD_TO_FILE: #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0) rc = ssh_session_update_known_hosts(sshc->ssh_session); #else rc = ssh_write_knownhost(sshc->ssh_session); #endif if(rc != SSH_OK) { goto cleanup; } break; case CURLKHSTAT_FINE: break; default: /* REJECT/DEFER */ rc = SSH_ERROR; goto cleanup; } } else { if(keymatch != CURLKHMATCH_OK) { rc = SSH_ERROR; goto cleanup; } } rc = SSH_OK; cleanup: if(found_base64) { free(found_base64); } if(known_base64) { free(known_base64); } if(hash) ssh_clean_pubkey_hash(&hash); ssh_key_free(pubkey); #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0) if(knownhostsentry) { ssh_knownhosts_entry_free(knownhostsentry); } #endif return rc; } #define MOVE_TO_ERROR_STATE(_r) { \ state(conn, SSH_SESSION_DISCONNECT); \ sshc->actualcode = _r; \ rc = SSH_ERROR; \ break; \ } #define MOVE_TO_SFTP_CLOSE_STATE() { \ state(conn, SSH_SFTP_CLOSE); \ sshc->actualcode = sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \ rc = SSH_ERROR; \ break; \ } #define MOVE_TO_LAST_AUTH \ if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \ rc = SSH_OK; \ state(conn, SSH_AUTH_PASS_INIT); \ break; \ } \ else { \ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \ } #define MOVE_TO_TERTIARY_AUTH \ if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \ rc = SSH_OK; \ state(conn, SSH_AUTH_KEY_INIT); \ break; \ } \ else { \ MOVE_TO_LAST_AUTH; \ } #define MOVE_TO_SECONDARY_AUTH \ if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \ rc = SSH_OK; \ state(conn, SSH_AUTH_GSSAPI); \ break; \ } \ else { \ MOVE_TO_TERTIARY_AUTH; \ } static int myssh_auth_interactive(struct connectdata *conn) { int rc; struct ssh_conn *sshc = &conn->proto.sshc; int nprompts; restart: switch(sshc->kbd_state) { case 0: rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); if(rc == SSH_AUTH_AGAIN) return SSH_AGAIN; if(rc != SSH_AUTH_INFO) return SSH_ERROR; nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session); if(nprompts != 1) return SSH_ERROR; rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd); if(rc < 0) return SSH_ERROR; /* FALLTHROUGH */ case 1: sshc->kbd_state = 1; rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); if(rc == SSH_AUTH_AGAIN) return SSH_AGAIN; else if(rc == SSH_AUTH_SUCCESS) rc = SSH_OK; else if(rc == SSH_AUTH_INFO) { nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session); if(nprompts != 0) return SSH_ERROR; sshc->kbd_state = 2; goto restart; } else rc = SSH_ERROR; break; case 2: sshc->kbd_state = 2; rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL); if(rc == SSH_AUTH_AGAIN) return SSH_AGAIN; else if(rc == SSH_AUTH_SUCCESS) rc = SSH_OK; else rc = SSH_ERROR; break; default: return SSH_ERROR; } sshc->kbd_state = 0; return rc; } /* * ssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points * to will be set to TRUE if the libssh function returns SSH_AGAIN * meaning it wants to be called again when the socket is ready */ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SSHPROTO *protop = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc = SSH_NO_ERROR, err; char *new_readdir_line; int seekerr = CURL_SEEKFUNC_OK; const char *err_msg; *block = 0; /* we're not blocking by default */ do { switch(sshc->state) { case SSH_INIT: sshc->secondCreateDirs = 0; sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_OK; #if 0 ssh_set_log_level(SSH_LOG_PROTOCOL); #endif /* Set libssh to non-blocking, since everything internally is non-blocking */ ssh_set_blocking(sshc->ssh_session, 0); state(conn, SSH_S_STARTUP); /* FALLTHROUGH */ case SSH_S_STARTUP: rc = ssh_connect(sshc->ssh_session); if(rc == SSH_AGAIN) break; if(rc != SSH_OK) { failf(data, "Failure establishing ssh session"); MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT); } state(conn, SSH_HOSTKEY); /* FALLTHROUGH */ case SSH_HOSTKEY: rc = myssh_is_known(conn); if(rc != SSH_OK) { MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION); } state(conn, SSH_AUTHLIST); /* FALLTHROUGH */ case SSH_AUTHLIST:{ sshc->authed = FALSE; rc = ssh_userauth_none(sshc->ssh_session, NULL); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Authenticated with none\n"); state(conn, SSH_AUTH_DONE); break; } else if(rc == SSH_AUTH_ERROR) { MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); } sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL); if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { state(conn, SSH_AUTH_PKEY_INIT); infof(data, "Authentication using SSH public key file\n"); } else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { state(conn, SSH_AUTH_GSSAPI); } else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { state(conn, SSH_AUTH_KEY_INIT); } else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { state(conn, SSH_AUTH_PASS_INIT); } else { /* unsupported authentication method */ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); } break; } case SSH_AUTH_PKEY_INIT: if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) { MOVE_TO_SECONDARY_AUTH; } /* Two choices, (1) private key was given on CMD, * (2) use the "default" keys. */ if(data->set.str[STRING_SSH_PRIVATE_KEY]) { if(sshc->pubkey && !data->set.ssl.key_passwd) { rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL, sshc->pubkey); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc != SSH_OK) { MOVE_TO_SECONDARY_AUTH; } } rc = ssh_pki_import_privkey_file(data-> set.str[STRING_SSH_PRIVATE_KEY], data->set.ssl.key_passwd, NULL, NULL, &sshc->privkey); if(rc != SSH_OK) { failf(data, "Could not load private key file %s", data->set.str[STRING_SSH_PRIVATE_KEY]); MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); break; } state(conn, SSH_AUTH_PKEY); break; } else { rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL, data->set.ssl.key_passwd); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc == SSH_AUTH_SUCCESS) { rc = SSH_OK; sshc->authed = TRUE; infof(data, "Completed public key authentication\n"); state(conn, SSH_AUTH_DONE); break; } MOVE_TO_SECONDARY_AUTH; } break; case SSH_AUTH_PKEY: rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Completed public key authentication\n"); state(conn, SSH_AUTH_DONE); break; } else { infof(data, "Failed public key authentication (rc: %d)\n", rc); MOVE_TO_SECONDARY_AUTH; } break; case SSH_AUTH_GSSAPI: if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) { MOVE_TO_TERTIARY_AUTH; } rc = ssh_userauth_gssapi(sshc->ssh_session); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc == SSH_AUTH_SUCCESS) { rc = SSH_OK; sshc->authed = TRUE; infof(data, "Completed gssapi authentication\n"); state(conn, SSH_AUTH_DONE); break; } MOVE_TO_TERTIARY_AUTH; break; case SSH_AUTH_KEY_INIT: if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) { state(conn, SSH_AUTH_KEY); } else { MOVE_TO_LAST_AUTH; } break; case SSH_AUTH_KEY: /* Authentication failed. Continue with keyboard-interactive now. */ rc = myssh_auth_interactive(conn); if(rc == SSH_AGAIN) { break; } if(rc == SSH_OK) { sshc->authed = TRUE; infof(data, "completed keyboard interactive authentication\n"); } state(conn, SSH_AUTH_DONE); break; case SSH_AUTH_PASS_INIT: if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) { /* Host key authentication is intentionally not implemented */ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); } state(conn, SSH_AUTH_PASS); /* FALLTHROUGH */ case SSH_AUTH_PASS: rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd); if(rc == SSH_AUTH_AGAIN) { rc = SSH_AGAIN; break; } if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Completed password authentication\n"); state(conn, SSH_AUTH_DONE); } else { MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); } break; case SSH_AUTH_DONE: if(!sshc->authed) { failf(data, "Authentication failure"); MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); break; } /* * At this point we have an authenticated ssh session. */ infof(data, "Authentication complete\n"); Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */ conn->sockfd = sock; conn->writesockfd = CURL_SOCKET_BAD; if(conn->handler->protocol == CURLPROTO_SFTP) { state(conn, SSH_SFTP_INIT); break; } infof(data, "SSH CONNECT phase done\n"); state(conn, SSH_STOP); break; case SSH_SFTP_INIT: ssh_set_blocking(sshc->ssh_session, 1); sshc->sftp_session = sftp_new(sshc->ssh_session); if(!sshc->sftp_session) { failf(data, "Failure initializing sftp session: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); break; } rc = sftp_init(sshc->sftp_session); if(rc != SSH_OK) { rc = sftp_get_error(sshc->sftp_session); failf(data, "Failure initializing sftp session: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc)); break; } state(conn, SSH_SFTP_REALPATH); /* FALLTHROUGH */ case SSH_SFTP_REALPATH: /* * Get the "home" directory */ sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, "."); if(sshc->homedir == NULL) { MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); } conn->data->state.most_recent_ftp_entrypath = sshc->homedir; /* This is the last step in the SFTP connect phase. Do note that while we get the homedir here, we get the "workingpath" in the DO action since the homedir will remain the same between request but the working path will not. */ DEBUGF(infof(data, "SSH CONNECT phase done\n")); state(conn, SSH_STOP); break; case SSH_SFTP_QUOTE_INIT: result = Curl_getworkingpath(conn, sshc->homedir, &protop->path); if(result) { sshc->actualcode = result; state(conn, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands\n"); sshc->quote_item = data->set.quote; state(conn, SSH_SFTP_QUOTE); } else { state(conn, SSH_SFTP_GETINFO); } break; case SSH_SFTP_POSTQUOTE_INIT: if(data->set.postquote) { infof(data, "Sending quote commands\n"); sshc->quote_item = data->set.postquote; state(conn, SSH_SFTP_QUOTE); } else { state(conn, SSH_STOP); } break; case SSH_SFTP_QUOTE: /* Send any quote commands */ sftp_quote(conn); break; case SSH_SFTP_NEXT_QUOTE: Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); sshc->quote_item = sshc->quote_item->next; if(sshc->quote_item) { state(conn, SSH_SFTP_QUOTE); } else { if(sshc->nextstate != SSH_NO_STATE) { state(conn, sshc->nextstate); sshc->nextstate = SSH_NO_STATE; } else { state(conn, SSH_SFTP_GETINFO); } } break; case SSH_SFTP_QUOTE_STAT: sftp_quote_stat(conn); break; case SSH_SFTP_QUOTE_SETSTAT: rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2, sshc->quote_attrs); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; /* sshc->actualcode = sftp_error_to_CURLE(err); * we do not send the actual error; we return * the error the libssh2 backend is returning */ break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_SYMLINK: rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2, sshc->quote_path1); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_MKDIR: rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1, (mode_t)data->set.new_directory_perms); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RENAME: rc = sftp_rename(sshc->sftp_session, sshc->quote_path1, sshc->quote_path2); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "rename command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RMDIR: rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_UNLINK: rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1); if(rc != 0 && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } state(conn, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_STATVFS: { sftp_statvfs_t statvfs; statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1); if(!statvfs && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "statvfs command failed: %s", ssh_get_error(sshc->ssh_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } else if(statvfs) { char *tmp = aprintf("statvfs:\n" "f_bsize: %llu\n" "f_frsize: %llu\n" "f_blocks: %llu\n" "f_bfree: %llu\n" "f_bavail: %llu\n" "f_files: %llu\n" "f_ffree: %llu\n" "f_favail: %llu\n" "f_fsid: %llu\n" "f_flag: %llu\n" "f_namemax: %llu\n", statvfs->f_bsize, statvfs->f_frsize, statvfs->f_blocks, statvfs->f_bfree, statvfs->f_bavail, statvfs->f_files, statvfs->f_ffree, statvfs->f_favail, statvfs->f_fsid, statvfs->f_flag, statvfs->f_namemax); sftp_statvfs_free(statvfs); if(!tmp) { result = CURLE_OUT_OF_MEMORY; state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; break; } result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } } state(conn, SSH_SFTP_NEXT_QUOTE); break; } case SSH_SFTP_GETINFO: if(data->set.get_filetime) { state(conn, SSH_SFTP_FILETIME); } else { state(conn, SSH_SFTP_TRANS_INIT); } break; case SSH_SFTP_FILETIME: { sftp_attributes attrs; attrs = sftp_stat(sshc->sftp_session, protop->path); if(attrs != 0) { data->info.filetime = attrs->mtime; sftp_attributes_free(attrs); } state(conn, SSH_SFTP_TRANS_INIT); break; } case SSH_SFTP_TRANS_INIT: if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); else { if(protop->path[strlen(protop->path)-1] == '/') state(conn, SSH_SFTP_READDIR_INIT); else state(conn, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: { int flags; if(data->state.resume_from != 0) { sftp_attributes attrs; if(data->state.resume_from < 0) { attrs = sftp_stat(sshc->sftp_session, protop->path); if(attrs != 0) { curl_off_t size = attrs->size; if(size < 0) { failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); } data->state.resume_from = attrs->size; sftp_attributes_free(attrs); } else { data->state.resume_from = 0; } } } if(data->set.ftp_append) /* Try to open for append, but create if nonexisting */ flags = O_WRONLY|O_CREAT|O_APPEND; else if(data->state.resume_from > 0) /* If we have restart position then open for append */ flags = O_WRONLY|O_APPEND; else /* Clear file before writing (normal behaviour) */ flags = O_WRONLY|O_CREAT|O_TRUNC; if(sshc->sftp_file) sftp_close(sshc->sftp_file); sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path, flags, (mode_t)data->set.new_file_perms); if(!sshc->sftp_file) { err = sftp_get_error(sshc->sftp_session); if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE || err == SSH_FX_NO_SUCH_PATH)) && (data->set.ftp_create_missing_dirs && (strlen(protop->path) > 1))) { /* try to create the path remotely */ rc = 0; sshc->secondCreateDirs = 1; state(conn, SSH_SFTP_CREATE_DIRS_INIT); break; } else { MOVE_TO_SFTP_CLOSE_STATE(); } } /* If we have a restart point then we need to seek to the correct position. */ if(data->state.resume_from > 0) { /* Let's read off the proper amount of bytes from the input. */ if(conn->seek_func) { Curl_set_in_callback(data, true); seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, SEEK_SET); Curl_set_in_callback(data, false); } if(seekerr != CURL_SEEKFUNC_OK) { curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { size_t readthisamountnow = (data->state.resume_from - passed > data->set.buffer_size) ? (size_t)data->set.buffer_size : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = data->state.fread_func(data->state.buffer, 1, readthisamountnow, data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Failed to read data"); MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST); } } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize > 0) { data->state.infilesize -= data->state.resume_from; data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); if(rc != 0) { MOVE_TO_SFTP_CLOSE_STATE(); } } if(data->state.infilesize > 0) { data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; /* store this original bitmask setup to use later on if we can't figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh sftp send function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ Curl_expire(data, 0, EXPIRE_RUN_NOW); state(conn, SSH_STOP); break; } case SSH_SFTP_CREATE_DIRS_INIT: if(strlen(protop->path) > 1) { sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */ state(conn, SSH_SFTP_CREATE_DIRS); } else { state(conn, SSH_SFTP_UPLOAD_INIT); } break; case SSH_SFTP_CREATE_DIRS: sshc->slash_pos = strchr(sshc->slash_pos, '/'); if(sshc->slash_pos) { *sshc->slash_pos = 0; infof(data, "Creating directory '%s'\n", protop->path); state(conn, SSH_SFTP_CREATE_DIRS_MKDIR); break; } state(conn, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: /* 'mode' - parameter is preliminary - default to 0644 */ rc = sftp_mkdir(sshc->sftp_session, protop->path, (mode_t)data->set.new_directory_perms); *sshc->slash_pos = '/'; ++sshc->slash_pos; if(rc < 0) { /* * Abort if failure wasn't that the dir already exists or the * permission was denied (creation might succeed further down the * path) - retry on unspecific FAILURE also */ err = sftp_get_error(sshc->sftp_session); if((err != SSH_FX_FILE_ALREADY_EXISTS) && (err != SSH_FX_FAILURE) && (err != SSH_FX_PERMISSION_DENIED)) { MOVE_TO_SFTP_CLOSE_STATE(); } rc = 0; /* clear rc and continue */ } state(conn, SSH_SFTP_CREATE_DIRS); break; case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->set.opt_no_body) { state(conn, SSH_STOP); break; } /* * This is a directory that we are trying to get, so produce a directory * listing */ sshc->sftp_dir = sftp_opendir(sshc->sftp_session, protop->path); if(!sshc->sftp_dir) { failf(data, "Could not open directory for reading: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_SFTP_CLOSE_STATE(); } state(conn, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR: if(sshc->readdir_attrs) sftp_attributes_free(sshc->readdir_attrs); sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir); if(sshc->readdir_attrs) { sshc->readdir_filename = sshc->readdir_attrs->name; sshc->readdir_longentry = sshc->readdir_attrs->longname; sshc->readdir_len = strlen(sshc->readdir_filename); if(data->set.ftp_list_only) { char *tmpLine; tmpLine = aprintf("%s\n", sshc->readdir_filename); if(tmpLine == NULL) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } result = Curl_client_write(conn, CLIENTWRITE_BODY, tmpLine, sshc->readdir_len + 1); free(tmpLine); if(result) { state(conn, SSH_STOP); break; } /* since this counts what we send to the client, we include the newline in this counter */ data->req.bytecount += sshc->readdir_len + 1; /* output debug output if that is requested */ if(data->set.verbose) { Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename, sshc->readdir_len); } } else { sshc->readdir_currLen = strlen(sshc->readdir_longentry); sshc->readdir_totalLen = 80 + sshc->readdir_currLen; sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); if(!sshc->readdir_line) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } memcpy(sshc->readdir_line, sshc->readdir_longentry, sshc->readdir_currLen); if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && ((sshc->readdir_attrs->permissions & S_IFMT) == S_IFLNK)) { sshc->readdir_linkPath = malloc(PATH_MAX + 1); if(sshc->readdir_linkPath == NULL) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path, sshc->readdir_filename); state(conn, SSH_SFTP_READDIR_LINK); break; } state(conn, SSH_SFTP_READDIR_BOTTOM); break; } } else if(sftp_dir_eof(sshc->sftp_dir)) { state(conn, SSH_SFTP_READDIR_DONE); break; } else { failf(data, "Could not open remote file for reading: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_SFTP_CLOSE_STATE(); break; } break; case SSH_SFTP_READDIR_LINK: if(sshc->readdir_link_attrs) sftp_attributes_free(sshc->readdir_link_attrs); sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session, sshc->readdir_linkPath); if(sshc->readdir_link_attrs == 0) { failf(data, "Could not read symlink for reading: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_SFTP_CLOSE_STATE(); } if(sshc->readdir_link_attrs->name == NULL) { sshc->readdir_tmp = sftp_readlink(sshc->sftp_session, sshc->readdir_linkPath); if(sshc->readdir_filename == NULL) sshc->readdir_len = 0; else sshc->readdir_len = strlen(sshc->readdir_tmp); sshc->readdir_longentry = NULL; sshc->readdir_filename = sshc->readdir_tmp; } else { sshc->readdir_len = strlen(sshc->readdir_link_attrs->name); sshc->readdir_filename = sshc->readdir_link_attrs->name; sshc->readdir_longentry = sshc->readdir_link_attrs->longname; } Curl_safefree(sshc->readdir_linkPath); /* get room for the filename and extra output */ sshc->readdir_totalLen += 4 + sshc->readdir_len; new_readdir_line = Curl_saferealloc(sshc->readdir_line, sshc->readdir_totalLen); if(!new_readdir_line) { sshc->readdir_line = NULL; state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } sshc->readdir_line = new_readdir_line; sshc->readdir_currLen += msnprintf(sshc->readdir_line + sshc->readdir_currLen, sshc->readdir_totalLen - sshc->readdir_currLen, " -> %s", sshc->readdir_filename); sftp_attributes_free(sshc->readdir_link_attrs); sshc->readdir_link_attrs = NULL; sshc->readdir_filename = NULL; sshc->readdir_longentry = NULL; state(conn, SSH_SFTP_READDIR_BOTTOM); /* FALLTHROUGH */ case SSH_SFTP_READDIR_BOTTOM: sshc->readdir_currLen += msnprintf(sshc->readdir_line + sshc->readdir_currLen, sshc->readdir_totalLen - sshc->readdir_currLen, "\n"); result = Curl_client_write(conn, CLIENTWRITE_BODY, sshc->readdir_line, sshc->readdir_currLen); if(!result) { /* output debug output if that is requested */ if(data->set.verbose) { Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line, sshc->readdir_currLen); } data->req.bytecount += sshc->readdir_currLen; } Curl_safefree(sshc->readdir_line); ssh_string_free_char(sshc->readdir_tmp); sshc->readdir_tmp = NULL; if(result) { state(conn, SSH_STOP); } else state(conn, SSH_SFTP_READDIR); break; case SSH_SFTP_READDIR_DONE: sftp_closedir(sshc->sftp_dir); sshc->sftp_dir = NULL; /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); state(conn, SSH_STOP); break; case SSH_SFTP_DOWNLOAD_INIT: /* * Work on getting the specified file */ if(sshc->sftp_file) sftp_close(sshc->sftp_file); sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path, O_RDONLY, (mode_t)data->set.new_file_perms); if(!sshc->sftp_file) { failf(data, "Could not open remote file for reading: %s", ssh_get_error(sshc->ssh_session)); MOVE_TO_SFTP_CLOSE_STATE(); } state(conn, SSH_SFTP_DOWNLOAD_STAT); break; case SSH_SFTP_DOWNLOAD_STAT: { sftp_attributes attrs; curl_off_t size; attrs = sftp_fstat(sshc->sftp_file); if(!attrs || !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) || (attrs->size == 0)) { /* * sftp_fstat didn't return an error, so maybe the server * just doesn't support stat() * OR the server doesn't return a file size with a stat() * OR file size is 0 */ data->req.size = -1; data->req.maxdownload = -1; Curl_pgrsSetDownloadSize(data, -1); size = 0; } else { size = attrs->size; sftp_attributes_free(attrs); if(size < 0) { failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } if(conn->data->state.use_range) { curl_off_t from, to; char *ptr; char *ptr2; CURLofft to_t; CURLofft from_t; from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) { return CURLE_RANGE_ERROR; } while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) { return CURLE_RANGE_ERROR; } if((to_t == CURL_OFFT_INVAL) /* no "to" value given */ || (to >= size)) { to = size - 1; } if(from_t) { /* from is relative to end of file */ from = size - to; to = size - 1; } if(from > size) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", from, size); return CURLE_BAD_DOWNLOAD_RESUME; } if(from > to) { from = to; size = 0; } else { size = to - from + 1; } rc = sftp_seek64(sshc->sftp_file, from); if(rc != 0) { MOVE_TO_SFTP_CLOSE_STATE(); } } data->req.size = size; data->req.maxdownload = size; Curl_pgrsSetDownloadSize(data, size); } /* We can resume if we can seek to the resume position */ if(data->state.resume_from) { if(data->state.resume_from < 0) { /* We're supposed to download the last abs(from) bytes */ if((curl_off_t)size < -data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, size); return CURLE_BAD_DOWNLOAD_RESUME; } /* download from where? */ data->state.resume_from += size; } else { if((curl_off_t)size < data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, size); return CURLE_BAD_DOWNLOAD_RESUME; } } /* Now store the number of bytes we are expected to download */ data->req.size = size - data->state.resume_from; data->req.maxdownload = size - data->state.resume_from; Curl_pgrsSetDownloadSize(data, size - data->state.resume_from); rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); if(rc != 0) { MOVE_TO_SFTP_CLOSE_STATE(); } } } /* Setup the actual download */ if(data->req.size == 0) { /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); infof(data, "File already completely downloaded\n"); state(conn, SSH_STOP); break; } Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh recv function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { sshc->sftp_recv_state = 0; state(conn, SSH_STOP); } break; case SSH_SFTP_CLOSE: if(sshc->sftp_file) { sftp_close(sshc->sftp_file); sshc->sftp_file = NULL; } Curl_safefree(protop->path); DEBUGF(infof(data, "SFTP DONE done\n")); /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT After nextstate is executed, the control should come back to SSH_SFTP_CLOSE to pass the correct result back */ if(sshc->nextstate != SSH_NO_STATE && sshc->nextstate != SSH_SFTP_CLOSE) { state(conn, sshc->nextstate); sshc->nextstate = SSH_SFTP_CLOSE; } else { state(conn, SSH_STOP); result = sshc->actualcode; } break; case SSH_SFTP_SHUTDOWN: /* during times we get here due to a broken transfer and then the sftp_handle might not have been taken down so make sure that is done before we proceed */ if(sshc->sftp_file) { sftp_close(sshc->sftp_file); sshc->sftp_file = NULL; } if(sshc->sftp_session) { sftp_free(sshc->sftp_session); sshc->sftp_session = NULL; } SSH_STRING_FREE_CHAR(sshc->homedir); conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_DISCONNECT); break; case SSH_SCP_TRANS_INIT: result = Curl_getworkingpath(conn, sshc->homedir, &protop->path); if(result) { sshc->actualcode = result; state(conn, SSH_STOP); break; } /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */ ssh_set_blocking(sshc->ssh_session, 1); if(data->set.upload) { if(data->state.infilesize < 0) { failf(data, "SCP requires a known file size for upload"); sshc->actualcode = CURLE_UPLOAD_FAILED; MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); } sshc->scp_session = ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path); state(conn, SSH_SCP_UPLOAD_INIT); } else { sshc->scp_session = ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path); state(conn, SSH_SCP_DOWNLOAD_INIT); } if(!sshc->scp_session) { err_msg = ssh_get_error(sshc->ssh_session); failf(conn->data, "%s", err_msg); MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); } break; case SSH_SCP_UPLOAD_INIT: rc = ssh_scp_init(sshc->scp_session); if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(conn->data, "%s", err_msg); MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); } rc = ssh_scp_push_file(sshc->scp_session, protop->path, data->state.infilesize, (int)data->set.new_file_perms); if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(conn->data, "%s", err_msg); MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); } /* upload data */ Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; /* store this original bitmask setup to use later on if we can't figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh scp send function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_OUT; state(conn, SSH_STOP); break; case SSH_SCP_DOWNLOAD_INIT: rc = ssh_scp_init(sshc->scp_session); if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(conn->data, "%s", err_msg); MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); } state(conn, SSH_SCP_DOWNLOAD); /* FALLTHROUGH */ case SSH_SCP_DOWNLOAD:{ curl_off_t bytecount; rc = ssh_scp_pull_request(sshc->scp_session); if(rc != SSH_SCP_REQUEST_NEWFILE) { err_msg = ssh_get_error(sshc->ssh_session); failf(conn->data, "%s", err_msg); MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND); break; } /* download data */ bytecount = ssh_scp_request_get_size(sshc->scp_session); data->req.maxdownload = (curl_off_t) bytecount; Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh recv function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; state(conn, SSH_STOP); break; } case SSH_SCP_DONE: if(data->set.upload) state(conn, SSH_SCP_SEND_EOF); else state(conn, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_SEND_EOF: if(sshc->scp_session) { rc = ssh_scp_close(sshc->scp_session); if(rc == SSH_AGAIN) { /* Currently the ssh_scp_close handles waiting for EOF in * blocking way. */ break; } if(rc != SSH_OK) { infof(data, "Failed to close libssh scp channel: %s\n", ssh_get_error(sshc->ssh_session)); } } state(conn, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_CHANNEL_FREE: if(sshc->scp_session) { ssh_scp_free(sshc->scp_session); sshc->scp_session = NULL; } DEBUGF(infof(data, "SCP DONE phase complete\n")); ssh_set_blocking(sshc->ssh_session, 0); state(conn, SSH_SESSION_DISCONNECT); /* FALLTHROUGH */ case SSH_SESSION_DISCONNECT: /* during weird times when we've been prematurely aborted, the channel is still alive when we reach this state and we MUST kill the channel properly first */ if(sshc->scp_session) { ssh_scp_free(sshc->scp_session); sshc->scp_session = NULL; } ssh_disconnect(sshc->ssh_session); SSH_STRING_FREE_CHAR(sshc->homedir); conn->data->state.most_recent_ftp_entrypath = NULL; state(conn, SSH_SESSION_FREE); /* FALLTHROUGH */ case SSH_SESSION_FREE: if(sshc->ssh_session) { ssh_free(sshc->ssh_session); sshc->ssh_session = NULL; } /* worst-case scenario cleanup */ DEBUGASSERT(sshc->ssh_session == NULL); DEBUGASSERT(sshc->scp_session == NULL); if(sshc->readdir_tmp) { ssh_string_free_char(sshc->readdir_tmp); sshc->readdir_tmp = NULL; } if(sshc->quote_attrs) sftp_attributes_free(sshc->quote_attrs); if(sshc->readdir_attrs) sftp_attributes_free(sshc->readdir_attrs); if(sshc->readdir_link_attrs) sftp_attributes_free(sshc->readdir_link_attrs); if(sshc->privkey) ssh_key_free(sshc->privkey); if(sshc->pubkey) ssh_key_free(sshc->pubkey); Curl_safefree(sshc->rsa_pub); Curl_safefree(sshc->rsa); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->readdir_line); Curl_safefree(sshc->readdir_linkPath); SSH_STRING_FREE_CHAR(sshc->homedir); /* the code we are about to return */ result = sshc->actualcode; memset(sshc, 0, sizeof(struct ssh_conn)); connclose(conn, "SSH session free"); sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); break; case SSH_QUIT: /* fallthrough, just stop! */ default: /* internal error */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); break; } } while(!rc && (sshc->state != SSH_STOP)); if(rc == SSH_AGAIN) { /* we would block, we need to wait for the socket to be ready (in the right direction too)! */ *block = TRUE; } return result; } /* called by the multi interface to figure out what socket(s) to wait for and for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ static int myssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock) { int bitmap = GETSOCK_BLANK; sock[0] = conn->sock[FIRSTSOCKET]; if(conn->waitfor & KEEP_RECV) bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); if(conn->waitfor & KEEP_SEND) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; } /* Generic function called by the multi interface to figure out what socket(s) to wait for and for what actions during the DOING and PROTOCONNECT states*/ static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock) { /* if we know the direction we can use the generic *_getsock() function even for the protocol_connect and doing states */ return myssh_perform_getsock(conn, sock); } static void myssh_block2waitfor(struct connectdata *conn, bool block) { struct ssh_conn *sshc = &conn->proto.sshc; /* If it didn't block, or nothing was returned by ssh_get_poll_flags * have the original set */ conn->waitfor = sshc->orig_waitfor; if(block) { int dir = ssh_get_poll_flags(sshc->ssh_session); if(dir & SSH_READ_PENDING) { /* translate the libssh define bits into our own bit defines */ conn->waitfor = KEEP_RECV; } else if(dir & SSH_WRITE_PENDING) { conn->waitfor = KEEP_SEND; } } } /* called repeatedly until done from multi.c */ static CURLcode myssh_multi_statemach(struct connectdata *conn, bool *done) { struct ssh_conn *sshc = &conn->proto.sshc; bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ CURLcode result = myssh_statemach_act(conn, &block); *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; myssh_block2waitfor(conn, block); return result; } static CURLcode myssh_block_statemach(struct connectdata *conn, bool disconnect) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; while((sshc->state != SSH_STOP) && !result) { bool block; timediff_t left = 1000; struct curltime now = Curl_now(); result = myssh_statemach_act(conn, &block); if(result) break; if(!disconnect) { if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; result = Curl_speedcheck(data, now); if(result) break; left = Curl_timeleft(data, NULL, FALSE); if(left < 0) { failf(data, "Operation timed out"); return CURLE_OPERATION_TIMEDOUT; } } if(block) { curl_socket_t fd_read = conn->sock[FIRSTSOCKET]; /* wait for the socket to become ready */ (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD, CURL_SOCKET_BAD, left > 1000 ? 1000 : left); } } return result; } /* * SSH setup connection */ static CURLcode myssh_setup_connection(struct connectdata *conn) { struct SSHPROTO *ssh; conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static Curl_recv scp_recv, sftp_recv; static Curl_send scp_send, sftp_send; /* * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to * do protocol-specific actions at connect-time. */ static CURLcode myssh_connect(struct connectdata *conn, bool *done) { struct ssh_conn *ssh; CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; /* initialize per-handle data if not already */ if(!data->req.protop) myssh_setup_connection(conn); /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "SSH default"); if(conn->handler->protocol & CURLPROTO_SCP) { conn->recv[FIRSTSOCKET] = scp_recv; conn->send[FIRSTSOCKET] = scp_send; } else { conn->recv[FIRSTSOCKET] = sftp_recv; conn->send[FIRSTSOCKET] = sftp_send; } ssh = &conn->proto.sshc; ssh->ssh_session = ssh_new(); if(ssh->ssh_session == NULL) { failf(data, "Failure initialising ssh session"); return CURLE_FAILED_INIT; } ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock); if(conn->user) { infof(data, "User: %s\n", conn->user); ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user); } if(data->set.str[STRING_SSH_KNOWNHOSTS]) { infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]); ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, data->set.str[STRING_SSH_KNOWNHOSTS]); } ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name); if(conn->remote_port) ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT, &conn->remote_port); if(data->set.ssh_compression) { ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION, "zlib,zlib@openssh.com,none"); } ssh->privkey = NULL; ssh->pubkey = NULL; if(data->set.str[STRING_SSH_PUBLIC_KEY]) { int rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY], &ssh->pubkey); if(rc != SSH_OK) { failf(data, "Could not load public key file"); /* ignore */ } } /* we do not verify here, we do it at the state machine, * after connection */ state(conn, SSH_INIT); result = myssh_multi_statemach(conn, done); return result; } /* called from multi.c while DOing */ static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result; result = myssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* *********************************************************************** * * scp_perform() * * This is the actual DO function for SCP. Get a file according to * the options previously setup. */ static CURLcode scp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ state(conn, SSH_SCP_TRANS_INIT); result = myssh_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } static CURLcode myssh_do_it(struct connectdata *conn, bool *done) { CURLcode result; bool connected = 0; struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ data->req.size = -1; /* make sure this is unknown at this point */ sshc->actualcode = CURLE_OK; /* reset error code */ sshc->secondCreateDirs = 0; /* reset the create dir attempt state variable */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); if(conn->handler->protocol & CURLPROTO_SCP) result = scp_perform(conn, &connected, done); else result = sftp_perform(conn, &connected, done); return result; } /* BLOCKING, but the function is using the state machine so the only reason this is still blocking is that the multi interface code has no support for disconnecting operations that takes a while */ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; struct ssh_conn *ssh = &conn->proto.sshc; (void) dead_connection; if(ssh->ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SESSION_DISCONNECT); result = myssh_block_statemach(conn, TRUE); } return result; } /* generic done function for both SCP and SFTP called from their specific done functions */ static CURLcode myssh_done(struct connectdata *conn, CURLcode status) { CURLcode result = CURLE_OK; struct SSHPROTO *protop = conn->data->req.protop; if(!status) { /* run the state-machine */ result = myssh_block_statemach(conn, FALSE); } else result = status; if(protop) Curl_safefree(protop->path); if(Curl_pgrsDone(conn)) return CURLE_ABORTED_BY_CALLBACK; conn->data->req.keepon = 0; /* clear all bits */ return result; } static CURLcode scp_done(struct connectdata *conn, CURLcode status, bool premature) { (void) premature; /* not used */ if(!status) state(conn, SSH_SCP_DONE); return myssh_done(conn, status); } static ssize_t scp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { int rc; (void) sockindex; /* we only support SCP on the fixed known primary socket */ (void) err; rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len); #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. * Currently rc can only be number of bytes read or SSH_ERROR. */ myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE); if(rc == SSH_AGAIN) { *err = CURLE_AGAIN; return 0; } else #endif if(rc != SSH_OK) { *err = CURLE_SSH; return -1; } return len; } static ssize_t scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { ssize_t nread; (void) err; (void) sockindex; /* we only support SCP on the fixed known primary socket */ /* libssh returns int */ nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len); #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. * Currently rc can only be SSH_OK or SSH_ERROR. */ myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE); if(nread == SSH_AGAIN) { *err = CURLE_AGAIN; nread = -1; } #endif return nread; } /* * =============== SFTP =============== */ /* *********************************************************************** * * sftp_perform() * * This is the actual DO function for SFTP. Get a file/directory according to * the options previously setup. */ static CURLcode sftp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ state(conn, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = myssh_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* called from multi.c while DOing */ static CURLcode sftp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = myssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* BLOCKING, but the function is using the state machine so the only reason this is still blocking is that the multi interface code has no support for disconnecting operations that takes a while */ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; (void) dead_connection; DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); result = myssh_block_statemach(conn, TRUE); } DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); return result; } static CURLcode sftp_done(struct connectdata *conn, CURLcode status, bool premature) { struct ssh_conn *sshc = &conn->proto.sshc; if(!status) { /* Post quote commands are executed after the SFTP_CLOSE state to avoid errors that could happen due to open file handles during POSTQUOTE operation */ if(!premature && conn->data->set.postquote && !conn->bits.retry) sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; state(conn, SSH_SFTP_CLOSE); } return myssh_done(conn, status); } /* return number of sent bytes */ static ssize_t sftp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { ssize_t nwrite; (void)sockindex; nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len); myssh_block2waitfor(conn, FALSE); #if 0 /* not returned by libssh on write */ if(nwrite == SSH_AGAIN) { *err = CURLE_AGAIN; nwrite = 0; } else #endif if(nwrite < 0) { *err = CURLE_SSH; nwrite = -1; } return nwrite; } /* * Return number of received (decrypted) bytes * or <0 on error */ static ssize_t sftp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { ssize_t nread; (void)sockindex; DEBUGASSERT(len < CURL_MAX_READ_SIZE); switch(conn->proto.sshc.sftp_recv_state) { case 0: conn->proto.sshc.sftp_file_index = sftp_async_read_begin(conn->proto.sshc.sftp_file, (uint32_t)len); if(conn->proto.sshc.sftp_file_index < 0) { *err = CURLE_RECV_ERROR; return -1; } /* FALLTHROUGH */ case 1: conn->proto.sshc.sftp_recv_state = 1; nread = sftp_async_read(conn->proto.sshc.sftp_file, mem, (uint32_t)len, conn->proto.sshc.sftp_file_index); myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE); if(nread == SSH_AGAIN) { *err = CURLE_AGAIN; return -1; } else if(nread < 0) { *err = CURLE_RECV_ERROR; return -1; } conn->proto.sshc.sftp_recv_state = 0; return nread; default: /* we never reach here */ return -1; } } static void sftp_quote(struct connectdata *conn) { const char *cp; struct Curl_easy *data = conn->data; struct SSHPROTO *protop = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result; /* * Support some of the "FTP" commands */ char *cmd = sshc->quote_item->data; sshc->acceptfail = FALSE; /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command is successful, whatever the server reponds. */ if(cmd[0] == '*') { cmd++; sshc->acceptfail = TRUE; } if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", protop->path); if(!tmp) { sshc->actualcode = CURLE_OUT_OF_MEMORY; state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; return; } if(data->set.verbose) { Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4); Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); } /* this sends an FTP-like "header" to the header callback so that the current directory can be read very similar to how it is read when using ordinary FTP. */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); free(tmp); if(result) { state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; } else state(conn, SSH_SFTP_NEXT_QUOTE); return; } /* * the arguments following the command must be separated from the * command with a space so we can check for it unconditionally */ cp = strchr(cmd, ' '); if(cp == NULL) { failf(data, "Syntax error in SFTP command. Supply parameter(s)!"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } /* * also, every command takes at least one argument so we get that * first argument right now */ result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error: Bad first parameter"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } /* * SFTP is a binary protocol, so we don't send text commands * to the server. Instead, we scan for commands used by * OpenSSH's sftp program and call the appropriate libssh * functions. */ if(strncasecompare(cmd, "chgrp ", 6) || strncasecompare(cmd, "chmod ", 6) || strncasecompare(cmd, "chown ", 6)) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ /* get the destination */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in chgrp/chmod/chown: " "Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } sshc->quote_attrs = NULL; state(conn, SSH_SFTP_QUOTE_STAT); return; } if(strncasecompare(cmd, "ln ", 3) || strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in ln/symlink: Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } state(conn, SSH_SFTP_QUOTE_SYMLINK); return; } else if(strncasecompare(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); return; } else if(strncasecompare(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); if(result) { if(result == CURLE_OUT_OF_MEMORY) failf(data, "Out of memory"); else failf(data, "Syntax error in rename: Bad second parameter"); Curl_safefree(sshc->quote_path1); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = result; return; } state(conn, SSH_SFTP_QUOTE_RENAME); return; } else if(strncasecompare(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); return; } else if(strncasecompare(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); return; } #ifdef HAS_STATVFS_SUPPORT else if(strncasecompare(cmd, "statvfs ", 8)) { state(conn, SSH_SFTP_QUOTE_STATVFS); return; } #endif failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; } static void sftp_quote_stat(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; char *cmd = sshc->quote_item->data; sshc->acceptfail = FALSE; /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command is successful, whatever the server reponds. */ if(cmd[0] == '*') { cmd++; sshc->acceptfail = TRUE; } /* We read the file attributes, store them in sshc->quote_attrs * and modify them accordingly to command. Then we switch to * QUOTE_SETSTAT state to write new ones. */ if(sshc->quote_attrs) sftp_attributes_free(sshc->quote_attrs); sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2); if(sshc->quote_attrs == NULL) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Attempt to get SFTP stats failed: %d", sftp_get_error(sshc->sftp_session)); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } /* Now set the new attributes... */ if(strncasecompare(cmd, "chgrp", 5)) { sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(strncasecompare(cmd, "chmod", 5)) { mode_t perms; perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8); /* permissions are octal */ if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chmod permissions not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } sshc->quote_attrs->permissions = perms; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS; } else if(strncasecompare(cmd, "chown", 5)) { sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10); if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); state(conn, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } /* Now send the completed structure... */ state(conn, SSH_SFTP_QUOTE_SETSTAT); return; } CURLcode Curl_ssh_init(void) { if(ssh_init()) { DEBUGF(fprintf(stderr, "Error: libssh_init failed\n")); return CURLE_FAILED_INIT; } return CURLE_OK; } void Curl_ssh_cleanup(void) { (void)ssh_finalize(); } size_t Curl_ssh_version(char *buffer, size_t buflen) { return msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION); } #endif /* USE_LIBSSH */ davix-0.8.0/deps/curl/lib/vssh/wolfssh.c0000644000000000000000000010254514121063461016617 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_WOLFSSH #include #include #include #include "urldata.h" #include "connect.h" #include "sendf.h" #include "progress.h" #include "curl_path.h" #include "strtoofft.h" #include "transfer.h" #include "speedcheck.h" #include "select.h" #include "multiif.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static CURLcode wssh_connect(struct connectdata *conn, bool *done); static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done); static CURLcode wssh_do(struct connectdata *conn, bool *done); #if 0 static CURLcode wscp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode wscp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection); #endif static CURLcode wsftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode wsftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead); static int wssh_getsock(struct connectdata *conn, curl_socket_t *sock); static int wssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock); static CURLcode wssh_setup_connection(struct connectdata *conn); #if 0 /* * SCP protocol handler. */ const struct Curl_handler Curl_handler_scp = { "SCP", /* scheme */ wssh_setup_connection, /* setup_connection */ wssh_do, /* do_it */ wscp_done, /* done */ ZERO_NULL, /* do_more */ wssh_connect, /* connect_it */ wssh_multi_statemach, /* connecting */ wscp_doing, /* doing */ wssh_getsock, /* proto_getsock */ wssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ wssh_perform_getsock, /* perform_getsock */ wscp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SCP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; #endif /* * SFTP protocol handler. */ const struct Curl_handler Curl_handler_sftp = { "SFTP", /* scheme */ wssh_setup_connection, /* setup_connection */ wssh_do, /* do_it */ wsftp_done, /* done */ ZERO_NULL, /* do_more */ wssh_connect, /* connect_it */ wssh_multi_statemach, /* connecting */ wsftp_doing, /* doing */ wssh_getsock, /* proto_getsock */ wssh_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ wssh_perform_getsock, /* perform_getsock */ wsftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SSH, /* defport */ CURLPROTO_SFTP, /* protocol */ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ }; /* * SSH State machine related code */ /* This is the ONLY way to change SSH state! */ static void state(struct connectdata *conn, sshstate nowstate) { struct ssh_conn *sshc = &conn->proto.sshc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { "SSH_STOP", "SSH_INIT", "SSH_S_STARTUP", "SSH_HOSTKEY", "SSH_AUTHLIST", "SSH_AUTH_PKEY_INIT", "SSH_AUTH_PKEY", "SSH_AUTH_PASS_INIT", "SSH_AUTH_PASS", "SSH_AUTH_AGENT_INIT", "SSH_AUTH_AGENT_LIST", "SSH_AUTH_AGENT", "SSH_AUTH_HOST_INIT", "SSH_AUTH_HOST", "SSH_AUTH_KEY_INIT", "SSH_AUTH_KEY", "SSH_AUTH_GSSAPI", "SSH_AUTH_DONE", "SSH_SFTP_INIT", "SSH_SFTP_REALPATH", "SSH_SFTP_QUOTE_INIT", "SSH_SFTP_POSTQUOTE_INIT", "SSH_SFTP_QUOTE", "SSH_SFTP_NEXT_QUOTE", "SSH_SFTP_QUOTE_STAT", "SSH_SFTP_QUOTE_SETSTAT", "SSH_SFTP_QUOTE_SYMLINK", "SSH_SFTP_QUOTE_MKDIR", "SSH_SFTP_QUOTE_RENAME", "SSH_SFTP_QUOTE_RMDIR", "SSH_SFTP_QUOTE_UNLINK", "SSH_SFTP_QUOTE_STATVFS", "SSH_SFTP_GETINFO", "SSH_SFTP_FILETIME", "SSH_SFTP_TRANS_INIT", "SSH_SFTP_UPLOAD_INIT", "SSH_SFTP_CREATE_DIRS_INIT", "SSH_SFTP_CREATE_DIRS", "SSH_SFTP_CREATE_DIRS_MKDIR", "SSH_SFTP_READDIR_INIT", "SSH_SFTP_READDIR", "SSH_SFTP_READDIR_LINK", "SSH_SFTP_READDIR_BOTTOM", "SSH_SFTP_READDIR_DONE", "SSH_SFTP_DOWNLOAD_INIT", "SSH_SFTP_DOWNLOAD_STAT", "SSH_SFTP_CLOSE", "SSH_SFTP_SHUTDOWN", "SSH_SCP_TRANS_INIT", "SSH_SCP_UPLOAD_INIT", "SSH_SCP_DOWNLOAD_INIT", "SSH_SCP_DOWNLOAD", "SSH_SCP_DONE", "SSH_SCP_SEND_EOF", "SSH_SCP_WAIT_EOF", "SSH_SCP_WAIT_CLOSE", "SSH_SCP_CHANNEL_FREE", "SSH_SESSION_DISCONNECT", "SSH_SESSION_FREE", "QUIT" }; /* a precaution to make sure the lists are in sync */ DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST); if(sshc->state != nowstate) { infof(conn->data, "wolfssh %p state change from %s to %s\n", (void *)sshc, names[sshc->state], names[nowstate]); } #endif sshc->state = nowstate; } static ssize_t wscp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { ssize_t nwrite = 0; (void)conn; (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)mem; (void)len; (void)err; return nwrite; } static ssize_t wscp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { ssize_t nread = 0; (void)conn; (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)mem; (void)len; (void)err; return nread; } /* return number of sent bytes */ static ssize_t wsftp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { struct ssh_conn *sshc = &conn->proto.sshc; word32 offset[2]; int rc; (void)sockindex; offset[0] = (word32)sshc->offset&0xFFFFFFFF; offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, sshc->handleSz, &offset[0], (byte *)mem, (word32)len); if(rc == WS_FATAL_ERROR) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { conn->waitfor = KEEP_RECV; *err = CURLE_AGAIN; return -1; } else if(rc == WS_WANT_WRITE) { conn->waitfor = KEEP_SEND; *err = CURLE_AGAIN; return -1; } if(rc < 0) { failf(conn->data, "wolfSSH_SFTP_SendWritePacket returned %d\n", rc); return -1; } DEBUGASSERT(rc == (int)len); infof(conn->data, "sent %zd bytes SFTP from offset %zd\n", len, sshc->offset); sshc->offset += len; return (ssize_t)rc; } /* * Return number of received (decrypted) bytes * or <0 on error */ static ssize_t wsftp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { int rc; struct ssh_conn *sshc = &conn->proto.sshc; word32 offset[2]; (void)sockindex; offset[0] = (word32)sshc->offset&0xFFFFFFFF; offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF; rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, sshc->handleSz, &offset[0], (byte *)mem, (word32)len); if(rc == WS_FATAL_ERROR) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { conn->waitfor = KEEP_RECV; *err = CURLE_AGAIN; return -1; } else if(rc == WS_WANT_WRITE) { conn->waitfor = KEEP_SEND; *err = CURLE_AGAIN; return -1; } DEBUGASSERT(rc <= (int)len); if(rc < 0) { failf(conn->data, "wolfSSH_SFTP_SendReadPacket returned %d\n", rc); return -1; } sshc->offset += len; return (ssize_t)rc; } /* * SSH setup and connection */ static CURLcode wssh_setup_connection(struct connectdata *conn) { struct SSHPROTO *ssh; conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static Curl_recv wscp_recv, wsftp_recv; static Curl_send wscp_send, wsftp_send; static int userauth(byte authtype, WS_UserAuthData* authdata, void *ctx) { struct connectdata *conn = ctx; DEBUGF(infof(conn->data, "wolfssh callback: type %s\n", authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : "PUBLICCKEY")); if(authtype == WOLFSSH_USERAUTH_PASSWORD) { authdata->sf.password.password = (byte *)conn->passwd; authdata->sf.password.passwordSz = (word32) strlen(conn->passwd); } return 0; } static CURLcode wssh_connect(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; struct ssh_conn *sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; /* initialize per-handle data if not already */ if(!data->req.protop) wssh_setup_connection(conn); /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "SSH default"); if(conn->handler->protocol & CURLPROTO_SCP) { conn->recv[FIRSTSOCKET] = wscp_recv; conn->send[FIRSTSOCKET] = wscp_send; } else { conn->recv[FIRSTSOCKET] = wsftp_recv; conn->send[FIRSTSOCKET] = wsftp_send; } sshc = &conn->proto.sshc; sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); if(!sshc->ctx) { failf(data, "No wolfSSH context"); goto error; } sshc->ssh_session = wolfSSH_new(sshc->ctx); if(sshc->ssh_session == NULL) { failf(data, "No wolfSSH session"); goto error; } rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); if(rc != WS_SUCCESS) { failf(data, "wolfSSH failed to set user name"); goto error; } /* set callback for authentication */ wolfSSH_SetUserAuth(sshc->ctx, userauth); wolfSSH_SetUserAuthCtx(sshc->ssh_session, conn); rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); if(rc) { failf(data, "wolfSSH failed to set socket"); goto error; } #if 0 wolfSSH_Debugging_ON(); #endif *done = TRUE; if(conn->handler->protocol & CURLPROTO_SCP) state(conn, SSH_INIT); else state(conn, SSH_SFTP_INIT); return wssh_multi_statemach(conn, done); error: wolfSSH_free(sshc->ssh_session); wolfSSH_CTX_free(sshc->ctx); return CURLE_FAILED_INIT; } /* * wssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it * wants to be called again when the socket is ready */ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; struct ssh_conn *sshc = &conn->proto.sshc; struct Curl_easy *data = conn->data; struct SSHPROTO *sftp_scp = data->req.protop; WS_SFTPNAME *name; int rc = 0; *block = FALSE; /* we're not blocking by default */ do { switch(sshc->state) { case SSH_INIT: state(conn, SSH_S_STARTUP); /* FALLTHROUGH */ case SSH_S_STARTUP: rc = wolfSSH_connect(sshc->ssh_session); if(rc != WS_SUCCESS) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc != WS_SUCCESS) { state(conn, SSH_STOP); return CURLE_SSH; } infof(data, "wolfssh connected!\n"); state(conn, SSH_STOP); break; case SSH_STOP: break; case SSH_SFTP_INIT: rc = wolfSSH_SFTP_connect(sshc->ssh_session); if(rc != WS_SUCCESS) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc == WS_SUCCESS) { infof(data, "wolfssh SFTP connected!\n"); state(conn, SSH_SFTP_REALPATH); } else { failf(data, "wolfssh SFTP connect error %d", rc); return CURLE_SSH; } break; case SSH_SFTP_REALPATH: name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)"."); rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(name && (rc == WS_SUCCESS)) { sshc->homedir = malloc(name->fSz + 1); if(!sshc->homedir) { sshc->actualcode = CURLE_OUT_OF_MEMORY; } else { memcpy(sshc->homedir, name->fName, name->fSz); sshc->homedir[name->fSz] = 0; infof(data, "wolfssh SFTP realpath succeeded!\n"); } wolfSSH_SFTPNAME_list_free(name); state(conn, SSH_STOP); return CURLE_OK; } failf(data, "wolfssh SFTP realpath %d", rc); return CURLE_SSH; case SSH_SFTP_QUOTE_INIT: result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path); if(result) { sshc->actualcode = result; state(conn, SSH_STOP); break; } if(data->set.quote) { infof(data, "Sending quote commands\n"); sshc->quote_item = data->set.quote; state(conn, SSH_SFTP_QUOTE); } else { state(conn, SSH_SFTP_GETINFO); } break; case SSH_SFTP_GETINFO: if(data->set.get_filetime) { state(conn, SSH_SFTP_FILETIME); } else { state(conn, SSH_SFTP_TRANS_INIT); } break; case SSH_SFTP_TRANS_INIT: if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); else { if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') state(conn, SSH_SFTP_READDIR_INIT); else state(conn, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: { word32 flags; WS_SFTP_FILEATRB createattrs; if(data->state.resume_from) { WS_SFTP_FILEATRB attrs; if(data->state.resume_from < 0) { rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); if(rc != WS_SUCCESS) break; if(rc) { data->state.resume_from = 0; } else { curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; if(size < 0) { failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size); return CURLE_BAD_DOWNLOAD_RESUME; } data->state.resume_from = size; } } } if(data->set.ftp_append) /* Try to open for append, but create if nonexisting */ flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; else if(data->state.resume_from > 0) /* If we have restart position then open for append */ flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; else /* Clear file before writing (normal behaviour) */ flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; memset(&createattrs, 0, sizeof(createattrs)); createattrs.per = (word32)data->set.new_file_perms; sshc->handleSz = sizeof(sshc->handle); rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, flags, &createattrs, sshc->handle, &sshc->handleSz); if(rc == WS_FATAL_ERROR) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc == WS_SUCCESS) { infof(data, "wolfssh SFTP open succeeded!\n"); } else { failf(data, "wolfssh SFTP upload open failed: %d", rc); return CURLE_SSH; } state(conn, SSH_SFTP_DOWNLOAD_STAT); /* If we have a restart point then we need to seek to the correct position. */ if(data->state.resume_from > 0) { /* Let's read off the proper amount of bytes from the input. */ int seekerr = CURL_SEEKFUNC_OK; if(conn->seek_func) { Curl_set_in_callback(data, true); seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, SEEK_SET); Curl_set_in_callback(data, false); } if(seekerr != CURL_SEEKFUNC_OK) { curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { size_t readthisamountnow = (data->state.resume_from - passed > data->set.buffer_size) ? (size_t)data->set.buffer_size : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread; Curl_set_in_callback(data, true); actuallyread = data->state.fread_func(data->state.buffer, 1, readthisamountnow, data->state.in); Curl_set_in_callback(data, false); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Failed to read data"); return CURLE_FTP_COULDNT_USE_REST; } } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize > 0) { data->state.infilesize -= data->state.resume_from; data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } sshc->offset += data->state.resume_from; } if(data->state.infilesize > 0) { data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->sockfd = conn->writesockfd; if(result) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { /* store this original bitmask setup to use later on if we can't figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 sftp send function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ Curl_expire(data, 0, EXPIRE_RUN_NOW); state(conn, SSH_STOP); } break; } case SSH_SFTP_DOWNLOAD_INIT: sshc->handleSz = sizeof(sshc->handle); rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, WOLFSSH_FXF_READ, NULL, sshc->handle, &sshc->handleSz); if(rc == WS_FATAL_ERROR) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc == WS_SUCCESS) { infof(data, "wolfssh SFTP open succeeded!\n"); state(conn, SSH_SFTP_DOWNLOAD_STAT); return CURLE_OK; } failf(data, "wolfssh SFTP open failed: %d", rc); return CURLE_SSH; case SSH_SFTP_DOWNLOAD_STAT: { WS_SFTP_FILEATRB attrs; curl_off_t size; rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); if(rc == WS_FATAL_ERROR) rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc == WS_SUCCESS) { infof(data, "wolfssh STAT succeeded!\n"); } else { failf(data, "wolfssh SFTP open failed: %d", rc); data->req.size = -1; data->req.maxdownload = -1; Curl_pgrsSetDownloadSize(data, -1); return CURLE_SSH; } size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0]; data->req.size = size; data->req.maxdownload = size; Curl_pgrsSetDownloadSize(data, size); infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes\n", size); /* We cannot seek with wolfSSH so resuming and range requests are not possible */ if(conn->data->state.use_range || data->state.resume_from) { infof(data, "wolfSSH cannot do range/seek on SFTP\n"); return CURLE_BAD_DOWNLOAD_RESUME; } /* Setup the actual download */ if(data->req.size == 0) { /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); infof(data, "File already completely downloaded\n"); state(conn, SSH_STOP); break; } Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1); /* not set by Curl_setup_transfer to preserve keepon bits */ conn->writesockfd = conn->sockfd; /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ conn->cselect_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ state(conn, SSH_SFTP_CLOSE); sshc->actualcode = result; } else { state(conn, SSH_STOP); } break; } case SSH_SFTP_CLOSE: if(sshc->handleSz) rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, sshc->handleSz); else rc = WS_SUCCESS; /* directory listing */ if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(rc == WS_SUCCESS) { state(conn, SSH_STOP); return CURLE_OK; } failf(data, "wolfssh SFTP CLOSE failed: %d", rc); return CURLE_SSH; case SSH_SFTP_READDIR_INIT: Curl_pgrsSetDownloadSize(data, -1); if(data->set.opt_no_body) { state(conn, SSH_STOP); break; } state(conn, SSH_SFTP_READDIR); /* FALLTHROUGH */ case SSH_SFTP_READDIR: name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); if(!name) rc = wolfSSH_get_error(sshc->ssh_session); else rc = WS_SUCCESS; if(rc == WS_WANT_READ) { *block = TRUE; conn->waitfor = KEEP_RECV; return CURLE_OK; } else if(rc == WS_WANT_WRITE) { *block = TRUE; conn->waitfor = KEEP_SEND; return CURLE_OK; } else if(name && (rc == WS_SUCCESS)) { WS_SFTPNAME *origname = name; result = CURLE_OK; while(name) { char *line = aprintf("%s\n", data->set.ftp_list_only ? name->fName : name->lName); if(line == NULL) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } result = Curl_client_write(conn, CLIENTWRITE_BODY, line, strlen(line)); free(line); if(result) { sshc->actualcode = result; break; } name = name->next; } wolfSSH_SFTPNAME_list_free(origname); state(conn, SSH_STOP); return result; } failf(data, "wolfssh SFTP ls failed: %d", rc); return CURLE_SSH; case SSH_SFTP_SHUTDOWN: Curl_safefree(sshc->homedir); wolfSSH_free(sshc->ssh_session); wolfSSH_CTX_free(sshc->ctx); state(conn, SSH_STOP); return CURLE_OK; default: break; } } while(!rc && (sshc->state != SSH_STOP)); return result; } /* called repeatedly until done from multi.c */ static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; bool block; /* we store the status and use that to provide a ssh_getsock() implementation */ do { result = wssh_statemach_act(conn, &block); *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then try again */ if(*done) { DEBUGF(infof(conn->data, "wssh_statemach_act says DONE\n")); } } while(!result && !*done && !block); return result; } static CURLcode wscp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { (void)conn; (void)connected; (void)dophase_done; return CURLE_OK; } static CURLcode wsftp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ state(conn, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = wssh_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /* * The DO function is generic for both protocols. */ static CURLcode wssh_do(struct connectdata *conn, bool *done) { CURLcode result; bool connected = 0; struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ data->req.size = -1; /* make sure this is unknown at this point */ sshc->actualcode = CURLE_OK; /* reset error code */ sshc->secondCreateDirs = 0; /* reset the create dir attempt state variable */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); if(conn->handler->protocol & CURLPROTO_SCP) result = wscp_perform(conn, &connected, done); else result = wsftp_perform(conn, &connected, done); return result; } static CURLcode wssh_block_statemach(struct connectdata *conn, bool disconnect) { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; while((sshc->state != SSH_STOP) && !result) { bool block; timediff_t left = 1000; struct curltime now = Curl_now(); result = wssh_statemach_act(conn, &block); if(result) break; if(!disconnect) { if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; result = Curl_speedcheck(data, now); if(result) break; left = Curl_timeleft(data, NULL, FALSE); if(left < 0) { failf(data, "Operation timed out"); return CURLE_OPERATION_TIMEDOUT; } } if(!result) { int dir = conn->waitfor; curl_socket_t sock = conn->sock[FIRSTSOCKET]; curl_socket_t fd_read = CURL_SOCKET_BAD; curl_socket_t fd_write = CURL_SOCKET_BAD; if(dir == KEEP_RECV) fd_read = sock; else if(dir == KEEP_SEND) fd_write = sock; /* wait for the socket to become ready */ (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, left>1000?1000:left); /* ignore result */ } } return result; } /* generic done function for both SCP and SFTP called from their specific done functions */ static CURLcode wssh_done(struct connectdata *conn, CURLcode status) { CURLcode result = CURLE_OK; struct SSHPROTO *sftp_scp = conn->data->req.protop; if(!status) { /* run the state-machine */ result = wssh_block_statemach(conn, FALSE); } else result = status; if(sftp_scp) Curl_safefree(sftp_scp->path); if(Curl_pgrsDone(conn)) return CURLE_ABORTED_BY_CALLBACK; conn->data->req.keepon = 0; /* clear all bits */ return result; } #if 0 static CURLcode wscp_done(struct connectdata *conn, CURLcode code, bool premature) { CURLcode result = CURLE_OK; (void)conn; (void)code; (void)premature; return result; } static CURLcode wscp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; (void)conn; (void)dophase_done; return result; } static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection) { CURLcode result = CURLE_OK; (void)conn; (void)dead_connection; return result; } #endif static CURLcode wsftp_done(struct connectdata *conn, CURLcode code, bool premature) { (void)premature; state(conn, SSH_SFTP_CLOSE); return wssh_done(conn, code); } static CURLcode wsftp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = wssh_multi_statemach(conn, dophase_done); if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead) { CURLcode result = CURLE_OK; (void)dead; DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); result = wssh_block_statemach(conn, TRUE); } DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n")); return result; } static int wssh_getsock(struct connectdata *conn, curl_socket_t *sock) { return wssh_perform_getsock(conn, sock); } static int wssh_perform_getsock(const struct connectdata *conn, curl_socket_t *sock) { int bitmap = GETSOCK_BLANK; int dir = conn->waitfor; sock[0] = conn->sock[FIRSTSOCKET]; if(dir == KEEP_RECV) bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); else if(dir == KEEP_SEND) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; } size_t Curl_ssh_version(char *buffer, size_t buflen) { return msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); } CURLcode Curl_ssh_init(void) { if(WS_SUCCESS != wolfSSH_Init()) { DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); return CURLE_FAILED_INIT; } return CURLE_OK; } void Curl_ssh_cleanup(void) { } #endif /* USE_WOLFSSH */ davix-0.8.0/deps/curl/lib/vssh/ssh.h0000644000000000000000000002052414121063461015730 0ustar rootroot#ifndef HEADER_CURL_SSH_H #define HEADER_CURL_SSH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(HAVE_LIBSSH2_H) #include #include #elif defined(HAVE_LIBSSH_LIBSSH_H) #include #include #elif defined(USE_WOLFSSH) #include #include #endif /**************************************************************************** * SSH unique setup ***************************************************************************/ typedef enum { SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */ SSH_STOP = 0, /* do nothing state, stops the state machine */ SSH_INIT, /* First state in SSH-CONNECT */ SSH_S_STARTUP, /* Session startup */ SSH_HOSTKEY, /* verify hostkey */ SSH_AUTHLIST, SSH_AUTH_PKEY_INIT, SSH_AUTH_PKEY, SSH_AUTH_PASS_INIT, SSH_AUTH_PASS, SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */ SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */ SSH_AUTH_AGENT, /* attempt one key at a time */ SSH_AUTH_HOST_INIT, SSH_AUTH_HOST, SSH_AUTH_KEY_INIT, SSH_AUTH_KEY, SSH_AUTH_GSSAPI, SSH_AUTH_DONE, SSH_SFTP_INIT, SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */ SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */ SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */ SSH_SFTP_QUOTE, SSH_SFTP_NEXT_QUOTE, SSH_SFTP_QUOTE_STAT, SSH_SFTP_QUOTE_SETSTAT, SSH_SFTP_QUOTE_SYMLINK, SSH_SFTP_QUOTE_MKDIR, SSH_SFTP_QUOTE_RENAME, SSH_SFTP_QUOTE_RMDIR, SSH_SFTP_QUOTE_UNLINK, SSH_SFTP_QUOTE_STATVFS, SSH_SFTP_GETINFO, SSH_SFTP_FILETIME, SSH_SFTP_TRANS_INIT, SSH_SFTP_UPLOAD_INIT, SSH_SFTP_CREATE_DIRS_INIT, SSH_SFTP_CREATE_DIRS, SSH_SFTP_CREATE_DIRS_MKDIR, SSH_SFTP_READDIR_INIT, SSH_SFTP_READDIR, SSH_SFTP_READDIR_LINK, SSH_SFTP_READDIR_BOTTOM, SSH_SFTP_READDIR_DONE, SSH_SFTP_DOWNLOAD_INIT, SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */ SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */ SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */ SSH_SCP_TRANS_INIT, /* First state in SCP-DO */ SSH_SCP_UPLOAD_INIT, SSH_SCP_DOWNLOAD_INIT, SSH_SCP_DOWNLOAD, SSH_SCP_DONE, SSH_SCP_SEND_EOF, SSH_SCP_WAIT_EOF, SSH_SCP_WAIT_CLOSE, SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */ SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */ SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */ SSH_QUIT, SSH_LAST /* never used */ } sshstate; /* this struct is used in the HandleData struct which is part of the Curl_easy, which means this is used on a per-easy handle basis. Everything that is strictly related to a connection is banned from this struct. */ struct SSHPROTO { char *path; /* the path we operate on */ }; /* ssh_conn is used for struct connection-oriented data in the connectdata struct */ struct ssh_conn { const char *authlist; /* List of auth. methods, managed by libssh2 */ /* common */ const char *passphrase; /* pass-phrase to use */ char *rsa_pub; /* path name */ char *rsa; /* path name */ bool authed; /* the connection has been authenticated fine */ sshstate state; /* always use ssh.c:state() to change state! */ sshstate nextstate; /* the state to goto after stopping */ CURLcode actualcode; /* the actual error code */ struct curl_slist *quote_item; /* for the quote option */ char *quote_path1; /* two generic pointers for the QUOTE stuff */ char *quote_path2; bool acceptfail; /* used by the SFTP_QUOTE (continue if quote command fails) */ char *homedir; /* when doing SFTP we figure out home dir in the connect phase */ size_t readdir_len, readdir_totalLen, readdir_currLen; char *readdir_line; char *readdir_linkPath; /* end of READDIR stuff */ int secondCreateDirs; /* counter use by the code to see if the second attempt has been made to change to/create a directory */ char *slash_pos; /* used by the SFTP_CREATE_DIRS state */ int orig_waitfor; /* default READ/WRITE bits wait for */ #if defined(USE_LIBSSH) /* our variables */ unsigned kbd_state; /* 0 or 1 */ ssh_key privkey; ssh_key pubkey; int auth_methods; ssh_session ssh_session; ssh_scp scp_session; sftp_session sftp_session; sftp_file sftp_file; sftp_dir sftp_dir; unsigned sftp_recv_state; /* 0 or 1 */ int sftp_file_index; /* for async read */ sftp_attributes readdir_attrs; /* used by the SFTP readdir actions */ sftp_attributes readdir_link_attrs; /* used by the SFTP readdir actions */ sftp_attributes quote_attrs; /* used by the SFTP_QUOTE state */ const char *readdir_filename; /* points within readdir_attrs */ const char *readdir_longentry; char *readdir_tmp; #elif defined(USE_LIBSSH2) char *readdir_filename; char *readdir_longentry; LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */ /* Here's a set of struct members used by the SFTP_READDIR state */ LIBSSH2_SFTP_ATTRIBUTES readdir_attrs; LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ LIBSSH2_SFTP *sftp_session; /* SFTP handle */ LIBSSH2_SFTP_HANDLE *sftp_handle; #ifdef HAVE_LIBSSH2_AGENT_API LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */ struct libssh2_agent_publickey *sshagent_identity, *sshagent_prev_identity; #endif /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h header */ #ifdef HAVE_LIBSSH2_KNOWNHOST_API LIBSSH2_KNOWNHOSTS *kh; #endif #elif defined(USE_WOLFSSH) WOLFSSH *ssh_session; WOLFSSH_CTX *ctx; word32 handleSz; byte handle[WOLFSSH_MAX_HANDLE]; curl_off_t offset; #endif /* USE_LIBSSH */ }; #if defined(USE_LIBSSH) #define CURL_LIBSSH_VERSION ssh_version(0) #elif defined(USE_LIBSSH2) /* Feature detection based on version numbers to better work with non-configure platforms */ #if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000) # error "SCP/SFTP protocols require libssh2 0.16 or later" #endif #if LIBSSH2_VERSION_NUM >= 0x010000 #define HAVE_LIBSSH2_SFTP_SEEK64 1 #endif #if LIBSSH2_VERSION_NUM >= 0x010100 #define HAVE_LIBSSH2_VERSION 1 #endif #if LIBSSH2_VERSION_NUM >= 0x010205 #define HAVE_LIBSSH2_INIT 1 #define HAVE_LIBSSH2_EXIT 1 #endif #if LIBSSH2_VERSION_NUM >= 0x010206 #define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1 #define HAVE_LIBSSH2_SCP_SEND64 1 #endif #if LIBSSH2_VERSION_NUM >= 0x010208 #define HAVE_LIBSSH2_SESSION_HANDSHAKE 1 #endif #ifdef HAVE_LIBSSH2_VERSION /* get it run-time if possible */ #define CURL_LIBSSH2_VERSION libssh2_version(0) #else /* use build-time if run-time not possible */ #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION #endif #endif /* USE_LIBSSH2 */ #ifdef USE_SSH extern const struct Curl_handler Curl_handler_scp; extern const struct Curl_handler Curl_handler_sftp; /* generic SSH backend functions */ CURLcode Curl_ssh_init(void); void Curl_ssh_cleanup(void); size_t Curl_ssh_version(char *buffer, size_t buflen); #else /* for non-SSH builds */ #define Curl_ssh_cleanup() #endif #endif /* HEADER_CURL_SSH_H */ davix-0.8.0/deps/curl/lib/setopt.h0000644000000000000000000000234514121063461015467 0ustar rootroot#ifndef HEADER_CURL_SETOPT_H #define HEADER_CURL_SETOPT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ CURLcode Curl_setstropt(char **charp, const char *s); CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg); #endif /* HEADER_CURL_SETOPT_H */ davix-0.8.0/deps/curl/lib/curl_ctype.c0000644000000000000000000000700314121063461016311 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DOES_CONVERSIONS #undef _U #define _U (1<<0) /* upper case */ #undef _L #define _L (1<<1) /* lower case */ #undef _N #define _N (1<<2) /* decimal numerical digit */ #undef _S #define _S (1<<3) /* space */ #undef _P #define _P (1<<4) /* punctuation */ #undef _C #define _C (1<<5) /* control */ #undef _X #define _X (1<<6) /* hexadecimal letter */ #undef _B #define _B (1<<7) /* blank */ static const unsigned char ascii[128] = { _C, _C, _C, _C, _C, _C, _C, _C, _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _S|_B, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _N, _N, _N, _N, _N, _N, _N, _N, _N, _N, _P, _P, _P, _P, _P, _P, _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _P, _P, _P, _P, _P, _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _P, _P, _P, _P, _C }; int Curl_isspace(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & _S); } int Curl_isdigit(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & _N); } int Curl_isalnum(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_N|_U|_L)); } int Curl_isxdigit(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_N|_X)); } int Curl_isgraph(int c) { if((c < 0) || (c >= 0x80) || (c == ' ')) return FALSE; return (ascii[c] & (_N|_X|_U|_L|_P|_S)); } int Curl_isprint(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_N|_X|_U|_L|_P|_S)); } int Curl_isalpha(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_U|_L)); } int Curl_isupper(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_U)); } int Curl_islower(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_L)); } int Curl_iscntrl(int c) { if((c < 0) || (c >= 0x80)) return FALSE; return (ascii[c] & (_C)); } #endif /* !CURL_DOES_CONVERSIONS */ davix-0.8.0/deps/curl/lib/mime.h0000644000000000000000000001543214121063461015101 0ustar rootroot#ifndef HEADER_CURL_MIME_H #define HEADER_CURL_MIME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */ #define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */ #define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */ /* Part flags. */ #define MIME_USERHEADERS_OWNER (1 << 0) #define MIME_BODY_ONLY (1 << 1) #define FILE_CONTENTTYPE_DEFAULT "application/octet-stream" #define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed" #define DISPOSITION_DEFAULT "attachment" /* Part source kinds. */ enum mimekind { MIMEKIND_NONE = 0, /* Part not set. */ MIMEKIND_DATA, /* Allocated mime data. */ MIMEKIND_FILE, /* Data from file. */ MIMEKIND_CALLBACK, /* Data from `read' callback. */ MIMEKIND_MULTIPART, /* Data is a mime subpart. */ MIMEKIND_LAST }; /* Readback state tokens. */ enum mimestate { MIMESTATE_BEGIN, /* Readback has not yet started. */ MIMESTATE_CURLHEADERS, /* In curl-generated headers. */ MIMESTATE_USERHEADERS, /* In caller's supplied headers. */ MIMESTATE_EOH, /* End of headers. */ MIMESTATE_BODY, /* Placeholder. */ MIMESTATE_BOUNDARY1, /* In boundary prefix. */ MIMESTATE_BOUNDARY2, /* In boundary. */ MIMESTATE_CONTENT, /* In content. */ MIMESTATE_END, /* End of part reached. */ MIMESTATE_LAST }; /* Mime headers strategies. */ enum mimestrategy { MIMESTRATEGY_MAIL, /* Mime mail. */ MIMESTRATEGY_FORM, /* HTTP post form. */ MIMESTRATEGY_LAST }; /* Content transfer encoder. */ typedef struct { const char * name; /* Encoding name. */ size_t (*encodefunc)(char *buffer, size_t size, bool ateof, curl_mimepart *part); /* Encoded read. */ curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */ } mime_encoder; /* Content transfer encoder state. */ typedef struct { size_t pos; /* Position on output line. */ size_t bufbeg; /* Next data index in input buffer. */ size_t bufend; /* First unused byte index in input buffer. */ char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */ } mime_encoder_state; /* Mime readback state. */ typedef struct { enum mimestate state; /* Current state token. */ void *ptr; /* State-dependent pointer. */ size_t offset; /* State-dependent offset. */ } mime_state; /* minimum buffer size for the boundary string */ #define MIME_BOUNDARY_LEN (24 + MIME_RAND_BOUNDARY_CHARS + 1) /* A mime multipart. */ struct curl_mime_s { struct Curl_easy *easy; /* The associated easy handle. */ curl_mimepart *parent; /* Parent part. */ curl_mimepart *firstpart; /* First part. */ curl_mimepart *lastpart; /* Last part. */ char boundary[MIME_BOUNDARY_LEN]; /* The part boundary. */ mime_state state; /* Current readback state. */ }; /* A mime part. */ struct curl_mimepart_s { struct Curl_easy *easy; /* The associated easy handle. */ curl_mime *parent; /* Parent mime structure. */ curl_mimepart *nextpart; /* Forward linked list. */ enum mimekind kind; /* The part kind. */ char *data; /* Memory data or file name. */ curl_read_callback readfunc; /* Read function. */ curl_seek_callback seekfunc; /* Seek function. */ curl_free_callback freefunc; /* Argument free function. */ void *arg; /* Argument to callback functions. */ FILE *fp; /* File pointer. */ struct curl_slist *curlheaders; /* Part headers. */ struct curl_slist *userheaders; /* Part headers. */ char *mimetype; /* Part mime type. */ char *filename; /* Remote file name. */ char *name; /* Data name. */ curl_off_t datasize; /* Expected data size. */ unsigned int flags; /* Flags. */ mime_state state; /* Current readback state. */ const mime_encoder *encoder; /* Content data encoder. */ mime_encoder_state encstate; /* Data encoder state. */ }; CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) /* Prototypes. */ void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy); void Curl_mime_cleanpart(curl_mimepart *part); CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src); CURLcode Curl_mime_set_subparts(curl_mimepart *part, curl_mime *subparts, int take_ownership); CURLcode Curl_mime_prepare_headers(curl_mimepart *part, const char *contenttype, const char *disposition, enum mimestrategy strategy); curl_off_t Curl_mime_size(curl_mimepart *part); size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream); CURLcode Curl_mime_rewind(curl_mimepart *part); const char *Curl_mime_contenttype(const char *filename); #else /* if disabled */ #define Curl_mime_initpart(x,y) #define Curl_mime_cleanpart(x) #define Curl_mime_duppart(x,y) CURLE_OK /* Nothing to duplicate. Succeed */ #define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN #define Curl_mime_prepare_headers(a,b,c,d) CURLE_NOT_BUILT_IN #define Curl_mime_size(x) (curl_off_t) -1 #define Curl_mime_read NULL #define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN) #endif #endif /* HEADER_CURL_MIME_H */ davix-0.8.0/deps/curl/lib/curl_ntlm_wb.h0000644000000000000000000000313614121063461016637 0ustar rootroot#ifndef HEADER_CURL_NTLM_WB_H #define HEADER_CURL_NTLM_WB_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) /* this is for ntlm header input */ CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy, const char *header); /* this is for creating ntlm header output */ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy); void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn); #endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ #endif /* HEADER_CURL_NTLM_WB_H */ davix-0.8.0/deps/curl/lib/curl_addrinfo.h0000644000000000000000000000625614121063461016771 0ustar rootroot#ifndef HEADER_CURL_ADDRINFO_H #define HEADER_CURL_ADDRINFO_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef __VMS # include # include # include #endif /* * Curl_addrinfo is our internal struct definition that we use to allow * consistent internal handling of this data. We use this even when the * system provides an addrinfo structure definition. And we use this for * all sorts of IPv4 and IPV6 builds. */ struct Curl_addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */ char *ai_canonname; struct sockaddr *ai_addr; struct Curl_addrinfo *ai_next; }; typedef struct Curl_addrinfo Curl_addrinfo; void Curl_freeaddrinfo(Curl_addrinfo *cahead); #ifdef HAVE_GETADDRINFO int Curl_getaddrinfo_ex(const char *nodename, const char *servname, const struct addrinfo *hints, Curl_addrinfo **result); #endif Curl_addrinfo * Curl_he2ai(const struct hostent *he, int port); Curl_addrinfo * Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); #ifdef USE_UNIX_SOCKETS Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract); #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ defined(HAVE_FREEADDRINFO) void curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source); #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) int curl_dbg_getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result, int line, const char *source); #endif #ifdef HAVE_GETADDRINFO #ifdef USE_RESOLVE_ON_IPS void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port); #else #define Curl_addrinfo_set_port(x,y) #endif #endif #endif /* HEADER_CURL_ADDRINFO_H */ davix-0.8.0/deps/curl/lib/curl_get_line.c0000644000000000000000000000332514121063461016756 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "curl_get_line.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * get_line() makes sure to only return complete whole lines that fit in 'len' * bytes and end with a newline. */ char *Curl_get_line(char *buf, int len, FILE *input) { bool partial = FALSE; while(1) { char *b = fgets(buf, len, input); if(b) { size_t rlen = strlen(b); if(rlen && (b[rlen-1] == '\n')) { if(partial) { partial = FALSE; continue; } return b; } /* read a partial, discard the next piece that ends with newline */ partial = TRUE; } else break; } return NULL; } davix-0.8.0/deps/curl/lib/altsvc.h0000644000000000000000000000532614121063461015447 0ustar rootroot#ifndef HEADER_CURL_ALTSVC_H #define HEADER_CURL_ALTSVC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC) #include #include "llist.h" enum alpnid { ALPN_none = 0, ALPN_h1 = CURLALTSVC_H1, ALPN_h2 = CURLALTSVC_H2, ALPN_h3 = CURLALTSVC_H3 }; struct althost { char *host; unsigned short port; enum alpnid alpnid; }; struct altsvc { struct althost src; struct althost dst; time_t expires; bool persist; int prio; struct curl_llist_element node; }; struct altsvcinfo { char *filename; struct curl_llist list; /* list of entries */ size_t num; /* number of alt-svc entries */ long flags; /* the publicly set bitmask */ }; const char *Curl_alpnid2str(enum alpnid id); struct altsvcinfo *Curl_altsvc_init(void); CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file); CURLcode Curl_altsvc_save(struct Curl_easy *data, struct altsvcinfo *asi, const char *file); CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl); void Curl_altsvc_cleanup(struct altsvcinfo *altsvc); CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvcinfo *altsvc, const char *value, enum alpnid srcalpn, const char *srchost, unsigned short srcport); bool Curl_altsvc_lookup(struct altsvcinfo *asi, enum alpnid srcalpnid, const char *srchost, int srcport, struct altsvc **dstentry, const int versions); /* CURLALTSVC_H* bits */ #else /* disabled */ #define Curl_altsvc_save(a,b,c) #endif /* CURL_DISABLE_HTTP || USE_ALTSVC */ #endif /* HEADER_CURL_ALTSVC_H */ davix-0.8.0/deps/curl/lib/asyn.h0000644000000000000000000001506414121063461015125 0ustar rootroot#ifndef HEADER_CURL_ASYN_H #define HEADER_CURL_ASYN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "curl_addrinfo.h" struct addrinfo; struct hostent; struct Curl_easy; struct connectdata; struct Curl_dns_entry; /* * This header defines all functions in the internal asynch resolver interface. * All asynch resolvers need to provide these functions. * asyn-ares.c and asyn-thread.c are the current implementations of asynch * resolver backends. */ /* * Curl_resolver_global_init() * * Called from curl_global_init() to initialize global resolver environment. * Returning anything else than CURLE_OK fails curl_global_init(). */ int Curl_resolver_global_init(void); /* * Curl_resolver_global_cleanup() * Called from curl_global_cleanup() to destroy global resolver environment. */ void Curl_resolver_global_cleanup(void); /* * Curl_resolver_init() * Called from curl_easy_init() -> Curl_open() to initialize resolver * URL-state specific environment ('resolver' member of the UrlState * structure). Should fill the passed pointer by the initialized handler. * Returning anything else than CURLE_OK fails curl_easy_init() with the * correspondent code. */ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver); /* * Curl_resolver_cleanup() * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver * URL-state specific environment ('resolver' member of the UrlState * structure). Should destroy the handler and free all resources connected to * it. */ void Curl_resolver_cleanup(void *resolver); /* * Curl_resolver_duphandle() * Called from curl_easy_duphandle() to duplicate resolver URL-state specific * environment ('resolver' member of the UrlState structure). Should * duplicate the 'from' handle and pass the resulting handle to the 'to' * pointer. Returning anything else than CURLE_OK causes failed * curl_easy_duphandle() call. */ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from); /* * Curl_resolver_cancel(). * * It is called from inside other functions to cancel currently performing * resolver request. Should also free any temporary resources allocated to * perform a request. This never waits for resolver threads to complete. * * It is safe to call this when conn is in any state. */ void Curl_resolver_cancel(struct connectdata *conn); /* * Curl_resolver_kill(). * * This acts like Curl_resolver_cancel() except it will block until any threads * associated with the resolver are complete. This never blocks for resolvers * that do not use threads. This is intended to be the "last chance" function * that cleans up an in-progress resolver completely (before its owner is about * to die). * * It is safe to call this when conn is in any state. */ void Curl_resolver_kill(struct connectdata *conn); /* Curl_resolver_getsock() * * This function is called from the multi_getsock() function. 'sock' is a * pointer to an array to hold the file descriptors, with 'numsock' being the * size of that array (in number of entries). This function is supposed to * return bitmask indicating what file descriptors (referring to array indexes * in the 'sock' array) to wait for, read/write. */ int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock); /* * Curl_resolver_is_resolved() * * Called repeatedly to check if a previous name resolve request has * completed. It should also make sure to time-out if the operation seems to * take too long. * * Returns normal CURLcode errors. */ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns); /* * Curl_resolver_wait_resolv() * * Waits for a resolve to finish. This function should be avoided since using * this risk getting the multi interface to "hang". * * If 'entry' is non-NULL, make it point to the resolved dns entry * * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. */ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **dnsentry); /* * Curl_resolver_getaddrinfo() - when using this resolver * * Returns name information about the given hostname and port number. If * successful, the 'hostent' is returned and the forth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. * * Each resolver backend must of course make sure to return data in the * correct format to comply with this. */ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp); #ifndef CURLRES_ASYNCH /* convert these functions if an asynch resolver isn't used */ #define Curl_resolver_cancel(x) Curl_nop_stmt #define Curl_resolver_kill(x) Curl_nop_stmt #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_getsock(x,y,z) 0 #define Curl_resolver_duphandle(x,y,z) CURLE_OK #define Curl_resolver_init(x,y) CURLE_OK #define Curl_resolver_global_init() CURLE_OK #define Curl_resolver_global_cleanup() Curl_nop_stmt #define Curl_resolver_cleanup(x) Curl_nop_stmt #endif #ifdef CURLRES_ASYNCH #define Curl_resolver_asynch() 1 #else #define Curl_resolver_asynch() 0 #endif /********** end of generic resolver interface functions *****************/ #endif /* HEADER_CURL_ASYN_H */ davix-0.8.0/deps/curl/lib/setopt.c0000644000000000000000000024264314121063461015471 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_LINUX_TCP_H #include #endif #include "urldata.h" #include "url.h" #include "progress.h" #include "content_encoding.h" #include "strcase.h" #include "share.h" #include "vtls/vtls.h" #include "warnless.h" #include "sendf.h" #include "http2.h" #include "setopt.h" #include "multiif.h" #include "altsvc.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" CURLcode Curl_setstropt(char **charp, const char *s) { /* Release the previous storage at `charp' and replace by a dynamic storage copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ Curl_safefree(*charp); if(s) { char *str = strdup(s); if(str) { size_t len = strlen(str); if(len > CURL_MAX_INPUT_LENGTH) { free(str); return CURLE_BAD_FUNCTION_ARGUMENT; } } if(!str) return CURLE_OUT_OF_MEMORY; *charp = str; } return CURLE_OK; } static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) { CURLcode result = CURLE_OK; char *user = NULL; char *passwd = NULL; /* Parse the login details if specified. It not then we treat NULL as a hint to clear the existing data */ if(option) { result = Curl_parse_login_details(option, strlen(option), (userp ? &user : NULL), (passwdp ? &passwd : NULL), NULL); } if(!result) { /* Store the username part of option if required */ if(userp) { if(!user && option && option[0] == ':') { /* Allocate an empty string instead of returning NULL as user name */ user = strdup(""); if(!user) result = CURLE_OUT_OF_MEMORY; } Curl_safefree(*userp); *userp = user; } /* Store the password part of option if required */ if(passwdp) { Curl_safefree(*passwdp); *passwdp = passwd; } } return result; } #define C_SSLVERSION_VALUE(x) (x & 0xffff) #define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) /* * Do not make Curl_vsetopt() static: it is called from * packages/OS400/ccsidcurl.c. */ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) { char *argptr; CURLcode result = CURLE_OK; long arg; unsigned long uarg; curl_off_t bigsize; switch(option) { case CURLOPT_DNS_CACHE_TIMEOUT: arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.dns_cache_timeout = arg; break; case CURLOPT_DNS_USE_GLOBAL_CACHE: /* deprecated */ break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection for proxy */ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_TLS13_CIPHERS: if(Curl_ssl_tls13_ciphersuites()) { /* set preferred list of TLS 1.3 cipher suites */ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_ORIG], va_arg(param, char *)); } else return CURLE_NOT_BUILT_IN; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLS13_CIPHERS: if(Curl_ssl_tls13_ciphersuites()) { /* set preferred list of TLS 1.3 cipher suites for proxy */ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY], va_arg(param, char *)); } else return CURLE_NOT_BUILT_IN; break; #endif case CURLOPT_RANDOM_FILE: /* * This is the path name to a file that contains random data to seed * the random SSL stuff with. The file is only used for reading. */ result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE], va_arg(param, char *)); break; case CURLOPT_EGDSOCKET: /* * The Entropy Gathering Daemon socket pathname */ result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET], va_arg(param, char *)); break; case CURLOPT_MAXCONNECTS: /* * Set the absolute number of maximum simultaneous alive connection that * libcurl is allowed to have. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxconnects = arg; break; case CURLOPT_FORBID_REUSE: /* * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else data->progress.flags &= ~PGRS_HIDE; break; case CURLOPT_NOBODY: /* * Do not include the body part in the output data stream. */ data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FAILONERROR: /* * Don't output the >=400 error code HTML-page, but instead only * return error. */ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_KEEP_SENDING_ON_ERROR: data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: /* * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; data->set.opt_no_body = FALSE; /* this is implied */ } else /* In HTTP, the opposite of upload is GET (unless NOBODY is true as then this can be changed to HEAD later on) */ data->set.httpreq = HTTPREQ_GET; break; case CURLOPT_REQUEST_TARGET: result = Curl_setstropt(&data->set.str[STRING_TARGET], va_arg(param, char *)); break; case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SERVER_RESPONSE_TIMEOUT: /* * Option that specifies how quickly an server response must be obtained * before it is considered failure. For pingpong protocols. */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.server_response_timeout = arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; #ifndef CURL_DISABLE_TFTP case CURLOPT_TFTP_NO_OPTIONS: /* * Option that prevents libcurl from sending TFTP option requests to the * server. */ data->set.tftp_no_options = va_arg(param, long) != 0; break; case CURLOPT_TFTP_BLKSIZE: /* * TFTP option that specifies the block size to use for data transmission. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.tftp_blksize = arg; break; #endif #ifndef CURL_DISABLE_NETRC case CURLOPT_NETRC: /* * Parse the $HOME/.netrc file */ arg = va_arg(param, long); if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.use_netrc = (enum CURL_NETRC_OPTION)arg; break; case CURLOPT_NETRC_FILE: /* * Use this file instead of the $HOME/.netrc file */ result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE], va_arg(param, char *)); break; #endif case CURLOPT_TRANSFERTEXT: /* * This option was previously named 'FTPASCII'. Renamed to work with * more protocols than merely FTP. * * Transfer using ASCII (instead of BINARY). */ data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TIMECONDITION: /* * Set HTTP time condition. This must be one of the defines in the * curl/curl.h header file. */ arg = va_arg(param, long); if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.timecondition = (curl_TimeCond)arg; break; case CURLOPT_TIMEVALUE: /* * This is the value to compare with the remote document with the * method set with CURLOPT_TIMECONDITION */ data->set.timevalue = (time_t)va_arg(param, long); break; case CURLOPT_TIMEVALUE_LARGE: /* * This is the value to compare with the remote document with the * method set with CURLOPT_TIMECONDITION */ data->set.timevalue = (time_t)va_arg(param, curl_off_t); break; case CURLOPT_SSLVERSION: case CURLOPT_PROXY_SSLVERSION: /* * Set explicit SSL version to try to connect with, as some SSL * implementations are lame. */ #ifdef USE_SSL { long version, version_max; struct ssl_primary_config *primary = (option == CURLOPT_SSLVERSION ? &data->set.ssl.primary : &data->set.proxy_ssl.primary); arg = va_arg(param, long); version = C_SSLVERSION_VALUE(arg); version_max = C_SSLVERSION_MAX_VALUE(arg); if(version < CURL_SSLVERSION_DEFAULT || version >= CURL_SSLVERSION_LAST || version_max < CURL_SSLVERSION_MAX_NONE || version_max >= CURL_SSLVERSION_MAX_LAST) return CURLE_BAD_FUNCTION_ARGUMENT; primary->version = version; primary->version_max = version_max; } #else result = CURLE_UNKNOWN_OPTION; #endif break; #ifndef CURL_DISABLE_HTTP case CURLOPT_AUTOREFERER: /* * Switch on automatic referer that gets set if curl follows locations. */ data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_ACCEPT_ENCODING: /* * String to use at the value of Accept-Encoding header. * * If the encoding is set to "" we use an Accept-Encoding header that * encompasses all the encodings we support. * If the encoding is set to NULL we don't send an Accept-Encoding header * and ignore an received Content-Encoding header. * */ argptr = va_arg(param, char *); if(argptr && !*argptr) { argptr = Curl_all_content_encodings(); if(!argptr) result = CURLE_OUT_OF_MEMORY; else { result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr); free(argptr); } } else result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr); break; case CURLOPT_TRANSFER_ENCODING: data->set.http_transfer_encoding = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: /* * Send authentication (user+password) when following locations, even when * hostname changed. */ data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_MAXREDIRS: /* * The maximum amount of hops you allow curl to follow Location: * headers. This should mostly be used to detect never-ending loops. */ arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxredirs = arg; break; case CURLOPT_POSTREDIR: /* * Set the behaviour of POST when redirecting * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302 * CURL_REDIR_POST_301 - POST is kept as POST after 301 * CURL_REDIR_POST_302 - POST is kept as POST after 302 * CURL_REDIR_POST_303 - POST is kept as POST after 303 * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 * other - POST is kept as POST after 301 and 302 */ arg = va_arg(param, long); if(arg < CURL_REDIR_GET_ALL) /* no return error on too high numbers since the bitmask could be extended in a future */ return CURLE_BAD_FUNCTION_ARGUMENT; data->set.keep_post = arg & CURL_REDIR_POST_ALL; break; case CURLOPT_POST: /* Does this option serve a purpose anymore? Yes it does, when CURLOPT_POSTFIELDS isn't used and the POST data is read off the callback! */ if(va_arg(param, long)) { data->set.httpreq = HTTPREQ_POST; data->set.opt_no_body = FALSE; /* this is implied */ } else data->set.httpreq = HTTPREQ_GET; break; case CURLOPT_COPYPOSTFIELDS: /* * A string with POST data. Makes curl HTTP POST. Even if it is NULL. * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to * CURLOPT_COPYPOSTFIELDS and not altered later. */ argptr = va_arg(param, char *); if(!argptr || data->set.postfieldsize == -1) result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr); else { /* * Check that requested length does not overflow the size_t type. */ if((data->set.postfieldsize < 0) || ((sizeof(curl_off_t) != sizeof(size_t)) && (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) result = CURLE_OUT_OF_MEMORY; else { char *p; (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); /* Allocate even when size == 0. This satisfies the need of possible later address compare to detect the COPYPOSTFIELDS mode, and to mark that postfields is used rather than read function or form data. */ p = malloc((size_t)(data->set.postfieldsize? data->set.postfieldsize:1)); if(!p) result = CURLE_OUT_OF_MEMORY; else { if(data->set.postfieldsize) memcpy(p, argptr, (size_t)data->set.postfieldsize); data->set.str[STRING_COPYPOSTFIELDS] = p; } } } data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; data->set.httpreq = HTTPREQ_POST; break; case CURLOPT_POSTFIELDS: /* * Like above, but use static data instead of copying it. */ data->set.postfields = va_arg(param, void *); /* Release old copied data. */ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); data->set.httpreq = HTTPREQ_POST; break; case CURLOPT_POSTFIELDSIZE: /* * The size of the POSTFIELD data to prevent libcurl to do strlen() to * figure it out. Enables binary posts. */ bigsize = va_arg(param, long); if(bigsize < -1) return CURLE_BAD_FUNCTION_ARGUMENT; if(data->set.postfieldsize < bigsize && data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); data->set.postfields = NULL; } data->set.postfieldsize = bigsize; break; case CURLOPT_POSTFIELDSIZE_LARGE: /* * The size of the POSTFIELD data to prevent libcurl to do strlen() to * figure it out. Enables binary posts. */ bigsize = va_arg(param, curl_off_t); if(bigsize < -1) return CURLE_BAD_FUNCTION_ARGUMENT; if(data->set.postfieldsize < bigsize && data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); data->set.postfields = NULL; } data->set.postfieldsize = bigsize; break; case CURLOPT_HTTPPOST: /* * Set to make us do HTTP POST */ data->set.httppost = va_arg(param, struct curl_httppost *); data->set.httpreq = HTTPREQ_POST_FORM; data->set.opt_no_body = FALSE; /* this is implied */ break; #endif /* CURL_DISABLE_HTTP */ case CURLOPT_MIMEPOST: /* * Set to make us do MIME/form POST */ result = Curl_mime_set_subparts(&data->set.mimepost, va_arg(param, curl_mime *), FALSE); if(!result) { data->set.httpreq = HTTPREQ_POST_MIME; data->set.opt_no_body = FALSE; /* this is implied */ } break; case CURLOPT_REFERER: /* * String to set in the HTTP Referer: field. */ if(data->change.referer_alloc) { Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], va_arg(param, char *)); data->change.referer = data->set.str[STRING_SET_REFERER]; break; case CURLOPT_USERAGENT: /* * String to use in the HTTP User-Agent field */ result = Curl_setstropt(&data->set.str[STRING_USERAGENT], va_arg(param, char *)); break; case CURLOPT_HTTPHEADER: /* * Set a list with HTTP headers to use (or replace internals with) */ data->set.headers = va_arg(param, struct curl_slist *); break; #ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYHEADER: /* * Set a list with proxy headers to use (or replace internals with) * * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a * long time we remain doing it this way until CURLOPT_PROXYHEADER is * used. As soon as this option has been used, if set to anything but * NULL, custom headers for proxies are only picked from this list. * * Set this option to NULL to restore the previous behavior. */ data->set.proxyheaders = va_arg(param, struct curl_slist *); break; #endif case CURLOPT_HEADEROPT: /* * Set header option. */ arg = va_arg(param, long); data->set.sep_headers = (bool)((arg & CURLHEADER_SEPARATE)? TRUE: FALSE); break; case CURLOPT_HTTP200ALIASES: /* * Set a list of aliases for HTTP 200 in response header */ data->set.http200aliases = va_arg(param, struct curl_slist *); break; #if !defined(CURL_DISABLE_COOKIES) case CURLOPT_COOKIE: /* * Cookie string to send to the remote server in the request. */ result = Curl_setstropt(&data->set.str[STRING_COOKIE], va_arg(param, char *)); break; case CURLOPT_COOKIEFILE: /* * Set cookie file to read and parse. Can be used multiple times. */ argptr = (char *)va_arg(param, void *); if(argptr) { struct curl_slist *cl; /* append the cookie file name to the list of file names, and deal with them later */ cl = curl_slist_append(data->change.cookielist, argptr); if(!cl) { curl_slist_free_all(data->change.cookielist); data->change.cookielist = NULL; return CURLE_OUT_OF_MEMORY; } data->change.cookielist = cl; /* store the list for later use */ } break; case CURLOPT_COOKIEJAR: /* * Set cookie file name to dump all cookies to when we're done. */ { struct CookieInfo *newcookies; result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], va_arg(param, char *)); /* * Activate the cookie parser. This may or may not already * have been made. */ newcookies = Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession); if(!newcookies) result = CURLE_OUT_OF_MEMORY; data->cookies = newcookies; } break; case CURLOPT_COOKIESESSION: /* * Set this option to TRUE to start a new "cookie session". It will * prevent the forthcoming read-cookies-from-file actions to accept * cookies that are marked as being session cookies, as they belong to a * previous session. * * In the original Netscape cookie spec, "session cookies" are cookies * with no expire date set. RFC2109 describes the same action if no * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds * a 'Discard' action that can enforce the discard even for cookies that * have a Max-Age. * * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_COOKIELIST: argptr = va_arg(param, char *); if(argptr == NULL) break; if(strcasecompare(argptr, "ALL")) { /* clear all cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } else if(strcasecompare(argptr, "SESS")) { /* clear session cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } else if(strcasecompare(argptr, "FLUSH")) { /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, FALSE); } else if(strcasecompare(argptr, "RELOAD")) { /* reload cookies from file */ Curl_cookie_loadfiles(data); break; } else { if(!data->cookies) /* if cookie engine was not running, activate it */ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); argptr = strdup(argptr); if(!argptr || !data->cookies) { result = CURLE_OUT_OF_MEMORY; free(argptr); } else { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); if(checkprefix("Set-Cookie:", argptr)) /* HTTP Header format line */ Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL, NULL, TRUE); else /* Netscape format line */ Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL, NULL, TRUE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); free(argptr); } } break; #endif /* !CURL_DISABLE_COOKIES */ case CURLOPT_HTTPGET: /* * Set to force us do HTTP GET */ if(va_arg(param, long)) { data->set.httpreq = HTTPREQ_GET; data->set.upload = FALSE; /* switch off upload */ data->set.opt_no_body = FALSE; /* this is implied */ } break; case CURLOPT_HTTP_VERSION: /* * This sets a requested HTTP version to be used. The value is one of * the listed enums in curl/curl.h. */ arg = va_arg(param, long); if(arg < CURL_HTTP_VERSION_NONE) return CURLE_BAD_FUNCTION_ARGUMENT; #ifdef ENABLE_QUIC if(arg == CURL_HTTP_VERSION_3) ; else #endif #ifndef USE_NGHTTP2 if(arg >= CURL_HTTP_VERSION_2) return CURLE_UNSUPPORTED_PROTOCOL; #else if(arg >= CURL_HTTP_VERSION_LAST) return CURLE_UNSUPPORTED_PROTOCOL; if(arg == CURL_HTTP_VERSION_NONE) arg = CURL_HTTP_VERSION_2TLS; #endif data->set.httpversion = arg; break; case CURLOPT_EXPECT_100_TIMEOUT_MS: /* * Time to wait for a response to a HTTP request containing an * Expect: 100-continue header before sending the data anyway. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.expect_100_timeout = arg; break; case CURLOPT_HTTP09_ALLOWED: arg = va_arg(param, unsigned long); if(arg > 1L) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.http09_allowed = arg ? TRUE : FALSE; break; #endif /* CURL_DISABLE_HTTP */ case CURLOPT_HTTPAUTH: /* * Set HTTP Authentication type BITMASK. */ { int bitcheck; bool authbits; unsigned long auth = va_arg(param, unsigned long); if(auth == CURLAUTH_NONE) { data->set.httpauth = auth; break; } /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ data->state.authhost.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE); if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ } /* switch off bits we can't support */ #ifndef USE_NTLM auth &= ~CURLAUTH_NTLM; /* no NTLM support */ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #elif !defined(NTLM_WB_ENABLED) auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif #ifndef USE_SPNEGO auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without GSS-API or SSPI */ #endif /* check if any auth bit lower than CURLAUTH_ONLY is still set */ bitcheck = 0; authbits = FALSE; while(bitcheck < 31) { if(auth & (1UL << bitcheck++)) { authbits = TRUE; break; } } if(!authbits) return CURLE_NOT_BUILT_IN; /* no supported types left! */ data->set.httpauth = auth; } break; case CURLOPT_CUSTOMREQUEST: /* * Set a custom string to use as request */ result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], va_arg(param, char *)); /* we don't set data->set.httpreq = HTTPREQ_CUSTOM; here, we continue as if we were using the already set type and this just changes the actual request keyword */ break; #ifndef CURL_DISABLE_PROXY case CURLOPT_HTTPPROXYTUNNEL: /* * Tunnel operations through the proxy instead of normal proxy use */ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_PROXYPORT: /* * Explicitly set HTTP proxy port number. */ arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.proxyport = arg; break; case CURLOPT_PROXYAUTH: /* * Set HTTP Authentication type BITMASK. */ { int bitcheck; bool authbits; unsigned long auth = va_arg(param, unsigned long); if(auth == CURLAUTH_NONE) { data->set.proxyauth = auth; break; } /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ data->state.authproxy.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE); if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */ } /* switch off bits we can't support */ #ifndef USE_NTLM auth &= ~CURLAUTH_NTLM; /* no NTLM support */ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #elif !defined(NTLM_WB_ENABLED) auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif #ifndef USE_SPNEGO auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without GSS-API or SSPI */ #endif /* check if any auth bit lower than CURLAUTH_ONLY is still set */ bitcheck = 0; authbits = FALSE; while(bitcheck < 31) { if(auth & (1UL << bitcheck++)) { authbits = TRUE; break; } } if(!authbits) return CURLE_NOT_BUILT_IN; /* no supported types left! */ data->set.proxyauth = auth; } break; case CURLOPT_PROXY: /* * Set proxy server:port to use as proxy. * * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) * we explicitly say that we don't want to use a proxy * (even though there might be environment variables saying so). * * Setting it to NULL, means no proxy but allows the environment variables * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). */ result = Curl_setstropt(&data->set.str[STRING_PROXY], va_arg(param, char *)); break; case CURLOPT_PRE_PROXY: /* * Set proxy server:port to use as SOCKS proxy. * * If the proxy is set to "" or NULL we explicitly say that we don't want * to use the socks proxy. */ result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY], va_arg(param, char *)); break; case CURLOPT_PROXYTYPE: /* * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME */ arg = va_arg(param, long); if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.proxytype = (curl_proxytype)arg; break; case CURLOPT_PROXY_TRANSFER_MODE: /* * set transfer mode (;type=) when doing FTP via an HTTP proxy */ switch(va_arg(param, long)) { case 0: data->set.proxy_transfer_mode = FALSE; break; case 1: data->set.proxy_transfer_mode = TRUE; break; default: /* reserve other values for future use */ result = CURLE_UNKNOWN_OPTION; break; } break; #endif /* CURL_DISABLE_PROXY */ case CURLOPT_SOCKS5_AUTH: data->set.socks5auth = va_arg(param, unsigned long); if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) result = CURLE_NOT_BUILT_IN; break; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CURLOPT_SOCKS5_GSSAPI_NEC: /* * Set flag for NEC SOCK5 support */ data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #endif #ifndef CURL_DISABLE_PROXY case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_PROXY_SERVICE_NAME: /* * Set proxy authentication service name for Kerberos 5 and SPNEGO */ result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], va_arg(param, char *)); break; #endif case CURLOPT_SERVICE_NAME: /* * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], va_arg(param, char *)); break; case CURLOPT_HEADERDATA: /* * Custom pointer to pass the header write callback function */ data->set.writeheader = (void *)va_arg(param, void *); break; case CURLOPT_ERRORBUFFER: /* * Error buffer provided by the caller to get the human readable * error string in. */ data->set.errorbuffer = va_arg(param, char *); break; case CURLOPT_WRITEDATA: /* * FILE pointer to write to. Or possibly * used as argument to the write callback. */ data->set.out = va_arg(param, void *); break; case CURLOPT_DIRLISTONLY: /* * An option that changes the command to one that asks for a list only, no * file info details. Used for FTP, POP3 and SFTP. */ data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. Used for FTP and * SFTP. */ data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifndef CURL_DISABLE_FTP case CURLOPT_FTP_FILEMETHOD: /* * How do access files over FTP. */ arg = va_arg(param, long); if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.ftp_filemethod = (curl_ftpfile)arg; break; case CURLOPT_FTPPORT: /* * Use FTP PORT, this also specifies which IP address to use */ result = Curl_setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPRT: data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPSV: data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_PRET: data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_SSL_CCC: arg = va_arg(param, long); if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.ftp_ccc = (curl_ftpccc)arg; break; case CURLOPT_FTP_SKIP_PASV_IP: /* * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_ACCOUNT: result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], va_arg(param, char *)); break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], va_arg(param, char *)); break; case CURLOPT_FTPSSLAUTH: /* * Set a specific auth for FTP-SSL transfers. */ arg = va_arg(param, long); if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.ftpsslauth = (curl_ftpauth)arg; break; case CURLOPT_KRBLEVEL: /* * A string that defines the kerberos security level. */ result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE; break; #endif case CURLOPT_FTP_CREATE_MISSING_DIRS: /* * An FTP/SFTP option that modifies an upload to create missing * directories on the server. */ switch(va_arg(param, long)) { case 0: data->set.ftp_create_missing_dirs = 0; break; case 1: data->set.ftp_create_missing_dirs = 1; break; case 2: data->set.ftp_create_missing_dirs = 2; break; default: /* reserve other values for future use */ result = CURLE_UNKNOWN_OPTION; break; } break; case CURLOPT_READDATA: /* * FILE pointer to read the file to be uploaded from. Or possibly * used as argument to the read callback. */ data->set.in_set = va_arg(param, void *); break; case CURLOPT_INFILESIZE: /* * If known, this should inform curl about the file size of the * to-be-uploaded file. */ arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.filesize = arg; break; case CURLOPT_INFILESIZE_LARGE: /* * If known, this should inform curl about the file size of the * to-be-uploaded file. */ bigsize = va_arg(param, curl_off_t); if(bigsize < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.filesize = bigsize; break; case CURLOPT_LOW_SPEED_LIMIT: /* * The low speed limit that if transfers are below this for * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.low_speed_limit = arg; break; case CURLOPT_MAX_SEND_SPEED_LARGE: /* * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE * bytes per second the transfer is throttled.. */ bigsize = va_arg(param, curl_off_t); if(bigsize < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.max_send_speed = bigsize; break; case CURLOPT_MAX_RECV_SPEED_LARGE: /* * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per * second the transfer is throttled.. */ bigsize = va_arg(param, curl_off_t); if(bigsize < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.max_recv_speed = bigsize; break; case CURLOPT_LOW_SPEED_TIME: /* * The low speed time that if transfers are below the set * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.low_speed_time = arg; break; case CURLOPT_CURLU: /* * pass CURLU to set URL */ data->set.uh = va_arg(param, CURLU *); break; case CURLOPT_URL: /* * The URL to fetch. */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ Curl_safefree(data->change.url); data->change.url_alloc = FALSE; } result = Curl_setstropt(&data->set.str[STRING_SET_URL], va_arg(param, char *)); data->change.url = data->set.str[STRING_SET_URL]; break; case CURLOPT_PORT: /* * The port number to use when getting the URL */ arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.use_port = arg; break; case CURLOPT_TIMEOUT: /* * The maximum time you allow curl to use for a single transfer * operation. */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.timeout = arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; case CURLOPT_TIMEOUT_MS: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.timeout = arg; break; case CURLOPT_CONNECTTIMEOUT: /* * The maximum time you allow curl to use to connect. */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.connecttimeout = arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; case CURLOPT_CONNECTTIMEOUT_MS: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.connecttimeout = arg; break; case CURLOPT_ACCEPTTIMEOUT_MS: /* * The maximum time you allow curl to wait for server connect */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.accepttimeout = arg; break; case CURLOPT_USERPWD: /* * user:password to use in the operation */ result = setstropt_userpwd(va_arg(param, char *), &data->set.str[STRING_USERNAME], &data->set.str[STRING_PASSWORD]); break; case CURLOPT_USERNAME: /* * authentication user name to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_USERNAME], va_arg(param, char *)); break; case CURLOPT_PASSWORD: /* * authentication password to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_PASSWORD], va_arg(param, char *)); break; case CURLOPT_LOGIN_OPTIONS: /* * authentication options to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_OPTIONS], va_arg(param, char *)); break; case CURLOPT_XOAUTH2_BEARER: /* * OAuth 2.0 bearer token to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_BEARER], va_arg(param, char *)); break; case CURLOPT_POSTQUOTE: /* * List of RAW FTP commands to use after a transfer */ data->set.postquote = va_arg(param, struct curl_slist *); break; case CURLOPT_PREQUOTE: /* * List of RAW FTP commands to use prior to RETR (Wesley Laxton) */ data->set.prequote = va_arg(param, struct curl_slist *); break; case CURLOPT_QUOTE: /* * List of RAW FTP commands to use before a transfer */ data->set.quote = va_arg(param, struct curl_slist *); break; case CURLOPT_RESOLVE: /* * List of NAME:[address] names to populate the DNS cache with * Prefix the NAME with dash (-) to _remove_ the name from the cache. * * Names added with this API will remain in the cache until explicitly * removed or the handle is cleaned up. * * This API can remove any name from the DNS cache, but only entries * that aren't actually in use right now will be pruned immediately. */ data->set.resolve = va_arg(param, struct curl_slist *); data->change.resolve = data->set.resolve; break; case CURLOPT_PROGRESSFUNCTION: /* * Progress callback function */ data->set.fprogress = va_arg(param, curl_progress_callback); if(data->set.fprogress) data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ break; case CURLOPT_XFERINFOFUNCTION: /* * Transfer info callback function */ data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); if(data->set.fxferinfo) data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ break; case CURLOPT_PROGRESSDATA: /* * Custom client data to pass to the progress callback */ data->set.progress_client = va_arg(param, void *); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYUSERPWD: /* * user:password needed to use the proxy */ result = setstropt_userpwd(va_arg(param, char *), &data->set.str[STRING_PROXYUSERNAME], &data->set.str[STRING_PROXYPASSWORD]); break; case CURLOPT_PROXYUSERNAME: /* * authentication user name to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], va_arg(param, char *)); break; case CURLOPT_PROXYPASSWORD: /* * authentication password to use in the operation */ result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], va_arg(param, char *)); break; case CURLOPT_NOPROXY: /* * proxy exception list */ result = Curl_setstropt(&data->set.str[STRING_NOPROXY], va_arg(param, char *)); break; #endif case CURLOPT_RANGE: /* * What range of the file you want to transfer */ result = Curl_setstropt(&data->set.str[STRING_SET_RANGE], va_arg(param, char *)); break; case CURLOPT_RESUME_FROM: /* * Resume transfer at the given file position */ arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.set_resume_from = arg; break; case CURLOPT_RESUME_FROM_LARGE: /* * Resume transfer at the given file position */ bigsize = va_arg(param, curl_off_t); if(bigsize < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.set_resume_from = bigsize; break; case CURLOPT_DEBUGFUNCTION: /* * stderr write callback. */ data->set.fdebug = va_arg(param, curl_debug_callback); /* * if the callback provided is NULL, it'll use the default callback */ break; case CURLOPT_DEBUGDATA: /* * Set to a void * that should receive all error writes. This * defaults to CURLOPT_STDERR for normal operations. */ data->set.debugdata = va_arg(param, void *); break; case CURLOPT_STDERR: /* * Set to a FILE * that should receive all error writes. This * defaults to stderr for normal operations. */ data->set.err = va_arg(param, FILE *); if(!data->set.err) data->set.err = stderr; break; case CURLOPT_HEADERFUNCTION: /* * Set header write callback */ data->set.fwrite_header = va_arg(param, curl_write_callback); break; case CURLOPT_WRITEFUNCTION: /* * Set data write callback */ data->set.fwrite_func = va_arg(param, curl_write_callback); if(!data->set.fwrite_func) { data->set.is_fwrite_set = 0; /* When set to NULL, reset to our internal default function */ data->set.fwrite_func = (curl_write_callback)fwrite; } else data->set.is_fwrite_set = 1; break; case CURLOPT_READFUNCTION: /* * Read data callback */ data->set.fread_func_set = va_arg(param, curl_read_callback); if(!data->set.fread_func_set) { data->set.is_fread_set = 0; /* When set to NULL, reset to our internal default function */ data->set.fread_func_set = (curl_read_callback)fread; } else data->set.is_fread_set = 1; break; case CURLOPT_SEEKFUNCTION: /* * Seek callback. Might be NULL. */ data->set.seek_func = va_arg(param, curl_seek_callback); break; case CURLOPT_SEEKDATA: /* * Seek control callback. Might be NULL. */ data->set.seek_client = va_arg(param, void *); break; case CURLOPT_CONV_FROM_NETWORK_FUNCTION: /* * "Convert from network encoding" callback */ data->set.convfromnetwork = va_arg(param, curl_conv_callback); break; case CURLOPT_CONV_TO_NETWORK_FUNCTION: /* * "Convert to network encoding" callback */ data->set.convtonetwork = va_arg(param, curl_conv_callback); break; case CURLOPT_CONV_FROM_UTF8_FUNCTION: /* * "Convert from UTF-8 encoding" callback */ data->set.convfromutf8 = va_arg(param, curl_conv_callback); break; case CURLOPT_IOCTLFUNCTION: /* * I/O control callback. Might be NULL. */ data->set.ioctl_func = va_arg(param, curl_ioctl_callback); break; case CURLOPT_IOCTLDATA: /* * I/O control data pointer. Might be NULL. */ data->set.ioctl_client = va_arg(param, void *); break; case CURLOPT_SSLCERT: /* * String that holds file name of the SSL certificate to use */ result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERT: /* * String that holds file name of the SSL certificate to use for proxy */ result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use for proxy */ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_SSLKEY: /* * String that holds file name of the SSL key to use */ result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLKEY: /* * String that holds file name of the SSL key to use for proxy */ result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL key to use */ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLKEYTYPE: /* * String that holds file type of the SSL key to use for proxy */ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_KEYPASSWD: /* * String that holds the SSL or SSH private key password. */ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_KEYPASSWD: /* * String that holds the SSL private key password for proxy. */ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_SSLENGINE: /* * String that holds the SSL crypto engine. */ argptr = va_arg(param, char *); if(argptr && argptr[0]) { result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr); if(!result) { result = Curl_ssl_set_engine(data, argptr); } } break; case CURLOPT_SSLENGINE_DEFAULT: /* * flag to set engine as default. */ Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], NULL); result = Curl_ssl_set_engine_default(data); break; case CURLOPT_CRLF: /* * Kludgy option to enable CRLF conversions. Subject for removal. */ data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_HAPROXYPROTOCOL: /* * Set to send the HAProxy Proxy Protocol header */ data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #endif case CURLOPT_INTERFACE: /* * Set what interface or address/hostname to bind the socket to when * performing an operation and thus what from-IP your connection will use. */ result = Curl_setstropt(&data->set.str[STRING_DEVICE], va_arg(param, char *)); break; case CURLOPT_LOCALPORT: /* * Set what local port to bind the socket to when performing an operation. */ arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.localport = curlx_sltous(arg); break; case CURLOPT_LOCALPORTRANGE: /* * Set number of local ports to try, starting with CURLOPT_LOCALPORT. */ arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.localportrange = curlx_sltosi(arg); break; case CURLOPT_GSSAPI_DELEGATION: /* * GSS-API credential delegation bitmask */ arg = va_arg(param, long); if(arg < CURLGSSAPI_DELEGATION_NONE) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.gssapi_delegation = arg; break; case CURLOPT_SSL_VERIFYPEER: /* * Enable peer SSL verifying. */ data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; /* Update the current connection ssl_config. */ if(data->conn) { data->conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; } break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_VERIFYPEER: /* * Enable peer SSL verifying for proxy. */ data->set.proxy_ssl.primary.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE; /* Update the current connection proxy_ssl_config. */ if(data->conn) { data->conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; } break; #endif case CURLOPT_SSL_VERIFYHOST: /* * Enable verification of the host name in the peer certificate */ arg = va_arg(param, long); /* Obviously people are not reading documentation and too many thought this argument took a boolean when it wasn't and misused it. Treat 1 and 2 the same */ data->set.ssl.primary.verifyhost = (bool)((arg & 3) ? TRUE : FALSE); /* Update the current connection ssl_config. */ if(data->conn) { data->conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; } break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_VERIFYHOST: /* * Enable verification of the host name in the peer certificate for proxy */ arg = va_arg(param, long); /* Treat both 1 and 2 as TRUE */ data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE); /* Update the current connection proxy_ssl_config. */ if(data->conn) { data->conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; } break; #endif case CURLOPT_SSL_VERIFYSTATUS: /* * Enable certificate status verifying. */ if(!Curl_ssl_cert_status_request()) { result = CURLE_NOT_BUILT_IN; break; } data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; /* Update the current connection ssl_config. */ if(data->conn) { data->conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; } break; case CURLOPT_SSL_CTX_FUNCTION: /* * Set a SSL_CTX callback */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_SSL_CTX) data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); else #endif result = CURLE_NOT_BUILT_IN; break; case CURLOPT_SSL_CTX_DATA: /* * Set a SSL_CTX callback parameter pointer */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_SSL_CTX) data->set.ssl.fsslctxp = va_arg(param, void *); else #endif result = CURLE_NOT_BUILT_IN; break; case CURLOPT_SSL_FALSESTART: /* * Enable TLS false start. */ if(!Curl_ssl_false_start()) { result = CURLE_NOT_BUILT_IN; break; } data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CERTINFO: #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_CERTINFO) data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; else #endif result = CURLE_NOT_BUILT_IN; break; case CURLOPT_PINNEDPUBLICKEY: /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY) result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG], va_arg(param, char *)); else #endif result = CURLE_NOT_BUILT_IN; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_PINNEDPUBLICKEY: /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY) result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], va_arg(param, char *)); else #endif result = CURLE_NOT_BUILT_IN; break; #endif case CURLOPT_CAINFO: /* * Set CA info for SSL connection. Specify file name of the CA certificate */ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CAINFO: /* * Set CA info SSL connection for proxy. Specify file name of the * CA certificate */ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_CAPATH: /* * Set CA path info for SSL connection. Specify directory name of the CA * certificates which have been prepared using openssl c_rehash utility. */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_CA_PATH) /* This does not work on windows. */ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], va_arg(param, char *)); else #endif result = CURLE_NOT_BUILT_IN; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CAPATH: /* * Set CA path info for SSL connection proxy. Specify directory name of the * CA certificates which have been prepared using openssl c_rehash utility. */ #ifdef USE_SSL if(Curl_ssl->supports & SSLSUPP_CA_PATH) /* This does not work on windows. */ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], va_arg(param, char *)); else #endif result = CURLE_NOT_BUILT_IN; break; #endif case CURLOPT_CRLFILE: /* * Set CRL file info for SSL connection. Specify file name of the CRL * to check certificates revocation */ result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CRLFILE: /* * Set CRL file info for SSL connection for proxy. Specify file name of the * CRL to check certificates revocation */ result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], va_arg(param, char *)); break; #endif case CURLOPT_ISSUERCERT: /* * Set Issuer certificate file * to check certificates issuer */ result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG], va_arg(param, char *)); break; #ifndef CURL_DISABLE_TELNET case CURLOPT_TELNETOPTIONS: /* * Set a linked list of telnet options */ data->set.telnet_options = va_arg(param, struct curl_slist *); break; #endif case CURLOPT_BUFFERSIZE: /* * The application kindly asks for a differently sized receive buffer. * If it seems reasonable, we'll use it. */ arg = va_arg(param, long); if(arg > READBUFFER_MAX) arg = READBUFFER_MAX; else if(arg < 1) arg = READBUFFER_SIZE; else if(arg < READBUFFER_MIN) arg = READBUFFER_MIN; /* Resize if new size */ if(arg != data->set.buffer_size) { char *newbuff = realloc(data->state.buffer, arg + 1); if(!newbuff) { DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); result = CURLE_OUT_OF_MEMORY; } else data->state.buffer = newbuff; } data->set.buffer_size = arg; break; case CURLOPT_UPLOAD_BUFFERSIZE: /* * The application kindly asks for a differently sized upload buffer. * Cap it to sensible. */ arg = va_arg(param, long); if(arg > UPLOADBUFFER_MAX) arg = UPLOADBUFFER_MAX; else if(arg < UPLOADBUFFER_MIN) arg = UPLOADBUFFER_MIN; data->set.upload_buffer_size = arg; Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */ break; case CURLOPT_NOSIGNAL: /* * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SHARE: { struct Curl_share *set; set = va_arg(param, struct Curl_share *); /* disconnect from old share, if any */ if(data->share) { Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); if(data->dns.hostcachetype == HCACHE_SHARED) { data->dns.hostcache = NULL; data->dns.hostcachetype = HCACHE_NONE; } #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies == data->cookies) data->cookies = NULL; #endif if(data->share->sslsession == data->state.session) data->state.session = NULL; #ifdef USE_LIBPSL if(data->psl == &data->share->psl) data->psl = data->multi? &data->multi->psl: NULL; #endif data->share->dirty--; Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); data->share = NULL; } /* use new share if it set */ data->share = set; if(data->share) { Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); data->share->dirty++; if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) { /* use shared host cache */ data->dns.hostcache = &data->share->hostcache; data->dns.hostcachetype = HCACHE_SHARED; } #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies) { /* use shared cookie list, first free own one if any */ Curl_cookie_cleanup(data->cookies); /* enable cookies since we now use a share that uses cookies! */ data->cookies = data->share->cookies; } #endif /* CURL_DISABLE_HTTP */ if(data->share->sslsession) { data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; data->state.session = data->share->sslsession; } #ifdef USE_LIBPSL if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) data->psl = &data->share->psl; #endif Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } /* check for host cache not needed, * it will be done by curl_easy_perform */ } break; case CURLOPT_PRIVATE: /* * Set private data pointer. */ data->set.private_data = va_arg(param, void *); break; case CURLOPT_MAXFILESIZE: /* * Set the maximum size of a file to download. */ arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.max_filesize = arg; break; #ifdef USE_SSL case CURLOPT_USE_SSL: /* * Make transfers attempt to use SSL/TLS. */ arg = va_arg(param, long); if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.use_ssl = (curl_usessl)arg; break; case CURLOPT_SSL_OPTIONS: arg = va_arg(param, long); data->set.ssl.enable_beast = (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_OPTIONS: arg = va_arg(param, long); data->set.proxy_ssl.enable_beast = (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE); data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); break; #endif #endif case CURLOPT_IPRESOLVE: arg = va_arg(param, long); if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.ipver = arg; break; case CURLOPT_MAXFILESIZE_LARGE: /* * Set the maximum size of a file to download. */ bigsize = va_arg(param, curl_off_t); if(bigsize < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.max_filesize = bigsize; break; case CURLOPT_TCP_NODELAY: /* * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_IGNORE_CONTENT_LENGTH: data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SOCKOPTFUNCTION: /* * socket callback function: called after socket() but before connect() */ data->set.fsockopt = va_arg(param, curl_sockopt_callback); break; case CURLOPT_SOCKOPTDATA: /* * socket callback data pointer. Might be NULL. */ data->set.sockopt_client = va_arg(param, void *); break; case CURLOPT_OPENSOCKETFUNCTION: /* * open/create socket callback function: called instead of socket(), * before connect() */ data->set.fopensocket = va_arg(param, curl_opensocket_callback); break; case CURLOPT_OPENSOCKETDATA: /* * socket callback data pointer. Might be NULL. */ data->set.opensocket_client = va_arg(param, void *); break; case CURLOPT_CLOSESOCKETFUNCTION: /* * close socket callback function: called instead of close() * when shutting down a connection */ data->set.fclosesocket = va_arg(param, curl_closesocket_callback); break; case CURLOPT_RESOLVER_START_FUNCTION: /* * resolver start callback function: called before a new resolver request * is started */ data->set.resolver_start = va_arg(param, curl_resolver_start_callback); break; case CURLOPT_RESOLVER_START_DATA: /* * resolver start callback data pointer. Might be NULL. */ data->set.resolver_start_client = va_arg(param, void *); break; case CURLOPT_CLOSESOCKETDATA: /* * socket callback data pointer. Might be NULL. */ data->set.closesocket_client = va_arg(param, void *); break; case CURLOPT_SSL_SESSIONID_CACHE: data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid; break; #ifdef USE_SSH /* we only include SSH options if explicitly built to support SSH */ case CURLOPT_SSH_AUTH_TYPES: data->set.ssh_auth_types = va_arg(param, long); break; case CURLOPT_SSH_PUBLIC_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa.pub file */ result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], va_arg(param, char *)); break; case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], va_arg(param, char *)); break; case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: /* * Option to allow for the MD5 of the host public key to be checked * for validation purposes. */ result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], va_arg(param, char *)); break; case CURLOPT_SSH_KNOWNHOSTS: /* * Store the file name to read known hosts from. */ result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], va_arg(param, char *)); break; case CURLOPT_SSH_KEYFUNCTION: /* setting to NULL is fine since the ssh.c functions themselves will then revert to use the internal default */ data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); break; case CURLOPT_SSH_KEYDATA: /* * Custom client data to pass to the SSH keyfunc callback */ data->set.ssh_keyfunc_userp = va_arg(param, void *); break; case CURLOPT_SSH_COMPRESSION: data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE; break; #endif /* USE_SSH */ case CURLOPT_HTTP_TRANSFER_DECODING: /* * disable libcurl transfer encoding is used */ data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) case CURLOPT_NEW_FILE_PERMS: /* * Uses these permissions instead of 0644 */ arg = va_arg(param, long); if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.new_file_perms = arg; break; case CURLOPT_NEW_DIRECTORY_PERMS: /* * Uses these permissions instead of 0755 */ arg = va_arg(param, long); if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.new_directory_perms = arg; break; #endif case CURLOPT_ADDRESS_SCOPE: /* * Use this scope id when using IPv6 * We always get longs when passed plain numericals so we should check * that the value fits into an unsigned 32 bit integer. */ uarg = va_arg(param, unsigned long); #if SIZEOF_LONG > 4 if(uarg > UINT_MAX) return CURLE_BAD_FUNCTION_ARGUMENT; #endif data->set.scope_id = (unsigned int)uarg; break; case CURLOPT_PROTOCOLS: /* set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ data->set.allowed_protocols = va_arg(param, long); break; case CURLOPT_REDIR_PROTOCOLS: /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ data->set.redir_protocols = va_arg(param, long); break; case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL doesn't include any protocol */ result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], va_arg(param, char *)); break; #ifndef CURL_DISABLE_SMTP case CURLOPT_MAIL_FROM: /* Set the SMTP mail originator */ result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM], va_arg(param, char *)); break; case CURLOPT_MAIL_AUTH: /* Set the SMTP auth originator */ result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], va_arg(param, char *)); break; case CURLOPT_MAIL_RCPT: /* Set the list of mail recipients */ data->set.mail_rcpt = va_arg(param, struct curl_slist *); break; case CURLOPT_MAIL_RCPT_ALLLOWFAILS: /* allow RCPT TO command to fail for some recipients */ data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #endif case CURLOPT_SASL_AUTHZID: /* Authorisation identity (identity to act as) */ result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], va_arg(param, char *)); break; case CURLOPT_SASL_IR: /* Enable/disable SASL initial response */ data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifndef CURL_DISABLE_RTSP case CURLOPT_RTSP_REQUEST: { /* * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...) * Would this be better if the RTSPREQ_* were just moved into here? */ long curl_rtspreq = va_arg(param, long); Curl_RtspReq rtspreq = RTSPREQ_NONE; switch(curl_rtspreq) { case CURL_RTSPREQ_OPTIONS: rtspreq = RTSPREQ_OPTIONS; break; case CURL_RTSPREQ_DESCRIBE: rtspreq = RTSPREQ_DESCRIBE; break; case CURL_RTSPREQ_ANNOUNCE: rtspreq = RTSPREQ_ANNOUNCE; break; case CURL_RTSPREQ_SETUP: rtspreq = RTSPREQ_SETUP; break; case CURL_RTSPREQ_PLAY: rtspreq = RTSPREQ_PLAY; break; case CURL_RTSPREQ_PAUSE: rtspreq = RTSPREQ_PAUSE; break; case CURL_RTSPREQ_TEARDOWN: rtspreq = RTSPREQ_TEARDOWN; break; case CURL_RTSPREQ_GET_PARAMETER: rtspreq = RTSPREQ_GET_PARAMETER; break; case CURL_RTSPREQ_SET_PARAMETER: rtspreq = RTSPREQ_SET_PARAMETER; break; case CURL_RTSPREQ_RECORD: rtspreq = RTSPREQ_RECORD; break; case CURL_RTSPREQ_RECEIVE: rtspreq = RTSPREQ_RECEIVE; break; default: rtspreq = RTSPREQ_NONE; } data->set.rtspreq = rtspreq; break; } case CURLOPT_RTSP_SESSION_ID: /* * Set the RTSP Session ID manually. Useful if the application is * resuming a previously established RTSP session */ result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], va_arg(param, char *)); break; case CURLOPT_RTSP_STREAM_URI: /* * Set the Stream URI for the RTSP request. Unless the request is * for generic server options, the application will need to set this. */ result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], va_arg(param, char *)); break; case CURLOPT_RTSP_TRANSPORT: /* * The content of the Transport: header for the RTSP request */ result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], va_arg(param, char *)); break; case CURLOPT_RTSP_CLIENT_CSEQ: /* * Set the CSEQ number to issue for the next RTSP request. Useful if the * application is resuming a previously broken connection. The CSEQ * will increment from this new number henceforth. */ data->state.rtsp_next_client_CSeq = va_arg(param, long); break; case CURLOPT_RTSP_SERVER_CSEQ: /* Same as the above, but for server-initiated requests */ data->state.rtsp_next_server_CSeq = va_arg(param, long); break; case CURLOPT_INTERLEAVEDATA: data->set.rtp_out = va_arg(param, void *); break; case CURLOPT_INTERLEAVEFUNCTION: /* Set the user defined RTP write function */ data->set.fwrite_rtp = va_arg(param, curl_write_callback); break; #endif #ifndef CURL_DISABLE_FTP case CURLOPT_WILDCARDMATCH: data->set.wildcard_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); break; case CURLOPT_CHUNK_END_FUNCTION: data->set.chunk_end = va_arg(param, curl_chunk_end_callback); break; case CURLOPT_FNMATCH_FUNCTION: data->set.fnmatch = va_arg(param, curl_fnmatch_callback); break; case CURLOPT_CHUNK_DATA: data->wildcard.customptr = va_arg(param, void *); break; case CURLOPT_FNMATCH_DATA: data->set.fnmatch_data = va_arg(param, void *); break; #endif #ifdef USE_TLS_SRP case CURLOPT_TLSAUTH_USERNAME: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], va_arg(param, char *)); if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_PROXY_TLSAUTH_USERNAME: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], va_arg(param, char *)); if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && !data->set.proxy_ssl.authtype) data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_TLSAUTH_PASSWORD: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], va_arg(param, char *)); if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_PROXY_TLSAUTH_PASSWORD: result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], va_arg(param, char *)); if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && !data->set.proxy_ssl.authtype) data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_TLSAUTH_TYPE: argptr = va_arg(param, char *); if(!argptr || strncasecompare(argptr, "SRP", strlen("SRP"))) data->set.ssl.authtype = CURL_TLSAUTH_SRP; else data->set.ssl.authtype = CURL_TLSAUTH_NONE; break; case CURLOPT_PROXY_TLSAUTH_TYPE: argptr = va_arg(param, char *); if(!argptr || strncasecompare(argptr, "SRP", strlen("SRP"))) data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; else data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; break; #endif #ifdef USE_ARES case CURLOPT_DNS_SERVERS: result = Curl_set_dns_servers(data, va_arg(param, char *)); break; case CURLOPT_DNS_INTERFACE: result = Curl_set_dns_interface(data, va_arg(param, char *)); break; case CURLOPT_DNS_LOCAL_IP4: result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); break; case CURLOPT_DNS_LOCAL_IP6: result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); break; #endif case CURLOPT_TCP_KEEPALIVE: data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TCP_KEEPIDLE: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.tcp_keepidle = arg; break; case CURLOPT_TCP_KEEPINTVL: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.tcp_keepintvl = arg; break; case CURLOPT_TCP_FASTOPEN: #if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ defined(TCP_FASTOPEN_CONNECT) data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE; #else result = CURLE_NOT_BUILT_IN; #endif break; case CURLOPT_SSL_ENABLE_NPN: data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_ENABLE_ALPN: data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: data->set.abstract_unix_socket = FALSE; result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], va_arg(param, char *)); break; case CURLOPT_ABSTRACT_UNIX_SOCKET: data->set.abstract_unix_socket = TRUE; result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], va_arg(param, char *)); break; #endif case CURLOPT_PATH_AS_IS: data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_PIPEWAIT: data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_STREAM_WEIGHT: #ifndef USE_NGHTTP2 return CURLE_NOT_BUILT_IN; #else arg = va_arg(param, long); if((arg >= 1) && (arg <= 256)) data->set.stream_weight = (int)arg; break; #endif case CURLOPT_STREAM_DEPENDS: case CURLOPT_STREAM_DEPENDS_E: { #ifndef USE_NGHTTP2 return CURLE_NOT_BUILT_IN; #else struct Curl_easy *dep = va_arg(param, struct Curl_easy *); if(!dep || GOOD_EASY_HANDLE(dep)) { if(data->set.stream_depends_on) { Curl_http2_remove_child(data->set.stream_depends_on, data); } Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E)); } break; #endif } case CURLOPT_CONNECT_TO: data->set.connect_to = va_arg(param, struct curl_slist *); break; case CURLOPT_SUPPRESS_CONNECT_HEADERS: data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.happy_eyeballs_timeout = arg; break; #ifndef CURL_DISABLE_SHUFFLE_DNS case CURLOPT_DNS_SHUFFLE_ADDRESSES: data->set.dns_shuffle_addresses = (0 != va_arg(param, long)) ? TRUE:FALSE; break; #endif case CURLOPT_DISALLOW_USERNAME_IN_URL: data->set.disallow_username_in_url = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_URL: result = Curl_setstropt(&data->set.str[STRING_DOH], va_arg(param, char *)); data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE; break; #endif case CURLOPT_UPKEEP_INTERVAL_MS: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.upkeep_interval_ms = arg; break; case CURLOPT_MAXAGE_CONN: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxage_conn = arg; break; case CURLOPT_TRAILERFUNCTION: #ifndef CURL_DISABLE_HTTP data->set.trailer_callback = va_arg(param, curl_trailer_callback); #endif break; case CURLOPT_TRAILERDATA: #ifndef CURL_DISABLE_HTTP data->set.trailer_data = va_arg(param, void *); #endif break; #ifdef USE_ALTSVC case CURLOPT_ALTSVC: if(!data->asi) { data->asi = Curl_altsvc_init(); if(!data->asi) return CURLE_OUT_OF_MEMORY; } argptr = va_arg(param, char *); result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr); if(result) return result; if(argptr) (void)Curl_altsvc_load(data->asi, argptr); break; case CURLOPT_ALTSVC_CTRL: if(!data->asi) { data->asi = Curl_altsvc_init(); if(!data->asi) return CURLE_OUT_OF_MEMORY; } arg = va_arg(param, long); result = Curl_altsvc_ctrl(data->asi, arg); if(result) return result; break; #endif default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; break; } return result; } /* * curl_easy_setopt() is the external interface for setting options on an * easy handle. * * NOTE: This is one of few API functions that are allowed to be called from * within a callback. */ #undef curl_easy_setopt CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) { va_list arg; CURLcode result; if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, tag); result = Curl_vsetopt(data, tag, arg); va_end(arg); return result; } davix-0.8.0/deps/curl/lib/curl_setup.h0000644000000000000000000005336614121063461016347 0ustar rootroot#ifndef HEADER_CURL_SETUP_H #define HEADER_CURL_SETUP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES) #define CURL_NO_OLDIES #endif /* * Disable Visual Studio warnings: * 4127 "conditional expression is constant" */ #ifdef _MSC_VER #pragma warning(disable:4127) #endif /* * Define WIN32 when build target is Win32 API */ #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \ !defined(__SYMBIAN32__) #define WIN32 #endif #ifdef WIN32 /* * Don't include unneeded stuff in Windows headers to avoid compiler * warnings and macro clashes. * Make sure to define this macro before including any Windows headers. */ # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # ifndef NOGDI # define NOGDI # endif #endif /* * Include configuration script results or hand-crafted * configuration file for platforms which lack config tool. */ #ifdef HAVE_CONFIG_H #include "curl_config.h" #else /* HAVE_CONFIG_H */ #ifdef _WIN32_WCE # include "config-win32ce.h" #else # ifdef WIN32 # include "config-win32.h" # endif #endif #if defined(macintosh) && defined(__MRC__) # include "config-mac.h" #endif #ifdef __riscos__ # include "config-riscos.h" #endif #ifdef __AMIGA__ # include "config-amigaos.h" #endif #ifdef __SYMBIAN32__ # include "config-symbian.h" #endif #ifdef __OS400__ # include "config-os400.h" #endif #ifdef TPF # include "config-tpf.h" #endif #ifdef __VXWORKS__ # include "config-vxworks.h" #endif #ifdef __PLAN9__ # include "config-plan9.h" #endif #endif /* HAVE_CONFIG_H */ /* ================================================================ */ /* Definition of preprocessor macros/symbols which modify compiler */ /* behavior or generated code characteristics must be done here, */ /* as appropriate, before any system header file is included. It is */ /* also possible to have them defined in the config file included */ /* before this point. As a result of all this we frown inclusion of */ /* system header files in our config files, avoid this at any cost. */ /* ================================================================ */ /* * AIX 4.3 and newer needs _THREAD_SAFE defined to build * proper reentrant code. Others may also need it. */ #ifdef NEED_THREAD_SAFE # ifndef _THREAD_SAFE # define _THREAD_SAFE # endif #endif /* * Tru64 needs _REENTRANT set for a few function prototypes and * things to appear in the system header files. Unixware needs it * to build proper reentrant code. Others may also need it. */ #ifdef NEED_REENTRANT # ifndef _REENTRANT # define _REENTRANT # endif #endif /* Solaris needs this to get a POSIX-conformant getpwuid_r */ #if defined(sun) || defined(__sun) # ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 # endif #endif /* ================================================================ */ /* If you need to include a system header file for your platform, */ /* please, do it beyond the point further indicated in this file. */ /* ================================================================ */ #include #define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T /* * Disable other protocols when http is the only one desired. */ #ifdef HTTP_ONLY # ifndef CURL_DISABLE_TFTP # define CURL_DISABLE_TFTP # endif # ifndef CURL_DISABLE_FTP # define CURL_DISABLE_FTP # endif # ifndef CURL_DISABLE_LDAP # define CURL_DISABLE_LDAP # endif # ifndef CURL_DISABLE_TELNET # define CURL_DISABLE_TELNET # endif # ifndef CURL_DISABLE_DICT # define CURL_DISABLE_DICT # endif # ifndef CURL_DISABLE_FILE # define CURL_DISABLE_FILE # endif # ifndef CURL_DISABLE_RTSP # define CURL_DISABLE_RTSP # endif # ifndef CURL_DISABLE_POP3 # define CURL_DISABLE_POP3 # endif # ifndef CURL_DISABLE_IMAP # define CURL_DISABLE_IMAP # endif # ifndef CURL_DISABLE_SMTP # define CURL_DISABLE_SMTP # endif # ifndef CURL_DISABLE_GOPHER # define CURL_DISABLE_GOPHER # endif # ifndef CURL_DISABLE_SMB # define CURL_DISABLE_SMB # endif #endif /* * When http is disabled rtsp is not supported. */ #if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP) # define CURL_DISABLE_RTSP #endif /* ================================================================ */ /* No system header file shall be included in this file before this */ /* point. The only allowed ones are those included from curl/system.h */ /* ================================================================ */ /* * OS/400 setup file includes some system headers. */ #ifdef __OS400__ # include "setup-os400.h" #endif /* * VMS setup file includes some system headers. */ #ifdef __VMS # include "setup-vms.h" #endif /* * Use getaddrinfo to resolve the IPv4 address literal. If the current network * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, * performing this task will result in a synthesized IPv6 address. */ #ifdef __APPLE__ #define USE_RESOLVE_ON_IPS 1 #endif /* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs * to any other further and independent block. Under Cygwin things work * just as under linux (e.g. ) and the winsock headers should * never be included when __CYGWIN__ is defined. configure script takes * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. */ #ifdef HAVE_WINDOWS_H # if defined(UNICODE) && !defined(_UNICODE) # define _UNICODE # endif # if defined(_UNICODE) && !defined(UNICODE) # define UNICODE # endif # include # include # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H # include # endif # else # ifdef HAVE_WINSOCK_H # include # endif # endif # include # ifdef UNICODE typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); # endif #endif /* * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else * define USE_WINSOCK to 1 if we have and use WINSOCK API, else * undefine USE_WINSOCK. */ #undef USE_WINSOCK #ifdef HAVE_WINSOCK2_H # define USE_WINSOCK 2 #else # ifdef HAVE_WINSOCK_H # define USE_WINSOCK 1 # endif #endif #ifdef USE_LWIPSOCK # include # include # include #endif #ifdef HAVE_EXTRA_STRICMP_H # include #endif #ifdef HAVE_EXTRA_STRDUP_H # include #endif #ifdef TPF # include /* for bzero, strcasecmp, and strncasecmp */ # include /* for strcpy and strlen */ # include /* for rand and srand */ # include /* for select and ioctl*/ # include /* for in_addr_t definition */ # include /* for tpf_process_signals */ /* change which select is used for libcurl */ # define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e) #endif #ifdef __VXWORKS__ # include /* for generic BSD socket functions */ # include /* for basic I/O interface functions */ #endif #ifdef __AMIGA__ # include # include # include # include # ifdef HAVE_PROTO_BSDSOCKET_H # include /* ensure bsdsocket.library use */ # define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) # endif #endif #include #ifdef HAVE_ASSERT_H #include #endif #ifdef __TANDEM /* for nsr-tandem-nsk systems */ #include #endif #ifndef STDC_HEADERS /* no standard C headers! */ #include #endif #ifdef __POCC__ # include # include # define sys_nerr EILSEQ #endif /* * Salford-C kludge section (mostly borrowed from wxWidgets). */ #ifdef __SALFORDC__ #pragma suppress 353 /* Possible nested comments */ #pragma suppress 593 /* Define not used */ #pragma suppress 61 /* enum has no name */ #pragma suppress 106 /* unnamed, unused parameter */ #include #endif /* * Large file (>2Gb) support using WIN32 functions. */ #ifdef USE_WIN32_LARGE_FILES # include # include # include # undef lseek # define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) # undef fstat # define fstat(fdes,stp) _fstati64(fdes, stp) # undef stat # define stat(fname,stp) _stati64(fname, stp) # define struct_stat struct _stati64 # define LSEEK_ERROR (__int64)-1 #endif /* * Small file (<2Gb) support using WIN32 functions. */ #ifdef USE_WIN32_SMALL_FILES # include # include # include # ifndef _WIN32_WCE # undef lseek # define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) # define fstat(fdes,stp) _fstat(fdes, stp) # define stat(fname,stp) _stat(fname, stp) # define struct_stat struct _stat # endif # define LSEEK_ERROR (long)-1 #endif #ifndef struct_stat # define struct_stat struct stat #endif #ifndef LSEEK_ERROR # define LSEEK_ERROR (off_t)-1 #endif #ifndef SIZEOF_TIME_T /* assume default size of time_t to be 32 bit */ #define SIZEOF_TIME_T 4 #endif /* * Default sizeof(off_t) in case it hasn't been defined in config file. */ #ifndef SIZEOF_OFF_T # if defined(__VMS) && !defined(__VAX) # if defined(_LARGEFILE) # define SIZEOF_OFF_T 8 # endif # elif defined(__OS400__) && defined(__ILEC400__) # if defined(_LARGE_FILES) # define SIZEOF_OFF_T 8 # endif # elif defined(__MVS__) && defined(__IBMC__) # if defined(_LP64) || defined(_LARGE_FILES) # define SIZEOF_OFF_T 8 # endif # elif defined(__370__) && defined(__IBMC__) # if defined(_LP64) || defined(_LARGE_FILES) # define SIZEOF_OFF_T 8 # endif # endif # ifndef SIZEOF_OFF_T # define SIZEOF_OFF_T 4 # endif #endif #if (SIZEOF_CURL_OFF_T == 4) # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) #else /* assume CURL_SIZEOF_CURL_OFF_T == 8 */ # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) #endif #define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1)) #if (SIZEOF_TIME_T == 4) # ifdef HAVE_TIME_T_UNSIGNED # define TIME_T_MAX UINT_MAX # define TIME_T_MIN 0 # else # define TIME_T_MAX INT_MAX # define TIME_T_MIN INT_MIN # endif #else # ifdef HAVE_TIME_T_UNSIGNED # define TIME_T_MAX 0xFFFFFFFFFFFFFFFF # define TIME_T_MIN 0 # else # define TIME_T_MAX 0x7FFFFFFFFFFFFFFF # define TIME_T_MIN (-TIME_T_MAX - 1) # endif #endif #ifndef SIZE_T_MAX /* some limits.h headers have this defined, some don't */ #if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) #define SIZE_T_MAX 18446744073709551615U #else #define SIZE_T_MAX 4294967295U #endif #endif /* * Arg 2 type for gethostname in case it hasn't been defined in config file. */ #ifndef GETHOSTNAME_TYPE_ARG2 # ifdef USE_WINSOCK # define GETHOSTNAME_TYPE_ARG2 int # else # define GETHOSTNAME_TYPE_ARG2 size_t # endif #endif /* Below we define some functions. They should 4. set the SIGALRM signal timeout 5. set dir/file naming defines */ #ifdef WIN32 # define DIR_CHAR "\\" #else /* WIN32 */ # ifdef MSDOS /* Watt-32 */ # include # define select(n,r,w,x,t) select_s(n,r,w,x,t) # define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) # include # ifdef word # undef word # endif # ifdef byte # undef byte # endif # endif /* MSDOS */ # ifdef __minix /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */ extern char *strtok_r(char *s, const char *delim, char **last); extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp); # endif # define DIR_CHAR "/" # ifndef fileno /* sunos 4 have this as a macro! */ int fileno(FILE *stream); # endif #endif /* WIN32 */ /* * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN * defined in ws2tcpip.h as well as to provide IPv6 support. * Does not apply if lwIP is used. */ #if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK) # if !defined(HAVE_WS2TCPIP_H) || \ ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN)) # undef HAVE_GETADDRINFO_THREADSAFE # undef HAVE_FREEADDRINFO # undef HAVE_GETADDRINFO # undef HAVE_GETNAMEINFO # undef ENABLE_IPV6 # endif #endif /* ---------------------------------------------------------------- */ /* resolver specialty compile-time defines */ /* CURLRES_* defines to use in the host*.c sources */ /* ---------------------------------------------------------------- */ /* * lcc-win32 doesn't have _beginthreadex(), lacks threads support. */ #if defined(__LCC__) && defined(WIN32) # undef USE_THREADS_POSIX # undef USE_THREADS_WIN32 #endif /* * MSVC threads support requires a multi-threaded runtime library. * _beginthreadex() is not available in single-threaded ones. */ #if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT) # undef USE_THREADS_POSIX # undef USE_THREADS_WIN32 #endif /* * Mutually exclusive CURLRES_* definitions. */ #if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO) # define CURLRES_IPV6 #else # define CURLRES_IPV4 #endif #ifdef USE_ARES # define CURLRES_ASYNCH # define CURLRES_ARES /* now undef the stock libc functions just to avoid them being used */ # undef HAVE_GETADDRINFO # undef HAVE_FREEADDRINFO # undef HAVE_GETHOSTBYNAME #elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) # define CURLRES_ASYNCH # define CURLRES_THREADED #else # define CURLRES_SYNCH #endif /* ---------------------------------------------------------------- */ /* * When using WINSOCK, TELNET protocol requires WINSOCK2 API. */ #if defined(USE_WINSOCK) && (USE_WINSOCK != 2) # define CURL_DISABLE_TELNET 1 #endif /* * msvc 6.0 does not have struct sockaddr_storage and * does not define IPPROTO_ESP in winsock2.h. But both * are available if PSDK is properly installed. */ #if defined(_MSC_VER) && !defined(__POCC__) # if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP)) # undef HAVE_STRUCT_SOCKADDR_STORAGE # endif #endif /* * Intentionally fail to build when using msvc 6.0 without PSDK installed. * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK * in lib/config-win32.h although absolutely discouraged and unsupported. */ #if defined(_MSC_VER) && !defined(__POCC__) # if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_)) # if !defined(ALLOW_MSVC6_WITHOUT_PSDK) # error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \ "Windows Server 2003 PSDK" # else # define CURL_DISABLE_LDAP 1 # endif # endif #endif #ifdef NETWARE int netware_init(void); #ifndef __NOVELL_LIBC__ #include #include #endif #endif #if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN) /* The lib and header are present */ #define USE_LIBIDN2 #endif #if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN) #error "Both libidn2 and WinIDN are enabled, choose one." #endif #define LIBIDN_REQUIRED_VERSION "0.4.1" #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \ defined(USE_MBEDTLS) || \ defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \ defined(USE_BEARSSL) #define USE_SSL /* SSL support has been enabled */ #endif /* Single point where USE_SPNEGO definition might be defined */ #if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) #define USE_SPNEGO #endif /* Single point where USE_KERBEROS5 definition might be defined */ #if !defined(CURL_DISABLE_CRYPTO_AUTH) && \ (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) #define USE_KERBEROS5 #endif /* Single point where USE_NTLM definition might be defined */ #if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH) #if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ defined(USE_MBEDTLS) #define USE_NTLM # if defined(USE_MBEDTLS) /* Get definition of MBEDTLS_MD4_C */ # include # endif #endif #endif #ifdef CURL_WANTS_CA_BUNDLE_ENV #error "No longer supported. Set CURLOPT_CAINFO at runtime instead." #endif #if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH) #define USE_SSH #endif /* * Provide a mechanism to silence picky compilers, such as gcc 4.6+. * Parameters should of course normally not be unused, but for example when * we have multiple implementations of the same interface it may happen. */ #if defined(__GNUC__) && ((__GNUC__ >= 3) || \ ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) # define UNUSED_PARAM __attribute__((__unused__)) # define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else # define UNUSED_PARAM /*NOTHING*/ # define WARN_UNUSED_RESULT #endif /* * Include macros and defines that should only be processed once. */ #ifndef HEADER_CURL_SETUP_ONCE_H #include "curl_setup_once.h" #endif /* * Definition of our NOP statement Object-like macro */ #ifndef Curl_nop_stmt # define Curl_nop_stmt do { } while(0) #endif /* * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. */ #if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) # if defined(SOCKET) || \ defined(USE_WINSOCK) || \ defined(HAVE_WINSOCK_H) || \ defined(HAVE_WINSOCK2_H) || \ defined(HAVE_WS2TCPIP_H) # error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" # endif #endif /* * Portable symbolic names for Winsock shutdown() mode flags. */ #ifdef USE_WINSOCK # define SHUT_RD 0x00 # define SHUT_WR 0x01 # define SHUT_RDWR 0x02 #endif /* Define S_ISREG if not defined by system headers, f.e. MSVC */ #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* Define S_ISDIR if not defined by system headers, f.e. MSVC */ #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* In Windows the default file mode is text but an application can override it. Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 */ #if defined(WIN32) || defined(MSDOS) #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "wt" #define FOPEN_APPENDTEXT "at" #elif defined(__CYGWIN__) /* Cygwin has specific behavior we need to address when WIN32 is not defined. https://cygwin.com/cygwin-ug-net/using-textbinary.html For write we want our output to have line endings of LF and be compatible with other Cygwin utilities. For read we want to handle input that may have line endings either CRLF or LF so 't' is appropriate. */ #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "w" #define FOPEN_APPENDTEXT "a" #else #define FOPEN_READTEXT "r" #define FOPEN_WRITETEXT "w" #define FOPEN_APPENDTEXT "a" #endif /* WinSock destroys recv() buffer when send() failed. * Enabled automatically for Windows and for Cygwin as Cygwin sockets are * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657 * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround. */ #if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND) # if defined(WIN32) || defined(__CYGWIN__) # define USE_RECV_BEFORE_SEND_WORKAROUND # endif #else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */ # ifdef USE_RECV_BEFORE_SEND_WORKAROUND # undef USE_RECV_BEFORE_SEND_WORKAROUND # endif #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */ /* Detect Windows App environment which has a restricted access * to the Win32 APIs. */ # if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \ defined(WINAPI_FAMILY) # include # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define CURL_WINDOWS_APP # endif # endif /* for systems that don't detect this in configure, use a sensible default */ #ifndef CURL_SA_FAMILY_T #define CURL_SA_FAMILY_T unsigned short #endif /* Some convenience macros to get the larger/smaller value out of two given. We prefix with CURL to prevent name collisions. */ #define CURLMAX(x,y) ((x)>(y)?(x):(y)) #define CURLMIN(x,y) ((x)<(y)?(x):(y)) /* Some versions of the Android SDK is missing the declaration */ #if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING) struct passwd; int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result); #endif #ifdef DEBUGBUILD #define UNITTEST #else #define UNITTEST static #endif #if defined(USE_NGTCP2) || defined(USE_QUICHE) #define ENABLE_QUIC #endif #endif /* HEADER_CURL_SETUP_H */ davix-0.8.0/deps/curl/lib/strcase.h0000644000000000000000000000375514121063461015623 0ustar rootroot#ifndef HEADER_CURL_STRCASE_H #define HEADER_CURL_STRCASE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include /* * Only "raw" case insensitive strings. This is meant to be locale independent * and only compare strings we know are safe for this. * * The function is capable of comparing a-z case insensitively even for * non-ascii. */ #define strcasecompare(a,b) Curl_strcasecompare(a,b) #define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) int Curl_strcasecompare(const char *first, const char *second); int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); /* checkprefix() is a shorter version of the above, used when the first argument is zero-byte terminated */ #define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) void Curl_strntoupper(char *dest, const char *src, size_t n); void Curl_strntolower(char *dest, const char *src, size_t n); #endif /* HEADER_CURL_STRCASE_H */ davix-0.8.0/deps/curl/lib/conncache.c0000644000000000000000000003775414121063461016101 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "url.h" #include "progress.h" #include "multiif.h" #include "sendf.h" #include "conncache.h" #include "share.h" #include "sigpipe.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define HASHKEY_SIZE 128 static void conn_llist_dtor(void *user, void *element) { struct connectdata *conn = element; (void)user; conn->bundle = NULL; } static CURLcode bundle_create(struct Curl_easy *data, struct connectbundle **cb_ptr) { (void)data; DEBUGASSERT(*cb_ptr == NULL); *cb_ptr = malloc(sizeof(struct connectbundle)); if(!*cb_ptr) return CURLE_OUT_OF_MEMORY; (*cb_ptr)->num_connections = 0; (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); return CURLE_OK; } static void bundle_destroy(struct connectbundle *cb_ptr) { if(!cb_ptr) return; Curl_llist_destroy(&cb_ptr->conn_list, NULL); free(cb_ptr); } /* Add a connection to a bundle */ static void bundle_add_conn(struct connectbundle *cb_ptr, struct connectdata *conn) { Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn, &conn->bundle_node); conn->bundle = cb_ptr; cb_ptr->num_connections++; } /* Remove a connection from a bundle */ static int bundle_remove_conn(struct connectbundle *cb_ptr, struct connectdata *conn) { struct curl_llist_element *curr; curr = cb_ptr->conn_list.head; while(curr) { if(curr->ptr == conn) { Curl_llist_remove(&cb_ptr->conn_list, curr, NULL); cb_ptr->num_connections--; conn->bundle = NULL; return 1; /* we removed a handle */ } curr = curr->next; } DEBUGASSERT(0); return 0; } static void free_bundle_hash_entry(void *freethis) { struct connectbundle *b = (struct connectbundle *) freethis; bundle_destroy(b); } int Curl_conncache_init(struct conncache *connc, int size) { int rc; /* allocate a new easy handle to use when closing cached connections */ connc->closure_handle = curl_easy_init(); if(!connc->closure_handle) return 1; /* bad */ rc = Curl_hash_init(&connc->hash, size, Curl_hash_str, Curl_str_key_compare, free_bundle_hash_entry); if(rc) Curl_close(&connc->closure_handle); else connc->closure_handle->state.conn_cache = connc; return rc; } void Curl_conncache_destroy(struct conncache *connc) { if(connc) Curl_hash_destroy(&connc->hash); } /* creates a key to find a bundle for this connection */ static void hashkey(struct connectdata *conn, char *buf, size_t len, /* something like 128 is fine */ const char **hostp) { const char *hostname; long port = conn->remote_port; if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { hostname = conn->http_proxy.host.name; port = conn->port; } else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; if(hostp) /* report back which name we used */ *hostp = hostname; /* put the number first so that the hostname gets cut off if too long */ msnprintf(buf, len, "%ld%s", port, hostname); } void Curl_conncache_unlock(struct Curl_easy *data) { CONN_UNLOCK(data); } /* Returns number of connections currently held in the connection cache. Locks/unlocks the cache itself! */ size_t Curl_conncache_size(struct Curl_easy *data) { size_t num; CONN_LOCK(data); num = data->state.conn_cache->num_conn; CONN_UNLOCK(data); return num; } /* Look up the bundle with all the connections to the same host this connectdata struct is setup to use. **NOTE**: When it returns, it holds the connection cache lock! */ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, struct conncache *connc, const char **hostp) { struct connectbundle *bundle = NULL; CONN_LOCK(conn->data); if(connc) { char key[HASHKEY_SIZE]; hashkey(conn, key, sizeof(key), hostp); bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); } return bundle; } static bool conncache_add_bundle(struct conncache *connc, char *key, struct connectbundle *bundle) { void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle); return p?TRUE:FALSE; } static void conncache_remove_bundle(struct conncache *connc, struct connectbundle *bundle) { struct curl_hash_iterator iter; struct curl_hash_element *he; if(!connc) return; Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { if(he->ptr == bundle) { /* The bundle is destroyed by the hash destructor function, free_bundle_hash_entry() */ Curl_hash_delete(&connc->hash, he->key, he->key_len); return; } he = Curl_hash_next_element(&iter); } } CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectdata *conn) { CURLcode result = CURLE_OK; struct connectbundle *bundle; struct connectbundle *new_bundle = NULL; struct Curl_easy *data = conn->data; /* *find_bundle() locks the connection cache */ bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, NULL); if(!bundle) { int rc; char key[HASHKEY_SIZE]; result = bundle_create(data, &new_bundle); if(result) { goto unlock; } hashkey(conn, key, sizeof(key), NULL); rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); if(!rc) { bundle_destroy(new_bundle); result = CURLE_OUT_OF_MEMORY; goto unlock; } bundle = new_bundle; } bundle_add_conn(bundle, conn); conn->connection_id = connc->next_connection_id++; connc->num_conn++; DEBUGF(infof(conn->data, "Added connection %ld. " "The cache now contains %zu members\n", conn->connection_id, connc->num_conn)); unlock: CONN_UNLOCK(data); return result; } /* * Removes the connectdata object from the connection cache *and* clears the * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument * depending on if the parent function already holds the lock or not. */ void Curl_conncache_remove_conn(struct Curl_easy *data, struct connectdata *conn, bool lock) { struct connectbundle *bundle = conn->bundle; struct conncache *connc = data->state.conn_cache; /* The bundle pointer can be NULL, since this function can be called due to a failed connection attempt, before being added to a bundle */ if(bundle) { if(lock) { CONN_LOCK(data); } bundle_remove_conn(bundle, conn); if(bundle->num_connections == 0) conncache_remove_bundle(connc, bundle); conn->bundle = NULL; /* removed from it */ if(connc) { connc->num_conn--; DEBUGF(infof(data, "The cache now contains %zu members\n", connc->num_conn)); } conn->data = NULL; /* clear the association */ if(lock) { CONN_UNLOCK(data); } } } /* This function iterates the entire connection cache and calls the function func() with the connection pointer as the first argument and the supplied 'param' argument as the other. The conncache lock is still held when the callback is called. It needs it, so that it can safely continue traversing the lists once the callback returns. Returns 1 if the loop was aborted due to the callback's return code. Return 0 from func() to continue the loop, return 1 to abort it. */ bool Curl_conncache_foreach(struct Curl_easy *data, struct conncache *connc, void *param, int (*func)(struct connectdata *conn, void *param)) { struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; if(!connc) return FALSE; CONN_LOCK(data); Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { struct connectbundle *bundle; bundle = he->ptr; he = Curl_hash_next_element(&iter); curr = bundle->conn_list.head; while(curr) { /* Yes, we need to update curr before calling func(), because func() might decide to remove the connection */ struct connectdata *conn = curr->ptr; curr = curr->next; if(1 == func(conn, param)) { CONN_UNLOCK(data); return TRUE; } } } CONN_UNLOCK(data); return FALSE; } /* Return the first connection found in the cache. Used when closing all connections. NOTE: no locking is done here as this is presumably only done when cleaning up a cache! */ static struct connectdata * conncache_find_first_connection(struct conncache *connc) { struct curl_hash_iterator iter; struct curl_hash_element *he; struct connectbundle *bundle; Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { struct curl_llist_element *curr; bundle = he->ptr; curr = bundle->conn_list.head; if(curr) { return curr->ptr; } he = Curl_hash_next_element(&iter); } return NULL; } /* * Give ownership of a connection back to the connection cache. Might * disconnect the oldest existing in there to make space. * * Return TRUE if stored, FALSE if closed. */ bool Curl_conncache_return_conn(struct Curl_easy *data, struct connectdata *conn) { /* data->multi->maxconnects can be negative, deal with it. */ size_t maxconnects = (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: data->multi->maxconnects; struct connectdata *conn_candidate = NULL; conn->lastused = Curl_now(); /* it was used up until now */ if(maxconnects > 0 && Curl_conncache_size(data) > maxconnects) { infof(data, "Connection cache is full, closing the oldest one.\n"); conn_candidate = Curl_conncache_extract_oldest(data); if(conn_candidate) { /* the winner gets the honour of being disconnected */ (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE); } } return (conn_candidate == conn) ? FALSE : TRUE; } /* * This function finds the connection in the connection bundle that has been * unused for the longest time. * * Does not lock the connection cache! * * Returns the pointer to the oldest idle connection, or NULL if none was * found. */ struct connectdata * Curl_conncache_extract_bundle(struct Curl_easy *data, struct connectbundle *bundle) { struct curl_llist_element *curr; timediff_t highscore = -1; timediff_t score; struct curltime now; struct connectdata *conn_candidate = NULL; struct connectdata *conn; (void)data; now = Curl_now(); curr = bundle->conn_list.head; while(curr) { conn = curr->ptr; if(!CONN_INUSE(conn) && !conn->data) { /* Set higher score for the age passed since the connection was used */ score = Curl_timediff(now, conn->lastused); if(score > highscore) { highscore = score; conn_candidate = conn; } } curr = curr->next; } if(conn_candidate) { /* remove it to prevent another thread from nicking it */ bundle_remove_conn(bundle, conn_candidate); data->state.conn_cache->num_conn--; DEBUGF(infof(data, "The cache now contains %zu members\n", data->state.conn_cache->num_conn)); conn_candidate->data = data; /* associate! */ } return conn_candidate; } /* * This function finds the connection in the connection cache that has been * unused for the longest time and extracts that from the bundle. * * Returns the pointer to the connection, or NULL if none was found. */ struct connectdata * Curl_conncache_extract_oldest(struct Curl_easy *data) { struct conncache *connc = data->state.conn_cache; struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; timediff_t highscore =- 1; timediff_t score; struct curltime now; struct connectdata *conn_candidate = NULL; struct connectbundle *bundle; struct connectbundle *bundle_candidate = NULL; now = Curl_now(); CONN_LOCK(data); Curl_hash_start_iterate(&connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { struct connectdata *conn; bundle = he->ptr; curr = bundle->conn_list.head; while(curr) { conn = curr->ptr; if(!CONN_INUSE(conn) && !conn->data && !conn->bits.close && !conn->bits.connect_only) { /* Set higher score for the age passed since the connection was used */ score = Curl_timediff(now, conn->lastused); if(score > highscore) { highscore = score; conn_candidate = conn; bundle_candidate = bundle; } } curr = curr->next; } he = Curl_hash_next_element(&iter); } if(conn_candidate) { /* remove it to prevent another thread from nicking it */ bundle_remove_conn(bundle_candidate, conn_candidate); connc->num_conn--; DEBUGF(infof(data, "The cache now contains %zu members\n", connc->num_conn)); conn_candidate->data = data; /* associate! */ } CONN_UNLOCK(data); return conn_candidate; } void Curl_conncache_close_all_connections(struct conncache *connc) { struct connectdata *conn; conn = conncache_find_first_connection(connc); while(conn) { SIGPIPE_VARIABLE(pipe_st); conn->data = connc->closure_handle; sigpipe_ignore(conn->data, &pipe_st); /* This will remove the connection from the cache */ connclose(conn, "kill all"); (void)Curl_disconnect(connc->closure_handle, conn, FALSE); sigpipe_restore(&pipe_st); conn = conncache_find_first_connection(connc); } if(connc->closure_handle) { SIGPIPE_VARIABLE(pipe_st); sigpipe_ignore(connc->closure_handle, &pipe_st); Curl_hostcache_clean(connc->closure_handle, connc->closure_handle->dns.hostcache); Curl_close(&connc->closure_handle); sigpipe_restore(&pipe_st); } } #if 0 /* Useful for debugging the connection cache */ void Curl_conncache_print(struct conncache *connc) { struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; if(!connc) return; fprintf(stderr, "=Bundle cache=\n"); Curl_hash_start_iterate(connc->hash, &iter); he = Curl_hash_next_element(&iter); while(he) { struct connectbundle *bundle; struct connectdata *conn; bundle = he->ptr; fprintf(stderr, "%s -", he->key); curr = bundle->conn_list->head; while(curr) { conn = curr->ptr; fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); curr = curr->next; } fprintf(stderr, "\n"); he = Curl_hash_next_element(&iter); } } #endif davix-0.8.0/deps/curl/lib/curl_endian.c0000644000000000000000000000710014121063461016421 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "curl_endian.h" /* * Curl_read16_le() * * This function converts a 16-bit integer from the little endian format, as * used in the incoming package to whatever endian format we're using * natively. * * Parameters: * * buf [in] - A pointer to a 2 byte buffer. * * Returns the integer. */ unsigned short Curl_read16_le(const unsigned char *buf) { return (unsigned short)(((unsigned short)buf[0]) | ((unsigned short)buf[1] << 8)); } /* * Curl_read32_le() * * This function converts a 32-bit integer from the little endian format, as * used in the incoming package to whatever endian format we're using * natively. * * Parameters: * * buf [in] - A pointer to a 4 byte buffer. * * Returns the integer. */ unsigned int Curl_read32_le(const unsigned char *buf) { return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); } /* * Curl_read16_be() * * This function converts a 16-bit integer from the big endian format, as * used in the incoming package to whatever endian format we're using * natively. * * Parameters: * * buf [in] - A pointer to a 2 byte buffer. * * Returns the integer. */ unsigned short Curl_read16_be(const unsigned char *buf) { return (unsigned short)(((unsigned short)buf[0] << 8) | ((unsigned short)buf[1])); } #if (CURL_SIZEOF_CURL_OFF_T > 4) /* * write32_le() * * This function converts a 32-bit integer from the native endian format, * to little endian format ready for sending down the wire. * * Parameters: * * value [in] - The 32-bit integer value. * buffer [in] - A pointer to the output buffer. */ static void write32_le(const int value, unsigned char *buffer) { buffer[0] = (char)(value & 0x000000FF); buffer[1] = (char)((value & 0x0000FF00) >> 8); buffer[2] = (char)((value & 0x00FF0000) >> 16); buffer[3] = (char)((value & 0xFF000000) >> 24); } /* * Curl_write64_le() * * This function converts a 64-bit integer from the native endian format, * to little endian format ready for sending down the wire. * * Parameters: * * value [in] - The 64-bit integer value. * buffer [in] - A pointer to the output buffer. */ #if defined(HAVE_LONGLONG) void Curl_write64_le(const long long value, unsigned char *buffer) #else void Curl_write64_le(const __int64 value, unsigned char *buffer) #endif { write32_le((int)value, buffer); write32_le((int)(value >> 32), buffer + 4); } #endif /* CURL_SIZEOF_CURL_OFF_T > 4 */ davix-0.8.0/deps/curl/lib/inet_ntop.c0000644000000000000000000001243714121063461016146 0ustar rootroot/* * Copyright (C) 1996-2019 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Original code by Paul Vixie. "curlified" by Gisle Vanem. */ #include "curl_setup.h" #ifndef HAVE_INET_NTOP #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include "inet_ntop.h" #include "curl_printf.h" #define IN6ADDRSZ 16 #define INADDRSZ 4 #define INT16SZ 2 /* * Format an IPv4 address, more or less like inet_ntoa(). * * Returns `dst' (as a const) * Note: * - uses no statics * - takes a unsigned char* not an in_addr as input */ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) { char tmp[sizeof("255.255.255.255")]; size_t len; DEBUGASSERT(size >= 16); tmp[0] = '\0'; (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", ((int)((unsigned char)src[0])) & 0xff, ((int)((unsigned char)src[1])) & 0xff, ((int)((unsigned char)src[2])) & 0xff, ((int)((unsigned char)src[3])) & 0xff); len = strlen(tmp); if(len == 0 || len >= size) { errno = ENOSPC; return (NULL); } strcpy(dst, tmp); return dst; } #ifdef ENABLE_IPV6 /* * Convert IPv6 binary address into presentation (printable) format. */ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char *tp; struct { long base; long len; } best, cur; unsigned long words[IN6ADDRSZ / INT16SZ]; int i; /* Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof(words)); for(i = 0; i < IN6ADDRSZ; i++) words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; best.len = 0; cur.len = 0; for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { if(words[i] == 0) { if(cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else if(cur.base != -1) { if(best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } if((cur.base != -1) && (best.base == -1 || cur.len > best.len)) best = cur; if(best.base != -1 && best.len < 2) best.base = -1; /* Format the result. */ tp = tmp; for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ if(best.base != -1 && i >= best.base && i < (best.base + best.len)) { if(i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if(i != 0) *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if(i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) { errno = ENOSPC; return (NULL); } tp += strlen(tp); break; } tp += msnprintf(tp, 5, "%lx", words[i]); } /* Was it a trailing run of 0x00's? */ if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) *tp++ = ':'; *tp++ = '\0'; /* Check for overflow, copy, and we're done. */ if((size_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } strcpy(dst, tmp); return dst; } #endif /* ENABLE_IPV6 */ /* * Convert a network format address to presentation format. * * Returns pointer to presentation format address (`buf'). * Returns NULL on error and errno set with the specific * error, EAFNOSUPPORT or ENOSPC. * * On Windows we store the error in the thread errno, not * in the winsock error code. This is to avoid losing the * actual last winsock error. So when this function returns * NULL, check errno not SOCKERRNO. */ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) { switch(af) { case AF_INET: return inet_ntop4((const unsigned char *)src, buf, size); #ifdef ENABLE_IPV6 case AF_INET6: return inet_ntop6((const unsigned char *)src, buf, size); #endif default: errno = EAFNOSUPPORT; return NULL; } } #endif /* HAVE_INET_NTOP */ davix-0.8.0/deps/curl/lib/asyn-thread.c0000644000000000000000000004714714121063461016374 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "socketpair.h" /*********************************************************************** * Only for threaded name resolves builds **********************************************************************/ #ifdef CURLRES_THREADED #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #if defined(USE_THREADS_POSIX) # ifdef HAVE_PTHREAD_H # include # endif #elif defined(USE_THREADS_WIN32) # ifdef HAVE_PROCESS_H # include # endif #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #ifdef HAVE_GETADDRINFO # define RESOLVER_ENOMEM EAI_MEMORY #else # define RESOLVER_ENOMEM ENOMEM #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" #include "multiif.h" #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" #include "socketpair.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" struct resdata { struct curltime start; }; /* * Curl_resolver_global_init() * Called from curl_global_init() to initialize global resolver environment. * Does nothing here. */ int Curl_resolver_global_init(void) { return CURLE_OK; } /* * Curl_resolver_global_cleanup() * Called from curl_global_cleanup() to destroy global resolver environment. * Does nothing here. */ void Curl_resolver_global_cleanup(void) { } /* * Curl_resolver_init() * Called from curl_easy_init() -> Curl_open() to initialize resolver * URL-state specific environment ('resolver' member of the UrlState * structure). */ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) { (void)easy; *resolver = calloc(1, sizeof(struct resdata)); if(!*resolver) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } /* * Curl_resolver_cleanup() * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver * URL-state specific environment ('resolver' member of the UrlState * structure). */ void Curl_resolver_cleanup(void *resolver) { free(resolver); } /* * Curl_resolver_duphandle() * Called from curl_easy_duphandle() to duplicate resolver URL state-specific * environment ('resolver' member of the UrlState structure). */ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) { (void)from; return Curl_resolver_init(easy, to); } static void destroy_async_data(struct Curl_async *); /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_resolver_cancel(struct connectdata *conn) { destroy_async_data(&conn->async); } /* This function is used to init a threaded resolve */ static bool init_resolve_thread(struct connectdata *conn, const char *hostname, int port, const struct addrinfo *hints); /* Data for synchronization between resolver thread and its parent */ struct thread_sync_data { curl_mutex_t * mtx; int done; char *hostname; /* hostname to resolve, Curl_async.hostname duplicate */ int port; #ifdef USE_SOCKETPAIR struct connectdata *conn; curl_socket_t sock_pair[2]; /* socket pair */ #endif int sock_error; Curl_addrinfo *res; #ifdef HAVE_GETADDRINFO struct addrinfo hints; #endif struct thread_data *td; /* for thread-self cleanup */ }; struct thread_data { curl_thread_t thread_hnd; unsigned int poll_interval; time_t interval_end; struct thread_sync_data tsd; }; static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn) { return &(((struct thread_data *)conn->async.os_specific)->tsd); } /* Destroy resolver thread synchronization data */ static void destroy_thread_sync_data(struct thread_sync_data * tsd) { if(tsd->mtx) { Curl_mutex_destroy(tsd->mtx); free(tsd->mtx); } free(tsd->hostname); if(tsd->res) Curl_freeaddrinfo(tsd->res); #ifdef USE_SOCKETPAIR /* * close one end of the socket pair (may be done in resolver thread); * the other end (for reading) is always closed in the parent thread. */ if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { sclose(tsd->sock_pair[1]); } #endif memset(tsd, 0, sizeof(*tsd)); } /* Initialize resolver thread synchronization data */ static int init_thread_sync_data(struct thread_data * td, const char *hostname, int port, const struct addrinfo *hints) { struct thread_sync_data *tsd = &td->tsd; memset(tsd, 0, sizeof(*tsd)); tsd->td = td; tsd->port = port; /* Treat the request as done until the thread actually starts so any early * cleanup gets done properly. */ tsd->done = 1; #ifdef HAVE_GETADDRINFO DEBUGASSERT(hints); tsd->hints = *hints; #else (void) hints; #endif tsd->mtx = malloc(sizeof(curl_mutex_t)); if(tsd->mtx == NULL) goto err_exit; Curl_mutex_init(tsd->mtx); #ifdef USE_SOCKETPAIR /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */ if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) { tsd->sock_pair[0] = CURL_SOCKET_BAD; tsd->sock_pair[1] = CURL_SOCKET_BAD; goto err_exit; } #endif tsd->sock_error = CURL_ASYNC_SUCCESS; /* Copying hostname string because original can be destroyed by parent * thread during gethostbyname execution. */ tsd->hostname = strdup(hostname); if(!tsd->hostname) goto err_exit; return 1; err_exit: /* Memory allocation failed */ destroy_thread_sync_data(tsd); return 0; } static int getaddrinfo_complete(struct connectdata *conn) { struct thread_sync_data *tsd = conn_thread_sync_data(conn); int rc; rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res); /* The tsd->res structure has been copied to async.dns and perhaps the DNS cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it. */ tsd->res = NULL; return rc; } #ifdef HAVE_GETADDRINFO /* * getaddrinfo_thread() resolves a name and then exits. * * For builds without ARES, but with ENABLE_IPV6, create a resolver thread * and wait on it. */ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data*)arg; struct thread_data *td = tsd->td; char service[12]; int rc; #ifdef USE_SOCKETPAIR char buf[1]; #endif msnprintf(service, sizeof(service), "%d", tsd->port); rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); if(rc != 0) { tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } else { Curl_addrinfo_set_port(tsd->res, tsd->port); } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { /* too late, gotta clean up the mess */ Curl_mutex_release(tsd->mtx); destroy_thread_sync_data(tsd); free(td); } else { #ifdef USE_SOCKETPAIR if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { /* DNS has been resolved, signal client task */ buf[0] = 1; if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) { /* update sock_erro to errno */ tsd->sock_error = SOCKERRNO; } } #endif tsd->done = 1; Curl_mutex_release(tsd->mtx); } return 0; } #else /* HAVE_GETADDRINFO */ /* * gethostbyname_thread() resolves a name and then exits. */ static unsigned int CURL_STDCALL gethostbyname_thread(void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data *)arg; struct thread_data *td = tsd->td; tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); if(!tsd->res) { tsd->sock_error = SOCKERRNO; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { /* too late, gotta clean up the mess */ Curl_mutex_release(tsd->mtx); destroy_thread_sync_data(tsd); free(td); } else { tsd->done = 1; Curl_mutex_release(tsd->mtx); } return 0; } #endif /* HAVE_GETADDRINFO */ /* * destroy_async_data() cleans up async resolver data and thread handle. */ static void destroy_async_data(struct Curl_async *async) { if(async->os_specific) { struct thread_data *td = (struct thread_data*) async->os_specific; int done; #ifdef USE_SOCKETPAIR curl_socket_t sock_rd = td->tsd.sock_pair[0]; struct connectdata *conn = td->tsd.conn; #endif /* * if the thread is still blocking in the resolve syscall, detach it and * let the thread do the cleanup... */ Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; td->tsd.done = 1; Curl_mutex_release(td->tsd.mtx); if(!done) { Curl_thread_destroy(td->thread_hnd); } else { if(td->thread_hnd != curl_thread_t_null) Curl_thread_join(&td->thread_hnd); destroy_thread_sync_data(&td->tsd); free(async->os_specific); } #ifdef USE_SOCKETPAIR /* * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL */ if(conn) Curl_multi_closed(conn->data, sock_rd); sclose(sock_rd); #endif } async->os_specific = NULL; free(async->hostname); async->hostname = NULL; } /* * init_resolve_thread() starts a new thread that performs the actual * resolve. This function returns before the resolve is done. * * Returns FALSE in case of failure, otherwise TRUE. */ static bool init_resolve_thread(struct connectdata *conn, const char *hostname, int port, const struct addrinfo *hints) { struct thread_data *td = calloc(1, sizeof(struct thread_data)); int err = ENOMEM; conn->async.os_specific = (void *)td; if(!td) goto errno_exit; conn->async.port = port; conn->async.done = FALSE; conn->async.status = 0; conn->async.dns = NULL; td->thread_hnd = curl_thread_t_null; if(!init_thread_sync_data(td, hostname, port, hints)) { conn->async.os_specific = NULL; free(td); goto errno_exit; } free(conn->async.hostname); conn->async.hostname = strdup(hostname); if(!conn->async.hostname) goto err_exit; /* The thread will set this to 1 when complete. */ td->tsd.done = 0; #ifdef HAVE_GETADDRINFO td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); #else td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd); #endif if(!td->thread_hnd) { /* The thread never started, so mark it as done here for proper cleanup. */ td->tsd.done = 1; err = errno; goto err_exit; } return TRUE; err_exit: destroy_async_data(&conn->async); errno_exit: errno = err; return FALSE; } /* * resolver_error() calls failf() with the appropriate message after a resolve * error */ static CURLcode resolver_error(struct connectdata *conn) { const char *host_or_proxy; CURLcode result; if(conn->bits.httpproxy) { host_or_proxy = "proxy"; result = CURLE_COULDNT_RESOLVE_PROXY; } else { host_or_proxy = "host"; result = CURLE_COULDNT_RESOLVE_HOST; } failf(conn->data, "Could not resolve %s: %s", host_or_proxy, conn->async.hostname); return result; } static CURLcode thread_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry, bool report) { struct thread_data *td = (struct thread_data*) conn->async.os_specific; CURLcode result = CURLE_OK; DEBUGASSERT(conn && td); DEBUGASSERT(td->thread_hnd != curl_thread_t_null); /* wait for the thread to resolve the name */ if(Curl_thread_join(&td->thread_hnd)) { if(entry) result = getaddrinfo_complete(conn); } else DEBUGASSERT(0); conn->async.done = TRUE; if(entry) *entry = conn->async.dns; if(!conn->async.dns && report) /* a name was not resolved, report error */ result = resolver_error(conn); destroy_async_data(&conn->async); if(!conn->async.dns && report) connclose(conn, "asynch resolve failed"); return result; } /* * Until we gain a way to signal the resolver threads to stop early, we must * simply wait for them and ignore their results. */ void Curl_resolver_kill(struct connectdata *conn) { struct thread_data *td = (struct thread_data*) conn->async.os_specific; /* If we're still resolving, we must wait for the threads to fully clean up, unfortunately. Otherwise, we can simply cancel to clean up any resolver data. */ if(td && td->thread_hnd != curl_thread_t_null) (void)thread_wait_resolv(conn, NULL, FALSE); else Curl_resolver_cancel(conn); } /* * Curl_resolver_wait_resolv() * * Waits for a resolve to finish. This function should be avoided since using * this risk getting the multi interface to "hang". * * If 'entry' is non-NULL, make it point to the resolved dns entry * * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. * * This is the version for resolves-in-a-thread. */ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { return thread_wait_resolv(conn, entry, TRUE); } /* * Curl_resolver_is_resolved() is called repeatedly to check if a previous * name resolve request has completed. It should also make sure to time-out if * the operation seems to take too long. */ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **entry) { struct Curl_easy *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; *entry = NULL; if(!td) { DEBUGASSERT(td); return CURLE_COULDNT_RESOLVE_HOST; } Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; Curl_mutex_release(td->tsd.mtx); if(done) { getaddrinfo_complete(conn); if(!conn->async.dns) { CURLcode result = resolver_error(conn); destroy_async_data(&conn->async); return result; } destroy_async_data(&conn->async); *entry = conn->async.dns; } else { /* poll for name lookup done with exponential backoff up to 250ms */ /* should be fine even if this converts to 32 bit */ time_t elapsed = (time_t)Curl_timediff(Curl_now(), data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; if(td->poll_interval == 0) /* Start at 1ms poll interval */ td->poll_interval = 1; else if(elapsed >= td->interval_end) /* Back-off exponentially if last interval expired */ td->poll_interval *= 2; if(td->poll_interval > 250) td->poll_interval = 250; td->interval_end = elapsed + td->poll_interval; Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME); } return CURLE_OK; } int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *socks) { int ret_val = 0; time_t milli; timediff_t ms; struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; #ifdef USE_SOCKETPAIR struct thread_data *td = (struct thread_data*)conn->async.os_specific; #else (void)socks; #endif #ifdef USE_SOCKETPAIR if(td) { /* return read fd to client for polling the DNS resolution status */ socks[0] = td->tsd.sock_pair[0]; DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn); td->tsd.conn = conn; ret_val = GETSOCK_READSOCK(0); } else { #endif ms = Curl_timediff(Curl_now(), reslv->start); if(ms < 3) milli = 0; else if(ms <= 50) milli = (time_t)ms/3; else if(ms <= 250) milli = 50; else milli = 200; Curl_expire(data, milli, EXPIRE_ASYNC_NAME); #ifdef USE_SOCKETPAIR } #endif return ret_val; } #ifndef HAVE_GETADDRINFO /* * Curl_getaddrinfo() - for platforms without getaddrinfo */ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; *waitp = 0; /* default to synchronous response */ reslv->start = Curl_now(); /* fire up a new resolver thread! */ if(init_resolve_thread(conn, hostname, port, NULL)) { *waitp = 1; /* expect asynchronous response */ return NULL; } failf(conn->data, "getaddrinfo() thread failed\n"); return NULL; } #else /* !HAVE_GETADDRINFO */ /* * Curl_resolver_getaddrinfo() - for getaddrinfo */ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { struct addrinfo hints; int pf = PF_INET; struct Curl_easy *data = conn->data; struct resdata *reslv = (struct resdata *)data->state.resolver; *waitp = 0; /* default to synchronous response */ #ifdef CURLRES_IPV6 /* * Check if a limited name resolve has been requested. */ switch(conn->ip_version) { case CURL_IPRESOLVE_V4: pf = PF_INET; break; case CURL_IPRESOLVE_V6: pf = PF_INET6; break; default: pf = PF_UNSPEC; break; } if((pf != PF_INET) && !Curl_ipv6works(conn)) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; #endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; hints.ai_socktype = (conn->transport == TRNSPRT_TCP)? SOCK_STREAM : SOCK_DGRAM; reslv->start = Curl_now(); /* fire up a new resolver thread! */ if(init_resolve_thread(conn, hostname, port, &hints)) { *waitp = 1; /* expect asynchronous response */ return NULL; } failf(data, "getaddrinfo() thread failed to start\n"); return NULL; } #endif /* !HAVE_GETADDRINFO */ CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; (void)servers; return CURLE_NOT_BUILT_IN; } CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; (void)interf; return CURLE_NOT_BUILT_IN; } CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; (void)local_ip4; return CURLE_NOT_BUILT_IN; } CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; (void)local_ip6; return CURLE_NOT_BUILT_IN; } #endif /* CURLRES_THREADED */ davix-0.8.0/deps/curl/lib/getenv.c0000644000000000000000000000437414121063461015440 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "curl_memory.h" #include "memdebug.h" static char *GetEnv(const char *variable) { #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) (void)variable; return NULL; #elif defined(WIN32) /* This uses Windows API instead of C runtime getenv() to get the environment variable since some changes aren't always visible to the latter. #4774 */ char *buf = NULL; char *tmp; DWORD bufsize; DWORD rc = 1; const DWORD max = 32768; /* max env var size from MSCRT source */ for(;;) { tmp = realloc(buf, rc); if(!tmp) { free(buf); return NULL; } buf = tmp; bufsize = rc; /* It's possible for rc to be 0 if the variable was found but empty. Since getenv doesn't make that distinction we ignore it as well. */ rc = GetEnvironmentVariableA(variable, buf, bufsize); if(!rc || rc == bufsize || rc > max) { free(buf); return NULL; } /* if rc < bufsize then rc is bytes written not including null */ if(rc < bufsize) return buf; /* else rc is bytes needed, try again */ } #else char *env = getenv(variable); return (env && env[0])?strdup(env):NULL; #endif } char *curl_getenv(const char *v) { return GetEnv(v); } davix-0.8.0/deps/curl/lib/telnet.c0000644000000000000000000013401114121063461015433 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_TELNET #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "telnet.h" #include "connect.h" #include "progress.h" #include "system_win32.h" #include "arpa_telnet.h" #include "select.h" #include "strcase.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define SUBBUFSIZE 512 #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer #define CURL_SB_TERM(x) \ do { \ x->subend = x->subpointer; \ CURL_SB_CLEAR(x); \ } while(0) #define CURL_SB_ACCUM(x,c) \ do { \ if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer))) \ *x->subpointer++ = (c); \ } while(0) #define CURL_SB_GET(x) ((*x->subpointer++)&0xff) #define CURL_SB_LEN(x) (x->subend - x->subpointer) /* For posterity: #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) #define CURL_SB_EOF(x) (x->subpointer >= x->subend) */ #ifdef CURL_DISABLE_VERBOSE_STRINGS #define printoption(a,b,c,d) Curl_nop_stmt #endif #ifdef USE_WINSOCK typedef WSAEVENT (WINAPI *WSOCK2_EVENT)(void); typedef FARPROC WSOCK2_FUNC; static CURLcode check_wsock2(struct Curl_easy *data); #endif static CURLcode telrcv(struct connectdata *, const unsigned char *inbuf, /* Data received from socket */ ssize_t count); /* Number of bytes received */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option); #endif static void negotiate(struct connectdata *); static void send_negotiation(struct connectdata *, int cmd, int option); static void set_local_option(struct connectdata *conn, int option, int newstate); static void set_remote_option(struct connectdata *conn, int option, int newstate); static void printsub(struct Curl_easy *data, int direction, unsigned char *pointer, size_t length); static void suboption(struct connectdata *); static void sendsuboption(struct connectdata *conn, int option); static CURLcode telnet_do(struct connectdata *conn, bool *done); static CURLcode telnet_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode send_telnet_data(struct connectdata *conn, char *buffer, ssize_t nread); /* For negotiation compliant to RFC 1143 */ #define CURL_NO 0 #define CURL_YES 1 #define CURL_WANTYES 2 #define CURL_WANTNO 3 #define CURL_EMPTY 0 #define CURL_OPPOSITE 1 /* * Telnet receiver states for fsm */ typedef enum { CURL_TS_DATA = 0, CURL_TS_IAC, CURL_TS_WILL, CURL_TS_WONT, CURL_TS_DO, CURL_TS_DONT, CURL_TS_CR, CURL_TS_SB, /* sub-option collection */ CURL_TS_SE /* looking for sub-option end */ } TelnetReceive; struct TELNET { int please_negotiate; int already_negotiated; int us[256]; int usq[256]; int us_preferred[256]; int him[256]; int himq[256]; int him_preferred[256]; int subnegotiation[256]; char subopt_ttype[32]; /* Set with suboption TTYPE */ char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ unsigned short subopt_wsx; /* Set with suboption NAWS */ unsigned short subopt_wsy; /* Set with suboption NAWS */ struct curl_slist *telnet_vars; /* Environment variables */ /* suboptions */ unsigned char subbuffer[SUBBUFSIZE]; unsigned char *subpointer, *subend; /* buffer for sub-options */ TelnetReceive telrcv_state; }; /* * TELNET protocol handler. */ const struct Curl_handler Curl_handler_telnet = { "TELNET", /* scheme */ ZERO_NULL, /* setup_connection */ telnet_do, /* do_it */ telnet_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_TELNET, /* defport */ CURLPROTO_TELNET, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; #ifdef USE_WINSOCK static CURLcode check_wsock2(struct Curl_easy *data) { int err; WORD wVersionRequested; WSADATA wsaData; DEBUGASSERT(data); /* telnet requires at least WinSock 2.0 so ask for it. */ wVersionRequested = MAKEWORD(2, 0); err = WSAStartup(wVersionRequested, &wsaData); /* We must've called this once already, so this call */ /* should always succeed. But, just in case... */ if(err != 0) { failf(data,"WSAStartup failed (%d)",err); return CURLE_FAILED_INIT; } /* We have to have a WSACleanup call for every successful */ /* WSAStartup call. */ WSACleanup(); /* Check that our version is supported */ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) { /* Our version isn't supported */ failf(data, "insufficient winsock version to support " "telnet"); return CURLE_FAILED_INIT; } /* Our version is supported */ return CURLE_OK; } #endif static CURLcode init_telnet(struct connectdata *conn) { struct TELNET *tn; tn = calloc(1, sizeof(struct TELNET)); if(!tn) return CURLE_OUT_OF_MEMORY; conn->data->req.protop = tn; /* make us known */ tn->telrcv_state = CURL_TS_DATA; /* Init suboptions */ CURL_SB_CLEAR(tn); /* Set the options we want by default */ tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; /* To be compliant with previous releases of libcurl we enable this option by default. This behaviour can be changed thanks to the "BINARY" option in CURLOPT_TELNETOPTIONS */ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; /* We must allow the server to echo what we sent but it is not necessary to request the server to do so (it might forces the server to close the connection). Hence, we ignore ECHO in the negotiate function */ tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; /* Set the subnegotiation fields to send information just after negotiation passed (do/will) Default values are (0,0) initialized by calloc. According to the RFC1013 it is valid: A value equal to zero is acceptable for the width (or height), and means that no character width (or height) is being sent. In this case, the width (or height) that will be assumed by the Telnet server is operating system specific (it will probably be based upon the terminal type information that may have been sent using the TERMINAL TYPE Telnet option). */ tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; return CURLE_OK; } static void negotiate(struct connectdata *conn) { int i; struct TELNET *tn = (struct TELNET *) conn->data->req.protop; for(i = 0; i < CURL_NTELOPTS; i++) { if(i == CURL_TELOPT_ECHO) continue; if(tn->us_preferred[i] == CURL_YES) set_local_option(conn, i, CURL_YES); if(tn->him_preferred[i] == CURL_YES) set_remote_option(conn, i, CURL_YES); } } #ifndef CURL_DISABLE_VERBOSE_STRINGS static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option) { if(data->set.verbose) { if(cmd == CURL_IAC) { if(CURL_TELCMD_OK(option)) infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option)); else infof(data, "%s IAC %d\n", direction, option); } else { const char *fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" : (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0; if(fmt) { const char *opt; if(CURL_TELOPT_OK(option)) opt = CURL_TELOPT(option); else if(option == CURL_TELOPT_EXOPL) opt = "EXOPL"; else opt = NULL; if(opt) infof(data, "%s %s %s\n", direction, fmt, opt); else infof(data, "%s %s %d\n", direction, fmt, option); } else infof(data, "%s %d %d\n", direction, cmd, option); } } } #endif static void send_negotiation(struct connectdata *conn, int cmd, int option) { unsigned char buf[3]; ssize_t bytes_written; struct Curl_easy *data = conn->data; buf[0] = CURL_IAC; buf[1] = (unsigned char)cmd; buf[2] = (unsigned char)option; bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); if(bytes_written < 0) { int err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); } printoption(conn->data, "SENT", cmd, option); } static void set_remote_option(struct connectdata *conn, int option, int newstate) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; if(newstate == CURL_YES) { switch(tn->him[option]) { case CURL_NO: tn->him[option] = CURL_WANTYES; send_negotiation(conn, CURL_DO, option); break; case CURL_YES: /* Already enabled */ break; case CURL_WANTNO: switch(tn->himq[option]) { case CURL_EMPTY: /* Already negotiating for CURL_YES, queue the request */ tn->himq[option] = CURL_OPPOSITE; break; case CURL_OPPOSITE: /* Error: already queued an enable request */ break; } break; case CURL_WANTYES: switch(tn->himq[option]) { case CURL_EMPTY: /* Error: already negotiating for enable */ break; case CURL_OPPOSITE: tn->himq[option] = CURL_EMPTY; break; } break; } } else { /* NO */ switch(tn->him[option]) { case CURL_NO: /* Already disabled */ break; case CURL_YES: tn->him[option] = CURL_WANTNO; send_negotiation(conn, CURL_DONT, option); break; case CURL_WANTNO: switch(tn->himq[option]) { case CURL_EMPTY: /* Already negotiating for NO */ break; case CURL_OPPOSITE: tn->himq[option] = CURL_EMPTY; break; } break; case CURL_WANTYES: switch(tn->himq[option]) { case CURL_EMPTY: tn->himq[option] = CURL_OPPOSITE; break; case CURL_OPPOSITE: break; } break; } } } static void rec_will(struct connectdata *conn, int option) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; switch(tn->him[option]) { case CURL_NO: if(tn->him_preferred[option] == CURL_YES) { tn->him[option] = CURL_YES; send_negotiation(conn, CURL_DO, option); } else send_negotiation(conn, CURL_DONT, option); break; case CURL_YES: /* Already enabled */ break; case CURL_WANTNO: switch(tn->himq[option]) { case CURL_EMPTY: /* Error: DONT answered by WILL */ tn->him[option] = CURL_NO; break; case CURL_OPPOSITE: /* Error: DONT answered by WILL */ tn->him[option] = CURL_YES; tn->himq[option] = CURL_EMPTY; break; } break; case CURL_WANTYES: switch(tn->himq[option]) { case CURL_EMPTY: tn->him[option] = CURL_YES; break; case CURL_OPPOSITE: tn->him[option] = CURL_WANTNO; tn->himq[option] = CURL_EMPTY; send_negotiation(conn, CURL_DONT, option); break; } break; } } static void rec_wont(struct connectdata *conn, int option) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; switch(tn->him[option]) { case CURL_NO: /* Already disabled */ break; case CURL_YES: tn->him[option] = CURL_NO; send_negotiation(conn, CURL_DONT, option); break; case CURL_WANTNO: switch(tn->himq[option]) { case CURL_EMPTY: tn->him[option] = CURL_NO; break; case CURL_OPPOSITE: tn->him[option] = CURL_WANTYES; tn->himq[option] = CURL_EMPTY; send_negotiation(conn, CURL_DO, option); break; } break; case CURL_WANTYES: switch(tn->himq[option]) { case CURL_EMPTY: tn->him[option] = CURL_NO; break; case CURL_OPPOSITE: tn->him[option] = CURL_NO; tn->himq[option] = CURL_EMPTY; break; } break; } } static void set_local_option(struct connectdata *conn, int option, int newstate) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; if(newstate == CURL_YES) { switch(tn->us[option]) { case CURL_NO: tn->us[option] = CURL_WANTYES; send_negotiation(conn, CURL_WILL, option); break; case CURL_YES: /* Already enabled */ break; case CURL_WANTNO: switch(tn->usq[option]) { case CURL_EMPTY: /* Already negotiating for CURL_YES, queue the request */ tn->usq[option] = CURL_OPPOSITE; break; case CURL_OPPOSITE: /* Error: already queued an enable request */ break; } break; case CURL_WANTYES: switch(tn->usq[option]) { case CURL_EMPTY: /* Error: already negotiating for enable */ break; case CURL_OPPOSITE: tn->usq[option] = CURL_EMPTY; break; } break; } } else { /* NO */ switch(tn->us[option]) { case CURL_NO: /* Already disabled */ break; case CURL_YES: tn->us[option] = CURL_WANTNO; send_negotiation(conn, CURL_WONT, option); break; case CURL_WANTNO: switch(tn->usq[option]) { case CURL_EMPTY: /* Already negotiating for NO */ break; case CURL_OPPOSITE: tn->usq[option] = CURL_EMPTY; break; } break; case CURL_WANTYES: switch(tn->usq[option]) { case CURL_EMPTY: tn->usq[option] = CURL_OPPOSITE; break; case CURL_OPPOSITE: break; } break; } } } static void rec_do(struct connectdata *conn, int option) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; switch(tn->us[option]) { case CURL_NO: if(tn->us_preferred[option] == CURL_YES) { tn->us[option] = CURL_YES; send_negotiation(conn, CURL_WILL, option); if(tn->subnegotiation[option] == CURL_YES) /* transmission of data option */ sendsuboption(conn, option); } else if(tn->subnegotiation[option] == CURL_YES) { /* send information to achieve this option*/ tn->us[option] = CURL_YES; send_negotiation(conn, CURL_WILL, option); sendsuboption(conn, option); } else send_negotiation(conn, CURL_WONT, option); break; case CURL_YES: /* Already enabled */ break; case CURL_WANTNO: switch(tn->usq[option]) { case CURL_EMPTY: /* Error: DONT answered by WILL */ tn->us[option] = CURL_NO; break; case CURL_OPPOSITE: /* Error: DONT answered by WILL */ tn->us[option] = CURL_YES; tn->usq[option] = CURL_EMPTY; break; } break; case CURL_WANTYES: switch(tn->usq[option]) { case CURL_EMPTY: tn->us[option] = CURL_YES; if(tn->subnegotiation[option] == CURL_YES) { /* transmission of data option */ sendsuboption(conn, option); } break; case CURL_OPPOSITE: tn->us[option] = CURL_WANTNO; tn->himq[option] = CURL_EMPTY; send_negotiation(conn, CURL_WONT, option); break; } break; } } static void rec_dont(struct connectdata *conn, int option) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; switch(tn->us[option]) { case CURL_NO: /* Already disabled */ break; case CURL_YES: tn->us[option] = CURL_NO; send_negotiation(conn, CURL_WONT, option); break; case CURL_WANTNO: switch(tn->usq[option]) { case CURL_EMPTY: tn->us[option] = CURL_NO; break; case CURL_OPPOSITE: tn->us[option] = CURL_WANTYES; tn->usq[option] = CURL_EMPTY; send_negotiation(conn, CURL_WILL, option); break; } break; case CURL_WANTYES: switch(tn->usq[option]) { case CURL_EMPTY: tn->us[option] = CURL_NO; break; case CURL_OPPOSITE: tn->us[option] = CURL_NO; tn->usq[option] = CURL_EMPTY; break; } break; } } static void printsub(struct Curl_easy *data, int direction, /* '<' or '>' */ unsigned char *pointer, /* where suboption data is */ size_t length) /* length of suboption data */ { if(data->set.verbose) { unsigned int i = 0; if(direction) { infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); if(length >= 3) { int j; i = pointer[length-2]; j = pointer[length-1]; if(i != CURL_IAC || j != CURL_SE) { infof(data, "(terminated by "); if(CURL_TELOPT_OK(i)) infof(data, "%s ", CURL_TELOPT(i)); else if(CURL_TELCMD_OK(i)) infof(data, "%s ", CURL_TELCMD(i)); else infof(data, "%u ", i); if(CURL_TELOPT_OK(j)) infof(data, "%s", CURL_TELOPT(j)); else if(CURL_TELCMD_OK(j)) infof(data, "%s", CURL_TELCMD(j)); else infof(data, "%d", j); infof(data, ", not IAC SE!) "); } } length -= 2; } if(length < 1) { infof(data, "(Empty suboption?)"); return; } if(CURL_TELOPT_OK(pointer[0])) { switch(pointer[0]) { case CURL_TELOPT_TTYPE: case CURL_TELOPT_XDISPLOC: case CURL_TELOPT_NEW_ENVIRON: case CURL_TELOPT_NAWS: infof(data, "%s", CURL_TELOPT(pointer[0])); break; default: infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); break; } } else infof(data, "%d (unknown)", pointer[i]); switch(pointer[0]) { case CURL_TELOPT_NAWS: if(length > 4) infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2], (pointer[3]<<8) | pointer[4]); break; default: switch(pointer[1]) { case CURL_TELQUAL_IS: infof(data, " IS"); break; case CURL_TELQUAL_SEND: infof(data, " SEND"); break; case CURL_TELQUAL_INFO: infof(data, " INFO/REPLY"); break; case CURL_TELQUAL_NAME: infof(data, " NAME"); break; } switch(pointer[0]) { case CURL_TELOPT_TTYPE: case CURL_TELOPT_XDISPLOC: pointer[length] = 0; infof(data, " \"%s\"", &pointer[2]); break; case CURL_TELOPT_NEW_ENVIRON: if(pointer[1] == CURL_TELQUAL_IS) { infof(data, " "); for(i = 3; i < length; i++) { switch(pointer[i]) { case CURL_NEW_ENV_VAR: infof(data, ", "); break; case CURL_NEW_ENV_VALUE: infof(data, " = "); break; default: infof(data, "%c", pointer[i]); break; } } } break; default: for(i = 2; i < length; i++) infof(data, " %.2x", pointer[i]); break; } } if(direction) infof(data, "\n"); } } static CURLcode check_telnet_options(struct connectdata *conn) { struct curl_slist *head; struct curl_slist *beg; char option_keyword[128] = ""; char option_arg[256] = ""; struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->req.protop; CURLcode result = CURLE_OK; int binary_option; /* Add the user name as an environment variable if it was given on the command line */ if(conn->bits.user_passwd) { msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; return CURLE_OUT_OF_MEMORY; } tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } for(head = data->set.telnet_options; head; head = head->next) { if(sscanf(head->data, "%127[^= ]%*[ =]%255s", option_keyword, option_arg) == 2) { /* Terminal type */ if(strcasecompare(option_keyword, "TTYPE")) { strncpy(tn->subopt_ttype, option_arg, 31); tn->subopt_ttype[31] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; continue; } /* Display variable */ if(strcasecompare(option_keyword, "XDISPLOC")) { strncpy(tn->subopt_xdisploc, option_arg, 127); tn->subopt_xdisploc[127] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; continue; } /* Environment variable */ if(strcasecompare(option_keyword, "NEW_ENV")) { beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { result = CURLE_OUT_OF_MEMORY; break; } tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; continue; } /* Window Size */ if(strcasecompare(option_keyword, "WS")) { if(sscanf(option_arg, "%hu%*[xX]%hu", &tn->subopt_wsx, &tn->subopt_wsy) == 2) tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; else { failf(data, "Syntax error in telnet option: %s", head->data); result = CURLE_TELNET_OPTION_SYNTAX; break; } continue; } /* To take care or not of the 8th bit in data exchange */ if(strcasecompare(option_keyword, "BINARY")) { binary_option = atoi(option_arg); if(binary_option != 1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; } continue; } failf(data, "Unknown telnet option %s", head->data); result = CURLE_UNKNOWN_OPTION; break; } failf(data, "Syntax error in telnet option: %s", head->data); result = CURLE_TELNET_OPTION_SYNTAX; break; } if(result) { curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; } return result; } /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. */ static void suboption(struct connectdata *conn) { struct curl_slist *v; unsigned char temp[2048]; ssize_t bytes_written; size_t len; int err; char varname[128] = ""; char varval[128] = ""; struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: len = strlen(tn->subopt_ttype) + 4 + 2; msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); } printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: len = strlen(tn->subopt_xdisploc) + 4 + 2; msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); } printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: msnprintf((char *)temp, sizeof(temp), "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, CURL_TELQUAL_IS); len = 4; for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); /* Add the variable only if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { if(sscanf(v->data, "%127[^,],%127s", varname, varval)) { msnprintf((char *)&temp[len], sizeof(temp) - len, "%c%s%c%s", CURL_NEW_ENV_VAR, varname, CURL_NEW_ENV_VALUE, varval); len += tmplen; } } } msnprintf((char *)&temp[len], sizeof(temp) - len, "%c%c", CURL_IAC, CURL_SE); len += 2; bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); } printsub(data, '>', &temp[2], len-2); break; } return; } /* * sendsuboption() * * Send suboption information to the server side. */ static void sendsuboption(struct connectdata *conn, int option) { ssize_t bytes_written; int err; unsigned short x, y; unsigned char *uc1, *uc2; struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; switch(option) { case CURL_TELOPT_NAWS: /* We prepare data to be sent */ CURL_SB_CLEAR(tn); CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SB); CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); /* We must deal either with little or big endian processors */ /* Window size must be sent according to the 'network order' */ x = htons(tn->subopt_wsx); y = htons(tn->subopt_wsy); uc1 = (unsigned char *)&x; uc2 = (unsigned char *)&y; CURL_SB_ACCUM(tn, uc1[0]); CURL_SB_ACCUM(tn, uc1[1]); CURL_SB_ACCUM(tn, uc2[0]); CURL_SB_ACCUM(tn, uc2[1]); CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); CURL_SB_TERM(tn); /* data suboption is now ready */ printsub(data, '>', (unsigned char *)tn->subbuffer + 2, CURL_SB_LEN(tn)-2); /* we send the header of the suboption... */ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); if(bytes_written < 0) { err = SOCKERRNO; failf(data, "Sending data failed (%d)", err); } /* ... then the window size with the send_telnet_data() function to deal with 0xFF cases ... */ send_telnet_data(conn, (char *)tn->subbuffer + 3, 4); /* ... and the footer */ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2); if(bytes_written < 0) { err = SOCKERRNO; failf(data, "Sending data failed (%d)", err); } break; } } static CURLcode telrcv(struct connectdata *conn, const unsigned char *inbuf, /* Data received from socket */ ssize_t count) /* Number of bytes received */ { unsigned char c; CURLcode result; int in = 0; int startwrite = -1; struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ if(startwrite >= 0) { \ result = Curl_client_write(conn, \ CLIENTWRITE_BODY, \ (char *)&inbuf[startwrite], \ in-startwrite); \ if(result) \ return result; \ } \ startwrite = -1 #define writebyte() \ if(startwrite < 0) \ startwrite = in #define bufferflush() startskipping() while(count--) { c = inbuf[in]; switch(tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if(c == '\0') { startskipping(); break; /* Ignore \0 after CR */ } writebyte(); break; case CURL_TS_DATA: if(c == CURL_IAC) { tn->telrcv_state = CURL_TS_IAC; startskipping(); break; } else if(c == '\r') tn->telrcv_state = CURL_TS_CR; writebyte(); break; case CURL_TS_IAC: process_iac: DEBUGASSERT(startwrite < 0); switch(c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; break; case CURL_WONT: tn->telrcv_state = CURL_TS_WONT; break; case CURL_DO: tn->telrcv_state = CURL_TS_DO; break; case CURL_DONT: tn->telrcv_state = CURL_TS_DONT; break; case CURL_SB: CURL_SB_CLEAR(tn); tn->telrcv_state = CURL_TS_SB; break; case CURL_IAC: tn->telrcv_state = CURL_TS_DATA; writebyte(); break; case CURL_DM: case CURL_NOP: case CURL_GA: default: tn->telrcv_state = CURL_TS_DATA; printoption(data, "RCVD", CURL_IAC, c); break; } break; case CURL_TS_WILL: printoption(data, "RCVD", CURL_WILL, c); tn->please_negotiate = 1; rec_will(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_WONT: printoption(data, "RCVD", CURL_WONT, c); tn->please_negotiate = 1; rec_wont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DO: printoption(data, "RCVD", CURL_DO, c); tn->please_negotiate = 1; rec_do(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DONT: printoption(data, "RCVD", CURL_DONT, c); tn->please_negotiate = 1; rec_dont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_SB: if(c == CURL_IAC) tn->telrcv_state = CURL_TS_SE; else CURL_SB_ACCUM(tn, c); break; case CURL_TS_SE: if(c != CURL_SE) { if(c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". * Several things may have happened. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get * into an infinite loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, c); tn->subpointer -= 2; CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_IAC; goto process_iac; } CURL_SB_ACCUM(tn, c); tn->telrcv_state = CURL_TS_SB; } else { CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_DATA; } break; } ++in; } bufferflush(); return CURLE_OK; } /* Escape and send a telnet data block */ static CURLcode send_telnet_data(struct connectdata *conn, char *buffer, ssize_t nread) { ssize_t escapes, i, outlen; unsigned char *outbuf = NULL; CURLcode result = CURLE_OK; ssize_t bytes_written, total_written; /* Determine size of new buffer after escaping */ escapes = 0; for(i = 0; i < nread; i++) if((unsigned char)buffer[i] == CURL_IAC) escapes++; outlen = nread + escapes; if(outlen == nread) outbuf = (unsigned char *)buffer; else { ssize_t j; outbuf = malloc(nread + escapes + 1); if(!outbuf) return CURLE_OUT_OF_MEMORY; j = 0; for(i = 0; i < nread; i++) { outbuf[j++] = buffer[i]; if((unsigned char)buffer[i] == CURL_IAC) outbuf[j++] = CURL_IAC; } outbuf[j] = '\0'; } total_written = 0; while(!result && total_written < outlen) { /* Make sure socket is writable to avoid EWOULDBLOCK condition */ struct pollfd pfd[1]; pfd[0].fd = conn->sock[FIRSTSOCKET]; pfd[0].events = POLLOUT; switch(Curl_poll(pfd, 1, -1)) { case -1: /* error, abort writing */ case 0: /* timeout (will never happen) */ result = CURLE_SEND_ERROR; break; default: /* write! */ bytes_written = 0; result = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf + total_written, outlen - total_written, &bytes_written); total_written += bytes_written; break; } } /* Free malloc copy if escaped */ if(outbuf != (unsigned char *)buffer) free(outbuf); return result; } static CURLcode telnet_done(struct connectdata *conn, CURLcode status, bool premature) { struct TELNET *tn = (struct TELNET *)conn->data->req.protop; (void)status; /* unused */ (void)premature; /* not used */ if(!tn) return CURLE_OK; curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; Curl_safefree(conn->data->req.protop); return CURLE_OK; } static CURLcode telnet_do(struct connectdata *conn, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; #ifdef USE_WINSOCK HMODULE wsock2; WSOCK2_FUNC close_event_func; WSOCK2_EVENT create_event_func; WSOCK2_FUNC event_select_func; WSOCK2_FUNC enum_netevents_func; WSAEVENT event_handle; WSANETWORKEVENTS events; HANDLE stdin_handle; HANDLE objs[2]; DWORD obj_count; DWORD wait_timeout; DWORD readfile_read; int err; #else int interval_ms; struct pollfd pfd[2]; int poll_cnt; curl_off_t total_dl = 0; curl_off_t total_ul = 0; #endif ssize_t nread; struct curltime now; bool keepon = TRUE; char *buf = data->state.buffer; struct TELNET *tn; *done = TRUE; /* unconditionally */ result = init_telnet(conn); if(result) return result; tn = (struct TELNET *)data->req.protop; result = check_telnet_options(conn); if(result) return result; #ifdef USE_WINSOCK /* ** This functionality only works with WinSock >= 2.0. So, ** make sure we have it. */ result = check_wsock2(data); if(result) return result; /* OK, so we have WinSock 2.0. We need to dynamically */ /* load ws2_32.dll and get the function pointers we need. */ wsock2 = Curl_load_library(TEXT("WS2_32.DLL")); if(wsock2 == NULL) { failf(data, "failed to load WS2_32.DLL (%u)", GetLastError()); return CURLE_FAILED_INIT; } /* Grab a pointer to WSACreateEvent */ create_event_func = CURLX_FUNCTION_CAST(WSOCK2_EVENT, (GetProcAddress(wsock2, "WSACreateEvent"))); if(create_event_func == NULL) { failf(data, "failed to find WSACreateEvent function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSACloseEvent */ close_event_func = GetProcAddress(wsock2, "WSACloseEvent"); if(close_event_func == NULL) { failf(data, "failed to find WSACloseEvent function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEventSelect */ event_select_func = GetProcAddress(wsock2, "WSAEventSelect"); if(event_select_func == NULL) { failf(data, "failed to find WSAEventSelect function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* And WSAEnumNetworkEvents */ enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents"); if(enum_netevents_func == NULL) { failf(data, "failed to find WSAEnumNetworkEvents function (%u)", GetLastError()); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* We want to wait for both stdin and the socket. Since ** the select() function in winsock only works on sockets ** we have to use the WaitForMultipleObjects() call. */ /* First, create a sockets event object */ event_handle = (WSAEVENT)create_event_func(); if(event_handle == WSA_INVALID_EVENT) { failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); FreeLibrary(wsock2); return CURLE_FAILED_INIT; } /* Tell winsock what events we want to listen to */ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { close_event_func(event_handle); FreeLibrary(wsock2); return CURLE_OK; } /* The get the Windows file handle for stdin */ stdin_handle = GetStdHandle(STD_INPUT_HANDLE); /* Create the list of objects to wait for */ objs[0] = event_handle; objs[1] = stdin_handle; /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, else use the old WaitForMultipleObjects() way */ if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || data->set.is_fread_set) { /* Don't wait for stdin_handle, just wait for event_handle */ obj_count = 1; /* Check stdin_handle per 100 milliseconds */ wait_timeout = 100; } else { obj_count = 2; wait_timeout = 1000; } /* Keep on listening and act on events */ while(keepon) { const DWORD buf_size = (DWORD)data->set.buffer_size; DWORD waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); switch(waitret) { case WAIT_TIMEOUT: { for(;;) { if(data->set.is_fread_set) { size_t n; /* read from user-supplied method */ n = data->state.fread_func(buf, 1, buf_size, data->state.in); if(n == CURL_READFUNC_ABORT) { keepon = FALSE; result = CURLE_READ_ERROR; break; } if(n == CURL_READFUNC_PAUSE) break; if(n == 0) /* no bytes */ break; /* fall through with number of bytes read */ readfile_read = (DWORD)n; } else { /* read from stdin */ if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; break; } if(!readfile_read) break; if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; break; } } result = send_telnet_data(conn, buf, readfile_read); if(result) { keepon = FALSE; break; } } } break; case WAIT_OBJECT_0 + 1: { if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; break; } result = send_telnet_data(conn, buf, readfile_read); if(result) { keepon = FALSE; break; } } break; case WAIT_OBJECT_0: events.lNetworkEvents = 0; if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) { err = SOCKERRNO; if(err != EINPROGRESS) { infof(data, "WSAEnumNetworkEvents failed (%d)", err); keepon = FALSE; result = CURLE_READ_ERROR; } break; } if(events.lNetworkEvents & FD_READ) { /* read data from network */ result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread); /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ else if(result) { keepon = FALSE; break; } /* returned zero but actually received 0 or less here, the server closed the connection and we bail out */ else if(nread <= 0) { keepon = FALSE; break; } result = telrcv(conn, (unsigned char *) buf, nread); if(result) { keepon = FALSE; break; } /* Negotiate if the peer has started negotiating, otherwise don't. We don't want to speak telnet with non-telnet servers, like POP or SMTP. */ if(tn->please_negotiate && !tn->already_negotiated) { negotiate(conn); tn->already_negotiated = 1; } } if(events.lNetworkEvents & FD_CLOSE) { keepon = FALSE; } break; } if(data->set.timeout) { now = Curl_now(); if(Curl_timediff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } } /* We called WSACreateEvent, so call WSACloseEvent */ if(!close_event_func(event_handle)) { infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); } /* "Forget" pointers into the library we're about to free */ create_event_func = NULL; close_event_func = NULL; event_select_func = NULL; enum_netevents_func = NULL; /* We called LoadLibrary, so call FreeLibrary */ if(!FreeLibrary(wsock2)) infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError()); #else pfd[0].fd = sockfd; pfd[0].events = POLLIN; if(data->set.is_fread_set) { poll_cnt = 1; interval_ms = 100; /* poll user-supplied read function */ } else { /* really using fread, so infile is a FILE* */ pfd[1].fd = fileno((FILE *)data->state.in); pfd[1].events = POLLIN; poll_cnt = 2; interval_ms = 1 * 1000; } while(keepon) { switch(Curl_poll(pfd, poll_cnt, interval_ms)) { case -1: /* error, stop reading */ keepon = FALSE; continue; case 0: /* timeout */ pfd[0].revents = 0; pfd[1].revents = 0; /* FALLTHROUGH */ default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread); /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ if(result) { keepon = FALSE; break; } /* returned zero but actually received 0 or less here, the server closed the connection and we bail out */ else if(nread <= 0) { keepon = FALSE; break; } total_dl += nread; Curl_pgrsSetDownloadCounter(data, total_dl); result = telrcv(conn, (unsigned char *)buf, nread); if(result) { keepon = FALSE; break; } /* Negotiate if the peer has started negotiating, otherwise don't. We don't want to speak telnet with non-telnet servers, like POP or SMTP. */ if(tn->please_negotiate && !tn->already_negotiated) { negotiate(conn); tn->already_negotiated = 1; } } nread = 0; if(poll_cnt == 2) { if(pfd[1].revents & POLLIN) { /* read from in file */ nread = read(pfd[1].fd, buf, data->set.buffer_size); } } else { /* read from user-supplied method */ nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size, data->state.in); if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; break; } if(nread == CURL_READFUNC_PAUSE) break; } if(nread > 0) { result = send_telnet_data(conn, buf, nread); if(result) { keepon = FALSE; break; } total_ul += nread; Curl_pgrsSetUploadCounter(data, total_ul); } else if(nread < 0) keepon = FALSE; break; } /* poll switch statement */ if(data->set.timeout) { now = Curl_now(); if(Curl_timediff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; } } if(Curl_pgrsUpdate(conn)) { result = CURLE_ABORTED_BY_CALLBACK; break; } } #endif /* mark this as "no further transfer wanted" */ Curl_setup_transfer(data, -1, -1, FALSE, -1); return result; } #endif davix-0.8.0/deps/curl/lib/config-riscos.h0000644000000000000000000003275614121063461016727 0ustar rootroot#ifndef HEADER_CURL_CONFIG_RISCOS_H #define HEADER_CURL_CONFIG_RISCOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for RISC OS */ /* ================================================================ */ /* Name of this package! */ #undef PACKAGE /* Version number of this archive. */ #undef VERSION /* Define if you have the getpass function. */ #undef HAVE_GETPASS /* Define cpu-machine-OS */ #define OS "ARM-RISC OS" /* Define if you want the built-in manual */ #define USE_MANUAL /* Define if you have the gethostbyaddr_r() function with 5 arguments */ #undef HAVE_GETHOSTBYADDR_R_5 /* Define if you have the gethostbyaddr_r() function with 7 arguments */ #undef HAVE_GETHOSTBYADDR_R_7 /* Define if you have the gethostbyaddr_r() function with 8 arguments */ #undef HAVE_GETHOSTBYADDR_R_8 /* Define if you have the gethostbyname_r() function with 3 arguments */ #undef HAVE_GETHOSTBYNAME_R_3 /* Define if you have the gethostbyname_r() function with 5 arguments */ #undef HAVE_GETHOSTBYNAME_R_5 /* Define if you have the gethostbyname_r() function with 6 arguments */ #undef HAVE_GETHOSTBYNAME_R_6 /* Define if you need the _REENTRANT define for some functions */ #undef NEED_REENTRANT /* Define if you have the Kerberos4 libraries (including -ldes) */ #undef HAVE_KRB4 /* Define if you want to enable IPv6 support */ #undef ENABLE_IPV6 /* Define if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define this to 'int' if ssize_t is not an available typedefed type */ #undef ssize_t /* Define this as a suitable file to read random data from */ #undef RANDOM_FILE /* Define this to your Entropy Gathering Daemon socket pathname */ #undef EGD_SOCKET /* Define if you want to enable IPv6 support */ #undef ENABLE_IPV6 /* Define if you have the alarm function. */ #define HAVE_ALARM /* Define if you have the header file. */ #define HAVE_ALLOCA_H /* Define if you have the header file. */ #define HAVE_ARPA_INET_H /* Define if you have the `closesocket' function. */ #undef HAVE_CLOSESOCKET /* Define if you have the header file. */ #undef HAVE_CRYPTO_H /* Define if you have the header file. */ #undef HAVE_DES_H /* Define if you have the header file. */ #define HAVE_ERRNO_H /* Define if you have the header file. */ #undef HAVE_ERR_H /* Define if you have the header file. */ #define HAVE_FCNTL_H /* Define if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE /* Define if getaddrinfo exists and works */ #define HAVE_GETADDRINFO /* Define if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define if you have the `gethostbyaddr' function. */ #define HAVE_GETHOSTBYADDR /* Define if you have the `gethostbyaddr_r' function. */ #undef HAVE_GETHOSTBYADDR_R /* Define if you have the `gethostbyname_r' function. */ #undef HAVE_GETHOSTBYNAME_R /* Define if you have the `gethostname' function. */ #define HAVE_GETHOSTNAME /* Define if you have the header file. */ #define HAVE_GETOPT_H /* Define if you have the `getpass_r' function. */ #undef HAVE_GETPASS_R /* Define if you have the `getpwuid' function. */ #undef HAVE_GETPWUID /* Define if you have the `getservbyname' function. */ #undef HAVE_GETSERVBYNAME /* Define if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY /* Define if you have the `timeval' struct. */ #define HAVE_STRUCT_TIMEVAL /* Define if you have the `inet_addr' function. */ #undef HAVE_INET_ADDR /* Define if you have the header file. */ #define HAVE_INTTYPES_H /* Define if you have the header file. */ #undef HAVE_IO_H /* Define if you have the `krb_get_our_ip_for_realm' function. */ #undef HAVE_KRB_GET_OUR_IP_FOR_REALM /* Define if you have the header file. */ #undef HAVE_KRB_H /* Define if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define if you have the `resolve' library (-lresolve). */ #undef HAVE_LIBRESOLVE /* Define if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define if you have the `ucb' library (-lucb). */ #undef HAVE_LIBUCB /* Define if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define if you have the header file. */ #define HAVE_MALLOC_H /* Define if you need the malloc.h header file even with stdlib.h */ /* #define NEED_MALLOC_H 1 */ /* Define if you have the header file. */ #undef HAVE_MEMORY_H /* Define if you have the header file. */ #define HAVE_NETDB_H /* Define if you have the header file. */ #undef HAVE_NETINET_IF_ETHER_H /* Define if you have the header file. */ #define HAVE_NETINET_IN_H /* Define if you have the header file. */ #define HAVE_NET_IF_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_CRYPTO_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_PEM_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_RSA_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_X509_H /* Define if you have the header file. */ #undef HAVE_PEM_H /* Define if you have the `perror' function. */ #undef HAVE_PERROR /* Define if you have the header file. */ #undef HAVE_PWD_H /* Define if you have the `RAND_egd' function. */ #undef HAVE_RAND_EGD /* Define if you have the `RAND_screen' function. */ #undef HAVE_RAND_SCREEN /* Define if you have the `RAND_status' function. */ #undef HAVE_RAND_STATUS /* Define if you have the header file. */ #undef HAVE_RSA_H /* Define if you have the `select' function. */ #define HAVE_SELECT /* Define if you have the `setvbuf' function. */ #undef HAVE_SETVBUF /* Define if you have the header file. */ #define HAVE_SGTTY_H /* Define if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define if you have the `signal' function. */ #define HAVE_SIGNAL /* Define if you have the header file. */ #define HAVE_SIGNAL_H /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T /* Define if sig_atomic_t is already defined as volatile. */ #undef HAVE_SIG_ATOMIC_T_VOLATILE /* Define if you have the `socket' function. */ #define HAVE_SOCKET /* Define if you have the header file. */ #undef HAVE_SSL_H /* Define if you have the header file. */ #undef HAVE_STDINT_H /* Define if you have the header file. */ #define HAVE_STDLIB_H /* Define if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define if you have the `strcmpi' function. */ #undef HAVE_STRCMPI /* Define if you have the `strdup' function. */ #define HAVE_STRDUP /* Define if you have the `strftime' function. */ #define HAVE_STRFTIME /* Define if you have the `stricmp' function. */ #define HAVE_STRICMP /* Define if you have the header file. */ #undef HAVE_STRINGS_H /* Define if you have the header file. */ #define HAVE_STRING_H /* Define if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define if you have the `strstr' function. */ #define HAVE_STRSTR /* Define if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* Define if you have the `strtoll' function. */ #undef HAVE_STRTOLL /* Define if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define if you have the header file. */ #define HAVE_SYS_SOCKET_H /* Define if you have the header file. */ #undef HAVE_SYS_SOCKIO_H /* Define if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define if you have the header file. */ #define HAVE_SYS_TIME_H /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H /* Define if you have the `tcgetattr' function. */ #define HAVE_TCGETATTR /* Define if you have the `tcsetattr' function. */ #define HAVE_TCSETATTR /* Define if you have the header file. */ #define HAVE_TERMIOS_H /* Define if you have the header file. */ #undef HAVE_TERMIO_H /* Define if you have the header file. */ #undef HAVE_TIME_H /* Define if you have the `uname' function. */ #define HAVE_UNAME /* Define if you have the header file. */ #define HAVE_UNISTD_H /* Define if you have the header file. */ #undef HAVE_WINSOCK_H /* Define if you have the header file. */ #undef HAVE_X509_H /* Name of package */ #undef PACKAGE /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `long double', as computed by sizeof. */ #undef SIZEOF_LONG_DOUBLE /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 4 /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Version number of package */ #undef VERSION /* Define if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `unsigned' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define if you have the ioctl function. */ #define HAVE_IOCTL /* Define if you have a working ioctl FIONBIO function. */ #define HAVE_IOCTL_FIONBIO /* to disable LDAP */ #define CURL_DISABLE_LDAP /* Define if you have the getnameinfo function. */ #define HAVE_GETNAMEINFO 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 size_t /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 int /* Define if you have the recv function. */ #define HAVE_RECV 1 /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 int /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 void * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 size_t /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV ssize_t /* Define 1 if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 int /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 void /* Define if the type pointed by arg 2 for recvfrom is void. */ #define RECVFROM_TYPE_ARG2_IS_VOID /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 size_t /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 int /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV ssize_t /* Define if you have the send function. */ #define HAVE_SEND 1 /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 int /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 const /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 void * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 size_t /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV ssize_t #endif /* HEADER_CURL_CONFIG_RISCOS_H */ davix-0.8.0/deps/curl/lib/inet_ntop.h0000644000000000000000000000260014121063461016142 0ustar rootroot#ifndef HEADER_CURL_INET_NTOP_H #define HEADER_CURL_INET_NTOP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); #ifdef HAVE_INET_NTOP #ifdef HAVE_ARPA_INET_H #include #endif #define Curl_inet_ntop(af,addr,buf,size) \ inet_ntop(af, addr, buf, (curl_socklen_t)size) #endif #endif /* HEADER_CURL_INET_NTOP_H */ davix-0.8.0/deps/curl/lib/getinfo.c0000644000000000000000000003352114121063461015577 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "getinfo.h" #include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Initialize statistical and informational data. * * This function is called in curl_easy_reset, curl_easy_duphandle and at the * beginning of a perform session. It must reset the session-info variables, * in particular all variables in struct PureInfo. */ CURLcode Curl_initinfo(struct Curl_easy *data) { struct Progress *pro = &data->progress; struct PureInfo *info = &data->info; pro->t_nslookup = 0; pro->t_connect = 0; pro->t_appconnect = 0; pro->t_pretransfer = 0; pro->t_starttransfer = 0; pro->timespent = 0; pro->t_redirect = 0; pro->is_t_startransfer_set = false; info->httpcode = 0; info->httpproxycode = 0; info->httpversion = 0; info->filetime = -1; /* -1 is an illegal time and thus means unknown */ info->timecond = FALSE; info->header_size = 0; info->request_size = 0; info->proxyauthavail = 0; info->httpauthavail = 0; info->numconnects = 0; free(info->contenttype); info->contenttype = NULL; free(info->wouldredirect); info->wouldredirect = NULL; info->conn_primary_ip[0] = '\0'; info->conn_local_ip[0] = '\0'; info->conn_primary_port = 0; info->conn_local_port = 0; info->conn_scheme = 0; info->conn_protocol = 0; #ifdef USE_SSL Curl_ssl_free_certinfo(data); #endif return CURLE_OK; } static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, const char **param_charp) { switch(info) { case CURLINFO_EFFECTIVE_URL: *param_charp = data->change.url?data->change.url:(char *)""; break; case CURLINFO_CONTENT_TYPE: *param_charp = data->info.contenttype; break; case CURLINFO_PRIVATE: *param_charp = (char *) data->set.private_data; break; case CURLINFO_FTP_ENTRY_PATH: /* Return the entrypath string from the most recent connection. This pointer was copied from the connectdata structure by FTP. The actual string may be free()ed by subsequent libcurl calls so it must be copied to a safer area before the next libcurl call. Callers must never free it themselves. */ *param_charp = data->state.most_recent_ftp_entrypath; break; case CURLINFO_REDIRECT_URL: /* Return the URL this request would have been redirected to if that option had been enabled! */ *param_charp = data->info.wouldredirect; break; case CURLINFO_PRIMARY_IP: /* Return the ip address of the most recent (primary) connection */ *param_charp = data->info.conn_primary_ip; break; case CURLINFO_LOCAL_IP: /* Return the source/local ip address of the most recent (primary) connection */ *param_charp = data->info.conn_local_ip; break; case CURLINFO_RTSP_SESSION_ID: *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; break; case CURLINFO_SCHEME: *param_charp = data->info.conn_scheme; break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, long *param_longp) { curl_socket_t sockfd; union { unsigned long *to_ulong; long *to_long; } lptr; switch(info) { case CURLINFO_RESPONSE_CODE: *param_longp = data->info.httpcode; break; case CURLINFO_HTTP_CONNECTCODE: *param_longp = data->info.httpproxycode; break; case CURLINFO_FILETIME: if(data->info.filetime > LONG_MAX) *param_longp = LONG_MAX; else if(data->info.filetime < LONG_MIN) *param_longp = LONG_MIN; else *param_longp = (long)data->info.filetime; break; case CURLINFO_HEADER_SIZE: *param_longp = (long)data->info.header_size; break; case CURLINFO_REQUEST_SIZE: *param_longp = (long)data->info.request_size; break; case CURLINFO_SSL_VERIFYRESULT: *param_longp = data->set.ssl.certverifyresult; break; case CURLINFO_PROXY_SSL_VERIFYRESULT: *param_longp = data->set.proxy_ssl.certverifyresult; break; case CURLINFO_REDIRECT_COUNT: *param_longp = data->set.followlocation; break; case CURLINFO_HTTPAUTH_AVAIL: lptr.to_long = param_longp; *lptr.to_ulong = data->info.httpauthavail; break; case CURLINFO_PROXYAUTH_AVAIL: lptr.to_long = param_longp; *lptr.to_ulong = data->info.proxyauthavail; break; case CURLINFO_OS_ERRNO: *param_longp = data->state.os_errno; break; case CURLINFO_NUM_CONNECTS: *param_longp = data->info.numconnects; break; case CURLINFO_LASTSOCKET: sockfd = Curl_getconnectinfo(data, NULL); /* note: this is not a good conversion for systems with 64 bit sockets and 32 bit longs */ if(sockfd != CURL_SOCKET_BAD) *param_longp = (long)sockfd; else /* this interface is documented to return -1 in case of badness, which may not be the same as the CURL_SOCKET_BAD value */ *param_longp = -1; break; case CURLINFO_PRIMARY_PORT: /* Return the (remote) port of the most recent (primary) connection */ *param_longp = data->info.conn_primary_port; break; case CURLINFO_LOCAL_PORT: /* Return the local port of the most recent (primary) connection */ *param_longp = data->info.conn_local_port; break; case CURLINFO_CONDITION_UNMET: /* return if the condition prevented the document to get transferred */ *param_longp = data->info.timecond ? 1L : 0L; break; case CURLINFO_RTSP_CLIENT_CSEQ: *param_longp = data->state.rtsp_next_client_CSeq; break; case CURLINFO_RTSP_SERVER_CSEQ: *param_longp = data->state.rtsp_next_server_CSeq; break; case CURLINFO_RTSP_CSEQ_RECV: *param_longp = data->state.rtsp_CSeq_recv; break; case CURLINFO_HTTP_VERSION: switch(data->info.httpversion) { case 10: *param_longp = CURL_HTTP_VERSION_1_0; break; case 11: *param_longp = CURL_HTTP_VERSION_1_1; break; case 20: *param_longp = CURL_HTTP_VERSION_2_0; break; case 30: *param_longp = CURL_HTTP_VERSION_3; break; default: *param_longp = CURL_HTTP_VERSION_NONE; break; } break; case CURLINFO_PROTOCOL: *param_longp = data->info.conn_protocol; break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } #define DOUBLE_SECS(x) (double)(x)/1000000 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, curl_off_t *param_offt) { switch(info) { case CURLINFO_FILETIME_T: *param_offt = (curl_off_t)data->info.filetime; break; case CURLINFO_SIZE_UPLOAD_T: *param_offt = data->progress.uploaded; break; case CURLINFO_SIZE_DOWNLOAD_T: *param_offt = data->progress.downloaded; break; case CURLINFO_SPEED_DOWNLOAD_T: *param_offt = data->progress.dlspeed; break; case CURLINFO_SPEED_UPLOAD_T: *param_offt = data->progress.ulspeed; break; case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T: *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? data->progress.size_dl:-1; break; case CURLINFO_CONTENT_LENGTH_UPLOAD_T: *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? data->progress.size_ul:-1; break; case CURLINFO_TOTAL_TIME_T: *param_offt = data->progress.timespent; break; case CURLINFO_NAMELOOKUP_TIME_T: *param_offt = data->progress.t_nslookup; break; case CURLINFO_CONNECT_TIME_T: *param_offt = data->progress.t_connect; break; case CURLINFO_APPCONNECT_TIME_T: *param_offt = data->progress.t_appconnect; break; case CURLINFO_PRETRANSFER_TIME_T: *param_offt = data->progress.t_pretransfer; break; case CURLINFO_STARTTRANSFER_TIME_T: *param_offt = data->progress.t_starttransfer; break; case CURLINFO_REDIRECT_TIME_T: *param_offt = data->progress.t_redirect; break; case CURLINFO_RETRY_AFTER: *param_offt = data->info.retry_after; break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { switch(info) { case CURLINFO_TOTAL_TIME: *param_doublep = DOUBLE_SECS(data->progress.timespent); break; case CURLINFO_NAMELOOKUP_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_nslookup); break; case CURLINFO_CONNECT_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_connect); break; case CURLINFO_APPCONNECT_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_appconnect); break; case CURLINFO_PRETRANSFER_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer); break; case CURLINFO_STARTTRANSFER_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer); break; case CURLINFO_SIZE_UPLOAD: *param_doublep = (double)data->progress.uploaded; break; case CURLINFO_SIZE_DOWNLOAD: *param_doublep = (double)data->progress.downloaded; break; case CURLINFO_SPEED_DOWNLOAD: *param_doublep = (double)data->progress.dlspeed; break; case CURLINFO_SPEED_UPLOAD: *param_doublep = (double)data->progress.ulspeed; break; case CURLINFO_CONTENT_LENGTH_DOWNLOAD: *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)? (double)data->progress.size_dl:-1; break; case CURLINFO_CONTENT_LENGTH_UPLOAD: *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)? (double)data->progress.size_ul:-1; break; case CURLINFO_REDIRECT_TIME: *param_doublep = DOUBLE_SECS(data->progress.t_redirect); break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_slist **param_slistp) { union { struct curl_certinfo *to_certinfo; struct curl_slist *to_slist; } ptr; switch(info) { case CURLINFO_SSL_ENGINES: *param_slistp = Curl_ssl_engines_list(data); break; case CURLINFO_COOKIELIST: *param_slistp = Curl_cookie_list(data); break; case CURLINFO_CERTINFO: /* Return the a pointer to the certinfo struct. Not really an slist pointer but we can pretend it is here */ ptr.to_certinfo = &data->info.certs; *param_slistp = ptr.to_slist; break; case CURLINFO_TLS_SESSION: case CURLINFO_TLS_SSL_PTR: { struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) param_slistp; struct curl_tlssessioninfo *tsi = &data->tsi; #ifdef USE_SSL struct connectdata *conn = data->conn; #endif *tsip = tsi; tsi->backend = Curl_ssl_backend(); tsi->internals = NULL; #ifdef USE_SSL if(conn && tsi->backend != CURLSSLBACKEND_NONE) { unsigned int i; for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) { if(conn->ssl[i].use) { tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info); break; } } } #endif } break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info, curl_socket_t *param_socketp) { switch(info) { case CURLINFO_ACTIVESOCKET: *param_socketp = Curl_getconnectinfo(data, NULL); break; default: return CURLE_UNKNOWN_OPTION; } return CURLE_OK; } CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; long *param_longp = NULL; double *param_doublep = NULL; curl_off_t *param_offt = NULL; const char **param_charp = NULL; struct curl_slist **param_slistp = NULL; curl_socket_t *param_socketp = NULL; int type; CURLcode result = CURLE_UNKNOWN_OPTION; if(!data) return result; va_start(arg, info); type = CURLINFO_TYPEMASK & (int)info; switch(type) { case CURLINFO_STRING: param_charp = va_arg(arg, const char **); if(param_charp) result = getinfo_char(data, info, param_charp); break; case CURLINFO_LONG: param_longp = va_arg(arg, long *); if(param_longp) result = getinfo_long(data, info, param_longp); break; case CURLINFO_DOUBLE: param_doublep = va_arg(arg, double *); if(param_doublep) result = getinfo_double(data, info, param_doublep); break; case CURLINFO_OFF_T: param_offt = va_arg(arg, curl_off_t *); if(param_offt) result = getinfo_offt(data, info, param_offt); break; case CURLINFO_SLIST: param_slistp = va_arg(arg, struct curl_slist **); if(param_slistp) result = getinfo_slist(data, info, param_slistp); break; case CURLINFO_SOCKET: param_socketp = va_arg(arg, curl_socket_t *); if(param_socketp) result = getinfo_socket(data, info, param_socketp); break; default: break; } va_end(arg); return result; } davix-0.8.0/deps/curl/lib/altsvc.c0000644000000000000000000004267014121063461015445 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * The Alt-Svc: header is defined in RFC 7838: * https://tools.ietf.org/html/rfc7838 */ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC) #include #include "urldata.h" #include "altsvc.h" #include "curl_get_line.h" #include "strcase.h" #include "parsedate.h" #include "sendf.h" #include "warnless.h" #include "rand.h" #include "rename.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define MAX_ALTSVC_LINE 4095 #define MAX_ALTSVC_DATELENSTR "64" #define MAX_ALTSVC_DATELEN 64 #define MAX_ALTSVC_HOSTLENSTR "512" #define MAX_ALTSVC_HOSTLEN 512 #define MAX_ALTSVC_ALPNLENSTR "10" #define MAX_ALTSVC_ALPNLEN 10 #if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS) #define H3VERSION "h3-27" #else #define H3VERSION "h3" #endif static enum alpnid alpn2alpnid(char *name) { if(strcasecompare(name, "h1")) return ALPN_h1; if(strcasecompare(name, "h2")) return ALPN_h2; if(strcasecompare(name, H3VERSION)) return ALPN_h3; return ALPN_none; /* unknown, probably rubbish input */ } /* Given the ALPN ID, return the name */ const char *Curl_alpnid2str(enum alpnid id) { switch(id) { case ALPN_h1: return "h1"; case ALPN_h2: return "h2"; case ALPN_h3: return H3VERSION; default: return ""; /* bad */ } } static void altsvc_free(struct altsvc *as) { free(as->src.host); free(as->dst.host); free(as); } static struct altsvc *altsvc_createid(const char *srchost, const char *dsthost, enum alpnid srcalpnid, enum alpnid dstalpnid, unsigned int srcport, unsigned int dstport) { struct altsvc *as = calloc(sizeof(struct altsvc), 1); if(!as) return NULL; as->src.host = strdup(srchost); if(!as->src.host) goto error; as->dst.host = strdup(dsthost); if(!as->dst.host) goto error; as->src.alpnid = srcalpnid; as->dst.alpnid = dstalpnid; as->src.port = curlx_ultous(srcport); as->dst.port = curlx_ultous(dstport); return as; error: altsvc_free(as); return NULL; } static struct altsvc *altsvc_create(char *srchost, char *dsthost, char *srcalpn, char *dstalpn, unsigned int srcport, unsigned int dstport) { enum alpnid dstalpnid = alpn2alpnid(dstalpn); enum alpnid srcalpnid = alpn2alpnid(srcalpn); if(!srcalpnid || !dstalpnid) return NULL; return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, srcport, dstport); } /* only returns SERIOUS errors */ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) { /* Example line: h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1 */ char srchost[MAX_ALTSVC_HOSTLEN + 1]; char dsthost[MAX_ALTSVC_HOSTLEN + 1]; char srcalpn[MAX_ALTSVC_ALPNLEN + 1]; char dstalpn[MAX_ALTSVC_ALPNLEN + 1]; char date[MAX_ALTSVC_DATELEN + 1]; unsigned int srcport; unsigned int dstport; unsigned int prio; unsigned int persist; int rc; rc = sscanf(line, "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u " "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u", srcalpn, srchost, &srcport, dstalpn, dsthost, &dstport, date, &persist, &prio); if(9 == rc) { struct altsvc *as; time_t expires = Curl_getdate_capped(date); as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport); if(as) { as->expires = expires; as->prio = prio; as->persist = persist ? 1 : 0; Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); asi->num++; /* one more entry */ } } return CURLE_OK; } /* * Load alt-svc entries from the given file. The text based line-oriented file * format is documented here: * https://github.com/curl/curl/wiki/QUIC-implementation * * This function only returns error on major problems that prevents alt-svc * handling to work completely. It will ignore individual syntactical errors * etc. */ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) { CURLcode result = CURLE_OK; char *line = NULL; FILE *fp; /* we need a private copy of the file name so that the altsvc cache file name survives an easy handle reset */ free(asi->filename); asi->filename = strdup(file); if(!asi->filename) return CURLE_OUT_OF_MEMORY; fp = fopen(file, FOPEN_READTEXT); if(fp) { line = malloc(MAX_ALTSVC_LINE); if(!line) goto fail; while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) { char *lineptr = line; while(*lineptr && ISBLANK(*lineptr)) lineptr++; if(*lineptr == '#') /* skip commented lines */ continue; altsvc_add(asi, lineptr); } free(line); /* free the line buffer */ fclose(fp); } return result; fail: Curl_safefree(asi->filename); free(line); fclose(fp); return CURLE_OUT_OF_MEMORY; } /* * Write this single altsvc entry to a single output line */ static CURLcode altsvc_out(struct altsvc *as, FILE *fp) { struct tm stamp; CURLcode result = Curl_gmtime(as->expires, &stamp); if(result) return result; fprintf(fp, "%s %s %u " "%s %s %u " "\"%d%02d%02d " "%02d:%02d:%02d\" " "%u %d\n", Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port, Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port, stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, stamp.tm_hour, stamp.tm_min, stamp.tm_sec, as->persist, as->prio); return CURLE_OK; } /* ---- library-wide functions below ---- */ /* * Curl_altsvc_init() creates a new altsvc cache. * It returns the new instance or NULL if something goes wrong. */ struct altsvcinfo *Curl_altsvc_init(void) { struct altsvcinfo *asi = calloc(sizeof(struct altsvcinfo), 1); if(!asi) return NULL; Curl_llist_init(&asi->list, NULL); /* set default behavior */ asi->flags = CURLALTSVC_H1 #ifdef USE_NGHTTP2 | CURLALTSVC_H2 #endif #ifdef ENABLE_QUIC | CURLALTSVC_H3 #endif ; return asi; } /* * Curl_altsvc_load() loads alt-svc from file. */ CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file) { CURLcode result; DEBUGASSERT(asi); result = altsvc_load(asi, file); return result; } /* * Curl_altsvc_ctrl() passes on the external bitmask. */ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl) { DEBUGASSERT(asi); if(!ctrl) /* unexpected */ return CURLE_BAD_FUNCTION_ARGUMENT; asi->flags = ctrl; return CURLE_OK; } /* * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated * resources. */ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc) { struct curl_llist_element *e; struct curl_llist_element *n; if(altsvc) { for(e = altsvc->list.head; e; e = n) { struct altsvc *as = e->ptr; n = e->next; altsvc_free(as); } free(altsvc->filename); free(altsvc); } } /* * Curl_altsvc_save() writes the altsvc cache to a file. */ CURLcode Curl_altsvc_save(struct Curl_easy *data, struct altsvcinfo *altsvc, const char *file) { struct curl_llist_element *e; struct curl_llist_element *n; CURLcode result = CURLE_OK; FILE *out; char *tempstore; unsigned char randsuffix[9]; if(!altsvc) /* no cache activated */ return CURLE_OK; /* if not new name is given, use the one we stored from the load */ if(!file && altsvc->filename) file = altsvc->filename; if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0]) /* marked as read-only, no file or zero length file name */ return CURLE_OK; if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) return CURLE_FAILED_INIT; tempstore = aprintf("%s.%s.tmp", file, randsuffix); if(!tempstore) return CURLE_OUT_OF_MEMORY; out = fopen(tempstore, FOPEN_WRITETEXT); if(!out) result = CURLE_WRITE_ERROR; else { fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); for(e = altsvc->list.head; e; e = n) { struct altsvc *as = e->ptr; n = e->next; result = altsvc_out(as, out); if(result) break; } fclose(out); if(!result && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; if(result) unlink(tempstore); } free(tempstore); return result; } static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen) { size_t len; const char *protop; const char *p = *ptr; while(*p && ISBLANK(*p)) p++; protop = p; while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '=')) p++; len = p - protop; *ptr = p; if(!len || (len >= buflen)) return CURLE_BAD_FUNCTION_ARGUMENT; memcpy(alpnbuf, protop, len); alpnbuf[len] = 0; return CURLE_OK; } /* altsvc_flush() removes all alternatives for this source origin from the list */ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid, const char *srchost, unsigned short srcport) { struct curl_llist_element *e; struct curl_llist_element *n; for(e = asi->list.head; e; e = n) { struct altsvc *as = e->ptr; n = e->next; if((srcalpnid == as->src.alpnid) && (srcport == as->src.port) && strcasecompare(srchost, as->src.host)) { Curl_llist_remove(&asi->list, e, NULL); altsvc_free(as); asi->num--; } } } #ifdef DEBUGBUILD /* to play well with debug builds, we can *set* a fixed time this will return */ static time_t debugtime(void *unused) { char *timestr = getenv("CURL_TIME"); (void)unused; if(timestr) { unsigned long val = strtol(timestr, NULL, 10); return (time_t)val; } return time(NULL); } #define time(x) debugtime(x) #endif /* * Curl_altsvc_parse() takes an incoming alt-svc response header and stores * the data correctly in the cache. * * 'value' points to the header *value*. That's contents to the right of the * header name. * * Currently this function rejects invalid data without returning an error. * Invalid host name, port number will result in the specific alternative * being rejected. Unknown protocols are skipped. */ CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvcinfo *asi, const char *value, enum alpnid srcalpnid, const char *srchost, unsigned short srcport) { const char *p = value; size_t len; enum alpnid dstalpnid = srcalpnid; /* the same by default */ char namebuf[MAX_ALTSVC_HOSTLEN] = ""; char alpnbuf[MAX_ALTSVC_ALPNLEN] = ""; struct altsvc *as; unsigned short dstport = srcport; /* the same by default */ CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); if(result) { infof(data, "Excessive alt-svc header, ignoring...\n"); return CURLE_OK; } DEBUGASSERT(asi); /* Flush all cached alternatives for this source origin, if any */ altsvc_flush(asi, srcalpnid, srchost, srcport); /* "clear" is a magic keyword */ if(strcasecompare(alpnbuf, "clear")) { return CURLE_OK; } do { if(*p == '=') { /* [protocol]="[host][:port]" */ dstalpnid = alpn2alpnid(alpnbuf); p++; if(*p == '\"') { const char *dsthost; const char *value_ptr; char option[32]; unsigned long num; char *end_ptr; bool quoted = FALSE; time_t maxage = 24 * 3600; /* default is 24 hours */ bool persist = FALSE; p++; if(*p != ':') { /* host name starts here */ const char *hostp = p; while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-'))) p++; len = p - hostp; if(!len || (len >= MAX_ALTSVC_HOSTLEN)) { infof(data, "Excessive alt-svc host name, ignoring...\n"); dstalpnid = ALPN_none; } else { memcpy(namebuf, hostp, len); namebuf[len] = 0; dsthost = namebuf; } } else { /* no destination name, use source host */ dsthost = srchost; } if(*p == ':') { /* a port number */ unsigned long port = strtoul(++p, &end_ptr, 10); if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { infof(data, "Unknown alt-svc port number, ignoring...\n"); dstalpnid = ALPN_none; } p = end_ptr; dstport = curlx_ultous(port); } if(*p++ != '\"') break; /* Handle the optional 'ma' and 'persist' flags. Unknown flags are skipped. */ for(;;) { while(*p && ISBLANK(*p) && *p != ';' && *p != ',') p++; if(!*p || *p == ',') break; p++; /* pass the semicolon */ if(!*p) break; result = getalnum(&p, option, sizeof(option)); if(result) { /* skip option if name is too long */ option[0] = '\0'; } while(*p && ISBLANK(*p)) p++; if(*p != '=') return CURLE_OK; p++; while(*p && ISBLANK(*p)) p++; if(!*p) return CURLE_OK; if(*p == '\"') { /* quoted value */ p++; quoted = TRUE; } value_ptr = p; if(quoted) { while(*p && *p != '\"') p++; if(!*p++) return CURLE_OK; } else { while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',') p++; } num = strtoul(value_ptr, &end_ptr, 10); if((end_ptr != value_ptr) && (num < ULONG_MAX)) { if(strcasecompare("ma", option)) maxage = num; else if(strcasecompare("persist", option) && (num == 1)) persist = TRUE; } } if(dstalpnid) { as = altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, srcport, dstport); if(as) { /* The expires time also needs to take the Age: value (if any) into account. [See RFC 7838 section 3.1] */ as->expires = maxage + time(NULL); as->persist = persist; Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); asi->num++; /* one more entry */ infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, Curl_alpnid2str(dstalpnid)); } } else { infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n", alpnbuf); } } else break; /* after the double quote there can be a comma if there's another string or a semicolon if no more */ if(*p == ',') { /* comma means another alternative is presented */ p++; result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); if(result) break; } } else break; } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r')); return CURLE_OK; } /* * Return TRUE on a match */ bool Curl_altsvc_lookup(struct altsvcinfo *asi, enum alpnid srcalpnid, const char *srchost, int srcport, struct altsvc **dstentry, const int versions) /* one or more bits */ { struct curl_llist_element *e; struct curl_llist_element *n; time_t now = time(NULL); DEBUGASSERT(asi); DEBUGASSERT(srchost); DEBUGASSERT(dstentry); for(e = asi->list.head; e; e = n) { struct altsvc *as = e->ptr; n = e->next; if(as->expires < now) { /* an expired entry, remove */ Curl_llist_remove(&asi->list, e, NULL); altsvc_free(as); continue; } if((as->src.alpnid == srcalpnid) && strcasecompare(as->src.host, srchost) && (as->src.port == srcport) && (versions & as->dst.alpnid)) { /* match */ *dstentry = as; return TRUE; } } return FALSE; } #endif /* CURL_DISABLE_HTTP || USE_ALTSVC */ davix-0.8.0/deps/curl/lib/http_negotiate.h0000644000000000000000000000307314121063461017166 0ustar rootroot#ifndef HEADER_CURL_HTTP_NEGOTIATE_H #define HEADER_CURL_HTTP_NEGOTIATE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) /* this is for Negotiate header input */ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header); /* this is for creating Negotiate header output */ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); void Curl_http_auth_cleanup_negotiate(struct connectdata *conn); #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ davix-0.8.0/deps/curl/lib/socks.c0000644000000000000000000007437714121063461015304 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_PROXY) #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include "urldata.h" #include "sendf.h" #include "select.h" #include "connect.h" #include "timeval.h" #include "socks.h" #include "multiif.h" /* for getsock macros */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* * Helper read-from-socket functions. Does the same as Curl_read() but it * blocks until all bytes amount of buffersize will be read. No more, no less. * * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions. */ int Curl_blockread_all(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ char *buf, /* store read data here */ ssize_t buffersize, /* max amount to read */ ssize_t *n) /* amount bytes read */ { ssize_t nread = 0; ssize_t allread = 0; int result; *n = 0; for(;;) { timediff_t timeleft = Curl_timeleft(conn->data, NULL, TRUE); if(timeleft < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } if(SOCKET_READABLE(sockfd, timeleft) <= 0) { result = ~CURLE_OK; break; } result = Curl_read_plain(sockfd, buf, buffersize, &nread); if(CURLE_AGAIN == result) continue; if(result) break; if(buffersize == nread) { allread += nread; *n = allread; result = CURLE_OK; break; } if(!nread) { result = ~CURLE_OK; break; } buffersize -= nread; buf += nread; allread += nread; } return result; } #endif #ifndef DEBUGBUILD #define sxstate(x,y) socksstate(x,y) #else #define sxstate(x,y) socksstate(x,y, __LINE__) #endif /* always use this function to change state, to make debugging easier */ static void socksstate(struct connectdata *conn, enum connect_t state #ifdef DEBUGBUILD , int lineno #endif ) { enum connect_t oldstate = conn->cnnct.state; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* synced with the state list in urldata.h */ static const char * const statename[] = { "INIT", "SOCKS_INIT", "SOCKS_SEND", "SOCKS_READ_INIT", "SOCKS_READ", "GSSAPI_INIT", "AUTH_INIT", "AUTH_SEND", "AUTH_READ", "REQ_INIT", "RESOLVING", "RESOLVED", "RESOLVE_REMOTE", "REQ_SEND", "REQ_SENDING", "REQ_READ", "REQ_READ_MORE", "DONE" }; #endif if(oldstate == state) /* don't bother when the new state is the same as the old state */ return; conn->cnnct.state = state; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) infof(conn->data, "SXSTATE: %s => %s conn %p; line %d\n", statename[oldstate], statename[conn->cnnct.state], conn, lineno); #endif } int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock, int sockindex) { int rc = 0; sock[0] = conn->sock[sockindex]; switch(conn->cnnct.state) { case CONNECT_RESOLVING: case CONNECT_SOCKS_READ: case CONNECT_AUTH_READ: case CONNECT_REQ_READ: case CONNECT_REQ_READ_MORE: rc = GETSOCK_READSOCK(0); break; default: rc = GETSOCK_WRITESOCK(0); break; } return rc; } /* * This function logs in to a SOCKS4 proxy and sends the specifics to the final * destination server. * * Reference : * https://www.openssh.com/txt/socks4.protocol * * Note : * Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" * Nonsupport "Identification Protocol (RFC1413)" */ CURLcode Curl_SOCKS4(const char *proxy_user, const char *hostname, int remote_port, int sockindex, struct connectdata *conn, bool *done) { const bool protocol4a = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; unsigned char *socksreq = &conn->cnnct.socksreq[0]; CURLcode result; curl_socket_t sockfd = conn->sock[sockindex]; struct Curl_easy *data = conn->data; struct connstate *sx = &conn->cnnct; struct Curl_dns_entry *dns = NULL; ssize_t actualread; ssize_t written; if(!SOCKS_STATE(sx->state) && !*done) sxstate(conn, CONNECT_SOCKS_INIT); switch(sx->state) { case CONNECT_SOCKS_INIT: if(conn->bits.httpproxy) infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", protocol4a ? "a" : "", hostname, remote_port); infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); /* * Compose socks4 request * * Request format * * +----+----+----+----+----+----+----+----+----+----+....+----+ * | VN | CD | DSTPORT | DSTIP | USERID |NULL| * +----+----+----+----+----+----+----+----+----+----+....+----+ * # of bytes: 1 1 2 4 variable 1 */ socksreq[0] = 4; /* version (SOCKS4) */ socksreq[1] = 1; /* connect */ socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */ socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */ /* DNS resolve only for SOCKS4, not SOCKS4a */ if(!protocol4a) { enum resolve_t rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns); if(rc == CURLRESOLV_ERROR) return CURLE_COULDNT_RESOLVE_PROXY; else if(rc == CURLRESOLV_PENDING) { sxstate(conn, CONNECT_RESOLVING); infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname); return CURLE_OK; } sxstate(conn, CONNECT_RESOLVED); goto CONNECT_RESOLVED; } /* socks4a doesn't resolve anything locally */ sxstate(conn, CONNECT_REQ_INIT); goto CONNECT_REQ_INIT; case CONNECT_RESOLVING: /* check if we have the name resolved by now */ dns = Curl_fetch_addr(conn, hostname, (int)conn->port); if(dns) { #ifdef CURLRES_ASYNCH conn->async.dns = dns; conn->async.done = TRUE; #endif infof(data, "Hostname '%s' was found\n", hostname); sxstate(conn, CONNECT_RESOLVED); } else { result = Curl_resolv_check(data->conn, &dns); /* stay in the state or error out */ return result; } /* FALLTHROUGH */ CONNECT_RESOLVED: case CONNECT_RESOLVED: { Curl_addrinfo *hp = NULL; char buf[64]; /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It * returns a Curl_addrinfo pointer that may not always look the same. */ if(dns) hp = dns->addr; if(hp) { Curl_printable_address(hp, buf, sizeof(buf)); if(hp->ai_family == AF_INET) { struct sockaddr_in *saddr_in; saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf); } else { hp = NULL; /* fail! */ failf(data, "SOCKS4 connection to %s not supported\n", buf); } Curl_resolv_unlock(data, dns); /* not used anymore from now on */ } if(!hp) { failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", hostname); return CURLE_COULDNT_RESOLVE_HOST; } } /* FALLTHROUGH */ CONNECT_REQ_INIT: case CONNECT_REQ_INIT: /* * This is currently not supporting "Identification Protocol (RFC1413)". */ socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ if(proxy_user) { size_t plen = strlen(proxy_user); if(plen >= sizeof(sx->socksreq) - 8) { failf(data, "Too long SOCKS proxy name, can't use!\n"); return CURLE_COULDNT_CONNECT; } /* copy the proxy name WITH trailing zero */ memcpy(socksreq + 8, proxy_user, plen + 1); } /* * Make connection */ { ssize_t packetsize = 9 + strlen((char *)socksreq + 8); /* size including NUL */ /* If SOCKS4a, set special invalid IP address 0.0.0.x */ if(protocol4a) { ssize_t hostnamelen = 0; socksreq[4] = 0; socksreq[5] = 0; socksreq[6] = 0; socksreq[7] = 1; /* append hostname */ hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ if(hostnamelen <= 255) strcpy((char *)socksreq + packetsize, hostname); else { failf(data, "SOCKS4: too long host name"); return CURLE_COULDNT_CONNECT; } packetsize += hostnamelen; } sx->outp = socksreq; sx->outstanding = packetsize; sxstate(conn, CONNECT_REQ_SENDING); } /* FALLTHROUGH */ case CONNECT_REQ_SENDING: /* Send request */ result = Curl_write_plain(conn, sockfd, (char *)sx->outp, sx->outstanding, &written); if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to send SOCKS4 connect request."); return CURLE_COULDNT_CONNECT; } if(written != sx->outstanding) { /* not done, remain in state */ sx->outstanding -= written; sx->outp += written; return CURLE_OK; } /* done sending! */ sx->outstanding = 8; /* receive data size */ sx->outp = socksreq; sxstate(conn, CONNECT_SOCKS_READ); /* FALLTHROUGH */ case CONNECT_SOCKS_READ: /* Receive response */ result = Curl_read_plain(sockfd, (char *)sx->outp, sx->outstanding, &actualread); if(result && (CURLE_AGAIN != result)) { failf(data, "SOCKS4: Failed receiving connect request ack: %s", curl_easy_strerror(result)); return CURLE_COULDNT_CONNECT; } else if(actualread != sx->outstanding) { /* remain in reading state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } sxstate(conn, CONNECT_DONE); break; default: /* lots of unused states in SOCKS4 */ break; } /* * Response format * * +----+----+----+----+----+----+----+----+ * | VN | CD | DSTPORT | DSTIP | * +----+----+----+----+----+----+----+----+ * # of bytes: 1 1 2 4 * * VN is the version of the reply code and should be 0. CD is the result * code with one of the following values: * * 90: request granted * 91: request rejected or failed * 92: request rejected because SOCKS server cannot connect to * identd on the client * 93: request rejected because the client program and identd * report different user-ids */ /* wrong version ? */ if(socksreq[0] != 0) { failf(data, "SOCKS4 reply has wrong version, version should be 0."); return CURLE_COULDNT_CONNECT; } /* Result */ switch(socksreq[1]) { case 90: infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); break; case 91: failf(data, "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected or failed.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 92: failf(data, "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected because SOCKS server cannot connect to " "identd on the client.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; case 93: failf(data, "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected because the client program and identd " "report different user-ids.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; default: failf(data, "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", Unknown.", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; } *done = TRUE; return CURLE_OK; /* Proxy was successful! */ } /* * This function logs in to a SOCKS5 proxy and sends the specifics to the final * destination server. */ CURLcode Curl_SOCKS5(const char *proxy_user, const char *proxy_password, const char *hostname, int remote_port, int sockindex, struct connectdata *conn, bool *done) { /* According to the RFC1928, section "6. Replies". This is what a SOCK5 replies: +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ Where: o VER protocol version: X'05' o REP Reply field: o X'00' succeeded */ unsigned char *socksreq = &conn->cnnct.socksreq[0]; char dest[256] = "unknown"; /* printable hostname:port */ int idx; ssize_t actualread; ssize_t written; CURLcode result; curl_socket_t sockfd = conn->sock[sockindex]; struct Curl_easy *data = conn->data; bool socks5_resolve_local = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(hostname); ssize_t len = 0; const unsigned long auth = data->set.socks5auth; bool allow_gssapi = FALSE; struct connstate *sx = &conn->cnnct; struct Curl_dns_entry *dns = NULL; if(!SOCKS_STATE(sx->state) && !*done) sxstate(conn, CONNECT_SOCKS_INIT); switch(sx->state) { case CONNECT_SOCKS_INIT: if(conn->bits.httpproxy) infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", hostname, remote_port); /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ if(!socks5_resolve_local && hostname_len > 255) { infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " "length > 255 [actual len=%zu]\n", hostname_len); socks5_resolve_local = TRUE; } if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) infof(conn->data, "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n", auth); if(!(auth & CURLAUTH_BASIC)) /* disable username/password auth */ proxy_user = NULL; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(auth & CURLAUTH_GSSAPI) allow_gssapi = TRUE; #endif idx = 0; socksreq[idx++] = 5; /* version */ idx++; /* number of authentication methods */ socksreq[idx++] = 0; /* no authentication */ if(allow_gssapi) socksreq[idx++] = 1; /* GSS-API */ if(proxy_user) socksreq[idx++] = 2; /* username/password */ /* write the number of authentication methods */ socksreq[1] = (unsigned char) (idx - 2); result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written); if(result && (CURLE_AGAIN != result)) { failf(data, "Unable to send initial SOCKS5 request."); return CURLE_COULDNT_CONNECT; } if(written != idx) { sxstate(conn, CONNECT_SOCKS_SEND); sx->outstanding = idx - written; sx->outp = &socksreq[written]; return CURLE_OK; } sxstate(conn, CONNECT_SOCKS_READ); goto CONNECT_SOCKS_READ_INIT; case CONNECT_SOCKS_SEND: result = Curl_write_plain(conn, sockfd, (char *)sx->outp, sx->outstanding, &written); if(result && (CURLE_AGAIN != result)) { failf(data, "Unable to send initial SOCKS5 request."); return CURLE_COULDNT_CONNECT; } if(written != sx->outstanding) { /* not done, remain in state */ sx->outstanding -= written; sx->outp += written; return CURLE_OK; } /* FALLTHROUGH */ CONNECT_SOCKS_READ_INIT: case CONNECT_SOCKS_READ_INIT: sx->outstanding = 2; /* expect two bytes */ sx->outp = socksreq; /* store it here */ /* FALLTHROUGH */ case CONNECT_SOCKS_READ: result = Curl_read_plain(sockfd, (char *)sx->outp, sx->outstanding, &actualread); if(result && (CURLE_AGAIN != result)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; } else if(actualread != sx->outstanding) { /* remain in reading state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } else if(socksreq[0] != 5) { failf(data, "Received invalid version in initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; } else if(socksreq[1] == 0) { /* DONE! No authentication needed. Send request. */ sxstate(conn, CONNECT_REQ_INIT); goto CONNECT_REQ_INIT; } else if(socksreq[1] == 2) { /* regular name + password authentication */ sxstate(conn, CONNECT_AUTH_INIT); goto CONNECT_AUTH_INIT; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) else if(allow_gssapi && (socksreq[1] == 1)) { sxstate(conn, CONNECT_GSSAPI_INIT); result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn); if(result) { failf(data, "Unable to negotiate SOCKS5 GSS-API context."); return CURLE_COULDNT_CONNECT; } } #endif else { /* error */ if(!allow_gssapi && (socksreq[1] == 1)) { failf(data, "SOCKS5 GSSAPI per-message authentication is not supported."); return CURLE_COULDNT_CONNECT; } else if(socksreq[1] == 255) { failf(data, "No authentication method was acceptable."); return CURLE_COULDNT_CONNECT; } failf(data, "Undocumented SOCKS5 mode attempted to be used by server."); return CURLE_COULDNT_CONNECT; } break; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CONNECT_GSSAPI_INIT: /* GSSAPI stuff done non-blocking */ break; #endif default: /* do nothing! */ break; CONNECT_AUTH_INIT: case CONNECT_AUTH_INIT: { /* Needs user name and password */ size_t proxy_user_len, proxy_password_len; if(proxy_user && proxy_password) { proxy_user_len = strlen(proxy_user); proxy_password_len = strlen(proxy_password); } else { proxy_user_len = 0; proxy_password_len = 0; } /* username/password request looks like * +----+------+----------+------+----------+ * |VER | ULEN | UNAME | PLEN | PASSWD | * +----+------+----------+------+----------+ * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | * +----+------+----------+------+----------+ */ len = 0; socksreq[len++] = 1; /* username/pw subnegotiation version */ socksreq[len++] = (unsigned char) proxy_user_len; if(proxy_user && proxy_user_len) { /* the length must fit in a single byte */ if(proxy_user_len >= 255) { failf(data, "Excessive user name length for proxy auth"); return CURLE_BAD_FUNCTION_ARGUMENT; } memcpy(socksreq + len, proxy_user, proxy_user_len); } len += proxy_user_len; socksreq[len++] = (unsigned char) proxy_password_len; if(proxy_password && proxy_password_len) { /* the length must fit in a single byte */ if(proxy_password_len > 255) { failf(data, "Excessive password length for proxy auth"); return CURLE_BAD_FUNCTION_ARGUMENT; } memcpy(socksreq + len, proxy_password, proxy_password_len); } len += proxy_password_len; sxstate(conn, CONNECT_AUTH_SEND); sx->outstanding = len; sx->outp = socksreq; } /* FALLTHROUGH */ case CONNECT_AUTH_SEND: result = Curl_write_plain(conn, sockfd, (char *)sx->outp, sx->outstanding, &written); if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to send SOCKS5 sub-negotiation request."); return CURLE_COULDNT_CONNECT; } if(sx->outstanding != written) { /* remain in state */ sx->outstanding -= written; sx->outp += written; return CURLE_OK; } sx->outp = socksreq; sx->outstanding = 2; sxstate(conn, CONNECT_AUTH_READ); /* FALLTHROUGH */ case CONNECT_AUTH_READ: result = Curl_read_plain(sockfd, (char *)sx->outp, sx->outstanding, &actualread); if(result && (CURLE_AGAIN != result)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; } if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } /* ignore the first (VER) byte */ if(socksreq[1] != 0) { /* status */ failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); return CURLE_COULDNT_CONNECT; } /* Everything is good so far, user was authenticated! */ sxstate(conn, CONNECT_REQ_INIT); /* FALLTHROUGH */ CONNECT_REQ_INIT: case CONNECT_REQ_INIT: if(socks5_resolve_local) { enum resolve_t rc = Curl_resolv(conn, hostname, remote_port, FALSE, &dns); if(rc == CURLRESOLV_ERROR) return CURLE_COULDNT_RESOLVE_HOST; if(rc == CURLRESOLV_PENDING) { sxstate(conn, CONNECT_RESOLVING); return CURLE_OK; } sxstate(conn, CONNECT_RESOLVED); goto CONNECT_RESOLVED; } goto CONNECT_RESOLVE_REMOTE; case CONNECT_RESOLVING: /* check if we have the name resolved by now */ dns = Curl_fetch_addr(conn, hostname, (int)conn->port); if(dns) { #ifdef CURLRES_ASYNCH conn->async.dns = dns; conn->async.done = TRUE; #endif infof(data, "SOCKS5: hostname '%s' found\n", hostname); } if(!dns) { result = Curl_resolv_check(data->conn, &dns); /* stay in the state or error out */ return result; } /* FALLTHROUGH */ CONNECT_RESOLVED: case CONNECT_RESOLVED: { Curl_addrinfo *hp = NULL; if(dns) hp = dns->addr; if(!hp) { failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", hostname); return CURLE_COULDNT_RESOLVE_HOST; } if(Curl_printable_address(hp, dest, sizeof(dest))) { size_t destlen = strlen(dest); msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port); } else { strcpy(dest, "unknown"); } len = 0; socksreq[len++] = 5; /* version (SOCKS5) */ socksreq[len++] = 1; /* connect */ socksreq[len++] = 0; /* must be zero */ if(hp->ai_family == AF_INET) { int i; struct sockaddr_in *saddr_in; socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; for(i = 0; i < 4; i++) { socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; } infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest); } #ifdef ENABLE_IPV6 else if(hp->ai_family == AF_INET6) { int i; struct sockaddr_in6 *saddr_in6; socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; for(i = 0; i < 16; i++) { socksreq[len++] = ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; } infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest); } #endif else { hp = NULL; /* fail! */ failf(data, "SOCKS5 connection to %s not supported\n", dest); } Curl_resolv_unlock(data, dns); /* not used anymore from now on */ goto CONNECT_REQ_SEND; } CONNECT_RESOLVE_REMOTE: case CONNECT_RESOLVE_REMOTE: /* Authentication is complete, now specify destination to the proxy */ len = 0; socksreq[len++] = 5; /* version (SOCKS5) */ socksreq[len++] = 1; /* connect */ socksreq[len++] = 0; /* must be zero */ if(!socks5_resolve_local) { socksreq[len++] = 3; /* ATYP: domain name = 3 */ socksreq[len++] = (char) hostname_len; /* one byte address length */ memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */ len += hostname_len; infof(data, "SOCKS5 connect to %s:%d (remotely resolved)\n", hostname, remote_port); } /* FALLTHROUGH */ CONNECT_REQ_SEND: case CONNECT_REQ_SEND: /* PORT MSB */ socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT LSB */ socksreq[len++] = (unsigned char)(remote_port & 0xff); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(conn->socks5_gssapi_enctype) { failf(data, "SOCKS5 GSS-API protection not yet implemented."); return CURLE_COULDNT_CONNECT; } #endif sx->outp = socksreq; sx->outstanding = len; sxstate(conn, CONNECT_REQ_SENDING); /* FALLTHROUGH */ case CONNECT_REQ_SENDING: result = Curl_write_plain(conn, sockfd, (char *)sx->outp, sx->outstanding, &written); if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to send SOCKS5 connect request."); return CURLE_COULDNT_CONNECT; } if(sx->outstanding != written) { /* remain in state */ sx->outstanding -= written; sx->outp += written; return CURLE_OK; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(conn->socks5_gssapi_enctype) { failf(data, "SOCKS5 GSS-API protection not yet implemented."); return CURLE_COULDNT_CONNECT; } #endif sx->outstanding = 10; /* minimum packet size is 10 */ sx->outp = socksreq; sxstate(conn, CONNECT_REQ_READ); /* FALLTHROUGH */ case CONNECT_REQ_READ: result = Curl_read_plain(sockfd, (char *)sx->outp, sx->outstanding, &actualread); if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } else if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } if(socksreq[0] != 5) { /* version */ failf(data, "SOCKS5 reply has wrong version, version should be 5."); return CURLE_COULDNT_CONNECT; } else if(socksreq[1] != 0) { /* Anything besides 0 is an error */ failf(data, "Can't complete SOCKS5 connection to %s. (%d)", hostname, (unsigned char)socksreq[1]); return CURLE_COULDNT_CONNECT; } /* Fix: in general, returned BND.ADDR is variable length parameter by RFC 1928, so the reply packet should be read until the end to avoid errors at subsequent protocol level. +----+-----+-------+------+----------+----------+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ ATYP: o IP v4 address: X'01', BND.ADDR = 4 byte o domain name: X'03', BND.ADDR = [ 1 byte length, string ] o IP v6 address: X'04', BND.ADDR = 16 byte */ /* Calculate real packet size */ if(socksreq[3] == 3) { /* domain name */ int addrlen = (int) socksreq[4]; len = 5 + addrlen + 2; } else if(socksreq[3] == 4) { /* IPv6 */ len = 4 + 16 + 2; } /* At this point we already read first 10 bytes */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) if(!conn->socks5_gssapi_enctype) { /* decrypt_gssapi_blockread already read the whole packet */ #endif if(len > 10) { sx->outstanding = len - 10; /* get the rest */ sx->outp = &socksreq[10]; sxstate(conn, CONNECT_REQ_READ_MORE); } else { sxstate(conn, CONNECT_DONE); break; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) } #endif /* FALLTHROUGH */ case CONNECT_REQ_READ_MORE: result = Curl_read_plain(sockfd, (char *)sx->outp, sx->outstanding, &actualread); if(result && (CURLE_AGAIN != result)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } if(actualread != sx->outstanding) { /* remain in state */ sx->outstanding -= actualread; sx->outp += actualread; return CURLE_OK; } sxstate(conn, CONNECT_DONE); } infof(data, "SOCKS5 request granted.\n"); *done = TRUE; return CURLE_OK; /* Proxy was successful! */ } #endif /* CURL_DISABLE_PROXY */ davix-0.8.0/deps/curl/lib/http_negotiate.c0000644000000000000000000001435114121063461017162 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) #include "urldata.h" #include "sendf.h" #include "http_negotiate.h" #include "vauth/vauth.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { CURLcode result; struct Curl_easy *data = conn->data; size_t len; /* Point to the username, password, service and host */ const char *userp; const char *passwdp; const char *service; const char *host; /* Point to the correct struct with this */ struct negotiatedata *neg_ctx; curlnegotiate state; if(proxy) { userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; host = conn->http_proxy.host.name; neg_ctx = &conn->proxyneg; state = conn->proxy_negotiate_state; } else { userp = conn->user; passwdp = conn->passwd; service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : "HTTP"; host = conn->host.name; neg_ctx = &conn->negotiate; state = conn->http_negotiate_state; } /* Not set means empty */ if(!userp) userp = ""; if(!passwdp) passwdp = ""; /* Obtain the input token, if any */ header += strlen("Negotiate"); while(*header && ISSPACE(*header)) header++; len = strlen(header); neg_ctx->havenegdata = len != 0; if(!len) { if(state == GSS_AUTHSUCC) { infof(conn->data, "Negotiate auth restarted\n"); Curl_http_auth_cleanup_negotiate(conn); } else if(state != GSS_AUTHNONE) { /* The server rejected our authentication and hasn't supplied any more negotiation mechanisms */ Curl_http_auth_cleanup_negotiate(conn); return CURLE_LOGIN_DENIED; } } /* Supports SSL channel binding for Windows ISS extended protection */ #if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS) neg_ctx->sslContext = conn->sslContext; #endif /* Initialize the security context and decode our challenge */ result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, host, header, neg_ctx); if(result) Curl_http_auth_cleanup_negotiate(conn); return result; } CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg : &conn->negotiate; struct auth *authp = proxy ? &conn->data->state.authproxy : &conn->data->state.authhost; curlnegotiate *state = proxy ? &conn->proxy_negotiate_state : &conn->http_negotiate_state; char *base64 = NULL; size_t len = 0; char *userp; CURLcode result; authp->done = FALSE; if(*state == GSS_AUTHRECV) { if(neg_ctx->havenegdata) { neg_ctx->havemultiplerequests = TRUE; } } else if(*state == GSS_AUTHSUCC) { if(!neg_ctx->havenoauthpersist) { neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests; } } if(neg_ctx->noauthpersist || (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) { if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) { infof(conn->data, "Curl_output_negotiate, " "no persistent authentication: cleanup existing context"); Curl_http_auth_cleanup_negotiate(conn); } if(!neg_ctx->context) { result = Curl_input_negotiate(conn, proxy, "Negotiate"); if(result == CURLE_AUTH_ERROR) { /* negotiate auth failed, let's continue unauthenticated to stay * compatible with the behavior before curl-7_64_0-158-g6c6035532 */ authp->done = TRUE; return CURLE_OK; } else if(result) return result; } result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len); if(result) return result; userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", base64); if(proxy) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = userp; } else { Curl_safefree(conn->allocptr.userpwd); conn->allocptr.userpwd = userp; } free(base64); if(userp == NULL) { return CURLE_OUT_OF_MEMORY; } *state = GSS_AUTHSENT; #ifdef HAVE_GSSAPI if(neg_ctx->status == GSS_S_COMPLETE || neg_ctx->status == GSS_S_CONTINUE_NEEDED) { *state = GSS_AUTHDONE; } #else #ifdef USE_WINDOWS_SSPI if(neg_ctx->status == SEC_E_OK || neg_ctx->status == SEC_I_CONTINUE_NEEDED) { *state = GSS_AUTHDONE; } #endif #endif } if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) { /* connection is already authenticated, * don't send a header in future requests */ authp->done = TRUE; } neg_ctx->havenegdata = FALSE; return CURLE_OK; } void Curl_http_auth_cleanup_negotiate(struct connectdata *conn) { conn->http_negotiate_state = GSS_AUTHNONE; conn->proxy_negotiate_state = GSS_AUTHNONE; Curl_auth_cleanup_spnego(&conn->negotiate); Curl_auth_cleanup_spnego(&conn->proxyneg); } #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ davix-0.8.0/deps/curl/lib/dict.c0000644000000000000000000001705314121063461015071 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_DICT #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "escape.h" #include "progress.h" #include "dict.h" #include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * Forward declarations. */ static CURLcode dict_do(struct connectdata *conn, bool *done); /* * DICT protocol handler. */ const struct Curl_handler Curl_handler_dict = { "DICT", /* scheme */ ZERO_NULL, /* setup_connection */ dict_do, /* do_it */ ZERO_NULL, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_DICT, /* defport */ CURLPROTO_DICT, /* protocol */ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; static char *unescape_word(struct Curl_easy *data, const char *inputbuff) { char *newp = NULL; char *dictp; size_t len; CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); if(!newp || result) return NULL; dictp = malloc(len*2 + 1); /* add one for terminating zero */ if(dictp) { char *ptr; char ch; int olen = 0; /* According to RFC2229 section 2.2, these letters need to be escaped with \[letter] */ for(ptr = newp; (ch = *ptr) != 0; ptr++) { if((ch <= 32) || (ch == 127) || (ch == '\'') || (ch == '\"') || (ch == '\\')) { dictp[olen++] = '\\'; } dictp[olen++] = ch; } dictp[olen] = 0; } free(newp); return dictp; } static CURLcode dict_do(struct connectdata *conn, bool *done) { char *word; char *eword; char *ppath; char *database = NULL; char *strategy = NULL; char *nthdef = NULL; /* This is not part of the protocol, but required by RFC 2229 */ CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; char *path = data->state.up.path; *done = TRUE; /* unconditionally */ if(conn->bits.user_passwd) { /* AUTH is missing */ } if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { word = strchr(path, ':'); if(word) { word++; database = strchr(word, ':'); if(database) { *database++ = (char)0; strategy = strchr(database, ':'); if(strategy) { *strategy++ = (char)0; nthdef = strchr(strategy, ':'); if(nthdef) { *nthdef = (char)0; } } } } if((word == NULL) || (*word == (char)0)) { infof(data, "lookup word is missing\n"); word = (char *)"default"; } if((database == NULL) || (*database == (char)0)) { database = (char *)"!"; } if((strategy == NULL) || (*strategy == (char)0)) { strategy = (char *)"."; } eword = unescape_word(data, word); if(!eword) return CURLE_OUT_OF_MEMORY; result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" "MATCH " "%s " /* database */ "%s " /* strategy */ "%s\r\n" /* word */ "QUIT\r\n", database, strategy, eword ); free(eword); if(result) { failf(data, "Failed sending DICT request"); return result; } Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */ } else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { word = strchr(path, ':'); if(word) { word++; database = strchr(word, ':'); if(database) { *database++ = (char)0; nthdef = strchr(database, ':'); if(nthdef) { *nthdef = (char)0; } } } if((word == NULL) || (*word == (char)0)) { infof(data, "lookup word is missing\n"); word = (char *)"default"; } if((database == NULL) || (*database == (char)0)) { database = (char *)"!"; } eword = unescape_word(data, word); if(!eword) return CURLE_OUT_OF_MEMORY; result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" "DEFINE " "%s " /* database */ "%s\r\n" /* word */ "QUIT\r\n", database, eword); free(eword); if(result) { failf(data, "Failed sending DICT request"); return result; } Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); } else { ppath = strchr(path, '/'); if(ppath) { int i; ppath++; for(i = 0; ppath[i]; i++) { if(ppath[i] == ':') ppath[i] = ' '; } result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n" "%s\r\n" "QUIT\r\n", ppath); if(result) { failf(data, "Failed sending DICT request"); return result; } Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); } } return CURLE_OK; } #endif /*CURL_DISABLE_DICT*/ davix-0.8.0/deps/curl/lib/curl_md4.h0000644000000000000000000000251514121063461015661 0ustar rootroot#ifndef HEADER_CURL_MD4_H #define HEADER_CURL_MD4_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_CRYPTO_AUTH) #define MD4_DIGEST_LENGTH 16 void Curl_md4it(unsigned char *output, const unsigned char *input, const size_t len); #endif /* !defined(CURL_DISABLE_CRYPTO_AUTH) */ #endif /* HEADER_CURL_MD4_H */ davix-0.8.0/deps/curl/lib/curl_get_line.h0000644000000000000000000000241714121063461016764 0ustar rootroot#ifndef HEADER_CURL_GET_LINE_H #define HEADER_CURL_GET_LINE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* get_line() makes sure to only return complete whole lines that fit in 'len' * bytes and end with a newline. */ char *Curl_get_line(char *buf, int len, FILE *input); #endif /* HEADER_CURL_GET_LINE_H */ davix-0.8.0/deps/curl/lib/dict.h0000644000000000000000000000225714121063461015076 0ustar rootroot#ifndef HEADER_CURL_DICT_H #define HEADER_CURL_DICT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_DICT extern const struct Curl_handler Curl_handler_dict; #endif #endif /* HEADER_CURL_DICT_H */ davix-0.8.0/deps/curl/lib/non-ascii.c0000644000000000000000000002307214121063461016024 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef CURL_DOES_CONVERSIONS #include #include "non-ascii.h" #include "formdata.h" #include "sendf.h" #include "urldata.h" #include "multiif.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #ifdef HAVE_ICONV #include /* set default codesets for iconv */ #ifndef CURL_ICONV_CODESET_OF_NETWORK #define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" #endif #ifndef CURL_ICONV_CODESET_FOR_UTF8 #define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8" #endif #define ICONV_ERROR (size_t)-1 #endif /* HAVE_ICONV */ /* * Curl_convert_clone() returns a malloced copy of the source string (if * returning CURLE_OK), with the data converted to network format. */ CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf) { char *convbuf; CURLcode result; convbuf = malloc(insize); if(!convbuf) return CURLE_OUT_OF_MEMORY; memcpy(convbuf, indata, insize); result = Curl_convert_to_network(data, convbuf, insize); if(result) { free(convbuf); return result; } *outbuf = convbuf; /* return the converted buffer */ return CURLE_OK; } /* * Curl_convert_to_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It converts the buffer _in place_. */ CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length) { if(data && data->set.convtonetwork) { /* use translation callback */ CURLcode result; Curl_set_in_callback(data, true); result = data->set.convtonetwork(buffer, length); Curl_set_in_callback(data, false); if(result) { failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s", (int)result, curl_easy_strerror(result)); } return result; } else { #ifdef HAVE_ICONV /* do the translation ourselves */ iconv_t tmpcd = (iconv_t) -1; iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; /* open an iconv conversion descriptor if necessary */ if(data) cd = &data->outbound_cd; if(*cd == (iconv_t)-1) { *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST); if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST, errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if(!data) iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { failf(data, "The Curl_convert_to_network iconv call failed with errno %i: %s", errno, strerror(errno)); return CURLE_CONV_FAILED; } #else failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required"); return CURLE_CONV_REQD; #endif /* HAVE_ICONV */ } return CURLE_OK; } /* * Curl_convert_from_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It converts the buffer _in place_. */ CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length) { if(data && data->set.convfromnetwork) { /* use translation callback */ CURLcode result; Curl_set_in_callback(data, true); result = data->set.convfromnetwork(buffer, length); Curl_set_in_callback(data, false); if(result) { failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s", (int)result, curl_easy_strerror(result)); } return result; } else { #ifdef HAVE_ICONV /* do the translation ourselves */ iconv_t tmpcd = (iconv_t) -1; iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; /* open an iconv conversion descriptor if necessary */ if(data) cd = &data->inbound_cd; if(*cd == (iconv_t)-1) { *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK, errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if(!data) iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { failf(data, "Curl_convert_from_network iconv call failed with errno %i: %s", errno, strerror(errno)); return CURLE_CONV_FAILED; } #else failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required"); return CURLE_CONV_REQD; #endif /* HAVE_ICONV */ } return CURLE_OK; } /* * Curl_convert_from_utf8() is an internal function for performing UTF-8 * conversions on non-ASCII platforms. */ CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length) { if(data && data->set.convfromutf8) { /* use translation callback */ CURLcode result; Curl_set_in_callback(data, true); result = data->set.convfromutf8(buffer, length); Curl_set_in_callback(data, false); if(result) { failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s", (int)result, curl_easy_strerror(result)); } return result; } else { #ifdef HAVE_ICONV /* do the translation ourselves */ iconv_t tmpcd = (iconv_t) -1; iconv_t *cd = &tmpcd; char *input_ptr; char *output_ptr; size_t in_bytes, out_bytes, rc; /* open an iconv conversion descriptor if necessary */ if(data) cd = &data->utf8_cd; if(*cd == (iconv_t)-1) { *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_FOR_UTF8); if(*cd == (iconv_t)-1) { failf(data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_FOR_UTF8, errno, strerror(errno)); return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; rc = iconv(*cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if(!data) iconv_close(tmpcd); if((rc == ICONV_ERROR) || (in_bytes != 0)) { failf(data, "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", errno, strerror(errno)); return CURLE_CONV_FAILED; } if(output_ptr < input_ptr) { /* null terminate the now shorter output string */ *output_ptr = 0x00; } #else failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required"); return CURLE_CONV_REQD; #endif /* HAVE_ICONV */ } return CURLE_OK; } /* * Init conversion stuff for a Curl_easy */ void Curl_convert_init(struct Curl_easy *data) { #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) /* conversion descriptors for iconv calls */ data->outbound_cd = (iconv_t)-1; data->inbound_cd = (iconv_t)-1; data->utf8_cd = (iconv_t)-1; #else (void)data; #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ } /* * Setup conversion stuff for a Curl_easy */ void Curl_convert_setup(struct Curl_easy *data) { data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST); data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_FOR_UTF8); } /* * Close conversion stuff for a Curl_easy */ void Curl_convert_close(struct Curl_easy *data) { #ifdef HAVE_ICONV /* close iconv conversion descriptors */ if(data->inbound_cd != (iconv_t)-1) { iconv_close(data->inbound_cd); } if(data->outbound_cd != (iconv_t)-1) { iconv_close(data->outbound_cd); } if(data->utf8_cd != (iconv_t)-1) { iconv_close(data->utf8_cd); } #else (void)data; #endif /* HAVE_ICONV */ } #endif /* CURL_DOES_CONVERSIONS */ davix-0.8.0/deps/curl/lib/llist.c0000644000000000000000000000637014121063461015275 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "llist.h" #include "curl_memory.h" /* this must be the last include file */ #include "memdebug.h" /* * @unittest: 1300 */ void Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor) { l->size = 0; l->dtor = dtor; l->head = NULL; l->tail = NULL; } /* * Curl_llist_insert_next() * * Inserts a new list element after the given one 'e'. If the given existing * entry is NULL and the list already has elements, the new one will be * inserted first in the list. * * The 'ne' argument should be a pointer into the object to store. * * @unittest: 1300 */ void Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, const void *p, struct curl_llist_element *ne) { ne->ptr = (void *) p; if(list->size == 0) { list->head = ne; list->head->prev = NULL; list->head->next = NULL; list->tail = ne; } else { /* if 'e' is NULL here, we insert the new element first in the list */ ne->next = e?e->next:list->head; ne->prev = e; if(!e) { list->head->prev = ne; list->head = ne; } else if(e->next) { e->next->prev = ne; } else { list->tail = ne; } if(e) e->next = ne; } ++list->size; } /* * @unittest: 1300 */ void Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, void *user) { void *ptr; if(e == NULL || list->size == 0) return; if(e == list->head) { list->head = e->next; if(list->head == NULL) list->tail = NULL; else e->next->prev = NULL; } else { if(!e->prev) list->head = e->next; else e->prev->next = e->next; if(!e->next) list->tail = e->prev; else e->next->prev = e->prev; } ptr = e->ptr; e->ptr = NULL; e->prev = NULL; e->next = NULL; --list->size; /* call the dtor() last for when it actually frees the 'e' memory itself */ if(list->dtor) list->dtor(user, ptr); } void Curl_llist_destroy(struct curl_llist *list, void *user) { if(list) { while(list->size > 0) Curl_llist_remove(list, list->tail, user); } } size_t Curl_llist_count(struct curl_llist *list) { return list->size; } davix-0.8.0/deps/curl/lib/urlapi.c0000644000000000000000000011520314121063461015436 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #include "urlapi-int.h" #include "strcase.h" #include "dotdot.h" #include "url.h" #include "escape.h" #include "curl_ctype.h" #include "inet_pton.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* MSDOS/Windows style drive prefix, eg c: in c:foo */ #define STARTS_WITH_DRIVE_PREFIX(str) \ ((('a' <= str[0] && str[0] <= 'z') || \ ('A' <= str[0] && str[0] <= 'Z')) && \ (str[1] == ':')) /* MSDOS/Windows style drive prefix, optionally with * a '|' instead of ':', followed by a slash or NUL */ #define STARTS_WITH_URL_DRIVE_PREFIX(str) \ ((('a' <= (str)[0] && (str)[0] <= 'z') || \ ('A' <= (str)[0] && (str)[0] <= 'Z')) && \ ((str)[1] == ':' || (str)[1] == '|') && \ ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0)) /* Internal representation of CURLU. Point to URL-encoded strings. */ struct Curl_URL { char *scheme; char *user; char *password; char *options; /* IMAP only? */ char *host; char *zoneid; /* for numerical IPv6 addresses */ char *port; char *path; char *query; char *fragment; char *scratch; /* temporary scratch area */ char *temppath; /* temporary path pointer */ long portnum; /* the numerical version */ }; #define DEFAULT_SCHEME "https" static void free_urlhandle(struct Curl_URL *u) { free(u->scheme); free(u->user); free(u->password); free(u->options); free(u->host); free(u->zoneid); free(u->port); free(u->path); free(u->query); free(u->fragment); free(u->scratch); free(u->temppath); } /* move the full contents of one handle onto another and free the original */ static void mv_urlhandle(struct Curl_URL *from, struct Curl_URL *to) { free_urlhandle(to); *to = *from; free(from); } /* * Find the separator at the end of the host name, or the '?' in cases like * http://www.url.com?id=2380 */ static const char *find_host_sep(const char *url) { const char *sep; const char *query; /* Find the start of the hostname */ sep = strstr(url, "//"); if(!sep) sep = url; else sep += 2; query = strchr(sep, '?'); sep = strchr(sep, '/'); if(!sep) sep = url + strlen(url); if(!query) query = url + strlen(url); return sep < query ? sep : query; } /* * Decide in an encoding-independent manner whether a character in an * URL must be escaped. The same criterion must be used in strlen_url() * and strcpy_url(). */ static bool urlchar_needs_escaping(int c) { return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)); } /* * strlen_url() returns the length of the given URL if the spaces within the * URL were properly URL encoded. * URL encoding should be skipped for host names, otherwise IDN resolution * will fail. */ static size_t strlen_url(const char *url, bool relative) { const unsigned char *ptr; size_t newlen = 0; bool left = TRUE; /* left side of the ? */ const unsigned char *host_sep = (const unsigned char *) url; if(!relative) host_sep = (const unsigned char *) find_host_sep(url); for(ptr = (unsigned char *)url; *ptr; ptr++) { if(ptr < host_sep) { ++newlen; continue; } switch(*ptr) { case '?': left = FALSE; /* FALLTHROUGH */ default: if(urlchar_needs_escaping(*ptr)) newlen += 2; newlen++; break; case ' ': if(left) newlen += 3; else newlen++; break; } } return newlen; } /* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in * the source URL accordingly. * URL encoding should be skipped for host names, otherwise IDN resolution * will fail. */ static void strcpy_url(char *output, const char *url, bool relative) { /* we must add this with whitespace-replacing */ bool left = TRUE; const unsigned char *iptr; char *optr = output; const unsigned char *host_sep = (const unsigned char *) url; if(!relative) host_sep = (const unsigned char *) find_host_sep(url); for(iptr = (unsigned char *)url; /* read from here */ *iptr; /* until zero byte */ iptr++) { if(iptr < host_sep) { *optr++ = *iptr; continue; } switch(*iptr) { case '?': left = FALSE; /* FALLTHROUGH */ default: if(urlchar_needs_escaping(*iptr)) { msnprintf(optr, 4, "%%%02x", *iptr); optr += 3; } else *optr++=*iptr; break; case ' ': if(left) { *optr++='%'; /* add a '%' */ *optr++='2'; /* add a '2' */ *optr++='0'; /* add a '0' */ } else *optr++='+'; /* add a '+' here */ break; } } *optr = 0; /* zero terminate output buffer */ } /* * Returns true if the given URL is absolute (as opposed to relative) within * the buffer size. Returns the scheme in the buffer if TRUE and 'buf' is * non-NULL. */ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) { size_t i; #ifdef WIN32 if(STARTS_WITH_DRIVE_PREFIX(url)) return FALSE; #endif for(i = 0; i < buflen && url[i]; ++i) { char s = url[i]; if((s == ':') && (url[i + 1] == '/')) { if(buf) buf[i] = 0; return TRUE; } /* RFC 3986 3.1 explains: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) { if(buf) buf[i] = (char)TOLOWER(s); } else break; } return FALSE; } /* * Concatenate a relative URL to a base URL making it absolute. * URL-encodes any spaces. * The returned pointer must be freed by the caller unless NULL * (returns NULL on out of memory). */ static char *concat_url(const char *base, const char *relurl) { /*** TRY to append this new path to the old URL to the right of the host part. Oh crap, this is doomed to cause problems in the future... */ char *newest; char *protsep; char *pathsep; size_t newlen; bool host_changed = FALSE; const char *useurl = relurl; size_t urllen; /* we must make our own copy of the URL to play with, as it may point to read-only data */ char *url_clone = strdup(base); if(!url_clone) return NULL; /* skip out of this NOW */ /* protsep points to the start of the host name */ protsep = strstr(url_clone, "//"); if(!protsep) protsep = url_clone; else protsep += 2; /* pass the slashes */ if('/' != relurl[0]) { int level = 0; /* First we need to find out if there's a ?-letter in the URL, and cut it and the right-side of that off */ pathsep = strchr(protsep, '?'); if(pathsep) *pathsep = 0; /* we have a relative path to append to the last slash if there's one available, or if the new URL is just a query string (starts with a '?') we append the new one at the end of the entire currently worked out URL */ if(useurl[0] != '?') { pathsep = strrchr(protsep, '/'); if(pathsep) *pathsep = 0; } /* Check if there's any slash after the host name, and if so, remember that position instead */ pathsep = strchr(protsep, '/'); if(pathsep) protsep = pathsep + 1; else protsep = NULL; /* now deal with one "./" or any amount of "../" in the newurl and act accordingly */ if((useurl[0] == '.') && (useurl[1] == '/')) useurl += 2; /* just skip the "./" */ while((useurl[0] == '.') && (useurl[1] == '.') && (useurl[2] == '/')) { level++; useurl += 3; /* pass the "../" */ } if(protsep) { while(level--) { /* cut off one more level from the right of the original URL */ pathsep = strrchr(protsep, '/'); if(pathsep) *pathsep = 0; else { *protsep = 0; break; } } } } else { /* We got a new absolute path for this server */ if(relurl[1] == '/') { /* the new URL starts with //, just keep the protocol part from the original one */ *protsep = 0; useurl = &relurl[2]; /* we keep the slashes from the original, so we skip the new ones */ host_changed = TRUE; } else { /* cut off the original URL from the first slash, or deal with URLs without slash */ pathsep = strchr(protsep, '/'); if(pathsep) { /* When people use badly formatted URLs, such as "http://www.url.com?dir=/home/daniel" we must not use the first slash, if there's a ?-letter before it! */ char *sep = strchr(protsep, '?'); if(sep && (sep < pathsep)) pathsep = sep; *pathsep = 0; } else { /* There was no slash. Now, since we might be operating on a badly formatted URL, such as "http://www.url.com?id=2380" which doesn't use a slash separator as it is supposed to, we need to check for a ?-letter as well! */ pathsep = strchr(protsep, '?'); if(pathsep) *pathsep = 0; } } } /* If the new part contains a space, this is a mighty stupid redirect but we still make an effort to do "right". To the left of a '?' letter we replace each space with %20 while it is replaced with '+' on the right side of the '?' letter. */ newlen = strlen_url(useurl, !host_changed); urllen = strlen(url_clone); newest = malloc(urllen + 1 + /* possible slash */ newlen + 1 /* zero byte */); if(!newest) { free(url_clone); /* don't leak this */ return NULL; } /* copy over the root url part */ memcpy(newest, url_clone, urllen); /* check if we need to append a slash */ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) ; else newest[urllen++]='/'; /* then append the new piece on the right side */ strcpy_url(&newest[urllen], useurl, !host_changed); free(url_clone); return newest; } /* * parse_hostname_login() * * Parse the login details (user name, password and options) from the URL and * strip them out of the host name * */ static CURLUcode parse_hostname_login(struct Curl_URL *u, char **hostname, unsigned int flags) { CURLUcode result = CURLUE_OK; CURLcode ccode; char *userp = NULL; char *passwdp = NULL; char *optionsp = NULL; const struct Curl_handler *h = NULL; /* At this point, we're hoping all the other special cases have * been taken care of, so conn->host.name is at most * [user[:password][;options]]@]hostname * * We need somewhere to put the embedded details, so do that first. */ char *ptr = strchr(*hostname, '@'); char *login = *hostname; if(!ptr) goto out; /* We will now try to extract the * possible login information in a string like: * ftp://user:password@ftp.my.site:8021/README */ *hostname = ++ptr; /* if this is a known scheme, get some details */ if(u->scheme) h = Curl_builtin_scheme(u->scheme); /* We could use the login information in the URL so extract it. Only parse options if the handler says we should. Note that 'h' might be NULL! */ ccode = Curl_parse_login_details(login, ptr - login - 1, &userp, &passwdp, (h && (h->flags & PROTOPT_URLOPTIONS)) ? &optionsp:NULL); if(ccode) { result = CURLUE_MALFORMED_INPUT; goto out; } if(userp) { if(flags & CURLU_DISALLOW_USER) { /* Option DISALLOW_USER is set and url contains username. */ result = CURLUE_USER_NOT_ALLOWED; goto out; } u->user = userp; } if(passwdp) u->password = passwdp; if(optionsp) u->options = optionsp; return CURLUE_OK; out: free(userp); free(passwdp); free(optionsp); return result; } UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname) { char *portptr = NULL; char endbracket; int len; /* * Find the end of an IPv6 address, either on the ']' ending bracket or * a percent-encoded zone index. */ if(1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.]%c%n", &endbracket, &len)) { if(']' == endbracket) portptr = &hostname[len]; else if('%' == endbracket) { int zonelen = len; if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) { if(']' != endbracket) return CURLUE_MALFORMED_INPUT; portptr = &hostname[--zonelen + len + 1]; } else return CURLUE_MALFORMED_INPUT; } else return CURLUE_MALFORMED_INPUT; /* this is a RFC2732-style specified IP-address */ if(portptr && *portptr) { if(*portptr != ':') return CURLUE_MALFORMED_INPUT; } else portptr = NULL; } else portptr = strchr(hostname, ':'); if(portptr) { char *rest; long port; char portbuf[7]; /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just use the default port. Firefox, Chrome and Safari all do that. */ if(!portptr[1]) { *portptr = '\0'; return CURLUE_OK; } if(!ISDIGIT(portptr[1])) return CURLUE_BAD_PORT_NUMBER; port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ if((port <= 0) || (port > 0xffff)) /* Single unix standard says port numbers are 16 bits long, but we don't treat port zero as OK. */ return CURLUE_BAD_PORT_NUMBER; if(rest[0]) return CURLUE_BAD_PORT_NUMBER; *portptr++ = '\0'; /* cut off the name there */ *rest = 0; /* generate a new port number string to get rid of leading zeroes etc */ msnprintf(portbuf, sizeof(portbuf), "%ld", port); u->portnum = port; u->port = strdup(portbuf); if(!u->port) return CURLUE_OUT_OF_MEMORY; } return CURLUE_OK; } /* scan for byte values < 31 or 127 */ static CURLUcode junkscan(const char *part) { if(part) { static const char badbytes[]={ /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x7f, 0x00 /* zero terminate */ }; size_t n = strlen(part); size_t nfine = strcspn(part, badbytes); if(nfine != n) /* since we don't know which part is scanned, return a generic error code */ return CURLUE_MALFORMED_INPUT; } return CURLUE_OK; } static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) { size_t len; size_t hlen = strlen(hostname); if(hostname[0] == '[') { #ifdef ENABLE_IPV6 char dest[16]; /* fits a binary IPv6 address */ #endif const char *l = "0123456789abcdefABCDEF:."; if(hlen < 5) /* '[::1]' is the shortest possible valid string */ return CURLUE_MALFORMED_INPUT; hostname++; hlen -= 2; if(hostname[hlen] != ']') return CURLUE_MALFORMED_INPUT; /* only valid letters are ok */ len = strspn(hostname, l); if(hlen != len) { hlen = len; if(hostname[len] == '%') { /* this could now be '%[zone id]' */ char zoneid[16]; int i = 0; char *h = &hostname[len + 1]; /* pass '25' if present and is a url encoded percent sign */ if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']')) h += 2; while(*h && (*h != ']') && (i < 15)) zoneid[i++] = *h++; if(!i || (']' != *h)) return CURLUE_MALFORMED_INPUT; zoneid[i] = 0; u->zoneid = strdup(zoneid); if(!u->zoneid) return CURLUE_OUT_OF_MEMORY; hostname[len] = ']'; /* insert end bracket */ hostname[len + 1] = 0; /* terminate the hostname */ } else return CURLUE_MALFORMED_INPUT; /* hostname is fine */ } #ifdef ENABLE_IPV6 hostname[hlen] = 0; /* end the address there */ if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) return CURLUE_MALFORMED_INPUT; hostname[hlen] = ']'; /* restore ending bracket */ #endif } else { /* letters from the second string is not ok */ len = strcspn(hostname, " "); if(hlen != len) /* hostname with bad content */ return CURLUE_MALFORMED_INPUT; } if(!hostname[0]) return CURLUE_NO_HOST; return CURLUE_OK; } #define HOSTNAME_END(x) (((x) == '/') || ((x) == '?') || ((x) == '#')) static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) { char *path; bool path_alloced = FALSE; char *hostname; char *query = NULL; char *fragment = NULL; CURLUcode result; bool url_has_scheme = FALSE; char schemebuf[MAX_SCHEME_LEN + 1]; const char *schemep = NULL; size_t schemelen = 0; size_t urllen; if(!url) return CURLUE_MALFORMED_INPUT; /************************************************************* * Parse the URL. ************************************************************/ /* allocate scratch area */ urllen = strlen(url); if(urllen > CURL_MAX_INPUT_LENGTH) /* excessive input length */ return CURLUE_MALFORMED_INPUT; path = u->scratch = malloc(urllen * 2 + 2); if(!path) return CURLUE_OUT_OF_MEMORY; hostname = &path[urllen + 1]; hostname[0] = 0; if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) { url_has_scheme = TRUE; schemelen = strlen(schemebuf); } /* handle the file: scheme */ if(url_has_scheme && strcasecompare(schemebuf, "file")) { /* path has been allocated large enough to hold this */ strcpy(path, &url[5]); hostname = NULL; /* no host for file: URLs */ u->scheme = strdup("file"); if(!u->scheme) return CURLUE_OUT_OF_MEMORY; /* Extra handling URLs with an authority component (i.e. that start with * "file://") * * We allow omitted hostname (e.g. file:/) -- valid according to * RFC 8089, but not the (current) WHAT-WG URL spec. */ if(path[0] == '/' && path[1] == '/') { /* swallow the two slashes */ char *ptr = &path[2]; /* * According to RFC 8089, a file: URL can be reliably dereferenced if: * * o it has no/blank hostname, or * * o the hostname matches "localhost" (case-insensitively), or * * o the hostname is a FQDN that resolves to this machine. * * For brevity, we only consider URLs with empty, "localhost", or * "127.0.0.1" hostnames as local. * * Additionally, there is an exception for URLs with a Windows drive * letter in the authority (which was accidentally omitted from RFC 8089 * Appendix E, but believe me, it was meant to be there. --MK) */ if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) { /* the URL includes a host name, it must match "localhost" or "127.0.0.1" to be valid */ if(!checkprefix("localhost/", ptr) && !checkprefix("127.0.0.1/", ptr)) { /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ return CURLUE_MALFORMED_INPUT; } ptr += 9; /* now points to the slash after the host */ } path = ptr; } #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) /* Don't allow Windows drive letters when not in Windows. * This catches both "file:/c:" and "file:c:" */ if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || STARTS_WITH_URL_DRIVE_PREFIX(path)) { /* File drive letters are only accepted in MSDOS/Windows */ return CURLUE_MALFORMED_INPUT; } #else /* If the path starts with a slash and a drive letter, ditch the slash */ if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) { /* This cannot be done with strcpy, as the memory chunks overlap! */ memmove(path, &path[1], strlen(&path[1]) + 1); } #endif } else { /* clear path */ const char *p; const char *hostp; size_t len; path[0] = 0; if(url_has_scheme) { int i = 0; p = &url[schemelen + 1]; while(p && (*p == '/') && (i < 4)) { p++; i++; } if((i < 1) || (i>3)) /* less than one or more than three slashes */ return CURLUE_MALFORMED_INPUT; schemep = schemebuf; if(!Curl_builtin_scheme(schemep) && !(flags & CURLU_NON_SUPPORT_SCHEME)) return CURLUE_UNSUPPORTED_SCHEME; if(junkscan(schemep)) return CURLUE_MALFORMED_INPUT; } else { /* no scheme! */ if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) return CURLUE_MALFORMED_INPUT; if(flags & CURLU_DEFAULT_SCHEME) schemep = DEFAULT_SCHEME; /* * The URL was badly formatted, let's try without scheme specified. */ p = url; } hostp = p; /* host name starts here */ while(*p && !HOSTNAME_END(*p)) /* find end of host name */ p++; len = p - hostp; if(len) { memcpy(hostname, hostp, len); hostname[len] = 0; } else { if(!(flags & CURLU_NO_AUTHORITY)) return CURLUE_MALFORMED_INPUT; } len = strlen(p); memcpy(path, p, len); path[len] = 0; if(schemep) { u->scheme = strdup(schemep); if(!u->scheme) return CURLUE_OUT_OF_MEMORY; } } if(junkscan(path)) return CURLUE_MALFORMED_INPUT; if((flags & CURLU_URLENCODE) && path[0]) { /* worst case output length is 3x the original! */ char *newp = malloc(strlen(path) * 3); if(!newp) return CURLUE_OUT_OF_MEMORY; path_alloced = TRUE; strcpy_url(newp, path, TRUE); /* consider it relative */ u->temppath = path = newp; } fragment = strchr(path, '#'); if(fragment) { *fragment++ = 0; if(fragment[0]) { u->fragment = strdup(fragment); if(!u->fragment) return CURLUE_OUT_OF_MEMORY; } } query = strchr(path, '?'); if(query) { *query++ = 0; /* done even if the query part is a blank string */ u->query = strdup(query); if(!u->query) return CURLUE_OUT_OF_MEMORY; } if(!path[0]) /* if there's no path left set, unset */ path = NULL; else { if(!(flags & CURLU_PATH_AS_IS)) { /* remove ../ and ./ sequences according to RFC3986 */ char *newp = Curl_dedotdotify(path); if(!newp) return CURLUE_OUT_OF_MEMORY; if(strcmp(newp, path)) { /* if we got a new version */ if(path_alloced) Curl_safefree(u->temppath); u->temppath = path = newp; path_alloced = TRUE; } else free(newp); } u->path = path_alloced?path:strdup(path); if(!u->path) return CURLUE_OUT_OF_MEMORY; u->temppath = NULL; /* used now */ } if(hostname) { /* * Parse the login details and strip them out of the host name. */ if(junkscan(hostname)) return CURLUE_MALFORMED_INPUT; result = parse_hostname_login(u, &hostname, flags); if(result) return result; result = Curl_parse_port(u, hostname); if(result) return result; if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ } else { result = hostname_check(u, hostname); if(result) return result; } u->host = strdup(hostname); if(!u->host) return CURLUE_OUT_OF_MEMORY; if((flags & CURLU_GUESS_SCHEME) && !schemep) { /* legacy curl-style guess based on host name */ if(checkprefix("ftp.", hostname)) schemep = "ftp"; else if(checkprefix("dict.", hostname)) schemep = "dict"; else if(checkprefix("ldap.", hostname)) schemep = "ldap"; else if(checkprefix("imap.", hostname)) schemep = "imap"; else if(checkprefix("smtp.", hostname)) schemep = "smtp"; else if(checkprefix("pop3.", hostname)) schemep = "pop3"; else schemep = "http"; u->scheme = strdup(schemep); if(!u->scheme) return CURLUE_OUT_OF_MEMORY; } } Curl_safefree(u->scratch); Curl_safefree(u->temppath); return CURLUE_OK; } /* * Parse the URL and set the relevant members of the Curl_URL struct. */ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) { CURLUcode result = seturl(url, u, flags); if(result) { free_urlhandle(u); memset(u, 0, sizeof(struct Curl_URL)); } return result; } /* */ CURLU *curl_url(void) { return calloc(sizeof(struct Curl_URL), 1); } void curl_url_cleanup(CURLU *u) { if(u) { free_urlhandle(u); free(u); } } #define DUP(dest, src, name) \ if(src->name) { \ dest->name = strdup(src->name); \ if(!dest->name) \ goto fail; \ } CURLU *curl_url_dup(CURLU *in) { struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1); if(u) { DUP(u, in, scheme); DUP(u, in, user); DUP(u, in, password); DUP(u, in, options); DUP(u, in, host); DUP(u, in, port); DUP(u, in, path); DUP(u, in, query); DUP(u, in, fragment); u->portnum = in->portnum; } return u; fail: curl_url_cleanup(u); return NULL; } CURLUcode curl_url_get(CURLU *u, CURLUPart what, char **part, unsigned int flags) { char *ptr; CURLUcode ifmissing = CURLUE_UNKNOWN_PART; char portbuf[7]; bool urldecode = (flags & CURLU_URLDECODE)?1:0; bool plusdecode = FALSE; (void)flags; if(!u) return CURLUE_BAD_HANDLE; if(!part) return CURLUE_BAD_PARTPOINTER; *part = NULL; switch(what) { case CURLUPART_SCHEME: ptr = u->scheme; ifmissing = CURLUE_NO_SCHEME; urldecode = FALSE; /* never for schemes */ break; case CURLUPART_USER: ptr = u->user; ifmissing = CURLUE_NO_USER; break; case CURLUPART_PASSWORD: ptr = u->password; ifmissing = CURLUE_NO_PASSWORD; break; case CURLUPART_OPTIONS: ptr = u->options; ifmissing = CURLUE_NO_OPTIONS; break; case CURLUPART_HOST: ptr = u->host; ifmissing = CURLUE_NO_HOST; break; case CURLUPART_ZONEID: ptr = u->zoneid; break; case CURLUPART_PORT: ptr = u->port; ifmissing = CURLUE_NO_PORT; urldecode = FALSE; /* never for port */ if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) { /* there's no stored port number, but asked to deliver a default one for the scheme */ const struct Curl_handler *h = Curl_builtin_scheme(u->scheme); if(h) { msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport); ptr = portbuf; } } else if(ptr && u->scheme) { /* there is a stored port number, but ask to inhibit if it matches the default one for the scheme */ const struct Curl_handler *h = Curl_builtin_scheme(u->scheme); if(h && (h->defport == u->portnum) && (flags & CURLU_NO_DEFAULT_PORT)) ptr = NULL; } break; case CURLUPART_PATH: ptr = u->path; if(!ptr) { ptr = u->path = strdup("/"); if(!u->path) return CURLUE_OUT_OF_MEMORY; } break; case CURLUPART_QUERY: ptr = u->query; ifmissing = CURLUE_NO_QUERY; plusdecode = urldecode; break; case CURLUPART_FRAGMENT: ptr = u->fragment; ifmissing = CURLUE_NO_FRAGMENT; break; case CURLUPART_URL: { char *url; char *scheme; char *options = u->options; char *port = u->port; char *allochost = NULL; if(u->scheme && strcasecompare("file", u->scheme)) { url = aprintf("file://%s%s%s", u->path, u->fragment? "#": "", u->fragment? u->fragment : ""); } else if(!u->host) return CURLUE_NO_HOST; else { const struct Curl_handler *h = NULL; if(u->scheme) scheme = u->scheme; else if(flags & CURLU_DEFAULT_SCHEME) scheme = (char *) DEFAULT_SCHEME; else return CURLUE_NO_SCHEME; h = Curl_builtin_scheme(scheme); if(!port && (flags & CURLU_DEFAULT_PORT)) { /* there's no stored port number, but asked to deliver a default one for the scheme */ if(h) { msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport); port = portbuf; } } else if(port) { /* there is a stored port number, but asked to inhibit if it matches the default one for the scheme */ if(h && (h->defport == u->portnum) && (flags & CURLU_NO_DEFAULT_PORT)) port = NULL; } if(h && !(h->flags & PROTOPT_URLOPTIONS)) options = NULL; if((u->host[0] == '[') && u->zoneid) { /* make it '[ host %25 zoneid ]' */ size_t hostlen = strlen(u->host); size_t alen = hostlen + 3 + strlen(u->zoneid) + 1; allochost = malloc(alen); if(!allochost) return CURLUE_OUT_OF_MEMORY; memcpy(allochost, u->host, hostlen - 1); msnprintf(&allochost[hostlen - 1], alen - hostlen + 1, "%%25%s]", u->zoneid); } url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", scheme, u->user ? u->user : "", u->password ? ":": "", u->password ? u->password : "", options ? ";" : "", options ? options : "", (u->user || u->password || options) ? "@": "", allochost ? allochost : u->host, port ? ":": "", port ? port : "", (u->path && (u->path[0] != '/')) ? "/": "", u->path ? u->path : "/", (u->query && u->query[0]) ? "?": "", (u->query && u->query[0]) ? u->query : "", u->fragment? "#": "", u->fragment? u->fragment : ""); free(allochost); } if(!url) return CURLUE_OUT_OF_MEMORY; *part = url; return CURLUE_OK; } default: ptr = NULL; break; } if(ptr) { *part = strdup(ptr); if(!*part) return CURLUE_OUT_OF_MEMORY; if(plusdecode) { /* convert + to space */ char *plus; for(plus = *part; *plus; ++plus) { if(*plus == '+') *plus = ' '; } } if(urldecode) { char *decoded; size_t dlen; CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, TRUE); free(*part); if(res) { *part = NULL; return CURLUE_URLDECODE; } *part = decoded; } return CURLUE_OK; } else return ifmissing; } CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags) { char **storep = NULL; long port = 0; bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0; bool plusencode = FALSE; bool urlskipslash = FALSE; bool appendquery = FALSE; bool equalsencode = FALSE; if(!u) return CURLUE_BAD_HANDLE; if(!part) { /* setting a part to NULL clears it */ switch(what) { case CURLUPART_URL: break; case CURLUPART_SCHEME: storep = &u->scheme; break; case CURLUPART_USER: storep = &u->user; break; case CURLUPART_PASSWORD: storep = &u->password; break; case CURLUPART_OPTIONS: storep = &u->options; break; case CURLUPART_HOST: storep = &u->host; break; case CURLUPART_ZONEID: storep = &u->zoneid; break; case CURLUPART_PORT: u->portnum = 0; storep = &u->port; break; case CURLUPART_PATH: storep = &u->path; break; case CURLUPART_QUERY: storep = &u->query; break; case CURLUPART_FRAGMENT: storep = &u->fragment; break; default: return CURLUE_UNKNOWN_PART; } if(storep && *storep) { free(*storep); *storep = NULL; } return CURLUE_OK; } switch(what) { case CURLUPART_SCHEME: if(strlen(part) > MAX_SCHEME_LEN) /* too long */ return CURLUE_MALFORMED_INPUT; if(!(flags & CURLU_NON_SUPPORT_SCHEME) && /* verify that it is a fine scheme */ !Curl_builtin_scheme(part)) return CURLUE_UNSUPPORTED_SCHEME; storep = &u->scheme; urlencode = FALSE; /* never */ break; case CURLUPART_USER: storep = &u->user; break; case CURLUPART_PASSWORD: storep = &u->password; break; case CURLUPART_OPTIONS: storep = &u->options; break; case CURLUPART_HOST: storep = &u->host; free(u->zoneid); u->zoneid = NULL; break; case CURLUPART_ZONEID: storep = &u->zoneid; break; case CURLUPART_PORT: { char *endp; urlencode = FALSE; /* never */ port = strtol(part, &endp, 10); /* Port number must be decimal */ if((port <= 0) || (port > 0xffff)) return CURLUE_BAD_PORT_NUMBER; if(*endp) /* weirdly provided number, not good! */ return CURLUE_MALFORMED_INPUT; storep = &u->port; } break; case CURLUPART_PATH: urlskipslash = TRUE; storep = &u->path; break; case CURLUPART_QUERY: plusencode = urlencode; appendquery = (flags & CURLU_APPENDQUERY)?1:0; equalsencode = appendquery; storep = &u->query; break; case CURLUPART_FRAGMENT: storep = &u->fragment; break; case CURLUPART_URL: { /* * Allow a new URL to replace the existing (if any) contents. * * If the existing contents is enough for a URL, allow a relative URL to * replace it. */ CURLUcode result; char *oldurl; char *redired_url; CURLU *handle2; if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN + 1)) { handle2 = curl_url(); if(!handle2) return CURLUE_OUT_OF_MEMORY; result = parseurl(part, handle2, flags); if(!result) mv_urlhandle(handle2, u); else curl_url_cleanup(handle2); return result; } /* extract the full "old" URL to do the redirect on */ result = curl_url_get(u, CURLUPART_URL, &oldurl, flags); if(result) { /* couldn't get the old URL, just use the new! */ handle2 = curl_url(); if(!handle2) return CURLUE_OUT_OF_MEMORY; result = parseurl(part, handle2, flags); if(!result) mv_urlhandle(handle2, u); else curl_url_cleanup(handle2); return result; } /* apply the relative part to create a new URL */ redired_url = concat_url(oldurl, part); free(oldurl); if(!redired_url) return CURLUE_OUT_OF_MEMORY; /* now parse the new URL */ handle2 = curl_url(); if(!handle2) { free(redired_url); return CURLUE_OUT_OF_MEMORY; } result = parseurl(redired_url, handle2, flags); free(redired_url); if(!result) mv_urlhandle(handle2, u); else curl_url_cleanup(handle2); return result; } default: return CURLUE_UNKNOWN_PART; } DEBUGASSERT(storep); { const char *newp = part; size_t nalloc = strlen(part); if(nalloc > CURL_MAX_INPUT_LENGTH) /* excessive input length */ return CURLUE_MALFORMED_INPUT; if(urlencode) { const unsigned char *i; char *o; bool free_part = FALSE; char *enc = malloc(nalloc * 3 + 1); /* for worst case! */ if(!enc) return CURLUE_OUT_OF_MEMORY; if(plusencode) { /* space to plus */ i = (const unsigned char *)part; for(o = enc; *i; ++o, ++i) *o = (*i == ' ') ? '+' : *i; *o = 0; /* zero terminate */ part = strdup(enc); if(!part) { free(enc); return CURLUE_OUT_OF_MEMORY; } free_part = TRUE; } for(i = (const unsigned char *)part, o = enc; *i; i++) { if(Curl_isunreserved(*i) || ((*i == '/') && urlskipslash) || ((*i == '=') && equalsencode) || ((*i == '+') && plusencode)) { if((*i == '=') && equalsencode) /* only skip the first equals sign */ equalsencode = FALSE; *o = *i; o++; } else { msnprintf(o, 4, "%%%02x", *i); o += 3; } } *o = 0; /* zero terminate */ newp = enc; if(free_part) free((char *)part); } else { char *p; newp = strdup(part); if(!newp) return CURLUE_OUT_OF_MEMORY; p = (char *)newp; while(*p) { /* make sure percent encoded are lower case */ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) && (ISUPPER(p[1]) || ISUPPER(p[2]))) { p[1] = (char)TOLOWER(p[1]); p[2] = (char)TOLOWER(p[2]); p += 3; } else p++; } } if(appendquery) { /* Append the string onto the old query. Add a '&' separator if none is present at the end of the exsting query already */ size_t querylen = u->query ? strlen(u->query) : 0; bool addamperand = querylen && (u->query[querylen -1] != '&'); if(querylen) { size_t newplen = strlen(newp); char *p = malloc(querylen + addamperand + newplen + 1); if(!p) { free((char *)newp); return CURLUE_OUT_OF_MEMORY; } strcpy(p, u->query); /* original query */ if(addamperand) p[querylen] = '&'; /* ampersand */ strcpy(&p[querylen + addamperand], newp); /* new suffix */ free((char *)newp); free(*storep); *storep = p; return CURLUE_OK; } } if(what == CURLUPART_HOST) { if(0 == strlen(newp) && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ } else { if(hostname_check(u, (char *)newp)) { free((char *)newp); return CURLUE_MALFORMED_INPUT; } } } free(*storep); *storep = (char *)newp; } /* set after the string, to make it not assigned if the allocation above fails */ if(port) u->portnum = port; return CURLUE_OK; } davix-0.8.0/deps/curl/lib/llist.h0000644000000000000000000000352614121063461015302 0ustar rootroot#ifndef HEADER_CURL_LLIST_H #define HEADER_CURL_LLIST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include typedef void (*curl_llist_dtor)(void *, void *); struct curl_llist_element { void *ptr; struct curl_llist_element *prev; struct curl_llist_element *next; }; struct curl_llist { struct curl_llist_element *head; struct curl_llist_element *tail; curl_llist_dtor dtor; size_t size; }; void Curl_llist_init(struct curl_llist *, curl_llist_dtor); void Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, const void *, struct curl_llist_element *node); void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, void *); size_t Curl_llist_count(struct curl_llist *); void Curl_llist_destroy(struct curl_llist *, void *); #endif /* HEADER_CURL_LLIST_H */ davix-0.8.0/deps/curl/lib/splay.c0000644000000000000000000001703314121063461015274 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1997 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "splay.h" /* * This macro compares two node keys i and j and returns: * * negative value: when i is smaller than j * zero : when i is equal to j * positive when : when i is larger than j */ #define compare(i,j) Curl_splaycomparekeys((i),(j)) /* * Splay using the key i (which may or may not be in the tree.) The starting * root is t. */ struct Curl_tree *Curl_splay(struct curltime i, struct Curl_tree *t) { struct Curl_tree N, *l, *r, *y; if(t == NULL) return t; N.smaller = N.larger = NULL; l = r = &N; for(;;) { long comp = compare(i, t->key); if(comp < 0) { if(t->smaller == NULL) break; if(compare(i, t->smaller->key) < 0) { y = t->smaller; /* rotate smaller */ t->smaller = y->larger; y->larger = t; t = y; if(t->smaller == NULL) break; } r->smaller = t; /* link smaller */ r = t; t = t->smaller; } else if(comp > 0) { if(t->larger == NULL) break; if(compare(i, t->larger->key) > 0) { y = t->larger; /* rotate larger */ t->larger = y->smaller; y->smaller = t; t = y; if(t->larger == NULL) break; } l->larger = t; /* link larger */ l = t; t = t->larger; } else break; } l->larger = t->smaller; /* assemble */ r->smaller = t->larger; t->smaller = N.larger; t->larger = N.smaller; return t; } /* Insert key i into the tree t. Return a pointer to the resulting tree or * NULL if something went wrong. * * @unittest: 1309 */ struct Curl_tree *Curl_splayinsert(struct curltime i, struct Curl_tree *t, struct Curl_tree *node) { static const struct curltime KEY_NOTUSED = { (time_t)-1, (unsigned int)-1 }; /* will *NEVER* appear */ if(node == NULL) return t; if(t != NULL) { t = Curl_splay(i, t); if(compare(i, t->key) == 0) { /* There already exists a node in the tree with the very same key. Build a doubly-linked circular list of nodes. We add the new 'node' struct to the end of this list. */ node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED to quickly identify this node as a subnode */ node->samen = t; node->samep = t->samep; t->samep->samen = node; t->samep = node; return t; /* the root node always stays the same */ } } if(t == NULL) { node->smaller = node->larger = NULL; } else if(compare(i, t->key) < 0) { node->smaller = t->smaller; node->larger = t; t->smaller = NULL; } else { node->larger = t->larger; node->smaller = t; t->larger = NULL; } node->key = i; /* no identical nodes (yet), we are the only one in the list of nodes */ node->samen = node; node->samep = node; return node; } /* Finds and deletes the best-fit node from the tree. Return a pointer to the resulting tree. best-fit means the smallest node if it is not larger than the key */ struct Curl_tree *Curl_splaygetbest(struct curltime i, struct Curl_tree *t, struct Curl_tree **removed) { static struct curltime tv_zero = {0, 0}; struct Curl_tree *x; if(!t) { *removed = NULL; /* none removed since there was no root */ return NULL; } /* find smallest */ t = Curl_splay(tv_zero, t); if(compare(i, t->key) < 0) { /* even the smallest is too big */ *removed = NULL; return t; } /* FIRST! Check if there is a list with identical keys */ x = t->samen; if(x != t) { /* there is, pick one from the list */ /* 'x' is the new root node */ x->key = t->key; x->larger = t->larger; x->smaller = t->smaller; x->samep = t->samep; t->samep->samen = x; *removed = t; return x; /* new root */ } /* we splayed the tree to the smallest element, there is no smaller */ x = t->larger; *removed = t; return x; } /* Deletes the very node we point out from the tree if it's there. Stores a * pointer to the new resulting tree in 'newroot'. * * Returns zero on success and non-zero on errors! * When returning error, it does not touch the 'newroot' pointer. * * NOTE: when the last node of the tree is removed, there's no tree left so * 'newroot' will be made to point to NULL. * * @unittest: 1309 */ int Curl_splayremovebyaddr(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot) { static const struct curltime KEY_NOTUSED = { (time_t)-1, (unsigned int)-1 }; /* will *NEVER* appear */ struct Curl_tree *x; if(!t || !removenode) return 1; if(compare(KEY_NOTUSED, removenode->key) == 0) { /* Key set to NOTUSED means it is a subnode within a 'same' linked list and thus we can unlink it easily. */ if(removenode->samen == removenode) /* A non-subnode should never be set to KEY_NOTUSED */ return 3; removenode->samep->samen = removenode->samen; removenode->samen->samep = removenode->samep; /* Ensures that double-remove gets caught. */ removenode->samen = removenode; *newroot = t; /* return the same root */ return 0; } t = Curl_splay(removenode->key, t); /* First make sure that we got the same root node as the one we want to remove, as otherwise we might be trying to remove a node that isn't actually in the tree. We cannot just compare the keys here as a double remove in quick succession of a node with key != KEY_NOTUSED && same != NULL could return the same key but a different node. */ if(t != removenode) return 2; /* Check if there is a list with identical sizes, as then we're trying to remove the root node of a list of nodes with identical keys. */ x = t->samen; if(x != t) { /* 'x' is the new root node, we just make it use the root node's smaller/larger links */ x->key = t->key; x->larger = t->larger; x->smaller = t->smaller; x->samep = t->samep; t->samep->samen = x; } else { /* Remove the root node */ if(t->smaller == NULL) x = t->larger; else { x = Curl_splay(removenode->key, t->smaller); x->larger = t->larger; } } *newroot = x; /* store new root pointer */ return 0; } davix-0.8.0/deps/curl/lib/curl_sspi.h0000644000000000000000000002751514121063461016162 0ustar rootroot#ifndef HEADER_CURL_SSPI_H #define HEADER_CURL_SSPI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_WINDOWS_SSPI #include /* * When including the following three headers, it is mandatory to define either * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code. */ #undef SECURITY_WIN32 #undef SECURITY_KERNEL #define SECURITY_WIN32 1 #include #include #include CURLcode Curl_sspi_global_init(void); void Curl_sspi_global_cleanup(void); /* This is used to populate the domain in a SSPI identity structure */ CURLcode Curl_override_sspi_http_realm(const char *chlg, SEC_WINNT_AUTH_IDENTITY *identity); /* This is used to generate an SSPI identity structure */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, SEC_WINNT_AUTH_IDENTITY *identity); /* This is used to free an SSPI identity structure */ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); /* Forward-declaration of global variables defined in curl_sspi.c */ extern HMODULE s_hSecDll; extern PSecurityFunctionTable s_pSecFn; /* Provide some definitions missing in old headers */ #define SP_NAME_DIGEST "WDigest" #define SP_NAME_NTLM "NTLM" #define SP_NAME_NEGOTIATE "Negotiate" #define SP_NAME_KERBEROS "Kerberos" #ifndef ISC_REQ_USE_HTTP_STYLE #define ISC_REQ_USE_HTTP_STYLE 0x01000000 #endif #ifndef ISC_RET_REPLAY_DETECT #define ISC_RET_REPLAY_DETECT 0x00000004 #endif #ifndef ISC_RET_SEQUENCE_DETECT #define ISC_RET_SEQUENCE_DETECT 0x00000008 #endif #ifndef ISC_RET_CONFIDENTIALITY #define ISC_RET_CONFIDENTIALITY 0x00000010 #endif #ifndef ISC_RET_ALLOCATED_MEMORY #define ISC_RET_ALLOCATED_MEMORY 0x00000100 #endif #ifndef ISC_RET_STREAM #define ISC_RET_STREAM 0x00008000 #endif #ifndef SEC_E_INSUFFICIENT_MEMORY # define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) #endif #ifndef SEC_E_INVALID_HANDLE # define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) #endif #ifndef SEC_E_UNSUPPORTED_FUNCTION # define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) #endif #ifndef SEC_E_TARGET_UNKNOWN # define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) #endif #ifndef SEC_E_INTERNAL_ERROR # define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) #endif #ifndef SEC_E_SECPKG_NOT_FOUND # define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) #endif #ifndef SEC_E_NOT_OWNER # define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) #endif #ifndef SEC_E_CANNOT_INSTALL # define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) #endif #ifndef SEC_E_INVALID_TOKEN # define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) #endif #ifndef SEC_E_CANNOT_PACK # define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) #endif #ifndef SEC_E_QOP_NOT_SUPPORTED # define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) #endif #ifndef SEC_E_NO_IMPERSONATION # define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) #endif #ifndef SEC_E_LOGON_DENIED # define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) #endif #ifndef SEC_E_UNKNOWN_CREDENTIALS # define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) #endif #ifndef SEC_E_NO_CREDENTIALS # define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) #endif #ifndef SEC_E_MESSAGE_ALTERED # define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) #endif #ifndef SEC_E_OUT_OF_SEQUENCE # define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) #endif #ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY # define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) #endif #ifndef SEC_E_BAD_PKGID # define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) #endif #ifndef SEC_E_CONTEXT_EXPIRED # define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) #endif #ifndef SEC_E_INCOMPLETE_MESSAGE # define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) #endif #ifndef SEC_E_INCOMPLETE_CREDENTIALS # define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) #endif #ifndef SEC_E_BUFFER_TOO_SMALL # define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) #endif #ifndef SEC_E_WRONG_PRINCIPAL # define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) #endif #ifndef SEC_E_TIME_SKEW # define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) #endif #ifndef SEC_E_UNTRUSTED_ROOT # define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) #endif #ifndef SEC_E_ILLEGAL_MESSAGE # define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) #endif #ifndef SEC_E_CERT_UNKNOWN # define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) #endif #ifndef SEC_E_CERT_EXPIRED # define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) #endif #ifndef SEC_E_ENCRYPT_FAILURE # define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) #endif #ifndef SEC_E_DECRYPT_FAILURE # define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) #endif #ifndef SEC_E_ALGORITHM_MISMATCH # define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) #endif #ifndef SEC_E_SECURITY_QOS_FAILED # define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) #endif #ifndef SEC_E_UNFINISHED_CONTEXT_DELETED # define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) #endif #ifndef SEC_E_NO_TGT_REPLY # define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) #endif #ifndef SEC_E_NO_IP_ADDRESSES # define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) #endif #ifndef SEC_E_WRONG_CREDENTIAL_HANDLE # define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) #endif #ifndef SEC_E_CRYPTO_SYSTEM_INVALID # define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) #endif #ifndef SEC_E_MAX_REFERRALS_EXCEEDED # define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) #endif #ifndef SEC_E_MUST_BE_KDC # define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) #endif #ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED # define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) #endif #ifndef SEC_E_TOO_MANY_PRINCIPALS # define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) #endif #ifndef SEC_E_NO_PA_DATA # define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) #endif #ifndef SEC_E_PKINIT_NAME_MISMATCH # define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) #endif #ifndef SEC_E_SMARTCARD_LOGON_REQUIRED # define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) #endif #ifndef SEC_E_SHUTDOWN_IN_PROGRESS # define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) #endif #ifndef SEC_E_KDC_INVALID_REQUEST # define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) #endif #ifndef SEC_E_KDC_UNABLE_TO_REFER # define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) #endif #ifndef SEC_E_KDC_UNKNOWN_ETYPE # define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) #endif #ifndef SEC_E_UNSUPPORTED_PREAUTH # define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) #endif #ifndef SEC_E_DELEGATION_REQUIRED # define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) #endif #ifndef SEC_E_BAD_BINDINGS # define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) #endif #ifndef SEC_E_MULTIPLE_ACCOUNTS # define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) #endif #ifndef SEC_E_NO_KERB_KEY # define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) #endif #ifndef SEC_E_CERT_WRONG_USAGE # define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) #endif #ifndef SEC_E_DOWNGRADE_DETECTED # define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) #endif #ifndef SEC_E_SMARTCARD_CERT_REVOKED # define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) #endif #ifndef SEC_E_ISSUING_CA_UNTRUSTED # define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) #endif #ifndef SEC_E_REVOCATION_OFFLINE_C # define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) #endif #ifndef SEC_E_PKINIT_CLIENT_FAILURE # define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) #endif #ifndef SEC_E_SMARTCARD_CERT_EXPIRED # define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) #endif #ifndef SEC_E_NO_S4U_PROT_SUPPORT # define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) #endif #ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE # define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) #endif #ifndef SEC_E_REVOCATION_OFFLINE_KDC # define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) #endif #ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC # define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) #endif #ifndef SEC_E_KDC_CERT_EXPIRED # define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) #endif #ifndef SEC_E_KDC_CERT_REVOKED # define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) #endif #ifndef SEC_E_INVALID_PARAMETER # define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) #endif #ifndef SEC_E_DELEGATION_POLICY # define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) #endif #ifndef SEC_E_POLICY_NLTM_ONLY # define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) #endif #ifndef SEC_I_CONTINUE_NEEDED # define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) #endif #ifndef SEC_I_COMPLETE_NEEDED # define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) #endif #ifndef SEC_I_COMPLETE_AND_CONTINUE # define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) #endif #ifndef SEC_I_LOCAL_LOGON # define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) #endif #ifndef SEC_I_CONTEXT_EXPIRED # define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) #endif #ifndef SEC_I_INCOMPLETE_CREDENTIALS # define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) #endif #ifndef SEC_I_RENEGOTIATE # define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) #endif #ifndef SEC_I_NO_LSA_CONTEXT # define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) #endif #ifndef SEC_I_SIGNATURE_NEEDED # define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) #endif #ifndef CRYPT_E_REVOKED # define CRYPT_E_REVOKED ((HRESULT)0x80092010L) #endif #ifdef UNICODE # define SECFLAG_WINNT_AUTH_IDENTITY \ (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE #else # define SECFLAG_WINNT_AUTH_IDENTITY \ (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI #endif /* * Definitions required from ntsecapi.h are directly provided below this point * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h */ #define KERB_WRAP_NO_ENCRYPT 0x80000001 #endif /* USE_WINDOWS_SSPI */ #endif /* HEADER_CURL_SSPI_H */ davix-0.8.0/deps/curl/lib/cookie.c0000644000000000000000000013476514121063461015431 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /*** RECEIVING COOKIE INFORMATION ============================ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession); Inits a cookie struct to store data in a local file. This is always called before any cookies are set. struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool httpheader, char *lineptr, const char *domain, const char *path); The 'lineptr' parameter is a full "Set-cookie:" line as received from a server. The function need to replace previously stored lines that this new line supersedes. It may remove lines that are expired. It should return an indication of success/error. SENDING COOKIE INFORMATION ========================== struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie, char *host, char *path, bool secure); For a given host and path, return a linked list of cookies that the client should send to the server if used now. The secure boolean informs the cookie if a secure connection is achieved or not. It shall only return cookies that haven't expired. Example set of cookies: Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/ftgw; secure Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure Set-cookie: Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure ****/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) #include "urldata.h" #include "cookie.h" #include "psl.h" #include "strtok.h" #include "sendf.h" #include "slist.h" #include "share.h" #include "strtoofft.h" #include "strcase.h" #include "curl_get_line.h" #include "curl_memrchr.h" #include "inet_pton.h" #include "parsedate.h" #include "rand.h" #include "rename.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static void freecookie(struct Cookie *co) { free(co->expirestr); free(co->domain); free(co->path); free(co->spath); free(co->name); free(co->value); free(co->maxage); free(co->version); free(co); } static bool tailmatch(const char *cooke_domain, const char *hostname) { size_t cookie_domain_len = strlen(cooke_domain); size_t hostname_len = strlen(hostname); if(hostname_len < cookie_domain_len) return FALSE; if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len)) return FALSE; /* A lead char of cookie_domain is not '.'. RFC6265 4.1.2.3. The Domain Attribute says: For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com. */ if(hostname_len == cookie_domain_len) return TRUE; if('.' == *(hostname + hostname_len - cookie_domain_len - 1)) return TRUE; return FALSE; } /* * Return true if the given string is an IP(v4|v6) address. */ static bool isip(const char *domain) { struct in_addr addr; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif if(Curl_inet_pton(AF_INET, domain, &addr) #ifdef ENABLE_IPV6 || Curl_inet_pton(AF_INET6, domain, &addr6) #endif ) { /* domain name given as IP address */ return TRUE; } return FALSE; } /* * matching cookie path and url path * RFC6265 5.1.4 Paths and Path-Match */ static bool pathmatch(const char *cookie_path, const char *request_uri) { size_t cookie_path_len; size_t uri_path_len; char *uri_path = NULL; char *pos; bool ret = FALSE; /* cookie_path must not have last '/' separator. ex: /sample */ cookie_path_len = strlen(cookie_path); if(1 == cookie_path_len) { /* cookie_path must be '/' */ return TRUE; } uri_path = strdup(request_uri); if(!uri_path) return FALSE; pos = strchr(uri_path, '?'); if(pos) *pos = 0x0; /* #-fragments are already cut off! */ if(0 == strlen(uri_path) || uri_path[0] != '/') { free(uri_path); uri_path = strdup("/"); if(!uri_path) return FALSE; } /* here, RFC6265 5.1.4 says 4. Output the characters of the uri-path from the first character up to, but not including, the right-most %x2F ("/"). but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site without redirect. Ignore this algorithm because /hoge is uri path for this case (uri path is not /). */ uri_path_len = strlen(uri_path); if(uri_path_len < cookie_path_len) { ret = FALSE; goto pathmatched; } /* not using checkprefix() because matching should be case-sensitive */ if(strncmp(cookie_path, uri_path, cookie_path_len)) { ret = FALSE; goto pathmatched; } /* The cookie-path and the uri-path are identical. */ if(cookie_path_len == uri_path_len) { ret = TRUE; goto pathmatched; } /* here, cookie_path_len < uri_path_len */ if(uri_path[cookie_path_len] == '/') { ret = TRUE; goto pathmatched; } ret = FALSE; pathmatched: free(uri_path); return ret; } /* * Return the top-level domain, for optimal hashing. */ static const char *get_top_domain(const char * const domain, size_t *outlen) { size_t len; const char *first = NULL, *last; if(!domain) return NULL; len = strlen(domain); last = memrchr(domain, '.', len); if(last) { first = memrchr(domain, '.', (last - domain)); if(first) len -= (++first - domain); } if(outlen) *outlen = len; return first? first: domain; } /* * A case-insensitive hash for the cookie domains. */ static size_t cookie_hash_domain(const char *domain, const size_t len) { const char *end = domain + len; size_t h = 5381; while(domain < end) { h += h << 5; h ^= Curl_raw_toupper(*domain++); } return (h % COOKIE_HASH_SIZE); } /* * Hash this domain. */ static size_t cookiehash(const char * const domain) { const char *top; size_t len; if(!domain || isip(domain)) return 0; top = get_top_domain(domain, &len); return cookie_hash_domain(top, len); } /* * cookie path sanitize */ static char *sanitize_cookie_path(const char *cookie_path) { size_t len; char *new_path = strdup(cookie_path); if(!new_path) return NULL; /* some stupid site sends path attribute with '"'. */ len = strlen(new_path); if(new_path[0] == '\"') { memmove((void *)new_path, (const void *)(new_path + 1), len); len--; } if(len && (new_path[len - 1] == '\"')) { new_path[len - 1] = 0x0; len--; } /* RFC6265 5.2.4 The Path Attribute */ if(new_path[0] != '/') { /* Let cookie-path be the default-path. */ free(new_path); new_path = strdup("/"); return new_path; } /* convert /hoge/ to /hoge */ if(len && new_path[len - 1] == '/') { new_path[len - 1] = 0x0; } return new_path; } /* * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). * * NOTE: OOM or cookie parsing failures are ignored. */ void Curl_cookie_loadfiles(struct Curl_easy *data) { struct curl_slist *list = data->change.cookielist; if(list) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); while(list) { struct CookieInfo *newcookies = Curl_cookie_init(data, list->data, data->cookies, data->set.cookiesession); if(!newcookies) /* Failure may be due to OOM or a bad cookie; both are ignored * but only the first should be */ infof(data, "ignoring failed cookie_init for %s\n", list->data); else data->cookies = newcookies; list = list->next; } curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; /* don't do this again! */ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } } /* * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL * that will be freed before the allocated string is stored there. * * It is meant to easily replace strdup() */ static void strstore(char **str, const char *newstr) { free(*str); *str = strdup(newstr); } /* * remove_expired() removes expired cookies. */ static void remove_expired(struct CookieInfo *cookies) { struct Cookie *co, *nx; curl_off_t now = (curl_off_t)time(NULL); unsigned int i; for(i = 0; i < COOKIE_HASH_SIZE; i++) { struct Cookie *pv = NULL; co = cookies->cookies[i]; while(co) { nx = co->next; if(co->expires && co->expires < now) { if(!pv) { cookies->cookies[i] = co->next; } else { pv->next = co->next; } cookies->numcookies--; freecookie(co); } else { pv = co; } co = nx; } } } /* Make sure domain contains a dot or is localhost. */ static bool bad_domain(const char *domain) { return !strchr(domain, '.') && !strcasecompare(domain, "localhost"); } /**************************************************************************** * * Curl_cookie_add() * * Add a single cookie line to the cookie keeping object. * * Be aware that sometimes we get an IP-only host name, and that might also be * a numerical IPv6 address. * * Returns NULL on out of memory or invalid cookie. This is suboptimal, * as they should be treated separately. ***************************************************************************/ struct Cookie * Curl_cookie_add(struct Curl_easy *data, /* The 'data' pointer here may be NULL at times, and thus must only be used very carefully for things that can deal with data being NULL. Such as infof() and similar */ struct CookieInfo *c, bool httpheader, /* TRUE if HTTP header-style line */ bool noexpire, /* if TRUE, skip remove_expired() */ char *lineptr, /* first character of the line */ const char *domain, /* default domain */ const char *path, /* full path used when this cookie is set, used to get default path for the cookie unless set */ bool secure) /* TRUE if connection is over secure origin */ { struct Cookie *clist; struct Cookie *co; struct Cookie *lastc = NULL; time_t now = time(NULL); bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ size_t myhash; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif /* First, alloc and init a new struct for it */ co = calloc(1, sizeof(struct Cookie)); if(!co) return NULL; /* bail out if we're this low on memory */ if(httpheader) { /* This line was read off a HTTP-header */ char name[MAX_NAME]; char what[MAX_NAME]; const char *ptr; const char *semiptr; size_t linelength = strlen(lineptr); if(linelength > MAX_COOKIE_LINE) { /* discard overly long lines at once */ free(co); return NULL; } semiptr = strchr(lineptr, ';'); /* first, find a semicolon */ while(*lineptr && ISBLANK(*lineptr)) lineptr++; ptr = lineptr; do { /* we have a = pair or a stand-alone word here */ name[0] = what[0] = 0; /* init the buffers */ if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" MAX_NAME_TXT "[^;\r\n]", name, what)) { /* Use strstore() below to properly deal with received cookie headers that have the same string property set more than once, and then we use the last one. */ const char *whatptr; bool done = FALSE; bool sep; size_t len = strlen(what); size_t nlen = strlen(name); const char *endofn = &ptr[ nlen ]; if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) || ((nlen + len) > MAX_NAME)) { /* too long individual name or contents, or too long combination of name + contents. Chrome and Firefox support 4095 or 4096 bytes combo. */ freecookie(co); infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n", nlen, len); return NULL; } /* name ends with a '=' ? */ sep = (*endofn == '=')?TRUE:FALSE; if(nlen) { endofn--; /* move to the last character */ if(ISBLANK(*endofn)) { /* skip trailing spaces in name */ while(*endofn && ISBLANK(*endofn) && nlen) { endofn--; nlen--; } name[nlen] = 0; /* new end of name */ } } /* Strip off trailing whitespace from the 'what' */ while(len && ISBLANK(what[len-1])) { what[len-1] = 0; len--; } /* Skip leading whitespace from the 'what' */ whatptr = what; while(*whatptr && ISBLANK(*whatptr)) whatptr++; /* * Check if we have a reserved prefix set before anything else, as we * otherwise have to test for the prefix in both the cookie name and * "the rest". Prefixes must start with '__' and end with a '-', so * only test for names where that can possibly be true. */ if(nlen > 3 && name[0] == '_' && name[1] == '_') { if(!strncmp("__Secure-", name, 9)) co->prefix |= COOKIE_PREFIX__SECURE; else if(!strncmp("__Host-", name, 7)) co->prefix |= COOKIE_PREFIX__HOST; } if(!co->name) { /* The very first name/value pair is the actual cookie name */ if(!sep) { /* Bad name/value pair. */ badcookie = TRUE; break; } co->name = strdup(name); co->value = strdup(whatptr); done = TRUE; if(!co->name || !co->value) { badcookie = TRUE; break; } } else if(!len) { /* this was a "=" with no content, and we must allow 'secure' and 'httponly' specified this weirdly */ done = TRUE; /* * secure cookies are only allowed to be set when the connection is * using a secure protocol, or when the cookie is being set by * reading from file */ if(strcasecompare("secure", name)) { if(secure || !c->running) { co->secure = TRUE; } else { badcookie = TRUE; break; } } else if(strcasecompare("httponly", name)) co->httponly = TRUE; else if(sep) /* there was a '=' so we're not done parsing this field */ done = FALSE; } if(done) ; else if(strcasecompare("path", name)) { strstore(&co->path, whatptr); if(!co->path) { badcookie = TRUE; /* out of memory bad */ break; } free(co->spath); /* if this is set again */ co->spath = sanitize_cookie_path(co->path); if(!co->spath) { badcookie = TRUE; /* out of memory bad */ break; } } else if(strcasecompare("domain", name)) { bool is_ip; /* Now, we make sure that our host is within the given domain, or the given domain is not valid and thus cannot be set. */ if('.' == whatptr[0]) whatptr++; /* ignore preceding dot */ #ifndef USE_LIBPSL /* * Without PSL we don't know when the incoming cookie is set on a * TLD or otherwise "protected" suffix. To reduce risk, we require a * dot OR the exact host name being "localhost". */ if(bad_domain(whatptr)) domain = ":"; #endif is_ip = isip(domain ? domain : whatptr); if(!domain || (is_ip && !strcmp(whatptr, domain)) || (!is_ip && tailmatch(whatptr, domain))) { strstore(&co->domain, whatptr); if(!co->domain) { badcookie = TRUE; break; } if(!is_ip) co->tailmatch = TRUE; /* we always do that if the domain name was given */ } else { /* we did not get a tailmatch and then the attempted set domain is not a domain to which the current host belongs. Mark as bad. */ badcookie = TRUE; infof(data, "skipped cookie with bad tailmatch domain: %s\n", whatptr); } } else if(strcasecompare("version", name)) { strstore(&co->version, whatptr); if(!co->version) { badcookie = TRUE; break; } } else if(strcasecompare("max-age", name)) { /* Defined in RFC2109: Optional. The Max-Age attribute defines the lifetime of the cookie, in seconds. The delta-seconds value is a decimal non- negative integer. After delta-seconds seconds elapse, the client should discard the cookie. A value of zero means the cookie should be discarded immediately. */ strstore(&co->maxage, whatptr); if(!co->maxage) { badcookie = TRUE; break; } } else if(strcasecompare("expires", name)) { strstore(&co->expirestr, whatptr); if(!co->expirestr) { badcookie = TRUE; break; } } /* else this is the second (or more) name we don't know about! */ } else { /* this is an "illegal" = pair */ } if(!semiptr || !*semiptr) { /* we already know there are no more cookies */ semiptr = NULL; continue; } ptr = semiptr + 1; while(*ptr && ISBLANK(*ptr)) ptr++; semiptr = strchr(ptr, ';'); /* now, find the next semicolon */ if(!semiptr && *ptr) /* There are no more semicolons, but there's a final name=value pair coming up */ semiptr = strchr(ptr, '\0'); } while(semiptr); if(co->maxage) { CURLofft offt; offt = curlx_strtoofft((*co->maxage == '\"')? &co->maxage[1]:&co->maxage[0], NULL, 10, &co->expires); if(offt == CURL_OFFT_FLOW) /* overflow, used max value */ co->expires = CURL_OFF_T_MAX; else if(!offt) { if(!co->expires) /* already expired */ co->expires = 1; else if(CURL_OFF_T_MAX - now < co->expires) /* would overflow */ co->expires = CURL_OFF_T_MAX; else co->expires += now; } } else if(co->expirestr) { /* Note that if the date couldn't get parsed for whatever reason, the cookie will be treated as a session cookie */ co->expires = Curl_getdate_capped(co->expirestr); /* Session cookies have expires set to 0 so if we get that back from the date parser let's add a second to make it a non-session cookie */ if(co->expires == 0) co->expires = 1; else if(co->expires < 0) co->expires = 0; } if(!badcookie && !co->domain) { if(domain) { /* no domain was given in the header line, set the default */ co->domain = strdup(domain); if(!co->domain) badcookie = TRUE; } } if(!badcookie && !co->path && path) { /* No path was given in the header line, set the default. Note that the passed-in path to this function MAY have a '?' and following part that MUST not be stored as part of the path. */ char *queryp = strchr(path, '?'); /* queryp is where the interesting part of the path ends, so now we want to the find the last */ char *endslash; if(!queryp) endslash = strrchr(path, '/'); else endslash = memrchr(path, '/', (queryp - path)); if(endslash) { size_t pathlen = (endslash-path + 1); /* include end slash */ co->path = malloc(pathlen + 1); /* one extra for the zero byte */ if(co->path) { memcpy(co->path, path, pathlen); co->path[pathlen] = 0; /* zero terminate */ co->spath = sanitize_cookie_path(co->path); if(!co->spath) badcookie = TRUE; /* out of memory bad */ } else badcookie = TRUE; } } if(badcookie || !co->name) { /* we didn't get a cookie name or a bad one, this is an illegal line, bail out */ freecookie(co); return NULL; } } else { /* This line is NOT a HTTP header style line, we do offer support for reading the odd netscape cookies-file format here */ char *ptr; char *firstptr; char *tok_buf = NULL; int fields; /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked with httpOnly after the domain name are not accessible from javascripts, but since curl does not operate at javascript level, we include them anyway. In Firefox's cookie files, these lines are preceded with #HttpOnly_ and then everything is as usual, so we skip 10 characters of the line.. */ if(strncmp(lineptr, "#HttpOnly_", 10) == 0) { lineptr += 10; co->httponly = TRUE; } if(lineptr[0]=='#') { /* don't even try the comments */ free(co); return NULL; } /* strip off the possible end-of-line characters */ ptr = strchr(lineptr, '\r'); if(ptr) *ptr = 0; /* clear it */ ptr = strchr(lineptr, '\n'); if(ptr) *ptr = 0; /* clear it */ firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ /* Now loop through the fields and init the struct we already have allocated */ for(ptr = firstptr, fields = 0; ptr && !badcookie; ptr = strtok_r(NULL, "\t", &tok_buf), fields++) { switch(fields) { case 0: if(ptr[0]=='.') /* skip preceding dots */ ptr++; co->domain = strdup(ptr); if(!co->domain) badcookie = TRUE; break; case 1: /* flag: A TRUE/FALSE value indicating if all machines within a given domain can access the variable. Set TRUE when the cookie says .domain.com and to false when the domain is complete www.domain.com */ co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* The file format allows the path field to remain not filled in */ if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { /* only if the path doesn't look like a boolean option! */ co->path = strdup(ptr); if(!co->path) badcookie = TRUE; else { co->spath = sanitize_cookie_path(co->path); if(!co->spath) { badcookie = TRUE; /* out of memory bad */ } } break; } /* this doesn't look like a path, make one up! */ co->path = strdup("/"); if(!co->path) badcookie = TRUE; co->spath = strdup("/"); if(!co->spath) badcookie = TRUE; fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: co->secure = FALSE; if(strcasecompare(ptr, "TRUE")) { if(secure || c->running) co->secure = TRUE; else badcookie = TRUE; } break; case 4: if(curlx_strtoofft(ptr, NULL, 10, &co->expires)) badcookie = TRUE; break; case 5: co->name = strdup(ptr); if(!co->name) badcookie = TRUE; else { /* For Netscape file format cookies we check prefix on the name */ if(strncasecompare("__Secure-", co->name, 9)) co->prefix |= COOKIE_PREFIX__SECURE; else if(strncasecompare("__Host-", co->name, 7)) co->prefix |= COOKIE_PREFIX__HOST; } break; case 6: co->value = strdup(ptr); if(!co->value) badcookie = TRUE; break; } } if(6 == fields) { /* we got a cookie with blank contents, fix it */ co->value = strdup(""); if(!co->value) badcookie = TRUE; else fields++; } if(!badcookie && (7 != fields)) /* we did not find the sufficient number of fields */ badcookie = TRUE; if(badcookie) { freecookie(co); return NULL; } } if(co->prefix & COOKIE_PREFIX__SECURE) { /* The __Secure- prefix only requires that the cookie be set secure */ if(!co->secure) { freecookie(co); return NULL; } } if(co->prefix & COOKIE_PREFIX__HOST) { /* * The __Host- prefix requires the cookie to be secure, have a "/" path * and not have a domain set. */ if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch) ; else { freecookie(co); return NULL; } } if(!c->running && /* read from a file */ c->newsession && /* clean session cookies */ !co->expires) { /* this is a session cookie since it doesn't expire! */ freecookie(co); return NULL; } co->livecookie = c->running; co->creationtime = ++c->lastct; /* now, we have parsed the incoming line, we must now check if this supersedes an already existing cookie, which it may if the previous have the same domain and path as this */ /* at first, remove expired cookies */ if(!noexpire) remove_expired(c); #ifdef USE_LIBPSL /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */ if(domain && co->domain && !isip(co->domain)) { const psl_ctx_t *psl = Curl_psl_use(data); int acceptable; if(psl) { acceptable = psl_is_cookie_domain_acceptable(psl, domain, co->domain); Curl_psl_release(data); } else acceptable = !bad_domain(domain); if(!acceptable) { infof(data, "cookie '%s' dropped, domain '%s' must not " "set cookies for '%s'\n", co->name, domain, co->domain); freecookie(co); return NULL; } } #endif myhash = cookiehash(co->domain); clist = c->cookies[myhash]; replace_old = FALSE; while(clist) { if(strcasecompare(clist->name, co->name)) { /* the names are identical */ if(clist->domain && co->domain) { if(strcasecompare(clist->domain, co->domain) && (clist->tailmatch == co->tailmatch)) /* The domains are identical */ replace_old = TRUE; } else if(!clist->domain && !co->domain) replace_old = TRUE; if(replace_old) { /* the domains were identical */ if(clist->spath && co->spath) { if(clist->secure && !co->secure && !secure) { size_t cllen; const char *sep; /* * A non-secure cookie may not overlay an existing secure cookie. * For an existing cookie "a" with path "/login", refuse a new * cookie "a" with for example path "/login/en", while the path * "/loginhelper" is ok. */ sep = strchr(clist->spath + 1, '/'); if(sep) cllen = sep - clist->spath; else cllen = strlen(clist->spath); if(strncasecompare(clist->spath, co->spath, cllen)) { freecookie(co); return NULL; } } else if(strcasecompare(clist->spath, co->spath)) replace_old = TRUE; else replace_old = FALSE; } else if(!clist->spath && !co->spath) replace_old = TRUE; else replace_old = FALSE; } if(replace_old && !co->livecookie && clist->livecookie) { /* Both cookies matched fine, except that the already present cookie is "live", which means it was set from a header, while the new one isn't "live" and thus only read from a file. We let live cookies stay alive */ /* Free the newcomer and get out of here! */ freecookie(co); return NULL; } if(replace_old) { co->next = clist->next; /* get the next-pointer first */ /* when replacing, creationtime is kept from old */ co->creationtime = clist->creationtime; /* then free all the old pointers */ free(clist->name); free(clist->value); free(clist->domain); free(clist->path); free(clist->spath); free(clist->expirestr); free(clist->version); free(clist->maxage); *clist = *co; /* then store all the new data */ free(co); /* free the newly allocated memory */ co = clist; /* point to the previous struct instead */ /* We have replaced a cookie, now skip the rest of the list but make sure the 'lastc' pointer is properly set */ do { lastc = clist; clist = clist->next; } while(clist); break; } } lastc = clist; clist = clist->next; } if(c->running) /* Only show this when NOT reading the cookies from a file */ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " "expire %" CURL_FORMAT_CURL_OFF_T "\n", replace_old?"Replaced":"Added", co->name, co->value, co->domain, co->path, co->expires); if(!replace_old) { /* then make the last item point on this new one */ if(lastc) lastc->next = co; else c->cookies[myhash] = co; c->numcookies++; /* one more cookie in the jar */ } return co; } /***************************************************************************** * * Curl_cookie_init() * * Inits a cookie struct to read data from a local file. This is always * called before any cookies are set. File may be NULL. * * If 'newsession' is TRUE, discard all "session cookies" on read from file. * * Note that 'data' might be called as NULL pointer. * * Returns NULL on out of memory. Invalid cookies are ignored. ****************************************************************************/ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession) { struct CookieInfo *c; FILE *fp = NULL; bool fromfile = TRUE; char *line = NULL; if(NULL == inc) { /* we didn't get a struct, create one */ c = calloc(1, sizeof(struct CookieInfo)); if(!c) return NULL; /* failed to get memory */ c->filename = strdup(file?file:"none"); /* copy the name just in case */ if(!c->filename) goto fail; /* failed to get memory */ } else { /* we got an already existing one, use that */ c = inc; } c->running = FALSE; /* this is not running, this is init */ if(file && !strcmp(file, "-")) { fp = stdin; fromfile = FALSE; } else if(file && !*file) { /* points to a "" string */ fp = NULL; } else fp = file?fopen(file, FOPEN_READTEXT):NULL; c->newsession = newsession; /* new session? */ if(fp) { char *lineptr; bool headerline; line = malloc(MAX_COOKIE_LINE); if(!line) goto fail; while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) { if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ lineptr = &line[11]; headerline = TRUE; } else { lineptr = line; headerline = FALSE; } while(*lineptr && ISBLANK(*lineptr)) lineptr++; Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE); } free(line); /* free the line buffer */ remove_expired(c); /* run this once, not on every cookie */ if(fromfile) fclose(fp); } c->running = TRUE; /* now, we're running */ if(data) data->state.cookie_engine = TRUE; return c; fail: free(line); if(!inc) /* Only clean up if we allocated it here, as the original could still be in * use by a share handle */ Curl_cookie_cleanup(c); if(fromfile && fp) fclose(fp); return NULL; /* out of memory */ } /* sort this so that the longest path gets before the shorter path */ static int cookie_sort(const void *p1, const void *p2) { struct Cookie *c1 = *(struct Cookie **)p1; struct Cookie *c2 = *(struct Cookie **)p2; size_t l1, l2; /* 1 - compare cookie path lengths */ l1 = c1->path ? strlen(c1->path) : 0; l2 = c2->path ? strlen(c2->path) : 0; if(l1 != l2) return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ /* 2 - compare cookie domain lengths */ l1 = c1->domain ? strlen(c1->domain) : 0; l2 = c2->domain ? strlen(c2->domain) : 0; if(l1 != l2) return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */ /* 3 - compare cookie name lengths */ l1 = c1->name ? strlen(c1->name) : 0; l2 = c2->name ? strlen(c2->name) : 0; if(l1 != l2) return (l2 > l1) ? 1 : -1; /* 4 - compare cookie creation time */ return (c2->creationtime > c1->creationtime) ? 1 : -1; } /* sort cookies only according to creation time */ static int cookie_sort_ct(const void *p1, const void *p2) { struct Cookie *c1 = *(struct Cookie **)p1; struct Cookie *c2 = *(struct Cookie **)p2; return (c2->creationtime > c1->creationtime) ? 1 : -1; } #define CLONE(field) \ do { \ if(src->field) { \ d->field = strdup(src->field); \ if(!d->field) \ goto fail; \ } \ } while(0) static struct Cookie *dup_cookie(struct Cookie *src) { struct Cookie *d = calloc(sizeof(struct Cookie), 1); if(d) { CLONE(expirestr); CLONE(domain); CLONE(path); CLONE(spath); CLONE(name); CLONE(value); CLONE(maxage); CLONE(version); d->expires = src->expires; d->tailmatch = src->tailmatch; d->secure = src->secure; d->livecookie = src->livecookie; d->httponly = src->httponly; d->creationtime = src->creationtime; } return d; fail: freecookie(d); return NULL; } /***************************************************************************** * * Curl_cookie_getlist() * * For a given host and path, return a linked list of cookies that the * client should send to the server if used now. The secure boolean informs * the cookie if a secure connection is achieved or not. * * It shall only return cookies that haven't expired. * ****************************************************************************/ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, const char *host, const char *path, bool secure) { struct Cookie *newco; struct Cookie *co; struct Cookie *mainco = NULL; size_t matches = 0; bool is_ip; const size_t myhash = cookiehash(host); if(!c || !c->cookies[myhash]) return NULL; /* no cookie struct or no cookies in the struct */ /* at first, remove expired cookies */ remove_expired(c); /* check if host is an IP(v4|v6) address */ is_ip = isip(host); co = c->cookies[myhash]; while(co) { /* if the cookie requires we're secure we must only continue if we are! */ if(co->secure?secure:TRUE) { /* now check if the domain is correct */ if(!co->domain || (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* the right part of the host matches the domain stuff in the cookie data */ /* now check the left part of the path with the cookies path requirement */ if(!co->spath || pathmatch(co->spath, path) ) { /* and now, we know this is a match and we should create an entry for the return-linked-list */ newco = dup_cookie(co); if(newco) { /* then modify our next */ newco->next = mainco; /* point the main to us */ mainco = newco; matches++; } else goto fail; } } } co = co->next; } if(matches) { /* Now we need to make sure that if there is a name appearing more than once, the longest specified path version comes first. To make this the swiftest way, we just sort them all based on path length. */ struct Cookie **array; size_t i; /* alloc an array and store all cookie pointers */ array = malloc(sizeof(struct Cookie *) * matches); if(!array) goto fail; co = mainco; for(i = 0; co; co = co->next) array[i++] = co; /* now sort the cookie pointers in path length order */ qsort(array, matches, sizeof(struct Cookie *), cookie_sort); /* remake the linked list order according to the new order */ mainco = array[0]; /* start here */ for(i = 0; inext = array[i + 1]; array[matches-1]->next = NULL; /* terminate the list */ free(array); /* remove the temporary data again */ } return mainco; /* return the new list */ fail: /* failure, clear up the allocated chain and return NULL */ Curl_cookie_freelist(mainco); return NULL; } /***************************************************************************** * * Curl_cookie_clearall() * * Clear all existing cookies and reset the counter. * ****************************************************************************/ void Curl_cookie_clearall(struct CookieInfo *cookies) { if(cookies) { unsigned int i; for(i = 0; i < COOKIE_HASH_SIZE; i++) { Curl_cookie_freelist(cookies->cookies[i]); cookies->cookies[i] = NULL; } cookies->numcookies = 0; } } /***************************************************************************** * * Curl_cookie_freelist() * * Free a list of cookies previously returned by Curl_cookie_getlist(); * ****************************************************************************/ void Curl_cookie_freelist(struct Cookie *co) { struct Cookie *next; while(co) { next = co->next; freecookie(co); co = next; } } /***************************************************************************** * * Curl_cookie_clearsess() * * Free all session cookies in the cookies list. * ****************************************************************************/ void Curl_cookie_clearsess(struct CookieInfo *cookies) { struct Cookie *first, *curr, *next, *prev = NULL; unsigned int i; if(!cookies) return; for(i = 0; i < COOKIE_HASH_SIZE; i++) { if(!cookies->cookies[i]) continue; first = curr = prev = cookies->cookies[i]; for(; curr; curr = next) { next = curr->next; if(!curr->expires) { if(first == curr) first = next; if(prev == curr) prev = next; else prev->next = next; freecookie(curr); cookies->numcookies--; } else prev = curr; } cookies->cookies[i] = first; } } /***************************************************************************** * * Curl_cookie_cleanup() * * Free a "cookie object" previous created with Curl_cookie_init(). * ****************************************************************************/ void Curl_cookie_cleanup(struct CookieInfo *c) { if(c) { unsigned int i; free(c->filename); for(i = 0; i < COOKIE_HASH_SIZE; i++) Curl_cookie_freelist(c->cookies[i]); free(c); /* free the base struct as well */ } } /* get_netscape_format() * * Formats a string for Netscape output file, w/o a newline at the end. * * Function returns a char * to a formatted line. Has to be free()d */ static char *get_netscape_format(const struct Cookie *co) { return aprintf( "%s" /* httponly preamble */ "%s%s\t" /* domain */ "%s\t" /* tailmatch */ "%s\t" /* path */ "%s\t" /* secure */ "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */ "%s\t" /* name */ "%s", /* value */ co->httponly?"#HttpOnly_":"", /* Make sure all domains are prefixed with a dot if they allow tailmatching. This is Mozilla-style. */ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"", co->domain?co->domain:"unknown", co->tailmatch?"TRUE":"FALSE", co->path?co->path:"/", co->secure?"TRUE":"FALSE", co->expires, co->name, co->value?co->value:""); } /* * cookie_output() * * Writes all internally known cookies to the specified file. Specify * "-" as file name to write to stdout. * * The function returns non-zero on write failure. */ static int cookie_output(struct Curl_easy *data, struct CookieInfo *c, const char *filename) { struct Cookie *co; FILE *out = NULL; bool use_stdout = FALSE; char *tempstore = NULL; bool error = false; if(!c) /* no cookie engine alive */ return 0; /* at first, remove expired cookies */ remove_expired(c); if(!strcmp("-", filename)) { /* use stdout */ out = stdout; use_stdout = TRUE; } else { unsigned char randsuffix[9]; if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) return 2; tempstore = aprintf("%s.%s.tmp", filename, randsuffix); if(!tempstore) return 1; out = fopen(tempstore, FOPEN_WRITETEXT); if(!out) goto error; } fputs("# Netscape HTTP Cookie File\n" "# https://curl.haxx.se/docs/http-cookies.html\n" "# This file was generated by libcurl! Edit at your own risk.\n\n", out); if(c->numcookies) { unsigned int i; size_t nvalid = 0; struct Cookie **array; array = calloc(1, sizeof(struct Cookie *) * c->numcookies); if(!array) { goto error; } /* only sort the cookies with a domain property */ for(i = 0; i < COOKIE_HASH_SIZE; i++) { for(co = c->cookies[i]; co; co = co->next) { if(!co->domain) continue; array[nvalid++] = co; } } qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct); for(i = 0; i < nvalid; i++) { char *format_ptr = get_netscape_format(array[i]); if(format_ptr == NULL) { fprintf(out, "#\n# Fatal libcurl error\n"); free(array); goto error; } fprintf(out, "%s\n", format_ptr); free(format_ptr); } free(array); } if(!use_stdout) { fclose(out); out = NULL; if(Curl_rename(tempstore, filename)) { unlink(tempstore); goto error; } } goto cleanup; error: error = true; cleanup: if(out && !use_stdout) fclose(out); free(tempstore); return error ? 1 : 0; } static struct curl_slist *cookie_list(struct Curl_easy *data) { struct curl_slist *list = NULL; struct curl_slist *beg; struct Cookie *c; char *line; unsigned int i; if((data->cookies == NULL) || (data->cookies->numcookies == 0)) return NULL; for(i = 0; i < COOKIE_HASH_SIZE; i++) { for(c = data->cookies->cookies[i]; c; c = c->next) { if(!c->domain) continue; line = get_netscape_format(c); if(!line) { curl_slist_free_all(list); return NULL; } beg = Curl_slist_append_nodup(list, line); if(!beg) { free(line); curl_slist_free_all(list); return NULL; } list = beg; } } return list; } struct curl_slist *Curl_cookie_list(struct Curl_easy *data) { struct curl_slist *list; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); list = cookie_list(data); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); return list; } void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) { if(data->set.str[STRING_COOKIEJAR]) { if(data->change.cookielist) { /* If there is a list of cookie files to read, do it first so that we have all the told files read before we write the new jar. Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */ Curl_cookie_loadfiles(data); } Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); /* if we have a destination file for all the cookies to get dumped to */ if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR])) infof(data, "WARNING: failed to save cookies in %s\n", data->set.str[STRING_COOKIEJAR]); } else { if(cleanup && data->change.cookielist) { /* since nothing is written, we can just free the list of cookie file names */ curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; } Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); } if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { Curl_cookie_cleanup(data->cookies); data->cookies = NULL; } Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ davix-0.8.0/deps/curl/lib/curl_setup_once.h0000644000000000000000000003236714121063461017351 0ustar rootroot#ifndef HEADER_CURL_SETUP_ONCE_H #define HEADER_CURL_SETUP_ONCE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Inclusion of common header files. */ #include #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef NEED_MALLOC_H #include #endif #ifdef NEED_MEMORY_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_TIME_H #include #ifdef TIME_WITH_SYS_TIME #include #endif #else #ifdef HAVE_TIME_H #include #endif #endif #ifdef WIN32 #include #include #endif #if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T) #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef __hpux # if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) # ifdef _APP32_64BIT_OFF_T # define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T # undef _APP32_64BIT_OFF_T # else # undef OLD_APP32_64BIT_OFF_T # endif # endif #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef __hpux # if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) # ifdef OLD_APP32_64BIT_OFF_T # define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T # undef OLD_APP32_64BIT_OFF_T # endif # endif #endif /* * Definition of timeval struct for platforms that don't have it. */ #ifndef HAVE_STRUCT_TIMEVAL struct timeval { long tv_sec; long tv_usec; }; #endif /* * If we have the MSG_NOSIGNAL define, make sure we use * it as the fourth argument of function send() */ #ifdef HAVE_MSG_NOSIGNAL #define SEND_4TH_ARG MSG_NOSIGNAL #else #define SEND_4TH_ARG 0 #endif #if defined(__minix) /* Minix doesn't support recv on TCP sockets */ #define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \ (RECV_TYPE_ARG2)(y), \ (RECV_TYPE_ARG3)(z)) #elif defined(HAVE_RECV) /* * The definitions for the return type and arguments types * of functions recv() and send() belong and come from the * configuration file. Do not define them in any other place. * * HAVE_RECV is defined if you have a function named recv() * which is used to read incoming data from sockets. If your * function has another name then don't define HAVE_RECV. * * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2, * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also * be defined. * * HAVE_SEND is defined if you have a function named send() * which is used to write outgoing data on a connected socket. * If yours has another name then don't define HAVE_SEND. * * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2, * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and * SEND_TYPE_RETV must also be defined. */ #if !defined(RECV_TYPE_ARG1) || \ !defined(RECV_TYPE_ARG2) || \ !defined(RECV_TYPE_ARG3) || \ !defined(RECV_TYPE_ARG4) || \ !defined(RECV_TYPE_RETV) /* */ Error Missing_definition_of_return_and_arguments_types_of_recv /* */ #else #define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ (RECV_TYPE_ARG2)(y), \ (RECV_TYPE_ARG3)(z), \ (RECV_TYPE_ARG4)(0)) #endif #else /* HAVE_RECV */ #ifndef sread /* */ Error Missing_definition_of_macro_sread /* */ #endif #endif /* HAVE_RECV */ #if defined(__minix) /* Minix doesn't support send on TCP sockets */ #define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \ (SEND_TYPE_ARG2)(y), \ (SEND_TYPE_ARG3)(z)) #elif defined(HAVE_SEND) #if !defined(SEND_TYPE_ARG1) || \ !defined(SEND_QUAL_ARG2) || \ !defined(SEND_TYPE_ARG2) || \ !defined(SEND_TYPE_ARG3) || \ !defined(SEND_TYPE_ARG4) || \ !defined(SEND_TYPE_RETV) /* */ Error Missing_definition_of_return_and_arguments_types_of_send /* */ #else #define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \ (SEND_TYPE_ARG3)(z), \ (SEND_TYPE_ARG4)(SEND_4TH_ARG)) #endif #else /* HAVE_SEND */ #ifndef swrite /* */ Error Missing_definition_of_macro_swrite /* */ #endif #endif /* HAVE_SEND */ #if 0 #if defined(HAVE_RECVFROM) /* * Currently recvfrom is only used on udp sockets. */ #if !defined(RECVFROM_TYPE_ARG1) || \ !defined(RECVFROM_TYPE_ARG2) || \ !defined(RECVFROM_TYPE_ARG3) || \ !defined(RECVFROM_TYPE_ARG4) || \ !defined(RECVFROM_TYPE_ARG5) || \ !defined(RECVFROM_TYPE_ARG6) || \ !defined(RECVFROM_TYPE_RETV) /* */ Error Missing_definition_of_return_and_arguments_types_of_recvfrom /* */ #else #define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \ (RECVFROM_TYPE_ARG2 *)(b), \ (RECVFROM_TYPE_ARG3) (bl), \ (RECVFROM_TYPE_ARG4) (0), \ (RECVFROM_TYPE_ARG5 *)(f), \ (RECVFROM_TYPE_ARG6 *)(fl)) #endif #else /* HAVE_RECVFROM */ #ifndef sreadfrom /* */ Error Missing_definition_of_macro_sreadfrom /* */ #endif #endif /* HAVE_RECVFROM */ #ifdef RECVFROM_TYPE_ARG6_IS_VOID # define RECVFROM_ARG6_T int #else # define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6 #endif #endif /* if 0 */ /* * Function-like macro definition used to close a socket. */ #if defined(HAVE_CLOSESOCKET) # define sclose(x) closesocket((x)) #elif defined(HAVE_CLOSESOCKET_CAMEL) # define sclose(x) CloseSocket((x)) #elif defined(HAVE_CLOSE_S) # define sclose(x) close_s((x)) #elif defined(USE_LWIPSOCK) # define sclose(x) lwip_close((x)) #else # define sclose(x) close((x)) #endif /* * Stack-independent version of fcntl() on sockets: */ #if defined(USE_LWIPSOCK) # define sfcntl lwip_fcntl #else # define sfcntl fcntl #endif #define TOLOWER(x) (tolower((int) ((unsigned char)x))) /* * 'bool' stuff compatible with HP-UX headers. */ #if defined(__hpux) && !defined(HAVE_BOOL_T) typedef int bool; # define false 0 # define true 1 # define HAVE_BOOL_T #endif /* * 'bool' exists on platforms with , i.e. C99 platforms. * On non-C99 platforms there's no bool, so define an enum for that. * On C99 platforms 'false' and 'true' also exist. Enum uses a * global namespace though, so use bool_false and bool_true. */ #ifndef HAVE_BOOL_T typedef enum { bool_false = 0, bool_true = 1 } bool; /* * Use a define to let 'true' and 'false' use those enums. There * are currently no use of true and false in libcurl proper, but * there are some in the examples. This will cater for any later * code happening to use true and false. */ # define false bool_false # define true bool_true # define HAVE_BOOL_T #endif /* * Redefine TRUE and FALSE too, to catch current use. With this * change, 'bool found = 1' will give a warning on MIPSPro, but * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro, * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too. */ #ifndef TRUE #define TRUE true #endif #ifndef FALSE #define FALSE false #endif #include "curl_ctype.h" /* * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. */ #ifndef HAVE_SIG_ATOMIC_T typedef int sig_atomic_t; #define HAVE_SIG_ATOMIC_T #endif /* * Convenience SIG_ATOMIC_T definition */ #ifdef HAVE_SIG_ATOMIC_T_VOLATILE #define SIG_ATOMIC_T static sig_atomic_t #else #define SIG_ATOMIC_T static volatile sig_atomic_t #endif /* * Default return type for signal handlers. */ #ifndef RETSIGTYPE #define RETSIGTYPE void #endif /* * Macro used to include code only in debug builds. */ #ifdef DEBUGBUILD #define DEBUGF(x) x #else #define DEBUGF(x) do { } while(0) #endif /* * Macro used to include assertion code only in debug builds. */ #undef DEBUGASSERT #if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) #define DEBUGASSERT(x) assert(x) #else #define DEBUGASSERT(x) do { } while(0) #endif /* * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno * (or equivalent) on this platform to hide platform details to code using it. */ #ifdef USE_WINSOCK #define SOCKERRNO ((int)WSAGetLastError()) #define SET_SOCKERRNO(x) (WSASetLastError((int)(x))) #else #define SOCKERRNO (errno) #define SET_SOCKERRNO(x) (errno = (x)) #endif /* * Portable error number symbolic names defined to Winsock error codes. */ #ifdef USE_WINSOCK #undef EBADF /* override definition in errno.h */ #define EBADF WSAEBADF #undef EINTR /* override definition in errno.h */ #define EINTR WSAEINTR #undef EINVAL /* override definition in errno.h */ #define EINVAL WSAEINVAL #undef EWOULDBLOCK /* override definition in errno.h */ #define EWOULDBLOCK WSAEWOULDBLOCK #undef EINPROGRESS /* override definition in errno.h */ #define EINPROGRESS WSAEINPROGRESS #undef EALREADY /* override definition in errno.h */ #define EALREADY WSAEALREADY #undef ENOTSOCK /* override definition in errno.h */ #define ENOTSOCK WSAENOTSOCK #undef EDESTADDRREQ /* override definition in errno.h */ #define EDESTADDRREQ WSAEDESTADDRREQ #undef EMSGSIZE /* override definition in errno.h */ #define EMSGSIZE WSAEMSGSIZE #undef EPROTOTYPE /* override definition in errno.h */ #define EPROTOTYPE WSAEPROTOTYPE #undef ENOPROTOOPT /* override definition in errno.h */ #define ENOPROTOOPT WSAENOPROTOOPT #undef EPROTONOSUPPORT /* override definition in errno.h */ #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #undef EOPNOTSUPP /* override definition in errno.h */ #define EOPNOTSUPP WSAEOPNOTSUPP #define EPFNOSUPPORT WSAEPFNOSUPPORT #undef EAFNOSUPPORT /* override definition in errno.h */ #define EAFNOSUPPORT WSAEAFNOSUPPORT #undef EADDRINUSE /* override definition in errno.h */ #define EADDRINUSE WSAEADDRINUSE #undef EADDRNOTAVAIL /* override definition in errno.h */ #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #undef ENETDOWN /* override definition in errno.h */ #define ENETDOWN WSAENETDOWN #undef ENETUNREACH /* override definition in errno.h */ #define ENETUNREACH WSAENETUNREACH #undef ENETRESET /* override definition in errno.h */ #define ENETRESET WSAENETRESET #undef ECONNABORTED /* override definition in errno.h */ #define ECONNABORTED WSAECONNABORTED #undef ECONNRESET /* override definition in errno.h */ #define ECONNRESET WSAECONNRESET #undef ENOBUFS /* override definition in errno.h */ #define ENOBUFS WSAENOBUFS #undef EISCONN /* override definition in errno.h */ #define EISCONN WSAEISCONN #undef ENOTCONN /* override definition in errno.h */ #define ENOTCONN WSAENOTCONN #define ESHUTDOWN WSAESHUTDOWN #define ETOOMANYREFS WSAETOOMANYREFS #undef ETIMEDOUT /* override definition in errno.h */ #define ETIMEDOUT WSAETIMEDOUT #undef ECONNREFUSED /* override definition in errno.h */ #define ECONNREFUSED WSAECONNREFUSED #undef ELOOP /* override definition in errno.h */ #define ELOOP WSAELOOP #ifndef ENAMETOOLONG /* possible previous definition in errno.h */ #define ENAMETOOLONG WSAENAMETOOLONG #endif #define EHOSTDOWN WSAEHOSTDOWN #undef EHOSTUNREACH /* override definition in errno.h */ #define EHOSTUNREACH WSAEHOSTUNREACH #ifndef ENOTEMPTY /* possible previous definition in errno.h */ #define ENOTEMPTY WSAENOTEMPTY #endif #define EPROCLIM WSAEPROCLIM #define EUSERS WSAEUSERS #define EDQUOT WSAEDQUOT #define ESTALE WSAESTALE #define EREMOTE WSAEREMOTE #endif /* * Macro argv_item_t hides platform details to code using it. */ #ifdef __VMS #define argv_item_t __char_ptr32 #else #define argv_item_t char * #endif /* * We use this ZERO_NULL to avoid picky compiler warnings, * when assigning a NULL pointer to a function pointer var. */ #define ZERO_NULL 0 #endif /* HEADER_CURL_SETUP_ONCE_H */ davix-0.8.0/deps/curl/lib/http_proxy.c0000644000000000000000000005507614121063461016375 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "http_proxy.h" #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) #include #include "sendf.h" #include "http.h" #include "url.h" #include "select.h" #include "progress.h" #include "non-ascii.h" #include "connect.h" #include "curlx.h" #include "vtls/vtls.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Perform SSL initialization for HTTPS proxy. Sets * proxy_ssl_connected connection bit when complete. Can be * called multiple times. */ static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) { #ifdef USE_SSL CURLcode result = CURLE_OK; DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS); if(!conn->bits.proxy_ssl_connected[sockindex]) { /* perform SSL initialization for this socket */ result = Curl_ssl_connect_nonblocking(conn, sockindex, &conn->bits.proxy_ssl_connected[sockindex]); if(result) /* a failed connection is marked for closure to prevent (bad) re-use or similar */ connclose(conn, "TLS handshake failed"); } return result; #else (void) conn; (void) sockindex; return CURLE_NOT_BUILT_IN; #endif } CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) { if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { const CURLcode result = https_proxy_connect(conn, sockindex); if(result) return result; if(!conn->bits.proxy_ssl_connected[sockindex]) return result; /* wait for HTTPS proxy SSL initialization to complete */ } if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { #ifndef CURL_DISABLE_PROXY /* for [protocol] tunneled through HTTP proxy */ struct HTTP http_proxy; void *prot_save; const char *hostname; int remote_port; CURLcode result; /* BLOCKING */ /* We want "seamless" operations through HTTP proxy tunnel */ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the * member conn->proto.http; we want [protocol] through HTTP and we have * to change the member temporarily for connecting to the HTTP * proxy. After Curl_proxyCONNECT we have to set back the member to the * original pointer * * This function might be called several times in the multi interface case * if the proxy's CONNECT response is not instant. */ prot_save = conn->data->req.protop; memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else if(sockindex == SECONDARYSOCKET) hostname = conn->secondaryhostname; else hostname = conn->host.name; if(sockindex == SECONDARYSOCKET) remote_port = conn->secondary_port; else if(conn->bits.conn_to_port) remote_port = conn->conn_to_port; else remote_port = conn->remote_port; result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port); conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; Curl_safefree(conn->allocptr.proxyuserpwd); #else return CURLE_NOT_BUILT_IN; #endif } /* no HTTP tunnel proxy, just return */ return CURLE_OK; } bool Curl_connect_complete(struct connectdata *conn) { return !conn->connect_state || (conn->connect_state->tunnel_state == TUNNEL_COMPLETE); } bool Curl_connect_ongoing(struct connectdata *conn) { return conn->connect_state && (conn->connect_state->tunnel_state != TUNNEL_COMPLETE); } static CURLcode connect_init(struct connectdata *conn, bool reinit) { struct http_connect_state *s; if(!reinit) { DEBUGASSERT(!conn->connect_state); s = calloc(1, sizeof(struct http_connect_state)); if(!s) return CURLE_OUT_OF_MEMORY; infof(conn->data, "allocate connect buffer!\n"); conn->connect_state = s; } else { DEBUGASSERT(conn->connect_state); s = conn->connect_state; } s->tunnel_state = TUNNEL_INIT; s->keepon = TRUE; s->line_start = s->connect_buffer; s->ptr = s->line_start; s->cl = 0; s->close_connection = FALSE; return CURLE_OK; } static void connect_done(struct connectdata *conn) { struct http_connect_state *s = conn->connect_state; s->tunnel_state = TUNNEL_COMPLETE; infof(conn->data, "CONNECT phase completed!\n"); } static CURLcode CONNECT(struct connectdata *conn, int sockindex, const char *hostname, int remote_port) { int subversion = 0; struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; CURLcode result; curl_socket_t tunnelsocket = conn->sock[sockindex]; struct http_connect_state *s = conn->connect_state; #define SELECT_OK 0 #define SELECT_ERROR 1 if(Curl_connect_complete(conn)) return CURLE_OK; /* CONNECT is already completed */ conn->bits.proxy_connect_closed = FALSE; do { timediff_t check; if(TUNNEL_INIT == s->tunnel_state) { /* BEGIN CONNECT PHASE */ char *host_port; Curl_send_buffer *req_buffer; infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ free(data->req.newurl); data->req.newurl = NULL; /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); if(!req_buffer) return CURLE_OUT_OF_MEMORY; host_port = aprintf("%s:%d", hostname, remote_port); if(!host_port) { Curl_add_buffer_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); free(host_port); if(!result) { char *host = NULL; const char *proxyconn = ""; const char *useragent = ""; const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; bool ipv6_ip = conn->bits.ipv6_ip; char *hostheader; /* the hostname may be different */ if(hostname != conn->host.name) ipv6_ip = (strchr(hostname, ':') != NULL); hostheader = /* host:port with IPv6 support */ aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { Curl_add_buffer_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } if(!Curl_checkProxyheaders(conn, "Host")) { host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); Curl_add_buffer_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } } if(!Curl_checkProxyheaders(conn, "Proxy-Connection")) proxyconn = "Proxy-Connection: Keep-Alive\r\n"; if(!Curl_checkProxyheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; result = Curl_add_bufferf(&req_buffer, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ "%s" /* Proxy-Authorization */ "%s" /* User-Agent */ "%s", /* Proxy-Connection */ hostheader, http, host?host:"", conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", useragent, proxyconn); if(host) free(host); free(hostheader); if(!result) result = Curl_add_custom_headers(conn, TRUE, req_buffer); if(!result) /* CRLF terminate the request */ result = Curl_add_bufferf(&req_buffer, "\r\n"); if(!result) { /* Send the connect request to the proxy */ /* BLOCKING */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, sockindex); } req_buffer = NULL; if(result) failf(data, "Failed sending CONNECT to proxy"); } Curl_add_buffer_free(&req_buffer); if(result) return result; s->tunnel_state = TUNNEL_CONNECT; s->perline = 0; } /* END CONNECT PHASE */ check = Curl_timeleft(data, NULL, TRUE); if(check <= 0) { failf(data, "Proxy CONNECT aborted due to timeout"); return CURLE_OPERATION_TIMEDOUT; } if(!Curl_conn_data_pending(conn, sockindex)) /* return so we'll be called again polling-style */ return CURLE_OK; /* at this point, the tunnel_connecting phase is over. */ { /* READING RESPONSE PHASE */ int error = SELECT_OK; while(s->keepon) { ssize_t gotbytes; /* make sure we have space to read more data */ if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) { failf(data, "CONNECT response too large!"); return CURLE_RECV_ERROR; } /* Read one byte at a time to avoid a race condition. Wait at most one second before looping to ensure continuous pgrsUpdates. */ result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes); if(result == CURLE_AGAIN) /* socket buffer drained, return */ return CURLE_OK; if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; if(result) { s->keepon = FALSE; break; } else if(gotbytes <= 0) { if(data->set.proxyauth && data->state.authproxy.avail) { /* proxy auth was requested and there was proxy auth available, then deem this as "mere" proxy disconnect */ conn->bits.proxy_connect_closed = TRUE; infof(data, "Proxy CONNECT connection closed\n"); } else { error = SELECT_ERROR; failf(data, "Proxy CONNECT aborted"); } s->keepon = FALSE; break; } if(s->keepon > TRUE) { /* This means we are currently ignoring a response-body */ s->ptr = s->connect_buffer; if(s->cl) { /* A Content-Length based body: simply count down the counter and make sure to break out of the loop when we're done! */ s->cl--; if(s->cl <= 0) { s->keepon = FALSE; s->tunnel_state = TUNNEL_COMPLETE; break; } } else { /* chunked-encoded body, so we need to do the chunked dance properly to know when the end of the body is reached */ CHUNKcode r; CURLcode extra; ssize_t tookcareof = 0; /* now parse the chunked piece of data so that we can properly tell when the stream ends */ r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof, &extra); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ infof(data, "chunk reading DONE\n"); s->keepon = FALSE; /* we did the full CONNECT treatment, go COMPLETE */ s->tunnel_state = TUNNEL_COMPLETE; } } continue; } s->perline++; /* amount of bytes in this line so far */ /* if this is not the end of a header line then continue */ if(*s->ptr != 0x0a) { s->ptr++; continue; } /* convert from the network encoding */ result = Curl_convert_from_network(data, s->line_start, (size_t)s->perline); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* output debug if that is requested */ if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, s->line_start, (size_t)s->perline); if(!data->set.suppress_connect_headers) { /* send the header to the callback */ int writetype = CLIENTWRITE_HEADER; if(data->set.include_header) writetype |= CLIENTWRITE_BODY; result = Curl_client_write(conn, writetype, s->line_start, s->perline); if(result) return result; } data->info.header_size += (long)s->perline; data->req.headerbytecount += (long)s->perline; /* Newlines are CRLF, so the CR is ignored as the line isn't really terminated until the LF comes. Treat a following CR as end-of-headers as well.*/ if(('\r' == s->line_start[0]) || ('\n' == s->line_start[0])) { /* end of response-headers from the proxy */ s->ptr = s->connect_buffer; if((407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length when we have no auth problem, we must ignore the whole response-body */ s->keepon = 2; if(s->cl) { infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T " bytes of response-body\n", s->cl); } else if(s->chunked_encoding) { CHUNKcode r; CURLcode extra; infof(data, "Ignore chunked response-body\n"); /* We set ignorebody true here since the chunked decoder function will acknowledge that. Pay attention so that this is cleared again when this function returns! */ k->ignorebody = TRUE; if(s->line_start[1] == '\n') { /* this can only be a LF if the letter at index 0 was a CR */ s->line_start++; } /* now parse the chunked piece of data so that we can properly tell when the stream ends */ r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes, &extra); if(r == CHUNKE_STOP) { /* we're done reading chunks! */ infof(data, "chunk reading DONE\n"); s->keepon = FALSE; /* we did the full CONNECT treatment, go to COMPLETE */ s->tunnel_state = TUNNEL_COMPLETE; } } else { /* without content-length or chunked encoding, we can't keep the connection alive since the close is the end signal so we bail out at once instead */ s->keepon = FALSE; } } else s->keepon = FALSE; if(!s->cl) /* we did the full CONNECT treatment, go to COMPLETE */ s->tunnel_state = TUNNEL_COMPLETE; continue; } s->line_start[s->perline] = 0; /* zero terminate the buffer */ if((checkprefix("WWW-Authenticate:", s->line_start) && (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", s->line_start) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; char *auth = Curl_copy_header_value(s->line_start); if(!auth) return CURLE_OUT_OF_MEMORY; result = Curl_http_input_auth(conn, proxy, auth); free(auth); if(result) return result; } else if(checkprefix("Content-Length:", s->line_start)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ infof(data, "Ignoring Content-Length in CONNECT %03d response\n", k->httpcode); } else { (void)curlx_strtoofft(s->line_start + strlen("Content-Length:"), NULL, 10, &s->cl); } } else if(Curl_compareheader(s->line_start, "Connection:", "close")) s->close_connection = TRUE; else if(checkprefix("Transfer-Encoding:", s->line_start)) { if(k->httpcode/100 == 2) { /* A client MUST ignore any Content-Length or Transfer-Encoding header fields received in a successful response to CONNECT. "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ infof(data, "Ignoring Transfer-Encoding in " "CONNECT %03d response\n", k->httpcode); } else if(Curl_compareheader(s->line_start, "Transfer-Encoding:", "chunked")) { infof(data, "CONNECT responded chunked\n"); s->chunked_encoding = TRUE; /* init our chunky engine */ Curl_httpchunk_init(conn); } } else if(Curl_compareheader(s->line_start, "Proxy-Connection:", "close")) s->close_connection = TRUE; else if(2 == sscanf(s->line_start, "HTTP/1.%d %d", &subversion, &k->httpcode)) { /* store the HTTP code from the proxy */ data->info.httpproxycode = k->httpcode; } s->perline = 0; /* line starts over here */ s->ptr = s->connect_buffer; s->line_start = s->ptr; } /* while there's buffer left and loop is requested */ if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; if(error) return CURLE_RECV_ERROR; if(data->info.httpproxycode/100 != 2) { /* Deal with the possibly already received authenticate headers. 'newurl' is set to a new URL if we must loop. */ result = Curl_http_auth_act(conn); if(result) return result; if(conn->bits.close) /* the connection has been marked for closure, most likely in the Curl_http_auth_act() function and thus we can kill it at once below */ s->close_connection = TRUE; } if(s->close_connection && data->req.newurl) { /* Connection closed by server. Don't use it anymore */ Curl_closesocket(conn, conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; break; } } /* END READING RESPONSE PHASE */ /* If we are supposed to continue and request a new URL, which basically * means the HTTP authentication is still going on so if the tunnel * is complete we start over in INIT state */ if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) { connect_init(conn, TRUE); /* reinit */ } } while(data->req.newurl); if(data->info.httpproxycode/100 != 2) { if(s->close_connection && data->req.newurl) { conn->bits.proxy_connect_closed = TRUE; infof(data, "Connect me again please\n"); connect_done(conn); } else { free(data->req.newurl); data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ streamclose(conn, "proxy CONNECT failure"); Curl_closesocket(conn, conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } /* to back to init state */ s->tunnel_state = TUNNEL_INIT; if(conn->bits.proxy_connect_closed) /* this is not an error, just part of the connection negotiation */ return CURLE_OK; failf(data, "Received HTTP code %d from proxy after CONNECT", data->req.httpcode); return CURLE_RECV_ERROR; } s->tunnel_state = TUNNEL_COMPLETE; /* If a proxy-authorization header was used for the proxy, then we should make sure that it isn't accidentally used for the document request after we've connected. So let's free and clear it here. */ Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = NULL; data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; infof(data, "Proxy replied %d to CONNECT request\n", data->info.httpproxycode); data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the document request */ return CURLE_OK; } void Curl_connect_free(struct Curl_easy *data) { struct connectdata *conn = data->conn; struct http_connect_state *s = conn->connect_state; if(s) { free(s); conn->connect_state = NULL; } } /* * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through * this proxy. After that, the socket can be used just as a normal socket. */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int sockindex, const char *hostname, int remote_port) { CURLcode result; if(!conn->connect_state) { result = connect_init(conn, FALSE); if(result) return result; } result = CONNECT(conn, sockindex, hostname, remote_port); if(result || Curl_connect_complete(conn)) connect_done(conn); return result; } #else void Curl_connect_free(struct Curl_easy *data) { (void)data; } #endif /* CURL_DISABLE_PROXY */ davix-0.8.0/deps/curl/lib/system_win32.h0000644000000000000000000000443714121063461016523 0ustar rootroot#ifndef HEADER_CURL_SYSTEM_WIN32_H #define HEADER_CURL_SYSTEM_WIN32_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2016 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(WIN32) extern LARGE_INTEGER Curl_freq; extern bool Curl_isVistaOrGreater; CURLcode Curl_win32_init(long flags); void Curl_win32_cleanup(long init_flags); /* Version condition */ typedef enum { VERSION_LESS_THAN, VERSION_LESS_THAN_EQUAL, VERSION_EQUAL, VERSION_GREATER_THAN_EQUAL, VERSION_GREATER_THAN } VersionCondition; /* Platform identifier */ typedef enum { PLATFORM_DONT_CARE, PLATFORM_WINDOWS, PLATFORM_WINNT } PlatformIdentifier; /* We use our own typedef here since some headers might lack this */ typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *); /* This is used instead of if_nametoindex if available on Windows */ extern IF_NAMETOINDEX_FN Curl_if_nametoindex; /* This is used to verify if we are running on a specific windows version */ bool Curl_verify_windows_version(const unsigned int majorVersion, const unsigned int minorVersion, const PlatformIdentifier platform, const VersionCondition condition); /* This is used to dynamically load DLLs */ HMODULE Curl_load_library(LPCTSTR filename); #endif /* WIN32 */ #endif /* HEADER_CURL_SYSTEM_WIN32_H */ davix-0.8.0/deps/curl/lib/libcurl.rc0000644000000000000000000000422514121063461015761 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #include "../include/curl/curlver.h" LANGUAGE 0, 0 #define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0 VS_VERSION_INFO VERSIONINFO FILEVERSION RC_VERSION PRODUCTVERSION RC_VERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #if defined(DEBUGBUILD) || defined(_DEBUG) FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0" VALUE "FileDescription", "libcurl Shared Library\0" VALUE "FileVersion", LIBCURL_VERSION "\0" VALUE "InternalName", "libcurl\0" VALUE "OriginalFilename", "libcurl.dll\0" VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */ VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END davix-0.8.0/deps/curl/lib/ldap.c0000644000000000000000000007051714121063461015072 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP) /* * Notice that USE_OPENLDAP is only a source code selection switch. When * libcurl is built with USE_OPENLDAP defined the libcurl source code that * gets compiled is the code from openldap.c, otherwise the code that gets * compiled is the code from ldap.c. * * When USE_OPENLDAP is defined a recent version of the OpenLDAP library * might be required for compilation and runtime. In order to use ancient * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ #ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ # include # ifndef LDAP_VENDOR_NAME # error Your Platform SDK is NOT sufficient for LDAP support! \ Update your Platform SDK, or disable LDAP support! # else # include # endif #else # define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */ # ifdef HAVE_LBER_H # include # endif # include # if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H)) # include # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ #endif #include "urldata.h" #include #include "sendf.h" #include "escape.h" #include "progress.h" #include "transfer.h" #include "strcase.h" #include "strtok.h" #include "curl_ldap.h" #include "curl_multibyte.h" #include "curl_base64.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifndef HAVE_LDAP_URL_PARSE /* Use our own implementation. */ typedef struct { char *lud_host; int lud_port; #if defined(USE_WIN32_LDAP) TCHAR *lud_dn; TCHAR **lud_attrs; #else char *lud_dn; char **lud_attrs; #endif int lud_scope; #if defined(USE_WIN32_LDAP) TCHAR *lud_filter; #else char *lud_filter; #endif char **lud_exts; size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the "real" struct so can only be used in code without HAVE_LDAP_URL_PARSE defined */ } CURL_LDAPURLDesc; #undef LDAPURLDesc #define LDAPURLDesc CURL_LDAPURLDesc static int _ldap_url_parse(const struct connectdata *conn, LDAPURLDesc **ludp); static void _ldap_free_urldesc(LDAPURLDesc *ludp); #undef ldap_free_urldesc #define ldap_free_urldesc _ldap_free_urldesc #endif #ifdef DEBUG_LDAP #define LDAP_TRACE(x) do { \ _ldap_trace("%u: ", __LINE__); \ _ldap_trace x; \ } while(0) static void _ldap_trace(const char *fmt, ...); #else #define LDAP_TRACE(x) Curl_nop_stmt #endif #if defined(USE_WIN32_LDAP) && defined(ldap_err2string) /* Use ansi error strings in UNICODE builds */ #undef ldap_err2string #define ldap_err2string ldap_err2stringA #endif static CURLcode Curl_ldap(struct connectdata *conn, bool *done); /* * LDAP protocol handler. */ const struct Curl_handler Curl_handler_ldap = { "LDAP", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_ldap, /* do_it */ ZERO_NULL, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_NONE /* flags */ }; #ifdef HAVE_LDAP_SSL /* * LDAPS protocol handler. */ const struct Curl_handler Curl_handler_ldaps = { "LDAPS", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_ldap, /* do_it */ ZERO_NULL, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_LDAPS, /* defport */ CURLPROTO_LDAPS, /* protocol */ PROTOPT_SSL /* flags */ }; #endif #if defined(USE_WIN32_LDAP) #if defined(USE_WINDOWS_SSPI) static int ldap_win_bind_auth(LDAP *server, const char *user, const char *passwd, unsigned long authflags) { ULONG method = 0; SEC_WINNT_AUTH_IDENTITY cred; int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; memset(&cred, 0, sizeof(cred)); #if defined(USE_SPNEGO) if(authflags & CURLAUTH_NEGOTIATE) { method = LDAP_AUTH_NEGOTIATE; } else #endif #if defined(USE_NTLM) if(authflags & CURLAUTH_NTLM) { method = LDAP_AUTH_NTLM; } else #endif #if !defined(CURL_DISABLE_CRYPTO_AUTH) if(authflags & CURLAUTH_DIGEST) { method = LDAP_AUTH_DIGEST; } else #endif { /* required anyway if one of upper preprocessor definitions enabled */ } if(method && user && passwd) { rc = Curl_create_sspi_identity(user, passwd, &cred); if(!rc) { rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method); Curl_sspi_free_identity(&cred); } } else { /* proceed with current user credentials */ method = LDAP_AUTH_NEGOTIATE; rc = ldap_bind_s(server, NULL, NULL, method); } return rc; } #endif /* #if defined(USE_WINDOWS_SSPI) */ static int ldap_win_bind(struct connectdata *conn, LDAP *server, const char *user, const char *passwd) { int rc = LDAP_INVALID_CREDENTIALS; PTCHAR inuser = NULL; PTCHAR inpass = NULL; if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) { inuser = Curl_convert_UTF8_to_tchar((char *) user); inpass = Curl_convert_UTF8_to_tchar((char *) passwd); rc = ldap_simple_bind_s(server, inuser, inpass); Curl_unicodefree(inuser); Curl_unicodefree(inpass); } #if defined(USE_WINDOWS_SSPI) else { rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth); } #endif return rc; } #endif /* #if defined(USE_WIN32_LDAP) */ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; int rc = 0; LDAP *server = NULL; LDAPURLDesc *ludp = NULL; LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; struct Curl_easy *data = conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; char *val_b64 = NULL; size_t val_b64_sz = 0; curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ #endif #if defined(USE_WIN32_LDAP) TCHAR *host = NULL; #else char *host = NULL; #endif char *user = NULL; char *passwd = NULL; *done = TRUE; /* unconditionally */ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n", LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION); infof(data, "LDAP local: %s\n", data->change.url); #ifdef HAVE_LDAP_URL_PARSE rc = ldap_url_parse(data->change.url, &ludp); #else rc = _ldap_url_parse(conn, &ludp); #endif if(rc != 0) { failf(data, "LDAP local: %s", ldap_err2string(rc)); result = CURLE_LDAP_INVALID_URL; goto quit; } /* Get the URL scheme (either ldap or ldaps) */ if(conn->given->flags & PROTOPT_SSL) ldap_ssl = 1; infof(data, "LDAP local: trying to establish %s connection\n", ldap_ssl ? "encrypted" : "cleartext"); #if defined(USE_WIN32_LDAP) host = Curl_convert_UTF8_to_tchar(conn->host.name); if(!host) { result = CURLE_OUT_OF_MEMORY; goto quit; } #else host = conn->host.name; #endif if(conn->bits.user_passwd) { user = conn->user; passwd = conn->passwd; } #ifdef LDAP_OPT_NETWORK_TIMEOUT ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); #endif ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); if(ldap_ssl) { #ifdef HAVE_LDAP_SSL #ifdef USE_WIN32_LDAP /* Win32 LDAP SDK doesn't support insecure mode without CA! */ server = ldap_sslinit(host, (int)conn->port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; char *ldap_ca = conn->ssl_config.CAfile; #if defined(CURL_HAS_NOVELL_LDAPSDK) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } if(conn->ssl_config.verifypeer) { /* Novell SDK supports DER or BASE64 files. */ int cert_type = LDAPSSL_CERT_FILETYPE_B64; if((data->set.ssl.cert_type) && (strcasecompare(data->set.ssl.cert_type, "DER"))) cert_type = LDAPSSL_CERT_FILETYPE_DER; if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using %s CA cert '%s'\n", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), ldap_ca); rc = ldapssl_add_trusted_cert(ldap_ca, cert_type); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting %s CA cert: %s", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAPSSL_VERIFY_SERVER; } else ldap_option = LDAPSSL_VERIFY_NONE; rc = ldapssl_set_verify_mode(ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } server = ldapssl_init(host, (int)conn->port, 1); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; } #elif defined(LDAP_OPT_X_TLS) if(conn->ssl_config.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ if((data->set.ssl.cert_type) && (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); result = CURLE_SSL_CERTPROBLEM; goto quit; } if(!ldap_ca) { failf(data, "LDAP local: ERROR PEM CA cert not set!"); result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting PEM CA cert: %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAP_OPT_X_TLS_DEMAND; } else ldap_option = LDAP_OPT_X_TLS_NEVER; rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; } ldap_option = LDAP_OPT_X_TLS_HARD; rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } /* rc = ldap_start_tls_s(server, NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } */ #else /* we should probably never come up to here since configure should check in first place if we can support LDAP SSL/TLS */ failf(data, "LDAP local: SSL/TLS not supported with this version " "of the OpenLDAP toolkit\n"); result = CURLE_SSL_CERTPROBLEM; goto quit; #endif #endif #endif /* CURL_LDAP_USE_SSL */ } else { server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; } } #ifdef USE_WIN32_LDAP ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #endif #ifdef USE_WIN32_LDAP rc = ldap_win_bind(conn, server, user, passwd); #else rc = ldap_simple_bind_s(server, user, passwd); #endif if(!ldap_ssl && rc != 0) { ldap_proto = LDAP_VERSION2; ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #ifdef USE_WIN32_LDAP rc = ldap_win_bind(conn, server, user, passwd); #else rc = ldap_simple_bind_s(server, user, passwd); #endif } if(rc != 0) { #ifdef USE_WIN32_LDAP failf(data, "LDAP local: bind via ldap_win_bind %s", ldap_err2string(rc)); #else failf(data, "LDAP local: bind via ldap_simple_bind_s %s", ldap_err2string(rc)); #endif result = CURLE_LDAP_CANNOT_BIND; goto quit; } rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { failf(data, "LDAP remote: %s", ldap_err2string(rc)); result = CURLE_LDAP_SEARCH_FAILED; goto quit; } for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); entryIterator; entryIterator = ldap_next_entry(server, entryIterator), num++) { BerElement *ber = NULL; #if defined(USE_WIN32_LDAP) TCHAR *attribute; #else char *attribute; /*! suspicious that this isn't 'const' */ #endif int i; /* Get the DN and write it to the client */ { char *name; size_t name_len; #if defined(USE_WIN32_LDAP) TCHAR *dn = ldap_get_dn(server, entryIterator); name = Curl_convert_tchar_to_UTF8(dn); if(!name) { ldap_memfree(dn); result = CURLE_OUT_OF_MEMORY; goto quit; } #else char *dn = name = ldap_get_dn(server, entryIterator); #endif name_len = strlen(name); result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); if(result) { #if defined(USE_WIN32_LDAP) Curl_unicodefree(name); #endif ldap_memfree(dn); goto quit; } result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name, name_len); if(result) { #if defined(USE_WIN32_LDAP) Curl_unicodefree(name); #endif ldap_memfree(dn); goto quit; } result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); if(result) { #if defined(USE_WIN32_LDAP) Curl_unicodefree(name); #endif ldap_memfree(dn); goto quit; } dlsize += name_len + 5; #if defined(USE_WIN32_LDAP) Curl_unicodefree(name); #endif ldap_memfree(dn); } /* Get the attributes and write them to the client */ for(attribute = ldap_first_attribute(server, entryIterator, &ber); attribute; attribute = ldap_next_attribute(server, entryIterator, ber)) { BerValue **vals; size_t attr_len; #if defined(USE_WIN32_LDAP) char *attr = Curl_convert_tchar_to_UTF8(attribute); if(!attr) { if(ber) ber_free(ber, 0); result = CURLE_OUT_OF_MEMORY; goto quit; } #else char *attr = attribute; #endif attr_len = strlen(attr); vals = ldap_get_values_len(server, entryIterator, attribute); if(vals != NULL) { for(i = 0; (vals[i] != NULL); i++) { result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attr, attr_len); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } dlsize += attr_len + 3; if((attr_len > 7) && (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ result = Curl_base64_encode(data, vals[i]->bv_val, vals[i]->bv_len, &val_b64, &val_b64_sz); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } if(val_b64_sz > 0) { result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); free(val_b64); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } dlsize += val_b64_sz; } } else { result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, vals[i]->bv_len); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } dlsize += vals[i]->bv_len; } result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); if(result) { ldap_value_free_len(vals); #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); if(ber) ber_free(ber, 0); goto quit; } dlsize++; } /* Free memory used to store values */ ldap_value_free_len(vals); } /* Free the attribute as we are done with it */ #if defined(USE_WIN32_LDAP) Curl_unicodefree(attr); #endif ldap_memfree(attribute); result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); if(result) goto quit; dlsize++; Curl_pgrsSetDownloadCounter(data, dlsize); } if(ber) ber_free(ber, 0); } quit: if(ldapmsg) { ldap_msgfree(ldapmsg); LDAP_TRACE(("Received %d entries\n", num)); } if(rc == LDAP_SIZELIMIT_EXCEEDED) infof(data, "There are more than %d entries\n", num); if(ludp) ldap_free_urldesc(ludp); if(server) ldap_unbind_s(server); #if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK) if(ldap_ssl) ldapssl_client_deinit(); #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ #if defined(USE_WIN32_LDAP) Curl_unicodefree(host); #endif /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); connclose(conn, "LDAP connection always disable re-use"); return result; } #ifdef DEBUG_LDAP static void _ldap_trace(const char *fmt, ...) { static int do_trace = -1; va_list args; if(do_trace == -1) { const char *env = getenv("CURL_TRACE"); do_trace = (env && strtol(env, NULL, 10) > 0); } if(!do_trace) return; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); } #endif #ifndef HAVE_LDAP_URL_PARSE /* * Return scope-value for a scope-string. */ static int str2scope(const char *p) { if(strcasecompare(p, "one")) return LDAP_SCOPE_ONELEVEL; if(strcasecompare(p, "onetree")) return LDAP_SCOPE_ONELEVEL; if(strcasecompare(p, "base")) return LDAP_SCOPE_BASE; if(strcasecompare(p, "sub")) return LDAP_SCOPE_SUBTREE; if(strcasecompare(p, "subtree")) return LDAP_SCOPE_SUBTREE; return (-1); } /* * Split 'str' into strings separated by commas. * Note: out[] points into 'str'. */ static bool split_str(char *str, char ***out, size_t *count) { char **res; char *lasts; char *s; size_t i; size_t items = 1; s = strchr(str, ','); while(s) { items++; s = strchr(++s, ','); } res = calloc(items, sizeof(char *)); if(!res) return FALSE; for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; s = strtok_r(NULL, ",", &lasts), i++) res[i] = s; *out = res; *count = items; return TRUE; } /* * Break apart the pieces of an LDAP URL. * Syntax: * ldap://:/???? * * already known from 'conn->host.name'. * already known from 'conn->remote_port'. * extract the rest from 'conn->data->state.path+1'. All fields are optional. * e.g. * ldap://:/??? * yields ludp->lud_dn = "". * * Defined in RFC4516 section 2. */ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *p; char *path; char *q = NULL; char *query = NULL; size_t i; if(!conn->data || !conn->data->state.up.path || conn->data->state.up.path[0] != '/' || !strncasecompare("LDAP", conn->data->state.up.scheme, 4)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; ludp->lud_port = conn->remote_port; ludp->lud_host = conn->host.name; /* Duplicate the path */ p = path = strdup(conn->data->state.up.path + 1); if(!path) return LDAP_NO_MEMORY; /* Duplicate the query if present */ if(conn->data->state.up.query) { q = query = strdup(conn->data->state.up.query); if(!query) { free(path); return LDAP_NO_MEMORY; } } /* Parse the DN (Distinguished Name) */ if(*p) { char *dn = p; char *unescaped; CURLcode result; LDAP_TRACE(("DN '%s'\n", dn)); /* Unescape the DN */ result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); if(result) { rc = LDAP_NO_MEMORY; goto quit; } #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ Curl_unicodefree(unescaped); if(!ludp->lud_dn) { rc = LDAP_NO_MEMORY; goto quit; } #else ludp->lud_dn = unescaped; #endif } p = q; if(!p) goto quit; /* Parse the attributes. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; if(*p) { char **attributes; size_t count = 0; /* Split the string into an array of attributes */ if(!split_str(p, &attributes, &count)) { rc = LDAP_NO_MEMORY; goto quit; } /* Allocate our array (+1 for the NULL entry) */ #if defined(USE_WIN32_LDAP) ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); #else ludp->lud_attrs = calloc(count + 1, sizeof(char *)); #endif if(!ludp->lud_attrs) { free(attributes); rc = LDAP_NO_MEMORY; goto quit; } for(i = 0; i < count; i++) { char *unescaped; CURLcode result; LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i])); /* Unescape the attribute */ result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, FALSE); if(result) { free(attributes); rc = LDAP_NO_MEMORY; goto quit; } #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ Curl_unicodefree(unescaped); if(!ludp->lud_attrs[i]) { free(attributes); rc = LDAP_NO_MEMORY; goto quit; } #else ludp->lud_attrs[i] = unescaped; #endif ludp->lud_attrs_dups++; } free(attributes); } p = q; if(!p) goto quit; /* Parse the scope. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; if(*p) { ludp->lud_scope = str2scope(p); if(ludp->lud_scope == -1) { rc = LDAP_INVALID_SYNTAX; goto quit; } LDAP_TRACE(("scope %d\n", ludp->lud_scope)); } p = q; if(!p) goto quit; /* Parse the filter */ q = strchr(p, '?'); if(q) *q++ = '\0'; if(*p) { char *filter = p; char *unescaped; CURLcode result; LDAP_TRACE(("filter '%s'\n", filter)); /* Unescape the filter */ result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); if(result) { rc = LDAP_NO_MEMORY; goto quit; } #if defined(USE_WIN32_LDAP) /* Convert the unescaped string to a tchar */ ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); /* Free the unescaped string as we are done with it */ Curl_unicodefree(unescaped); if(!ludp->lud_filter) { rc = LDAP_NO_MEMORY; goto quit; } #else ludp->lud_filter = unescaped; #endif } p = q; if(p && !*p) { rc = LDAP_INVALID_SYNTAX; goto quit; } quit: free(path); free(query); return rc; } static int _ldap_url_parse(const struct connectdata *conn, LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; *ludpp = NULL; if(!ludp) return LDAP_NO_MEMORY; rc = _ldap_url_parse2(conn, ludp); if(rc != LDAP_SUCCESS) { _ldap_free_urldesc(ludp); ludp = NULL; } *ludpp = ludp; return (rc); } static void _ldap_free_urldesc(LDAPURLDesc *ludp) { if(!ludp) return; free(ludp->lud_dn); free(ludp->lud_filter); if(ludp->lud_attrs) { size_t i; for(i = 0; i < ludp->lud_attrs_dups; i++) free(ludp->lud_attrs[i]); free(ludp->lud_attrs); } free(ludp); } #endif /* !HAVE_LDAP_URL_PARSE */ #endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ davix-0.8.0/deps/curl/lib/libcurl.vers.in0000644000000000000000000000020214121063461016730 0ustar rootrootHIDDEN { local: __*; _rest*; _save*; }; CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4 { global: curl_*; local: *; }; davix-0.8.0/deps/curl/lib/curl_threads.c0000644000000000000000000000737314121063461016631 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #if defined(USE_THREADS_POSIX) # ifdef HAVE_PTHREAD_H # include # endif #elif defined(USE_THREADS_WIN32) # ifdef HAVE_PROCESS_H # include # endif #endif #include "curl_threads.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #if defined(USE_THREADS_POSIX) struct curl_actual_call { unsigned int (*func)(void *); void *arg; }; static void *curl_thread_create_thunk(void *arg) { struct curl_actual_call * ac = arg; unsigned int (*func)(void *) = ac->func; void *real_arg = ac->arg; free(ac); (*func)(real_arg); return 0; } curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg) { curl_thread_t t = malloc(sizeof(pthread_t)); struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call)); if(!(ac && t)) goto err; ac->func = func; ac->arg = arg; if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0) goto err; return t; err: free(t); free(ac); return curl_thread_t_null; } void Curl_thread_destroy(curl_thread_t hnd) { if(hnd != curl_thread_t_null) { pthread_detach(*hnd); free(hnd); } } int Curl_thread_join(curl_thread_t *hnd) { int ret = (pthread_join(**hnd, NULL) == 0); free(*hnd); *hnd = curl_thread_t_null; return ret; } #elif defined(USE_THREADS_WIN32) /* !checksrc! disable SPACEBEFOREPAREN 1 */ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), void *arg) { #ifdef _WIN32_WCE typedef HANDLE curl_win_thread_handle_t; #elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) typedef unsigned long curl_win_thread_handle_t; #else typedef uintptr_t curl_win_thread_handle_t; #endif curl_thread_t t; curl_win_thread_handle_t thread_handle; #ifdef _WIN32_WCE thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL); #else thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL); #endif t = (curl_thread_t)thread_handle; if((t == 0) || (t == LongToHandle(-1L))) { #ifdef _WIN32_WCE DWORD gle = GetLastError(); errno = ((gle == ERROR_ACCESS_DENIED || gle == ERROR_NOT_ENOUGH_MEMORY) ? EACCES : EINVAL); #endif return curl_thread_t_null; } return t; } void Curl_thread_destroy(curl_thread_t hnd) { CloseHandle(hnd); } int Curl_thread_join(curl_thread_t *hnd) { #if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ (_WIN32_WINNT < _WIN32_WINNT_VISTA) int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); #else int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); #endif Curl_thread_destroy(*hnd); *hnd = curl_thread_t_null; return ret; } #endif /* USE_THREADS_* */ davix-0.8.0/deps/curl/lib/md4.c0000644000000000000000000003366114121063461014635 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_CRYPTO_AUTH) #include "curl_md4.h" #include "warnless.h" #ifdef USE_OPENSSL #include #endif /* USE_OPENSSL */ #ifdef USE_MBEDTLS #include #include #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS #endif #endif /* USE_MBEDTLS */ #if defined(USE_GNUTLS_NETTLE) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct md4_ctx MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { md4_init(ctx); } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { md4_update(ctx, size, data); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { md4_digest(ctx, MD4_DIGEST_SIZE, result); } #elif defined(USE_GNUTLS) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef gcry_md_hd_t MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_MD4, 0); } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { gcry_md_write(*ctx, data, size); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { memcpy(result, gcry_md_read(*ctx, 0), MD4_DIGEST_LENGTH); gcry_md_close(*ctx); } #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) /* When OpenSSL is available we use the MD4-functions from OpenSSL */ #include #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef CC_MD4_CTX MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { (void)CC_MD4_Init(ctx); } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { (void)CC_MD4_Update(ctx, data, (CC_LONG)size); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { (void)CC_MD4_Final(result, ctx); } #elif defined(USE_WIN32_CRYPTO) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; } MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { ctx->hCryptProv = 0; ctx->hHash = 0; if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash); } } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { unsigned long length = 0; CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); if(length == MD4_DIGEST_LENGTH) CryptGetHashParam(ctx->hHash, HP_HASHVAL, result, &length, 0); if(ctx->hHash) CryptDestroyHash(ctx->hHash); if(ctx->hCryptProv) CryptReleaseContext(ctx->hCryptProv, 0); } #elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C)) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct { void *data; unsigned long size; } MD4_CTX; static void MD4_Init(MD4_CTX *ctx) { ctx->data = NULL; ctx->size = 0; } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { if(ctx->data == NULL) { ctx->data = malloc(size); if(ctx->data != NULL) { memcpy(ctx->data, data, size); ctx->size = size; } } } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { if(ctx->data != NULL) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md4(ctx->data, ctx->size, result); #else (void) mbedtls_md4_ret(ctx->data, ctx->size, result); #endif Curl_safefree(ctx->data); ctx->size = 0; } } #else /* When no other crypto library is available, or the crypto library doesn't * support MD4, we use this code segment this implementation of it * * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. * MD4 Message-Digest Algorithm (RFC 1320). * * Homepage: https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 * * Author: * Alexander Peslyak, better known as Solar Designer * * This software was written by Alexander Peslyak in 2001. No copyright is * claimed, and the software is hereby placed in the public domain. In case * this attempt to disclaim copyright and place the software in the public * domain is deemed null and void, then the software is Copyright (c) 2001 * Alexander Peslyak and it is hereby released to the general public under the * following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * (This is a heavily cut-down "BSD license".) * * This differs from Colin Plumb's older public domain implementation in that * no exactly 32-bit integer data type is required (any 32-bit or wider * unsigned integer data type will do), there's no compile-time endianness * configuration, and the function prototypes match OpenSSL's. No code from * Colin Plumb's implementation has been reused; this comment merely compares * the properties of the two independent implementations. * * The primary goals of this implementation are portability and ease of use. * It is meant to be fast, but not as fast as possible. Some known * optimizations are not included to reduce source code size and avoid * compile-time configuration. */ #include /* Any 32-bit or wider unsigned integer data type will do */ typedef unsigned int MD4_u32plus; typedef struct { MD4_u32plus lo, hi; MD4_u32plus a, b, c, d; unsigned char buffer[64]; MD4_u32plus block[16]; } MD4_CTX; static void MD4_Init(MD4_CTX *ctx); static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size); static void MD4_Final(unsigned char *result, MD4_CTX *ctx); /* * The basic MD4 functions. * * F and G are optimized compared to their RFC 1320 definitions, with the * optimization for F borrowed from Colin Plumb's MD5 implementation. */ #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) /* * The MD4 transformation for all three rounds. */ #define STEP(f, a, b, c, d, x, s) \ (a) += f((b), (c), (d)) + (x); \ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); /* * SET reads 4 input bytes in little-endian byte order and stores them * in a properly aligned word in host byte order. * * The check for little-endian architectures that tolerate unaligned * memory accesses is just an optimization. Nothing will break if it * doesn't work. */ #if defined(__i386__) || defined(__x86_64__) || defined(__vax__) #define SET(n) \ (*(MD4_u32plus *)(void *)&ptr[(n) * 4]) #define GET(n) \ SET(n) #else #define SET(n) \ (ctx->block[(n)] = \ (MD4_u32plus)ptr[(n) * 4] | \ ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \ ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \ ((MD4_u32plus)ptr[(n) * 4 + 3] << 24)) #define GET(n) \ (ctx->block[(n)]) #endif /* * This processes one or more 64-byte data blocks, but does NOT update * the bit counters. There are no alignment requirements. */ static const void *body(MD4_CTX *ctx, const void *data, unsigned long size) { const unsigned char *ptr; MD4_u32plus a, b, c, d; ptr = (const unsigned char *)data; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; do { MD4_u32plus saved_a, saved_b, saved_c, saved_d; saved_a = a; saved_b = b; saved_c = c; saved_d = d; /* Round 1 */ STEP(F, a, b, c, d, SET(0), 3) STEP(F, d, a, b, c, SET(1), 7) STEP(F, c, d, a, b, SET(2), 11) STEP(F, b, c, d, a, SET(3), 19) STEP(F, a, b, c, d, SET(4), 3) STEP(F, d, a, b, c, SET(5), 7) STEP(F, c, d, a, b, SET(6), 11) STEP(F, b, c, d, a, SET(7), 19) STEP(F, a, b, c, d, SET(8), 3) STEP(F, d, a, b, c, SET(9), 7) STEP(F, c, d, a, b, SET(10), 11) STEP(F, b, c, d, a, SET(11), 19) STEP(F, a, b, c, d, SET(12), 3) STEP(F, d, a, b, c, SET(13), 7) STEP(F, c, d, a, b, SET(14), 11) STEP(F, b, c, d, a, SET(15), 19) /* Round 2 */ STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3) STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5) STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9) STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13) STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3) STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5) STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9) STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13) STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3) STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5) STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9) STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13) STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3) STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5) STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9) STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13) /* Round 3 */ STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3) STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9) STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11) STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15) STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3) STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9) STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11) STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15) STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3) STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9) STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11) STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15) STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3) STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9) STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11) STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15) a += saved_a; b += saved_b; c += saved_c; d += saved_d; ptr += 64; } while(size -= 64); ctx->a = a; ctx->b = b; ctx->c = c; ctx->d = d; return ptr; } static void MD4_Init(MD4_CTX *ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; ctx->c = 0x98badcfe; ctx->d = 0x10325476; ctx->lo = 0; ctx->hi = 0; } static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { MD4_u32plus saved_lo; unsigned long used; saved_lo = ctx->lo; ctx->lo = (saved_lo + size) & 0x1fffffff; if(ctx->lo < saved_lo) ctx->hi++; ctx->hi += (MD4_u32plus)size >> 29; used = saved_lo & 0x3f; if(used) { unsigned long available = 64 - used; if(size < available) { memcpy(&ctx->buffer[used], data, size); return; } memcpy(&ctx->buffer[used], data, available); data = (const unsigned char *)data + available; size -= available; body(ctx, ctx->buffer, 64); } if(size >= 64) { data = body(ctx, data, size & ~(unsigned long)0x3f); size &= 0x3f; } memcpy(ctx->buffer, data, size); } static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { unsigned long used, available; used = ctx->lo & 0x3f; ctx->buffer[used++] = 0x80; available = 64 - used; if(available < 8) { memset(&ctx->buffer[used], 0, available); body(ctx, ctx->buffer, 64); used = 0; available = 64; } memset(&ctx->buffer[used], 0, available - 8); ctx->lo <<= 3; ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff); ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); body(ctx, ctx->buffer, 64); result[0] = curlx_ultouc((ctx->a)&0xff); result[1] = curlx_ultouc((ctx->a >> 8)&0xff); result[2] = curlx_ultouc((ctx->a >> 16)&0xff); result[3] = curlx_ultouc(ctx->a >> 24); result[4] = curlx_ultouc((ctx->b)&0xff); result[5] = curlx_ultouc((ctx->b >> 8)&0xff); result[6] = curlx_ultouc((ctx->b >> 16)&0xff); result[7] = curlx_ultouc(ctx->b >> 24); result[8] = curlx_ultouc((ctx->c)&0xff); result[9] = curlx_ultouc((ctx->c >> 8)&0xff); result[10] = curlx_ultouc((ctx->c >> 16)&0xff); result[11] = curlx_ultouc(ctx->c >> 24); result[12] = curlx_ultouc((ctx->d)&0xff); result[13] = curlx_ultouc((ctx->d >> 8)&0xff); result[14] = curlx_ultouc((ctx->d >> 16)&0xff); result[15] = curlx_ultouc(ctx->d >> 24); memset(ctx, 0, sizeof(*ctx)); } #endif /* CRYPTO LIBS */ void Curl_md4it(unsigned char *output, const unsigned char *input, const size_t len) { MD4_CTX ctx; MD4_Init(&ctx); MD4_Update(&ctx, input, curlx_uztoui(len)); MD4_Final(output, &ctx); } #endif /* CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/hostip.c0000644000000000000000000007772714121063461015472 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_SETJMP_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_PROCESS_H #include #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "rand.h" #include "share.h" #include "strerror.h" #include "url.h" #include "inet_ntop.h" #include "inet_pton.h" #include "multiif.h" #include "doh.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if defined(CURLRES_SYNCH) && \ defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) /* alarm-based timeouts can only be used with all the dependencies satisfied */ #define USE_ALARM_TIMEOUT #endif #define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */ /* * hostip.c explained * ================== * * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c * source file are these: * * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use * that. The host may not be able to resolve IPv6, but we don't really have to * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4 * defined. * * CURLRES_ARES - is defined if libcurl is built to use c-ares for * asynchronous name resolves. This can be Windows or *nix. * * CURLRES_THREADED - is defined if libcurl is built to run under (native) * Windows, and then the name resolve will be done in a new thread, and the * supported API will be the same as for ares-builds. * * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is * defined. * * The host*.c sources files are split up like this: * * hostip.c - method-independent resolver functions and utility functions * hostasyn.c - functions for asynchronous name resolves * hostsyn.c - functions for synchronous name resolves * hostip4.c - IPv4 specific functions * hostip6.c - IPv6 specific functions * * The two asynchronous name resolver backends are implemented in: * asyn-ares.c - functions for ares-using name resolves * asyn-thread.c - functions for threaded name resolves * The hostip.h is the united header file for all this. It defines the * CURLRES_* defines based on the config*.h and curl_setup.h defines. */ static void freednsentry(void *freethis); /* * Return # of addresses in a Curl_addrinfo struct */ int Curl_num_addresses(const Curl_addrinfo *addr) { int i = 0; while(addr) { addr = addr->ai_next; i++; } return i; } /* * Curl_printable_address() returns a printable version of the 1st address * given in the 'ai' argument. The result will be stored in the buf that is * bufsize bytes big. * * If the conversion fails, it returns NULL. */ const char * Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize) { const struct sockaddr_in *sa4; const struct in_addr *ipaddr4; #ifdef ENABLE_IPV6 const struct sockaddr_in6 *sa6; const struct in6_addr *ipaddr6; #endif switch(ai->ai_family) { case AF_INET: sa4 = (const void *)ai->ai_addr; ipaddr4 = &sa4->sin_addr; return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize); #ifdef ENABLE_IPV6 case AF_INET6: sa6 = (const void *)ai->ai_addr; ipaddr6 = &sa6->sin6_addr; return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize); #endif default: break; } return NULL; } /* * Create a hostcache id string for the provided host + port, to be used by * the DNS caching. Without alloc. */ static void create_hostcache_id(const char *name, int port, char *ptr, size_t buflen) { size_t len = strlen(name); if(len > (buflen - 7)) len = buflen - 7; /* store and lower case the name */ while(len--) *ptr++ = (char)TOLOWER(*name++); msnprintf(ptr, 7, ":%u", port); } struct hostcache_prune_data { long cache_timeout; time_t now; }; /* * This function is set as a callback to be called for every entry in the DNS * cache when we want to prune old unused entries. * * Returning non-zero means remove the entry, return 0 to keep it in the * cache. */ static int hostcache_timestamp_remove(void *datap, void *hc) { struct hostcache_prune_data *data = (struct hostcache_prune_data *) datap; struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; return (0 != c->timestamp) && (data->now - c->timestamp >= data->cache_timeout); } /* * Prune the DNS cache. This assumes that a lock has already been taken. */ static void hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now) { struct hostcache_prune_data user; user.cache_timeout = cache_timeout; user.now = now; Curl_hash_clean_with_criterium(hostcache, (void *) &user, hostcache_timestamp_remove); } /* * Library-wide function for pruning the DNS cache. This function takes and * returns the appropriate locks. */ void Curl_hostcache_prune(struct Curl_easy *data) { time_t now; if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache) /* cache forever means never prune, and NULL hostcache means we can't do it */ return; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); time(&now); /* Remove outdated and unused entries from the hostcache */ hostcache_prune(data->dns.hostcache, data->set.dns_cache_timeout, now); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } #ifdef HAVE_SIGSETJMP /* Beware this is a global and unique instance. This is used to store the return address that we can jump back to from inside a signal handler. This is not thread-safe stuff. */ sigjmp_buf curl_jmpenv; #endif /* lookup address, returns entry if found and not stale */ static struct Curl_dns_entry * fetch_addr(struct connectdata *conn, const char *hostname, int port) { struct Curl_dns_entry *dns = NULL; size_t entry_len; struct Curl_easy *data = conn->data; char entry_id[MAX_HOSTCACHE_LEN]; /* Create an entry id, based upon the hostname and port */ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); entry_len = strlen(entry_id); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); /* No entry found in cache, check if we might have a wildcard entry */ if(!dns && data->change.wildcard_resolve) { create_hostcache_id("*", port, entry_id, sizeof(entry_id)); entry_len = strlen(entry_id); /* See if it's already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); } if(dns && (data->set.dns_cache_timeout != -1)) { /* See whether the returned entry is stale. Done before we release lock */ struct hostcache_prune_data user; time(&user.now); user.cache_timeout = data->set.dns_cache_timeout; if(hostcache_timestamp_remove(&user, dns)) { infof(data, "Hostname in DNS cache was stale, zapped\n"); dns = NULL; /* the memory deallocation is being handled by the hash */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); } } return dns; } /* * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache. * * Curl_resolv() checks initially and multi_runsingle() checks each time * it discovers the handle in the state WAITRESOLVE whether the hostname * has already been resolved and the address has already been stored in * the DNS cache. This short circuits waiting for a lot of pending * lookups for the same hostname requested by different handles. * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. * * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after * use, or we'll leak memory! */ struct Curl_dns_entry * Curl_fetch_addr(struct connectdata *conn, const char *hostname, int port) { struct Curl_easy *data = conn->data; struct Curl_dns_entry *dns = NULL; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = fetch_addr(conn, hostname, port); if(dns) dns->inuse++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); return dns; } #ifndef CURL_DISABLE_SHUFFLE_DNS UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr); /* * Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo' * struct by re-linking its linked list. * * The addr argument should be the address of a pointer to the head node of a * `Curl_addrinfo` list and it will be modified to point to the new head after * shuffling. * * Not declared static only to make it easy to use in a unit test! * * @unittest: 1608 */ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr) { CURLcode result = CURLE_OK; const int num_addrs = Curl_num_addresses(*addr); if(num_addrs > 1) { Curl_addrinfo **nodes; infof(data, "Shuffling %i addresses", num_addrs); nodes = malloc(num_addrs*sizeof(*nodes)); if(nodes) { int i; unsigned int *rnd; const size_t rnd_size = num_addrs * sizeof(*rnd); /* build a plain array of Curl_addrinfo pointers */ nodes[0] = *addr; for(i = 1; i < num_addrs; i++) { nodes[i] = nodes[i-1]->ai_next; } rnd = malloc(rnd_size); if(rnd) { /* Fisher-Yates shuffle */ if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) { Curl_addrinfo *swap_tmp; for(i = num_addrs - 1; i > 0; i--) { swap_tmp = nodes[rnd[i] % (i + 1)]; nodes[rnd[i] % (i + 1)] = nodes[i]; nodes[i] = swap_tmp; } /* relink list in the new order */ for(i = 1; i < num_addrs; i++) { nodes[i-1]->ai_next = nodes[i]; } nodes[num_addrs-1]->ai_next = NULL; *addr = nodes[0]; } free(rnd); } else result = CURLE_OUT_OF_MEMORY; free(nodes); } else result = CURLE_OUT_OF_MEMORY; } return result; } #endif /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. * * When calling Curl_resolv() has resulted in a response with a returned * address, we call this function to store the information in the dns * cache etc * * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port) { char entry_id[MAX_HOSTCACHE_LEN]; size_t entry_len; struct Curl_dns_entry *dns; struct Curl_dns_entry *dns2; #ifndef CURL_DISABLE_SHUFFLE_DNS /* shuffle addresses if requested */ if(data->set.dns_shuffle_addresses) { CURLcode result = Curl_shuffle_addr(data, &addr); if(result) return NULL; } #endif /* Create a new cache entry */ dns = calloc(1, sizeof(struct Curl_dns_entry)); if(!dns) { return NULL; } /* Create an entry id, based upon the hostname and port */ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); entry_len = strlen(entry_id); dns->inuse = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ time(&dns->timestamp); if(dns->timestamp == 0) dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */ /* Store the resolved data in our DNS cache. */ dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1, (void *)dns); if(!dns2) { free(dns); return NULL; } dns = dns2; dns->inuse++; /* mark entry as in-use */ return dns; } /* * Curl_resolv() is the main name resolve function within libcurl. It resolves * a name and returns a pointer to the entry in the 'entry' argument (if one * is provided). This function might return immediately if we're using asynch * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this * function is used. You MUST call Curl_resolv_unlock() later (when you're * done using this struct) to decrease the counter again. * * In debug mode, we specifically test for an interface name "LocalHost" * and resolve "localhost" instead as a means to permit test cases * to connect to a local test server with any host name. * * Return codes: * * CURLRESOLV_ERROR (-1) = error, no pointer * CURLRESOLV_RESOLVED (0) = OK, pointer provided * CURLRESOLV_PENDING (1) = waiting for response, no pointer */ enum resolve_t Curl_resolv(struct connectdata *conn, const char *hostname, int port, bool allowDOH, struct Curl_dns_entry **entry) { struct Curl_dns_entry *dns = NULL; struct Curl_easy *data = conn->data; CURLcode result; enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = fetch_addr(conn, hostname, port); if(dns) { infof(data, "Hostname %s was found in DNS cache\n", hostname); dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { /* The entry was not in the cache. Resolve it to IP address */ Curl_addrinfo *addr = NULL; int respwait = 0; #ifndef USE_RESOLVE_ON_IPS struct in_addr in; #endif /* notify the resolver start callback */ if(data->set.resolver_start) { int st; Curl_set_in_callback(data, true); st = data->set.resolver_start(data->state.resolver, NULL, data->set.resolver_start_client); Curl_set_in_callback(data, false); if(st) return CURLRESOLV_ERROR; } #ifndef USE_RESOLVE_ON_IPS /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ addr = Curl_ip2addr(AF_INET, &in, hostname, port); #ifdef ENABLE_IPV6 if(!addr) { struct in6_addr in6; /* check if this is an IPv6 address string */ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) /* This is an IPv6 address literal */ addr = Curl_ip2addr(AF_INET6, &in6, hostname, port); } #endif /* ENABLE_IPV6 */ #endif /* !USE_RESOLVE_ON_IPS */ if(!addr) { /* Check what IP specifics the app has requested and if we can provide * it. If not, bail out. */ if(!Curl_ipvalid(conn)) return CURLRESOLV_ERROR; if(allowDOH && data->set.doh) { addr = Curl_doh(conn, hostname, port, &respwait); } else { /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ addr = Curl_getaddrinfo(conn, #ifdef DEBUGBUILD (data->set.str[STRING_DEVICE] && !strcmp(data->set.str[STRING_DEVICE], "LocalHost"))?"localhost": #endif hostname, port, &respwait); } } if(!addr) { if(respwait) { /* the response to our resolve call will come asynchronously at a later time, good or bad */ /* First, check that we haven't received the info by now */ result = Curl_resolv_check(conn, &dns); if(result) /* error detected */ return CURLRESOLV_ERROR; if(dns) rc = CURLRESOLV_RESOLVED; /* pointer provided */ else rc = CURLRESOLV_PENDING; /* no info yet */ } } else { if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) /* returned failure, bail out nicely */ Curl_freeaddrinfo(addr); else rc = CURLRESOLV_RESOLVED; } } *entry = dns; return rc; } #ifdef USE_ALARM_TIMEOUT /* * This signal handler jumps back into the main libcurl code and continues * execution. This effectively causes the remainder of the application to run * within a signal handler which is nonportable and could lead to problems. */ static RETSIGTYPE alarmfunc(int sig) { /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ (void)sig; siglongjmp(curl_jmpenv, 1); } #endif /* USE_ALARM_TIMEOUT */ /* * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a * timeout. This function might return immediately if we're using asynch * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this * function is used. You MUST call Curl_resolv_unlock() later (when you're * done using this struct) to decrease the counter again. * * If built with a synchronous resolver and use of signals is not * disabled by the application, then a nonzero timeout will cause a * timeout after the specified number of milliseconds. Otherwise, timeout * is ignored. * * Return codes: * * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired * CURLRESOLV_ERROR (-1) = error, no pointer * CURLRESOLV_RESOLVED (0) = OK, pointer provided * CURLRESOLV_PENDING (1) = waiting for response, no pointer */ enum resolve_t Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry, timediff_t timeoutms) { #ifdef USE_ALARM_TIMEOUT #ifdef HAVE_SIGACTION struct sigaction keep_sigact; /* store the old struct here */ volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */ struct sigaction sigact; #else #ifdef HAVE_SIGNAL void (*keep_sigact)(int); /* store the old handler here */ #endif /* HAVE_SIGNAL */ #endif /* HAVE_SIGACTION */ volatile long timeout; volatile unsigned int prev_alarm = 0; struct Curl_easy *data = conn->data; #endif /* USE_ALARM_TIMEOUT */ enum resolve_t rc; *entry = NULL; if(timeoutms < 0) /* got an already expired timeout */ return CURLRESOLV_TIMEDOUT; #ifdef USE_ALARM_TIMEOUT if(data->set.no_signal) /* Ignore the timeout when signals are disabled */ timeout = 0; else timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms; if(!timeout) /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, TRUE, entry); if(timeout < 1000) { /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ failf(data, "remaining timeout of %ld too small to resolve via SIGALRM method", timeout); return CURLRESOLV_TIMEDOUT; } /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). This should be the last thing we do before calling Curl_resolv(), as otherwise we'd have to worry about variables that get modified before we invoke Curl_resolv() (and thus use "volatile"). */ if(sigsetjmp(curl_jmpenv, 1)) { /* this is coming from a siglongjmp() after an alarm signal */ failf(data, "name lookup timed out"); rc = CURLRESOLV_ERROR; goto clean_up; } else { /************************************************************* * Set signal handler to catch SIGALRM * Store the old value to be able to set it back later! *************************************************************/ #ifdef HAVE_SIGACTION sigaction(SIGALRM, NULL, &sigact); keep_sigact = sigact; keep_copysig = TRUE; /* yes, we have a copy */ sigact.sa_handler = alarmfunc; #ifdef SA_RESTART /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */ sigact.sa_flags &= ~SA_RESTART; #endif /* now set the new struct */ sigaction(SIGALRM, &sigact, NULL); #else /* HAVE_SIGACTION */ /* no sigaction(), revert to the much lamer signal() */ #ifdef HAVE_SIGNAL keep_sigact = signal(SIGALRM, alarmfunc); #endif #endif /* HAVE_SIGACTION */ /* alarm() makes a signal get sent when the timeout fires off, and that will abort system calls */ prev_alarm = alarm(curlx_sltoui(timeout/1000L)); } #else #ifndef CURLRES_ASYNCH if(timeoutms) infof(conn->data, "timeout on name lookup is not supported\n"); #else (void)timeoutms; /* timeoutms not used with an async resolver */ #endif #endif /* USE_ALARM_TIMEOUT */ /* Perform the actual name resolution. This might be interrupted by an * alarm if it takes too long. */ rc = Curl_resolv(conn, hostname, port, TRUE, entry); #ifdef USE_ALARM_TIMEOUT clean_up: if(!prev_alarm) /* deactivate a possibly active alarm before uninstalling the handler */ alarm(0); #ifdef HAVE_SIGACTION if(keep_copysig) { /* we got a struct as it looked before, now put that one back nice and clean */ sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */ } #else #ifdef HAVE_SIGNAL /* restore the previous SIGALRM handler */ signal(SIGALRM, keep_sigact); #endif #endif /* HAVE_SIGACTION */ /* switch back the alarm() to either zero or to what it was before minus the time we spent until now! */ if(prev_alarm) { /* there was an alarm() set before us, now put it back */ timediff_t elapsed_secs = Curl_timediff(Curl_now(), conn->created) / 1000; /* the alarm period is counted in even number of seconds */ unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs); if(!alarm_set || ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) { /* if the alarm time-left reached zero or turned "negative" (counted with unsigned values), we should fire off a SIGALRM here, but we won't, and zero would be to switch it off so we never set it to less than 1! */ alarm(1); rc = CURLRESOLV_TIMEDOUT; failf(data, "Previous alarm fired off!"); } else alarm((unsigned int)alarm_set); } #endif /* USE_ALARM_TIMEOUT */ return rc; } /* * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been * made, the struct may be destroyed due to pruning. It is important that only * one unlock is made for each Curl_resolv() call. * * May be called with 'data' == NULL for global cache. */ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) { if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); freednsentry(dns); if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } /* * File-internal: release cache dns entry reference, free if inuse drops to 0 */ static void freednsentry(void *freethis) { struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; DEBUGASSERT(dns && (dns->inuse>0)); dns->inuse--; if(dns->inuse == 0) { Curl_freeaddrinfo(dns->addr); free(dns); } } /* * Curl_mk_dnscache() inits a new DNS cache and returns success/failure. */ int Curl_mk_dnscache(struct curl_hash *hash) { return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, freednsentry); } /* * Curl_hostcache_clean() * * This _can_ be called with 'data' == NULL but then of course no locking * can be done! */ void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash) { if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); Curl_hash_clean(hash); if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } CURLcode Curl_loadhostpairs(struct Curl_easy *data) { struct curl_slist *hostp; char hostname[256]; int port = 0; /* Default is no wildcard found */ data->change.wildcard_resolve = false; for(hostp = data->change.resolve; hostp; hostp = hostp->next) { char entry_id[MAX_HOSTCACHE_LEN]; if(!hostp->data) continue; if(hostp->data[0] == '-') { size_t entry_len; if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", hostp->data); continue; } /* Create an entry id, based upon the hostname and port */ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* delete entry, ignore if it didn't exist */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } else { struct Curl_dns_entry *dns; Curl_addrinfo *head = NULL, *tail = NULL; size_t entry_len; char address[64]; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) char *addresses = NULL; #endif char *addr_begin; char *addr_end; char *port_ptr; char *end_ptr; char *host_end; unsigned long tmp_port; bool error = true; host_end = strchr(hostp->data, ':'); if(!host_end || ((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname))) goto err; memcpy(hostname, hostp->data, host_end - hostp->data); hostname[host_end - hostp->data] = '\0'; port_ptr = host_end + 1; tmp_port = strtoul(port_ptr, &end_ptr, 10); if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':') goto err; port = (int)tmp_port; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) addresses = end_ptr + 1; #endif while(*end_ptr) { size_t alen; Curl_addrinfo *ai; addr_begin = end_ptr + 1; addr_end = strchr(addr_begin, ','); if(!addr_end) addr_end = addr_begin + strlen(addr_begin); end_ptr = addr_end; /* allow IP(v6) address within [brackets] */ if(*addr_begin == '[') { if(addr_end == addr_begin || *(addr_end - 1) != ']') goto err; ++addr_begin; --addr_end; } alen = addr_end - addr_begin; if(!alen) continue; if(alen >= sizeof(address)) goto err; memcpy(address, addr_begin, alen); address[alen] = '\0'; #ifndef ENABLE_IPV6 if(strchr(address, ':')) { infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n", address); continue; } #endif ai = Curl_str2addr(address, port); if(!ai) { infof(data, "Resolve address '%s' found illegal!\n", address); goto err; } if(tail) { tail->ai_next = ai; tail = tail->ai_next; } else { head = tail = ai; } } if(!head) goto err; error = false; err: if(error) { infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", hostp->data); Curl_freeaddrinfo(head); continue; } /* Create an entry id, based upon the hostname and port */ create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); if(dns) { infof(data, "RESOLVE %s:%d is - old addresses discarded!\n", hostname, port); /* delete old entry entry, there are two reasons for this 1. old entry may have different addresses. 2. even if entry with correct addresses is already in the cache, but if it is close to expire, then by the time next http request is made, it can get expired and pruned because old entry is not necessarily marked as added by CURLOPT_RESOLVE. */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); } /* put this new host in the cache */ dns = Curl_cache_addr(data, head, hostname, port); if(dns) { dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */ /* release the returned reference; the cache itself will keep the * entry alive: */ dns->inuse--; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { Curl_freeaddrinfo(head); return CURLE_OUT_OF_MEMORY; } infof(data, "Added %s:%d:%s to DNS cache\n", hostname, port, addresses); /* Wildcard hostname */ if(hostname[0] == '*' && hostname[1] == '\0') { infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n", hostname, port); data->change.wildcard_resolve = true; } } } data->change.resolve = NULL; /* dealt with now */ return CURLE_OK; } CURLcode Curl_resolv_check(struct connectdata *conn, struct Curl_dns_entry **dns) { #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH) (void)dns; #endif if(conn->data->set.doh) return Curl_doh_is_resolved(conn, dns); return Curl_resolver_is_resolved(conn, dns); } int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *socks) { #ifdef CURLRES_ASYNCH if(conn->data->set.doh) /* nothing to wait for during DOH resolve, those handles have their own sockets */ return GETSOCK_BLANK; return Curl_resolver_getsock(conn, socks); #else (void)conn; (void)socks; return GETSOCK_BLANK; #endif } /* Call this function after Curl_connect() has returned async=TRUE and then a successful name resolve has been received. Note: this function disconnects and frees the conn data in case of resolve failure */ CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_done) { CURLcode result; if(conn->async.dns) { conn->dns_entry = conn->async.dns; conn->async.dns = NULL; } result = Curl_setup_conn(conn, protocol_done); if(result) /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ Curl_disconnect(conn->data, conn, TRUE); /* close the connection */ return result; } davix-0.8.0/deps/curl/lib/curl_ntlm_core.h0000644000000000000000000001001614121063461017152 0ustar rootroot#ifndef HEADER_CURL_NTLM_CORE_H #define HEADER_CURL_NTLM_CORE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_NTLM) /* If NSS is the first available SSL backend (see order in curl_ntlm_core.c) then it must be initialized to be used by NTLM. */ #if !defined(USE_OPENSSL) && \ !defined(USE_GNUTLS_NETTLE) && \ !defined(USE_GNUTLS) && \ defined(USE_NSS) #define NTLM_NEEDS_NSS_INIT #endif #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) #ifdef USE_OPENSSL # include #endif /* Define USE_NTRESPONSES in order to make the type-3 message include * the NT response message. */ #define USE_NTRESPONSES /* Define USE_NTLM2SESSION in order to make the type-3 message include the NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and MD5 support */ #if defined(USE_NTRESPONSES) && !defined(CURL_DISABLE_CRYPTO_AUTH) #define USE_NTLM2SESSION #endif /* Define USE_NTLM_V2 in order to allow the type-3 message to include the LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 and support for 64-bit integers. */ #if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4) #define USE_NTLM_V2 #endif void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results); CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */); #ifdef USE_NTRESPONSES CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */); #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, const unsigned char *data, unsigned int datalen, unsigned char *output); CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, const char *domain, size_t domlen, unsigned char *ntlmhash, unsigned char *ntlmv2hash); CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, unsigned char *challenge_client, struct ntlmdata *ntlm, unsigned char **ntresp, unsigned int *ntresp_len); CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, unsigned char *challenge_client, unsigned char *challenge_server, unsigned char *lmresp); #endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ #endif /* USE_NTRESPONSES */ #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ #endif /* USE_NTLM */ #endif /* HEADER_CURL_NTLM_CORE_H */ davix-0.8.0/deps/curl/lib/hostcheck.c0000644000000000000000000001147014121063461016116 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_OPENSSL) \ || defined(USE_GSKIT) \ || defined(USE_SCHANNEL) /* these backends use functions from this file */ #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #include "hostcheck.h" #include "strcase.h" #include "inet_pton.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * Match a hostname against a wildcard pattern. * E.g. * "foo.host.com" matches "*.host.com". * * We use the matching rule described in RFC6125, section 6.4.3. * https://tools.ietf.org/html/rfc6125#section-6.4.3 * * In addition: ignore trailing dots in the host names and wildcards, so that * the names are used normalized. This is what the browsers do. * * Do not allow wildcard matching on IP numbers. There are apparently * certificates being used with an IP address in the CN field, thus making no * apparent distinction between a name and an IP. We need to detect the use of * an IP address and not wildcard match on such names. * * NOTE: hostmatch() gets called with copied buffers so that it can modify the * contents at will. */ static int hostmatch(char *hostname, char *pattern) { const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; int wildcard_enabled; size_t prefixlen, suffixlen; struct in_addr ignored; #ifdef ENABLE_IPV6 struct sockaddr_in6 si6; #endif /* normalize pattern and hostname by stripping off trailing dots */ size_t len = strlen(hostname); if(hostname[len-1]=='.') hostname[len-1] = 0; len = strlen(pattern); if(pattern[len-1]=='.') pattern[len-1] = 0; pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* detect IP address as hostname and fail the match if so */ if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) return CURL_HOST_NOMATCH; #ifdef ENABLE_IPV6 if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) return CURL_HOST_NOMATCH; #endif /* We require at least 2 dots in pattern to avoid too wide wildcard match. */ wildcard_enabled = 1; pattern_label_end = strchr(pattern, '.'); if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || pattern_wildcard > pattern_label_end || strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; } if(!wildcard_enabled) return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if(hostname_label_end == NULL || !strcasecompare(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most label of the hostname is at least as large as the left-most label of the pattern. */ if(hostname_label_end - hostname < pattern_label_end - pattern) return CURL_HOST_NOMATCH; prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard + 1); return strncasecompare(pattern, hostname, prefixlen) && strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) { int res = 0; if(!match_pattern || !*match_pattern || !hostname || !*hostname) /* sanity check */ ; else { char *matchp = strdup(match_pattern); if(matchp) { char *hostp = strdup(hostname); if(hostp) { if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) res = 1; free(hostp); } free(matchp); } } return res; } #endif /* OPENSSL, GSKIT or schannel+wince */ davix-0.8.0/deps/curl/lib/transfer.c0000644000000000000000000017373114121063461016000 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "strtoofft.h" #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifndef HAVE_SOCKET #error "We can't compile without socket() support!" #endif #include "urldata.h" #include #include "netrc.h" #include "content_encoding.h" #include "hostip.h" #include "transfer.h" #include "sendf.h" #include "speedcheck.h" #include "progress.h" #include "http.h" #include "url.h" #include "getinfo.h" #include "vtls/vtls.h" #include "select.h" #include "multiif.h" #include "connect.h" #include "non-ascii.h" #include "http2.h" #include "mime.h" #include "strcase.h" #include "urlapi-int.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ !defined(CURL_DISABLE_IMAP) /* * checkheaders() checks the linked list of custom headers for a * particular header (prefix). Provide the prefix without colon! * * Returns a pointer to the first matching header or NULL if none matched. */ char *Curl_checkheaders(const struct connectdata *conn, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); struct Curl_easy *data = conn->data; for(head = data->set.headers; head; head = head->next) { if(strncasecompare(head->data, thisheader, thislen) && Curl_headersep(head->data[thislen]) ) return head->data; } return NULL; } #endif CURLcode Curl_get_upload_buffer(struct Curl_easy *data) { if(!data->state.ulbuf) { data->state.ulbuf = malloc(data->set.upload_buffer_size); if(!data->state.ulbuf) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } #ifndef CURL_DISABLE_HTTP /* * This function will be called to loop through the trailers buffer * until no more data is available for sending. */ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems, void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; Curl_send_buffer *trailers_buf = data->state.trailers_buf; size_t bytes_left = trailers_buf->size_used-data->state.trailers_bytes_sent; size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left; if(to_copy) { memcpy(buffer, &trailers_buf->buffer[data->state.trailers_bytes_sent], to_copy); data->state.trailers_bytes_sent += to_copy; } return to_copy; } static size_t Curl_trailers_left(void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; Curl_send_buffer *trailers_buf = data->state.trailers_buf; return trailers_buf->size_used - data->state.trailers_bytes_sent; } #endif /* * This function will call the read callback to fill our buffer with data * to upload. */ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, size_t *nreadp) { struct Curl_easy *data = conn->data; size_t buffersize = bytes; size_t nread; curl_read_callback readfunc = NULL; void *extra_data = NULL; #ifdef CURL_DOES_CONVERSIONS bool sending_http_headers = FALSE; if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { const struct HTTP *http = data->req.protop; if(http->sending == HTTPSEND_REQUEST) /* We're sending the HTTP request headers, not the data. Remember that so we don't re-translate them into garbage. */ sending_http_headers = TRUE; } #endif #ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_INITIALIZED) { struct curl_slist *trailers = NULL; CURLcode result; int trailers_ret_code; /* at this point we already verified that the callback exists so we compile and store the trailers buffer, then proceed */ infof(data, "Moving trailers state machine from initialized to sending.\n"); data->state.trailers_state = TRAILERS_SENDING; data->state.trailers_buf = Curl_add_buffer_init(); if(!data->state.trailers_buf) { failf(data, "Unable to allocate trailing headers buffer !"); return CURLE_OUT_OF_MEMORY; } data->state.trailers_bytes_sent = 0; Curl_set_in_callback(data, true); trailers_ret_code = data->set.trailer_callback(&trailers, data->set.trailer_data); Curl_set_in_callback(data, false); if(trailers_ret_code == CURL_TRAILERFUNC_OK) { result = Curl_http_compile_trailers(trailers, &data->state.trailers_buf, data); } else { failf(data, "operation aborted by trailing headers callback"); *nreadp = 0; result = CURLE_ABORTED_BY_CALLBACK; } if(result) { Curl_add_buffer_free(&data->state.trailers_buf); curl_slist_free_all(trailers); return result; } infof(data, "Successfully compiled trailers.\r\n"); curl_slist_free_all(trailers); } #endif /* if we are transmitting trailing data, we don't need to write a chunk size so we skip this */ if(data->req.upload_chunky && data->state.trailers_state == TRAILERS_NONE) { /* if chunked Transfer-Encoding */ buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */ data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */ } #ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING) { /* if we're here then that means that we already sent the last empty chunk but we didn't send a final CR LF, so we sent 0 CR LF. We then start pulling trailing data until we have no more at which point we simply return to the previous point in the state machine as if nothing happened. */ readfunc = Curl_trailers_read; extra_data = (void *)data; } else #endif { readfunc = data->state.fread_func; extra_data = data->state.in; } Curl_set_in_callback(data, true); nread = readfunc(data->req.upload_fromhere, 1, buffersize, extra_data); Curl_set_in_callback(data, false); if(nread == CURL_READFUNC_ABORT) { failf(data, "operation aborted by callback"); *nreadp = 0; return CURLE_ABORTED_BY_CALLBACK; } if(nread == CURL_READFUNC_PAUSE) { struct SingleRequest *k = &data->req; if(conn->handler->flags & PROTOPT_NONETWORK) { /* protocols that work without network cannot be paused. This is actually only FILE:// just now, and it can't pause since the transfer isn't done using the "normal" procedure. */ failf(data, "Read callback asked for PAUSE when not supported!"); return CURLE_READ_ERROR; } /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ if(data->req.upload_chunky) { /* Back out the preallocation done above */ data->req.upload_fromhere -= (8 + 2); } *nreadp = 0; return CURLE_OK; /* nothing was read */ } else if(nread > buffersize) { /* the read function returned a too large value */ *nreadp = 0; failf(data, "read function returned funny value"); return CURLE_READ_ERROR; } if(!data->req.forbidchunk && data->req.upload_chunky) { /* if chunked Transfer-Encoding * build chunk: * * CRLF * CRLF */ /* On non-ASCII platforms the may or may not be translated based on set.prefer_ascii while the protocol portion must always be translated to the network encoding. To further complicate matters, line end conversion might be done later on, so we need to prevent CRLFs from becoming CRCRLFs if that's the case. To do this we use bare LFs here, knowing they'll become CRLFs later on. */ bool added_crlf = FALSE; int hexlen = 0; const char *endofline_native; const char *endofline_network; if( #ifdef CURL_DO_LINEEND_CONV (data->set.prefer_ascii) || #endif (data->set.crlf)) { /* \n will become \r\n later on */ endofline_native = "\n"; endofline_network = "\x0a"; } else { endofline_native = "\r\n"; endofline_network = "\x0d\x0a"; } /* if we're not handling trailing data, proceed as usual */ if(data->state.trailers_state != TRAILERS_SENDING) { char hexbuffer[11] = ""; hexlen = msnprintf(hexbuffer, sizeof(hexbuffer), "%zx%s", nread, endofline_native); /* move buffer pointer */ data->req.upload_fromhere -= hexlen; nread += hexlen; /* copy the prefix to the buffer, leaving out the NUL */ memcpy(data->req.upload_fromhere, hexbuffer, hexlen); /* always append ASCII CRLF to the data unless we have a valid trailer callback */ #ifndef CURL_DISABLE_HTTP if((nread-hexlen) == 0 && data->set.trailer_callback != NULL && data->state.trailers_state == TRAILERS_NONE) { data->state.trailers_state = TRAILERS_INITIALIZED; } else #endif { memcpy(data->req.upload_fromhere + nread, endofline_network, strlen(endofline_network)); added_crlf = TRUE; } } #ifdef CURL_DOES_CONVERSIONS { CURLcode result; size_t length; if(data->set.prefer_ascii) /* translate the protocol and data */ length = nread; else /* just translate the protocol portion */ length = hexlen; if(length) { result = Curl_convert_to_network(data, data->req.upload_fromhere, length); /* Curl_convert_to_network calls failf if unsuccessful */ if(result) return result; } } #endif /* CURL_DOES_CONVERSIONS */ #ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING && !Curl_trailers_left(data)) { Curl_add_buffer_free(&data->state.trailers_buf); data->state.trailers_state = TRAILERS_DONE; data->set.trailer_data = NULL; data->set.trailer_callback = NULL; /* mark the transfer as done */ data->req.upload_done = TRUE; infof(data, "Signaling end of chunked upload after trailers.\n"); } else #endif if((nread - hexlen) == 0 && data->state.trailers_state != TRAILERS_INITIALIZED) { /* mark this as done once this chunk is transferred */ data->req.upload_done = TRUE; infof(data, "Signaling end of chunked upload via terminating chunk.\n"); } if(added_crlf) nread += strlen(endofline_network); /* for the added end of line */ } #ifdef CURL_DOES_CONVERSIONS else if((data->set.prefer_ascii) && (!sending_http_headers)) { CURLcode result; result = Curl_convert_to_network(data, data->req.upload_fromhere, nread); /* Curl_convert_to_network calls failf if unsuccessful */ if(result) return result; } #endif /* CURL_DOES_CONVERSIONS */ *nreadp = nread; return CURLE_OK; } /* * Curl_readrewind() rewinds the read stream. This is typically used for HTTP * POST/PUT with multi-pass authentication when a sending was denied and a * resend is necessary. */ CURLcode Curl_readrewind(struct connectdata *conn) { struct Curl_easy *data = conn->data; curl_mimepart *mimepart = &data->set.mimepost; conn->bits.rewindaftersend = FALSE; /* we rewind now */ /* explicitly switch off sending data on this connection now since we are about to restart a new transfer and thus we want to avoid inadvertently sending more data on the existing connection until the next transfer starts */ data->req.keepon &= ~KEEP_SEND; /* We have sent away data. If not using CURLOPT_POSTFIELDS or CURLOPT_HTTPPOST, call app to rewind */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { struct HTTP *http = data->req.protop; if(http->sendit) mimepart = http->sendit; } if(data->set.postfields) ; /* do nothing */ else if(data->set.httpreq == HTTPREQ_POST_MIME || data->set.httpreq == HTTPREQ_POST_FORM) { if(Curl_mime_rewind(mimepart)) { failf(data, "Cannot rewind mime/post data"); return CURLE_SEND_FAIL_REWIND; } } else { if(data->set.seek_func) { int err; Curl_set_in_callback(data, true); err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET); Curl_set_in_callback(data, false); if(err) { failf(data, "seek callback returned error %d", (int)err); return CURLE_SEND_FAIL_REWIND; } } else if(data->set.ioctl_func) { curlioerr err; Curl_set_in_callback(data, true); err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD, data->set.ioctl_client); Curl_set_in_callback(data, false); infof(data, "the ioctl callback returned %d\n", (int)err); if(err) { failf(data, "ioctl callback returned error %d", (int)err); return CURLE_SEND_FAIL_REWIND; } } else { /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that ourselves with fseek() */ if(data->state.fread_func == (curl_read_callback)fread) { if(-1 != fseek(data->state.in, 0, SEEK_SET)) /* successful rewind */ return CURLE_OK; } /* no callback set or failure above, makes us fail at once */ failf(data, "necessary data rewind wasn't possible"); return CURLE_SEND_FAIL_REWIND; } } return CURLE_OK; } static int data_pending(const struct Curl_easy *data) { struct connectdata *conn = data->conn; /* in the case of libssh2, we can never be really sure that we have emptied its internal buffers so we MUST always try until we get EAGAIN back */ return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || #if defined(USE_NGHTTP2) Curl_ssl_data_pending(conn, FIRSTSOCKET) || /* For HTTP/2, we may read up everything including response body with header fields in Curl_http_readwrite_headers. If no content-length is provided, curl waits for the connection close, which we emulate it using conn->proto.httpc.closed = TRUE. The thing is if we read everything, then http2_recv won't be called and we cannot signal the HTTP/2 stream has closed. As a workaround, we return nonzero here to call http2_recv. */ ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20); #elif defined(ENABLE_QUIC) Curl_ssl_data_pending(conn, FIRSTSOCKET) || Curl_quic_data_pending(data); #else Curl_ssl_data_pending(conn, FIRSTSOCKET); #endif } /* * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the * remote document with the time provided by CURLOPT_TIMEVAL */ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) { if((timeofdoc == 0) || (data->set.timevalue == 0)) return TRUE; switch(data->set.timecondition) { case CURL_TIMECOND_IFMODSINCE: default: if(timeofdoc <= data->set.timevalue) { infof(data, "The requested document is not new enough\n"); data->info.timecond = TRUE; return FALSE; } break; case CURL_TIMECOND_IFUNMODSINCE: if(timeofdoc >= data->set.timevalue) { infof(data, "The requested document is not old enough\n"); data->info.timecond = TRUE; return FALSE; } break; } return TRUE; } /* * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) * * return '*comeback' TRUE if we didn't properly drain the socket so this * function should get called again without select() or similar in between! */ static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, int *didwhat, bool *done, bool *comeback) { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ size_t excess = 0; /* excess bytes read */ bool readmore = FALSE; /* used by RTP to signal for more data */ int maxloops = 100; *done = FALSE; *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ do { bool is_empty_data = FALSE; size_t buffersize = data->set.buffer_size; size_t bytestoread = buffersize; if( #if defined(USE_NGHTTP2) /* For HTTP/2, read data without caring about the content length. This is safe because body in HTTP/2 is always segmented thanks to its framing layer. Meanwhile, we have to call Curl_read to ensure that http2_handle_stream_close is called when we read all incoming bytes for a particular stream. */ !((conn->handler->protocol & PROTO_FAMILY_HTTP) && conn->httpversion == 20) && #endif k->size != -1 && !k->header) { /* make sure we don't read too much */ curl_off_t totalleft = k->size - k->bytecount; if(totalleft < (curl_off_t)bytestoread) bytestoread = (size_t)totalleft; } if(bytestoread) { /* receive data from the network! */ result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread); /* read would've blocked */ if(CURLE_AGAIN == result) break; /* get out of loop */ if(result>0) return result; } else { /* read nothing but since we wanted nothing we consider this an OK situation to proceed from */ DEBUGF(infof(data, "readwrite_data: we're done!\n")); nread = 0; } if(!k->bytecount) { Curl_pgrsTime(data, TIMER_STARTTRANSFER); if(k->exp100 > EXP100_SEND_DATA) /* set time stamp to compare with when waiting for the 100 */ k->start100 = Curl_now(); } *didwhat |= KEEP_RECV; /* indicates data of zero size, i.e. empty file */ is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; /* NUL terminate, allowing string ops to be used */ if(0 < nread || is_empty_data) { k->buf[nread] = 0; } else { /* if we receive 0 or less here, the server closed the connection and we bail out from this! */ DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n")); k->keepon &= ~KEEP_RECV; break; } /* Default buffer to use when we write the buffer, it may be changed in the flow below before the actual storing is done. */ k->str = k->buf; if(conn->handler->readwrite) { result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } #ifndef CURL_DISABLE_HTTP /* Since this is a two-state thing, we check if we are parsing headers at the moment or not. */ if(k->header) { /* we are in parse-the-header-mode */ bool stop_reading = FALSE; result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading); if(result) return result; if(conn->handler->readwrite && (k->maxdownload <= 0 && nread > 0)) { result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } if(stop_reading) { /* We've stopped dealing with input, get out of the do-while loop */ if(nread > 0) { infof(data, "Excess found:" " excess = %zd" " url = %s (zero-length body)\n", nread, data->state.up.path); } break; } } #endif /* CURL_DISABLE_HTTP */ /* This is not an 'else if' since it may be a rest from the header parsing, where the beginning of the buffer is headers and the end is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { if(data->set.opt_no_body) { /* data arrives although we want none, bail out */ streamclose(conn, "ignoring body"); *done = TRUE; return CURLE_WEIRD_SERVER_REPLY; } #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to write a piece of the body */ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { /* HTTP-only checks */ if(data->req.newurl) { if(conn->bits.close) { /* Abort after the headers if "follow Location" is set and we're set to close anyway. */ k->keepon &= ~KEEP_RECV; *done = TRUE; return CURLE_OK; } /* We have a new url to load, but since we want to be able to re-use this connection properly, we read the full response in "ignore more" */ k->ignorebody = TRUE; infof(data, "Ignoring the response-body\n"); } if(data->state.resume_from && !k->content_range && (data->set.httpreq == HTTPREQ_GET) && !k->ignorebody) { if(k->size == data->state.resume_from) { /* The resume point is at the end of file, consider this fine even if it doesn't allow resume from here. */ infof(data, "The entire document is already downloaded"); connclose(conn, "already downloaded"); /* Abort download */ k->keepon &= ~KEEP_RECV; *done = TRUE; return CURLE_OK; } /* we wanted to resume a download, although the server doesn't * seem to support this and we did this with a GET (if it * wasn't a GET we did a POST or PUT resume) */ failf(data, "HTTP server doesn't seem to support " "byte ranges. Cannot resume."); return CURLE_RANGE_ERROR; } if(data->set.timecondition && !data->state.range) { /* A time condition has been set AND no ranges have been requested. This seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct action for a HTTP/1.1 client */ if(!Curl_meets_timecondition(data, k->timeofdoc)) { *done = TRUE; /* We're simulating a http 304 from server so we return what should have been returned from the server */ data->info.httpcode = 304; infof(data, "Simulate a HTTP 304 response!\n"); /* we abort the transfer before it is completed == we ruin the re-use ability. Close the connection */ connclose(conn, "Simulated 304 handling"); return CURLE_OK; } } /* we have a time condition */ } /* this is HTTP or RTSP */ } /* this is the first time we write a body part */ #endif /* CURL_DISABLE_HTTP */ k->bodywrites++; /* pass data to the debug function before it gets "dechunked" */ if(data->set.verbose) { if(k->badheader) { Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, (size_t)k->hbuflen); if(k->badheader == HEADER_PARTHEADER) Curl_debug(data, CURLINFO_DATA_IN, k->str, (size_t)nread); } else Curl_debug(data, CURLINFO_DATA_IN, k->str, (size_t)nread); } #ifndef CURL_DISABLE_HTTP if(k->chunk) { /* * Here comes a chunked transfer flying and we need to decode this * properly. While the name says read, this function both reads * and writes away the data. The returned 'nread' holds the number * of actual data it wrote to the client. */ CURLcode extra; CHUNKcode res = Curl_httpchunk_read(conn, k->str, nread, &nread, &extra); if(CHUNKE_OK < res) { if(CHUNKE_PASSTHRU_ERROR == res) { failf(data, "Failed reading the chunked-encoded stream"); return extra; } failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res)); return CURLE_RECV_ERROR; } if(CHUNKE_STOP == res) { size_t dataleft; /* we're done reading chunks! */ k->keepon &= ~KEEP_RECV; /* read no more */ /* There are now possibly N number of bytes at the end of the str buffer that weren't written to the client. Push it back to be read on the next pass. */ dataleft = conn->chunk.dataleft; if(dataleft != 0) { infof(conn->data, "Leftovers after chunking: %zu bytes\n", dataleft); } } /* If it returned OK, we just keep going */ } #endif /* CURL_DISABLE_HTTP */ /* Account for body content stored in the header buffer */ if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) { DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n", k->hbuflen)); k->bytecount += k->hbuflen; } if((-1 != k->maxdownload) && (k->bytecount + nread >= k->maxdownload)) { excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { infof(data, "Excess found in a read:" " excess = %zu" ", size = %" CURL_FORMAT_CURL_OFF_T ", maxdownload = %" CURL_FORMAT_CURL_OFF_T ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n", excess, k->size, k->maxdownload, k->bytecount); } nread = (ssize_t) (k->maxdownload - k->bytecount); if(nread < 0) /* this should be unusual */ nread = 0; k->keepon &= ~KEEP_RECV; /* we're done reading */ } k->bytecount += nread; Curl_pgrsSetDownloadCounter(data, k->bytecount); if(!k->chunk && (nread || k->badheader || is_empty_data)) { /* If this is chunky transfer, it was already written */ if(k->badheader && !k->ignorebody) { /* we parsed a piece of data wrongly assuming it was a header and now we output it as body instead */ /* Don't let excess data pollute body writes */ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, k->hbuflen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, (size_t)k->maxdownload); if(result) return result; } if(k->badheader < HEADER_ALLBAD) { /* This switch handles various content encodings. If there's an error here, be sure to check over the almost identical code in http_chunks.c. Make sure that ALL_CONTENT_ENCODINGS contains all the encodings handled here. */ if(conn->data->set.http_ce_skip || !k->writer_stack) { if(!k->ignorebody) { #ifndef CURL_DISABLE_POP3 if(conn->handler->protocol & PROTO_FAMILY_POP3) result = Curl_pop3_write(conn, k->str, nread); else #endif /* CURL_DISABLE_POP3 */ result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str, nread); } } else if(!k->ignorebody) result = Curl_unencode_write(conn, k->writer_stack, k->str, nread); } k->badheader = HEADER_NORMAL; /* taken care of now */ if(result) return result; } } /* if(!header and data to read) */ if(conn->handler->readwrite && excess && !conn->bits.stream_was_rewound) { /* Parse the excess data */ k->str += nread; if(&k->str[excess] > &k->buf[data->set.buffer_size]) { /* the excess amount was too excessive(!), make sure it doesn't read out of buffer */ excess = &k->buf[data->set.buffer_size] - k->str; } nread = (ssize_t)excess; result = conn->handler->readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) k->keepon |= KEEP_RECV; /* we're not done reading */ break; } if(is_empty_data) { /* if we received nothing, the server closed the connection and we are done */ k->keepon &= ~KEEP_RECV; } if(k->keepon & KEEP_RECV_PAUSE) { /* this is a paused transfer */ break; } } while(data_pending(data) && maxloops--); if(maxloops <= 0) { /* we mark it as read-again-please */ conn->cselect_bits = CURL_CSELECT_IN; *comeback = TRUE; } if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server may now close the connection. If there's now any kind of sending going on from our side, we need to stop that immediately. */ infof(data, "we are done reading and this is set to close, stop send\n"); k->keepon &= ~KEEP_SEND; /* no writing anymore either */ } return CURLE_OK; } CURLcode Curl_done_sending(struct connectdata *conn, struct SingleRequest *k) { k->keepon &= ~KEEP_SEND; /* we're done writing */ /* These functions should be moved into the handler struct! */ Curl_http2_done_sending(conn); Curl_quic_done_sending(conn); if(conn->bits.rewindaftersend) { CURLcode result = Curl_readrewind(conn); if(result) return result; } return CURLE_OK; } #if defined(WIN32) && !defined(USE_LWIPSOCK) #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B #endif static void win_update_buffer_size(curl_socket_t sockfd) { int result; ULONG ideal; DWORD ideallen; result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0, &ideal, sizeof(ideal), &ideallen, 0, 0); if(result == 0) { setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&ideal, sizeof(ideal)); } } #else #define win_update_buffer_size(x) #endif /* * Send data to upload to the server, when the socket is writable. */ static CURLcode readwrite_upload(struct Curl_easy *data, struct connectdata *conn, int *didwhat) { ssize_t i, si; ssize_t bytes_written; CURLcode result; ssize_t nread; /* number of bytes read */ bool sending_http_headers = FALSE; struct SingleRequest *k = &data->req; if((k->bytecount == 0) && (k->writebytecount == 0)) Curl_pgrsTime(data, TIMER_STARTTRANSFER); *didwhat |= KEEP_SEND; do { /* only read more data if there's no upload data already present in the upload buffer */ if(0 == k->upload_present) { result = Curl_get_upload_buffer(data); if(result) return result; /* init the "upload from here" pointer */ k->upload_fromhere = data->state.ulbuf; if(!k->upload_done) { /* HTTP pollution, this should be written nicer to become more protocol agnostic. */ size_t fillcount; struct HTTP *http = k->protop; if((k->exp100 == EXP100_SENDING_REQUEST) && (http->sending == HTTPSEND_BODY)) { /* If this call is to send body data, we must take some action: We have sent off the full HTTP 1.1 request, and we shall now go into the Expect: 100 state and await such a header */ k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */ k->keepon &= ~KEEP_SEND; /* disable writing */ k->start100 = Curl_now(); /* timeout count starts now */ *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */ /* set a timeout for the multi interface */ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); break; } if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { if(http->sending == HTTPSEND_REQUEST) /* We're sending the HTTP request headers, not the data. Remember that so we don't change the line endings. */ sending_http_headers = TRUE; else sending_http_headers = FALSE; } result = Curl_fillreadbuffer(conn, data->set.upload_buffer_size, &fillcount); if(result) return result; nread = fillcount; } else nread = 0; /* we're done uploading/reading */ if(!nread && (k->keepon & KEEP_SEND_PAUSE)) { /* this is a paused transfer */ break; } if(nread <= 0) { result = Curl_done_sending(conn, k); if(result) return result; break; } /* store number of bytes available for upload */ k->upload_present = nread; /* convert LF to CRLF if so asked */ if((!sending_http_headers) && ( #ifdef CURL_DO_LINEEND_CONV /* always convert if we're FTPing in ASCII mode */ (data->set.prefer_ascii) || #endif (data->set.crlf))) { /* Do we need to allocate a scratch buffer? */ if(!data->state.scratch) { data->state.scratch = malloc(2 * data->set.upload_buffer_size); if(!data->state.scratch) { failf(data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } } /* * ASCII/EBCDIC Note: This is presumably a text (not binary) * transfer so the data should already be in ASCII. * That means the hex values for ASCII CR (0x0d) & LF (0x0a) * must be used instead of the escape sequences \r & \n. */ for(i = 0, si = 0; i < nread; i++, si++) { if(k->upload_fromhere[i] == 0x0a) { data->state.scratch[si++] = 0x0d; data->state.scratch[si] = 0x0a; if(!data->set.crlf) { /* we're here only because FTP is in ASCII mode... bump infilesize for the LF we just added */ if(data->state.infilesize != -1) data->state.infilesize++; } } else data->state.scratch[si] = k->upload_fromhere[i]; } if(si != nread) { /* only perform the special operation if we really did replace anything */ nread = si; /* upload from the new (replaced) buffer instead */ k->upload_fromhere = data->state.scratch; /* set the new amount too */ k->upload_present = nread; } } #ifndef CURL_DISABLE_SMTP if(conn->handler->protocol & PROTO_FAMILY_SMTP) { result = Curl_smtp_escape_eob(conn, nread); if(result) return result; } #endif /* CURL_DISABLE_SMTP */ } /* if 0 == k->upload_present */ else { /* We have a partial buffer left from a previous "round". Use that instead of reading more data */ } /* write to socket (send away data) */ result = Curl_write(conn, conn->writesockfd, /* socket to send to */ k->upload_fromhere, /* buffer pointer */ k->upload_present, /* buffer size */ &bytes_written); /* actually sent */ if(result) return result; win_update_buffer_size(conn->writesockfd); if(data->set.verbose) /* show the data before we change the pointer upload_fromhere */ Curl_debug(data, CURLINFO_DATA_OUT, k->upload_fromhere, (size_t)bytes_written); k->writebytecount += bytes_written; Curl_pgrsSetUploadCounter(data, k->writebytecount); if((!k->upload_chunky || k->forbidchunk) && (k->writebytecount == data->state.infilesize)) { /* we have sent all data we were supposed to */ k->upload_done = TRUE; infof(data, "We are completely uploaded and fine\n"); } if(k->upload_present != bytes_written) { /* we only wrote a part of the buffer (if anything), deal with it! */ /* store the amount of bytes left in the buffer to write */ k->upload_present -= bytes_written; /* advance the pointer where to find the buffer when the next send is to happen */ k->upload_fromhere += bytes_written; } else { /* we've uploaded that buffer now */ result = Curl_get_upload_buffer(data); if(result) return result; k->upload_fromhere = data->state.ulbuf; k->upload_present = 0; /* no more bytes left */ if(k->upload_done) { result = Curl_done_sending(conn, k); if(result) return result; } } } while(0); /* just to break out from! */ return CURLE_OK; } /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. * * return '*comeback' TRUE if we didn't properly drain the socket so this * function should get called again without select() or similar in between! */ CURLcode Curl_readwrite(struct connectdata *conn, struct Curl_easy *data, bool *done, bool *comeback) { struct SingleRequest *k = &data->req; CURLcode result; int didwhat = 0; curl_socket_t fd_read; curl_socket_t fd_write; int select_res = conn->cselect_bits; conn->cselect_bits = 0; /* only use the proper socket if the *_HOLD bit is not set simultaneously as then we are in rate limiting state in that transfer direction */ if((k->keepon & KEEP_RECVBITS) == KEEP_RECV) fd_read = conn->sockfd; else fd_read = CURL_SOCKET_BAD; if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) fd_write = conn->writesockfd; else fd_write = CURL_SOCKET_BAD; if(data->state.drain) { data->state.drain--; select_res |= CURL_CSELECT_IN; DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n")); } if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); if(select_res == CURL_CSELECT_ERR) { failf(data, "select/poll returned error"); return CURLE_SEND_ERROR; } /* We go ahead and do a read if we have a readable socket or if the stream was rewound (in which case we have data in a buffer) */ if((k->keepon & KEEP_RECV) && ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; } /* If we still have writing to do, we check if we have a writable socket. */ if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) { /* write */ result = readwrite_upload(data, conn, &didwhat); if(result) return result; } k->now = Curl_now(); if(didwhat) { ; } else { /* no read no write, this is a timeout? */ if(k->exp100 == EXP100_AWAITING_CONTINUE) { /* This should allow some time for the header to arrive, but only a very short time as otherwise it'll be too much wasted time too often. */ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status": Therefore, when a client sends this header field to an origin server (possibly via a proxy) from which it has never seen a 100 (Continue) status, the client SHOULD NOT wait for an indefinite period before sending the request body. */ timediff_t ms = Curl_timediff(k->now, k->start100); if(ms >= data->set.expect_100_timeout) { /* we've waited long enough, continue anyway */ k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; Curl_expire_done(data, EXPIRE_100_TIMEOUT); infof(data, "Done waiting for 100-continue\n"); } } } if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(data, k->now); if(result) return result; if(k->keepon) { if(0 > Curl_timeleft(data, &k->now, FALSE)) { if(k->size != -1) { failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", Curl_timediff(k->now, data->progress.t_startsingle), k->bytecount, k->size); } else { failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", Curl_timediff(k->now, data->progress.t_startsingle), k->bytecount); } return CURLE_OPERATION_TIMEDOUT; } } else { /* * The transfer has been performed. Just make some general checks before * returning. */ if(!(data->set.opt_no_body) && (k->size != -1) && (k->bytecount != k->size) && #ifdef CURL_DO_LINEEND_CONV /* Most FTP servers don't adjust their file SIZE response for CRLFs, so we'll check to see if the discrepancy can be explained by the number of CRLFs we've changed to LFs. */ (k->bytecount != (k->size + data->state.crlf_conversions)) && #endif /* CURL_DO_LINEEND_CONV */ !k->newurl) { failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T " bytes remaining to read", k->size - k->bytecount); return CURLE_PARTIAL_FILE; } if(!(data->set.opt_no_body) && k->chunk && (conn->chunk.state != CHUNK_STOP)) { /* * In chunked mode, return an error if the connection is closed prior to * the empty (terminating) chunk is read. * * The condition above used to check for * conn->proto.http->chunk.datasize != 0 which is true after reading * *any* chunk, not just the empty chunk. * */ failf(data, "transfer closed with outstanding read data remaining"); return CURLE_PARTIAL_FILE; } if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; } /* Now update the "done" boolean we return */ *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; return CURLE_OK; } /* * Curl_single_getsock() gets called by the multi interface code when the app * has requested to get the sockets for the current connection. This function * will then be called once for every connection that the multi interface * keeps track of. This function will only be called for connections that are * in the proper state to have this information available. */ int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *sock) { const struct Curl_easy *data = conn->data; int bitmap = GETSOCK_BLANK; unsigned sockindex = 0; if(conn->handler->perform_getsock) return conn->handler->perform_getsock(conn, sock); /* don't include HOLD and PAUSE connections */ if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) { DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); bitmap |= GETSOCK_READSOCK(sockindex); sock[sockindex] = conn->sockfd; } /* don't include HOLD and PAUSE connections */ if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) { if((conn->sockfd != conn->writesockfd) || bitmap == GETSOCK_BLANK) { /* only if they are not the same socket and we have a readable one, we increase index */ if(bitmap != GETSOCK_BLANK) sockindex++; /* increase index if we need two entries */ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); sock[sockindex] = conn->writesockfd; } bitmap |= GETSOCK_WRITESOCK(sockindex); } return bitmap; } /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT which means this gets called once for each subsequent redirect etc */ void Curl_init_CONNECT(struct Curl_easy *data) { data->state.fread_func = data->set.fread_func_set; data->state.in = data->set.in_set; } /* * Curl_pretransfer() is called immediately before a transfer starts, and only * once for one transfer no matter if it has redirects or do multi-pass * authentication etc. */ CURLcode Curl_pretransfer(struct Curl_easy *data) { CURLcode result; if(!data->change.url && !data->set.uh) { /* we can't do anything without URL */ failf(data, "No URL set!"); return CURLE_URL_MALFORMAT; } /* since the URL may have been redirected in a previous use of this handle */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ Curl_safefree(data->change.url); data->change.url_alloc = FALSE; } if(!data->change.url && data->set.uh) { CURLUcode uc; uc = curl_url_get(data->set.uh, CURLUPART_URL, &data->set.str[STRING_SET_URL], 0); if(uc) { failf(data, "No URL set!"); return CURLE_URL_MALFORMAT; } } data->change.url = data->set.str[STRING_SET_URL]; /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could specify the size of the cache) but before any transfer takes place. */ result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); if(result) return result; data->state.wildcardmatch = data->set.wildcard_enabled; data->set.followlocation = 0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ data->state.httpversion = 0; /* don't assume any particular server version */ data->state.authproblem = FALSE; data->state.authhost.want = data->set.httpauth; data->state.authproxy.want = data->set.proxyauth; Curl_safefree(data->info.wouldredirect); data->info.wouldredirect = NULL; if(data->set.httpreq == HTTPREQ_PUT) data->state.infilesize = data->set.filesize; else if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD)) { data->state.infilesize = data->set.postfieldsize; if(data->set.postfields && (data->state.infilesize == -1)) data->state.infilesize = (curl_off_t)strlen(data->set.postfields); } else data->state.infilesize = 0; /* If there is a list of cookie files to read, do it now! */ if(data->change.cookielist) Curl_cookie_loadfiles(data); /* If there is a list of host pairs to deal with */ if(data->change.resolve) result = Curl_loadhostpairs(data); if(!result) { /* Allow data->set.use_port to set which port to use. This needs to be * disabled for example when we follow Location: headers to URLs using * different ports! */ data->state.allow_port = TRUE; #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) /************************************************************* * Tell signal handler to ignore SIGPIPE *************************************************************/ if(!data->set.no_signal) data->state.prev_signal = signal(SIGPIPE, SIG_IGN); #endif Curl_initinfo(data); /* reset session-specific information "variables" */ Curl_pgrsResetTransferSizes(data); Curl_pgrsStartNow(data); /* In case the handle is re-used and an authentication method was picked in the session we need to make sure we only use the one(s) we now consider to be fine */ data->state.authhost.picked &= data->state.authhost.want; data->state.authproxy.picked &= data->state.authproxy.want; #ifndef CURL_DISABLE_FTP if(data->state.wildcardmatch) { struct WildcardData *wc = &data->wildcard; if(wc->state < CURLWC_INIT) { result = Curl_wildcard_init(wc); /* init wildcard structures */ if(result) return CURLE_OUT_OF_MEMORY; } } #endif Curl_http2_init_state(&data->state); } return result; } /* * Curl_posttransfer() is called immediately after a transfer ends */ CURLcode Curl_posttransfer(struct Curl_easy *data) { #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) /* restore the signal handler for SIGPIPE before we get back */ if(!data->set.no_signal) signal(SIGPIPE, data->state.prev_signal); #else (void)data; /* unused parameter */ #endif return CURLE_OK; } /* * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string * as given by the remote server and set up the new URL to request. * * This function DOES NOT FREE the given url. */ CURLcode Curl_follow(struct Curl_easy *data, char *newurl, /* the Location: string */ followtype type) /* see transfer.h */ { #ifdef CURL_DISABLE_HTTP (void)data; (void)newurl; (void)type; /* Location: following will not happen when HTTP is disabled */ return CURLE_TOO_MANY_REDIRECTS; #else /* Location: redirect */ bool disallowport = FALSE; bool reachedmax = FALSE; CURLUcode uc; if(type == FOLLOW_REDIR) { if((data->set.maxredirs != -1) && (data->set.followlocation >= data->set.maxredirs)) { reachedmax = TRUE; type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected to URL */ } else { /* mark the next request as a followed location: */ data->state.this_is_a_follow = TRUE; data->set.followlocation++; /* count location-followers */ if(data->set.http_auto_referer) { /* We are asked to automatically set the previous URL as the referer when we get the next URL. We pick the ->url field, which may or may not be 100% correct */ if(data->change.referer_alloc) { Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } data->change.referer = strdup(data->change.url); if(!data->change.referer) return CURLE_OUT_OF_MEMORY; data->change.referer_alloc = TRUE; /* yes, free this later */ } } } if(Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN)) /* This is an absolute URL, don't allow the custom port number */ disallowport = TRUE; DEBUGASSERT(data->state.uh); uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) ); if(uc) { if(type != FOLLOW_FAKE) return Curl_uc_to_curlcode(uc); /* the URL could not be parsed for some reason, but since this is FAKE mode, just duplicate the field as-is */ newurl = strdup(newurl); if(!newurl) return CURLE_OUT_OF_MEMORY; } else { uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); if(uc) return Curl_uc_to_curlcode(uc); } if(type == FOLLOW_FAKE) { /* we're only figuring out the new url if we would've followed locations but now we're done so we can get out! */ data->info.wouldredirect = newurl; if(reachedmax) { failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); return CURLE_TOO_MANY_REDIRECTS; } return CURLE_OK; } if(disallowport) data->state.allow_port = FALSE; if(data->change.url_alloc) Curl_safefree(data->change.url); data->change.url = newurl; data->change.url_alloc = TRUE; infof(data, "Issue another request to this URL: '%s'\n", data->change.url); /* * We get here when the HTTP code is 300-399 (and 401). We need to perform * differently based on exactly what return code there was. * * News from 7.10.6: we can also get here on a 401 or 407, in case we act on * a HTTP (proxy-) authentication scheme other than Basic. */ switch(data->info.httpcode) { /* 401 - Act on a WWW-Authenticate, we keep on moving and do the Authorization: XXXX header in the HTTP request code snippet */ /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the Proxy-Authorization: XXXX header in the HTTP request code snippet */ /* 300 - Multiple Choices */ /* 306 - Not used */ /* 307 - Temporary Redirect */ default: /* for all above (and the unknown ones) */ /* Some codes are explicitly mentioned since I've checked RFC2616 and they * seem to be OK to POST to. */ break; case 301: /* Moved Permanently */ /* (quote from RFC7231, section 6.4.2) * * Note: For historical reasons, a user agent MAY change the request * method from POST to GET for the subsequent request. If this * behavior is undesired, the 307 (Temporary Redirect) status code * can be used instead. * * ---- * * Many webservers expect this, so these servers often answers to a POST * request with an error page. To be sure that libcurl gets the page that * most user agents would get, libcurl has to force GET. * * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and * can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM || data->set.httpreq == HTTPREQ_POST_MIME) && !(data->set.keep_post & CURL_REDIR_POST_301)) { infof(data, "Switch from POST to GET\n"); data->set.httpreq = HTTPREQ_GET; } break; case 302: /* Found */ /* (quote from RFC7231, section 6.4.3) * * Note: For historical reasons, a user agent MAY change the request * method from POST to GET for the subsequent request. If this * behavior is undesired, the 307 (Temporary Redirect) status code * can be used instead. * * ---- * * Many webservers expect this, so these servers often answers to a POST * request with an error page. To be sure that libcurl gets the page that * most user agents would get, libcurl has to force GET. * * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and * can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM || data->set.httpreq == HTTPREQ_POST_MIME) && !(data->set.keep_post & CURL_REDIR_POST_302)) { infof(data, "Switch from POST to GET\n"); data->set.httpreq = HTTPREQ_GET; } break; case 303: /* See Other */ /* Disable both types of POSTs, unless the user explicitly asks for POST after POST */ if(data->set.httpreq != HTTPREQ_GET && !(data->set.keep_post & CURL_REDIR_POST_303)) { data->set.httpreq = HTTPREQ_GET; /* enforce GET request */ infof(data, "Disables POST, goes with %s\n", data->set.opt_no_body?"HEAD":"GET"); } break; case 304: /* Not Modified */ /* 304 means we did a conditional request and it was "Not modified". * We shouldn't get any Location: header in this response! */ break; case 305: /* Use Proxy */ /* (quote from RFC2616, section 10.3.6): * "The requested resource MUST be accessed through the proxy given * by the Location field. The Location field gives the URI of the * proxy. The recipient is expected to repeat this single request * via the proxy. 305 responses MUST only be generated by origin * servers." */ break; } Curl_pgrsTime(data, TIMER_REDIRECT); Curl_pgrsResetTransferSizes(data); return CURLE_OK; #endif /* CURL_DISABLE_HTTP */ } /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. NOTE: that the *url is malloc()ed. */ CURLcode Curl_retry_request(struct connectdata *conn, char **url) { struct Curl_easy *data = conn->data; bool retry = FALSE; *url = NULL; /* if we're talking upload, we can't do the checks below, unless the protocol is HTTP as when uploading over HTTP we will still get a response */ if(data->set.upload && !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) return CURLE_OK; if((data->req.bytecount + data->req.headerbytecount == 0) && conn->bits.reuse && (!data->set.opt_no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP)) && (data->set.rtspreq != RTSPREQ_RECEIVE)) /* We got no data, we attempted to re-use a connection. For HTTP this can be a retry so we try again regardless if we expected a body. For other protocols we only try again only if we expected a body. This might happen if the connection was left alive when we were done using it before, but that was closed when we wanted to read from it again. Bad luck. Retry the same request on a fresh connect! */ retry = TRUE; else if(data->state.refused_stream && (data->req.bytecount + data->req.headerbytecount == 0) ) { /* This was sent on a refused stream, safe to rerun. A refused stream error can typically only happen on HTTP/2 level if the stream is safe to issue again, but the nghttp2 API can deliver the message to other streams as well, which is why this adds the check the data counters too. */ infof(conn->data, "REFUSED_STREAM, retrying a fresh connect\n"); data->state.refused_stream = FALSE; /* clear again */ retry = TRUE; } if(retry) { infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) return CURLE_OUT_OF_MEMORY; connclose(conn, "retry"); /* close this connection */ conn->bits.retry = TRUE; /* mark this as a connection we're about to retry. Marking it this way should prevent i.e HTTP transfers to return error just because nothing has been transferred! */ if(conn->handler->protocol&PROTO_FAMILY_HTTP) { if(data->req.writebytecount) { CURLcode result = Curl_readrewind(conn); if(result) { Curl_safefree(*url); return result; } } } } return CURLE_OK; } /* * Curl_setup_transfer() is called to setup some basic properties for the * upcoming transfer. */ void Curl_setup_transfer( struct Curl_easy *data, /* transfer */ int sockindex, /* socket index to read from or -1 */ curl_off_t size, /* -1 if unknown at this point */ bool getheader, /* TRUE if header parsing is wanted */ int writesockindex /* socket index to write to, it may very well be the same we read from. -1 disables */ ) { struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; DEBUGASSERT(conn != NULL); DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); if(conn->bits.multiplex || conn->httpversion == 20) { /* when multiplexing, the read/write sockets need to be the same! */ conn->sockfd = sockindex == -1 ? ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : conn->sock[sockindex]; conn->writesockfd = conn->sockfd; } else { conn->sockfd = sockindex == -1 ? CURL_SOCKET_BAD : conn->sock[sockindex]; conn->writesockfd = writesockindex == -1 ? CURL_SOCKET_BAD:conn->sock[writesockindex]; } k->getheader = getheader; k->size = size; /* The code sequence below is placed in this function just because all necessary input is not always known in do_complete() as this function may be called after that */ if(!k->getheader) { k->header = FALSE; if(size > 0) Curl_pgrsSetDownloadSize(data, size); } /* we want header and/or body, if neither then don't do this! */ if(k->getheader || !data->set.opt_no_body) { if(sockindex != -1) k->keepon |= KEEP_RECV; if(writesockindex != -1) { struct HTTP *http = data->req.protop; /* HTTP 1.1 magic: Even if we require a 100-return code before uploading data, we might need to write data before that since the REQUEST may not have been finished sent off just yet. Thus, we must check if the request has been sent before we set the state info where we wait for the 100-return code */ if((data->state.expect100header) && (conn->handler->protocol&PROTO_FAMILY_HTTP) && (http->sending == HTTPSEND_BODY)) { /* wait with write until we either got 100-continue or a timeout */ k->exp100 = EXP100_AWAITING_CONTINUE; k->start100 = Curl_now(); /* Set a timeout for the multi interface. Add the inaccuracy margin so that we don't fire slightly too early and get denied to run. */ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); } else { if(data->state.expect100header) /* when we've sent off the rest of the headers, we must await a 100-continue but first finish sending the request */ k->exp100 = EXP100_SENDING_REQUEST; /* enable the write bit when we're not waiting for continue */ k->keepon |= KEEP_SEND; } } /* if(writesockindex != -1) */ } /* if(k->getheader || !data->set.opt_no_body) */ } davix-0.8.0/deps/curl/lib/http_proxy.h0000644000000000000000000000361614121063461016373 0ustar rootroot#ifndef HEADER_CURL_HTTP_PROXY_H #define HEADER_CURL_HTTP_PROXY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP) /* ftp can use this as well */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int tunnelsocket, const char *hostname, int remote_port); /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex); bool Curl_connect_complete(struct connectdata *conn); bool Curl_connect_ongoing(struct connectdata *conn); #else #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN #define Curl_proxy_connect(x,y) CURLE_OK #define Curl_connect_complete(x) CURLE_OK #define Curl_connect_ongoing(x) FALSE #endif void Curl_connect_free(struct Curl_easy *data); #endif /* HEADER_CURL_HTTP_PROXY_H */ davix-0.8.0/deps/curl/lib/curl_memrchr.h0000644000000000000000000000262314121063461016632 0ustar rootroot#ifndef HEADER_CURL_MEMRCHR_H #define HEADER_CURL_MEMRCHR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_MEMRCHR #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #else /* HAVE_MEMRCHR */ void *Curl_memrchr(const void *s, int c, size_t n); #define memrchr(x,y,z) Curl_memrchr((x),(y),(z)) #endif /* HAVE_MEMRCHR */ #endif /* HEADER_CURL_MEMRCHR_H */ davix-0.8.0/deps/curl/lib/krb5.c0000644000000000000000000002317614121063461015014 0ustar rootroot/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c * * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * Copyright (c) 2004 - 2019 Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "curl_setup.h" #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) #ifdef HAVE_NETDB_H #include #endif #include "urldata.h" #include "curl_base64.h" #include "ftp.h" #include "curl_gssapi.h" #include "sendf.h" #include "curl_sec.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static int krb5_init(void *app_data) { gss_ctx_id_t *context = app_data; /* Make sure our context is initialized for krb5_end. */ *context = GSS_C_NO_CONTEXT; return 0; } static int krb5_check_prot(void *app_data, int level) { (void)app_data; /* unused */ if(level == PROT_CONFIDENTIAL) return -1; return 0; } static int krb5_decode(void *app_data, void *buf, int len, int level UNUSED_PARAM, struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; gss_buffer_desc enc, dec; (void)level; (void)conn; enc.value = buf; enc.length = len; maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); if(maj != GSS_S_COMPLETE) { if(len >= 4) strcpy(buf, "599 "); return -1; } memcpy(buf, dec.value, dec.length); len = curlx_uztosi(dec.length); gss_release_buffer(&min, &dec); return len; } static int krb5_overhead(void *app_data, int level, int len) { /* no arguments are used */ (void)app_data; (void)level; (void)len; return 0; } static int krb5_encode(void *app_data, const void *from, int length, int level, void **to) { gss_ctx_id_t *context = app_data; gss_buffer_desc dec, enc; OM_uint32 maj, min; int state; int len; /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal * libraries modify the input buffer in gss_wrap() */ dec.value = (void *)from; dec.length = length; maj = gss_wrap(&min, *context, level == PROT_PRIVATE, GSS_C_QOP_DEFAULT, &dec, &state, &enc); if(maj != GSS_S_COMPLETE) return -1; /* malloc a new buffer, in case gss_release_buffer doesn't work as expected */ *to = malloc(enc.length); if(!*to) return -1; memcpy(*to, enc.value, enc.length); len = curlx_uztosi(enc.length); gss_release_buffer(&min, &enc); return len; } static int krb5_auth(void *app_data, struct connectdata *conn) { int ret = AUTH_OK; char *p; const char *host = conn->host.name; ssize_t nread; curl_socklen_t l = sizeof(conn->local_addr); struct Curl_easy *data = conn->data; CURLcode result; const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : "ftp"; const char *srv_host = "host"; gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; OM_uint32 maj, min; gss_name_t gssname; gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; size_t base64_sz = 0; struct sockaddr_in **remote_addr = (struct sockaddr_in **)&conn->ip_addr->ai_addr; char *stringp; if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&conn->local_addr, &l) < 0) perror("getsockname()"); chan.initiator_addrtype = GSS_C_AF_INET; chan.initiator_address.length = l - 4; chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; chan.acceptor_addrtype = GSS_C_AF_INET; chan.acceptor_address.length = l - 4; chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr; chan.application_data.length = 0; chan.application_data.value = NULL; /* this loop will execute twice (once for service, once for host) */ for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsend(conn, "AUTH GSSAPI"); if(result) return -2; if(Curl_GetFTPResponse(&nread, conn, NULL)) return -1; if(data->state.buffer[0] != '3') return -1; } stringp = aprintf("%s@%s", service, host); if(!stringp) return -2; input_buffer.value = stringp; input_buffer.length = strlen(stringp); maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, &gssname); free(stringp); if(maj != GSS_S_COMPLETE) { gss_release_name(&min, &gssname); if(service == srv_host) { failf(data, "Error importing service name %s@%s", service, host); return AUTH_ERROR; } service = srv_host; continue; } /* We pass NULL as |output_name_type| to avoid a leak. */ gss_display_name(&min, gssname, &output_buffer, NULL); Curl_infof(data, "Trying against %s\n", output_buffer.value); gssresp = GSS_C_NO_BUFFER; *context = GSS_C_NO_CONTEXT; do { /* Release the buffer at each iteration to avoid leaking: the first time we are releasing the memory from gss_display_name. The last item is taken care by a final gss_release_buffer. */ gss_release_buffer(&min, &output_buffer); ret = AUTH_OK; maj = Curl_gss_init_sec_context(data, &min, context, gssname, &Curl_krb5_mech_oid, &chan, gssresp, &output_buffer, TRUE, NULL); if(gssresp) { free(_gssresp.value); gssresp = NULL; } if(GSS_ERROR(maj)) { Curl_infof(data, "Error creating security context\n"); ret = AUTH_ERROR; break; } if(output_buffer.length != 0) { char *cmd; result = Curl_base64_encode(data, (char *)output_buffer.value, output_buffer.length, &p, &base64_sz); if(result) { Curl_infof(data, "base64-encoding: %s\n", curl_easy_strerror(result)); ret = AUTH_ERROR; break; } cmd = aprintf("ADAT %s", p); if(cmd) result = Curl_ftpsend(conn, cmd); else result = CURLE_OUT_OF_MEMORY; free(p); free(cmd); if(result) { ret = -2; break; } if(Curl_GetFTPResponse(&nread, conn, NULL)) { ret = -1; break; } if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { Curl_infof(data, "Server didn't accept auth data\n"); ret = AUTH_ERROR; break; } _gssresp.value = NULL; /* make sure it is initialized */ p = data->state.buffer + 4; p = strstr(p, "ADAT="); if(p) { result = Curl_base64_decode(p + 5, (unsigned char **)&_gssresp.value, &_gssresp.length); if(result) { failf(data, "base64-decoding: %s", curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } } gssresp = &_gssresp; } } while(maj == GSS_S_CONTINUE_NEEDED); gss_release_name(&min, &gssname); gss_release_buffer(&min, &output_buffer); if(gssresp) free(_gssresp.value); if(ret == AUTH_OK || service == srv_host) return ret; service = srv_host; } return ret; } static void krb5_end(void *app_data) { OM_uint32 min; gss_ctx_id_t *context = app_data; if(*context != GSS_C_NO_CONTEXT) { OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); (void)maj; DEBUGASSERT(maj == GSS_S_COMPLETE); } } struct Curl_sec_client_mech Curl_krb5_client_mech = { "GSSAPI", sizeof(gss_ctx_id_t), krb5_init, krb5_auth, krb5_end, krb5_check_prot, krb5_overhead, krb5_encode, krb5_decode }; #endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ davix-0.8.0/deps/curl/lib/http.c0000644000000000000000000041053014121063461015122 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_HTTP #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include "urldata.h" #include #include "transfer.h" #include "sendf.h" #include "formdata.h" #include "mime.h" #include "progress.h" #include "curl_base64.h" #include "cookie.h" #include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" #include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" #include "share.h" #include "hostip.h" #include "http.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" #include "multiif.h" #include "strcase.h" #include "content_encoding.h" #include "http_proxy.h" #include "warnless.h" #include "non-ascii.h" #include "http2.h" #include "connect.h" #include "strdup.h" #include "altsvc.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Forward declarations. */ static int http_getsock_do(struct connectdata *conn, curl_socket_t *socks); static int http_should_fail(struct connectdata *conn); #ifndef CURL_DISABLE_PROXY static CURLcode add_haproxy_protocol_header(struct connectdata *conn); #endif #ifdef USE_SSL static CURLcode https_connecting(struct connectdata *conn, bool *done); static int https_getsock(struct connectdata *conn, curl_socket_t *socks); #else #define https_connecting(x,y) CURLE_COULDNT_CONNECT #endif static CURLcode http_setup_conn(struct connectdata *conn); /* * HTTP handler interface. */ const struct Curl_handler Curl_handler_http = { "HTTP", /* scheme */ http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ Curl_http_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ http_getsock_do, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_CREDSPERREQUEST /* flags */ }; #ifdef USE_SSL /* * HTTPS handler interface. */ const struct Curl_handler Curl_handler_https = { "HTTPS", /* scheme */ http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ Curl_http_connect, /* connect_it */ https_connecting, /* connecting */ ZERO_NULL, /* doing */ https_getsock, /* proto_getsock */ http_getsock_do, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ }; #endif static CURLcode http_setup_conn(struct connectdata *conn) { /* allocate the HTTP-specific struct for the Curl_easy, only to survive during this request */ struct HTTP *http; struct Curl_easy *data = conn->data; DEBUGASSERT(data->req.protop == NULL); http = calloc(1, sizeof(struct HTTP)); if(!http) return CURLE_OUT_OF_MEMORY; Curl_mime_initpart(&http->form, conn->data); data->req.protop = http; if(data->set.httpversion == CURL_HTTP_VERSION_3) { if(conn->handler->flags & PROTOPT_SSL) /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does the QUIC dance. */ conn->transport = TRNSPRT_QUIC; else { failf(data, "HTTP/3 requested for non-HTTPS URL"); return CURLE_URL_MALFORMAT; } } else { if(!CONN_INUSE(conn)) /* if not already multi-using, setup connection details */ Curl_http2_setup_conn(conn); Curl_http2_setup_req(data); } return CURLE_OK; } #ifndef CURL_DISABLE_PROXY /* * checkProxyHeaders() checks the linked list of custom proxy headers * if proxy headers are not available, then it will lookup into http header * link list * * It takes a connectdata struct as input instead of the Curl_easy simply to * know if this is a proxy request or not, as it then might check a different * header list. Provide the header prefix without colon!. */ char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); struct Curl_easy *data = conn->data; for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; head; head = head->next) { if(strncasecompare(head->data, thisheader, thislen) && Curl_headersep(head->data[thislen])) return head->data; } return NULL; } #else /* disabled */ #define Curl_checkProxyheaders(x,y) NULL #endif /* * Strip off leading and trailing whitespace from the value in the * given HTTP header line and return a strdupped copy. Returns NULL in * case of allocation failure. Returns an empty string if the header value * consists entirely of whitespace. */ char *Curl_copy_header_value(const char *header) { const char *start; const char *end; char *value; size_t len; /* Find the end of the header name */ while(*header && (*header != ':')) ++header; if(*header) /* Skip over colon */ ++header; /* Find the first non-space letter */ start = header; while(*start && ISSPACE(*start)) start++; /* data is in the host encoding so use '\r' and '\n' instead of 0x0d and 0x0a */ end = strchr(start, '\r'); if(!end) end = strchr(start, '\n'); if(!end) end = strchr(start, '\0'); if(!end) return NULL; /* skip all trailing space letters */ while((end > start) && ISSPACE(*end)) end--; /* get length of the type */ len = end - start + 1; value = malloc(len + 1); if(!value) return NULL; memcpy(value, start, len); value[len] = 0; /* zero terminate */ return value; } #ifndef CURL_DISABLE_HTTP_AUTH /* * http_output_basic() sets up an Authorization: header (or the proxy version) * for HTTP Basic authentication. * * Returns CURLcode. */ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { size_t size = 0; char *authorization = NULL; struct Curl_easy *data = conn->data; char **userp; const char *user; const char *pwd; CURLcode result; char *out; if(proxy) { userp = &conn->allocptr.proxyuserpwd; user = conn->http_proxy.user; pwd = conn->http_proxy.passwd; } else { userp = &conn->allocptr.userpwd; user = conn->user; pwd = conn->passwd; } out = aprintf("%s:%s", user, pwd); if(!out) return CURLE_OUT_OF_MEMORY; result = Curl_base64_encode(data, out, strlen(out), &authorization, &size); if(result) goto fail; if(!authorization) { result = CURLE_REMOTE_ACCESS_DENIED; goto fail; } free(*userp); *userp = aprintf("%sAuthorization: Basic %s\r\n", proxy ? "Proxy-" : "", authorization); free(authorization); if(!*userp) { result = CURLE_OUT_OF_MEMORY; goto fail; } fail: free(out); return result; } /* * http_output_bearer() sets up an Authorization: header * for HTTP Bearer authentication. * * Returns CURLcode. */ static CURLcode http_output_bearer(struct connectdata *conn) { char **userp; CURLcode result = CURLE_OK; userp = &conn->allocptr.userpwd; free(*userp); *userp = aprintf("Authorization: Bearer %s\r\n", conn->data->set.str[STRING_BEARER]); if(!*userp) { result = CURLE_OUT_OF_MEMORY; goto fail; } fail: return result; } #endif /* pickoneauth() selects the most favourable authentication method from the * ones available and the ones we want. * * return TRUE if one was picked */ static bool pickoneauth(struct auth *pick, unsigned long mask) { bool picked; /* only deal with authentication we want */ unsigned long avail = pick->avail & pick->want & mask; picked = TRUE; /* The order of these checks is highly relevant, as this will be the order of preference in case of the existence of multiple accepted types. */ if(avail & CURLAUTH_NEGOTIATE) pick->picked = CURLAUTH_NEGOTIATE; else if(avail & CURLAUTH_BEARER) pick->picked = CURLAUTH_BEARER; else if(avail & CURLAUTH_DIGEST) pick->picked = CURLAUTH_DIGEST; else if(avail & CURLAUTH_NTLM) pick->picked = CURLAUTH_NTLM; else if(avail & CURLAUTH_NTLM_WB) pick->picked = CURLAUTH_NTLM_WB; else if(avail & CURLAUTH_BASIC) pick->picked = CURLAUTH_BASIC; else { pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ picked = FALSE; } pick->avail = CURLAUTH_NONE; /* clear it here */ return picked; } /* * http_perhapsrewind() * * If we are doing POST or PUT { * If we have more data to send { * If we are doing NTLM { * Keep sending since we must not disconnect * } * else { * If there is more than just a little data left to send, close * the current connection by force. * } * } * If we have sent any data { * If we don't have track of all the data { * call app to tell it to rewind * } * else { * rewind internally so that the operation can restart fine * } * } * } */ static CURLcode http_perhapsrewind(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; curl_off_t bytessent; curl_off_t expectsend = -1; /* default is unknown */ if(!http) /* If this is still NULL, we have not reach very far and we can safely skip this rewinding stuff */ return CURLE_OK; switch(data->set.httpreq) { case HTTPREQ_GET: case HTTPREQ_HEAD: return CURLE_OK; default: break; } bytessent = data->req.writebytecount; if(conn->bits.authneg) { /* This is a state where we are known to be negotiating and we don't send any data then. */ expectsend = 0; } else if(!conn->bits.protoconnstart) { /* HTTP CONNECT in progress: there is no body */ expectsend = 0; } else { /* figure out how much data we are expected to send */ switch(data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_PUT: if(data->state.infilesize != -1) expectsend = data->state.infilesize; break; case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: expectsend = http->postsize; break; default: break; } } conn->bits.rewindaftersend = FALSE; /* default */ if((expectsend == -1) || (expectsend > bytessent)) { #if defined(USE_NTLM) /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NTLM) || (data->state.authhost.picked == CURLAUTH_NTLM) || (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { if(((expectsend - bytessent) < 2000) || (conn->http_ntlm_state != NTLMSTATE_NONE) || (conn->proxy_ntlm_state != NTLMSTATE_NONE)) { /* The NTLM-negotiation has started *OR* there is just a little (<2K) data left to send, keep on sending. */ /* rewind data when completely done sending! */ if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { conn->bits.rewindaftersend = TRUE; infof(data, "Rewind stream after send\n"); } return CURLE_OK; } if(conn->bits.close) /* this is already marked to get closed */ return CURLE_OK; infof(data, "NTLM send, close instead of sending %" CURL_FORMAT_CURL_OFF_T " bytes\n", (curl_off_t)(expectsend - bytessent)); } #endif #if defined(USE_SPNEGO) /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) || (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) { if(((expectsend - bytessent) < 2000) || (conn->http_negotiate_state != GSS_AUTHNONE) || (conn->proxy_negotiate_state != GSS_AUTHNONE)) { /* The NEGOTIATE-negotiation has started *OR* there is just a little (<2K) data left to send, keep on sending. */ /* rewind data when completely done sending! */ if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { conn->bits.rewindaftersend = TRUE; infof(data, "Rewind stream after send\n"); } return CURLE_OK; } if(conn->bits.close) /* this is already marked to get closed */ return CURLE_OK; infof(data, "NEGOTIATE send, close instead of sending %" CURL_FORMAT_CURL_OFF_T " bytes\n", (curl_off_t)(expectsend - bytessent)); } #endif /* This is not NEGOTIATE/NTLM or many bytes left to send: close */ streamclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ /* There still is data left to send, but this connection is marked for closure so we can safely do the rewind right now */ } if(bytessent) /* we rewind now at once since if we already sent something */ return Curl_readrewind(conn); return CURLE_OK; } /* * Curl_http_auth_act() gets called when all HTTP headers have been received * and it checks what authentication methods that are available and decides * which one (if any) to use. It will set 'newurl' if an auth method was * picked. */ CURLcode Curl_http_auth_act(struct connectdata *conn) { struct Curl_easy *data = conn->data; bool pickhost = FALSE; bool pickproxy = FALSE; CURLcode result = CURLE_OK; unsigned long authmask = ~0ul; if(!data->set.str[STRING_BEARER]) authmask &= (unsigned long)~CURLAUTH_BEARER; if(100 <= data->req.httpcode && 199 >= data->req.httpcode) /* this is a transient response code, ignore */ return CURLE_OK; if(data->state.authproblem) return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; if((conn->bits.user_passwd || data->set.str[STRING_BEARER]) && ((data->req.httpcode == 401) || (conn->bits.authneg && data->req.httpcode < 300))) { pickhost = pickoneauth(&data->state.authhost, authmask); if(!pickhost) data->state.authproblem = TRUE; if(data->state.authhost.picked == CURLAUTH_NTLM && conn->httpversion > 11) { infof(data, "Forcing HTTP/1.1 for NTLM"); connclose(conn, "Force HTTP/1.1 connection"); conn->data->set.httpversion = CURL_HTTP_VERSION_1_1; } } if(conn->bits.proxy_user_passwd && ((data->req.httpcode == 407) || (conn->bits.authneg && data->req.httpcode < 300))) { pickproxy = pickoneauth(&data->state.authproxy, authmask & ~CURLAUTH_BEARER); if(!pickproxy) data->state.authproblem = TRUE; } if(pickhost || pickproxy) { if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD) && !conn->bits.rewindaftersend) { result = http_perhapsrewind(conn); if(result) return result; } /* In case this is GSS auth, the newurl field is already allocated so we must make sure to free it before allocating a new one. As figured out in bug #2284386 */ Curl_safefree(data->req.newurl); data->req.newurl = strdup(data->change.url); /* clone URL */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; } else if((data->req.httpcode < 300) && (!data->state.authhost.done) && conn->bits.authneg) { /* no (known) authentication available, authentication is not "done" yet and no authentication seems to be required and we didn't try HEAD or GET */ if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD)) { data->req.newurl = strdup(data->change.url); /* clone URL */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; data->state.authhost.done = TRUE; } } if(http_should_fail(conn)) { failf(data, "The requested URL returned error: %d", data->req.httpcode); result = CURLE_HTTP_RETURNED_ERROR; } return result; } #ifndef CURL_DISABLE_HTTP_AUTH /* * Output the correct authentication header depending on the auth type * and whether or not it is to a proxy. */ static CURLcode output_auth_headers(struct connectdata *conn, struct auth *authstatus, const char *request, const char *path, bool proxy) { const char *auth = NULL; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; #ifdef CURL_DISABLE_CRYPTO_AUTH (void)request; (void)path; #endif #ifdef USE_SPNEGO if(authstatus->picked == CURLAUTH_NEGOTIATE) { auth = "Negotiate"; result = Curl_output_negotiate(conn, proxy); if(result) return result; } else #endif #ifdef USE_NTLM if(authstatus->picked == CURLAUTH_NTLM) { auth = "NTLM"; result = Curl_output_ntlm(conn, proxy); if(result) return result; } else #endif #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) if(authstatus->picked == CURLAUTH_NTLM_WB) { auth = "NTLM_WB"; result = Curl_output_ntlm_wb(conn, proxy); if(result) return result; } else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { auth = "Digest"; result = Curl_output_digest(conn, proxy, (const unsigned char *)request, (const unsigned char *)path); if(result) return result; } else #endif if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ if((proxy && conn->bits.proxy_user_passwd && !Curl_checkProxyheaders(conn, "Proxy-authorization")) || (!proxy && conn->bits.user_passwd && !Curl_checkheaders(conn, "Authorization"))) { auth = "Basic"; result = http_output_basic(conn, proxy); if(result) return result; } /* NOTE: this function should set 'done' TRUE, as the other auth functions work that way */ authstatus->done = TRUE; } if(authstatus->picked == CURLAUTH_BEARER) { /* Bearer */ if((!proxy && data->set.str[STRING_BEARER] && !Curl_checkheaders(conn, "Authorization:"))) { auth = "Bearer"; result = http_output_bearer(conn); if(result) return result; } /* NOTE: this function should set 'done' TRUE, as the other auth functions work that way */ authstatus->done = TRUE; } if(auth) { infof(data, "%s auth using %s with user '%s'\n", proxy ? "Proxy" : "Server", auth, proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : (conn->user ? conn->user : "")); authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; } else authstatus->multipass = FALSE; return CURLE_OK; } /** * Curl_http_output_auth() setups the authentication headers for the * host/proxy and the correct authentication * method. conn->data->state.authdone is set to TRUE when authentication is * done. * * @param conn all information about the current connection * @param request pointer to the request keyword * @param path pointer to the requested path; should include query part * @param proxytunnel boolean if this is the request setting up a "proxy * tunnel" * * @returns CURLcode */ CURLcode Curl_http_output_auth(struct connectdata *conn, const char *request, const char *path, bool proxytunnel) /* TRUE if this is the request setting up the proxy tunnel */ { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct auth *authhost; struct auth *authproxy; DEBUGASSERT(data); authhost = &data->state.authhost; authproxy = &data->state.authproxy; if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || conn->bits.user_passwd || data->set.str[STRING_BEARER]) /* continue please */; else { authhost->done = TRUE; authproxy->done = TRUE; return CURLE_OK; /* no authentication with no user or password */ } if(authhost->want && !authhost->picked) /* The app has selected one or more methods, but none has been picked so far by a server round-trip. Then we set the picked one to the want one, and if this is one single bit it'll be used instantly. */ authhost->picked = authhost->want; if(authproxy->want && !authproxy->picked) /* The app has selected one or more methods, but none has been picked so far by a proxy round-trip. Then we set the picked one to the want one, and if this is one single bit it'll be used instantly. */ authproxy->picked = authproxy->want; #ifndef CURL_DISABLE_PROXY /* Send proxy authentication header if needed */ if(conn->bits.httpproxy && (conn->bits.tunnel_proxy == (bit)proxytunnel)) { result = output_auth_headers(conn, authproxy, request, path, TRUE); if(result) return result; } else #else (void)proxytunnel; #endif /* CURL_DISABLE_PROXY */ /* we have no proxy so let's pretend we're done authenticating with it */ authproxy->done = TRUE; /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || conn->bits.netrc || !data->state.first_host || data->set.allow_auth_to_other_hosts || strcasecompare(data->state.first_host, conn->host.name)) { result = output_auth_headers(conn, authhost, request, path, FALSE); } else authhost->done = TRUE; return result; } #else /* when disabled */ CURLcode Curl_http_output_auth(struct connectdata *conn, const char *request, const char *path, bool proxytunnel) { (void)conn; (void)request; (void)path; (void)proxytunnel; return CURLE_OK; } #endif /* * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the * proxy CONNECT loop. */ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, const char *auth) /* the first non-space */ { /* * This resource requires authentication */ struct Curl_easy *data = conn->data; #ifdef USE_SPNEGO curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state : &conn->http_negotiate_state; #endif unsigned long *availp; struct auth *authp; if(proxy) { availp = &data->info.proxyauthavail; authp = &data->state.authproxy; } else { availp = &data->info.httpauthavail; authp = &data->state.authhost; } /* * Here we check if we want the specific single authentication (using ==) and * if we do, we initiate usage of it. * * If the provided authentication is wanted as one out of several accepted * types (using &), we OR this authentication type to the authavail * variable. * * Note: * * ->picked is first set to the 'want' value (one or more bits) before the * request is sent, and then it is again set _after_ all response 401/407 * headers have been received but then only to a single preferred method * (bit). */ while(*auth) { #ifdef USE_SPNEGO if(checkprefix("Negotiate", auth)) { if((authp->avail & CURLAUTH_NEGOTIATE) || Curl_auth_is_spnego_supported()) { *availp |= CURLAUTH_NEGOTIATE; authp->avail |= CURLAUTH_NEGOTIATE; if(authp->picked == CURLAUTH_NEGOTIATE) { CURLcode result = Curl_input_negotiate(conn, proxy, auth); if(!result) { DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->change.url); if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; data->state.authproblem = FALSE; /* we received a GSS auth token and we dealt with it fine */ *negstate = GSS_AUTHRECV; } else data->state.authproblem = TRUE; } } } else #endif #ifdef USE_NTLM /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", auth)) { if((authp->avail & CURLAUTH_NTLM) || (authp->avail & CURLAUTH_NTLM_WB) || Curl_auth_is_ntlm_supported()) { *availp |= CURLAUTH_NTLM; authp->avail |= CURLAUTH_NTLM; if(authp->picked == CURLAUTH_NTLM || authp->picked == CURLAUTH_NTLM_WB) { /* NTLM authentication is picked and activated */ CURLcode result = Curl_input_ntlm(conn, proxy, auth); if(!result) { data->state.authproblem = FALSE; #ifdef NTLM_WB_ENABLED if(authp->picked == CURLAUTH_NTLM_WB) { *availp &= ~CURLAUTH_NTLM; authp->avail &= ~CURLAUTH_NTLM; *availp |= CURLAUTH_NTLM_WB; authp->avail |= CURLAUTH_NTLM_WB; result = Curl_input_ntlm_wb(conn, proxy, auth); if(result) { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } #endif } else { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } } } else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(checkprefix("Digest", auth)) { if((authp->avail & CURLAUTH_DIGEST) != 0) infof(data, "Ignoring duplicate digest auth header.\n"); else if(Curl_auth_is_digest_supported()) { CURLcode result; *availp |= CURLAUTH_DIGEST; authp->avail |= CURLAUTH_DIGEST; /* We call this function on input Digest headers even if Digest * authentication isn't activated yet, as we need to store the * incoming data from this header in case we are going to use * Digest */ result = Curl_input_digest(conn, proxy, auth); if(result) { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } } else #endif if(checkprefix("Basic", auth)) { *availp |= CURLAUTH_BASIC; authp->avail |= CURLAUTH_BASIC; if(authp->picked == CURLAUTH_BASIC) { /* We asked for Basic authentication but got a 40X back anyway, which basically means our name+password isn't valid. */ authp->avail = CURLAUTH_NONE; infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } else if(checkprefix("Bearer", auth)) { *availp |= CURLAUTH_BEARER; authp->avail |= CURLAUTH_BEARER; if(authp->picked == CURLAUTH_BEARER) { /* We asked for Bearer authentication but got a 40X back anyway, which basically means our token isn't valid. */ authp->avail = CURLAUTH_NONE; infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } /* there may be multiple methods on one line, so keep reading */ while(*auth && *auth != ',') /* read up to the next comma */ auth++; if(*auth == ',') /* if we're on a comma, skip it */ auth++; while(*auth && ISSPACE(*auth)) auth++; } return CURLE_OK; } /** * http_should_fail() determines whether an HTTP response has gotten us * into an error state or not. * * @param conn all information about the current connection * * @retval 0 communications should continue * * @retval 1 communications should not continue */ static int http_should_fail(struct connectdata *conn) { struct Curl_easy *data; int httpcode; DEBUGASSERT(conn); data = conn->data; DEBUGASSERT(data); httpcode = data->req.httpcode; /* ** If we haven't been asked to fail on error, ** don't fail. */ if(!data->set.http_fail_on_error) return 0; /* ** Any code < 400 is never terminal. */ if(httpcode < 400) return 0; /* ** Any code >= 400 that's not 401 or 407 is always ** a terminal error */ if((httpcode != 401) && (httpcode != 407)) return 1; /* ** All we have left to deal with is 401 and 407 */ DEBUGASSERT((httpcode == 401) || (httpcode == 407)); /* ** Examine the current authentication state to see if this ** is an error. The idea is for this function to get ** called after processing all the headers in a response ** message. So, if we've been to asked to authenticate a ** particular stage, and we've done it, we're OK. But, if ** we're already completely authenticated, it's not OK to ** get another 401 or 407. ** ** It is possible for authentication to go stale such that ** the client needs to reauthenticate. Once that info is ** available, use it here. */ /* ** Either we're not authenticating, or we're supposed to ** be authenticating something else. This is an error. */ if((httpcode == 401) && !conn->bits.user_passwd) return TRUE; if((httpcode == 407) && !conn->bits.proxy_user_passwd) return TRUE; return data->state.authproblem; } /* * readmoredata() is a "fread() emulation" to provide POST and/or request * data. It is used when a huge POST is to be made and the entire chunk wasn't * sent in the first send(). This function will then be called from the * transfer.c loop when more data is to be sent to the peer. * * Returns the amount of bytes it filled the buffer with. */ static size_t readmoredata(char *buffer, size_t size, size_t nitems, void *userp) { struct connectdata *conn = (struct connectdata *)userp; struct HTTP *http = conn->data->req.protop; size_t fullsize = size * nitems; if(!http->postsize) /* nothing to return */ return 0; /* make sure that a HTTP request is never sent away chunked! */ conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; if(http->postsize <= (curl_off_t)fullsize) { memcpy(buffer, http->postdata, (size_t)http->postsize); fullsize = (size_t)http->postsize; if(http->backup.postsize) { /* move backup data into focus and continue on that */ http->postdata = http->backup.postdata; http->postsize = http->backup.postsize; conn->data->state.fread_func = http->backup.fread_func; conn->data->state.in = http->backup.fread_in; http->sending++; /* move one step up */ http->backup.postsize = 0; } else http->postsize = 0; return fullsize; } memcpy(buffer, http->postdata, fullsize); http->postdata += fullsize; http->postsize -= fullsize; return fullsize; } /* ------------------------------------------------------------------------- */ /* add_buffer functions */ /* * Curl_add_buffer_init() sets up and returns a fine buffer struct */ Curl_send_buffer *Curl_add_buffer_init(void) { return calloc(1, sizeof(Curl_send_buffer)); } /* * Curl_add_buffer_free() frees all associated resources. */ void Curl_add_buffer_free(Curl_send_buffer **inp) { Curl_send_buffer *in; if(!inp) return; in = *inp; if(in) { /* deal with NULL input */ free(in->buffer); free(in); } *inp = NULL; } /* * Curl_add_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. * * Returns CURLcode */ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, struct connectdata *conn, /* add the number of sent bytes to this counter */ curl_off_t *bytes_written, /* how much of the buffer contains body data */ size_t included_body_bytes, int socketindex) { ssize_t amount; CURLcode result; char *ptr; size_t size; struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; size_t sendsize; curl_socket_t sockfd; size_t headersize; Curl_send_buffer *in = *inp; DEBUGASSERT(socketindex <= SECONDARYSOCKET); sockfd = conn->sock[socketindex]; /* The looping below is required since we use non-blocking sockets, but due to the circumstances we will just loop and try again and again etc */ ptr = in->buffer; size = in->size_used; headersize = size - included_body_bytes; /* the initial part that isn't body is header */ DEBUGASSERT(size > included_body_bytes); result = Curl_convert_to_network(data, ptr, headersize); /* Curl_convert_to_network calls failf if unsuccessful */ if(result) { /* conversion failed, free memory and return to the caller */ Curl_add_buffer_free(inp); return result; } if((conn->handler->flags & PROTOPT_SSL || conn->http_proxy.proxytype == CURLPROXY_HTTPS) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data needs to fit into the normal read-callback buffer later on and that buffer is using this size. */ sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE); /* OpenSSL is very picky and we must send the SAME buffer pointer to the library when we attempt to re-send this buffer. Sending the same data is not enough, we must use the exact same address. For this reason, we must copy the data to the uploadbuffer first, since that is the buffer we will be using if this send is retried later. */ result = Curl_get_upload_buffer(data); if(result) { /* malloc failed, free memory and return to the caller */ Curl_add_buffer_free(&in); return result; } memcpy(data->state.ulbuf, ptr, sendsize); ptr = data->state.ulbuf; } else sendsize = size; result = Curl_write(conn, sockfd, ptr, sendsize, &amount); if(!result) { /* * Note that we may not send the entire chunk at once, and we have a set * number of data bytes at the end of the big buffer (out of which we may * only send away a part). */ /* how much of the header that was sent */ size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; size_t bodylen = amount - headlen; if(data->set.verbose) { /* this data _may_ contain binary stuff */ Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen); if(bodylen) { /* there was body data sent beyond the initial header part, pass that on to the debug callback too */ Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen); } } /* 'amount' can never be a very large value here so typecasting it so a signed 31 bit value should not cause problems even if ssize_t is 64bit */ *bytes_written += (long)amount; if(http) { /* if we sent a piece of the body here, up the byte counter for it accordingly */ data->req.writebytecount += bodylen; Curl_pgrsSetUploadCounter(data, data->req.writebytecount); if((size_t)amount != size) { /* The whole request could not be sent in one system call. We must queue it up and send it later when we get the chance. We must not loop here and wait until it might work again. */ size -= amount; ptr = in->buffer + amount; /* backup the currently set pointers */ http->backup.fread_func = data->state.fread_func; http->backup.fread_in = data->state.in; http->backup.postdata = http->postdata; http->backup.postsize = http->postsize; /* set the new pointers for the request-sending */ data->state.fread_func = (curl_read_callback)readmoredata; data->state.in = (void *)conn; http->postdata = ptr; http->postsize = (curl_off_t)size; http->send_buffer = in; http->sending = HTTPSEND_REQUEST; return CURLE_OK; } http->sending = HTTPSEND_BODY; /* the full buffer was sent, clean up and return */ } else { if((size_t)amount != size) /* We have no continue-send mechanism now, fail. This can only happen when this function is used from the CONNECT sending function. We currently (stupidly) assume that the whole request is always sent away in the first single chunk. This needs FIXing. */ return CURLE_SEND_ERROR; } } Curl_add_buffer_free(&in); return result; } /* * add_bufferf() add the formatted input to the buffer. */ CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) { char *s; va_list ap; Curl_send_buffer *in = *inp; va_start(ap, fmt); s = vaprintf(fmt, ap); /* this allocs a new string to append */ va_end(ap); if(s) { CURLcode result = Curl_add_buffer(inp, s, strlen(s)); free(s); return result; } /* If we failed, we cleanup the whole buffer and return error */ free(in->buffer); free(in); *inp = NULL; return CURLE_OUT_OF_MEMORY; } /* * Curl_add_buffer() appends a memory chunk to the existing buffer */ CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, size_t size) { char *new_rb; Curl_send_buffer *in = *inp; if(~size < in->size_used) { /* If resulting used size of send buffer would wrap size_t, cleanup the whole buffer and return error. Otherwise the required buffer size will fit into a single allocatable memory chunk */ Curl_safefree(in->buffer); free(in); *inp = NULL; return CURLE_OUT_OF_MEMORY; } if(!in->buffer || ((in->size_used + size) > (in->size_max - 1))) { /* If current buffer size isn't enough to hold the result, use a buffer size that doubles the required size. If this new size would wrap size_t, then just use the largest possible one */ size_t new_size; if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || (~(size * 2) < (in->size_used * 2))) new_size = (size_t)-1; else new_size = (in->size_used + size) * 2; if(in->buffer) /* we have a buffer, enlarge the existing one */ new_rb = Curl_saferealloc(in->buffer, new_size); else /* create a new buffer */ new_rb = malloc(new_size); if(!new_rb) { /* If we failed, we cleanup the whole buffer and return error */ free(in); *inp = NULL; return CURLE_OUT_OF_MEMORY; } in->buffer = new_rb; in->size_max = new_size; } memcpy(&in->buffer[in->size_used], inptr, size); in->size_used += size; return CURLE_OK; } /* end of the add_buffer functions */ /* ------------------------------------------------------------------------- */ /* * Curl_compareheader() * * Returns TRUE if 'headerline' contains the 'header' with given 'content'. * Pass headers WITH the colon. */ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content) /* content string to find */ { /* RFC2616, section 4.2 says: "Each header field consists of a name followed * by a colon (":") and the field value. Field names are case-insensitive. * The field value MAY be preceded by any amount of LWS, though a single SP * is preferred." */ size_t hlen = strlen(header); size_t clen; size_t len; const char *start; const char *end; if(!strncasecompare(headerline, header, hlen)) return FALSE; /* doesn't start with header */ /* pass the header */ start = &headerline[hlen]; /* pass all white spaces */ while(*start && ISSPACE(*start)) start++; /* find the end of the header line */ end = strchr(start, '\r'); /* lines end with CRLF */ if(!end) { /* in case there's a non-standard compliant line here */ end = strchr(start, '\n'); if(!end) /* hm, there's no line ending here, use the zero byte! */ end = strchr(start, '\0'); } len = end-start; /* length of the content part of the input line */ clen = strlen(content); /* length of the word to find */ /* find the content string in the rest of the line */ for(; len >= clen; len--, start++) { if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } return FALSE; /* no match */ } /* * Curl_http_connect() performs HTTP stuff to do at connect-time, called from * the generic Curl_connect(). */ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) { CURLcode result; /* We default to persistent connections. We set this already in this connect function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "HTTP default"); /* the CONNECT procedure might not have been completed */ result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; if(conn->bits.proxy_connect_closed) /* this is not an error, just part of the connection negotiation */ return CURLE_OK; if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ if(Curl_connect_ongoing(conn)) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; #ifndef CURL_DISABLE_PROXY if(conn->data->set.haproxyprotocol) { /* add HAProxy PROXY protocol header */ result = add_haproxy_protocol_header(conn); if(result) return result; } #endif if(conn->given->protocol & CURLPROTO_HTTPS) { /* perform SSL initialization */ result = https_connecting(conn, done); if(result) return result; } else *done = TRUE; return CURLE_OK; } /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for the single socket to become writable only */ static int http_getsock_do(struct connectdata *conn, curl_socket_t *socks) { /* write mode */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_WRITESOCK(0); } #ifndef CURL_DISABLE_PROXY static CURLcode add_haproxy_protocol_header(struct connectdata *conn) { char proxy_header[128]; Curl_send_buffer *req_buffer; CURLcode result; char tcp_version[5]; /* Emit the correct prefix for IPv6 */ if(conn->bits.ipv6) { strcpy(tcp_version, "TCP6"); } else { strcpy(tcp_version, "TCP4"); } msnprintf(proxy_header, sizeof(proxy_header), "PROXY %s %s %s %li %li\r\n", tcp_version, conn->data->info.conn_local_ip, conn->data->info.conn_primary_ip, conn->data->info.conn_local_port, conn->data->info.conn_primary_port); req_buffer = Curl_add_buffer_init(); if(!req_buffer) return CURLE_OUT_OF_MEMORY; result = Curl_add_bufferf(&req_buffer, proxy_header); if(result) return result; result = Curl_add_buffer_send(&req_buffer, conn, &conn->data->info.request_size, 0, FIRSTSOCKET); return result; } #endif #ifdef USE_SSL static CURLcode https_connecting(struct connectdata *conn, bool *done) { CURLcode result; DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL)); #ifdef ENABLE_QUIC if(conn->transport == TRNSPRT_QUIC) { *done = TRUE; return CURLE_OK; } #endif /* perform SSL initialization for this socket */ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done); if(result) connclose(conn, "Failed HTTPS connection"); return result; } static int https_getsock(struct connectdata *conn, curl_socket_t *socks) { if(conn->handler->flags & PROTOPT_SSL) return Curl_ssl_getsock(conn, socks); return GETSOCK_BLANK; } #endif /* USE_SSL */ /* * Curl_http_done() gets called after a single HTTP request has been * performed. */ CURLcode Curl_http_done(struct connectdata *conn, CURLcode status, bool premature) { struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; /* Clear multipass flag. If authentication isn't done yet, then it will get * a chance to be set back to true when we output the next auth header */ data->state.authhost.multipass = FALSE; data->state.authproxy.multipass = FALSE; Curl_unencode_cleanup(conn); /* set the proper values (possibly modified on POST) */ conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ if(!http) return CURLE_OK; if(http->send_buffer) { Curl_add_buffer_free(&http->send_buffer); } Curl_http2_done(data, premature); Curl_quic_done(data, premature); Curl_mime_cleanpart(&http->form); if(status) return status; if(!premature && /* this check is pointless when DONE is called before the entire operation is complete */ !conn->bits.retry && !data->set.connect_only && (data->req.bytecount + data->req.headerbytecount - data->req.deductheadercount) <= 0) { /* If this connection isn't simply closed to be retried, AND nothing was read from the HTTP server (that counts), this can't be right so we return an error here */ failf(data, "Empty reply from server"); return CURLE_GOT_NOTHING; } return CURLE_OK; } /* * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons * to avoid it include: * * - if the user specifically requested HTTP 1.0 * - if the server we are connected to only supports 1.0 * - if any server previously contacted to handle this request only supports * 1.0. */ static bool use_http_1_1plus(const struct Curl_easy *data, const struct connectdata *conn) { if((data->state.httpversion == 10) || (conn->httpversion == 10)) return FALSE; if((data->set.httpversion == CURL_HTTP_VERSION_1_0) && (conn->httpversion <= 10)) return FALSE; return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) || (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); } static const char *get_http_string(const struct Curl_easy *data, const struct connectdata *conn) { #ifdef ENABLE_QUIC if((data->set.httpversion == CURL_HTTP_VERSION_3) || (conn->httpversion == 30)) return "3"; #endif #ifdef USE_NGHTTP2 if(conn->proto.httpc.h2) return "2"; #endif if(use_http_1_1plus(data, conn)) return "1.1"; return "1.0"; } /* check and possibly add an Expect: header */ static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, Curl_send_buffer *req_buffer) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ if(!data->state.disableexpect && use_http_1_1plus(data, conn) && (conn->httpversion < 20)) { /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an Expect: 100-continue to the headers which actually speeds up post operations (as there is one packet coming back from the web server) */ const char *ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } else { result = Curl_add_bufferf(&req_buffer, "Expect: 100-continue\r\n"); if(!result) data->state.expect100header = TRUE; } } return result; } enum proxy_use { HEADER_SERVER, /* direct to server */ HEADER_PROXY, /* regular request to proxy */ HEADER_CONNECT /* sending CONNECT to a proxy */ }; /* used to compile the provided trailers into one buffer will return an error code if one of the headers is not formatted correctly */ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, Curl_send_buffer **buffer, struct Curl_easy *handle) { char *ptr = NULL; CURLcode result = CURLE_OK; const char *endofline_native = NULL; const char *endofline_network = NULL; if( #ifdef CURL_DO_LINEEND_CONV (handle->set.prefer_ascii) || #endif (handle->set.crlf)) { /* \n will become \r\n later on */ endofline_native = "\n"; endofline_network = "\x0a"; } else { endofline_native = "\r\n"; endofline_network = "\x0d\x0a"; } while(trailers) { /* only add correctly formatted trailers */ ptr = strchr(trailers->data, ':'); if(ptr && *(ptr + 1) == ' ') { result = Curl_add_bufferf(buffer, "%s%s", trailers->data, endofline_native); if(result) return result; } else infof(handle, "Malformatted trailing header ! Skipping trailer."); trailers = trailers->next; } result = Curl_add_buffer(buffer, endofline_network, strlen(endofline_network)); return result; } CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, Curl_send_buffer *req_buffer) { char *ptr; struct curl_slist *h[2]; struct curl_slist *headers; int numlists = 1; /* by default */ struct Curl_easy *data = conn->data; int i; enum proxy_use proxy; if(is_connect) proxy = HEADER_CONNECT; else proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? HEADER_PROXY:HEADER_SERVER; switch(proxy) { case HEADER_SERVER: h[0] = data->set.headers; break; case HEADER_PROXY: h[0] = data->set.headers; if(data->set.sep_headers) { h[1] = data->set.proxyheaders; numlists++; } break; case HEADER_CONNECT: if(data->set.sep_headers) h[0] = data->set.proxyheaders; else h[0] = data->set.headers; break; } /* loop through one or two lists */ for(i = 0; i < numlists; i++) { headers = h[i]; while(headers) { char *semicolonp = NULL; ptr = strchr(headers->data, ':'); if(!ptr) { char *optr; /* no colon, semicolon? */ ptr = strchr(headers->data, ';'); if(ptr) { optr = ptr; ptr++; /* pass the semicolon */ while(*ptr && ISSPACE(*ptr)) ptr++; if(*ptr) { /* this may be used for something else in the future */ optr = NULL; } else { if(*(--ptr) == ';') { /* copy the source */ semicolonp = strdup(headers->data); if(!semicolonp) { Curl_add_buffer_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } /* put a colon where the semicolon is */ semicolonp[ptr - headers->data] = ':'; /* point at the colon */ optr = &semicolonp [ptr - headers->data]; } } ptr = optr; } } if(ptr) { /* we require a colon for this to be a true header */ ptr++; /* pass the colon */ while(*ptr && ISSPACE(*ptr)) ptr++; if(*ptr || semicolonp) { /* only send this if the contents was non-blank or done special */ CURLcode result = CURLE_OK; char *compare = semicolonp ? semicolonp : headers->data; if(conn->allocptr.host && /* a Host: header was sent already, don't pass on any custom Host: header as that will produce *two* in the same request! */ checkprefix("Host:", compare)) ; else if(data->set.httpreq == HTTPREQ_POST_FORM && /* this header (extended by formdata.c) is sent later */ checkprefix("Content-Type:", compare)) ; else if(data->set.httpreq == HTTPREQ_POST_MIME && /* this header is sent later */ checkprefix("Content-Type:", compare)) ; else if(conn->bits.authneg && /* while doing auth neg, don't allow the custom length since we will force length zero then */ checkprefix("Content-Length:", compare)) ; else if(conn->allocptr.te && /* when asking for Transfer-Encoding, don't pass on a custom Connection: */ checkprefix("Connection:", compare)) ; else if((conn->httpversion >= 20) && checkprefix("Transfer-Encoding:", compare)) /* HTTP/2 doesn't support chunked requests */ ; else if((checkprefix("Authorization:", compare) || checkprefix("Cookie:", compare)) && /* be careful of sending this potentially sensitive header to other hosts */ (data->state.this_is_a_follow && data->state.first_host && !data->set.allow_auth_to_other_hosts && !strcasecompare(data->state.first_host, conn->host.name))) ; else { result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); } if(semicolonp) free(semicolonp); if(result) return result; } } headers = headers->next; } } return CURLE_OK; } #ifndef CURL_DISABLE_PARSEDATE CURLcode Curl_add_timecondition(const struct connectdata *conn, Curl_send_buffer *req_buffer) { struct Curl_easy *data = conn->data; const struct tm *tm; struct tm keeptime; CURLcode result; char datestr[80]; const char *condp; if(data->set.timecondition == CURL_TIMECOND_NONE) /* no condition was asked for */ return CURLE_OK; result = Curl_gmtime(data->set.timevalue, &keeptime); if(result) { failf(data, "Invalid TIMEVALUE"); return result; } tm = &keeptime; switch(data->set.timecondition) { default: return CURLE_BAD_FUNCTION_ARGUMENT; case CURL_TIMECOND_IFMODSINCE: condp = "If-Modified-Since"; break; case CURL_TIMECOND_IFUNMODSINCE: condp = "If-Unmodified-Since"; break; case CURL_TIMECOND_LASTMOD: condp = "Last-Modified"; break; } if(Curl_checkheaders(conn, condp)) { /* A custom header was specified; it will be sent instead. */ return CURLE_OK; } /* The If-Modified-Since header family should have their times set in * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be * represented in Greenwich Mean Time (GMT), without exception. For the * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal * Time)." (see page 20 of RFC2616). */ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ msnprintf(datestr, sizeof(datestr), "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", condp, Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, Curl_month[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); return result; } #else /* disabled */ CURLcode Curl_add_timecondition(const struct connectdata *conn, Curl_send_buffer *req_buffer) { (void)conn; (void)req_buffer; return CURLE_OK; } #endif /* * Curl_http() gets called from the generic multi_do() function when a HTTP * request is to be performed. This creates and sends a properly constructed * HTTP request. */ CURLcode Curl_http(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct HTTP *http; const char *path = data->state.up.path; const char *query = data->state.up.query; bool paste_ftp_userpwd = FALSE; char ftp_typecode[sizeof("/;type=?")] = ""; const char *host = conn->host.name; const char *te = ""; /* transfer-encoding */ const char *ptr; const char *request; Curl_HttpReq httpreq = data->set.httpreq; #if !defined(CURL_DISABLE_COOKIES) char *addcookies = NULL; #endif curl_off_t included_body = 0; const char *httpstring; Curl_send_buffer *req_buffer; curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ char *altused = NULL; /* Always consider the DO phase done after this function call, even if there may be parts of the request that is not yet sent, since we can deal with the rest of the request in the PERFORM phase. */ *done = TRUE; if(conn->transport != TRNSPRT_QUIC) { if(conn->httpversion < 20) { /* unless the connection is re-used and already http2 */ switch(conn->negnpn) { case CURL_HTTP_VERSION_2: conn->httpversion = 20; /* we know we're on HTTP/2 now */ result = Curl_http2_switched(conn, NULL, 0); if(result) return result; break; case CURL_HTTP_VERSION_1_1: /* continue with HTTP/1.1 when explicitly requested */ break; default: /* Check if user wants to use HTTP/2 with clear TCP*/ #ifdef USE_NGHTTP2 if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* We don't support HTTP/2 proxies yet. Also it's debatable whether or not this setting should apply to HTTP/2 proxies. */ infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n"); break; } DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); conn->httpversion = 20; result = Curl_http2_switched(conn, NULL, 0); if(result) return result; } #endif break; } } else { /* prepare for a http2 request */ result = Curl_http2_setup(conn); if(result) return result; } } http = data->req.protop; DEBUGASSERT(http); if(!data->state.this_is_a_follow) { /* Free to avoid leaking memory on multiple requests*/ free(data->state.first_host); data->state.first_host = strdup(conn->host.name); if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; data->state.first_remote_port = conn->remote_port; } if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && data->set.upload) { httpreq = HTTPREQ_PUT; } /* Now set the 'request' pointer to the proper request string */ if(data->set.str[STRING_CUSTOMREQUEST]) request = data->set.str[STRING_CUSTOMREQUEST]; else { if(data->set.opt_no_body) request = "HEAD"; else { DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST)); switch(httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: request = "POST"; break; case HTTPREQ_PUT: request = "PUT"; break; case HTTPREQ_OPTIONS: request = "OPTIONS"; break; default: /* this should never happen */ case HTTPREQ_GET: request = "GET"; break; case HTTPREQ_HEAD: request = "HEAD"; break; } } } /* The User-Agent string might have been allocated in url.c already, because it might have been used in the proxy connect, but if we have got a header with the user-agent string specified, we erase the previously made string here. */ if(Curl_checkheaders(conn, "User-Agent")) { free(conn->allocptr.uagent); conn->allocptr.uagent = NULL; } /* setup the authentication headers */ { char *pq = NULL; if(query && *query) { pq = aprintf("%s?%s", path, query); if(!pq) return CURLE_OUT_OF_MEMORY; } result = Curl_http_output_auth(conn, request, (pq ? pq : path), FALSE); free(pq); if(result) return result; } if(((data->state.authhost.multipass && !data->state.authhost.done) || (data->state.authproxy.multipass && !data->state.authproxy.done)) && (httpreq != HTTPREQ_GET) && (httpreq != HTTPREQ_HEAD)) { /* Auth is required and we are not authenticated yet. Make a PUT or POST with content-length zero as a "probe". */ conn->bits.authneg = TRUE; } else conn->bits.authneg = FALSE; Curl_safefree(conn->allocptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer")) { conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); if(!conn->allocptr.ref) return CURLE_OUT_OF_MEMORY; } else conn->allocptr.ref = NULL; #if !defined(CURL_DISABLE_COOKIES) if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie")) addcookies = data->set.str[STRING_COOKIE]; #endif if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } else { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = NULL; } #ifdef HAVE_LIBZ /* we only consider transfer-encoding magic if libz support is built-in */ if(!Curl_checkheaders(conn, "TE") && data->set.http_transfer_encoding) { /* When we are to insert a TE: header in the request, we must also insert TE in a Connection: header, so we need to merge the custom provided Connection: header and prevent the original to get sent. Note that if the user has inserted his/hers own TE: header we don't do this magic but then assume that the user will handle it all! */ char *cptr = Curl_checkheaders(conn, "Connection"); #define TE_HEADER "TE: gzip\r\n" Curl_safefree(conn->allocptr.te); if(cptr) { cptr = Curl_copy_header_value(cptr); if(!cptr) return CURLE_OUT_OF_MEMORY; } /* Create the (updated) Connection: header */ conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, cptr ? cptr : "", (cptr && *cptr) ? ", ":""); free(cptr); if(!conn->allocptr.te) return CURLE_OUT_OF_MEMORY; } #endif switch(httpreq) { case HTTPREQ_POST_MIME: http->sendit = &data->set.mimepost; break; case HTTPREQ_POST_FORM: /* Convert the form structure into a mime structure. */ Curl_mime_cleanpart(&http->form); result = Curl_getformdata(data, &http->form, data->set.httppost, data->state.fread_func); if(result) return result; http->sendit = &http->form; break; default: http->sendit = NULL; } #ifndef CURL_DISABLE_MIME if(http->sendit) { const char *cthdr = Curl_checkheaders(conn, "Content-Type"); /* Read and seek body only. */ http->sendit->flags |= MIME_BODY_ONLY; /* Prepare the mime structure headers & set content type. */ if(cthdr) for(cthdr += 13; *cthdr == ' '; cthdr++) ; else if(http->sendit->kind == MIMEKIND_MULTIPART) cthdr = "multipart/form-data"; curl_mime_headers(http->sendit, data->set.headers, 0); result = Curl_mime_prepare_headers(http->sendit, cthdr, NULL, MIMESTRATEGY_FORM); curl_mime_headers(http->sendit, NULL, 0); if(!result) result = Curl_mime_rewind(http->sendit); if(result) return result; http->postsize = Curl_mime_size(http->sendit); } #endif ptr = Curl_checkheaders(conn, "Transfer-Encoding"); if(ptr) { /* Some kind of TE is requested, check if 'chunked' is chosen */ data->req.upload_chunky = Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); } else { if((conn->handler->protocol & PROTO_FAMILY_HTTP) && (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && http->postsize < 0) || ((data->set.upload || httpreq == HTTPREQ_POST) && data->state.infilesize == -1))) { if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; else if(use_http_1_1plus(data, conn)) { if(conn->httpversion < 20) /* HTTP, upload, unknown file size and not HTTP 1.0 */ data->req.upload_chunky = TRUE; } else { failf(data, "Chunky upload is not supported by HTTP 1.0"); return CURLE_UPLOAD_FAILED; } } else { /* else, no chunky upload */ data->req.upload_chunky = FALSE; } if(data->req.upload_chunky) te = "Transfer-Encoding: chunked\r\n"; } Curl_safefree(conn->allocptr.host); ptr = Curl_checkheaders(conn, "Host"); if(ptr && (!data->state.this_is_a_follow || strcasecompare(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) /* If we have a given custom Host: header, we extract the host name in order to possibly use it for cookie reasons later on. We only allow the custom Host: header if this is NOT a redirect, as setting Host: in the redirected request is being out on thin ice. Except if the host name is the same as the first one! */ char *cookiehost = Curl_copy_header_value(ptr); if(!cookiehost) return CURLE_OUT_OF_MEMORY; if(!*cookiehost) /* ignore empty data */ free(cookiehost); else { /* If the host begins with '[', we start searching for the port after the bracket has been closed */ if(*cookiehost == '[') { char *closingbracket; /* since the 'cookiehost' is an allocated memory area that will be freed later we cannot simply increment the pointer */ memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); closingbracket = strchr(cookiehost, ']'); if(closingbracket) *closingbracket = 0; } else { int startsearch = 0; char *colon = strchr(cookiehost + startsearch, ':'); if(colon) *colon = 0; /* The host must not include an embedded port number */ } Curl_safefree(conn->allocptr.cookiehost); conn->allocptr.cookiehost = cookiehost; } #endif if(strcmp("Host:", ptr)) { conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]); if(!conn->allocptr.host) return CURLE_OUT_OF_MEMORY; } else /* when clearing the header */ conn->allocptr.host = NULL; } else { /* When building Host: headers, we must put the host name within [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ if(((conn->given->protocol&CURLPROTO_HTTPS) && (conn->remote_port == PORT_HTTPS)) || ((conn->given->protocol&CURLPROTO_HTTP) && (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ conn->allocptr.host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":""); else conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":"", conn->remote_port); if(!conn->allocptr.host) /* without Host: we can't make a nice request */ return CURLE_OUT_OF_MEMORY; } #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* Using a proxy but does not tunnel through it */ /* The path sent to the proxy is in fact the entire URL. But if the remote host is a IDN-name, we must make sure that the request we produce only uses the encoded host name! */ /* and no fragment part */ CURLUcode uc; CURLU *h = curl_url_dup(data->state.uh); if(!h) return CURLE_OUT_OF_MEMORY; if(conn->host.dispname != conn->host.name) { uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; } } uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; } if(strcasecompare("http", data->state.up.scheme)) { /* when getting HTTP, we don't want the userinfo the URL */ uc = curl_url_set(h, CURLUPART_USER, NULL, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; } uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; } } /* Extract the URL to use in the request. Store in STRING_TEMP_URL for clean-up reasons if the function returns before the free() further down. */ uc = curl_url_get(h, CURLUPART_URL, &data->set.str[STRING_TEMP_URL], 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; } curl_url_cleanup(h); if(strcasecompare("ftp", data->state.up.scheme)) { if(data->set.proxy_transfer_mode) { /* when doing ftp, append ;type= if not present */ char *type = strstr(path, ";type="); if(type && type[6] && type[7] == 0) { switch(Curl_raw_toupper(type[6])) { case 'A': case 'D': case 'I': break; default: type = NULL; } } if(!type) { char *p = ftp_typecode; /* avoid sending invalid URLs like ftp://example.com;type=i if the * user specified ftp://example.com without the slash */ if(!*data->state.up.path && path[strlen(path) - 1] != '/') { *p++ = '/'; } msnprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", data->set.prefer_ascii ? 'a' : 'i'); } } if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) paste_ftp_userpwd = TRUE; } } #endif /* CURL_DISABLE_PROXY */ http->p_accept = Curl_checkheaders(conn, "Accept")?NULL:"Accept: */*\r\n"; if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && data->state.resume_from) { /********************************************************************** * Resuming upload in HTTP means that we PUT or POST and that we have * got a resume_from value set. The resume value has already created * a Range: header that will be passed along. We need to "fast forward" * the file the given number of bytes and decrease the assume upload * file size before we continue this venture in the dark lands of HTTP. * Resuming mime/form posting at an offset > 0 has no sense and is ignored. *********************************************************************/ if(data->state.resume_from < 0) { /* * This is meant to get the size of the present remote-file by itself. * We don't support this now. Bail out! */ data->state.resume_from = 0; } if(data->state.resume_from && !data->state.this_is_a_follow) { /* do we still game? */ /* Now, let's read off the proper amount of bytes from the input. */ int seekerr = CURL_SEEKFUNC_CANTSEEK; if(conn->seek_func) { Curl_set_in_callback(data, true); seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, SEEK_SET); Curl_set_in_callback(data, false); } if(seekerr != CURL_SEEKFUNC_OK) { curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_READ_ERROR; } /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { size_t readthisamountnow = (data->state.resume_from - passed > data->set.buffer_size) ? (size_t)data->set.buffer_size : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = data->state.fread_func(data->state.buffer, 1, readthisamountnow, data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T " bytes from the input", passed); return CURLE_READ_ERROR; } } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize>0) { data->state.infilesize -= data->state.resume_from; if(data->state.infilesize <= 0) { failf(data, "File already completely uploaded"); return CURLE_PARTIAL_FILE; } } /* we've passed, proceed as normal */ } } if(data->state.use_range) { /* * A range is selected. We use different headers whether we're downloading * or uploading and we always let customized headers override our internal * ones if any such are specified. */ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && !Curl_checkheaders(conn, "Range")) { /* if a line like this was already allocated, free the previous one */ free(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && !Curl_checkheaders(conn, "Content-Range")) { /* if a line like this was already allocated, free the previous one */ free(conn->allocptr.rangeline); if(data->set.set_resume_from < 0) { /* Upload resume was asked for, but we don't know the size of the remote part so we tell the server (and act accordingly) that we upload the whole file (again) */ conn->allocptr.rangeline = aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.infilesize - 1, data->state.infilesize); } else if(data->state.resume_from) { /* This is because "resume" was selected */ curl_off_t total_expected_size = data->state.resume_from + data->state.infilesize; conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, total_expected_size-1, total_expected_size); } else { /* Range was selected and then we just pass the incoming range and append total size */ conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, data->state.infilesize); } if(!conn->allocptr.rangeline) return CURLE_OUT_OF_MEMORY; } } httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); if(!req_buffer) return CURLE_OUT_OF_MEMORY; /* add the main request stuff */ /* GET/HEAD/POST/PUT */ result = Curl_add_bufferf(&req_buffer, "%s ", request); if(result) return result; if(data->set.str[STRING_TARGET]) { path = data->set.str[STRING_TARGET]; query = NULL; } #ifndef CURL_DISABLE_PROXY /* url */ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { char *url = data->set.str[STRING_TEMP_URL]; result = Curl_add_buffer(&req_buffer, url, strlen(url)); Curl_safefree(data->set.str[STRING_TEMP_URL]); } else #endif if(paste_ftp_userpwd) result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", conn->user, conn->passwd, path + sizeof("ftp://") - 1); else { result = Curl_add_buffer(&req_buffer, path, strlen(path)); if(result) return result; if(query) result = Curl_add_bufferf(&req_buffer, "?%s", query); } if(result) return result; #ifdef USE_ALTSVC if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) { altused = aprintf("Alt-Used: %s:%d\r\n", conn->conn_to_host.name, conn->conn_to_port); if(!altused) return CURLE_OUT_OF_MEMORY; } #endif result = Curl_add_bufferf(&req_buffer, "%s" /* ftp typecode (;type=x) */ " HTTP/%s\r\n" /* HTTP version */ "%s" /* host */ "%s" /* proxyuserpwd */ "%s" /* userpwd */ "%s" /* range */ "%s" /* user agent */ "%s" /* accept */ "%s" /* TE: */ "%s" /* accept-encoding */ "%s" /* referer */ "%s" /* Proxy-Connection */ "%s" /* transfer-encoding */ "%s",/* Alt-Used */ ftp_typecode, httpstring, (conn->allocptr.host?conn->allocptr.host:""), conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", conn->allocptr.userpwd?conn->allocptr.userpwd:"", (data->state.use_range && conn->allocptr.rangeline)? conn->allocptr.rangeline:"", (data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? conn->allocptr.uagent:"", http->p_accept?http->p_accept:"", conn->allocptr.te?conn->allocptr.te:"", (data->set.str[STRING_ENCODING] && *data->set.str[STRING_ENCODING] && conn->allocptr.accept_encoding)? conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)? conn->allocptr.ref:"" /* Referer: */, (conn->bits.httpproxy && !conn->bits.tunnel_proxy && !Curl_checkProxyheaders(conn, "Proxy-Connection"))? "Proxy-Connection: Keep-Alive\r\n":"", te, altused ? altused : "" ); /* clear userpwd and proxyuserpwd to avoid re-using old credentials * from re-used connections */ Curl_safefree(conn->allocptr.userpwd); Curl_safefree(conn->allocptr.proxyuserpwd); free(altused); if(result) return result; if(!(conn->handler->flags&PROTOPT_SSL) && conn->httpversion != 20 && (data->set.httpversion == CURL_HTTP_VERSION_2)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ result = Curl_http2_request_upgrade(req_buffer, conn); if(result) return result; } #if !defined(CURL_DISABLE_COOKIES) if(data->cookies || addcookies) { struct Cookie *co = NULL; /* no cookies from start */ int count = 0; if(data->cookies && data->state.cookie_engine) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); co = Curl_cookie_getlist(data->cookies, conn->allocptr.cookiehost? conn->allocptr.cookiehost:host, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { struct Cookie *store = co; /* now loop through all cookies that matched */ while(co) { if(co->value) { if(0 == count) { result = Curl_add_bufferf(&req_buffer, "Cookie: "); if(result) break; } result = Curl_add_bufferf(&req_buffer, "%s%s=%s", count?"; ":"", co->name, co->value); if(result) break; count++; } co = co->next; /* next cookie please */ } Curl_cookie_freelist(store); } if(addcookies && !result) { if(!count) result = Curl_add_bufferf(&req_buffer, "Cookie: "); if(!result) { result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"", addcookies); count++; } } if(count && !result) result = Curl_add_buffer(&req_buffer, "\r\n", 2); if(result) return result; } #endif result = Curl_add_timecondition(conn, req_buffer); if(result) return result; result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; http->postdata = NULL; /* nothing to post at this point */ Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */ /* If 'authdone' is FALSE, we must not set the write socket index to the Curl_transfer() call below, as we're not ready to actually upload any data yet. */ switch(httpreq) { case HTTPREQ_PUT: /* Let's PUT the data to the server! */ if(conn->bits.authneg) postsize = 0; else postsize = data->state.infilesize; if((postsize != -1) && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(&req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", postsize); if(result) return result; } if(postsize != 0) { result = expect100(data, conn, req_buffer); if(result) return result; } result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */ if(result) return result; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize); /* this sends the buffer and frees all the buffer resources */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) failf(data, "Failed sending PUT request"); else /* prepare for transfer */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, postsize?FIRSTSOCKET:-1); if(result) return result; break; case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: /* This is form posting using mime data. */ if(conn->bits.authneg) { /* nothing to post! */ result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n"); if(result) return result; result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else /* setup variables for the upcoming transfer */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); break; } data->state.infilesize = postsize = http->postsize; /* We only set Content-Length and allow a custom Content-Length if we don't upload data chunked, as RFC2616 forbids us to set both kinds of headers (Transfer-Encoding: chunked and Content-Length) */ if(postsize != -1 && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(&req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", postsize); if(result) return result; } #ifndef CURL_DISABLE_MIME /* Output mime-generated headers. */ { struct curl_slist *hdr; for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data); if(result) return result; } } #endif /* For really small posts we don't use Expect: headers at all, and for the somewhat bigger ones we allow the app to disable it. Just make sure that the expect100header is always set to the preferred value here. */ ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; } else data->state.expect100header = FALSE; /* make the request end in a true CRLF */ result = Curl_add_buffer(&req_buffer, "\r\n", 2); if(result) return result; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize); /* Read from mime structure. */ data->state.fread_func = (curl_read_callback) Curl_mime_read; data->state.in = (void *) http->sendit; http->sending = HTTPSEND_BODY; /* this sends the buffer and frees all the buffer resources */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else /* prepare for transfer */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, postsize?FIRSTSOCKET:-1); if(result) return result; break; case HTTPREQ_POST: /* this is the simple POST, using x-www-form-urlencoded style */ if(conn->bits.authneg) postsize = 0; else /* the size of the post body */ postsize = data->state.infilesize; /* We only set Content-Length and allow a custom Content-Length if we don't upload data chunked, as RFC2616 forbids us to set both kinds of headers (Transfer-Encoding: chunked and Content-Length) */ if((postsize != -1) && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(&req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", postsize); if(result) return result; } if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(&req_buffer, "Content-Type: application/" "x-www-form-urlencoded\r\n"); if(result) return result; } /* For really small posts we don't use Expect: headers at all, and for the somewhat bigger ones we allow the app to disable it. Just make sure that the expect100header is always set to the preferred value here. */ ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; } else data->state.expect100header = FALSE; if(data->set.postfields) { /* In HTTP2, we send request body in DATA frame regardless of its size. */ if(conn->httpversion != 20 && !data->state.expect100header && (postsize < MAX_INITIAL_POST_SIZE)) { /* if we don't use expect: 100 AND postsize is less than MAX_INITIAL_POST_SIZE then append the post data to the HTTP request header. This limit is no magic limit but only set to prevent really huge POSTs to get the data duplicated with malloc() and family. */ result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ if(result) return result; if(!data->req.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ result = Curl_add_buffer(&req_buffer, data->set.postfields, (size_t)postsize); included_body = postsize; } else { if(postsize) { /* Append the POST data chunky-style */ result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize); if(!result) { result = Curl_add_buffer(&req_buffer, data->set.postfields, (size_t)postsize); if(!result) result = Curl_add_buffer(&req_buffer, "\r\n", 2); included_body = postsize + 2; } } if(!result) result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); /* 0 CR LF CR LF */ included_body += 5; } if(result) return result; /* Make sure the progress information is accurate */ Curl_pgrsSetUploadSize(data, postsize); } else { /* A huge POST coming up, do data separate from the request */ http->postsize = postsize; http->postdata = data->set.postfields; http->sending = HTTPSEND_BODY; data->state.fread_func = (curl_read_callback)readmoredata; data->state.in = (void *)conn; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ if(result) return result; } } else { result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ if(result) return result; if(data->req.upload_chunky && conn->bits.authneg) { /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); /* 0 CR LF CR LF */ if(result) return result; } else if(data->state.infilesize) { /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize?postsize:-1); /* set the pointer to mark that we will send the post body using the read callback, but only if we're not in authenticate negotiation */ if(!conn->bits.authneg) { http->postdata = (char *)&http->postdata; http->postsize = postsize; } } } /* issue the request */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, (size_t)included_body, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP POST request"); else Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, http->postdata?FIRSTSOCKET:-1); break; default: result = Curl_add_buffer(&req_buffer, "\r\n", 2); if(result) return result; /* issue the request */ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); else /* HTTP GET/HEAD download: */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); } if(result) return result; if(!postsize) data->req.upload_done = TRUE; if(data->req.writebytecount) { /* if a request-body has been sent off, we make sure this progress is noted properly */ Curl_pgrsSetUploadCounter(data, data->req.writebytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; if(data->req.writebytecount >= postsize) { /* already sent the entire request body, mark the "upload" as complete */ infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n", data->req.writebytecount, postsize); data->req.upload_done = TRUE; data->req.keepon &= ~KEEP_SEND; /* we're done writing */ data->req.exp100 = EXP100_SEND_DATA; /* already sent */ Curl_expire_done(data, EXPIRE_100_TIMEOUT); } } if((conn->httpversion == 20) && data->req.upload_chunky) /* upload_chunky was set above to set up the request in a chunky fashion, but is disabled here again to avoid that the chunked encoded version is actually used when sending the request body over h2 */ data->req.upload_chunky = FALSE; return result; } typedef enum { STATUS_UNKNOWN, /* not enough data to tell yet */ STATUS_DONE, /* a status line was read */ STATUS_BAD /* not a status line */ } statusline; /* Check a string for a prefix. Check no more than 'len' bytes */ static bool checkprefixmax(const char *prefix, const char *buffer, size_t len) { size_t ch = CURLMIN(strlen(prefix), len); return curl_strnequal(prefix, buffer, ch); } /* * checkhttpprefix() * * Returns TRUE if member of the list matches prefix of string */ static statusline checkhttpprefix(struct Curl_easy *data, const char *s, size_t len) { struct curl_slist *head = data->set.http200aliases; statusline rc = STATUS_BAD; statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); if(NULL == scratch) { failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ free(scratch); return FALSE; /* can't return CURLE_foobar so return FALSE */ } s = scratch; #endif /* CURL_DOES_CONVERSIONS */ while(head) { if(checkprefixmax(head->data, s, len)) { rc = onmatch; break; } head = head->next; } if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len))) rc = onmatch; #ifdef CURL_DOES_CONVERSIONS free(scratch); #endif /* CURL_DOES_CONVERSIONS */ return rc; } #ifndef CURL_DISABLE_RTSP static statusline checkrtspprefix(struct Curl_easy *data, const char *s, size_t len) { statusline result = STATUS_BAD; statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); if(NULL == scratch) { failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ result = FALSE; /* can't return CURLE_foobar so return FALSE */ } else if(checkprefixmax("RTSP/", scratch, len)) result = onmatch; free(scratch); #else (void)data; /* unused */ if(checkprefixmax("RTSP/", s, len)) result = onmatch; #endif /* CURL_DOES_CONVERSIONS */ return result; } #endif /* CURL_DISABLE_RTSP */ static statusline checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, const char *s, size_t len) { #ifndef CURL_DISABLE_RTSP if(conn->handler->protocol & CURLPROTO_RTSP) return checkrtspprefix(data, s, len); #else (void)conn; #endif /* CURL_DISABLE_RTSP */ return checkhttpprefix(data, s, len); } /* * header_append() copies a chunk of data to the end of the already received * header. We make sure that the full string fit in the allocated header * buffer, or else we enlarge it. */ static CURLcode header_append(struct Curl_easy *data, struct SingleRequest *k, size_t length) { /* length is at most the size of a full read buffer, for which the upper bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this calculation. */ size_t newsize = k->hbuflen + length; if(newsize > CURL_MAX_HTTP_HEADER) { /* The reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a never-ending header that will cause reallocs infinitely */ failf(data, "Rejected %zu bytes header (max is %d)!", newsize, CURL_MAX_HTTP_HEADER); return CURLE_OUT_OF_MEMORY; } if(newsize >= data->state.headersize) { /* We enlarge the header buffer as it is too small */ char *newbuff; size_t hbufp_index; newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); hbufp_index = k->hbufp - data->state.headerbuff; newbuff = realloc(data->state.headerbuff, newsize); if(!newbuff) { failf(data, "Failed to alloc memory for big header!"); return CURLE_OUT_OF_MEMORY; } data->state.headersize = newsize; data->state.headerbuff = newbuff; k->hbufp = data->state.headerbuff + hbufp_index; } memcpy(k->hbufp, k->str_start, length); k->hbufp += length; k->hbuflen += length; *k->hbufp = 0; return CURLE_OK; } static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; char *beg = k->p; /* make sure that data->req.p points to the HTTP status line */ if(!strncmp(beg, "HTTP", 4)) { /* skip to HTTP status code */ beg = strchr(beg, ' '); if(beg && *++beg) { /* find trailing CR */ char end_char = '\r'; char *end = strchr(beg, end_char); if(!end) { /* try to find LF (workaround for non-compliant HTTP servers) */ end_char = '\n'; end = strchr(beg, end_char); } if(end) { /* temporarily replace CR or LF by NUL and print the error message */ *end = '\0'; failf(data, "The requested URL returned error: %s", beg); /* restore the previously replaced CR or LF */ *end = end_char; return; } } } /* fall-back to printing the HTTP status code only */ failf(data, "The requested URL returned error: %d", k->httpcode); } /* * Read any HTTP header lines from the server and pass them to the client app. */ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading) { CURLcode result; struct SingleRequest *k = &data->req; ssize_t onread = *nread; char *ostr = k->str; /* header line within buffer loop */ do { size_t rest_length; size_t full_length; int writetype; /* str_start is start of line within buf */ k->str_start = k->str; /* data is in network encoding so use 0x0a instead of '\n' */ k->end_ptr = memchr(k->str_start, 0x0a, *nread); if(!k->end_ptr) { /* Not a complete header line within buffer, append the data to the end of the headerbuff. */ result = header_append(data, k, *nread); if(result) return result; if(!k->headerline) { /* check if this looks like a protocol header */ statusline st = checkprotoprefix(data, conn, data->state.headerbuff, k->hbuflen); if(st == STATUS_BAD) { /* this is not the beginning of a protocol first header line */ k->header = FALSE; k->badheader = HEADER_ALLBAD; streamclose(conn, "bad HTTP: No end-of-message indicator"); if(!data->set.http09_allowed) { failf(data, "Received HTTP/0.9 when not allowed\n"); return CURLE_UNSUPPORTED_PROTOCOL; } break; } } break; /* read more and try again */ } /* decrease the size of the remaining (supposed) header line */ rest_length = (k->end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; k->str = k->end_ptr + 1; /* move past new line */ full_length = k->str - k->str_start; result = header_append(data, k, full_length); if(result) return result; k->end_ptr = k->hbufp; k->p = data->state.headerbuff; /**** * We now have a FULL header line that p points to *****/ if(!k->headerline) { /* the first read header */ statusline st = checkprotoprefix(data, conn, data->state.headerbuff, k->hbuflen); if(st == STATUS_BAD) { streamclose(conn, "bad HTTP: No end-of-message indicator"); /* this is not the beginning of a protocol first header line */ if(!data->set.http09_allowed) { failf(data, "Received HTTP/0.9 when not allowed\n"); return CURLE_UNSUPPORTED_PROTOCOL; } k->header = FALSE; if(*nread) /* since there's more, this is a partial bad header */ k->badheader = HEADER_PARTHEADER; else { /* this was all we read so it's all a bad header */ k->badheader = HEADER_ALLBAD; *nread = onread; k->str = ostr; return CURLE_OK; } break; } } /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' and '\r' */ if((0x0a == *k->p) || (0x0d == *k->p)) { size_t headerlen; /* Zero-length header line means end of headers! */ #ifdef CURL_DOES_CONVERSIONS if(0x0d == *k->p) { *k->p = '\r'; /* replace with CR in host encoding */ k->p++; /* pass the CR byte */ } if(0x0a == *k->p) { *k->p = '\n'; /* replace with LF in host encoding */ k->p++; /* pass the LF byte */ } #else if('\r' == *k->p) k->p++; /* pass the \r byte */ if('\n' == *k->p) k->p++; /* pass the \n byte */ #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { /* "A user agent MAY ignore unexpected 1xx status responses." */ switch(k->httpcode) { case 100: /* * We have made a HTTP PUT or POST and this is 1.1-lingo * that tells us that the server is OK with this and ready * to receive the data. * However, we'll get more headers now so we must get * back into the header-parsing state! */ k->header = TRUE; k->headerline = 0; /* restart the header line counter */ /* if we did wait for this do enable write now! */ if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; Curl_expire_done(data, EXPIRE_100_TIMEOUT); } break; case 101: /* Switching Protocols */ if(k->upgr101 == UPGR101_REQUESTED) { /* Switching to HTTP/2 */ infof(data, "Received 101\n"); k->upgr101 = UPGR101_RECEIVED; /* we'll get more headers (HTTP/2 response) */ k->header = TRUE; k->headerline = 0; /* restart the header line counter */ /* switch to http2 now. The bytes after response headers are also processed here, otherwise they are lost. */ result = Curl_http2_switched(conn, k->str, *nread); if(result) return result; *nread = 0; } else { /* Switching to another protocol (e.g. WebSocket) */ k->header = FALSE; /* no more header to parse! */ } break; default: /* the status code 1xx indicates a provisional response, so we'll get another set of headers */ k->header = TRUE; k->headerline = 0; /* restart the header line counter */ break; } } else { k->header = FALSE; /* no more header to parse! */ if((k->size == -1) && !k->chunk && !conn->bits.close && (conn->httpversion == 11) && !(conn->handler->protocol & CURLPROTO_RTSP) && data->set.httpreq != HTTPREQ_HEAD) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Transfer-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we assume that the server will close the connection to signal the end of the document. */ infof(data, "no chunk, no close, no size. Assume close to " "signal end\n"); streamclose(conn, "HTTP: No end-of-message indicator"); } } /* At this point we have some idea about the fate of the connection. If we are closing the connection it may result auth failure. */ #if defined(USE_NTLM) if(conn->bits.close && (((data->req.httpcode == 401) && (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || ((data->req.httpcode == 407) && (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) { infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); data->state.authproblem = TRUE; } #endif #if defined(USE_SPNEGO) if(conn->bits.close && (((data->req.httpcode == 401) && (conn->http_negotiate_state == GSS_AUTHRECV)) || ((data->req.httpcode == 407) && (conn->proxy_negotiate_state == GSS_AUTHRECV)))) { infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n"); data->state.authproblem = TRUE; } if((conn->http_negotiate_state == GSS_AUTHDONE) && (data->req.httpcode != 401)) { conn->http_negotiate_state = GSS_AUTHSUCC; } if((conn->proxy_negotiate_state == GSS_AUTHDONE) && (data->req.httpcode != 407)) { conn->proxy_negotiate_state = GSS_AUTHSUCC; } #endif /* * When all the headers have been parsed, see if we should give * up and return an error. */ if(http_should_fail(conn)) { failf(data, "The requested URL returned error: %d", k->httpcode); return CURLE_HTTP_RETURNED_ERROR; } /* now, only output this if the header AND body are requested: */ writetype = CLIENTWRITE_HEADER; if(data->set.include_header) writetype |= CLIENTWRITE_BODY; headerlen = k->p - data->state.headerbuff; result = Curl_client_write(conn, writetype, data->state.headerbuff, headerlen); if(result) return result; data->info.header_size += (long)headerlen; data->req.headerbytecount += (long)headerlen; data->req.deductheadercount = (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; /* Curl_http_auth_act() checks what authentication methods * that are available and decides which one (if any) to * use. It will set 'newurl' if an auth method was picked. */ result = Curl_http_auth_act(conn); if(result) return result; if(k->httpcode >= 300) { if((!conn->bits.authneg) && !conn->bits.close && !conn->bits.rewindaftersend) { /* * General treatment of errors when about to send data. Including : * "417 Expectation Failed", while waiting for 100-continue. * * The check for close above is done simply because of something * else has already deemed the connection to get closed then * something else should've considered the big picture and we * avoid this check. * * rewindaftersend indicates that something has told libcurl to * continue sending even if it gets discarded */ switch(data->set.httpreq) { case HTTPREQ_PUT: case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: /* We got an error response. If this happened before the whole * request body has been sent we stop sending and mark the * connection for closure after we've read the entire response. */ Curl_expire_done(data, EXPIRE_100_TIMEOUT); if(!k->upload_done) { if((k->httpcode == 417) && data->state.expect100header) { /* 417 Expectation Failed - try again without the Expect header */ infof(data, "Got 417 while waiting for a 100\n"); data->state.disableexpect = TRUE; DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(conn->data->change.url); Curl_done_sending(conn, k); } else if(data->set.http_keep_sending_on_error) { infof(data, "HTTP error before end of send, keep sending\n"); if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; } } else { infof(data, "HTTP error before end of send, stop sending\n"); streamclose(conn, "Stop sending data before everything sent"); result = Curl_done_sending(conn, k); if(result) return result; k->upload_done = TRUE; if(data->state.expect100header) k->exp100 = EXP100_FAILED; } } break; default: /* default label present to avoid compiler warnings */ break; } } if(conn->bits.rewindaftersend) { /* We rewind after a complete send, so thus we continue sending now */ infof(data, "Keep sending data to get tossed away!\n"); k->keepon |= KEEP_SEND; } } if(!k->header) { /* * really end-of-headers. * * If we requested a "no body", this is a good time to get * out and return home. */ if(data->set.opt_no_body) *stop_reading = TRUE; #ifndef CURL_DISABLE_RTSP else if((conn->handler->protocol & CURLPROTO_RTSP) && (data->set.rtspreq == RTSPREQ_DESCRIBE) && (k->size <= -1)) /* Respect section 4.4 of rfc2326: If the Content-Length header is absent, a length 0 must be assumed. It will prevent libcurl from hanging on DESCRIBE request that got refused for whatever reason */ *stop_reading = TRUE; #endif else { /* If we know the expected size of this document, we set the maximum download size to the size of the expected document or else, we won't know when to stop reading! Note that we set the download maximum even if we read a "Connection: close" header, to make sure that "Content-Length: 0" still prevents us from attempting to read the (missing) response-body. */ /* According to RFC2616 section 4.4, we MUST ignore Content-Length: headers if we are now receiving data using chunked Transfer-Encoding. */ if(k->chunk) k->maxdownload = k->size = -1; } if(-1 != k->size) { /* We do this operation even if no_body is true, since this data might be retrieved later with curl_easy_getinfo() and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ Curl_pgrsSetDownloadSize(data, k->size); k->maxdownload = k->size; } /* If max download size is *zero* (nothing) we already have nothing and can safely return ok now! But for HTTP/2, we'd like to call http2_handle_stream_close to properly close a stream. In order to do this, we keep reading until we close the stream. */ if(0 == k->maxdownload #if defined(USE_NGHTTP2) && !((conn->handler->protocol & PROTO_FAMILY_HTTP) && conn->httpversion == 20) #endif ) *stop_reading = TRUE; if(*stop_reading) { /* we make sure that this socket isn't read more now */ k->keepon &= ~KEEP_RECV; } if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, k->str_start, headerlen); break; /* exit header line loop */ } /* We continue reading headers, so reset the line-based header parsing variables hbufp && hbuflen */ k->hbufp = data->state.headerbuff; k->hbuflen = 0; continue; } /* * Checks for special headers coming up. */ if(!k->headerline++) { /* This is the first header, it MUST be the error code line or else we consider this to be the body right away! */ int httpversion_major; int rtspversion_major; int nc = 0; #ifdef CURL_DOES_CONVERSIONS #define HEADER1 scratch #define SCRATCHSIZE 21 CURLcode res; char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ /* We can't really convert this yet because we don't know if it's the 1st header line or the body. So we do a partial conversion into a scratch area, leaving the data at k->p as-is. */ strncpy(&scratch[0], k->p, SCRATCHSIZE); scratch[SCRATCHSIZE] = 0; /* null terminate */ res = Curl_convert_from_network(data, &scratch[0], SCRATCHSIZE); if(res) /* Curl_convert_from_network calls failf if unsuccessful */ return res; #else #define HEADER1 k->p /* no conversion needed, just use k->p */ #endif /* CURL_DOES_CONVERSIONS */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { /* * https://tools.ietf.org/html/rfc7230#section-3.1.2 * * The response code is always a three-digit number in HTTP as the spec * says. We try to allow any number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ char separator; char twoorthree[2]; nc = sscanf(HEADER1, " HTTP/%1d.%1d%c%3d", &httpversion_major, &conn->httpversion, &separator, &k->httpcode); if(nc == 1 && httpversion_major >= 2 && 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) { conn->httpversion = 0; nc = 4; separator = ' '; } if((nc == 4) && (' ' == separator)) { conn->httpversion += 10 * httpversion_major; if(k->upgr101 == UPGR101_RECEIVED) { /* supposedly upgraded to http2 now */ if(conn->httpversion != 20) infof(data, "Lying server, not serving HTTP/2\n"); } if(conn->httpversion < 20) { conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; infof(data, "Mark bundle as not supporting multiuse\n"); } } else if(!nc) { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 */ nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases */ if(!nc) { if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) { nc = 1; k->httpcode = 200; conn->httpversion = 10; } } } else { failf(data, "Unsupported HTTP version in response"); return CURLE_UNSUPPORTED_PROTOCOL; } } else if(conn->handler->protocol & CURLPROTO_RTSP) { char separator; nc = sscanf(HEADER1, " RTSP/%1d.%1d%c%3d", &rtspversion_major, &conn->rtspversion, &separator, &k->httpcode); if((nc == 4) && (' ' == separator)) { conn->rtspversion += 10 * rtspversion_major; conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ } else { nc = 0; } } if(nc) { data->info.httpcode = k->httpcode; data->info.httpversion = conn->httpversion; if(!data->state.httpversion || data->state.httpversion > conn->httpversion) /* store the lowest server version we encounter */ data->state.httpversion = conn->httpversion; /* * This code executes as part of processing the header. As a * result, it's not totally clear how to interpret the * response code yet as that depends on what other headers may * be present. 401 and 407 may be errors, but may be OK * depending on how authentication is working. Other codes * are definitely errors, so give up here. */ if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET && k->httpcode == 416) { /* "Requested Range Not Satisfiable", just proceed and pretend this is no error */ k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ } else if(data->set.http_fail_on_error && (k->httpcode >= 400) && ((k->httpcode != 401) || !conn->bits.user_passwd) && ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { /* serious error, go home! */ print_http_error(data); return CURLE_HTTP_RETURNED_ERROR; } if(conn->httpversion == 10) { /* Default action for HTTP/1.0 must be to close, unless we get one of those fancy headers that tell us the server keeps it open for us! */ infof(data, "HTTP 1.0, assume close after body\n"); connclose(conn, "HTTP/1.0 close after body"); } else if(conn->httpversion == 20 || (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); /* HTTP/2 cannot blacklist multiplexing since it is a core functionality of the protocol */ conn->bundle->multiuse = BUNDLE_MULTIPLEX; } else if(conn->httpversion >= 11 && !conn->bits.close) { /* If HTTP version is >= 1.1 and connection is persistent */ DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection\n")); } k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; switch(k->httpcode) { case 304: /* (quote from RFC2616, section 10.3.5): The 304 response * MUST NOT contain a message-body, and thus is always * terminated by the first empty line after the header * fields. */ if(data->set.timecondition) data->info.timecond = TRUE; /* FALLTHROUGH */ case 204: /* (quote from RFC2616, section 10.2.5): The server has * fulfilled the request but does not need to return an * entity-body ... The 204 response MUST NOT include a * message-body, and thus is always terminated by the first * empty line after the header fields. */ k->size = 0; k->maxdownload = 0; k->http_bodyless = TRUE; break; default: break; } } else { k->header = FALSE; /* this is not a header line */ break; } } result = Curl_convert_from_network(data, k->p, strlen(k->p)); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* Check for Content-Length: header lines to get size */ if(!k->http_bodyless && !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { curl_off_t contentlength; CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength); if(offt == CURL_OFFT_OK) { if(data->set.max_filesize && contentlength > data->set.max_filesize) { failf(data, "Maximum file size exceeded"); return CURLE_FILESIZE_EXCEEDED; } k->size = contentlength; k->maxdownload = k->size; /* we set the progress download size already at this point just to make it easier for apps/callbacks to extract this info as soon as possible */ Curl_pgrsSetDownloadSize(data, k->size); } else if(offt == CURL_OFFT_FLOW) { /* out of range */ if(data->set.max_filesize) { failf(data, "Maximum file size exceeded"); return CURLE_FILESIZE_EXCEEDED; } streamclose(conn, "overflow content-length"); infof(data, "Overflow Content-Length: value!\n"); } else { /* negative or just rubbish - bad HTTP */ failf(data, "Invalid Content-Length: value"); return CURLE_WEIRD_SERVER_REPLY; } } /* check for Content-Type: header lines to get the MIME-type */ else if(checkprefix("Content-Type:", k->p)) { char *contenttype = Curl_copy_header_value(k->p); if(!contenttype) return CURLE_OUT_OF_MEMORY; if(!*contenttype) /* ignore empty data */ free(contenttype); else { Curl_safefree(data->info.contenttype); data->info.contenttype = contenttype; } } else if((conn->httpversion == 10) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "keep-alive")) { /* * When a HTTP/1.0 reply comes when using a proxy, the * 'Proxy-Connection: keep-alive' line tells us the * connection will be kept alive for our pleasure. * Default action for 1.0 is to close. */ connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); } else if((conn->httpversion == 11) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "close")) { /* * We get a HTTP/1.1 response from a proxy and it says it'll * close down after this transfer. */ connclose(conn, "Proxy-Connection: asked to close after done"); infof(data, "HTTP/1.1 proxy connection set close!\n"); } else if((conn->httpversion == 10) && Curl_compareheader(k->p, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line * tells us the connection will be kept alive for our * pleasure. Default action for 1.0 is to close. * * [RFC2068, section 19.7.1] */ connkeep(conn, "Connection keep-alive"); infof(data, "HTTP/1.0 connection set to keep alive!\n"); } else if(Curl_compareheader(k->p, "Connection:", "close")) { /* * [RFC 2616, section 8.1.2.1] * "Connection: close" is HTTP/1.1 language and means that * the connection will close when this request has been * served. */ streamclose(conn, "Connection: close used"); } else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) { /* One or more encodings. We check for chunked and/or a compression algorithm. */ /* * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding * means that the server will send a series of "chunks". Each * chunk starts with line with info (including size of the * coming block) (terminated with CRLF), then a block of data * with the previously mentioned size. There can be any amount * of chunks, and a chunk-data set to zero signals the * end-of-chunks. */ result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE); if(result) return result; } else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) && data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, * gzip, deflate, compress, x-gzip and x-compress. x-gzip and * x-compress are the same as gzip and compress. (Sec 3.5 RFC * 2616). zlib cannot handle compress. However, errors are * handled further down when the response body is processed */ result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE); if(result) return result; } else if(checkprefix("Retry-After:", k->p)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ time_t date = Curl_getdate_capped(&k->p[12]); if(-1 == date) { /* not a date, try it as a decimal number */ (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); } else /* convert date to number of seconds into the future */ retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) { /* Content-Range: bytes [num]- Content-Range: bytes: [num]- Content-Range: [num]- Content-Range: [asterisk]/[total] The second format was added since Sun's webserver JavaWebServer/1.1.1 obviously sends the header this way! The third added since some servers use that! The forth means the requested range was unsatisfied. */ char *ptr = k->p + 14; /* Move forward until first digit or asterisk */ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') ptr++; /* if it truly stopped on a digit */ if(ISDIGIT(*ptr)) { if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { if(data->state.resume_from == k->offset) /* we asked for a resume and we got it */ k->content_range = TRUE; } } else data->state.resume_from = 0; /* get everything */ } #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && data->state.cookie_engine && checkprefix("Set-Cookie:", k->p)) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, data->cookies, TRUE, FALSE, k->p + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ conn->allocptr.cookiehost? conn->allocptr.cookiehost:conn->host.name, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && (data->set.timecondition || data->set.get_filetime) ) { k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:")); if(data->set.get_filetime) data->info.filetime = k->timeofdoc; } else if((checkprefix("WWW-Authenticate:", k->p) && (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", k->p) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; char *auth = Curl_copy_header_value(k->p); if(!auth) return CURLE_OUT_OF_MEMORY; result = Curl_http_input_auth(conn, proxy, auth); free(auth); if(result) return result; } #ifdef USE_SPNEGO else if(checkprefix("Persistent-Auth", k->p)) { struct negotiatedata *negdata = &conn->negotiate; struct auth *authp = &data->state.authhost; if(authp->picked == CURLAUTH_NEGOTIATE) { char *persistentauth = Curl_copy_header_value(k->p); if(!persistentauth) return CURLE_OUT_OF_MEMORY; negdata->noauthpersist = checkprefix("false", persistentauth)? TRUE:FALSE; negdata->havenoauthpersist = TRUE; infof(data, "Negotiate: noauthpersist -> %d, header part: %s", negdata->noauthpersist, persistentauth); free(persistentauth); } } #endif else if((k->httpcode >= 300 && k->httpcode < 400) && checkprefix("Location:", k->p) && !data->req.location) { /* this is the URL that the server advises us to use instead */ char *location = Curl_copy_header_value(k->p); if(!location) return CURLE_OUT_OF_MEMORY; if(!*location) /* ignore empty data */ free(location); else { data->req.location = location; if(data->set.http_follow_location) { DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->req.location); /* clone */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; /* some cases of POST and PUT etc needs to rewind the data stream at this point */ result = http_perhapsrewind(conn); if(result) return result; } } } #ifdef USE_ALTSVC /* If enabled, the header is incoming and this is over HTTPS */ else if(data->asi && checkprefix("Alt-Svc:", k->p) && ((conn->handler->flags & PROTOPT_SSL) || #ifdef CURLDEBUG /* allow debug builds to circumvent the HTTPS restriction */ getenv("CURL_ALTSVC_HTTP") #else 0 #endif )) { /* the ALPN of the current request */ enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; result = Curl_altsvc_parse(data, data->asi, &k->p[ strlen("Alt-Svc:") ], id, conn->host.name, curlx_uitous(conn->remote_port)); if(result) return result; } #endif else if(conn->handler->protocol & CURLPROTO_RTSP) { result = Curl_rtsp_parseheader(conn, k->p); if(result) return result; } /* * End of header-checks. Write them to the client. */ writetype = CLIENTWRITE_HEADER; if(data->set.include_header) writetype |= CLIENTWRITE_BODY; if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen); result = Curl_client_write(conn, writetype, k->p, k->hbuflen); if(result) return result; data->info.header_size += (long)k->hbuflen; data->req.headerbytecount += (long)k->hbuflen; /* reset hbufp pointer && hbuflen */ k->hbufp = data->state.headerbuff; k->hbuflen = 0; } while(*k->str); /* header line within buffer */ /* We might have reached the end of the header part here, but there might be a non-header part left in the end of the read buffer. */ return CURLE_OK; } #endif /* CURL_DISABLE_HTTP */ davix-0.8.0/deps/curl/lib/curl_gethostname.h0000644000000000000000000000244314121063461017513 0ustar rootroot#ifndef HEADER_CURL_GETHOSTNAME_H #define HEADER_CURL_GETHOSTNAME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Hostname buffer size */ #define HOSTNAME_MAX 1024 /* This returns the local machine's un-qualified hostname */ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen); #endif /* HEADER_CURL_GETHOSTNAME_H */ davix-0.8.0/deps/curl/lib/curl_config.h.cmake0000644000000000000000000007241514121063461017527 0ustar rootroot/* lib/curl_config.h.in. Generated somehow by cmake. */ /* when building libcurl itself */ #cmakedefine BUILDING_LIBCURL 1 /* Location of default ca bundle */ #cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}" /* define "1" to use built-in ca store of TLS backend */ #cmakedefine CURL_CA_FALLBACK 1 /* Location of default ca path */ #cmakedefine CURL_CA_PATH "${CURL_CA_PATH}" /* to disable cookies support */ #cmakedefine CURL_DISABLE_COOKIES 1 /* to disable cryptographic authentication */ #cmakedefine CURL_DISABLE_CRYPTO_AUTH 1 /* to disable DICT */ #cmakedefine CURL_DISABLE_DICT 1 /* to disable FILE */ #cmakedefine CURL_DISABLE_FILE 1 /* to disable FTP */ #cmakedefine CURL_DISABLE_FTP 1 /* to disable GOPHER */ #cmakedefine CURL_DISABLE_GOPHER 1 /* to disable IMAP */ #cmakedefine CURL_DISABLE_IMAP 1 /* to disable HTTP */ #cmakedefine CURL_DISABLE_HTTP 1 /* to disable LDAP */ #cmakedefine CURL_DISABLE_LDAP 1 /* to disable LDAPS */ #cmakedefine CURL_DISABLE_LDAPS 1 /* to disable POP3 */ #cmakedefine CURL_DISABLE_POP3 1 /* to disable proxies */ #cmakedefine CURL_DISABLE_PROXY 1 /* to disable RTSP */ #cmakedefine CURL_DISABLE_RTSP 1 /* to disable SMB */ #cmakedefine CURL_DISABLE_SMB 1 /* to disable SMTP */ #cmakedefine CURL_DISABLE_SMTP 1 /* to disable TELNET */ #cmakedefine CURL_DISABLE_TELNET 1 /* to disable TFTP */ #cmakedefine CURL_DISABLE_TFTP 1 /* to disable verbose strings */ #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 /* to make a symbol visible */ #cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} /* Ensure using CURL_EXTERN_SYMBOL is possible */ #ifndef CURL_EXTERN_SYMBOL #define CURL_EXTERN_SYMBOL #endif /* Allow SMB to work on Windows */ #cmakedefine USE_WIN32_CRYPTO /* Use Windows LDAP implementation */ #cmakedefine USE_WIN32_LDAP 1 /* when not building a shared library */ #cmakedefine CURL_STATICLIB 1 /* your Entropy Gathering Daemon socket pathname */ #cmakedefine EGD_SOCKET ${EGD_SOCKET} /* Define if you want to enable IPv6 support */ #cmakedefine ENABLE_IPV6 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1} /* Define to the type of arg 1 for getnameinfo. */ #cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1} /* Define to the type of arg 2 for getnameinfo. */ #cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2} /* Define to the type of args 4 and 6 for getnameinfo. */ #cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46} /* Define to the type of arg 7 for getnameinfo. */ #cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7} /* Specifies the number of arguments to getservbyport_r */ #cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS} /* Specifies the size of the buffer to pass to getservbyport_r */ #cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE} /* Define to 1 if you have the alarm function. */ #cmakedefine HAVE_ALARM 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ALLOCA_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_TFTP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ASSERT_H 1 /* Define to 1 if you have the `basename' function. */ #cmakedefine HAVE_BASENAME 1 /* Define to 1 if bool is an available type. */ #cmakedefine HAVE_BOOL_T 1 /* Define to 1 if you have the __builtin_available function. */ #cmakedefine HAVE_BUILTIN_AVAILABLE 1 /* Define to 1 if you have the clock_gettime function and monotonic timer. */ #cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1 /* Define to 1 if you have the `closesocket' function. */ #cmakedefine HAVE_CLOSESOCKET 1 /* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ #cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_CRYPTO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ERR_H 1 /* Define to 1 if you have the fcntl function. */ #cmakedefine HAVE_FCNTL 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_FCNTL_H 1 /* Define to 1 if you have a working fcntl O_NONBLOCK function. */ #cmakedefine HAVE_FCNTL_O_NONBLOCK 1 /* Define to 1 if you have the fdopen function. */ #cmakedefine HAVE_FDOPEN 1 /* Define to 1 if you have the `fork' function. */ #cmakedefine HAVE_FORK 1 /* Define to 1 if you have the freeaddrinfo function. */ #cmakedefine HAVE_FREEADDRINFO 1 /* Define to 1 if you have the freeifaddrs function. */ #cmakedefine HAVE_FREEIFADDRS 1 /* Define to 1 if you have the ftruncate function. */ #cmakedefine HAVE_FTRUNCATE 1 /* Define to 1 if you have a working getaddrinfo function. */ #cmakedefine HAVE_GETADDRINFO 1 /* Define to 1 if you have the `geteuid' function. */ #cmakedefine HAVE_GETEUID 1 /* Define to 1 if you have the gethostbyaddr function. */ #cmakedefine HAVE_GETHOSTBYADDR 1 /* Define to 1 if you have the gethostbyaddr_r function. */ #cmakedefine HAVE_GETHOSTBYADDR_R 1 /* gethostbyaddr_r() takes 5 args */ #cmakedefine HAVE_GETHOSTBYADDR_R_5 1 /* gethostbyaddr_r() takes 7 args */ #cmakedefine HAVE_GETHOSTBYADDR_R_7 1 /* gethostbyaddr_r() takes 8 args */ #cmakedefine HAVE_GETHOSTBYADDR_R_8 1 /* Define to 1 if you have the gethostbyname function. */ #cmakedefine HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the gethostbyname_r function. */ #cmakedefine HAVE_GETHOSTBYNAME_R 1 /* gethostbyname_r() takes 3 args */ #cmakedefine HAVE_GETHOSTBYNAME_R_3 1 /* gethostbyname_r() takes 5 args */ #cmakedefine HAVE_GETHOSTBYNAME_R_5 1 /* gethostbyname_r() takes 6 args */ #cmakedefine HAVE_GETHOSTBYNAME_R_6 1 /* Define to 1 if you have the gethostname function. */ #cmakedefine HAVE_GETHOSTNAME 1 /* Define to 1 if you have a working getifaddrs function. */ #cmakedefine HAVE_GETIFADDRS 1 /* Define to 1 if you have the getnameinfo function. */ #cmakedefine HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getpass_r' function. */ #cmakedefine HAVE_GETPASS_R 1 /* Define to 1 if you have the `getppid' function. */ #cmakedefine HAVE_GETPPID 1 /* Define to 1 if you have the `getprotobyname' function. */ #cmakedefine HAVE_GETPROTOBYNAME 1 /* Define to 1 if you have the `getpeername' function. */ #cmakedefine HAVE_GETPEERNAME 1 /* Define to 1 if you have the `getsockname' function. */ #cmakedefine HAVE_GETSOCKNAME 1 /* Define to 1 if you have the `if_nametoindex' function. */ #cmakedefine HAVE_IF_NAMETOINDEX 1 /* Define to 1 if you have the `getpwuid' function. */ #cmakedefine HAVE_GETPWUID 1 /* Define to 1 if you have the `getpwuid_r' function. */ #cmakedefine HAVE_GETPWUID_R 1 /* Define to 1 if you have the `getrlimit' function. */ #cmakedefine HAVE_GETRLIMIT 1 /* Define to 1 if you have the getservbyport_r function. */ #cmakedefine HAVE_GETSERVBYPORT_R 1 /* Define to 1 if you have the `gettimeofday' function. */ #cmakedefine HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have a working glibc-style strerror_r function. */ #cmakedefine HAVE_GLIBC_STRERROR_R 1 /* Define to 1 if you have a working gmtime_r function. */ #cmakedefine HAVE_GMTIME_R 1 /* if you have the gssapi libraries */ #cmakedefine HAVE_GSSAPI 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GSSAPI_GSSAPI_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1 /* if you have the GNU gssapi libraries */ #cmakedefine HAVE_GSSGNU 1 /* if you have the Heimdal gssapi libraries */ #cmakedefine HAVE_GSSHEIMDAL 1 /* if you have the MIT gssapi libraries */ #cmakedefine HAVE_GSSMIT 1 /* Define to 1 if you have the `idna_strerror' function. */ #cmakedefine HAVE_IDNA_STRERROR 1 /* Define to 1 if you have the `idn_free' function. */ #cmakedefine HAVE_IDN_FREE 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_IDN_FREE_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_IFADDRS_H 1 /* Define to 1 if you have the `inet_addr' function. */ #cmakedefine HAVE_INET_ADDR 1 /* Define to 1 if you have the inet_ntoa_r function. */ #cmakedefine HAVE_INET_NTOA_R 1 /* inet_ntoa_r() takes 2 args */ #cmakedefine HAVE_INET_NTOA_R_2 1 /* inet_ntoa_r() takes 3 args */ #cmakedefine HAVE_INET_NTOA_R_3 1 /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ #cmakedefine HAVE_INET_NTOP 1 /* Define to 1 if you have a IPv6 capable working inet_pton function. */ #cmakedefine HAVE_INET_PTON 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H 1 /* Define to 1 if you have the ioctl function. */ #cmakedefine HAVE_IOCTL 1 /* Define to 1 if you have the ioctlsocket function. */ #cmakedefine HAVE_IOCTLSOCKET 1 /* Define to 1 if you have the IoctlSocket camel case function. */ #cmakedefine HAVE_IOCTLSOCKET_CAMEL 1 /* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ #cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 /* Define to 1 if you have a working ioctlsocket FIONBIO function. */ #cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1 /* Define to 1 if you have a working ioctl FIONBIO function. */ #cmakedefine HAVE_IOCTL_FIONBIO 1 /* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ #cmakedefine HAVE_IOCTL_SIOCGIFADDR 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_IO_H 1 /* if you have the Kerberos4 libraries (including -ldes) */ #cmakedefine HAVE_KRB4 1 /* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ #cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_KRB_H 1 /* Define to 1 if you have the lber.h header file. */ #cmakedefine HAVE_LBER_H 1 /* Define to 1 if you have the ldapssl.h header file. */ #cmakedefine HAVE_LDAPSSL_H 1 /* Define to 1 if you have the ldap.h header file. */ #cmakedefine HAVE_LDAP_H 1 /* Use LDAPS implementation */ #cmakedefine HAVE_LDAP_SSL 1 /* Define to 1 if you have the ldap_ssl.h header file. */ #cmakedefine HAVE_LDAP_SSL_H 1 /* Define to 1 if you have the `ldap_url_parse' function. */ #cmakedefine HAVE_LDAP_URL_PARSE 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIBGEN_H 1 /* Define to 1 if you have the `idn' library (-lidn). */ #cmakedefine HAVE_LIBIDN 1 /* Define to 1 if you have the `resolv' library (-lresolv). */ #cmakedefine HAVE_LIBRESOLV 1 /* Define to 1 if you have the `resolve' library (-lresolve). */ #cmakedefine HAVE_LIBRESOLVE 1 /* Define to 1 if you have the `socket' library (-lsocket). */ #cmakedefine HAVE_LIBSOCKET 1 /* Define to 1 if you have the `ssh2' library (-lssh2). */ #cmakedefine HAVE_LIBSSH2 1 /* Define to 1 if libssh2 provides `libssh2_version'. */ #cmakedefine HAVE_LIBSSH2_VERSION 1 /* Define to 1 if libssh2 provides `libssh2_init'. */ #cmakedefine HAVE_LIBSSH2_INIT 1 /* Define to 1 if libssh2 provides `libssh2_exit'. */ #cmakedefine HAVE_LIBSSH2_EXIT 1 /* Define to 1 if libssh2 provides `libssh2_scp_send64'. */ #cmakedefine HAVE_LIBSSH2_SCP_SEND64 1 /* Define to 1 if libssh2 provides `libssh2_session_handshake'. */ #cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIBSSH2_H 1 /* if zlib is available */ #cmakedefine HAVE_LIBZ 1 /* if brotli is available */ #cmakedefine HAVE_BROTLI 1 /* if your compiler supports LL */ #cmakedefine HAVE_LL 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LOCALE_H 1 /* Define to 1 if you have a working localtime_r function. */ #cmakedefine HAVE_LOCALTIME_R 1 /* Define to 1 if the compiler supports the 'long long' data type. */ #cmakedefine HAVE_LONGLONG 1 /* Define to 1 if you have the malloc.h header file. */ #cmakedefine HAVE_MALLOC_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H 1 /* Define to 1 if you have the MSG_NOSIGNAL flag. */ #cmakedefine HAVE_MSG_NOSIGNAL 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NET_IF_H 1 /* Define to 1 if NI_WITHSCOPEID exists and works. */ #cmakedefine HAVE_NI_WITHSCOPEID 1 /* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ #cmakedefine HAVE_OLD_GSSMIT 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_CRYPTO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_ERR_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_PEM_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_PKCS12_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_RSA_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_X509_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PEM_H 1 /* Define to 1 if you have the `perror' function. */ #cmakedefine HAVE_PERROR 1 /* Define to 1 if you have the `pipe' function. */ #cmakedefine HAVE_PIPE 1 /* Define to 1 if you have a working poll function. */ #cmakedefine HAVE_POLL 1 /* If you have a fine poll */ #cmakedefine HAVE_POLL_FINE 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_POLL_H 1 /* Define to 1 if you have a working POSIX-style strerror_r function. */ #cmakedefine HAVE_POSIX_STRERROR_R 1 /* Define to 1 if you have the header file */ #cmakedefine HAVE_PTHREAD_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PWD_H 1 /* Define to 1 if you have the `RAND_egd' function. */ #cmakedefine HAVE_RAND_EGD 1 /* Define to 1 if you have the `RAND_screen' function. */ #cmakedefine HAVE_RAND_SCREEN 1 /* Define to 1 if you have the `RAND_status' function. */ #cmakedefine HAVE_RAND_STATUS 1 /* Define to 1 if you have the recv function. */ #cmakedefine HAVE_RECV 1 /* Define to 1 if you have the recvfrom function. */ #cmakedefine HAVE_RECVFROM 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_RSA_H 1 /* Define to 1 if you have the select function. */ #cmakedefine HAVE_SELECT 1 /* Define to 1 if you have the send function. */ #cmakedefine HAVE_SEND 1 /* Define to 1 if you have the 'fsetxattr' function. */ #cmakedefine HAVE_FSETXATTR 1 /* fsetxattr() takes 5 args */ #cmakedefine HAVE_FSETXATTR_5 1 /* fsetxattr() takes 6 args */ #cmakedefine HAVE_FSETXATTR_6 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SETJMP_H 1 /* Define to 1 if you have the `setlocale' function. */ #cmakedefine HAVE_SETLOCALE 1 /* Define to 1 if you have the `setmode' function. */ #cmakedefine HAVE_SETMODE 1 /* Define to 1 if you have the `setrlimit' function. */ #cmakedefine HAVE_SETRLIMIT 1 /* Define to 1 if you have the setsockopt function. */ #cmakedefine HAVE_SETSOCKOPT 1 /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ #cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SGTTY_H 1 /* Define to 1 if you have the sigaction function. */ #cmakedefine HAVE_SIGACTION 1 /* Define to 1 if you have the siginterrupt function. */ #cmakedefine HAVE_SIGINTERRUPT 1 /* Define to 1 if you have the signal function. */ #cmakedefine HAVE_SIGNAL 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SIGNAL_H 1 /* Define to 1 if you have the sigsetjmp function or macro. */ #cmakedefine HAVE_SIGSETJMP 1 /* Define to 1 if sig_atomic_t is an available typedef. */ #cmakedefine HAVE_SIG_ATOMIC_T 1 /* Define to 1 if sig_atomic_t is already defined as volatile. */ #cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1 /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define to 1 if you have the `socket' function. */ #cmakedefine HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SSL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H 1 /* Define to 1 if you have the strcasecmp function. */ #cmakedefine HAVE_STRCASECMP 1 /* Define to 1 if you have the strcasestr function. */ #cmakedefine HAVE_STRCASESTR 1 /* Define to 1 if you have the strcmpi function. */ #cmakedefine HAVE_STRCMPI 1 /* Define to 1 if you have the strdup function. */ #cmakedefine HAVE_STRDUP 1 /* Define to 1 if you have the strerror_r function. */ #cmakedefine HAVE_STRERROR_R 1 /* Define to 1 if you have the stricmp function. */ #cmakedefine HAVE_STRICMP 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H 1 /* Define to 1 if you have the strlcat function. */ #cmakedefine HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ #cmakedefine HAVE_STRLCPY 1 /* Define to 1 if you have the strncasecmp function. */ #cmakedefine HAVE_STRNCASECMP 1 /* Define to 1 if you have the strncmpi function. */ #cmakedefine HAVE_STRNCMPI 1 /* Define to 1 if you have the strnicmp function. */ #cmakedefine HAVE_STRNICMP 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STROPTS_H 1 /* Define to 1 if you have the strstr function. */ #cmakedefine HAVE_STRSTR 1 /* Define to 1 if you have the strtok_r function. */ #cmakedefine HAVE_STRTOK_R 1 /* Define to 1 if you have the strtoll function. */ #cmakedefine HAVE_STRTOLL 1 /* if struct sockaddr_storage is defined */ #cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if you have the timeval struct. */ #cmakedefine HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_FILIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UTIME_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIO_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TLD_H 1 /* Define to 1 if you have the `tld_strerror' function. */ #cmakedefine HAVE_TLD_STRERROR 1 /* Define to 1 if you have the `uname' function. */ #cmakedefine HAVE_UNAME 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* Define to 1 if you have the `utime' function. */ #cmakedefine HAVE_UTIME 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UTIME_H 1 /* Define to 1 if compiler supports C99 variadic macro style. */ #cmakedefine HAVE_VARIADIC_MACROS_C99 1 /* Define to 1 if compiler supports old gcc variadic macro style. */ #cmakedefine HAVE_VARIADIC_MACROS_GCC 1 /* Define to 1 if you have the winber.h header file. */ #cmakedefine HAVE_WINBER_H 1 /* Define to 1 if you have the windows.h header file. */ #cmakedefine HAVE_WINDOWS_H 1 /* Define to 1 if you have the winldap.h header file. */ #cmakedefine HAVE_WINLDAP_H 1 /* Define to 1 if you have the winsock2.h header file. */ #cmakedefine HAVE_WINSOCK2_H 1 /* Define to 1 if you have the winsock.h header file. */ #cmakedefine HAVE_WINSOCK_H 1 /* Define this symbol if your OS supports changing the contents of argv */ #cmakedefine HAVE_WRITABLE_ARGV 1 /* Define to 1 if you have the writev function. */ #cmakedefine HAVE_WRITEV 1 /* Define to 1 if you have the ws2tcpip.h header file. */ #cmakedefine HAVE_WS2TCPIP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X509_H 1 /* Define if you have the header file. */ #cmakedefine HAVE_PROCESS_H 1 /* if you have the zlib.h header file */ #cmakedefine HAVE_ZLIB_H 1 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #cmakedefine LT_OBJDIR ${LT_OBJDIR} /* If you lack a fine basename() prototype */ #cmakedefine NEED_BASENAME_PROTO 1 /* Define to 1 if you need the lber.h header file even with ldap.h */ #cmakedefine NEED_LBER_H 1 /* Define to 1 if you need the malloc.h header file even with stdlib.h */ #cmakedefine NEED_MALLOC_H 1 /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ #cmakedefine NEED_REENTRANT 1 /* cpu-machine-OS */ #cmakedefine OS ${OS} /* Name of package */ #cmakedefine PACKAGE ${PACKAGE} /* Define to the address where bug reports for this package should be sent. */ #cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT} /* Define to the full name of this package. */ #cmakedefine PACKAGE_NAME ${PACKAGE_NAME} /* Define to the full name and version of this package. */ #cmakedefine PACKAGE_STRING ${PACKAGE_STRING} /* Define to the one symbol short name of this package. */ #cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME} /* Define to the version of this package. */ #cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION} /* a suitable file to read random data from */ #cmakedefine RANDOM_FILE "${RANDOM_FILE}" /* Define to the type of arg 1 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1} /* Define to the type pointed by arg 2 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2} /* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ #cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1 /* Define to the type of arg 3 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3} /* Define to the type of arg 4 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4} /* Define to the type pointed by arg 5 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5} /* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ #cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1 /* Define to the type pointed by arg 6 for recvfrom. */ #cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6} /* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ #cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1 /* Define to the function return type for recvfrom. */ #cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV} /* Define to the type of arg 1 for recv. */ #cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1} /* Define to the type of arg 2 for recv. */ #cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2} /* Define to the type of arg 3 for recv. */ #cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3} /* Define to the type of arg 4 for recv. */ #cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4} /* Define to the function return type for recv. */ #cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV} /* Define as the return type of signal handlers (`int' or `void'). */ #cmakedefine RETSIGTYPE ${RETSIGTYPE} /* Define to the type qualifier of arg 5 for select. */ #cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5} /* Define to the type of arg 1 for select. */ #cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1} /* Define to the type of args 2, 3 and 4 for select. */ #cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234} /* Define to the type of arg 5 for select. */ #cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5} /* Define to the function return type for select. */ #cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV} /* Define to the type qualifier of arg 2 for send. */ #cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2} /* Define to the type of arg 1 for send. */ #cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1} /* Define to the type of arg 2 for send. */ #cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2} /* Define to the type of arg 3 for send. */ #cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3} /* Define to the type of arg 4 for send. */ #cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4} /* Define to the function return type for send. */ #cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV} /* Note: SIZEOF_* variables are fetched with CMake through check_type_size(). As per CMake documentation on CheckTypeSize, C preprocessor code is generated by CMake into SIZEOF_*_CODE. This is what we use in the following statements. Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html */ /* The size of `int', as computed by sizeof. */ ${SIZEOF_INT_CODE} /* The size of `short', as computed by sizeof. */ ${SIZEOF_SHORT_CODE} /* The size of `long', as computed by sizeof. */ ${SIZEOF_LONG_CODE} /* The size of `off_t', as computed by sizeof. */ ${SIZEOF_OFF_T_CODE} /* The size of `curl_off_t', as computed by sizeof. */ ${SIZEOF_CURL_OFF_T_CODE} /* The size of `size_t', as computed by sizeof. */ ${SIZEOF_SIZE_T_CODE} /* The size of `time_t', as computed by sizeof. */ ${SIZEOF_TIME_T_CODE} /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS 1 /* Define to the type of arg 3 for strerror_r. */ #cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3} /* Define to 1 if you can safely include both and . */ #cmakedefine TIME_WITH_SYS_TIME 1 /* Define if you want to enable c-ares support */ #cmakedefine USE_ARES 1 /* Define if you want to enable POSIX threaded DNS lookup */ #cmakedefine USE_THREADS_POSIX 1 /* Define if you want to enable WIN32 threaded DNS lookup */ #cmakedefine USE_THREADS_WIN32 1 /* Define to disable non-blocking sockets. */ #cmakedefine USE_BLOCKING_SOCKETS 1 /* if GnuTLS is enabled */ #cmakedefine USE_GNUTLS 1 /* if Secure Transport is enabled */ #cmakedefine USE_SECTRANSP 1 /* if mbedTLS is enabled */ #cmakedefine USE_MBEDTLS 1 /* if BearSSL is enabled */ #cmakedefine USE_BEARSSL 1 /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 /* If you want to build curl with the built-in manual */ #cmakedefine USE_MANUAL 1 /* if NSS is enabled */ #cmakedefine USE_NSS 1 /* if you have the PK11_CreateManagedGenericObject function */ #cmakedefine HAVE_PK11_CREATEMANAGEDGENERICOBJECT 1 /* if you want to use OpenLDAP code instead of legacy ldap implementation */ #cmakedefine USE_OPENLDAP 1 /* if OpenSSL is in use */ #cmakedefine USE_OPENSSL 1 /* to enable NGHTTP2 */ #cmakedefine USE_NGHTTP2 1 /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS /* Define to 1 if you are building a Windows target with large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 /* to enable SSPI support */ #cmakedefine USE_WINDOWS_SSPI 1 /* to enable Windows SSL */ #cmakedefine USE_SCHANNEL 1 /* enable multiple SSL backends */ #cmakedefine CURL_WITH_MULTI_SSL 1 /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ #cmakedefine USE_YASSLEMUL 1 /* Version number of package */ #cmakedefine VERSION ${VERSION} /* Define to 1 if OS is AIX. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Number of bits in a file offset, on hosts where this is settable. */ #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} /* Define for large files, on AIX-style hosts. */ #cmakedefine _LARGE_FILES ${_LARGE_FILES} /* define this if you need it to compile thread-safe code */ #cmakedefine _THREAD_SAFE ${_THREAD_SAFE} /* Define to empty if `const' does not conform to ANSI C. */ #cmakedefine const ${const} /* Type to use in place of in_addr_t when system does not provide it. */ #cmakedefine in_addr_t ${in_addr_t} /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `unsigned int' if does not define. */ #cmakedefine size_t ${size_t} /* the signed version of size_t */ #cmakedefine ssize_t ${ssize_t} /* Define to 1 if you have the mach_absolute_time function. */ #cmakedefine HAVE_MACH_ABSOLUTE_TIME 1 davix-0.8.0/deps/curl/lib/smtp.c0000644000000000000000000015613614121063461015137 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC1870 SMTP Service Extension for Message Size * RFC2195 CRAM-MD5 authentication * RFC2831 DIGEST-MD5 authentication * RFC3207 SMTP over TLS * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * RFC4954 SMTP Authentication * RFC5321 SMTP protocol * RFC5890 Internationalized Domain Names for Applications (IDNA) * RFC6531 SMTP Extension for Internationalized Email * RFC6532 Internationalized Email Headers * RFC6749 OAuth 2.0 Authorization Framework * RFC8314 Use of TLS for Email Submission and Access * Draft SMTP URL Interface * Draft LOGIN SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_SMTP #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "mime.h" #include "socks.h" #include "smtp.h" #include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Local API functions */ static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done); static CURLcode smtp_do(struct connectdata *conn, bool *done); static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode smtp_connect(struct connectdata *conn, bool *done); static CURLcode smtp_disconnect(struct connectdata *conn, bool dead); static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done); static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode smtp_setup_connection(struct connectdata *conn); static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn); static CURLcode smtp_parse_custom_request(struct connectdata *conn); static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, char **address, struct hostname *host); static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); static void smtp_get_message(char *buffer, char **outptr); /* * SMTP protocol handler. */ const struct Curl_handler Curl_handler_smtp = { "SMTP", /* scheme */ smtp_setup_connection, /* setup_connection */ smtp_do, /* do_it */ smtp_done, /* done */ ZERO_NULL, /* do_more */ smtp_connect, /* connect_it */ smtp_multi_statemach, /* connecting */ smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SMTP, /* defport */ CURLPROTO_SMTP, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ PROTOPT_URLOPTIONS }; #ifdef USE_SSL /* * SMTPS protocol handler. */ const struct Curl_handler Curl_handler_smtps = { "SMTPS", /* scheme */ smtp_setup_connection, /* setup_connection */ smtp_do, /* do_it */ smtp_done, /* done */ ZERO_NULL, /* do_more */ smtp_connect, /* connect_it */ smtp_multi_statemach, /* connecting */ smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SMTPS, /* defport */ CURLPROTO_SMTPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif /* SASL parameters for the smtp protocol */ static const struct SASLproto saslsmtp = { "smtp", /* The service name */ 334, /* Code received when continuation is expected */ 235, /* Code to receive upon authentication success */ 512 - 8, /* Maximum initial response length (no max) */ smtp_perform_auth, /* Send authentication command */ smtp_continue_auth, /* Send authentication continuation */ smtp_get_message /* Get SASL response message */ }; #ifdef USE_SSL static void smtp_to_smtps(struct connectdata *conn) { /* Change the connection handler */ conn->handler = &Curl_handler_smtps; /* Set the connection's upgraded to TLS flag */ conn->tls_upgraded = TRUE; } #else #define smtp_to_smtps(x) Curl_nop_stmt #endif /*********************************************************************** * * smtp_endofresp() * * Checks for an ending SMTP status code at the start of the given string, but * also detects various capabilities from the EHLO response including the * supported authentication mechanisms. */ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len, int *resp) { struct smtp_conn *smtpc = &conn->proto.smtpc; bool result = FALSE; /* Nothing for us */ if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2])) return FALSE; /* Do we have a command response? This should be the response code followed by a space and optionally some text as per RFC-5321 and as outlined in Section 4. Examples of RFC-4954 but some e-mail servers ignore this and only send the response code instead as per Section 4.2. */ if(line[3] == ' ' || len == 5) { char tmpline[6]; result = TRUE; memset(tmpline, '\0', sizeof(tmpline)); memcpy(tmpline, line, (len == 5 ? 5 : 3)); *resp = curlx_sltosi(strtol(tmpline, NULL, 10)); /* Make sure real server never sends internal value */ if(*resp == 1) *resp = 0; } /* Do we have a multiline (continuation) response? */ else if(line[3] == '-' && (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) { result = TRUE; *resp = 1; /* Internal response code */ } return result; } /*********************************************************************** * * smtp_get_message() * * Gets the authentication message from the response buffer. */ static void smtp_get_message(char *buffer, char **outptr) { size_t len = strlen(buffer); char *message = NULL; if(len > 4) { /* Find the start of the message */ len -= 4; for(message = buffer + 4; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ for(; len--;) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ if(++len) { message[len] = '\0'; } } else /* junk input => zero length output */ message = &buffer[len]; *outptr = message; } /*********************************************************************** * * state() * * This is the ONLY way to change SMTP state! */ static void state(struct connectdata *conn, smtpstate newstate) { struct smtp_conn *smtpc = &conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { "STOP", "SERVERGREET", "EHLO", "HELO", "STARTTLS", "UPGRADETLS", "AUTH", "COMMAND", "MAIL", "RCPT", "DATA", "POSTDATA", "QUIT", /* LAST */ }; if(smtpc->state != newstate) infof(conn->data, "SMTP %p state change from %s to %s\n", (void *)smtpc, names[smtpc->state], names[newstate]); #endif smtpc->state = newstate; } /*********************************************************************** * * smtp_perform_ehlo() * * Sends the EHLO command to not only initialise communication with the ESMTP * server but to also obtain a list of server side supported capabilities. */ static CURLcode smtp_perform_ehlo(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */ smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism used for esmtp connections */ smtpc->tls_supported = FALSE; /* Clear the TLS capability */ smtpc->auth_supported = FALSE; /* Clear the AUTH capability */ /* Send the EHLO command */ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); if(!result) state(conn, SMTP_EHLO); return result; } /*********************************************************************** * * smtp_perform_helo() * * Sends the HELO command to initialise communication with the SMTP server. */ static CURLcode smtp_perform_helo(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used in smtp connections */ /* Send the HELO command */ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); if(!result) state(conn, SMTP_HELO); return result; } /*********************************************************************** * * smtp_perform_starttls() * * Sends the STLS command to start the upgrade to TLS. */ static CURLcode smtp_perform_starttls(struct connectdata *conn) { /* Send the STARTTLS command */ CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS"); if(!result) state(conn, SMTP_STARTTLS); return result; } /*********************************************************************** * * smtp_perform_upgrade_tls() * * Performs the upgrade to TLS. */ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn) { /* Start the SSL connection */ struct smtp_conn *smtpc = &conn->proto.smtpc; CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); if(!result) { if(smtpc->state != SMTP_UPGRADETLS) state(conn, SMTP_UPGRADETLS); if(smtpc->ssldone) { smtp_to_smtps(conn); result = smtp_perform_ehlo(conn); } } return result; } /*********************************************************************** * * smtp_perform_auth() * * Sends an AUTH command allowing the client to login with the given SASL * authentication mechanism. */ static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, const char *initresp) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; if(initresp) { /* AUTH ... */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); } return result; } /*********************************************************************** * * smtp_continue_auth() * * Sends SASL continuation data or cancellation. */ static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) { struct smtp_conn *smtpc = &conn->proto.smtpc; return Curl_pp_sendf(&smtpc->pp, "%s", resp); } /*********************************************************************** * * smtp_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL * authentication mechanism. */ static CURLcode smtp_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; saslprogress progress; /* Check we have enough data to authenticate with, and the server supports authentiation, and end the connect phase if not */ if(!smtpc->auth_supported || !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { state(conn, SMTP_STOP); return result; } /* Calculate the SASL login details */ result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress); if(!result) { if(progress == SASL_INPROGRESS) state(conn, SMTP_AUTH); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; } } return result; } /*********************************************************************** * * smtp_perform_command() * * Sends a SMTP based command. */ static CURLcode smtp_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; if(smtp->rcpt) { /* We notify the server we are sending UTF-8 data if a) it supports the SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in either the local address or host name parts. This is regardless of whether the host name is encoded using IDN ACE */ bool utf8 = FALSE; if((!smtp->custom) || (!smtp->custom[0])) { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; /* Parse the mailbox to verify into the local address and host name parts, converting the host name to an IDN A-label if necessary */ result = smtp_parse_address(conn, smtp->rcpt->data, &address, &host); if(result) return result; /* Establish whether we should report SMTPUTF8 to the server for this mailbox as per RFC-6531 sect. 3.1 point 6 */ utf8 = (conn->proto.smtpc.utf8_supported) && ((host.encalloc) || (!Curl_is_ASCII_name(address)) || (!Curl_is_ASCII_name(host.name))); /* Send the VRFY command (Note: The host name part may be absent when the host is a local system) */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "VRFY %s%s%s%s", address, host.name ? "@" : "", host.name ? host.name : "", utf8 ? " SMTPUTF8" : ""); Curl_free_idnconverted_hostname(&host); free(address); } else { /* Establish whether we should report that we support SMTPUTF8 for EXPN commands to the server as per RFC-6531 sect. 3.1 point 6 */ utf8 = (conn->proto.smtpc.utf8_supported) && (!strcmp(smtp->custom, "EXPN")); /* Send the custom recipient based command such as the EXPN command */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s%s", smtp->custom, smtp->rcpt->data, utf8 ? " SMTPUTF8" : ""); } } else /* Send the non-recipient based command such as HELP */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", smtp->custom && smtp->custom[0] != '\0' ? smtp->custom : "HELP"); if(!result) state(conn, SMTP_COMMAND); return result; } /*********************************************************************** * * smtp_perform_mail() * * Sends an MAIL command to initiate the upload of a message. */ static CURLcode smtp_perform_mail(struct connectdata *conn) { char *from = NULL; char *auth = NULL; char *size = NULL; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; /* We notify the server we are sending UTF-8 data if a) it supports the SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in either the local address or host name parts. This is regardless of whether the host name is encoded using IDN ACE */ bool utf8 = FALSE; /* Calculate the FROM parameter */ if(data->set.str[STRING_MAIL_FROM]) { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; /* Parse the FROM mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM], &address, &host); if(result) return result; /* Establish whether we should report SMTPUTF8 to the server for this mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ utf8 = (conn->proto.smtpc.utf8_supported) && ((host.encalloc) || (!Curl_is_ASCII_name(address)) || (!Curl_is_ASCII_name(host.name))); if(host.name) { from = aprintf("<%s@%s>", address, host.name); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we'll simply let the server worry about that and reply with a 501 error */ from = aprintf("<%s>", address); free(address); } else /* Null reverse-path, RFC-5321, sect. 3.6.3 */ from = strdup("<>"); if(!from) return CURLE_OUT_OF_MEMORY; /* Calculate the optional AUTH parameter */ if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) { if(data->set.str[STRING_MAIL_AUTH][0] != '\0') { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; /* Parse the AUTH mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH], &address, &host); if(result) { free(from); return result; } /* Establish whether we should report SMTPUTF8 to the server for this mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */ if((!utf8) && (conn->proto.smtpc.utf8_supported) && ((host.encalloc) || (!Curl_is_ASCII_name(address)) || (!Curl_is_ASCII_name(host.name)))) utf8 = TRUE; if(host.name) { free(from); from = aprintf("<%s@%s>", address, host.name); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we'll simply let the server worry about it */ auth = aprintf("<%s>", address); free(address); if(!from) return CURLE_OUT_OF_MEMORY; } else /* Empty AUTH, RFC-2554, sect. 5 */ auth = strdup("<>"); if(!auth) { free(from); return CURLE_OUT_OF_MEMORY; } } /* Prepare the mime data if some. */ if(data->set.mimepost.kind != MIMEKIND_NONE) { /* Use the whole structure as data. */ data->set.mimepost.flags &= ~MIME_BODY_ONLY; /* Add external headers and mime version. */ curl_mime_headers(&data->set.mimepost, data->set.headers, 0); result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, NULL, MIMESTRATEGY_MAIL); if(!result) if(!Curl_checkheaders(conn, "Mime-Version")) result = Curl_mime_add_header(&data->set.mimepost.curlheaders, "Mime-Version: 1.0"); /* Make sure we will read the entire mime structure. */ if(!result) result = Curl_mime_rewind(&data->set.mimepost); if(result) { free(from); free(auth); return result; } data->state.infilesize = Curl_mime_size(&data->set.mimepost); /* Read from mime structure. */ data->state.fread_func = (curl_read_callback) Curl_mime_read; data->state.in = (void *) &data->set.mimepost; } /* Calculate the optional SIZE parameter */ if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) { size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize); if(!size) { free(from); free(auth); return CURLE_OUT_OF_MEMORY; } } /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8 based address then quickly scan through the recipient list and check if any there do, as we need to correctly identify our support for SMTPUTF8 in the envelope, as per RFC-6531 sect. 3.4 */ if(conn->proto.smtpc.utf8_supported && !utf8) { struct SMTP *smtp = data->req.protop; struct curl_slist *rcpt = smtp->rcpt; while(rcpt && !utf8) { /* Does the host name contain non-ASCII characters? */ if(!Curl_is_ASCII_name(rcpt->data)) utf8 = TRUE; rcpt = rcpt->next; } } /* Send the MAIL command */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s%s%s%s%s%s", from, /* Mandatory */ auth ? " AUTH=" : "", /* Optional on AUTH support */ auth ? auth : "", /* */ size ? " SIZE=" : "", /* Optional on SIZE support */ size ? size : "", /* */ utf8 ? " SMTPUTF8" /* Internationalised mailbox */ : ""); /* included in our envelope */ free(from); free(auth); free(size); if(!result) state(conn, SMTP_MAIL); return result; } /*********************************************************************** * * smtp_perform_rcpt_to() * * Sends a RCPT TO command for a given recipient as part of the message upload * process. */ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; /* Parse the recipient mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ result = smtp_parse_address(conn, smtp->rcpt->data, &address, &host); if(result) return result; /* Send the RCPT TO command */ if(host.name) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", address, host.name); else /* An invalid mailbox was provided but we'll simply let the server worry about that and reply with a 501 error */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", address); Curl_free_idnconverted_hostname(&host); free(address); if(!result) state(conn, SMTP_RCPT); return result; } /*********************************************************************** * * smtp_perform_quit() * * Performs the quit action prior to sclose() being called. */ static CURLcode smtp_perform_quit(struct connectdata *conn) { /* Send the QUIT command */ CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT"); if(!result) state(conn, SMTP_QUIT); return result; } /* For the initial server greeting */ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode/100 != 2) { failf(data, "Got unexpected smtp-server response: %d", smtpcode); result = CURLE_WEIRD_SERVER_REPLY; } else result = smtp_perform_ehlo(conn); return result; } /* For STARTTLS responses */ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode != 220) { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied, code %d", smtpcode); result = CURLE_USE_SSL_FAILED; } else result = smtp_perform_authentication(conn); } else result = smtp_perform_upgrade_tls(conn); return result; } /* For EHLO responses */ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *line = data->state.buffer; size_t len = strlen(line); (void)instate; /* no use for this yet */ if(smtpcode/100 != 2 && smtpcode != 1) { if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) result = smtp_perform_helo(conn); else { failf(data, "Remote access denied: %d", smtpcode); result = CURLE_REMOTE_ACCESS_DENIED; } } else if(len >= 4) { line += 4; len -= 4; /* Does the server support the STARTTLS capability? */ if(len >= 8 && !memcmp(line, "STARTTLS", 8)) smtpc->tls_supported = TRUE; /* Does the server support the SIZE capability? */ else if(len >= 4 && !memcmp(line, "SIZE", 4)) smtpc->size_supported = TRUE; /* Does the server support the UTF-8 capability? */ else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8)) smtpc->utf8_supported = TRUE; /* Does the server support authentication? */ else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { smtpc->auth_supported = TRUE; /* Advance past the AUTH keyword */ line += 5; len -= 5; /* Loop through the data line */ for(;;) { size_t llen; size_t wordlen; unsigned int mechbit; while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { line++; len--; } if(!len) break; /* Extract the word */ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && line[wordlen] != '\t' && line[wordlen] != '\r' && line[wordlen] != '\n';) wordlen++; /* Test the word for a matching authentication mechanism */ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); if(mechbit && llen == wordlen) smtpc->sasl.authmechs |= mechbit; line += wordlen; len -= wordlen; } } if(smtpcode != 1) { if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested */ if(smtpc->tls_supported) /* Switch to TLS connection now */ result = smtp_perform_starttls(conn); else if(data->set.use_ssl == CURLUSESSL_TRY) /* Fallback and carry on with authentication */ result = smtp_perform_authentication(conn); else { failf(data, "STARTTLS not supported."); result = CURLE_USE_SSL_FAILED; } } else result = smtp_perform_authentication(conn); } } else { failf(data, "Unexpectedly short EHLO response"); result = CURLE_WEIRD_SERVER_REPLY; } return result; } /* For HELO responses */ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode/100 != 2) { failf(data, "Remote access denied: %d", smtpcode); result = CURLE_REMOTE_ACCESS_DENIED; } else /* End of connect phase */ state(conn, SMTP_STOP); return result; } /* For SASL authentication responses */ static CURLcode smtp_state_auth_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; saslprogress progress; (void)instate; /* no use for this yet */ result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); if(!result) switch(progress) { case SASL_DONE: state(conn, SMTP_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ failf(data, "Authentication cancelled"); result = CURLE_LOGIN_DENIED; break; default: break; } return result; } /* For command responses */ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *line = data->state.buffer; size_t len = strlen(line); (void)instate; /* no use for this yet */ if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { failf(data, "Command failed: %d", smtpcode); result = CURLE_RECV_ERROR; } else { /* Temporarily add the LF character back and send as body to the client */ if(!data->set.opt_no_body) { line[len] = '\n'; result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); line[len] = '\0'; } if(smtpcode != 1) { if(smtp->rcpt) { smtp->rcpt = smtp->rcpt->next; if(smtp->rcpt) { /* Send the next command */ result = smtp_perform_command(conn); } else /* End of DO phase */ state(conn, SMTP_STOP); } else /* End of DO phase */ state(conn, SMTP_STOP); } } return result; } /* For MAIL responses */ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode/100 != 2) { failf(data, "MAIL failed: %d", smtpcode); result = CURLE_SEND_ERROR; } else /* Start the RCPT TO command */ result = smtp_perform_rcpt_to(conn); return result; } /* For RCPT responses */ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; bool is_smtp_err = FALSE; bool is_smtp_blocking_err = FALSE; (void)instate; /* no use for this yet */ is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE; /* If there's multiple RCPT TO to be issued, it's possible to ignore errors and proceed with only the valid addresses. */ is_smtp_blocking_err = (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE; if(is_smtp_err) { /* Remembering the last failure which we can report if all "RCPT TO" have failed and we cannot proceed. */ smtp->rcpt_last_error = smtpcode; if(is_smtp_blocking_err) { failf(data, "RCPT failed: %d", smtpcode); result = CURLE_SEND_ERROR; } } else { /* Some RCPT TO commands have succeeded. */ smtp->rcpt_had_ok = TRUE; } if(!is_smtp_blocking_err) { smtp->rcpt = smtp->rcpt->next; if(smtp->rcpt) /* Send the next RCPT TO command */ result = smtp_perform_rcpt_to(conn); else { /* We weren't able to issue a successful RCPT TO command while going over recipients (potentially multiple). Sending back last error. */ if(!smtp->rcpt_had_ok) { failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error); result = CURLE_SEND_ERROR; } else { /* Send the DATA command */ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA"); if(!result) state(conn, SMTP_DATA); } } } return result; } /* For DATA response */ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode != 354) { failf(data, "DATA failed: %d", smtpcode); result = CURLE_SEND_ERROR; } else { /* Set the progress upload size */ Curl_pgrsSetUploadSize(data, data->state.infilesize); /* SMTP upload */ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* End of DO phase */ state(conn, SMTP_STOP); } return result; } /* For POSTDATA responses, which are received after the entire DATA part has been sent to the server */ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; (void)instate; /* no use for this yet */ if(smtpcode != 250) result = CURLE_RECV_ERROR; /* End of DONE phase */ state(conn, SMTP_STOP); return result; } static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; size_t nread = 0; /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */ if(smtpc->state == SMTP_UPGRADETLS) return smtp_perform_upgrade_tls(conn); /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); do { /* Read the response from the server */ result = Curl_pp_readresp(sock, pp, &smtpcode, &nread); if(result) return result; /* Store the latest response for later retrieval if necessary */ if(smtpc->state != SMTP_QUIT && smtpcode != 1) data->info.httpcode = smtpcode; if(!smtpcode) break; /* We have now received a full SMTP server response */ switch(smtpc->state) { case SMTP_SERVERGREET: result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state); break; case SMTP_EHLO: result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state); break; case SMTP_HELO: result = smtp_state_helo_resp(conn, smtpcode, smtpc->state); break; case SMTP_STARTTLS: result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state); break; case SMTP_AUTH: result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; case SMTP_COMMAND: result = smtp_state_command_resp(conn, smtpcode, smtpc->state); break; case SMTP_MAIL: result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); break; case SMTP_RCPT: result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state); break; case SMTP_DATA: result = smtp_state_data_resp(conn, smtpcode, smtpc->state); break; case SMTP_POSTDATA: result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state); break; case SMTP_QUIT: /* fallthrough, just stop! */ default: /* internal error */ state(conn, SMTP_STOP); break; } } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp)); return result; } /* Called repeatedly until done from multi.c */ static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) { result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone); if(result || !smtpc->ssldone) return result; } result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE); *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; return result; } static CURLcode smtp_block_statemach(struct connectdata *conn, bool disconnecting) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; while(smtpc->state != SMTP_STOP && !result) result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting); return result; } /* Allocate and initialize the SMTP struct for the current Curl_easy if required */ static CURLcode smtp_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp; smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); if(!smtp) result = CURLE_OUT_OF_MEMORY; return result; } /* For the SMTP "protocol connect" and "doing" phases only */ static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks) { return Curl_pp_getsock(&conn->proto.smtpc.pp, socks); } /*********************************************************************** * * smtp_connect() * * This function should do everything that is to be considered a part of * the connection phase. * * The variable pointed to by 'done' will be TRUE if the protocol-layer * connect phase is done when this function returns, or FALSE if not. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; *done = FALSE; /* default to not done yet */ /* We always support persistent connections in SMTP */ connkeep(conn, "SMTP default"); /* Set the default response time-out */ pp->response_time = RESP_TIMEOUT; pp->statemach_act = smtp_statemach_act; pp->endofresp = smtp_endofresp; pp->conn = conn; /* Initialize the SASL storage */ Curl_sasl_init(&smtpc->sasl, &saslsmtp); /* Initialise the pingpong layer */ Curl_pp_init(pp); /* Parse the URL options */ result = smtp_parse_url_options(conn); if(result) return result; /* Parse the URL path */ result = smtp_parse_url_path(conn); if(result) return result; /* Start off waiting for the server greeting response */ state(conn, SMTP_SERVERGREET); result = smtp_multi_statemach(conn, done); return result; } /*********************************************************************** * * smtp_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; struct pingpong *pp = &conn->proto.smtpc.pp; char *eob; ssize_t len; ssize_t bytes_written; (void)premature; if(!smtp || !pp->conn) return CURLE_OK; /* Cleanup our per-request based variables */ Curl_safefree(smtp->custom); if(status) { connclose(conn, "SMTP done with bad status"); /* marked for closure */ result = status; /* use the already set error code */ } else if(!data->set.connect_only && data->set.mail_rcpt && (data->set.upload || data->set.mimepost.kind)) { /* Calculate the EOB taking into account any terminating CRLF from the previous line of the email or the CRLF of the DATA command when there is "no mail data". RFC-5321, sect. 4.1.1.4. Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to fail when using a different pointer following a previous write, that returned CURLE_AGAIN, we duplicate the EOB now rather than when the bytes written doesn't equal len. */ if(smtp->trailing_crlf || !conn->data->state.infilesize) { eob = strdup(&SMTP_EOB[2]); len = SMTP_EOB_LEN - 2; } else { eob = strdup(SMTP_EOB); len = SMTP_EOB_LEN; } if(!eob) return CURLE_OUT_OF_MEMORY; /* Send the end of block data */ result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written); if(result) { free(eob); return result; } if(bytes_written != len) { /* The whole chunk was not sent so keep it around and adjust the pingpong structure accordingly */ pp->sendthis = eob; pp->sendsize = len; pp->sendleft = len - bytes_written; } else { /* Successfully sent so adjust the response timeout relative to now */ pp->response = Curl_now(); free(eob); } state(conn, SMTP_POSTDATA); /* Run the state-machine */ result = smtp_block_statemach(conn, FALSE); } /* Clear the transfer mode for the next request */ smtp->transfer = FTPTRANSFER_BODY; return result; } /*********************************************************************** * * smtp_perform() * * This is the actual DO function for SMTP. Transfer a mail, send a command * or get some data according to the options previously setup. */ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { /* This is SMTP and no proxy */ CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); if(data->set.opt_no_body) { /* Requested no body means no transfer */ smtp->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* Store the first recipient (or NULL if not specified) */ smtp->rcpt = data->set.mail_rcpt; /* Track of whether we've successfully sent at least one RCPT TO command */ smtp->rcpt_had_ok = FALSE; /* Track of the last error we've received by sending RCPT TO command */ smtp->rcpt_last_error = 0; /* Initial data character is the first character in line: it is implicitly preceded by a virtual CRLF. */ smtp->trailing_crlf = TRUE; smtp->eob = 2; /* Start the first command in the DO phase */ if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) /* MAIL transfer */ result = smtp_perform_mail(conn); else /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */ result = smtp_perform_command(conn); if(result) return result; /* Run the state-machine */ result = smtp_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); return result; } /*********************************************************************** * * smtp_do() * * This function is registered as 'curl_do' function. It decodes the path * parts etc as a wrapper to the actual DO function (smtp_perform). * * The input argument is already checked for validity. */ static CURLcode smtp_do(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ /* Parse the custom request */ result = smtp_parse_custom_request(conn); if(result) return result; result = smtp_regular_transfer(conn, done); return result; } /*********************************************************************** * * smtp_disconnect() * * Disconnect from an SMTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) { struct smtp_conn *smtpc = &conn->proto.smtpc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ /* The SMTP session may or may not have been allocated/setup at this point! */ if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart) if(!smtp_perform_quit(conn)) (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */ /* Disconnect from the server */ Curl_pp_disconnect(&smtpc->pp); /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, smtpc->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(smtpc->domain); return CURLE_OK; } /* Call this when the DO phase has completed */ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) { struct SMTP *smtp = conn->data->req.protop; (void)connected; if(smtp->transfer != FTPTRANSFER_BODY) /* no data to transfer */ Curl_setup_transfer(conn->data, -1, -1, FALSE, -1); return CURLE_OK; } /* Called from multi.c while DOing */ static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = smtp_multi_statemach(conn, dophase_done); if(result) DEBUGF(infof(conn->data, "DO phase failed\n")); else if(*dophase_done) { result = smtp_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /*********************************************************************** * * smtp_regular_transfer() * * The input argument is already checked for validity. * * Performs all commands done before a regular transfer between a local and a * remote host. */ static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; bool connected = FALSE; struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); /* Carry out the perform */ result = smtp_perform(conn, &connected, dophase_done); /* Perform post DO phase operations if necessary */ if(!result && *dophase_done) result = smtp_dophase_done(conn, connected); return result; } static CURLcode smtp_setup_connection(struct connectdata *conn) { CURLcode result; /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; /* Initialise the SMTP layer */ result = smtp_init(conn); if(result) return result; return CURLE_OK; } /*********************************************************************** * * smtp_parse_url_options() * * Parse the URL login options. */ static CURLcode smtp_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *ptr = conn->options; smtpc->sasl.resetprefs = TRUE; while(!result && ptr && *ptr) { const char *key = ptr; const char *value; while(*ptr && *ptr != '=') ptr++; value = ptr + 1; while(*ptr && *ptr != ';') ptr++; if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, value, ptr - value); else result = CURLE_URL_MALFORMAT; if(*ptr == ';') ptr++; } return result; } /*********************************************************************** * * smtp_parse_url_path() * * Parse the URL path into separate path components. */ static CURLcode smtp_parse_url_path(struct connectdata *conn) { /* The SMTP struct is already initialised in smtp_connect() */ struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *path = &data->state.up.path[1]; /* skip leading path */ char localhost[HOSTNAME_MAX + 1]; /* Calculate the path if necessary */ if(!*path) { if(!Curl_gethostname(localhost, sizeof(localhost))) path = localhost; else path = "localhost"; } /* URL decode the path and use it as the domain in our EHLO */ return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); } /*********************************************************************** * * smtp_parse_custom_request() * * Parse the custom request. */ static CURLcode smtp_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; /* URL decode the custom request */ if(custom) result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE); return result; } /*********************************************************************** * * smtp_parse_address() * * Parse the fully qualified mailbox address into a local address part and the * host name, converting the host name to an IDN A-label, as per RFC-5890, if * necessary. * * Parameters: * * conn [in] - The connection handle. * fqma [in] - The fully qualified mailbox address (which may or * may not contain UTF-8 characters). * address [in/out] - A new allocated buffer which holds the local * address part of the mailbox. This buffer must be * free'ed by the caller. * host [in/out] - The host name structure that holds the original, * and optionally encoded, host name. * Curl_free_idnconverted_hostname() must be called * once the caller has finished with the structure. * * Returns CURLE_OK on success. * * Notes: * * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor * that convertion then we shall return success. This allow the caller to send * the data to the server as a U-label (as per RFC-6531 sect. 3.2). * * If an mailbox '@' seperator cannot be located then the mailbox is considered * to be either a local mailbox or an invalid mailbox (depending on what the * calling function deems it to be) then the input will simply be returned in * the address part with the host name being NULL. */ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma, char **address, struct hostname *host) { CURLcode result = CURLE_OK; size_t length; /* Duplicate the fully qualified email address so we can manipulate it, ensuring it doesn't contain the delimiters if specified */ char *dup = strdup(fqma[0] == '<' ? fqma + 1 : fqma); if(!dup) return CURLE_OUT_OF_MEMORY; length = strlen(dup); if(dup[length - 1] == '>') dup[length - 1] = '\0'; /* Extract the host name from the addresss (if we can) */ host->name = strpbrk(dup, "@"); if(host->name) { *host->name = '\0'; host->name = host->name + 1; /* Attempt to convert the host name to IDN ACE */ (void) Curl_idnconvert_hostname(conn, host); /* If Curl_idnconvert_hostname() fails then we shall attempt to continue and send the host name using UTF-8 rather than as 7-bit ACE (which is our preference) */ } /* Extract the local address from the mailbox */ *address = dup; return result; } CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) { /* When sending a SMTP payload we must detect CRLF. sequences making sure they are sent as CRLF.. instead, as a . on the beginning of a line will be deleted by the server when not part of an EOB terminator and a genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of data by the server */ ssize_t i; ssize_t si; struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *scratch = data->state.scratch; char *newscratch = NULL; char *oldscratch = NULL; size_t eob_sent; /* Do we need to allocate a scratch buffer? */ if(!scratch || data->set.crlf) { oldscratch = scratch; scratch = newscratch = malloc(2 * data->set.upload_buffer_size); if(!newscratch) { failf(data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } } DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread); /* Have we already sent part of the EOB? */ eob_sent = smtp->eob; /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ for(i = 0, si = 0; i < nread; i++) { if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { smtp->eob++; /* Is the EOB potentially the terminating CRLF? */ if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob) smtp->trailing_crlf = TRUE; else smtp->trailing_crlf = FALSE; } else if(smtp->eob) { /* A previous substring matched so output that first */ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); si += smtp->eob - eob_sent; /* Then compare the first byte */ if(SMTP_EOB[0] == data->req.upload_fromhere[i]) smtp->eob = 1; else smtp->eob = 0; eob_sent = 0; /* Reset the trailing CRLF flag as there was more data */ smtp->trailing_crlf = FALSE; } /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */ if(SMTP_EOB_FIND_LEN == smtp->eob) { /* Copy the replacement data to the target buffer */ memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent], SMTP_EOB_REPL_LEN - eob_sent); si += SMTP_EOB_REPL_LEN - eob_sent; smtp->eob = 0; eob_sent = 0; } else if(!smtp->eob) scratch[si++] = data->req.upload_fromhere[i]; } if(smtp->eob - eob_sent) { /* A substring matched before processing ended so output that now */ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent); si += smtp->eob - eob_sent; } /* Only use the new buffer if we replaced something */ if(si != nread) { /* Upload from the new (replaced) buffer instead */ data->req.upload_fromhere = scratch; /* Save the buffer so it can be freed later */ data->state.scratch = scratch; /* Free the old scratch buffer */ free(oldscratch); /* Set the new amount too */ data->req.upload_present = si; } else free(newscratch); return CURLE_OK; } #endif /* CURL_DISABLE_SMTP */ davix-0.8.0/deps/curl/lib/curl_gssapi.h0000644000000000000000000000414014121063461016457 0ustar rootroot#ifndef HEADER_CURL_GSSAPI_H #define HEADER_CURL_GSSAPI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2011 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #ifdef HAVE_GSSAPI extern gss_OID_desc Curl_spnego_mech_oid; extern gss_OID_desc Curl_krb5_mech_oid; /* Common method for using GSS-API */ OM_uint32 Curl_gss_init_sec_context( struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, gss_OID mech_type, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, OM_uint32 *ret_flags); /* Helper to log a GSS-API error status */ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, OM_uint32 major, OM_uint32 minor); /* Provide some definitions missing in old headers */ #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name #define NCOMPAT 1 #endif /* Define our privacy and integrity protection values */ #define GSSAUTH_P_NONE 1 #define GSSAUTH_P_INTEGRITY 2 #define GSSAUTH_P_PRIVACY 4 #endif /* HAVE_GSSAPI */ #endif /* HEADER_CURL_GSSAPI_H */ davix-0.8.0/deps/curl/lib/connect.h0000644000000000000000000001215414121063461015601 0ustar rootroot#ifndef HEADER_CURL_CONNECT_H #define HEADER_CURL_CONNECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ #include "sockaddr.h" #include "timeval.h" CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected); CURLcode Curl_connecthost(struct connectdata *conn, const struct Curl_dns_entry *host); /* generic function that returns how much time there's left to run, according to the timeouts set */ timediff_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ /* * Used to extract socket and connectdata struct for the most recent * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp); bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, char *addr, long *port); /* * Check if a connection seems to be alive. */ bool Curl_connalive(struct connectdata *conn); #ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size */ void Curl_sndbufset(curl_socket_t sockfd); #else #define Curl_sndbufset(y) Curl_nop_stmt #endif void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd); void Curl_persistconninfo(struct connectdata *conn); int Curl_closesocket(struct connectdata *conn, curl_socket_t sock); /* * The Curl_sockaddr_ex structure is basically libcurl's external API * curl_sockaddr structure with enough space available to directly hold any * protocol-specific address structures. The variable declared here will be * used to pass / receive data to/from the fopensocket callback if this has * been set, before that, it is initialized from parameters. */ struct Curl_sockaddr_ex { int family; int socktype; int protocol; unsigned int addrlen; union { struct sockaddr addr; struct Curl_sockaddr_storage buff; } _sa_ex_u; }; #define sa_addr _sa_ex_u.addr /* * Create a socket based on info from 'conn' and 'ai'. * * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open * socket callback is set, used that! * */ CURLcode Curl_socket(struct connectdata *conn, const Curl_addrinfo *ai, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd); /* * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' * argument specifies if it is the end of a connection or a stream. * * For stream-based protocols (such as HTTP/2), a stream close will not cause * a connection close. Other protocols will close the connection for both * cases. * * It sets the bit.close bit to TRUE (with an explanation for debug builds), * when the connection will close. */ #define CONNCTRL_KEEP 0 /* undo a marked closure */ #define CONNCTRL_CONNECTION 1 #define CONNCTRL_STREAM 2 void Curl_conncontrol(struct connectdata *conn, int closeit #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) , const char *reason #endif ); #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) #define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) #define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) #else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */ #define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) #define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) #define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) #endif bool Curl_conn_data_pending(struct connectdata *conn, int sockindex); #endif /* HEADER_CURL_CONNECT_H */ davix-0.8.0/deps/curl/lib/multi.c0000644000000000000000000031377614121063461015313 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "transfer.h" #include "url.h" #include "connect.h" #include "progress.h" #include "easyif.h" #include "share.h" #include "psl.h" #include "multiif.h" #include "sendf.h" #include "timeval.h" #include "http.h" #include "select.h" #include "warnless.h" #include "speedcheck.h" #include "conncache.h" #include "multihandle.h" #include "sigpipe.h" #include "vtls/vtls.h" #include "connect.h" #include "http_proxy.h" #include "http2.h" #include "socketpair.h" #include "socks.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97 to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every CURL handle takes 45-50 K memory, therefore this 3K are not significant. */ #ifndef CURL_SOCKET_HASH_TABLE_SIZE #define CURL_SOCKET_HASH_TABLE_SIZE 911 #endif #ifndef CURL_CONNECTION_HASH_SIZE #define CURL_CONNECTION_HASH_SIZE 97 #endif #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ ((x) && (x)->type == CURL_MULTI_HANDLE) static CURLMcode singlesocket(struct Curl_multi *multi, struct Curl_easy *data); static CURLMcode add_next_timeout(struct curltime now, struct Curl_multi *multi, struct Curl_easy *d); static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms); static void process_pending_handles(struct Curl_multi *multi); static void detach_connnection(struct Curl_easy *data); #ifdef DEBUGBUILD static const char * const statename[]={ "INIT", "CONNECT_PEND", "CONNECT", "WAITRESOLVE", "WAITCONNECT", "WAITPROXYCONNECT", "SENDPROTOCONNECT", "PROTOCONNECT", "DO", "DOING", "DO_MORE", "DO_DONE", "PERFORM", "TOOFAST", "DONE", "COMPLETED", "MSGSENT", }; #endif /* function pointer called once when switching TO a state */ typedef void (*init_multistate_func)(struct Curl_easy *data); static void Curl_init_completed(struct Curl_easy *data) { /* this is a completed transfer */ /* Important: reset the conn pointer so that we don't point to memory that could be freed anytime */ detach_connnection(data); Curl_expire_clear(data); /* stop all timers */ } /* always use this function to change state, to make debugging easier */ static void mstate(struct Curl_easy *data, CURLMstate state #ifdef DEBUGBUILD , int lineno #endif ) { CURLMstate oldstate = data->mstate; static const init_multistate_func finit[CURLM_STATE_LAST] = { NULL, /* INIT */ NULL, /* CONNECT_PEND */ Curl_init_CONNECT, /* CONNECT */ NULL, /* WAITRESOLVE */ NULL, /* WAITCONNECT */ NULL, /* WAITPROXYCONNECT */ NULL, /* SENDPROTOCONNECT */ NULL, /* PROTOCONNECT */ Curl_connect_free, /* DO */ NULL, /* DOING */ NULL, /* DO_MORE */ NULL, /* DO_DONE */ NULL, /* PERFORM */ NULL, /* TOOFAST */ NULL, /* DONE */ Curl_init_completed, /* COMPLETED */ NULL /* MSGSENT */ }; #if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS) (void) lineno; #endif if(oldstate == state) /* don't bother when the new state is the same as the old state */ return; data->mstate = state; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) if(data->mstate >= CURLM_STATE_CONNECT_PEND && data->mstate < CURLM_STATE_COMPLETED) { long connection_id = -5000; if(data->conn) connection_id = data->conn->connection_id; infof(data, "STATE: %s => %s handle %p; line %d (connection #%ld)\n", statename[oldstate], statename[data->mstate], (void *)data, lineno, connection_id); } #endif if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ data->multi->num_alive--; /* if this state has an init-function, run it */ if(finit[state]) finit[state](data); } #ifndef DEBUGBUILD #define multistate(x,y) mstate(x,y) #else #define multistate(x,y) mstate(x,y, __LINE__) #endif /* * We add one of these structs to the sockhash for each socket */ struct Curl_sh_entry { struct curl_hash transfers; /* hash of transfers using this socket */ unsigned int action; /* what combined action READ/WRITE this socket waits for */ void *socketp; /* settable by users with curl_multi_assign() */ unsigned int users; /* number of transfers using this */ unsigned int readers; /* this many transfers want to read */ unsigned int writers; /* this many transfers want to write */ }; /* bits for 'action' having no bits means this socket is not expecting any action */ #define SH_READ 1 #define SH_WRITE 2 /* look up a given socket in the socket hash, skip invalid sockets */ static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh, curl_socket_t s) { if(s != CURL_SOCKET_BAD) { /* only look for proper sockets */ return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); } return NULL; } #define TRHASH_SIZE 13 static size_t trhash(void *key, size_t key_length, size_t slots_num) { size_t keyval = (size_t)*(struct Curl_easy **)key; (void) key_length; return (keyval % slots_num); } static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) { (void)k1_len; (void)k2_len; return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2; } static void trhash_dtor(void *nada) { (void)nada; } /* make sure this socket is present in the hash for this handle */ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, curl_socket_t s) { struct Curl_sh_entry *there = sh_getentry(sh, s); struct Curl_sh_entry *check; if(there) { /* it is present, return fine */ return there; } /* not present, add it */ check = calloc(1, sizeof(struct Curl_sh_entry)); if(!check) return NULL; /* major failure */ if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare, trhash_dtor)) { free(check); return NULL; } /* make/add new hash entry */ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { Curl_hash_destroy(&check->transfers); free(check); return NULL; /* major failure */ } return check; /* things are good in sockhash land */ } /* delete the given socket + handle from the hash */ static void sh_delentry(struct Curl_sh_entry *entry, struct curl_hash *sh, curl_socket_t s) { Curl_hash_destroy(&entry->transfers); /* We remove the hash entry. This will end up in a call to sh_freeentry(). */ Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); } /* * free a sockhash entry */ static void sh_freeentry(void *freethis) { struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; free(p); } static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) { (void) k1_len; (void) k2_len; return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); } static size_t hash_fd(void *key, size_t key_length, size_t slots_num) { curl_socket_t fd = *((curl_socket_t *) key); (void) key_length; return (fd % slots_num); } /* * sh_init() creates a new socket hash and returns the handle for it. * * Quote from README.multi_socket: * * "Some tests at 7000 and 9000 connections showed that the socket hash lookup * is somewhat of a bottle neck. Its current implementation may be a bit too * limiting. It simply has a fixed-size array, and on each entry in the array * it has a linked list with entries. So the hash only checks which list to * scan through. The code I had used so for used a list with merely 7 slots * (as that is what the DNS hash uses) but with 7000 connections that would * make an average of 1000 nodes in each list to run through. I upped that to * 97 slots (I believe a prime is suitable) and noticed a significant speed * increase. I need to reconsider the hash implementation or use a rather * large default value like this. At 9000 connections I was still below 10us * per call." * */ static int sh_init(struct curl_hash *hash, int hashsize) { return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare, sh_freeentry); } /* * multi_addmsg() * * Called when a transfer is completed. Adds the given msg pointer to * the list kept in the multi handle. */ static CURLMcode multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg, &msg->list); return CURLM_OK; } struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ int chashsize) /* connection hash */ { struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); if(!multi) return NULL; multi->type = CURL_MULTI_HANDLE; if(Curl_mk_dnscache(&multi->hostcache)) goto error; if(sh_init(&multi->sockhash, hashsize)) goto error; if(Curl_conncache_init(&multi->conn_cache, chashsize)) goto error; Curl_llist_init(&multi->msglist, NULL); Curl_llist_init(&multi->pending, NULL); multi->multiplexing = TRUE; /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; multi->max_concurrent_streams = 100; multi->ipv6_works = Curl_ipv6works(NULL); #ifdef ENABLE_WAKEUP if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) { multi->wakeup_pair[0] = CURL_SOCKET_BAD; multi->wakeup_pair[1] = CURL_SOCKET_BAD; } else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 || curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) { sclose(multi->wakeup_pair[0]); sclose(multi->wakeup_pair[1]); multi->wakeup_pair[0] = CURL_SOCKET_BAD; multi->wakeup_pair[1] = CURL_SOCKET_BAD; } #endif return multi; error: Curl_hash_destroy(&multi->sockhash); Curl_hash_destroy(&multi->hostcache); Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(&multi->msglist, NULL); Curl_llist_destroy(&multi->pending, NULL); free(multi); return NULL; } struct Curl_multi *curl_multi_init(void) { return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, CURL_CONNECTION_HASH_SIZE); } CURLMcode curl_multi_add_handle(struct Curl_multi *multi, struct Curl_easy *data) { /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from adding same easy handle more than once and prevent adding to more than one multi stack */ if(data->multi) return CURLM_ADDED_ALREADY; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; /* Initialize timeout list for this handle */ Curl_llist_init(&data->state.timeoutlist, NULL); /* * No failure allowed in this function beyond this point. And no * modification of easy nor multi handle allowed before this except for * potential multi's connection cache growing which won't be undone in this * function no matter what. */ if(data->set.errorbuffer) data->set.errorbuffer[0] = 0; /* set the easy handle */ multistate(data, CURLM_STATE_INIT); /* for multi interface connections, we share DNS cache automatically if the easy handle's one is currently not set. */ if(!data->dns.hostcache || (data->dns.hostcachetype == HCACHE_NONE)) { data->dns.hostcache = &multi->hostcache; data->dns.hostcachetype = HCACHE_MULTI; } /* Point to the shared or multi handle connection cache */ if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) data->state.conn_cache = &data->share->conn_cache; else data->state.conn_cache = &multi->conn_cache; #ifdef USE_LIBPSL /* Do the same for PSL. */ if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) data->psl = &data->share->psl; else data->psl = &multi->psl; #endif /* We add the new entry last in the list. */ data->next = NULL; /* end of the line */ if(multi->easyp) { struct Curl_easy *last = multi->easylp; last->next = data; data->prev = last; multi->easylp = data; /* the new last node */ } else { /* first node, make prev NULL! */ data->prev = NULL; multi->easylp = multi->easyp = data; /* both first and last */ } /* make the Curl_easy refer back to this multi handle */ data->multi = multi; /* Set the timeout for this handle to expire really soon so that it will be taken care of even when this handle is added in the midst of operation when only the curl_multi_socket() API is used. During that flow, only sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ Curl_expire(data, 0, EXPIRE_RUN_NOW); /* increase the node-counter */ multi->num_easy++; /* increase the alive-counter */ multi->num_alive++; /* A somewhat crude work-around for a little glitch in Curl_update_timer() that happens if the lastcall time is set to the same time when the handle is removed as when the next handle is added, as then the check in Curl_update_timer() that prevents calling the application multiple times with the same timer info will not trigger and then the new handle's timeout will not be notified to the app. The work-around is thus simply to clear the 'lastcall' variable to force Curl_update_timer() to always trigger a callback to the app when a new easy handle is added */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); /* The closure handle only ever has default timeouts set. To improve the state somewhat we clone the timeouts from each added handle so that the closure handle always has the same timeouts as the most recently added easy handle. */ data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; data->state.conn_cache->closure_handle->set.server_response_timeout = data->set.server_response_timeout; data->state.conn_cache->closure_handle->set.no_signal = data->set.no_signal; Curl_update_timer(multi); return CURLM_OK; } #if 0 /* Debug-function, used like this: * * Curl_hash_print(multi->sockhash, debug_print_sock_hash); * * Enable the hash print function first by editing hash.c */ static void debug_print_sock_hash(void *p) { struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; fprintf(stderr, " [easy %p/magic %x/socket %d]", (void *)sh->data, sh->data->magic, (int)sh->socket); } #endif static CURLcode multi_done(struct Curl_easy *data, CURLcode status, /* an error if this is called after an error was detected */ bool premature) { CURLcode result; struct connectdata *conn = data->conn; unsigned int i; DEBUGF(infof(data, "multi_done\n")); if(data->state.done) /* Stop if multi_done() has already been called */ return CURLE_OK; conn->data = data; /* ensure the connection uses this transfer now */ /* Stop the resolver and free its own resources (but not dns_entry yet). */ Curl_resolver_kill(conn); /* Cleanup possible redirect junk */ Curl_safefree(data->req.newurl); Curl_safefree(data->req.location); switch(status) { case CURLE_ABORTED_BY_CALLBACK: case CURLE_READ_ERROR: case CURLE_WRITE_ERROR: /* When we're aborted due to a callback return code it basically have to be counted as premature as there is trouble ahead if we don't. We have many callbacks and protocols work differently, we could potentially do this more fine-grained in the future. */ premature = TRUE; default: break; } /* this calls the protocol-specific function pointer previously set */ if(conn->handler->done) result = conn->handler->done(conn, status, premature); else result = status; if(CURLE_ABORTED_BY_CALLBACK != result) { /* avoid this if we already aborted by callback to avoid this calling another callback */ CURLcode rc = Curl_pgrsDone(conn); if(!result && rc) result = CURLE_ABORTED_BY_CALLBACK; } process_pending_handles(data->multi); /* connection / multiplex */ CONN_LOCK(data); detach_connnection(data); if(CONN_INUSE(conn)) { /* Stop if still used. */ /* conn->data must not remain pointing to this transfer since it is going away! Find another to own it! */ conn->data = conn->easyq.head->ptr; CONN_UNLOCK(data); DEBUGF(infof(data, "Connection still in use %zu, " "no more multi_done now!\n", conn->easyq.size)); return CURLE_OK; } conn->data = NULL; /* the connection now has no owner */ data->state.done = TRUE; /* called just now! */ if(conn->dns_entry) { Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ conn->dns_entry = NULL; } Curl_hostcache_prune(data); Curl_safefree(data->state.ulbuf); /* if the transfer was completed in a paused state there can be buffered data left to free */ for(i = 0; i < data->state.tempcount; i++) { free(data->state.tempwrite[i].buf); } data->state.tempcount = 0; /* if data->set.reuse_forbid is TRUE, it means the libcurl client has forced us to close this connection. This is ignored for requests taking place in a NTLM/NEGOTIATE authentication handshake if conn->bits.close is TRUE, it means that the connection should be closed in spite of all our efforts to be nice, due to protocol restrictions in our or the server's end if premature is TRUE, it means this connection was said to be DONE before the entire request operation is complete and thus we can't know in what state it is for re-using, so we're forced to close it. In a perfect world we can add code that keep track of if we really must close it here or not, but currently we have no such detail knowledge. */ if((data->set.reuse_forbid #if defined(USE_NTLM) && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || conn->proxy_ntlm_state == NTLMSTATE_TYPE2) #endif #if defined(USE_SPNEGO) && !(conn->http_negotiate_state == GSS_AUTHRECV || conn->proxy_negotiate_state == GSS_AUTHRECV) #endif ) || conn->bits.close || (premature && !(conn->handler->flags & PROTOPT_STREAM))) { CURLcode res2; connclose(conn, "disconnecting"); CONN_UNLOCK(data); res2 = Curl_disconnect(data, conn, premature); /* If we had an error already, make sure we return that one. But if we got a new error, return that. */ if(!result && res2) result = res2; } else { char buffer[256]; /* create string before returning the connection */ msnprintf(buffer, sizeof(buffer), "Connection #%ld to host %s left intact", conn->connection_id, conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->host.dispname); /* the connection is no longer in use by this transfer */ CONN_UNLOCK(data); if(Curl_conncache_return_conn(data, conn)) { /* remember the most recently used connection */ data->state.lastconnect = conn; infof(data, "%s\n", buffer); } else data->state.lastconnect = NULL; } Curl_free_request_state(data); return result; } CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, struct Curl_easy *data) { struct Curl_easy *easy = data; bool premature; bool easy_owns_conn; struct curl_llist_element *e; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from trying to remove same easy handle more than once */ if(!data->multi) return CURLM_OK; /* it is already removed so let's say it is fine! */ if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; easy_owns_conn = (data->conn && (data->conn->data == easy)) ? TRUE : FALSE; /* If the 'state' is not INIT or COMPLETED, we might need to do something nice to put the easy_handle in a good known state when this returns. */ if(premature) { /* this handle is "alive" so we need to count down the total number of alive connections when this is removed */ multi->num_alive--; } if(data->conn && data->mstate > CURLM_STATE_DO && data->mstate < CURLM_STATE_COMPLETED) { /* Set connection owner so that the DONE function closes it. We can safely do this here since connection is killed. */ data->conn->data = easy; streamclose(data->conn, "Removed with partial response"); easy_owns_conn = TRUE; } if(data->conn) { /* we must call multi_done() here (if we still own the connection) so that we don't leave a half-baked one around */ if(easy_owns_conn) { /* multi_done() clears the association between the easy handle and the connection. Note that this ignores the return code simply because there's nothing really useful to do with it anyway! */ (void)multi_done(data, data->result, premature); } } /* The timer must be shut down before data->multi is set to NULL, else the timenode will remain in the splay tree after curl_easy_cleanup is called. Do it after multi_done() in case that sets another time! */ Curl_expire_clear(data); if(data->connect_queue.ptr) /* the handle was in the pending list waiting for an available connection, so go ahead and remove it */ Curl_llist_remove(&multi->pending, &data->connect_queue, NULL); if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache, *after* the possible multi_done() call above */ data->dns.hostcache = NULL; data->dns.hostcachetype = HCACHE_NONE; } Curl_wildcard_dtor(&data->wildcard); /* destroy the timeout list that is held in the easy handle, do this *after* multi_done() as that may actually call Curl_expire that uses this */ Curl_llist_destroy(&data->state.timeoutlist, NULL); /* as this was using a shared connection cache we clear the pointer to that since we're not part of that multi handle anymore */ data->state.conn_cache = NULL; /* change state without using multistate(), only to make singlesocket() do what we want */ data->mstate = CURLM_STATE_COMPLETED; singlesocket(multi, easy); /* to let the application know what sockets that vanish with this handle */ /* Remove the association between the connection and the handle */ if(data->conn) detach_connnection(data); #ifdef USE_LIBPSL /* Remove the PSL association. */ if(data->psl == &multi->psl) data->psl = NULL; #endif data->multi = NULL; /* clear the association to this multi handle */ /* make sure there's no pending message in the queue sent from this easy handle */ for(e = multi->msglist.head; e; e = e->next) { struct Curl_message *msg = e->ptr; if(msg->extmsg.easy_handle == easy) { Curl_llist_remove(&multi->msglist, e, NULL); /* there can only be one from this specific handle */ break; } } /* make the previous node point to our next */ if(data->prev) data->prev->next = data->next; else multi->easyp = data->next; /* point to first node */ /* make our next point to our previous node */ if(data->next) data->next->prev = data->prev; else multi->easylp = data->prev; /* point to last node */ /* NOTE NOTE NOTE We do not touch the easy handle here! */ multi->num_easy--; /* one less to care about now */ Curl_update_timer(multi); return CURLM_OK; } /* Return TRUE if the application asked for multiplexing */ bool Curl_multiplex_wanted(const struct Curl_multi *multi) { return (multi && (multi->multiplexing)); } /* This is the only function that should clear data->conn. This will occasionally be called with the pointer already cleared. */ static void detach_connnection(struct Curl_easy *data) { struct connectdata *conn = data->conn; if(conn) Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); data->conn = NULL; } /* This is the only function that should assign data->conn */ void Curl_attach_connnection(struct Curl_easy *data, struct connectdata *conn) { DEBUGASSERT(!data->conn); DEBUGASSERT(conn); data->conn = conn; Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data, &data->conn_queue); } static int waitconnect_getsock(struct connectdata *conn, curl_socket_t *sock) { int i; int s = 0; int rc = 0; #ifdef USE_SSL if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return Curl_ssl_getsock(conn, sock); #endif if(SOCKS_STATE(conn->cnnct.state)) return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET); for(i = 0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { sock[s] = conn->tempsock[i]; rc |= GETSOCK_WRITESOCK(s); #ifdef ENABLE_QUIC if(conn->transport == TRNSPRT_QUIC) /* when connecting QUIC, we want to read the socket too */ rc |= GETSOCK_READSOCK(s); #endif s++; } } return rc; } static int waitproxyconnect_getsock(struct connectdata *conn, curl_socket_t *sock) { sock[0] = conn->sock[FIRSTSOCKET]; /* when we've sent a CONNECT to a proxy, we should rather wait for the socket to become readable to be able to get the response headers */ if(conn->connect_state) return GETSOCK_READSOCK(0); return GETSOCK_WRITESOCK(0); } static int domore_getsock(struct connectdata *conn, curl_socket_t *socks) { if(conn && conn->handler->domore_getsock) return conn->handler->domore_getsock(conn, socks); return GETSOCK_BLANK; } static int doing_getsock(struct connectdata *conn, curl_socket_t *socks) { if(conn && conn->handler->doing_getsock) return conn->handler->doing_getsock(conn, socks); return GETSOCK_BLANK; } static int protocol_getsock(struct connectdata *conn, curl_socket_t *socks) { if(conn->handler->proto_getsock) return conn->handler->proto_getsock(conn, socks); /* Backup getsock logic. Since there is a live socket in use, we must wait for it or it will be removed from watching when the multi_socket API is used. */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); } /* returns bitmapped flags for this handle and its sockets. The 'socks[]' array contains MAX_SOCKSPEREASYHANDLE entries. */ static int multi_getsock(struct Curl_easy *data, curl_socket_t *socks) { /* The no connection case can happen when this is called from curl_multi_remove_handle() => singlesocket() => multi_getsock(). */ if(!data->conn) return 0; if(data->mstate > CURLM_STATE_CONNECT && data->mstate < CURLM_STATE_COMPLETED) { /* Set up ownership correctly */ data->conn->data = data; } switch(data->mstate) { default: #if 0 /* switch back on these cases to get the compiler to check for all enums to be present */ case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */ case CURLM_STATE_COMPLETED: case CURLM_STATE_MSGSENT: case CURLM_STATE_INIT: case CURLM_STATE_CONNECT: case CURLM_STATE_WAITDO: case CURLM_STATE_DONE: case CURLM_STATE_LAST: /* this will get called with CURLM_STATE_COMPLETED when a handle is removed */ #endif return 0; case CURLM_STATE_WAITRESOLVE: return Curl_resolv_getsock(data->conn, socks); case CURLM_STATE_PROTOCONNECT: case CURLM_STATE_SENDPROTOCONNECT: return protocol_getsock(data->conn, socks); case CURLM_STATE_DO: case CURLM_STATE_DOING: return doing_getsock(data->conn, socks); case CURLM_STATE_WAITPROXYCONNECT: return waitproxyconnect_getsock(data->conn, socks); case CURLM_STATE_WAITCONNECT: return waitconnect_getsock(data->conn, socks); case CURLM_STATE_DO_MORE: return domore_getsock(data->conn, socks); case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch to waiting for the same as the *PERFORM states */ case CURLM_STATE_PERFORM: return Curl_single_getsock(data->conn, socks); } } CURLMcode curl_multi_fdset(struct Curl_multi *multi, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd) { /* Scan through all the easy handles to get the file descriptors set. Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ struct Curl_easy *data; int this_max_fd = -1; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int i; (void)exc_fd_set; /* not used */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; data = multi->easyp; while(data) { int bitmap = multi_getsock(data, sockbunch); for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], read_fd_set); s = sockbunch[i]; } if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], write_fd_set); s = sockbunch[i]; } if(s == CURL_SOCKET_BAD) /* this socket is unused, break out of loop */ break; if((int)s > this_max_fd) this_max_fd = (int)s; } data = data->next; /* check next handle */ } *max_fd = this_max_fd; return CURLM_OK; } #define NUM_POLLS_ON_STACK 10 static CURLMcode Curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret, bool extrawait, /* when no socket, wait */ bool use_wakeup) { struct Curl_easy *data; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; unsigned int i; unsigned int nfds = 0; unsigned int curlfds; bool ufds_malloc = FALSE; long timeout_internal; int retcode = 0; struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; struct pollfd *ufds = &a_few_on_stack[0]; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; if(timeout_ms < 0) return CURLM_BAD_FUNCTION_ARGUMENT; /* Count up how many fds we have from the multi handle */ data = multi->easyp; while(data) { bitmap = multi_getsock(data, sockbunch); for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if(bitmap & GETSOCK_READSOCK(i)) { ++nfds; s = sockbunch[i]; } if(bitmap & GETSOCK_WRITESOCK(i)) { ++nfds; s = sockbunch[i]; } if(s == CURL_SOCKET_BAD) { break; } } data = data->next; /* check next handle */ } /* If the internally desired timeout is actually shorter than requested from the outside, then use the shorter time! But only if the internal timer is actually larger than -1! */ (void)multi_timeout(multi, &timeout_internal); if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) timeout_ms = (int)timeout_internal; curlfds = nfds; /* number of internal file descriptors */ nfds += extra_nfds; /* add the externally provided ones */ #ifdef ENABLE_WAKEUP if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { ++nfds; } #endif if(nfds > NUM_POLLS_ON_STACK) { /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes big, so at 2^29 sockets this value might wrap. When a process gets the capability to actually handle over 500 million sockets this calculation needs a integer overflow check. */ ufds = malloc(nfds * sizeof(struct pollfd)); if(!ufds) return CURLM_OUT_OF_MEMORY; ufds_malloc = TRUE; } nfds = 0; /* only do the second loop if we found descriptors in the first stage run above */ if(curlfds) { /* Add the curl handles to our pollfds first */ data = multi->easyp; while(data) { bitmap = multi_getsock(data, sockbunch); for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; if(bitmap & GETSOCK_READSOCK(i)) { ufds[nfds].fd = sockbunch[i]; ufds[nfds].events = POLLIN; ++nfds; s = sockbunch[i]; } if(bitmap & GETSOCK_WRITESOCK(i)) { ufds[nfds].fd = sockbunch[i]; ufds[nfds].events = POLLOUT; ++nfds; s = sockbunch[i]; } if(s == CURL_SOCKET_BAD) { break; } } data = data->next; /* check next handle */ } } /* Add external file descriptions from poll-like struct curl_waitfd */ for(i = 0; i < extra_nfds; i++) { ufds[nfds].fd = extra_fds[i].fd; ufds[nfds].events = 0; if(extra_fds[i].events & CURL_WAIT_POLLIN) ufds[nfds].events |= POLLIN; if(extra_fds[i].events & CURL_WAIT_POLLPRI) ufds[nfds].events |= POLLPRI; if(extra_fds[i].events & CURL_WAIT_POLLOUT) ufds[nfds].events |= POLLOUT; ++nfds; } #ifdef ENABLE_WAKEUP if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { ufds[nfds].fd = multi->wakeup_pair[0]; ufds[nfds].events = POLLIN; ++nfds; } #endif if(nfds) { int pollrc; /* wait... */ pollrc = Curl_poll(ufds, nfds, timeout_ms); if(pollrc > 0) { retcode = pollrc; /* copy revents results from the poll to the curl_multi_wait poll struct, the bit values of the actual underlying poll() implementation may not be the same as the ones in the public libcurl API! */ for(i = 0; i < extra_nfds; i++) { unsigned short mask = 0; unsigned r = ufds[curlfds + i].revents; if(r & POLLIN) mask |= CURL_WAIT_POLLIN; if(r & POLLOUT) mask |= CURL_WAIT_POLLOUT; if(r & POLLPRI) mask |= CURL_WAIT_POLLPRI; extra_fds[i].revents = mask; } #ifdef ENABLE_WAKEUP if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) { if(ufds[curlfds + extra_nfds].revents & POLLIN) { char buf[64]; while(1) { /* the reading socket is non-blocking, try to read data from it until it receives an error (except EINTR). In normal cases it will get EAGAIN or EWOULDBLOCK when there is no more data, breaking the loop. */ if(sread(multi->wakeup_pair[0], buf, sizeof(buf)) <= 0) { #ifndef USE_WINSOCK if(EINTR == SOCKERRNO) continue; #endif break; } } /* do not count the wakeup socket into the returned value */ retcode--; } } #endif } } if(ufds_malloc) free(ufds); if(ret) *ret = retcode; if(!extrawait || nfds) /* if any socket was checked */ ; else { long sleep_ms = 0; /* Avoid busy-looping when there's nothing particular to wait for */ if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) { if(sleep_ms > timeout_ms) sleep_ms = timeout_ms; /* when there are no easy handles in the multi, this holds a -1 timeout */ else if((sleep_ms < 0) && extrawait) sleep_ms = timeout_ms; Curl_wait_ms((int)sleep_ms); } } return CURLM_OK; } CURLMcode curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret) { return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE, FALSE); } CURLMcode curl_multi_poll(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret) { return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE, TRUE); } CURLMcode curl_multi_wakeup(struct Curl_multi *multi) { /* this function is usually called from another thread, it has to be careful only to access parts of the Curl_multi struct that are constant */ /* GOOD_MULTI_HANDLE can be safely called */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; #ifdef ENABLE_WAKEUP /* the wakeup_pair variable is only written during init and cleanup, making it safe to access from another thread after the init part and before cleanup */ if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) { char buf[1]; buf[0] = 1; while(1) { /* swrite() is not thread-safe in general, because concurrent calls can have their messages interleaved, but in this case the content of the messages does not matter, which makes it ok to call. The write socket is set to non-blocking, this way this function cannot block, making it safe to call even from the same thread that will call Curl_multi_wait(). If swrite() returns that it would block, it's considered successful because it means that previous calls to this function will wake up the poll(). */ if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) { int err = SOCKERRNO; int return_success; #ifdef USE_WINSOCK return_success = WSAEWOULDBLOCK == err; #else if(EINTR == err) continue; return_success = EWOULDBLOCK == err || EAGAIN == err; #endif if(!return_success) return CURLM_WAKEUP_FAILURE; } return CURLM_OK; } } #endif return CURLM_WAKEUP_FAILURE; } /* * multi_ischanged() is called * * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND * => CONNECT action. * * Set 'clear' to TRUE to have it also clear the state variable. */ static bool multi_ischanged(struct Curl_multi *multi, bool clear) { bool retval = multi->recheckstate; if(clear) multi->recheckstate = FALSE; return retval; } CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, struct Curl_easy *data, struct connectdata *conn) { CURLMcode rc; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; rc = curl_multi_add_handle(multi, data); if(!rc) { struct SingleRequest *k = &data->req; /* pass in NULL for 'conn' here since we don't want to init the connection, only this transfer */ Curl_init_do(data, NULL); /* take this handle to the perform state right away */ multistate(data, CURLM_STATE_PERFORM); Curl_attach_connnection(data, conn); k->keepon |= KEEP_RECV; /* setup to receive! */ } return rc; } /* * do_complete is called when the DO actions are complete. * * We init chunking and trailer bits to their default values here immediately * before receiving any header data for the current request. */ static void do_complete(struct connectdata *conn) { conn->data->req.chunk = FALSE; Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); } static CURLcode multi_do(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; DEBUGASSERT(conn); DEBUGASSERT(conn->handler); DEBUGASSERT(conn->data == data); if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ result = conn->handler->do_it(conn, done); if(!result && *done) /* do_complete must be called after the protocol-specific DO function */ do_complete(conn); } return result; } /* * multi_do_more() is called during the DO_MORE multi state. It is basically a * second stage DO state which (wrongly) was introduced to support FTP's * second connection. * * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to * DOING state there's more work to do! */ static CURLcode multi_do_more(struct connectdata *conn, int *complete) { CURLcode result = CURLE_OK; *complete = 0; if(conn->handler->do_more) result = conn->handler->do_more(conn, complete); if(!result && (*complete == 1)) /* do_complete must be called after the protocol-specific DO function */ do_complete(conn); return result; } /* * We are doing protocol-specific connecting and this is being called over and * over from the multi interface until the connection phase is done on * protocol layer. */ static CURLcode protocol_connecting(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; if(conn && conn->handler->connecting) { *done = FALSE; result = conn->handler->connecting(conn, done); } else *done = TRUE; return result; } /* * We are DOING this is being called over and over from the multi interface * until the DOING phase is done on protocol layer. */ static CURLcode protocol_doing(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; if(conn && conn->handler->doing) { *done = FALSE; result = conn->handler->doing(conn, done); } else *done = TRUE; return result; } /* * We have discovered that the TCP connection has been successful, we can now * proceed with some action. * */ static CURLcode protocol_connect(struct connectdata *conn, bool *protocol_done) { CURLcode result = CURLE_OK; DEBUGASSERT(conn); DEBUGASSERT(protocol_done); *protocol_done = FALSE; if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) { /* We already are connected, get back. This may happen when the connect worked fine in the first call, like when we connect to a local server or proxy. Note that we don't know if the protocol is actually done. Unless this protocol doesn't have any protocol-connect callback, as then we know we're done. */ if(!conn->handler->connecting) *protocol_done = TRUE; return CURLE_OK; } if(!conn->bits.protoconnstart) { result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; if(CONNECT_FIRSTSOCKET_PROXY_SSL()) /* wait for HTTPS proxy SSL initialization to complete */ return CURLE_OK; if(conn->bits.tunnel_proxy && conn->bits.httpproxy && Curl_connect_ongoing(conn)) /* when using an HTTP tunnel proxy, await complete tunnel establishment before proceeding further. Return CURLE_OK so we'll be called again */ return CURLE_OK; if(conn->handler->connect_it) { /* is there a protocol-specific connect() procedure? */ /* Call the protocol-specific connect function */ result = conn->handler->connect_it(conn, protocol_done); } else *protocol_done = TRUE; /* it has started, possibly even completed but that knowledge isn't stored in this bit! */ if(!result) conn->bits.protoconnstart = TRUE; } return result; /* pass back status */ } static CURLMcode multi_runsingle(struct Curl_multi *multi, struct curltime now, struct Curl_easy *data) { struct Curl_message *msg = NULL; bool connected; bool async; bool protocol_connected = FALSE; bool dophase_done = FALSE; bool done = FALSE; CURLMcode rc; CURLcode result = CURLE_OK; timediff_t timeout_ms; timediff_t recv_timeout_ms; timediff_t send_timeout_ms; int control; if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; do { /* A "stream" here is a logical stream if the protocol can handle that (HTTP/2), or the full connection for older protocols */ bool stream_error = FALSE; rc = CURLM_OK; DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) || (data->mstate >= CURLM_STATE_DONE) || data->conn); if(!data->conn && data->mstate > CURLM_STATE_CONNECT && data->mstate < CURLM_STATE_DONE) { /* In all these states, the code will blindly access 'data->conn' so this is precaution that it isn't NULL. And it silences static analyzers. */ failf(data, "In state %d with no conn, bail out!\n", data->mstate); return CURLM_INTERNAL_ERROR; } if(multi_ischanged(multi, TRUE)) { DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n")); process_pending_handles(multi); /* multiplexed */ } if(data->conn && data->mstate > CURLM_STATE_CONNECT && data->mstate < CURLM_STATE_COMPLETED) { /* Make sure we set the connection's current owner */ data->conn->data = data; } if(data->conn && (data->mstate >= CURLM_STATE_CONNECT) && (data->mstate < CURLM_STATE_COMPLETED)) { /* we need to wait for the connect state as only then is the start time stored, but we must not check already completed handles */ timeout_ms = Curl_timeleft(data, &now, (data->mstate <= CURLM_STATE_DO)? TRUE:FALSE); if(timeout_ms < 0) { /* Handle timed out */ if(data->mstate == CURLM_STATE_WAITRESOLVE) failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds", Curl_timediff(now, data->progress.t_startsingle)); else if(data->mstate == CURLM_STATE_WAITCONNECT) failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds", Curl_timediff(now, data->progress.t_startsingle)); else { struct SingleRequest *k = &data->req; if(k->size != -1) { failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", Curl_timediff(now, data->progress.t_startsingle), k->bytecount, k->size); } else { failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", Curl_timediff(now, data->progress.t_startsingle), k->bytecount); } } /* Force connection closed if the connection has indeed been used */ if(data->mstate > CURLM_STATE_DO) { streamclose(data->conn, "Disconnected with pending data"); stream_error = TRUE; } result = CURLE_OPERATION_TIMEDOUT; (void)multi_done(data, result, TRUE); /* Skip the statemachine and go directly to error handling section. */ goto statemachine_end; } } switch(data->mstate) { case CURLM_STATE_INIT: /* init this transfer. */ result = Curl_pretransfer(data); if(!result) { /* after init, go CONNECT */ multistate(data, CURLM_STATE_CONNECT); Curl_pgrsTime(data, TIMER_STARTOP); rc = CURLM_CALL_MULTI_PERFORM; } break; case CURLM_STATE_CONNECT_PEND: /* We will stay here until there is a connection available. Then we try again in the CURLM_STATE_CONNECT state. */ break; case CURLM_STATE_CONNECT: /* Connect. We want to get a connection identifier filled in. */ Curl_pgrsTime(data, TIMER_STARTSINGLE); if(data->set.timeout) Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT); if(data->set.connecttimeout) Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT); result = Curl_connect(data, &async, &protocol_connected); if(CURLE_NO_CONNECTION_AVAILABLE == result) { /* There was no connection available. We will go to the pending state and wait for an available connection. */ multistate(data, CURLM_STATE_CONNECT_PEND); /* add this handle to the list of connect-pending handles */ Curl_llist_insert_next(&multi->pending, multi->pending.tail, data, &data->connect_queue); result = CURLE_OK; break; } else if(data->state.previouslypending) { /* this transfer comes from the pending queue so try move another */ infof(data, "Transfer was pending, now try another\n"); process_pending_handles(data->multi); } if(!result) { if(async) /* We're now waiting for an asynchronous name lookup */ multistate(data, CURLM_STATE_WAITRESOLVE); else { /* after the connect has been sent off, go WAITCONNECT unless the protocol connect is already done and we can go directly to WAITDO or DO! */ rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connected) multistate(data, CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP if(Curl_connect_ongoing(data->conn)) multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif multistate(data, CURLM_STATE_WAITCONNECT); } } } break; case CURLM_STATE_WAITRESOLVE: /* awaiting an asynch name resolve to complete */ { struct Curl_dns_entry *dns = NULL; struct connectdata *conn = data->conn; const char *hostname; DEBUGASSERT(conn); if(conn->bits.httpproxy) hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; /* check if we have the name resolved by now */ dns = Curl_fetch_addr(conn, hostname, (int)conn->port); if(dns) { #ifdef CURLRES_ASYNCH conn->async.dns = dns; conn->async.done = TRUE; #endif result = CURLE_OK; infof(data, "Hostname '%s' was found in DNS cache\n", hostname); } if(!dns) result = Curl_resolv_check(data->conn, &dns); /* Update sockets here, because the socket(s) may have been closed and the application thus needs to be told, even if it is likely that the same socket(s) will again be used further down. If the name has not yet been resolved, it is likely that new sockets have been opened in an attempt to contact another resolver. */ singlesocket(multi, data); if(dns) { /* Perform the next step in the connection phase, and then move on to the WAITCONNECT state */ result = Curl_once_resolved(data->conn, &protocol_connected); if(result) /* if Curl_once_resolved() returns failure, the connection struct is already freed and gone */ data->conn = NULL; /* no more connection */ else { /* call again please so that we get the next socket setup */ rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connected) multistate(data, CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP if(Curl_connect_ongoing(data->conn)) multistate(data, CURLM_STATE_WAITPROXYCONNECT); else #endif multistate(data, CURLM_STATE_WAITCONNECT); } } } if(result) { /* failure detected */ stream_error = TRUE; break; } } break; #ifndef CURL_DISABLE_HTTP case CURLM_STATE_WAITPROXYCONNECT: /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ DEBUGASSERT(data->conn); result = Curl_http_connect(data->conn, &protocol_connected); if(data->conn->bits.proxy_connect_closed) { rc = CURLM_CALL_MULTI_PERFORM; /* connect back to proxy again */ result = CURLE_OK; multi_done(data, CURLE_OK, FALSE); multistate(data, CURLM_STATE_CONNECT); } else if(!result) { if((data->conn->http_proxy.proxytype != CURLPROXY_HTTPS || data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && Curl_connect_complete(data->conn)) { rc = CURLM_CALL_MULTI_PERFORM; /* initiate protocol connect phase */ multistate(data, CURLM_STATE_SENDPROTOCONNECT); } } else if(result) stream_error = TRUE; break; #endif case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch TCP connect */ DEBUGASSERT(data->conn); result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected); if(connected && !result) { #ifndef CURL_DISABLE_HTTP if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS && !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || Curl_connect_ongoing(data->conn)) { multistate(data, CURLM_STATE_WAITPROXYCONNECT); break; } #endif rc = CURLM_CALL_MULTI_PERFORM; multistate(data, data->conn->bits.tunnel_proxy? CURLM_STATE_WAITPROXYCONNECT: CURLM_STATE_SENDPROTOCONNECT); } else if(result) { /* failure detected */ Curl_posttransfer(data); multi_done(data, result, TRUE); stream_error = TRUE; break; } break; case CURLM_STATE_SENDPROTOCONNECT: result = protocol_connect(data->conn, &protocol_connected); if(!result && !protocol_connected) /* switch to waiting state */ multistate(data, CURLM_STATE_PROTOCONNECT); else if(!result) { /* protocol connect has completed, go WAITDO or DO */ multistate(data, CURLM_STATE_DO); rc = CURLM_CALL_MULTI_PERFORM; } else if(result) { /* failure detected */ Curl_posttransfer(data); multi_done(data, result, TRUE); stream_error = TRUE; } break; case CURLM_STATE_PROTOCONNECT: /* protocol-specific connect phase */ result = protocol_connecting(data->conn, &protocol_connected); if(!result && protocol_connected) { /* after the connect has completed, go WAITDO or DO */ multistate(data, CURLM_STATE_DO); rc = CURLM_CALL_MULTI_PERFORM; } else if(result) { /* failure detected */ Curl_posttransfer(data); multi_done(data, result, TRUE); stream_error = TRUE; } break; case CURLM_STATE_DO: if(data->set.connect_only) { /* keep connection open for application to use the socket */ connkeep(data->conn, "CONNECT_ONLY"); multistate(data, CURLM_STATE_DONE); result = CURLE_OK; rc = CURLM_CALL_MULTI_PERFORM; } else { /* Perform the protocol's DO action */ result = multi_do(data, &dophase_done); /* When multi_do() returns failure, data->conn might be NULL! */ if(!result) { if(!dophase_done) { #ifndef CURL_DISABLE_FTP /* some steps needed for wildcard matching */ if(data->state.wildcardmatch) { struct WildcardData *wc = &data->wildcard; if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { /* skip some states if it is important */ multi_done(data, CURLE_OK, FALSE); multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; break; } } #endif /* DO was not completed in one function call, we must continue DOING... */ multistate(data, CURLM_STATE_DOING); rc = CURLM_OK; } /* after DO, go DO_DONE... or DO_MORE */ else if(data->conn->bits.do_more) { /* we're supposed to do more, but we need to sit down, relax and wait a little while first */ multistate(data, CURLM_STATE_DO_MORE); rc = CURLM_OK; } else { /* we're done with the DO, now DO_DONE */ multistate(data, CURLM_STATE_DO_DONE); rc = CURLM_CALL_MULTI_PERFORM; } } else if((CURLE_SEND_ERROR == result) && data->conn->bits.reuse) { /* * In this situation, a connection that we were trying to use * may have unexpectedly died. If possible, send the connection * back to the CONNECT phase so we can try again. */ char *newurl = NULL; followtype follow = FOLLOW_NONE; CURLcode drc; drc = Curl_retry_request(data->conn, &newurl); if(drc) { /* a failure here pretty much implies an out of memory */ result = drc; stream_error = TRUE; } Curl_posttransfer(data); drc = multi_done(data, result, FALSE); /* When set to retry the connection, we must to go back to * the CONNECT state */ if(newurl) { if(!drc || (drc == CURLE_SEND_ERROR)) { follow = FOLLOW_RETRY; drc = Curl_follow(data, newurl, follow); if(!drc) { multistate(data, CURLM_STATE_CONNECT); rc = CURLM_CALL_MULTI_PERFORM; result = CURLE_OK; } else { /* Follow failed */ result = drc; } } else { /* done didn't return OK or SEND_ERROR */ result = drc; } } else { /* Have error handler disconnect conn if we can't retry */ stream_error = TRUE; } free(newurl); } else { /* failure detected */ Curl_posttransfer(data); if(data->conn) multi_done(data, result, FALSE); stream_error = TRUE; } } break; case CURLM_STATE_DOING: /* we continue DOING until the DO phase is complete */ DEBUGASSERT(data->conn); result = protocol_doing(data->conn, &dophase_done); if(!result) { if(dophase_done) { /* after DO, go DO_DONE or DO_MORE */ multistate(data, data->conn->bits.do_more? CURLM_STATE_DO_MORE: CURLM_STATE_DO_DONE); rc = CURLM_CALL_MULTI_PERFORM; } /* dophase_done */ } else { /* failure detected */ Curl_posttransfer(data); multi_done(data, result, FALSE); stream_error = TRUE; } break; case CURLM_STATE_DO_MORE: /* * When we are connected, DO MORE and then go DO_DONE */ DEBUGASSERT(data->conn); result = multi_do_more(data->conn, &control); if(!result) { if(control) { /* if positive, advance to DO_DONE if negative, go back to DOING */ multistate(data, control == 1? CURLM_STATE_DO_DONE: CURLM_STATE_DOING); rc = CURLM_CALL_MULTI_PERFORM; } else /* stay in DO_MORE */ rc = CURLM_OK; } else { /* failure detected */ Curl_posttransfer(data); multi_done(data, result, FALSE); stream_error = TRUE; } break; case CURLM_STATE_DO_DONE: DEBUGASSERT(data->conn); if(data->conn->bits.multiplex) /* Check if we can move pending requests to send pipe */ process_pending_handles(multi); /* multiplexed */ /* Only perform the transfer if there's a good socket to work with. Having both BAD is a signal to skip immediately to DONE */ if((data->conn->sockfd != CURL_SOCKET_BAD) || (data->conn->writesockfd != CURL_SOCKET_BAD)) multistate(data, CURLM_STATE_PERFORM); else { #ifndef CURL_DISABLE_FTP if(data->state.wildcardmatch && ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) { data->wildcard.state = CURLWC_DONE; } #endif multistate(data, CURLM_STATE_DONE); } rc = CURLM_CALL_MULTI_PERFORM; break; case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ DEBUGASSERT(data->conn); /* if both rates are within spec, resume transfer */ if(Curl_pgrsUpdate(data->conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(data, now); if(!result) { send_timeout_ms = 0; if(data->set.max_send_speed > 0) send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, data->progress.ul_limit_size, data->set.max_send_speed, data->progress.ul_limit_start, now); recv_timeout_ms = 0; if(data->set.max_recv_speed > 0) recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, data->progress.dl_limit_size, data->set.max_recv_speed, data->progress.dl_limit_start, now); if(!send_timeout_ms && !recv_timeout_ms) { multistate(data, CURLM_STATE_PERFORM); Curl_ratelimit(data, now); } else if(send_timeout_ms >= recv_timeout_ms) Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); else Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); } break; case CURLM_STATE_PERFORM: { char *newurl = NULL; bool retry = FALSE; bool comeback = FALSE; /* check if over send speed */ send_timeout_ms = 0; if(data->set.max_send_speed > 0) send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, data->progress.ul_limit_size, data->set.max_send_speed, data->progress.ul_limit_start, now); /* check if over recv speed */ recv_timeout_ms = 0; if(data->set.max_recv_speed > 0) recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, data->progress.dl_limit_size, data->set.max_recv_speed, data->progress.dl_limit_start, now); if(send_timeout_ms || recv_timeout_ms) { Curl_ratelimit(data, now); multistate(data, CURLM_STATE_TOOFAST); if(send_timeout_ms >= recv_timeout_ms) Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); else Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); break; } /* read/write data if it is ready to do so */ result = Curl_readwrite(data->conn, data, &done, &comeback); if(done || (result == CURLE_RECV_ERROR)) { /* If CURLE_RECV_ERROR happens early enough, we assume it was a race * condition and the server closed the re-used connection exactly when * we wanted to use it, so figure out if that is indeed the case. */ CURLcode ret = Curl_retry_request(data->conn, &newurl); if(!ret) retry = (newurl)?TRUE:FALSE; else if(!result) result = ret; if(retry) { /* if we are to retry, set the result to OK and consider the request as done */ result = CURLE_OK; done = TRUE; } } else if((CURLE_HTTP2_STREAM == result) && Curl_h2_http_1_1_error(data->conn)) { CURLcode ret = Curl_retry_request(data->conn, &newurl); if(!ret) { infof(data, "Downgrades to HTTP/1.1!\n"); data->set.httpversion = CURL_HTTP_VERSION_1_1; /* clear the error message bit too as we ignore the one we got */ data->state.errorbuf = FALSE; if(!newurl) /* typically for HTTP_1_1_REQUIRED error on first flight */ newurl = strdup(data->change.url); /* if we are to retry, set the result to OK and consider the request as done */ retry = TRUE; result = CURLE_OK; done = TRUE; } else result = ret; } if(result) { /* * The transfer phase returned error, we mark the connection to get * closed to prevent being re-used. This is because we can't possibly * know if the connection is in a good shape or not now. Unless it is * a protocol which uses two "channels" like FTP, as then the error * happened in the data connection. */ if(!(data->conn->handler->flags & PROTOPT_DUAL) && result != CURLE_HTTP2_STREAM) streamclose(data->conn, "Transfer returned error"); Curl_posttransfer(data); multi_done(data, result, TRUE); } else if(done) { followtype follow = FOLLOW_NONE; /* call this even if the readwrite function returned error */ Curl_posttransfer(data); /* When we follow redirects or is set to retry the connection, we must to go back to the CONNECT state */ if(data->req.newurl || retry) { if(!retry) { /* if the URL is a follow-location and not just a retried request then figure out the URL here */ free(newurl); newurl = data->req.newurl; data->req.newurl = NULL; follow = FOLLOW_REDIR; } else follow = FOLLOW_RETRY; (void)multi_done(data, CURLE_OK, FALSE); /* multi_done() might return CURLE_GOT_NOTHING */ result = Curl_follow(data, newurl, follow); if(!result) { multistate(data, CURLM_STATE_CONNECT); rc = CURLM_CALL_MULTI_PERFORM; } free(newurl); } else { /* after the transfer is done, go DONE */ /* but first check to see if we got a location info even though we're not following redirects */ if(data->req.location) { free(newurl); newurl = data->req.location; data->req.location = NULL; result = Curl_follow(data, newurl, FOLLOW_FAKE); free(newurl); if(result) { stream_error = TRUE; result = multi_done(data, result, TRUE); } } if(!result) { multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; } } } else if(comeback) { /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer won't get stuck on this transfer at the expense of other concurrent transfers */ Curl_expire(data, 0, EXPIRE_RUN_NOW); rc = CURLM_OK; } break; } case CURLM_STATE_DONE: /* this state is highly transient, so run another loop after this */ rc = CURLM_CALL_MULTI_PERFORM; if(data->conn) { CURLcode res; if(data->conn->bits.multiplex) /* Check if we can move pending requests to connection */ process_pending_handles(multi); /* multiplexing */ /* post-transfer command */ res = multi_done(data, result, FALSE); /* allow a previously set error code take precedence */ if(!result) result = res; /* * If there are other handles on the connection, multi_done won't set * conn to NULL. In such a case, curl_multi_remove_handle() can * access free'd data, if the connection is free'd and the handle * removed before we perform the processing in CURLM_STATE_COMPLETED */ if(data->conn) detach_connnection(data); } #ifndef CURL_DISABLE_FTP if(data->state.wildcardmatch) { if(data->wildcard.state != CURLWC_DONE) { /* if a wildcard is set and we are not ending -> lets start again with CURLM_STATE_INIT */ multistate(data, CURLM_STATE_INIT); break; } } #endif /* after we have DONE what we're supposed to do, go COMPLETED, and it doesn't matter what the multi_done() returned! */ multistate(data, CURLM_STATE_COMPLETED); break; case CURLM_STATE_COMPLETED: break; case CURLM_STATE_MSGSENT: data->result = result; return CURLM_OK; /* do nothing */ default: return CURLM_INTERNAL_ERROR; } statemachine_end: if(data->mstate < CURLM_STATE_COMPLETED) { if(result) { /* * If an error was returned, and we aren't in completed state now, * then we go to completed and consider this transfer aborted. */ /* NOTE: no attempt to disconnect connections must be made in the case blocks above - cleanup happens only here */ /* Check if we can move pending requests to send pipe */ process_pending_handles(multi); /* connection */ if(data->conn) { if(stream_error) { /* Don't attempt to send data over a connection that timed out */ bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; struct connectdata *conn = data->conn; /* This is where we make sure that the conn pointer is reset. We don't have to do this in every case block above where a failure is detected */ detach_connnection(data); /* disconnect properly */ Curl_disconnect(data, conn, dead_connection); } } else if(data->mstate == CURLM_STATE_CONNECT) { /* Curl_connect() failed */ (void)Curl_posttransfer(data); } multistate(data, CURLM_STATE_COMPLETED); rc = CURLM_CALL_MULTI_PERFORM; } /* if there's still a connection to use, call the progress function */ else if(data->conn && Curl_pgrsUpdate(data->conn)) { /* aborted due to progress callback return code must close the connection */ result = CURLE_ABORTED_BY_CALLBACK; streamclose(data->conn, "Aborted by callback"); /* if not yet in DONE state, go there, otherwise COMPLETED */ multistate(data, (data->mstate < CURLM_STATE_DONE)? CURLM_STATE_DONE: CURLM_STATE_COMPLETED); rc = CURLM_CALL_MULTI_PERFORM; } } if(CURLM_STATE_COMPLETED == data->mstate) { if(data->set.fmultidone) { /* signal via callback instead */ data->set.fmultidone(data, result); } else { /* now fill in the Curl_message with this info */ msg = &data->msg; msg->extmsg.msg = CURLMSG_DONE; msg->extmsg.easy_handle = data; msg->extmsg.data.result = result; rc = multi_addmsg(multi, msg); DEBUGASSERT(!data->conn); } multistate(data, CURLM_STATE_MSGSENT); } } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE)); data->result = result; return rc; } CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) { struct Curl_easy *data; CURLMcode returncode = CURLM_OK; struct Curl_tree *t; struct curltime now = Curl_now(); if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; data = multi->easyp; while(data) { CURLMcode result; SIGPIPE_VARIABLE(pipe_st); sigpipe_ignore(data, &pipe_st); result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); if(result) returncode = result; data = data->next; /* operate on next handle */ } /* * Simply remove all expired timers from the splay since handles are dealt * with unconditionally by this function and curl_multi_timeout() requires * that already passed/handled expire times are removed from the splay. * * It is important that the 'now' value is set at the entry of this function * and not for the current time as it may have ticked a little while since * then and then we risk this loop to remove timers that actually have not * been handled! */ do { multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); if(t) /* the removed may have another timeout in queue */ (void)add_next_timeout(now, multi, t->payload); } while(t); *running_handles = multi->num_alive; if(CURLM_OK >= returncode) Curl_update_timer(multi); return returncode; } CURLMcode curl_multi_cleanup(struct Curl_multi *multi) { struct Curl_easy *data; struct Curl_easy *nextdata; if(GOOD_MULTI_HANDLE(multi)) { if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; multi->type = 0; /* not good anymore */ /* Firsrt remove all remaining easy handles */ data = multi->easyp; while(data) { nextdata = data->next; if(!data->state.done && data->conn) /* if DONE was never called for this handle */ (void)multi_done(data, CURLE_OK, TRUE); if(data->dns.hostcachetype == HCACHE_MULTI) { /* clear out the usage of the shared DNS cache */ Curl_hostcache_clean(data, data->dns.hostcache); data->dns.hostcache = NULL; data->dns.hostcachetype = HCACHE_NONE; } /* Clear the pointer to the connection cache */ data->state.conn_cache = NULL; data->multi = NULL; /* clear the association */ #ifdef USE_LIBPSL if(data->psl == &multi->psl) data->psl = NULL; #endif data = nextdata; } /* Close all the connections in the connection cache */ Curl_conncache_close_all_connections(&multi->conn_cache); Curl_hash_destroy(&multi->sockhash); Curl_conncache_destroy(&multi->conn_cache); Curl_llist_destroy(&multi->msglist, NULL); Curl_llist_destroy(&multi->pending, NULL); Curl_hash_destroy(&multi->hostcache); Curl_psl_destroy(&multi->psl); #ifdef ENABLE_WAKEUP sclose(multi->wakeup_pair[0]); sclose(multi->wakeup_pair[1]); #endif free(multi); return CURLM_OK; } return CURLM_BAD_HANDLE; } /* * curl_multi_info_read() * * This function is the primary way for a multi/multi_socket application to * figure out if a transfer has ended. We MUST make this function as fast as * possible as it will be polled frequently and we MUST NOT scan any lists in * here to figure out things. We must scale fine to thousands of handles and * beyond. The current design is fully O(1). */ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) { struct Curl_message *msg; *msgs_in_queue = 0; /* default to none */ if(GOOD_MULTI_HANDLE(multi) && !multi->in_callback && Curl_llist_count(&multi->msglist)) { /* there is one or more messages in the list */ struct curl_llist_element *e; /* extract the head of the list to return */ e = multi->msglist.head; msg = e->ptr; /* remove the extracted entry */ Curl_llist_remove(&multi->msglist, e, NULL); *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist)); return &msg->extmsg; } return NULL; } /* * singlesocket() checks what sockets we deal with and their "action state" * and if we have a different state in any of those sockets from last time we * call the callback accordingly. */ static CURLMcode singlesocket(struct Curl_multi *multi, struct Curl_easy *data) { curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; int i; struct Curl_sh_entry *entry; curl_socket_t s; int num; unsigned int curraction; int actions[MAX_SOCKSPEREASYHANDLE]; for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) socks[i] = CURL_SOCKET_BAD; /* Fill in the 'current' struct with the state as it is now: what sockets to supervise and for what actions */ curraction = multi_getsock(data, socks); /* We have 0 .. N sockets already and we get to know about the 0 .. M sockets we should have from now on. Detect the differences, remove no longer supervised ones and add new ones */ /* walk over the sockets we got right now */ for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) && (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); i++) { unsigned int action = CURL_POLL_NONE; unsigned int prevaction = 0; unsigned int comboaction; bool sincebefore = FALSE; s = socks[i]; /* get it from the hash */ entry = sh_getentry(&multi->sockhash, s); if(curraction & GETSOCK_READSOCK(i)) action |= CURL_POLL_IN; if(curraction & GETSOCK_WRITESOCK(i)) action |= CURL_POLL_OUT; actions[i] = action; if(entry) { /* check if new for this transfer */ int j; for(j = 0; j< data->numsocks; j++) { if(s == data->sockets[j]) { prevaction = data->actions[j]; sincebefore = TRUE; break; } } } else { /* this is a socket we didn't have before, add it to the hash! */ entry = sh_addentry(&multi->sockhash, s); if(!entry) /* fatal */ return CURLM_OUT_OF_MEMORY; } if(sincebefore && (prevaction != action)) { /* Socket was used already, but different action now */ if(prevaction & CURL_POLL_IN) entry->readers--; if(prevaction & CURL_POLL_OUT) entry->writers--; if(action & CURL_POLL_IN) entry->readers++; if(action & CURL_POLL_OUT) entry->writers++; } else if(!sincebefore) { /* a new user */ entry->users++; if(action & CURL_POLL_IN) entry->readers++; if(action & CURL_POLL_OUT) entry->writers++; /* add 'data' to the transfer hash on this socket! */ if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */ sizeof(struct Curl_easy *), data)) return CURLM_OUT_OF_MEMORY; } comboaction = (entry->writers? CURL_POLL_OUT : 0) | (entry->readers ? CURL_POLL_IN : 0); /* socket existed before and has the same action set as before */ if(sincebefore && (entry->action == comboaction)) /* same, continue */ continue; if(multi->socket_cb) multi->socket_cb(data, s, comboaction, multi->socket_userp, entry->socketp); entry->action = comboaction; /* store the current action state */ } num = i; /* number of sockets */ /* when we've walked over all the sockets we should have right now, we must make sure to detect sockets that are removed */ for(i = 0; i< data->numsocks; i++) { int j; bool stillused = FALSE; s = data->sockets[i]; for(j = 0; j < num; j++) { if(s == socks[j]) { /* this is still supervised */ stillused = TRUE; break; } } if(stillused) continue; entry = sh_getentry(&multi->sockhash, s); /* if this is NULL here, the socket has been closed and notified so already by Curl_multi_closed() */ if(entry) { int oldactions = data->actions[i]; /* this socket has been removed. Decrease user count */ entry->users--; if(oldactions & CURL_POLL_OUT) entry->writers--; if(oldactions & CURL_POLL_IN) entry->readers--; if(!entry->users) { if(multi->socket_cb) multi->socket_cb(data, s, CURL_POLL_REMOVE, multi->socket_userp, entry->socketp); sh_delentry(entry, &multi->sockhash, s); } else { /* still users, but remove this handle as a user of this socket */ if(Curl_hash_delete(&entry->transfers, (char *)&data, sizeof(struct Curl_easy *))) { DEBUGASSERT(NULL); } } } } /* for loop over numsocks */ memcpy(data->sockets, socks, num*sizeof(curl_socket_t)); memcpy(data->actions, actions, num*sizeof(int)); data->numsocks = num; return CURLM_OK; } void Curl_updatesocket(struct Curl_easy *data) { singlesocket(data->multi, data); } /* * Curl_multi_closed() * * Used by the connect code to tell the multi_socket code that one of the * sockets we were using is about to be closed. This function will then * remove it from the sockethash for this handle to make the multi_socket API * behave properly, especially for the case when libcurl will create another * socket again and it gets the same file descriptor number. */ void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s) { if(data) { /* if there's still an easy handle associated with this connection */ struct Curl_multi *multi = data->multi; if(multi) { /* this is set if this connection is part of a handle that is added to a multi handle, and only then this is necessary */ struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(entry) { if(multi->socket_cb) multi->socket_cb(data, s, CURL_POLL_REMOVE, multi->socket_userp, entry->socketp); /* now remove it from the socket hash */ sh_delentry(entry, &multi->sockhash, s); } } } } /* * add_next_timeout() * * Each Curl_easy has a list of timeouts. The add_next_timeout() is called * when it has just been removed from the splay tree because the timeout has * expired. This function is then to advance in the list to pick the next * timeout to use (skip the already expired ones) and add this node back to * the splay tree again. * * The splay tree only has each sessionhandle as a single node and the nearest * timeout is used to sort it on. */ static CURLMcode add_next_timeout(struct curltime now, struct Curl_multi *multi, struct Curl_easy *d) { struct curltime *tv = &d->state.expiretime; struct curl_llist *list = &d->state.timeoutlist; struct curl_llist_element *e; struct time_node *node = NULL; /* move over the timeout list for this specific handle and remove all timeouts that are now passed tense and store the next pending timeout in *tv */ for(e = list->head; e;) { struct curl_llist_element *n = e->next; timediff_t diff; node = (struct time_node *)e->ptr; diff = Curl_timediff(node->time, now); if(diff <= 0) /* remove outdated entry */ Curl_llist_remove(list, e, NULL); else /* the list is sorted so get out on the first mismatch */ break; e = n; } e = list->head; if(!e) { /* clear the expire times within the handles that we remove from the splay tree */ tv->tv_sec = 0; tv->tv_usec = 0; } else { /* copy the first entry to 'tv' */ memcpy(tv, &node->time, sizeof(*tv)); /* Insert this node again into the splay. Keep the timer in the list in case we need to recompute future timers. */ multi->timetree = Curl_splayinsert(*tv, multi->timetree, &d->state.timenode); } return CURLM_OK; } static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s, int ev_bitmask, int *running_handles) { CURLMcode result = CURLM_OK; struct Curl_easy *data = NULL; struct Curl_tree *t; struct curltime now = Curl_now(); if(checkall) { /* *perform() deals with running_handles on its own */ result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ if(result != CURLM_BAD_HANDLE) { data = multi->easyp; while(data && !result) { result = singlesocket(multi, data); data = data->next; } } /* or should we fall-through and do the timer-based stuff? */ return result; } if(s != CURL_SOCKET_TIMEOUT) { struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); if(!entry) /* Unmatched socket, we can't act on it but we ignore this fact. In real-world tests it has been proved that libevent can in fact give the application actions even though the socket was just previously asked to get removed, so thus we better survive stray socket actions and just move on. */ ; else { struct curl_hash_iterator iter; struct curl_hash_element *he; /* the socket can be shared by many transfers, iterate */ Curl_hash_start_iterate(&entry->transfers, &iter); for(he = Curl_hash_next_element(&iter); he; he = Curl_hash_next_element(&iter)) { data = (struct Curl_easy *)he->ptr; DEBUGASSERT(data); DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER); if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK)) /* set socket event bitmask if they're not locked */ data->conn->cselect_bits = ev_bitmask; Curl_expire(data, 0, EXPIRE_RUN_NOW); } /* Now we fall-through and do the timer-based stuff, since we don't want to force the user to have to deal with timeouts as long as at least one connection in fact has traffic. */ data = NULL; /* set data to NULL again to avoid calling multi_runsingle() in case there's no need to */ now = Curl_now(); /* get a newer time since the multi_runsingle() loop may have taken some time */ } } else { /* Asked to run due to time-out. Clear the 'lastcall' variable to force Curl_update_timer() to trigger a callback to the app again even if the same timeout is still the one to run after this call. That handles the case when the application asks libcurl to run the timeout prematurely. */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); } /* * The loop following here will go on as long as there are expire-times left * to process in the splay and 'data' will be re-assigned for every expired * handle we deal with. */ do { /* the first loop lap 'data' can be NULL */ if(data) { SIGPIPE_VARIABLE(pipe_st); sigpipe_ignore(data, &pipe_st); result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); if(CURLM_OK >= result) { /* get the socket(s) and check if the state has been changed since last */ result = singlesocket(multi, data); if(result) return result; } } /* Check if there's one (more) expired timer to deal with! This function extracts a matching node if there is one */ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); if(t) { data = t->payload; /* assign this for next loop */ (void)add_next_timeout(now, multi, t->payload); } } while(t); *running_handles = multi->num_alive; return result; } #undef curl_multi_setopt CURLMcode curl_multi_setopt(struct Curl_multi *multi, CURLMoption option, ...) { CURLMcode res = CURLM_OK; va_list param; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; va_start(param, option); switch(option) { case CURLMOPT_SOCKETFUNCTION: multi->socket_cb = va_arg(param, curl_socket_callback); break; case CURLMOPT_SOCKETDATA: multi->socket_userp = va_arg(param, void *); break; case CURLMOPT_PUSHFUNCTION: multi->push_cb = va_arg(param, curl_push_callback); break; case CURLMOPT_PUSHDATA: multi->push_userp = va_arg(param, void *); break; case CURLMOPT_PIPELINING: multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX; break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); break; case CURLMOPT_TIMERDATA: multi->timer_userp = va_arg(param, void *); break; case CURLMOPT_MAXCONNECTS: multi->maxconnects = va_arg(param, long); break; case CURLMOPT_MAX_HOST_CONNECTIONS: multi->max_host_connections = va_arg(param, long); break; case CURLMOPT_MAX_TOTAL_CONNECTIONS: multi->max_total_connections = va_arg(param, long); break; /* options formerly used for pipelining */ case CURLMOPT_MAX_PIPELINE_LENGTH: break; case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: break; case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: break; case CURLMOPT_PIPELINING_SITE_BL: break; case CURLMOPT_PIPELINING_SERVER_BL: break; case CURLMOPT_MAX_CONCURRENT_STREAMS: { long streams = va_arg(param, long); if(streams < 1) streams = 100; multi->max_concurrent_streams = (streams > (long)INITIAL_MAX_CONCURRENT_STREAMS)? INITIAL_MAX_CONCURRENT_STREAMS : (unsigned int)streams; } break; default: res = CURLM_UNKNOWN_OPTION; break; } va_end(param); return res; } /* we define curl_multi_socket() in the public multi.h header */ #undef curl_multi_socket CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, int *running_handles) { CURLMcode result; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, FALSE, s, 0, running_handles); if(CURLM_OK >= result) Curl_update_timer(multi); return result; } CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, int ev_bitmask, int *running_handles) { CURLMcode result; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); if(CURLM_OK >= result) Curl_update_timer(multi); return result; } CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) { CURLMcode result; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); if(CURLM_OK >= result) Curl_update_timer(multi); return result; } static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { static struct curltime tv_zero = {0, 0}; if(multi->timetree) { /* we have a tree of expire times */ struct curltime now = Curl_now(); /* splay the lowest to the bottom */ multi->timetree = Curl_splay(tv_zero, multi->timetree); if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { /* some time left before expiration */ timediff_t diff = Curl_timediff(multi->timetree->key, now); if(diff <= 0) /* * Since we only provide millisecond resolution on the returned value * and the diff might be less than one millisecond here, we don't * return zero as that may cause short bursts of busyloops on fast * processors while the diff is still present but less than one * millisecond! instead we return 1 until the time is ripe. */ *timeout_ms = 1; else /* this should be safe even on 64 bit archs, as we don't use that overly long timeouts */ *timeout_ms = (long)diff; } else /* 0 means immediately */ *timeout_ms = 0; } else *timeout_ms = -1; return CURLM_OK; } CURLMcode curl_multi_timeout(struct Curl_multi *multi, long *timeout_ms) { /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; return multi_timeout(multi, timeout_ms); } /* * Tell the application it should update its timers, if it subscribes to the * update timer callback. */ void Curl_update_timer(struct Curl_multi *multi) { long timeout_ms; if(!multi->timer_cb) return; if(multi_timeout(multi, &timeout_ms)) { return; } if(timeout_ms < 0) { static const struct curltime none = {0, 0}; if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to disable it */ multi->timer_cb(multi, -1, multi->timer_userp); return; } return; } /* When multi_timeout() is done, multi->timetree points to the node with the * timeout we got the (relative) time-out time for. We can thus easily check * if this is the same (fixed) time as we got in a previous call and then * avoid calling the callback again. */ if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) return; multi->timer_lastcall = multi->timetree->key; multi->timer_cb(multi, timeout_ms, multi->timer_userp); } /* * multi_deltimeout() * * Remove a given timestamp from the list of timeouts. */ static void multi_deltimeout(struct Curl_easy *data, expire_id eid) { struct curl_llist_element *e; struct curl_llist *timeoutlist = &data->state.timeoutlist; /* find and remove the specific node from the list */ for(e = timeoutlist->head; e; e = e->next) { struct time_node *n = (struct time_node *)e->ptr; if(n->eid == eid) { Curl_llist_remove(timeoutlist, e, NULL); return; } } } /* * multi_addtimeout() * * Add a timestamp to the list of timeouts. Keep the list sorted so that head * of list is always the timeout nearest in time. * */ static CURLMcode multi_addtimeout(struct Curl_easy *data, struct curltime *stamp, expire_id eid) { struct curl_llist_element *e; struct time_node *node; struct curl_llist_element *prev = NULL; size_t n; struct curl_llist *timeoutlist = &data->state.timeoutlist; node = &data->state.expires[eid]; /* copy the timestamp and id */ memcpy(&node->time, stamp, sizeof(*stamp)); node->eid = eid; /* also marks it as in use */ n = Curl_llist_count(timeoutlist); if(n) { /* find the correct spot in the list */ for(e = timeoutlist->head; e; e = e->next) { struct time_node *check = (struct time_node *)e->ptr; timediff_t diff = Curl_timediff(check->time, node->time); if(diff > 0) break; prev = e; } } /* else this is the first timeout on the list */ Curl_llist_insert_next(timeoutlist, prev, node, &node->list); return CURLM_OK; } /* * Curl_expire() * * given a number of milliseconds from now to use to set the 'act before * this'-time for the transfer, to be extracted by curl_multi_timeout() * * The timeout will be added to a queue of timeouts if it defines a moment in * time that is later than the current head of queue. * * Expire replaces a former timeout using the same id if already set. */ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id) { struct Curl_multi *multi = data->multi; struct curltime *nowp = &data->state.expiretime; struct curltime set; /* this is only interesting while there is still an associated multi struct remaining! */ if(!multi) return; DEBUGASSERT(id < EXPIRE_LAST); set = Curl_now(); set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */ set.tv_usec += (unsigned int)(milli%1000)*1000; if(set.tv_usec >= 1000000) { set.tv_sec++; set.tv_usec -= 1000000; } /* Remove any timer with the same id just in case. */ multi_deltimeout(data, id); /* Add it to the timer list. It must stay in the list until it has expired in case we need to recompute the minimum timer later. */ multi_addtimeout(data, &set, id); if(nowp->tv_sec || nowp->tv_usec) { /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it is. */ timediff_t diff = Curl_timediff(set, *nowp); int rc; if(diff > 0) { /* The current splay tree entry is sooner than this new expiry time. We don't need to update our splay tree entry. */ return; } /* Since this is an updated time, we must remove the previous entry from the splay tree first and then re-add the new value */ rc = Curl_splayremovebyaddr(multi->timetree, &data->state.timenode, &multi->timetree); if(rc) infof(data, "Internal error removing splay node = %d\n", rc); } /* Indicate that we are in the splay tree and insert the new timer expiry value since it is our local minimum. */ *nowp = set; data->state.timenode.payload = data; multi->timetree = Curl_splayinsert(*nowp, multi->timetree, &data->state.timenode); } /* * Curl_expire_done() * * Removes the expire timer. Marks it as done. * */ void Curl_expire_done(struct Curl_easy *data, expire_id id) { /* remove the timer, if there */ multi_deltimeout(data, id); } /* * Curl_expire_clear() * * Clear ALL timeout values for this handle. */ void Curl_expire_clear(struct Curl_easy *data) { struct Curl_multi *multi = data->multi; struct curltime *nowp = &data->state.expiretime; /* this is only interesting while there is still an associated multi struct remaining! */ if(!multi) return; if(nowp->tv_sec || nowp->tv_usec) { /* Since this is an cleared time, we must remove the previous entry from the splay tree */ struct curl_llist *list = &data->state.timeoutlist; int rc; rc = Curl_splayremovebyaddr(multi->timetree, &data->state.timenode, &multi->timetree); if(rc) infof(data, "Internal error clearing splay node = %d\n", rc); /* flush the timeout list too */ while(list->size > 0) { Curl_llist_remove(list, list->tail, NULL); } #ifdef DEBUGBUILD infof(data, "Expire cleared (transfer %p)\n", data); #endif nowp->tv_sec = 0; nowp->tv_usec = 0; } } CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, void *hashp) { struct Curl_sh_entry *there = NULL; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; there = sh_getentry(&multi->sockhash, s); if(!there) return CURLM_BAD_SOCKET; there->socketp = hashp; return CURLM_OK; } size_t Curl_multi_max_host_connections(struct Curl_multi *multi) { return multi ? multi->max_host_connections : 0; } size_t Curl_multi_max_total_connections(struct Curl_multi *multi) { return multi ? multi->max_total_connections : 0; } /* * When information about a connection has appeared, call this! */ void Curl_multiuse_state(struct connectdata *conn, int bundlestate) /* use BUNDLE_* defines */ { DEBUGASSERT(conn); DEBUGASSERT(conn->bundle); DEBUGASSERT(conn->data); DEBUGASSERT(conn->data->multi); conn->bundle->multiuse = bundlestate; process_pending_handles(conn->data->multi); } static void process_pending_handles(struct Curl_multi *multi) { struct curl_llist_element *e = multi->pending.head; if(e) { struct Curl_easy *data = e->ptr; DEBUGASSERT(data->mstate == CURLM_STATE_CONNECT_PEND); multistate(data, CURLM_STATE_CONNECT); /* Remove this node from the list */ Curl_llist_remove(&multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ Curl_expire(data, 0, EXPIRE_RUN_NOW); /* mark this as having been in the pending queue */ data->state.previouslypending = TRUE; } } void Curl_set_in_callback(struct Curl_easy *data, bool value) { /* might get called when there is no data pointer! */ if(data) { if(data->multi_easy) data->multi_easy->in_callback = value; else if(data->multi) data->multi->in_callback = value; } } bool Curl_is_in_callback(struct Curl_easy *easy) { return ((easy->multi && easy->multi->in_callback) || (easy->multi_easy && easy->multi_easy->in_callback)); } #ifdef DEBUGBUILD void Curl_multi_dump(struct Curl_multi *multi) { struct Curl_easy *data; int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); for(data = multi->easyp; data; data = data->next) { if(data->mstate < CURLM_STATE_COMPLETED) { /* only display handles that are not completed */ fprintf(stderr, "handle %p, state %s, %d sockets\n", (void *)data, statename[data->mstate], data->numsocks); for(i = 0; i < data->numsocks; i++) { curl_socket_t s = data->sockets[i]; struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); fprintf(stderr, "%d ", (int)s); if(!entry) { fprintf(stderr, "INTERNAL CONFUSION\n"); continue; } fprintf(stderr, "[%s %s] ", (entry->action&CURL_POLL_IN)?"RECVING":"", (entry->action&CURL_POLL_OUT)?"SENDING":""); } if(data->numsocks) fprintf(stderr, "\n"); } } } #endif unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) { DEBUGASSERT(multi); return multi->max_concurrent_streams; } davix-0.8.0/deps/curl/lib/strerror.c0000644000000000000000000006303114121063461016025 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2004 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_STRERROR_R # if (!defined(HAVE_POSIX_STRERROR_R) && \ !defined(HAVE_GLIBC_STRERROR_R) && \ !defined(HAVE_VXWORKS_STRERROR_R)) || \ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) # error "strerror_r MUST be either POSIX, glibc or vxworks-style" # endif #endif #include #ifdef USE_LIBIDN2 #include #endif #ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" #endif #include "strerror.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if defined(WIN32) || defined(_WIN32_WCE) #define PRESERVE_WINDOWS_ERROR_CODE #endif const char * curl_easy_strerror(CURLcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS switch(error) { case CURLE_OK: return "No error"; case CURLE_UNSUPPORTED_PROTOCOL: return "Unsupported protocol"; case CURLE_FAILED_INIT: return "Failed initialization"; case CURLE_URL_MALFORMAT: return "URL using bad/illegal format or missing URL"; case CURLE_NOT_BUILT_IN: return "A requested feature, protocol or option was not found built-in in" " this libcurl due to a build-time decision."; case CURLE_COULDNT_RESOLVE_PROXY: return "Couldn't resolve proxy name"; case CURLE_COULDNT_RESOLVE_HOST: return "Couldn't resolve host name"; case CURLE_COULDNT_CONNECT: return "Couldn't connect to server"; case CURLE_WEIRD_SERVER_REPLY: return "Weird server reply"; case CURLE_REMOTE_ACCESS_DENIED: return "Access denied to remote resource"; case CURLE_FTP_ACCEPT_FAILED: return "FTP: The server failed to connect to data port"; case CURLE_FTP_ACCEPT_TIMEOUT: return "FTP: Accepting server connect has timed out"; case CURLE_FTP_PRET_FAILED: return "FTP: The server did not accept the PRET command."; case CURLE_FTP_WEIRD_PASS_REPLY: return "FTP: unknown PASS reply"; case CURLE_FTP_WEIRD_PASV_REPLY: return "FTP: unknown PASV reply"; case CURLE_FTP_WEIRD_227_FORMAT: return "FTP: unknown 227 response format"; case CURLE_FTP_CANT_GET_HOST: return "FTP: can't figure out the host in the PASV response"; case CURLE_HTTP2: return "Error in the HTTP2 framing layer"; case CURLE_FTP_COULDNT_SET_TYPE: return "FTP: couldn't set file type"; case CURLE_PARTIAL_FILE: return "Transferred a partial file"; case CURLE_FTP_COULDNT_RETR_FILE: return "FTP: couldn't retrieve (RETR failed) the specified file"; case CURLE_QUOTE_ERROR: return "Quote command returned error"; case CURLE_HTTP_RETURNED_ERROR: return "HTTP response code said error"; case CURLE_WRITE_ERROR: return "Failed writing received data to disk/application"; case CURLE_UPLOAD_FAILED: return "Upload failed (at start/before it took off)"; case CURLE_READ_ERROR: return "Failed to open/read local data from file/application"; case CURLE_OUT_OF_MEMORY: return "Out of memory"; case CURLE_OPERATION_TIMEDOUT: return "Timeout was reached"; case CURLE_FTP_PORT_FAILED: return "FTP: command PORT failed"; case CURLE_FTP_COULDNT_USE_REST: return "FTP: command REST failed"; case CURLE_RANGE_ERROR: return "Requested range was not delivered by the server"; case CURLE_HTTP_POST_ERROR: return "Internal problem setting up the POST"; case CURLE_SSL_CONNECT_ERROR: return "SSL connect error"; case CURLE_BAD_DOWNLOAD_RESUME: return "Couldn't resume download"; case CURLE_FILE_COULDNT_READ_FILE: return "Couldn't read a file:// file"; case CURLE_LDAP_CANNOT_BIND: return "LDAP: cannot bind"; case CURLE_LDAP_SEARCH_FAILED: return "LDAP: search failed"; case CURLE_FUNCTION_NOT_FOUND: return "A required function in the library was not found"; case CURLE_ABORTED_BY_CALLBACK: return "Operation was aborted by an application callback"; case CURLE_BAD_FUNCTION_ARGUMENT: return "A libcurl function was given a bad argument"; case CURLE_INTERFACE_FAILED: return "Failed binding local connection end"; case CURLE_TOO_MANY_REDIRECTS : return "Number of redirects hit maximum amount"; case CURLE_UNKNOWN_OPTION: return "An unknown option was passed in to libcurl"; case CURLE_TELNET_OPTION_SYNTAX : return "Malformed telnet option"; case CURLE_GOT_NOTHING: return "Server returned nothing (no headers, no data)"; case CURLE_SSL_ENGINE_NOTFOUND: return "SSL crypto engine not found"; case CURLE_SSL_ENGINE_SETFAILED: return "Can not set SSL crypto engine as default"; case CURLE_SSL_ENGINE_INITFAILED: return "Failed to initialise SSL crypto engine"; case CURLE_SEND_ERROR: return "Failed sending data to the peer"; case CURLE_RECV_ERROR: return "Failure when receiving data from the peer"; case CURLE_SSL_CERTPROBLEM: return "Problem with the local SSL certificate"; case CURLE_SSL_CIPHER: return "Couldn't use specified SSL cipher"; case CURLE_PEER_FAILED_VERIFICATION: return "SSL peer certificate or SSH remote key was not OK"; case CURLE_SSL_CACERT_BADFILE: return "Problem with the SSL CA cert (path? access rights?)"; case CURLE_BAD_CONTENT_ENCODING: return "Unrecognized or bad HTTP Content or Transfer-Encoding"; case CURLE_LDAP_INVALID_URL: return "Invalid LDAP URL"; case CURLE_FILESIZE_EXCEEDED: return "Maximum file size exceeded"; case CURLE_USE_SSL_FAILED: return "Requested SSL level failed"; case CURLE_SSL_SHUTDOWN_FAILED: return "Failed to shut down the SSL connection"; case CURLE_SSL_CRL_BADFILE: return "Failed to load CRL file (path? access rights?, format?)"; case CURLE_SSL_ISSUER_ERROR: return "Issuer check against peer certificate failed"; case CURLE_SEND_FAIL_REWIND: return "Send failed since rewinding of the data stream failed"; case CURLE_LOGIN_DENIED: return "Login denied"; case CURLE_TFTP_NOTFOUND: return "TFTP: File Not Found"; case CURLE_TFTP_PERM: return "TFTP: Access Violation"; case CURLE_REMOTE_DISK_FULL: return "Disk full or allocation exceeded"; case CURLE_TFTP_ILLEGAL: return "TFTP: Illegal operation"; case CURLE_TFTP_UNKNOWNID: return "TFTP: Unknown transfer ID"; case CURLE_REMOTE_FILE_EXISTS: return "Remote file already exists"; case CURLE_TFTP_NOSUCHUSER: return "TFTP: No such user"; case CURLE_CONV_FAILED: return "Conversion failed"; case CURLE_CONV_REQD: return "Caller must register CURLOPT_CONV_ callback options"; case CURLE_REMOTE_FILE_NOT_FOUND: return "Remote file not found"; case CURLE_SSH: return "Error in the SSH layer"; case CURLE_AGAIN: return "Socket not ready for send/recv"; case CURLE_RTSP_CSEQ_ERROR: return "RTSP CSeq mismatch or invalid CSeq"; case CURLE_RTSP_SESSION_ERROR: return "RTSP session error"; case CURLE_FTP_BAD_FILE_LIST: return "Unable to parse FTP file list"; case CURLE_CHUNK_FAILED: return "Chunk callback failed"; case CURLE_NO_CONNECTION_AVAILABLE: return "The max connection limit is reached"; case CURLE_SSL_PINNEDPUBKEYNOTMATCH: return "SSL public key does not match pinned public key"; case CURLE_SSL_INVALIDCERTSTATUS: return "SSL server certificate status verification FAILED"; case CURLE_HTTP2_STREAM: return "Stream error in the HTTP/2 framing layer"; case CURLE_RECURSIVE_API_CALL: return "API function called from within callback"; case CURLE_AUTH_ERROR: return "An authentication function returned an error"; case CURLE_HTTP3: return "HTTP/3 error"; case CURLE_QUIC_CONNECT_ERROR: return "QUIC connection error"; /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: case CURLE_OBSOLETE29: case CURLE_OBSOLETE32: case CURLE_OBSOLETE40: case CURLE_OBSOLETE44: case CURLE_OBSOLETE46: case CURLE_OBSOLETE50: case CURLE_OBSOLETE51: case CURLE_OBSOLETE57: case CURL_LAST: break; } /* * By using a switch, gcc -Wall will complain about enum values * which do not appear, helping keep this function up-to-date. * By using gcc -Wall -Werror, you can't forget. * * A table would not have the same benefit. Most compilers will * generate code very similar to a table in any case, so there * is little performance gain from a table. And something is broken * for the user's application, anyways, so does it matter how fast * it _doesn't_ work? * * The line number for the error will be near this comment, which * is why it is here, and not at the start of the switch. */ return "Unknown error"; #else if(!error) return "No error"; else return "Error"; #endif } const char * curl_multi_strerror(CURLMcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS switch(error) { case CURLM_CALL_MULTI_PERFORM: return "Please call curl_multi_perform() soon"; case CURLM_OK: return "No error"; case CURLM_BAD_HANDLE: return "Invalid multi handle"; case CURLM_BAD_EASY_HANDLE: return "Invalid easy handle"; case CURLM_OUT_OF_MEMORY: return "Out of memory"; case CURLM_INTERNAL_ERROR: return "Internal error"; case CURLM_BAD_SOCKET: return "Invalid socket argument"; case CURLM_UNKNOWN_OPTION: return "Unknown option"; case CURLM_ADDED_ALREADY: return "The easy handle is already added to a multi handle"; case CURLM_RECURSIVE_API_CALL: return "API function called from within callback"; case CURLM_WAKEUP_FAILURE: return "Wakeup is unavailable or failed"; case CURLM_BAD_FUNCTION_ARGUMENT: return "A libcurl function was given a bad argument"; case CURLM_LAST: break; } return "Unknown error"; #else if(error == CURLM_OK) return "No error"; else return "Error"; #endif } const char * curl_share_strerror(CURLSHcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS switch(error) { case CURLSHE_OK: return "No error"; case CURLSHE_BAD_OPTION: return "Unknown share option"; case CURLSHE_IN_USE: return "Share currently in use"; case CURLSHE_INVALID: return "Invalid share handle"; case CURLSHE_NOMEM: return "Out of memory"; case CURLSHE_NOT_BUILT_IN: return "Feature not enabled in this library"; case CURLSHE_LAST: break; } return "CURLSHcode unknown"; #else if(error == CURLSHE_OK) return "No error"; else return "Error"; #endif } #ifdef USE_WINSOCK /* This is a helper function for Curl_strerror that converts Winsock error * codes (WSAGetLastError) to error messages. * Returns NULL if no error message was found for error code. */ static const char * get_winsock_error (int err, char *buf, size_t len) { #ifndef CURL_DISABLE_VERBOSE_STRINGS const char *p; #endif if(!len) return NULL; *buf = '\0'; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)err; return NULL; #else switch(err) { case WSAEINTR: p = "Call interrupted"; break; case WSAEBADF: p = "Bad file"; break; case WSAEACCES: p = "Bad access"; break; case WSAEFAULT: p = "Bad argument"; break; case WSAEINVAL: p = "Invalid arguments"; break; case WSAEMFILE: p = "Out of file descriptors"; break; case WSAEWOULDBLOCK: p = "Call would block"; break; case WSAEINPROGRESS: case WSAEALREADY: p = "Blocking call in progress"; break; case WSAENOTSOCK: p = "Descriptor is not a socket"; break; case WSAEDESTADDRREQ: p = "Need destination address"; break; case WSAEMSGSIZE: p = "Bad message size"; break; case WSAEPROTOTYPE: p = "Bad protocol"; break; case WSAENOPROTOOPT: p = "Protocol option is unsupported"; break; case WSAEPROTONOSUPPORT: p = "Protocol is unsupported"; break; case WSAESOCKTNOSUPPORT: p = "Socket is unsupported"; break; case WSAEOPNOTSUPP: p = "Operation not supported"; break; case WSAEAFNOSUPPORT: p = "Address family not supported"; break; case WSAEPFNOSUPPORT: p = "Protocol family not supported"; break; case WSAEADDRINUSE: p = "Address already in use"; break; case WSAEADDRNOTAVAIL: p = "Address not available"; break; case WSAENETDOWN: p = "Network down"; break; case WSAENETUNREACH: p = "Network unreachable"; break; case WSAENETRESET: p = "Network has been reset"; break; case WSAECONNABORTED: p = "Connection was aborted"; break; case WSAECONNRESET: p = "Connection was reset"; break; case WSAENOBUFS: p = "No buffer space"; break; case WSAEISCONN: p = "Socket is already connected"; break; case WSAENOTCONN: p = "Socket is not connected"; break; case WSAESHUTDOWN: p = "Socket has been shut down"; break; case WSAETOOMANYREFS: p = "Too many references"; break; case WSAETIMEDOUT: p = "Timed out"; break; case WSAECONNREFUSED: p = "Connection refused"; break; case WSAELOOP: p = "Loop??"; break; case WSAENAMETOOLONG: p = "Name too long"; break; case WSAEHOSTDOWN: p = "Host down"; break; case WSAEHOSTUNREACH: p = "Host unreachable"; break; case WSAENOTEMPTY: p = "Not empty"; break; case WSAEPROCLIM: p = "Process limit reached"; break; case WSAEUSERS: p = "Too many users"; break; case WSAEDQUOT: p = "Bad quota"; break; case WSAESTALE: p = "Something is stale"; break; case WSAEREMOTE: p = "Remote error"; break; #ifdef WSAEDISCON /* missing in SalfordC! */ case WSAEDISCON: p = "Disconnected"; break; #endif /* Extended Winsock errors */ case WSASYSNOTREADY: p = "Winsock library is not ready"; break; case WSANOTINITIALISED: p = "Winsock library not initialised"; break; case WSAVERNOTSUPPORTED: p = "Winsock version not supported"; break; /* getXbyY() errors (already handled in herrmsg): * Authoritative Answer: Host not found */ case WSAHOST_NOT_FOUND: p = "Host not found"; break; /* Non-Authoritative: Host not found, or SERVERFAIL */ case WSATRY_AGAIN: p = "Host not found, try again"; break; /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ case WSANO_RECOVERY: p = "Unrecoverable error in call to nameserver"; break; /* Valid name, no data record of requested type */ case WSANO_DATA: p = "No data record of requested type"; break; default: return NULL; } strncpy(buf, p, len); buf [len-1] = '\0'; return buf; #endif } #endif /* USE_WINSOCK */ #if defined(WIN32) || defined(_WIN32_WCE) /* This is a helper function for Curl_strerror that converts Windows API error * codes (GetLastError) to error messages. * Returns NULL if no error message was found for error code. */ static const char * get_winapi_error(int err, char *buf, size_t buflen) { char *p; if(!buflen) return NULL; *buf = '\0'; #ifdef _WIN32_WCE { wchar_t wbuf[256]; wbuf[0] = L'\0'; if(FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err, LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { size_t written = wcstombs(buf, wbuf, buflen - 1); if(written != (size_t)-1) buf[written] = '\0'; else *buf = '\0'; } } #else if(!FormatMessageA((FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err, LANG_NEUTRAL, buf, (DWORD)buflen, NULL)) { *buf = '\0'; } #endif /* Truncate multiple lines */ p = strchr(buf, '\n'); if(p) { if(p > buf && *(p-1) == '\r') *(p-1) = '\0'; else *p = '\0'; } return (*buf ? buf : NULL); } #endif /* WIN32 || _WIN32_WCE */ /* * Our thread-safe and smart strerror() replacement. * * The 'err' argument passed in to this function MUST be a true errno number * as reported on this system. We do no range checking on the number before * we pass it to the "number-to-message" conversion function and there might * be systems that don't do proper range checking in there themselves. * * We don't do range checking (on systems other than Windows) since there is * no good reliable and portable way to do it. * * On Windows different types of error codes overlap. This function has an * order of preference when trying to match error codes: * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError). * * It may be more correct to call one of the variant functions instead: * Call Curl_sspi_strerror if the error code is definitely Windows SSPI. * Call Curl_winapi_strerror if the error code is definitely Windows API. */ const char *Curl_strerror(int err, char *buf, size_t buflen) { #ifdef PRESERVE_WINDOWS_ERROR_CODE DWORD old_win_err = GetLastError(); #endif int old_errno = errno; char *p; size_t max; if(!buflen) return NULL; DEBUGASSERT(err >= 0); max = buflen - 1; *buf = '\0'; #if defined(WIN32) || defined(_WIN32_WCE) #if defined(WIN32) /* 'sys_nerr' is the maximum errno number, it is not widely portable */ if(err >= 0 && err < sys_nerr) strncpy(buf, strerror(err), max); else #endif { if( #ifdef USE_WINSOCK !get_winsock_error(err, buf, max) && #endif !get_winapi_error((DWORD)err, buf, max)) msnprintf(buf, max, "Unknown error %d (%#x)", err, err); } #else /* not Windows coming up */ #if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) /* * The POSIX-style strerror_r() may set errno to ERANGE if insufficient * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated * message string, or EINVAL if 'errnum' is not a valid error number. */ if(0 != strerror_r(err, buf, max)) { if('\0' == buf[0]) msnprintf(buf, max, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) /* * The glibc-style strerror_r() only *might* use the buffer we pass to * the function, but it always returns the error message as a pointer, * so we must copy that string unconditionally (if non-NULL). */ { char buffer[256]; char *msg = strerror_r(err, buffer, sizeof(buffer)); if(msg) strncpy(buf, msg, max); else msnprintf(buf, max, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R) /* * The vxworks-style strerror_r() does use the buffer we pass to the function. * The buffer size should be at least NAME_MAX (256) */ { char buffer[256]; if(OK == strerror_r(err, buffer)) strncpy(buf, buffer, max); else msnprintf(buf, max, "Unknown error %d", err); } #else { char *msg = strerror(err); if(msg) strncpy(buf, msg, max); else msnprintf(buf, max, "Unknown error %d", err); } #endif #endif /* end of not Windows */ buf[max] = '\0'; /* make sure the string is zero terminated */ /* strip trailing '\r\n' or '\n'. */ p = strrchr(buf, '\n'); if(p && (p - buf) >= 2) *p = '\0'; p = strrchr(buf, '\r'); if(p && (p - buf) >= 1) *p = '\0'; if(errno != old_errno) errno = old_errno; #ifdef PRESERVE_WINDOWS_ERROR_CODE if(old_win_err != GetLastError()) SetLastError(old_win_err); #endif return buf; } /* * Curl_winapi_strerror: * Variant of Curl_strerror if the error code is definitely Windows API. */ #if defined(WIN32) || defined(_WIN32_WCE) const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen) { #ifdef PRESERVE_WINDOWS_ERROR_CODE DWORD old_win_err = GetLastError(); #endif int old_errno = errno; if(!buflen) return NULL; *buf = '\0'; #ifndef CURL_DISABLE_VERBOSE_STRINGS if(!get_winapi_error(err, buf, buflen)) { msnprintf(buf, buflen, "Unknown error %u (0x%08X)", err, err); } #else { const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error"; strncpy(buf, txt, buflen); buf[buflen - 1] = '\0'; } #endif if(errno != old_errno) errno = old_errno; #ifdef PRESERVE_WINDOWS_ERROR_CODE if(old_win_err != GetLastError()) SetLastError(old_win_err); #endif return buf; } #endif /* WIN32 || _WIN32_WCE */ #ifdef USE_WINDOWS_SSPI /* * Curl_sspi_strerror: * Variant of Curl_strerror if the error code is definitely Windows SSPI. */ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) { #ifdef PRESERVE_WINDOWS_ERROR_CODE DWORD old_win_err = GetLastError(); #endif int old_errno = errno; const char *txt; if(!buflen) return NULL; *buf = '\0'; #ifndef CURL_DISABLE_VERBOSE_STRINGS switch(err) { case SEC_E_OK: txt = "No error"; break; #define SEC2TXT(sec) case sec: txt = #sec; break SEC2TXT(CRYPT_E_REVOKED); SEC2TXT(SEC_E_ALGORITHM_MISMATCH); SEC2TXT(SEC_E_BAD_BINDINGS); SEC2TXT(SEC_E_BAD_PKGID); SEC2TXT(SEC_E_BUFFER_TOO_SMALL); SEC2TXT(SEC_E_CANNOT_INSTALL); SEC2TXT(SEC_E_CANNOT_PACK); SEC2TXT(SEC_E_CERT_EXPIRED); SEC2TXT(SEC_E_CERT_UNKNOWN); SEC2TXT(SEC_E_CERT_WRONG_USAGE); SEC2TXT(SEC_E_CONTEXT_EXPIRED); SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE); SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID); SEC2TXT(SEC_E_DECRYPT_FAILURE); SEC2TXT(SEC_E_DELEGATION_POLICY); SEC2TXT(SEC_E_DELEGATION_REQUIRED); SEC2TXT(SEC_E_DOWNGRADE_DETECTED); SEC2TXT(SEC_E_ENCRYPT_FAILURE); SEC2TXT(SEC_E_ILLEGAL_MESSAGE); SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS); SEC2TXT(SEC_E_INCOMPLETE_MESSAGE); SEC2TXT(SEC_E_INSUFFICIENT_MEMORY); SEC2TXT(SEC_E_INTERNAL_ERROR); SEC2TXT(SEC_E_INVALID_HANDLE); SEC2TXT(SEC_E_INVALID_PARAMETER); SEC2TXT(SEC_E_INVALID_TOKEN); SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED); SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC); SEC2TXT(SEC_E_KDC_CERT_EXPIRED); SEC2TXT(SEC_E_KDC_CERT_REVOKED); SEC2TXT(SEC_E_KDC_INVALID_REQUEST); SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER); SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE); SEC2TXT(SEC_E_LOGON_DENIED); SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED); SEC2TXT(SEC_E_MESSAGE_ALTERED); SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS); SEC2TXT(SEC_E_MUST_BE_KDC); SEC2TXT(SEC_E_NOT_OWNER); SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY); SEC2TXT(SEC_E_NO_CREDENTIALS); SEC2TXT(SEC_E_NO_IMPERSONATION); SEC2TXT(SEC_E_NO_IP_ADDRESSES); SEC2TXT(SEC_E_NO_KERB_KEY); SEC2TXT(SEC_E_NO_PA_DATA); SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT); SEC2TXT(SEC_E_NO_TGT_REPLY); SEC2TXT(SEC_E_OUT_OF_SEQUENCE); SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE); SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH); SEC2TXT(SEC_E_POLICY_NLTM_ONLY); SEC2TXT(SEC_E_QOP_NOT_SUPPORTED); SEC2TXT(SEC_E_REVOCATION_OFFLINE_C); SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC); SEC2TXT(SEC_E_SECPKG_NOT_FOUND); SEC2TXT(SEC_E_SECURITY_QOS_FAILED); SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS); SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED); SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED); SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED); SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED); SEC2TXT(SEC_E_TARGET_UNKNOWN); SEC2TXT(SEC_E_TIME_SKEW); SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS); SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED); SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS); SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION); SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH); SEC2TXT(SEC_E_UNTRUSTED_ROOT); SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE); SEC2TXT(SEC_E_WRONG_PRINCIPAL); SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE); SEC2TXT(SEC_I_COMPLETE_NEEDED); SEC2TXT(SEC_I_CONTEXT_EXPIRED); SEC2TXT(SEC_I_CONTINUE_NEEDED); SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS); SEC2TXT(SEC_I_LOCAL_LOGON); SEC2TXT(SEC_I_NO_LSA_CONTEXT); SEC2TXT(SEC_I_RENEGOTIATE); SEC2TXT(SEC_I_SIGNATURE_NEEDED); default: txt = "Unknown error"; } if(err == SEC_E_ILLEGAL_MESSAGE) { msnprintf(buf, buflen, "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " "when a fatal SSL/TLS alert is received (e.g. handshake failed)." " More detail may be available in the Windows System event log.", err); } else { char txtbuf[80]; char msgbuf[256]; msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); if(get_winapi_error(err, msgbuf, sizeof(msgbuf))) msnprintf(buf, buflen, "%s - %s", txtbuf, msgbuf); else { strncpy(buf, txtbuf, buflen); buf[buflen - 1] = '\0'; } } #else if(err == SEC_E_OK) txt = "No error"; else txt = "Error"; strncpy(buf, txt, buflen); buf[buflen - 1] = '\0'; #endif if(errno != old_errno) errno = old_errno; #ifdef PRESERVE_WINDOWS_ERROR_CODE if(old_win_err != GetLastError()) SetLastError(old_win_err); #endif return buf; } #endif /* USE_WINDOWS_SSPI */ davix-0.8.0/deps/curl/lib/socketpair.c0000644000000000000000000000645214121063461016313 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "socketpair.h" #ifndef HAVE_SOCKETPAIR #ifdef WIN32 /* * This is a socketpair() implementation for Windows. */ #include #include #include #include #include #else #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_NETINET_IN_H #include /* IPPROTO_TCP */ #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 #endif /* !INADDR_LOOPBACK */ #endif /* !WIN32 */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" int Curl_socketpair(int domain, int type, int protocol, curl_socket_t socks[2]) { union { struct sockaddr_in inaddr; struct sockaddr addr; } a; curl_socket_t listener; curl_socklen_t addrlen = sizeof(a.inaddr); int reuse = 1; char data[2][12]; ssize_t dlen; (void)domain; (void)type; (void)protocol; listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listener == CURL_SOCKET_BAD) return -1; memset(&a, 0, sizeof(a)); a.inaddr.sin_family = AF_INET; a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.inaddr.sin_port = 0; socks[0] = socks[1] = CURL_SOCKET_BAD; if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1) goto error; if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1) goto error; if(getsockname(listener, &a.addr, &addrlen) == -1) goto error; if(listen(listener, 1) == -1) goto error; socks[0] = socket(AF_INET, SOCK_STREAM, 0); if(socks[0] == CURL_SOCKET_BAD) goto error; if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) goto error; socks[1] = accept(listener, NULL, NULL); if(socks[1] == CURL_SOCKET_BAD) goto error; /* verify that nothing else connected */ msnprintf(data[0], sizeof(data[0]), "%p", socks); dlen = strlen(data[0]); if(swrite(socks[0], data[0], dlen) != dlen) goto error; if(sread(socks[1], data[1], sizeof(data[1])) != dlen) goto error; if(memcmp(data[0], data[1], dlen)) goto error; sclose(listener); return 0; error: sclose(listener); sclose(socks[0]); sclose(socks[1]); return -1; } #endif /* ! HAVE_SOCKETPAIR */ davix-0.8.0/deps/curl/lib/pingpong.h0000644000000000000000000001256114121063461015773 0ustar rootroot#ifndef HEADER_CURL_PINGPONG_H #define HEADER_CURL_PINGPONG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP) #define USE_PINGPONG #endif /* forward-declaration, this is defined in urldata.h */ struct connectdata; typedef enum { FTPTRANSFER_BODY, /* yes do transfer a body */ FTPTRANSFER_INFO, /* do still go through to get info/headers */ FTPTRANSFER_NONE, /* don't get anything and don't get info */ FTPTRANSFER_LAST /* end of list marker, never used */ } curl_pp_transfer; /* * 'pingpong' is the generic struct used for protocols doing server<->client * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc. * * It holds response cache and non-blocking sending data. */ struct pingpong { char *cache; /* data cache between getresponse()-calls */ size_t cache_size; /* size of cache in bytes */ size_t nread_resp; /* number of bytes currently read of a server response */ char *linestart_resp; /* line start pointer for the server response reader function */ bool pending_resp; /* set TRUE when a server response is pending or in progress, and is cleared once the last response is read */ char *sendthis; /* allocated pointer to a buffer that is to be sent to the server */ size_t sendleft; /* number of bytes left to send from the sendthis buffer */ size_t sendsize; /* total size of the sendthis buffer */ struct curltime response; /* set to Curl_now() when a command has been sent off, used to time-out response reading */ long response_time; /* When no timeout is given, this is the amount of milliseconds we await for a server response. */ struct connectdata *conn; /* points to the connectdata struct that this belongs to */ /* Function pointers the protocols MUST implement and provide for the pingpong layer to function */ CURLcode (*statemach_act)(struct connectdata *conn); bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len, int *code); }; /* * Curl_pp_statemach() * * called repeatedly until done. Set 'wait' to make it wait a while on the * socket if there's no traffic. */ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block, bool disconnecting); /* initialize stuff to prepare for reading a fresh new response */ void Curl_pp_init(struct pingpong *pp); /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting); /*********************************************************************** * * Curl_pp_sendf() * * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, const char *fmt, ...); /*********************************************************************** * * Curl_pp_vsendf() * * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, const char *fmt, va_list args); /* * Curl_pp_readresp() * * Reads a piece of a server response. */ CURLcode Curl_pp_readresp(curl_socket_t sockfd, struct pingpong *pp, int *code, /* return the server code if done */ size_t *size); /* size of the response */ CURLcode Curl_pp_flushsend(struct pingpong *pp); /* call this when a pingpong connection is disconnected */ CURLcode Curl_pp_disconnect(struct pingpong *pp); int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks); /*********************************************************************** * * Curl_pp_moredata() * * Returns whether there are still more data in the cache and so a call * to Curl_pp_readresp() will not block. */ bool Curl_pp_moredata(struct pingpong *pp); #endif /* HEADER_CURL_PINGPONG_H */ davix-0.8.0/deps/curl/lib/curl_memrchr.c0000644000000000000000000000337214121063461016627 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "curl_memrchr.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #ifndef HAVE_MEMRCHR /* * Curl_memrchr() * * Our memrchr() function clone for systems which lack this function. The * memrchr() function is like the memchr() function, except that it searches * backwards from the end of the n bytes pointed to by s instead of forward * from the beginning. */ void * Curl_memrchr(const void *s, int c, size_t n) { if(n > 0) { const unsigned char *p = s; const unsigned char *q = s; p += n - 1; while(p >= q) { if(*p == (unsigned char)c) return (void *)p; p--; } } return NULL; } #endif /* HAVE_MEMRCHR */ davix-0.8.0/deps/curl/lib/mk-ca-bundle.vbs0000755000000000000000000004035014121063461016754 0ustar rootroot'*************************************************************************** '* _ _ ____ _ '* Project ___| | | | _ \| | '* / __| | | | |_) | | '* | (__| |_| | _ <| |___ '* \___|\___/|_| \_\_____| '* '* Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. '* '* This software is licensed as described in the file COPYING, which '* you should have received as part of this distribution. The terms '* are also available at https://curl.haxx.se/docs/copyright.html. '* '* You may opt to use, copy, modify, merge, publish, distribute and/or sell '* copies of the Software, and permit persons to whom the Software is '* furnished to do so, under the terms of the COPYING file. '* '* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY '* KIND, either express or implied. '* '*************************************************************************** '* Script to fetch certdata.txt from Mozilla.org site and create a '* ca-bundle.crt for use with OpenSSL / libcurl / libcurl bindings '* Requires WinHttp.WinHttpRequest.5.1 and ADODB.Stream which are part of '* W2000 SP3 or later, WXP SP1 or later, W2003 Server SP1 or later. '* Hacked by Guenter Knauf '*************************************************************************** Option Explicit Const myVersion = "0.4.0" Const myUrl = "https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt" Const myOpenSSL = "openssl.exe" Dim myUseOpenSSL myUseOpenSSL = TRUE ' Flag: TRUE to use OpenSSL. If TRUE and is not ' found then a warning is shown before continuing. Const myCdSavF = TRUE ' Flag: save downloaded data to file certdata.txt Const myCaBakF = TRUE ' Flag: backup existing ca-bundle certificate Const myAskLiF = TRUE ' Flag: display certdata.txt license agreement Const myWrapLe = 76 ' Default length of base64 output lines ' cert info code doesn't work properly with any recent openssl, leave disabled. ' Also: we want our certificate output by default to be as similar as possible ' to mk-ca-bundle.pl and setting this TRUE changes the base64 width to ' OpenSSL's built-in default width, which is not the same as mk-ca-bundle.pl. Const myAskTiF = FALSE ' Flag: ask to include certificate text info ' '******************* Nothing to configure below! ******************* ' Const adTypeBinary = 1 Const adTypeText = 2 Const adSaveCreateNotExist = 1 Const adSaveCreateOverWrite = 2 Dim objShell, objNetwork, objFSO, objHttp Dim myBase, mySelf, myStream, myTmpFh, myCdData, myCdFile Dim myCaFile, myTmpName, myBakNum, myOptTxt, i Set objNetwork = WScript.CreateObject("WScript.Network") Set objShell = WScript.CreateObject("WScript.Shell") Set objFSO = WScript.CreateObject("Scripting.FileSystemObject") Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest.5.1") If objHttp Is Nothing Then Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest") myBase = Left(WScript.ScriptFullName, InstrRev(WScript.ScriptFullName, "\")) mySelf = Left(WScript.ScriptName, InstrRev(WScript.ScriptName, ".") - 1) & " " & myVersion myCdFile = Mid(myUrl, InstrRev(myUrl, "/") + 1) myCaFile = "ca-bundle.crt" myTmpName = InputBox("It will take a minute to download and parse the " & _ "certificate data." & _ vbLf & vbLf & _ "Please enter the output filename:", mySelf, myCaFile) If (myTmpName = "") Then WScript.Quit 1 End If myCaFile = myTmpName If (myCdFile = "") Then MsgBox("URL does not contain filename!"), vbCritical, mySelf WScript.Quit 1 End If ' Don't use OpenSSL if it's not present. If (myUseOpenSSL = TRUE) Then Dim errnum On Error Resume Next Call objShell.Run("""" & myOpenSSL & """ version", 0, TRUE) errnum = Err.Number On Error GoTo 0 If Not (errnum = 0) Then myUseOpenSSL = FALSE MsgBox("OpenSSL was not found so the certificate bundle will not " & _ "include the SHA256 hash of the raw certificate data file " & _ "that was used to generate the certificates in the bundle. " & _ vbLf & vbLf & _ "This does not have any effect on the certificate output, " & _ "so this script will continue." & _ vbLf & vbLf & _ "If you want to set a custom location for OpenSSL or disable " & _ "this message then edit the variables at the start of the " & _ "script."), vbInformation, mySelf End If End If If (myAskTiF = TRUE) And (myUseOpenSSL = TRUE) Then If (6 = objShell.PopUp("Do you want to include text information about " & _ "each certificate?" & vbLf & _ "(Requires OpenSSL.exe in the current directory " & _ "or search path)",, _ mySelf, vbQuestion + vbYesNo + vbDefaultButton2)) Then myOptTxt = TRUE Else myOptTxt = FALSE End If End If ' Uncomment the line below to ignore SSL invalid cert errors ' objHttp.Option(4) = 256 + 512 + 4096 + 8192 objHttp.SetTimeouts 0, 5000, 10000, 10000 objHttp.Open "GET", myUrl, FALSE objHttp.setRequestHeader "User-Agent", WScript.ScriptName & "/" & myVersion objHttp.Send "" If Not (objHttp.Status = 200) Then MsgBox("Failed to download '" & myCdFile & "': " & objHttp.Status & " - " & objHttp.StatusText), vbCritical, mySelf WScript.Quit 1 End If ' Write received data to file if enabled If (myCdSavF = TRUE) Then Call SaveBinaryData(myCdFile, objHttp.ResponseBody) End If ' Convert data from ResponseBody instead of using ResponseText because of UTF-8 myCdData = ConvertBinaryToUTF8(objHttp.ResponseBody) Set objHttp = Nothing ' Backup exitsing ca-bundle certificate file If (myCaBakF = TRUE) Then If objFSO.FileExists(myCaFile) Then Dim myBakFile, b b = 1 myBakFile = myCaFile & ".~" & b & "~" While objFSO.FileExists(myBakFile) b = b + 1 myBakFile = myCaFile & ".~" & b & "~" Wend Set myTmpFh = objFSO.GetFile(myCaFile) myTmpFh.Move myBakFile End If End If ' Process the received data Dim myLines, myPattern, myInsideCert, myInsideLicense, myLicenseText, myNumCerts, myNumSkipped Dim myLabel, myOctets, myData, myPem, myRev, myUntrusted, j myNumSkipped = 0 myNumCerts = 0 myData = "" myLines = Split(myCdData, vbLf, -1) Set myStream = CreateObject("ADODB.Stream") myStream.Open myStream.Type = adTypeText myStream.Charset = "utf-8" myStream.WriteText "##" & vbLf & _ "## Bundle of CA Root Certificates" & vbLf & _ "##" & vbLf & _ "## Certificate data from Mozilla as of: " & _ ConvertDateToString(LocalDateToUTC(Now)) & " GMT" & vbLf & _ "##" & vbLf & _ "## This is a bundle of X.509 certificates of public Certificate Authorities" & vbLf & _ "## (CA). These were automatically extracted from Mozilla's root certificates" & vbLf & _ "## file (certdata.txt). This file can be found in the mozilla source tree:" & vbLf & _ "## " & myUrl & vbLf & _ "##" & vbLf & _ "## It contains the certificates in PEM format and therefore" & vbLf & _ "## can be directly used with curl / libcurl / php_curl, or with" & vbLf & _ "## an Apache+mod_ssl webserver for SSL client authentication." & vbLf & _ "## Just configure this file as the SSLCACertificateFile." & vbLf & _ "##" & vbLf & _ "## Conversion done with mk-ca-bundle.vbs version " & myVersion & "." & vbLf If (myCdSavF = TRUE) And (myUseOpenSSL = TRUE) Then myStream.WriteText "## SHA256: " & FileSHA256(myCdFile) & vbLf End If myStream.WriteText "##" & vbLf & vbLf myStream.WriteText vbLf For i = 0 To UBound(myLines) If InstrRev(myLines(i), "CKA_LABEL ") Then myPattern = "^CKA_LABEL\s+[A-Z0-9]+\s+""(.+?)""" myLabel = RegExprFirst(myPattern, myLines(i)) End If If (myInsideCert = TRUE) Then If InstrRev(myLines(i), "END") Then myInsideCert = FALSE While (i < UBound(myLines)) And Not (myLines(i) = "#") i = i + 1 If InstrRev(myLines(i), "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR") Then myUntrusted = FALSE End If Wend If (myUntrusted = TRUE) Then myNumSkipped = myNumSkipped + 1 Else myStream.WriteText myLabel & vbLf myStream.WriteText String(Len(myLabel), "=") & vbLf myPem = "-----BEGIN CERTIFICATE-----" & vbLf & _ Base64Encode(myData) & vbLf & _ "-----END CERTIFICATE-----" & vbLf If (myOptTxt = FALSE) Then myStream.WriteText myPem & vbLf Else Dim myCmd, myRval, myTmpIn, myTmpOut myTmpIn = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName myTmpOut = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName Set myTmpFh = objFSO.OpenTextFile(myTmpIn, 2, TRUE) myTmpFh.Write myPem myTmpFh.Close myCmd = """" & myOpenSSL & """ x509 -md5 -fingerprint -text " & _ "-inform PEM -in " & myTmpIn & " -out " & myTmpOut myRval = objShell.Run (myCmd, 0, TRUE) objFSO.DeleteFile myTmpIn, TRUE If Not (myRval = 0) Then MsgBox("Failed to process PEM cert with OpenSSL commandline!"), vbCritical, mySelf objFSO.DeleteFile myTmpOut, TRUE WScript.Quit 3 End If Set myTmpFh = objFSO.OpenTextFile(myTmpOut, 1) myStream.WriteText myTmpFh.ReadAll & vbLf myTmpFh.Close objFSO.DeleteFile myTmpOut, TRUE End If myNumCerts = myNumCerts + 1 End If Else myOctets = Split(myLines(i), "\") For j = 1 To UBound(myOctets) myData = myData & Chr(CByte("&o" & myOctets(j))) Next End If End If If InstrRev(myLines(i), "CVS_ID ") Then myPattern = "^CVS_ID\s+""(.+?)""" myRev = RegExprFirst(myPattern, myLines(i)) myStream.WriteText "# " & myRev & vbLf & vbLf End If If InstrRev(myLines(i), "CKA_VALUE MULTILINE_OCTAL") Then myInsideCert = TRUE myUntrusted = TRUE myData = "" End If If InstrRev(myLines(i), "***** BEGIN LICENSE BLOCK *****") Then myInsideLicense = TRUE End If If (myInsideLicense = TRUE) Then myStream.WriteText myLines(i) & vbLf myLicenseText = myLicenseText & Mid(myLines(i), 2) & vbLf End If If InstrRev(myLines(i), "***** END LICENSE BLOCK *****") Then myInsideLicense = FALSE If (myAskLiF = TRUE) Then If Not (6 = objShell.PopUp(myLicenseText & vbLf & _ "Do you agree to the license shown above (required to proceed) ?",, _ mySelf, vbQuestion + vbYesNo + vbDefaultButton1)) Then myStream.Close objFSO.DeleteFile myCaFile, TRUE WScript.Quit 2 End If End If End If Next ' To stop the UTF-8 BOM from being written the stream has to be copied and ' then saved as binary. Dim myCopy Set myCopy = CreateObject("ADODB.Stream") myCopy.Type = adTypeBinary myCopy.Open myStream.Position = 3 ' Skip UTF-8 BOM myStream.CopyTo myCopy myCopy.SaveToFile myCaFile, adSaveCreateOverWrite myCopy.Close myStream.Close Set myCopy = Nothing Set myStream = Nothing ' Done objShell.PopUp "Done (" & myNumCerts & " CA certs processed, " & myNumSkipped & _ " untrusted skipped).", 20, mySelf, vbInformation WScript.Quit 0 Function ConvertBinaryToUTF8(arrBytes) Dim objStream Set objStream = CreateObject("ADODB.Stream") objStream.Open objStream.Type = adTypeBinary objStream.Write arrBytes objStream.Position = 0 objStream.Type = adTypeText objStream.Charset = "utf-8" ConvertBinaryToUTF8 = objStream.ReadText Set objStream = Nothing End Function Function SaveBinaryData(filename, data) Dim objStream Set objStream = CreateObject("ADODB.Stream") objStream.Type = adTypeBinary objStream.Open objStream.Write data objStream.SaveToFile filename, adSaveCreateOverWrite objStream.Close Set objStream = Nothing End Function Function RegExprFirst(SearchPattern, TheString) Dim objRegExp, Matches ' create variables. Set objRegExp = New RegExp ' create a regular expression. objRegExp.Pattern = SearchPattern ' sets the search pattern. objRegExp.IgnoreCase = TRUE ' set to ignores case. objRegExp.Global = TRUE ' set to global search. Set Matches = objRegExp.Execute(TheString) ' do the search. If (Matches.Count) Then RegExprFirst = Matches(0).SubMatches(0) ' return first match. Else RegExprFirst = "" End If Set objRegExp = Nothing End Function Function Base64Encode(inData) Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" Dim cOut, sOut, lWrap, I lWrap = Int(myWrapLe * 3 / 4) 'For each group of 3 bytes For I = 1 To Len(inData) Step 3 Dim nGroup, pOut, sGroup 'Create one long from this 3 bytes. nGroup = &H10000 * Asc(Mid(inData, I, 1)) + _ &H100 * MyASC(Mid(inData, I + 1, 1)) + _ MyASC(Mid(inData, I + 2, 1)) 'Oct splits the long To 8 groups with 3 bits nGroup = Oct(nGroup) 'Add leading zeros nGroup = String(8 - Len(nGroup), "0") & nGroup 'Convert To base64 pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) & _ Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) & _ Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) & _ Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1) 'Add the part To OutPut string sOut = sOut + pOut 'Add a new line For Each myWrapLe chars In dest If (I < Len(inData) - 2) Then If (I + 2) Mod lWrap = 0 Then sOut = sOut & vbLf End If Next Select Case Len(inData) Mod 3 Case 1: '8 bit final sOut = Left(sOut, Len(sOut) - 2) & "==" Case 2: '16 bit final sOut = Left(sOut, Len(sOut) - 1) & "=" End Select Base64Encode = sOut End Function Function MyASC(OneChar) If OneChar = "" Then MyASC = 0 Else MyASC = Asc(OneChar) End Function ' Return the date in the same format as perl to match mk-ca-bundle.pl output: ' Wed Sep 7 03:12:05 2016 Function ConvertDateToString(input) Dim output output = WeekDayName(WeekDay(input), TRUE) & " " & _ MonthName(Month(input), TRUE) & " " If (Len(Day(input)) = 1) Then output = output & " " End If output = output & _ Day(input) & " " & _ FormatDateTime(input, vbShortTime) & ":" If (Len(Second(input)) = 1) Then output = output & "0" End If output = output & _ Second(input) & " " & _ Year(input) ConvertDateToString = output End Function ' Convert local Date to UTC. Microsoft says: ' Use Win32_ComputerSystem CurrentTimeZone property, because it automatically ' adjusts the Time Zone bias for daylight saving time; Win32_Time Zone Bias ' property does not. ' https://msdn.microsoft.com/en-us/library/windows/desktop/ms696015.aspx Function LocalDateToUTC(localdate) Dim item, offset For Each item In GetObject("winmgmts:").InstancesOf("Win32_ComputerSystem") offset = item.CurrentTimeZone ' the offset in minutes Next If (offset < 0) Then LocalDateToUTC = DateAdd("n", ABS(offset), localdate) Else LocalDateToUTC = DateAdd("n", -ABS(offset), localdate) End If 'objShell.PopUp LocalDateToUTC End Function Function FileSHA256(filename) Dim cmd, rval, tmpOut, tmpFh if (myUseOpenSSL = TRUE) Then tmpOut = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName cmd = """" & myOpenSSL & """ dgst -r -sha256 -out """ & tmpOut & """ """ & filename & """" rval = objShell.Run(cmd, 0, TRUE) If Not (rval = 0) Then MsgBox("Failed to get sha256 of """ & filename & """ with OpenSSL commandline!"), vbCritical, mySelf objFSO.DeleteFile tmpOut, TRUE WScript.Quit 3 End If Set tmpFh = objFSO.OpenTextFile(tmpOut, 1) FileSHA256 = RegExprFirst("^([0-9a-f]{64}) .+", tmpFh.ReadAll) tmpFh.Close objFSO.DeleteFile tmpOut, TRUE Else FileSHA256 = "" End If End Function davix-0.8.0/deps/curl/lib/base64.c0000644000000000000000000002077614121063461015240 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Base64 encoding/decoding */ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \ !defined(CURL_DISABLE_LDAP) || \ !defined(CURL_DISABLE_DOH) || defined(USE_SSL) #include "urldata.h" /* for the Curl_easy definition */ #include "warnless.h" #include "curl_base64.h" #include "non-ascii.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* ---- Base64 Encoding/Decoding Table --- */ static const char base64[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 section 5 */ static const char base64url[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; static size_t decodeQuantum(unsigned char *dest, const char *src) { size_t padding = 0; const char *s, *p; unsigned long i, x = 0; for(i = 0, s = src; i < 4; i++, s++) { if(*s == '=') { x = (x << 6); padding++; } else { unsigned long v = 0; p = base64; while(*p && (*p != *s)) { v++; p++; } if(*p == *s) x = (x << 6) + v; else return 0; } } if(padding < 1) dest[2] = curlx_ultouc(x & 0xFFUL); x >>= 8; if(padding < 2) dest[1] = curlx_ultouc(x & 0xFFUL); x >>= 8; dest[0] = curlx_ultouc(x & 0xFFUL); return 3 - padding; } /* * Curl_base64_decode() * * Given a base64 NUL-terminated string at src, decode it and return a * pointer in *outptr to a newly allocated memory area holding decoded * data. Size of decoded data is returned in variable pointed by outlen. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * * When decoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen) { size_t srclen = 0; size_t length = 0; size_t padding = 0; size_t i; size_t numQuantums; size_t rawlen = 0; unsigned char *pos; unsigned char *newstr; *outptr = NULL; *outlen = 0; srclen = strlen(src); /* Check the length of the input string is valid */ if(!srclen || srclen % 4) return CURLE_BAD_CONTENT_ENCODING; /* Find the position of any = padding characters */ while((src[length] != '=') && src[length]) length++; /* A maximum of two = padding characters is allowed */ if(src[length] == '=') { padding++; if(src[length + 1] == '=') padding++; } /* Check the = padding characters weren't part way through the input */ if(length + padding != srclen) return CURLE_BAD_CONTENT_ENCODING; /* Calculate the number of quantums */ numQuantums = srclen / 4; /* Calculate the size of the decoded string */ rawlen = (numQuantums * 3) - padding; /* Allocate our buffer including room for a zero terminator */ newstr = malloc(rawlen + 1); if(!newstr) return CURLE_OUT_OF_MEMORY; pos = newstr; /* Decode the quantums */ for(i = 0; i < numQuantums; i++) { size_t result = decodeQuantum(pos, src); if(!result) { free(newstr); return CURLE_BAD_CONTENT_ENCODING; } pos += result; src += 4; } /* Zero terminate */ *pos = '\0'; /* Return the decoded data */ *outptr = newstr; *outlen = rawlen; return CURLE_OK; } static CURLcode base64_encode(const char *table64, struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { CURLcode result; unsigned char ibuf[3]; unsigned char obuf[4]; int i; int inputparts; char *output; char *base64data; char *convbuf = NULL; const char *indata = inputbuff; *outptr = NULL; *outlen = 0; if(!insize) insize = strlen(indata); #if SIZEOF_SIZE_T == 4 if(insize > UINT_MAX/4) return CURLE_OUT_OF_MEMORY; #endif base64data = output = malloc(insize * 4 / 3 + 4); if(!output) return CURLE_OUT_OF_MEMORY; /* * The base64 data needs to be created using the network encoding * not the host encoding. And we can't change the actual input * so we copy it to a buffer, translate it, and use that instead. */ result = Curl_convert_clone(data, indata, insize, &convbuf); if(result) { free(output); return result; } if(convbuf) indata = (char *)convbuf; while(insize > 0) { for(i = inputparts = 0; i < 3; i++) { if(insize > 0) { inputparts++; ibuf[i] = (unsigned char) *indata; indata++; insize--; } else ibuf[i] = 0; } obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ ((ibuf[1] & 0xF0) >> 4)); obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ ((ibuf[2] & 0xC0) >> 6)); obuf[3] = (unsigned char) (ibuf[2] & 0x3F); switch(inputparts) { case 1: /* only one byte read */ msnprintf(output, 5, "%c%c==", table64[obuf[0]], table64[obuf[1]]); break; case 2: /* two bytes read */ msnprintf(output, 5, "%c%c%c=", table64[obuf[0]], table64[obuf[1]], table64[obuf[2]]); break; default: msnprintf(output, 5, "%c%c%c%c", table64[obuf[0]], table64[obuf[1]], table64[obuf[2]], table64[obuf[3]]); break; } output += 4; } /* Zero terminate */ *output = '\0'; /* Return the pointer to the new data (allocated memory) */ *outptr = base64data; free(convbuf); /* Return the length of the new data */ *outlen = strlen(base64data); return CURLE_OK; } /* * Curl_base64_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding * encoded data. Size of encoded data is returned in variable pointed by * outlen. * * Input length of 0 indicates input buffer holds a NUL-terminated string. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * * When encoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { return base64_encode(base64, data, inputbuff, insize, outptr, outlen); } /* * Curl_base64url_encode() * * Given a pointer to an input buffer and an input size, encode it and * return a pointer in *outptr to a newly allocated memory area holding * encoded data. Size of encoded data is returned in variable pointed by * outlen. * * Input length of 0 indicates input buffer holds a NUL-terminated string. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * * When encoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { return base64_encode(base64url, data, inputbuff, insize, outptr, outlen); } #endif /* no users so disabled */ davix-0.8.0/deps/curl/lib/amigaos.c0000644000000000000000000000457514121063461015573 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef __AMIGA__ # include "amigaos.h" # if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL) # include # endif # ifdef __libnix__ # include # endif #endif /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" #ifdef __AMIGA__ #if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL) struct Library *SocketBase = NULL; extern int errno, h_errno; #ifdef __libnix__ void __request(const char *msg); #else # define __request(msg) Printf(msg "\n\a") #endif void Curl_amiga_cleanup() { if(SocketBase) { CloseLibrary(SocketBase); SocketBase = NULL; } } bool Curl_amiga_init() { if(!SocketBase) SocketBase = OpenLibrary("bsdsocket.library", 4); if(!SocketBase) { __request("No TCP/IP Stack running!"); return FALSE; } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { __request("SocketBaseTags ERROR"); return FALSE; } #ifndef __libnix__ atexit(Curl_amiga_cleanup); #endif return TRUE; } #ifdef __libnix__ ADD2EXIT(Curl_amiga_cleanup, -50); #endif #endif /* HAVE_PROTO_BSDSOCKET_H */ #ifdef USE_AMISSL void Curl_amiga_X509_free(X509 *a) { X509_free(a); } #endif /* USE_AMISSL */ #endif /* __AMIGA__ */ davix-0.8.0/deps/curl/lib/http_chunks.c0000644000000000000000000002652014121063461016477 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_HTTP #include "urldata.h" /* it includes http_chunks.h */ #include "sendf.h" /* for the client write stuff */ #include "content_encoding.h" #include "http.h" #include "non-ascii.h" /* for Curl_convert_to_network prototype */ #include "strtoofft.h" #include "warnless.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* * Chunk format (simplified): * * [ chunk extension ] CRLF * CRLF * * Highlights from RFC2616 section 3.6 say: The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing entity-header fields. This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message. Chunked-Body = *chunk last-chunk trailer CRLF chunk = chunk-size [ chunk-extension ] CRLF chunk-data CRLF chunk-size = 1*HEX last-chunk = 1*("0") [ chunk-extension ] CRLF chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token | quoted-string chunk-data = chunk-size(OCTET) trailer = *(entity-header CRLF) The chunk-size field is a string of hex digits indicating the size of the chunk. The chunked encoding is ended by any chunk whose size is zero, followed by the trailer, which is terminated by an empty line. */ #ifdef CURL_DOES_CONVERSIONS /* Check for an ASCII hex digit. We avoid the use of ISXDIGIT to accommodate non-ASCII hosts. */ static bool Curl_isxdigit_ascii(char digit) { return (digit >= 0x30 && digit <= 0x39) /* 0-9 */ || (digit >= 0x41 && digit <= 0x46) /* A-F */ || (digit >= 0x61 && digit <= 0x66); /* a-f */ } #else #define Curl_isxdigit_ascii(x) Curl_isxdigit(x) #endif void Curl_httpchunk_init(struct connectdata *conn) { struct Curl_chunker *chunk = &conn->chunk; chunk->hexindex = 0; /* start at 0 */ chunk->dataleft = 0; /* no data left yet! */ chunk->state = CHUNK_HEX; /* we get hex first! */ } /* * chunk_read() returns a OK for normal operations, or a positive return code * for errors. STOP means this sequence of chunks is complete. The 'wrote' * argument is set to tell the caller how many bytes we actually passed to the * client (for byte-counting and whatever). * * The states and the state-machine is further explained in the header file. * * This function always uses ASCII hex values to accommodate non-ASCII hosts. * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. */ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t datalen, ssize_t *wrotep, CURLcode *extrap) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct Curl_chunker *ch = &conn->chunk; struct SingleRequest *k = &data->req; size_t piece; curl_off_t length = (curl_off_t)datalen; size_t *wrote = (size_t *)wrotep; *wrote = 0; /* nothing's written yet */ /* the original data is written to the client, but we go on with the chunk read process, to properly calculate the content length*/ if(data->set.http_te_skip && !k->ignorebody) { result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen); if(result) { *extrap = result; return CHUNKE_PASSTHRU_ERROR; } } while(length) { switch(ch->state) { case CHUNK_HEX: if(Curl_isxdigit_ascii(*datap)) { if(ch->hexindex < MAXNUM_SIZE) { ch->hexbuffer[ch->hexindex] = *datap; datap++; length--; ch->hexindex++; } else { return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ } } else { char *endptr; if(0 == ch->hexindex) /* This is illegal data, we received junk where we expected a hexadecimal digit. */ return CHUNKE_ILLEGAL_HEX; /* length and datap are unmodified */ ch->hexbuffer[ch->hexindex] = 0; /* convert to host encoding before calling strtoul */ result = Curl_convert_from_network(conn->data, ch->hexbuffer, ch->hexindex); if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad hex character */ return CHUNKE_ILLEGAL_HEX; } if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) return CHUNKE_ILLEGAL_HEX; ch->state = CHUNK_LF; /* now wait for the CRLF */ } break; case CHUNK_LF: /* waiting for the LF after a chunk size */ if(*datap == 0x0a) { /* we're now expecting data to come, unless size was zero! */ if(0 == ch->datasize) { ch->state = CHUNK_TRAILER; /* now check for trailers */ conn->trlPos = 0; } else ch->state = CHUNK_DATA; } datap++; length--; break; case CHUNK_DATA: /* We expect 'datasize' of data. We have 'length' right now, it can be more or less than 'datasize'. Get the smallest piece. */ piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize); /* Write the data portion available */ if(!conn->data->set.http_te_skip && !k->ignorebody) { if(!conn->data->set.http_ce_skip && k->writer_stack) result = Curl_unencode_write(conn, k->writer_stack, datap, piece); else result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece); if(result) { *extrap = result; return CHUNKE_PASSTHRU_ERROR; } } *wrote += piece; ch->datasize -= piece; /* decrease amount left to expect */ datap += piece; /* move read pointer forward */ length -= piece; /* decrease space left in this round */ if(0 == ch->datasize) /* end of data this round, we now expect a trailing CRLF */ ch->state = CHUNK_POSTLF; break; case CHUNK_POSTLF: if(*datap == 0x0a) { /* The last one before we go back to hex state and start all over. */ Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */ } else if(*datap != 0x0d) return CHUNKE_BAD_CHUNK; datap++; length--; break; case CHUNK_TRAILER: if((*datap == 0x0d) || (*datap == 0x0a)) { /* this is the end of a trailer, but if the trailer was zero bytes there was no trailer and we move on */ if(conn->trlPos) { /* we allocate trailer with 3 bytes extra room to fit this */ conn->trailer[conn->trlPos++] = 0x0d; conn->trailer[conn->trlPos++] = 0x0a; conn->trailer[conn->trlPos] = 0; /* Convert to host encoding before calling Curl_client_write */ result = Curl_convert_from_network(conn->data, conn->trailer, conn->trlPos); if(result) /* Curl_convert_from_network calls failf if unsuccessful */ /* Treat it as a bad chunk */ return CHUNKE_BAD_CHUNK; if(!data->set.http_te_skip) { result = Curl_client_write(conn, CLIENTWRITE_HEADER, conn->trailer, conn->trlPos); if(result) { *extrap = result; return CHUNKE_PASSTHRU_ERROR; } } conn->trlPos = 0; ch->state = CHUNK_TRAILER_CR; if(*datap == 0x0a) /* already on the LF */ break; } else { /* no trailer, we're on the final CRLF pair */ ch->state = CHUNK_TRAILER_POSTCR; break; /* don't advance the pointer */ } } else { /* conn->trailer is assumed to be freed in url.c on a connection basis */ if(conn->trlPos >= conn->trlMax) { /* we always allocate three extra bytes, just because when the full header has been received we append CRLF\0 */ char *ptr; if(conn->trlMax) { conn->trlMax *= 2; ptr = realloc(conn->trailer, conn->trlMax + 3); } else { conn->trlMax = 128; ptr = malloc(conn->trlMax + 3); } if(!ptr) return CHUNKE_OUT_OF_MEMORY; conn->trailer = ptr; } conn->trailer[conn->trlPos++]=*datap; } datap++; length--; break; case CHUNK_TRAILER_CR: if(*datap == 0x0a) { ch->state = CHUNK_TRAILER_POSTCR; datap++; length--; } else return CHUNKE_BAD_CHUNK; break; case CHUNK_TRAILER_POSTCR: /* We enter this state when a CR should arrive so we expect to have to first pass a CR before we wait for LF */ if((*datap != 0x0d) && (*datap != 0x0a)) { /* not a CR then it must be another header in the trailer */ ch->state = CHUNK_TRAILER; break; } if(*datap == 0x0d) { /* skip if CR */ datap++; length--; } /* now wait for the final LF */ ch->state = CHUNK_STOP; break; case CHUNK_STOP: if(*datap == 0x0a) { length--; /* Record the length of any data left in the end of the buffer even if there's no more chunks to read */ ch->dataleft = curlx_sotouz(length); return CHUNKE_STOP; /* return stop */ } else return CHUNKE_BAD_CHUNK; } } return CHUNKE_OK; } const char *Curl_chunked_strerror(CHUNKcode code) { switch(code) { default: return "OK"; case CHUNKE_TOO_LONG_HEX: return "Too long hexadecimal number"; case CHUNKE_ILLEGAL_HEX: return "Illegal or missing hexadecimal sequence"; case CHUNKE_BAD_CHUNK: return "Malformed encoding found"; case CHUNKE_PASSTHRU_ERROR: DEBUGASSERT(0); /* never used */ return ""; case CHUNKE_BAD_ENCODING: return "Bad content-encoding found"; case CHUNKE_OUT_OF_MEMORY: return "Out of memory"; } } #endif /* CURL_DISABLE_HTTP */ davix-0.8.0/deps/curl/lib/easy.c0000644000000000000000000007641314121063461015114 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* * See comment in curl_memory.h for the explanation of this sanity check. */ #ifdef CURLX_NO_MEMORY_CALLBACKS #error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined" #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include "urldata.h" #include #include "transfer.h" #include "vtls/vtls.h" #include "url.h" #include "getinfo.h" #include "hostip.h" #include "share.h" #include "strdup.h" #include "progress.h" #include "easyif.h" #include "multiif.h" #include "select.h" #include "sendf.h" /* for failf function prototype */ #include "connect.h" /* for Curl_getconnectinfo */ #include "slist.h" #include "mime.h" #include "amigaos.h" #include "non-ascii.h" #include "warnless.h" #include "multiif.h" #include "sigpipe.h" #include "vssh/ssh.h" #include "setopt.h" #include "http_digest.h" #include "system_win32.h" #include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" void Curl_version_init(void); /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; /* * strdup (and other memory functions) is redefined in complicated * ways, but at this point it must be defined as the system-supplied strdup * so the callback pointer is initialized correctly. */ #if defined(_WIN32_WCE) #define system_strdup _strdup #elif !defined(HAVE_STRDUP) #define system_strdup curlx_strdup #else #define system_strdup strdup #endif #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) # pragma warning(disable:4232) /* MSVC extension, dllimport identity */ #endif #ifndef __SYMBIAN32__ /* * If a memory-using function (like curl_getenv) is used before * curl_global_init() is called, we need to have these pointers set already. */ curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; curl_free_callback Curl_cfree = (curl_free_callback)free; curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; #if defined(WIN32) && defined(UNICODE) curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; #endif #else /* * Symbian OS doesn't support initialization to code in writable static data. * Initialization will occur in the curl_global_init() call. */ curl_malloc_callback Curl_cmalloc; curl_free_callback Curl_cfree; curl_realloc_callback Curl_crealloc; curl_strdup_callback Curl_cstrdup; curl_calloc_callback Curl_ccalloc; #endif #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) # pragma warning(default:4232) /* MSVC extension, dllimport identity */ #endif /** * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ static CURLcode global_init(long flags, bool memoryfuncs) { if(initialized++) return CURLE_OK; if(memoryfuncs) { /* Setup the default memory functions here (again) */ Curl_cmalloc = (curl_malloc_callback)malloc; Curl_cfree = (curl_free_callback)free; Curl_crealloc = (curl_realloc_callback)realloc; Curl_cstrdup = (curl_strdup_callback)system_strdup; Curl_ccalloc = (curl_calloc_callback)calloc; #if defined(WIN32) && defined(UNICODE) Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; #endif } if(!Curl_ssl_init()) { DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); goto fail; } #ifdef WIN32 if(Curl_win32_init(flags)) { DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); goto fail; } #endif #ifdef __AMIGA__ if(!Curl_amiga_init()) { DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); goto fail; } #endif #ifdef NETWARE if(netware_init()) { DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n")); } #endif if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); goto fail; } #if defined(USE_SSH) if(Curl_ssh_init()) { goto fail; } #endif #ifdef USE_WOLFSSH if(WS_SUCCESS != wolfSSH_Init()) { DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); return CURLE_FAILED_INIT; } #endif init_flags = flags; Curl_version_init(); return CURLE_OK; fail: initialized--; /* undo the increase */ return CURLE_FAILED_INIT; } /** * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ CURLcode curl_global_init(long flags) { return global_init(flags, TRUE); } /* * curl_global_init_mem() globally initializes curl and also registers the * user provided callback routines. */ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c) { /* Invalid input, return immediately */ if(!m || !f || !r || !s || !c) return CURLE_FAILED_INIT; if(initialized) { /* Already initialized, don't do it again, but bump the variable anyway to work like curl_global_init() and require the same amount of cleanup calls. */ initialized++; return CURLE_OK; } /* set memory functions before global_init() in case it wants memory functions */ Curl_cmalloc = m; Curl_cfree = f; Curl_cstrdup = s; Curl_crealloc = r; Curl_ccalloc = c; /* Call the actual init function, but without setting */ return global_init(flags, FALSE); } /** * curl_global_cleanup() globally cleanups curl, uses the value of * "init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) { if(!initialized) return; if(--initialized) return; Curl_ssl_cleanup(); Curl_resolver_global_cleanup(); #ifdef WIN32 Curl_win32_cleanup(init_flags); #endif Curl_amiga_cleanup(); Curl_ssh_cleanup(); #ifdef USE_WOLFSSH (void)wolfSSH_Cleanup(); #endif init_flags = 0; } /* * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. */ struct Curl_easy *curl_easy_init(void) { CURLcode result; struct Curl_easy *data; /* Make sure we inited the global SSL stuff */ if(!initialized) { result = curl_global_init(CURL_GLOBAL_DEFAULT); if(result) { /* something in the global init failed, return nothing */ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); return NULL; } } /* We use curl_open() with undefined URL so far */ result = Curl_open(&data); if(result) { DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); return NULL; } return data; } #ifdef CURLDEBUG struct socketmonitor { struct socketmonitor *next; /* the next node in the list or NULL */ struct pollfd socket; /* socket info of what to monitor */ }; struct events { long ms; /* timeout, run the timeout function when reached */ bool msbump; /* set TRUE when timeout is set by callback */ int num_sockets; /* number of nodes in the monitor list */ struct socketmonitor *list; /* list of sockets to monitor */ int running_handles; /* store the returned number */ }; /* events_timer * * Callback that gets called with a new value when the timeout should be * updated. */ static int events_timer(struct Curl_multi *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp) /* private callback pointer */ { struct events *ev = userp; (void)multi; if(timeout_ms == -1) /* timeout removed */ timeout_ms = 0; else if(timeout_ms == 0) /* timeout is already reached! */ timeout_ms = 1; /* trigger asap */ ev->ms = timeout_ms; ev->msbump = TRUE; return 0; } /* poll2cselect * * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones */ static int poll2cselect(int pollmask) { int omask = 0; if(pollmask & POLLIN) omask |= CURL_CSELECT_IN; if(pollmask & POLLOUT) omask |= CURL_CSELECT_OUT; if(pollmask & POLLERR) omask |= CURL_CSELECT_ERR; return omask; } /* socketcb2poll * * convert from libcurl' CURL_POLL_* bit definitions to poll()'s */ static short socketcb2poll(int pollmask) { short omask = 0; if(pollmask & CURL_POLL_IN) omask |= POLLIN; if(pollmask & CURL_POLL_OUT) omask |= POLLOUT; return omask; } /* events_socket * * Callback that gets called with information about socket activity to * monitor. */ static int events_socket(struct Curl_easy *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ void *userp, /* private callback pointer */ void *socketp) /* private socket pointer */ { struct events *ev = userp; struct socketmonitor *m; struct socketmonitor *prev = NULL; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) easy; #endif (void)socketp; m = ev->list; while(m) { if(m->socket.fd == s) { if(what == CURL_POLL_REMOVE) { struct socketmonitor *nxt = m->next; /* remove this node from the list of monitored sockets */ if(prev) prev->next = nxt; else ev->list = nxt; free(m); m = nxt; infof(easy, "socket cb: socket %d REMOVED\n", s); } else { /* The socket 's' is already being monitored, update the activity mask. Convert from libcurl bitmask to the poll one. */ m->socket.events = socketcb2poll(what); infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } break; } prev = m; m = m->next; /* move to next node */ } if(!m) { if(what == CURL_POLL_REMOVE) { /* this happens a bit too often, libcurl fix perhaps? */ /* fprintf(stderr, "%s: socket %d asked to be REMOVED but not present!\n", __func__, s); */ } else { m = malloc(sizeof(struct socketmonitor)); if(m) { m->next = ev->list; m->socket.fd = s; m->socket.events = socketcb2poll(what); m->socket.revents = 0; ev->list = m; infof(easy, "socket cb: socket %d ADDED as %s%s\n", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } else return CURLE_OUT_OF_MEMORY; } } return 0; } /* * events_setup() * * Do the multi handle setups that only event-based transfers need. */ static void events_setup(struct Curl_multi *multi, struct events *ev) { /* timer callback */ curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev); /* socket callback */ curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket); curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev); } /* wait_or_timeout() * * waits for activity on any of the given sockets, or the timeout to trigger. */ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) { bool done = FALSE; CURLMcode mcode = CURLM_OK; CURLcode result = CURLE_OK; while(!done) { CURLMsg *msg; struct socketmonitor *m; struct pollfd *f; struct pollfd fds[4]; int numfds = 0; int pollrc; int i; struct curltime before; struct curltime after; /* populate the fds[] array */ for(m = ev->list, f = &fds[0]; m; m = m->next) { f->fd = m->socket.fd; f->events = m->socket.events; f->revents = 0; /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ f++; numfds++; } /* get the time stamp to use to figure out how long poll takes */ before = Curl_now(); /* wait for activity or timeout */ pollrc = Curl_poll(fds, numfds, (int)ev->ms); after = Curl_now(); ev->msbump = FALSE; /* reset here */ if(0 == pollrc) { /* timeout! */ ev->ms = 0; /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &ev->running_handles); } else if(pollrc > 0) { /* loop over the monitored sockets to see which ones had activity */ for(i = 0; i< numfds; i++) { if(fds[i].revents) { /* socket activity, tell libcurl */ int act = poll2cselect(fds[i].revents); /* convert */ infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n", fds[i].fd); mcode = curl_multi_socket_action(multi, fds[i].fd, act, &ev->running_handles); } } if(!ev->msbump) { /* If nothing updated the timeout, we decrease it by the spent time. * If it was updated, it has the new timeout time stored already. */ timediff_t timediff = Curl_timediff(after, before); if(timediff > 0) { if(timediff > ev->ms) ev->ms = 0; else ev->ms -= (long)timediff; } } } else return CURLE_RECV_ERROR; if(mcode) return CURLE_URL_MALFORMAT; /* we don't really care about the "msgs_in_queue" value returned in the second argument */ msg = curl_multi_info_read(multi, &pollrc); if(msg) { result = msg->data.result; done = TRUE; } } return result; } /* easy_events() * * Runs a transfer in a blocking manner using the events-based API */ static CURLcode easy_events(struct Curl_multi *multi) { /* this struct is made static to allow it to be used after this function returns and curl_multi_remove_handle() is called */ static struct events evs = {2, FALSE, 0, NULL, 0}; /* if running event-based, do some further multi inits */ events_setup(multi, &evs); return wait_or_timeout(multi, &evs); } #else /* CURLDEBUG */ /* when not built with debug, this function doesn't exist */ #define easy_events(x) CURLE_NOT_BUILT_IN #endif static CURLcode easy_transfer(struct Curl_multi *multi) { bool done = FALSE; CURLMcode mcode = CURLM_OK; CURLcode result = CURLE_OK; while(!done && !mcode) { int still_running = 0; mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL); if(!mcode) mcode = curl_multi_perform(multi, &still_running); /* only read 'still_running' if curl_multi_perform() return OK */ if(!mcode && !still_running) { int rc; CURLMsg *msg = curl_multi_info_read(multi, &rc); if(msg) { result = msg->data.result; done = TRUE; } } } /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : /* The other multi errors should never happen, so return something suitably generic */ CURLE_BAD_FUNCTION_ARGUMENT; } return result; } /* * easy_perform() is the external interface that performs a blocking * transfer as previously setup. * * CONCEPT: This function creates a multi handle, adds the easy handle to it, * runs curl_multi_perform() until the transfer is done, then detaches the * easy handle, destroys the multi handle and returns the easy handle's return * code. * * REALITY: it can't just create and destroy the multi handle that easily. It * needs to keep it around since if this easy handle is used again by this * function, the same multi handle must be re-used so that the same pools and * caches can be used. * * DEBUG: if 'events' is set TRUE, this function will use a replacement engine * instead of curl_multi_perform() and use curl_multi_socket_action(). */ static CURLcode easy_perform(struct Curl_easy *data, bool events) { struct Curl_multi *multi; CURLMcode mcode; CURLcode result = CURLE_OK; SIGPIPE_VARIABLE(pipe_st); if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; if(data->set.errorbuffer) /* clear this as early as possible */ data->set.errorbuffer[0] = 0; if(data->multi) { failf(data, "easy handle already used in multi handle"); return CURLE_FAILED_INIT; } if(data->multi_easy) multi = data->multi_easy; else { /* this multi handle will only ever have a single easy handled attached to it, so make it use minimal hashes */ multi = Curl_multi_handle(1, 3); if(!multi) return CURLE_OUT_OF_MEMORY; data->multi_easy = multi; } if(multi->in_callback) return CURLE_RECURSIVE_API_CALL; /* Copy the MAXCONNECTS option to the multi handle */ curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects); mcode = curl_multi_add_handle(multi, data); if(mcode) { curl_multi_cleanup(multi); if(mcode == CURLM_OUT_OF_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_FAILED_INIT; } sigpipe_ignore(data, &pipe_st); /* run the transfer */ result = events ? easy_events(multi) : easy_transfer(multi); /* ignoring the return code isn't nice, but atm we can't really handle a failure here, room for future improvement! */ (void)curl_multi_remove_handle(multi, data); sigpipe_restore(&pipe_st); /* The multi handle is kept alive, owned by the easy handle */ return result; } /* * curl_easy_perform() is the external interface that performs a blocking * transfer as previously setup. */ CURLcode curl_easy_perform(struct Curl_easy *data) { return easy_perform(data, FALSE); } #ifdef CURLDEBUG /* * curl_easy_perform_ev() is the external interface that performs a blocking * transfer using the event-based API internally. */ CURLcode curl_easy_perform_ev(struct Curl_easy *data) { return easy_perform(data, TRUE); } #endif /* * curl_easy_cleanup() is the external interface to cleaning/freeing the given * easy handle. */ void curl_easy_cleanup(struct Curl_easy *data) { SIGPIPE_VARIABLE(pipe_st); if(!data) return; sigpipe_ignore(data, &pipe_st); Curl_close(&data); sigpipe_restore(&pipe_st); } /* * curl_easy_getinfo() is an external interface that allows an app to retrieve * information from a performed transfer and similar. */ #undef curl_easy_getinfo CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; void *paramp; CURLcode result; va_start(arg, info); paramp = va_arg(arg, void *); result = Curl_getinfo(data, info, paramp); va_end(arg); return result; } static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) { CURLcode result = CURLE_OK; enum dupstring i; /* Copy src->set into dst->set first, then deal with the strings afterwards */ dst->set = src->set; Curl_mime_initpart(&dst->set.mimepost, dst); /* clear all string pointers first */ memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); /* duplicate all strings */ for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { result = Curl_setstropt(&dst->set.str[i], src->set.str[i]); if(result) return result; } /* duplicate memory areas pointed to */ i = STRING_COPYPOSTFIELDS; if(src->set.postfieldsize && src->set.str[i]) { /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ dst->set.str[i] = Curl_memdup(src->set.str[i], curlx_sotouz(src->set.postfieldsize)); if(!dst->set.str[i]) return CURLE_OUT_OF_MEMORY; /* point to the new copy */ dst->set.postfields = dst->set.str[i]; } /* Duplicate mime data. */ result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost); if(src->set.resolve) dst->change.resolve = dst->set.resolve; return result; } /* * curl_easy_duphandle() is an external interface to allow duplication of a * given input easy handle. The returned handle will be a new working handle * with all options set exactly as the input source handle. */ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) { struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); if(NULL == outcurl) goto fail; /* * We setup a few buffers we need. We should probably make them * get setup on-demand in the code, as that would probably decrease * the likeliness of us forgetting to init a buffer here in the future. */ outcurl->set.buffer_size = data->set.buffer_size; outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1); if(!outcurl->state.buffer) goto fail; outcurl->state.headerbuff = malloc(HEADERSIZE); if(!outcurl->state.headerbuff) goto fail; outcurl->state.headersize = HEADERSIZE; /* copy all userdefined values */ if(dupset(outcurl, data)) goto fail; /* the connection cache is setup on demand */ outcurl->state.conn_cache = NULL; outcurl->state.lastconnect = NULL; outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; if(data->cookies) { /* If cookies are enabled in the parent handle, we enable them in the clone as well! */ outcurl->cookies = Curl_cookie_init(data, data->cookies->filename, outcurl->cookies, data->set.cookiesession); if(!outcurl->cookies) goto fail; } /* duplicate all values in 'change' */ if(data->change.cookielist) { outcurl->change.cookielist = Curl_slist_duplicate(data->change.cookielist); if(!outcurl->change.cookielist) goto fail; } if(data->change.url) { outcurl->change.url = strdup(data->change.url); if(!outcurl->change.url) goto fail; outcurl->change.url_alloc = TRUE; } if(data->change.referer) { outcurl->change.referer = strdup(data->change.referer); if(!outcurl->change.referer) goto fail; outcurl->change.referer_alloc = TRUE; } /* Reinitialize an SSL engine for the new handle * note: the engine name has already been copied by dupset */ if(outcurl->set.str[STRING_SSL_ENGINE]) { if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE])) goto fail; } /* Clone the resolver handle, if present, for the new handle */ if(Curl_resolver_duphandle(outcurl, &outcurl->state.resolver, data->state.resolver)) goto fail; Curl_convert_setup(outcurl); Curl_initinfo(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; /* we reach this point and thus we are OK */ return outcurl; fail: if(outcurl) { curl_slist_free_all(outcurl->change.cookielist); outcurl->change.cookielist = NULL; Curl_safefree(outcurl->state.buffer); Curl_safefree(outcurl->state.headerbuff); Curl_safefree(outcurl->change.url); Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); free(outcurl); } return NULL; } /* * curl_easy_reset() is an external interface that allows an app to re- * initialize a session handle to the default values. */ void curl_easy_reset(struct Curl_easy *data) { long old_buffer_size = data->set.buffer_size; Curl_free_request_state(data); /* zero out UserDefined data: */ Curl_freeset(data); memset(&data->set, 0, sizeof(struct UserDefined)); (void)Curl_init_userdefined(data); /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); /* zero out PureInfo data: */ Curl_initinfo(data); data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ /* zero out authentication data: */ memset(&data->state.authhost, 0, sizeof(struct auth)); memset(&data->state.authproxy, 0, sizeof(struct auth)); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif /* resize receive buffer */ if(old_buffer_size != data->set.buffer_size) { char *newbuff = realloc(data->state.buffer, data->set.buffer_size + 1); if(!newbuff) { DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); /* nothing we can do here except use the old size */ data->set.buffer_size = old_buffer_size; } else data->state.buffer = newbuff; } } /* * curl_easy_pause() allows an application to pause or unpause a specific * transfer and direction. This function sets the full new state for the * current connection this easy handle operates on. * * NOTE: if you have the receiving paused and you call this function to remove * the pausing, you may get your write callback called at this point. * * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h * * NOTE: This is one of few API functions that are allowed to be called from * within a callback. */ CURLcode curl_easy_pause(struct Curl_easy *data, int action) { struct SingleRequest *k = &data->req; CURLcode result = CURLE_OK; /* first switch off both pause bits */ int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); /* set the new desired pause bits */ newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); /* put it back in the keepon */ k->keepon = newstate; if(!(newstate & KEEP_RECV_PAUSE)) { Curl_http2_stream_pause(data, FALSE); if(data->state.tempcount) { /* there are buffers for sending that can be delivered as the receive pausing is lifted! */ unsigned int i; unsigned int count = data->state.tempcount; struct tempbuf writebuf[3]; /* there can only be three */ struct connectdata *conn = data->conn; struct Curl_easy *saved_data = NULL; /* copy the structs to allow for immediate re-pausing */ for(i = 0; i < data->state.tempcount; i++) { writebuf[i] = data->state.tempwrite[i]; data->state.tempwrite[i].buf = NULL; } data->state.tempcount = 0; /* set the connection's current owner */ if(conn->data != data) { saved_data = conn->data; conn->data = data; } for(i = 0; i < count; i++) { /* even if one function returns error, this loops through and frees all buffers */ if(!result) result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf, writebuf[i].len); free(writebuf[i].buf); } /* recover previous owner of the connection */ if(saved_data) conn->data = saved_data; if(result) return result; } } /* if there's no error and we're not pausing both directions, we want to have this handle checked soon */ if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { data->state.drain++; Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ if(data->multi) Curl_update_timer(data->multi); } if(!data->state.done) /* This transfer may have been moved in or out of the bundle, update the corresponding socket callback, if used */ Curl_updatesocket(data); return result; } static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { if(data == NULL) return CURLE_BAD_FUNCTION_ARGUMENT; /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */ if(!data->set.connect_only) { failf(data, "CONNECT_ONLY is required!"); return CURLE_UNSUPPORTED_PROTOCOL; } *sfd = Curl_getconnectinfo(data, connp); if(*sfd == CURL_SOCKET_BAD) { failf(data, "Failed to get recent socket"); return CURLE_UNSUPPORTED_PROTOCOL; } return CURLE_OK; } /* * Receives data from the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. * Returns CURLE_OK on success, error code on error. */ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c; if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; result = easy_connection(data, &sfd, &c); if(result) return result; *n = 0; result = Curl_read(c, sfd, buffer, buflen, &n1); if(result) return result; *n = (size_t)n1; return CURLE_OK; } /* * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, size_t buflen, size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c = NULL; if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; result = easy_connection(data, &sfd, &c); if(result) return result; *n = 0; result = Curl_write(c, sfd, buffer, buflen, &n1); if(n1 == -1) return CURLE_SEND_ERROR; /* detect EAGAIN */ if(!result && !n1) return CURLE_AGAIN; *n = (size_t)n1; return result; } /* * Wrapper to call functions in Curl_conncache_foreach() * * Returns always 0. */ static int conn_upkeep(struct connectdata *conn, void *param) { /* Param is unused. */ (void)param; if(conn->handler->connection_check) { /* Do a protocol-specific keepalive check on the connection. */ conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE); } return 0; /* continue iteration */ } static CURLcode upkeep(struct conncache *conn_cache, void *data) { /* Loop over every connection and make connection alive. */ Curl_conncache_foreach(data, conn_cache, data, conn_upkeep); return CURLE_OK; } /* * Performs connection upkeep for the given session handle. */ CURLcode curl_easy_upkeep(struct Curl_easy *data) { /* Verify that we got an easy handle we can work with. */ if(!GOOD_EASY_HANDLE(data)) return CURLE_BAD_FUNCTION_ARGUMENT; if(data->multi_easy) { /* Use the common function to keep connections alive. */ return upkeep(&data->multi_easy->conn_cache, data); } else { /* No connections, so just return success */ return CURLE_OK; } } davix-0.8.0/deps/curl/lib/doh.c0000644000000000000000000007133214121063461014720 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_DOH #include "urldata.h" #include "curl_addrinfo.h" #include "doh.h" #include "sendf.h" #include "multiif.h" #include "url.h" #include "share.h" #include "curl_base64.h" #include "connect.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define DNS_CLASS_IN 0x01 #define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static const char * const errors[]={ "", "Bad label", "Out of range", "Label loop", "Too small", "Out of memory", "RDATA length", "Malformat", "Bad RCODE", "Unexpected TYPE", "Unexpected CLASS", "No content", "Bad ID" }; static const char *doh_strerror(DOHcode code) { if((code >= DOH_OK) && (code <= DOH_DNS_BAD_ID)) return errors[code]; return "bad error code"; } #endif #ifdef DEBUGBUILD #define UNITTEST #else #define UNITTEST static #endif /* @unittest 1655 */ UNITTEST DOHcode doh_encode(const char *host, DNStype dnstype, unsigned char *dnsp, /* buffer */ size_t len, /* buffer size */ size_t *olen) /* output length */ { const size_t hostlen = strlen(host); unsigned char *orig = dnsp; const char *hostp = host; /* The expected output length is 16 bytes more than the length of * the QNAME-encoding of the host name. * * A valid DNS name may not contain a zero-length label, except at * the end. For this reason, a name beginning with a dot, or * containing a sequence of two or more consecutive dots, is invalid * and cannot be encoded as a QNAME. * * If the host name ends with a trailing dot, the corresponding * QNAME-encoding is one byte longer than the host name. If (as is * also valid) the hostname is shortened by the omission of the * trailing dot, then its QNAME-encoding will be two bytes longer * than the host name. * * Each [ label, dot ] pair is encoded as [ length, label ], * preserving overall length. A final [ label ] without a dot is * also encoded as [ length, label ], increasing overall length * by one. The encoding is completed by appending a zero byte, * representing the zero-length root label, again increasing * the overall length by one. */ size_t expected_len; DEBUGASSERT(hostlen); expected_len = 12 + 1 + hostlen + 4; if(host[hostlen-1]!='.') expected_len++; if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */ return DOH_DNS_NAME_TOO_LONG; if(len < expected_len) return DOH_TOO_SMALL_BUFFER; *dnsp++ = 0; /* 16 bit id */ *dnsp++ = 0; *dnsp++ = 0x01; /* |QR| Opcode |AA|TC|RD| Set the RD bit */ *dnsp++ = '\0'; /* |RA| Z | RCODE | */ *dnsp++ = '\0'; *dnsp++ = 1; /* QDCOUNT (number of entries in the question section) */ *dnsp++ = '\0'; *dnsp++ = '\0'; /* ANCOUNT */ *dnsp++ = '\0'; *dnsp++ = '\0'; /* NSCOUNT */ *dnsp++ = '\0'; *dnsp++ = '\0'; /* ARCOUNT */ /* encode each label and store it in the QNAME */ while(*hostp) { size_t labellen; char *dot = strchr(hostp, '.'); if(dot) labellen = dot - hostp; else labellen = strlen(hostp); if((labellen > 63) || (!labellen)) { /* label is too long or too short, error out */ *olen = 0; return DOH_DNS_BAD_LABEL; } /* label is non-empty, process it */ *dnsp++ = (unsigned char)labellen; memcpy(dnsp, hostp, labellen); dnsp += labellen; hostp += labellen; /* advance past dot, but only if there is one */ if(dot) hostp++; } /* next label */ *dnsp++ = 0; /* append zero-length label for root */ /* There are assigned TYPE codes beyond 255: use range [1..65535] */ *dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */ *dnsp++ = (unsigned char)(255 & dnstype); /* lower 8 bit TYPE */ *dnsp++ = '\0'; /* upper 8 bit CLASS */ *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */ *olen = dnsp - orig; /* verify that our estimation of length is valid, since * this has led to buffer overflows in this function */ DEBUGASSERT(*olen == expected_len); return DOH_OK; } static size_t doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct dohresponse *mem = (struct dohresponse *)userp; if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE) /* suspiciously much for us */ return 0; mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize); if(!mem->memory) /* out of memory! */ return 0; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; return realsize; } /* called from multi.c when this DOH transfer is complete */ static int Curl_doh_done(struct Curl_easy *doh, CURLcode result) { struct Curl_easy *data = doh->set.dohfor; /* so one of the DOH request done for the 'data' transfer is now complete! */ data->req.doh.pending--; infof(data, "a DOH request is completed, %u to go\n", data->req.doh.pending); if(result) infof(data, "DOH request %s\n", curl_easy_strerror(result)); if(!data->req.doh.pending) { /* DOH completed */ curl_slist_free_all(data->req.doh.headers); data->req.doh.headers = NULL; Curl_expire(data, 0, EXPIRE_RUN_NOW); } return 0; } #define ERROR_CHECK_SETOPT(x,y) \ do { \ result = curl_easy_setopt(doh, x, y); \ if(result) \ goto error; \ } while(0) static CURLcode dohprobe(struct Curl_easy *data, struct dnsprobe *p, DNStype dnstype, const char *host, const char *url, CURLM *multi, struct curl_slist *headers) { struct Curl_easy *doh = NULL; char *nurl = NULL; CURLcode result = CURLE_OK; timediff_t timeout_ms; DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer), &p->dohlen); if(d) { failf(data, "Failed to encode DOH packet [%d]\n", d); return CURLE_OUT_OF_MEMORY; } p->dnstype = dnstype; p->serverdoh.memory = NULL; /* the memory will be grown as needed by realloc in the doh_write_cb function */ p->serverdoh.size = 0; /* Note: this is code for sending the DoH request with GET but there's still no logic that actually enables this. We should either add that ability or yank out the GET code. Discuss! */ if(data->set.doh_get) { char *b64; size_t b64len; result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen, &b64, &b64len); if(result) goto error; nurl = aprintf("%s?dns=%s", url, b64); free(b64); if(!nurl) { result = CURLE_OUT_OF_MEMORY; goto error; } url = nurl; } timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms <= 0) { result = CURLE_OPERATION_TIMEDOUT; goto error; } /* Curl_open() is the internal version of curl_easy_init() */ result = Curl_open(&doh); if(!result) { /* pass in the struct pointer via a local variable to please coverity and the gcc typecheck helpers */ struct dohresponse *resp = &p->serverdoh; ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); if(!data->set.doh_get) { ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer); ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen); } ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers); #ifdef USE_NGHTTP2 ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); #endif #ifndef CURLDEBUG /* enforce HTTPS if not debug */ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); #else /* in debug mode, also allow http */ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); #endif ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms); if(data->set.verbose) ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L); if(data->set.no_signal) ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L); /* Inherit *some* SSL options from the user's transfer. This is a best-guess as to which options are needed for compatibility. #3661 */ if(data->set.ssl.falsestart) ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L); if(data->set.ssl.primary.verifyhost) ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, 2L); #ifndef CURL_DISABLE_PROXY if(data->set.proxy_ssl.primary.verifyhost) ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYHOST, 2L); if(data->set.proxy_ssl.primary.verifypeer) ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYPEER, 1L); if(data->set.str[STRING_SSL_CAFILE_PROXY]) { ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO, data->set.str[STRING_SSL_CAFILE_PROXY]); } if(data->set.str[STRING_SSL_CRLFILE_PROXY]) { ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE, data->set.str[STRING_SSL_CRLFILE_PROXY]); } if(data->set.proxy_ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); if(data->set.str[STRING_SSL_CAPATH_PROXY]) { ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH, data->set.str[STRING_SSL_CAPATH_PROXY]); } #endif if(data->set.ssl.primary.verifypeer) ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L); if(data->set.ssl.primary.verifystatus) ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, 1L); if(data->set.str[STRING_SSL_CAFILE_ORIG]) { ERROR_CHECK_SETOPT(CURLOPT_CAINFO, data->set.str[STRING_SSL_CAFILE_ORIG]); } if(data->set.str[STRING_SSL_CAPATH_ORIG]) { ERROR_CHECK_SETOPT(CURLOPT_CAPATH, data->set.str[STRING_SSL_CAPATH_ORIG]); } if(data->set.str[STRING_SSL_CRLFILE_ORIG]) { ERROR_CHECK_SETOPT(CURLOPT_CRLFILE, data->set.str[STRING_SSL_CRLFILE_ORIG]); } if(data->set.ssl.certinfo) ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L); if(data->set.str[STRING_SSL_RANDOM_FILE]) { ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE, data->set.str[STRING_SSL_RANDOM_FILE]); } if(data->set.str[STRING_SSL_EGDSOCKET]) { ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET, data->set.str[STRING_SSL_EGDSOCKET]); } if(data->set.ssl.no_revoke) ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); if(data->set.ssl.fsslctx) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp); doh->set.fmultidone = Curl_doh_done; doh->set.dohfor = data; /* identify for which transfer this is done */ p->easy = doh; /* add this transfer to the multi handle */ if(curl_multi_add_handle(multi, doh)) goto error; } else goto error; free(nurl); return CURLE_OK; error: free(nurl); Curl_close(&doh); return result; } /* * Curl_doh() resolves a name using DOH. It resolves a name and returns a * 'Curl_addrinfo *' with the address information. */ Curl_addrinfo *Curl_doh(struct connectdata *conn, const char *hostname, int port, int *waitp) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; int slot; *waitp = TRUE; /* this never returns synchronously */ (void)conn; (void)hostname; (void)port; /* start clean, consider allocating this struct on demand */ memset(&data->req.doh, 0, sizeof(struct dohdata)); data->req.doh.host = hostname; data->req.doh.port = port; data->req.doh.headers = curl_slist_append(NULL, "Content-Type: application/dns-message"); if(!data->req.doh.headers) goto error; if(conn->ip_version != CURL_IPRESOLVE_V6) { /* create IPv4 DOH request */ result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4], DNS_TYPE_A, hostname, data->set.str[STRING_DOH], data->multi, data->req.doh.headers); if(result) goto error; data->req.doh.pending++; } if(conn->ip_version != CURL_IPRESOLVE_V4) { /* create IPv6 DOH request */ result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6], DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH], data->multi, data->req.doh.headers); if(result) goto error; data->req.doh.pending++; } return NULL; error: curl_slist_free_all(data->req.doh.headers); data->req.doh.headers = NULL; for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { Curl_close(&data->req.doh.probe[slot].easy); } return NULL; } static DOHcode skipqname(unsigned char *doh, size_t dohlen, unsigned int *indexp) { unsigned char length; do { if(dohlen < (*indexp + 1)) return DOH_DNS_OUT_OF_RANGE; length = doh[*indexp]; if((length & 0xc0) == 0xc0) { /* name pointer, advance over it and be done */ if(dohlen < (*indexp + 2)) return DOH_DNS_OUT_OF_RANGE; *indexp += 2; break; } if(length & 0xc0) return DOH_DNS_BAD_LABEL; if(dohlen < (*indexp + 1 + length)) return DOH_DNS_OUT_OF_RANGE; *indexp += 1 + length; } while(length); return DOH_OK; } static unsigned short get16bit(unsigned char *doh, int index) { return (unsigned short)((doh[index] << 8) | doh[index + 1]); } static unsigned int get32bit(unsigned char *doh, int index) { /* make clang and gcc optimize this to bswap by incrementing the pointer first. */ doh += index; /* avoid undefined behaviour by casting to unsigned before shifting 24 bits, possibly into the sign bit. codegen is same, but ub sanitizer won't be upset */ return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3]; } static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { struct dohaddr *a = &d->addr[d->numaddr]; a->type = DNS_TYPE_A; memcpy(&a->ip.v4, &doh[index], 4); d->numaddr++; } return DOH_OK; } static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { struct dohaddr *a = &d->addr[d->numaddr]; a->type = DNS_TYPE_AAAA; memcpy(&a->ip.v6, &doh[index], 16); d->numaddr++; } return DOH_OK; } static DOHcode cnameappend(struct cnamestore *c, unsigned char *src, size_t len) { if(!c->alloc) { c->allocsize = len + 1; c->alloc = malloc(c->allocsize); if(!c->alloc) return DOH_OUT_OF_MEM; } else if(c->allocsize < (c->allocsize + len + 1)) { char *ptr; c->allocsize += len + 1; ptr = realloc(c->alloc, c->allocsize); if(!ptr) { free(c->alloc); return DOH_OUT_OF_MEM; } c->alloc = ptr; } memcpy(&c->alloc[c->len], src, len); c->len += len; c->alloc[c->len] = 0; /* keep it zero terminated */ return DOH_OK; } static DOHcode store_cname(unsigned char *doh, size_t dohlen, unsigned int index, struct dohentry *d) { struct cnamestore *c; unsigned int loop = 128; /* a valid DNS name can never loop this much */ unsigned char length; if(d->numcname == DOH_MAX_CNAME) return DOH_OK; /* skip! */ c = &d->cname[d->numcname++]; do { if(index >= dohlen) return DOH_DNS_OUT_OF_RANGE; length = doh[index]; if((length & 0xc0) == 0xc0) { int newpos; /* name pointer, get the new offset (14 bits) */ if((index + 1) >= dohlen) return DOH_DNS_OUT_OF_RANGE; /* move to the new index */ newpos = (length & 0x3f) << 8 | doh[index + 1]; index = newpos; continue; } else if(length & 0xc0) return DOH_DNS_BAD_LABEL; /* bad input */ else index++; if(length) { DOHcode rc; if(c->len) { rc = cnameappend(c, (unsigned char *)".", 1); if(rc) return rc; } if((index + length) > dohlen) return DOH_DNS_BAD_LABEL; rc = cnameappend(c, &doh[index], length); if(rc) return rc; index += length; } } while(length && --loop); if(!loop) return DOH_DNS_LABEL_LOOP; return DOH_OK; } static DOHcode rdata(unsigned char *doh, size_t dohlen, unsigned short rdlength, unsigned short type, int index, struct dohentry *d) { /* RDATA - A (TYPE 1): 4 bytes - AAAA (TYPE 28): 16 bytes - NS (TYPE 2): N bytes */ DOHcode rc; switch(type) { case DNS_TYPE_A: if(rdlength != 4) return DOH_DNS_RDATA_LEN; rc = store_a(doh, index, d); if(rc) return rc; break; case DNS_TYPE_AAAA: if(rdlength != 16) return DOH_DNS_RDATA_LEN; rc = store_aaaa(doh, index, d); if(rc) return rc; break; case DNS_TYPE_CNAME: rc = store_cname(doh, dohlen, index, d); if(rc) return rc; break; case DNS_TYPE_DNAME: /* explicit for clarity; just skip; rely on synthesized CNAME */ break; default: /* unsupported type, just skip it */ break; } return DOH_OK; } static void init_dohentry(struct dohentry *de) { memset(de, 0, sizeof(*de)); de->ttl = INT_MAX; } UNITTEST DOHcode doh_decode(unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d) { unsigned char rcode; unsigned short qdcount; unsigned short ancount; unsigned short type = 0; unsigned short rdlength; unsigned short nscount; unsigned short arcount; unsigned int index = 12; DOHcode rc; if(dohlen < 12) return DOH_TOO_SMALL_BUFFER; /* too small */ if(!doh || doh[0] || doh[1]) return DOH_DNS_BAD_ID; /* bad ID */ rcode = doh[3] & 0x0f; if(rcode) return DOH_DNS_BAD_RCODE; /* bad rcode */ qdcount = get16bit(doh, 4); while(qdcount) { rc = skipqname(doh, dohlen, &index); if(rc) return rc; /* bad qname */ if(dohlen < (index + 4)) return DOH_DNS_OUT_OF_RANGE; index += 4; /* skip question's type and class */ qdcount--; } ancount = get16bit(doh, 6); while(ancount) { unsigned short class; unsigned int ttl; rc = skipqname(doh, dohlen, &index); if(rc) return rc; /* bad qname */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; type = get16bit(doh, index); if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */ && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */ && (type != dnstype)) /* Not the same type as was asked for nor CNAME nor DNAME */ return DOH_DNS_UNEXPECTED_TYPE; index += 2; if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; class = get16bit(doh, index); if(DNS_CLASS_IN != class) return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */ index += 2; if(dohlen < (index + 4)) return DOH_DNS_OUT_OF_RANGE; ttl = get32bit(doh, index); if(ttl < d->ttl) d->ttl = ttl; index += 4; if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; rdlength = get16bit(doh, index); index += 2; if(dohlen < (index + rdlength)) return DOH_DNS_OUT_OF_RANGE; rc = rdata(doh, dohlen, rdlength, type, index, d); if(rc) return rc; /* bad rdata */ index += rdlength; ancount--; } nscount = get16bit(doh, 8); while(nscount) { rc = skipqname(doh, dohlen, &index); if(rc) return rc; /* bad qname */ if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; index += 2 + 2 + 4; /* type, class and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; rdlength = get16bit(doh, index); index += 2; if(dohlen < (index + rdlength)) return DOH_DNS_OUT_OF_RANGE; index += rdlength; nscount--; } arcount = get16bit(doh, 10); while(arcount) { rc = skipqname(doh, dohlen, &index); if(rc) return rc; /* bad qname */ if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; index += 2 + 2 + 4; /* type, class and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; rdlength = get16bit(doh, index); index += 2; if(dohlen < (index + rdlength)) return DOH_DNS_OUT_OF_RANGE; index += rdlength; arcount--; } if(index != dohlen) return DOH_DNS_MALFORMAT; /* something is wrong */ if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr) /* nothing stored! */ return DOH_NO_CONTENT; return DOH_OK; /* ok */ } #ifndef CURL_DISABLE_VERBOSE_STRINGS static void showdoh(struct Curl_easy *data, struct dohentry *d) { int i; infof(data, "TTL: %u seconds\n", d->ttl); for(i = 0; i < d->numaddr; i++) { struct dohaddr *a = &d->addr[i]; if(a->type == DNS_TYPE_A) { infof(data, "DOH A: %u.%u.%u.%u\n", a->ip.v4[0], a->ip.v4[1], a->ip.v4[2], a->ip.v4[3]); } else if(a->type == DNS_TYPE_AAAA) { int j; char buffer[128]; char *ptr; size_t len; msnprintf(buffer, 128, "DOH AAAA: "); ptr = &buffer[10]; len = 118; for(j = 0; j < 16; j += 2) { size_t l; msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j], d->addr[i].ip.v6[j + 1]); l = strlen(ptr); len -= l; ptr += l; } infof(data, "%s\n", buffer); } } for(i = 0; i < d->numcname; i++) { infof(data, "CNAME: %s\n", d->cname[i].alloc); } } #else #define showdoh(x,y) #endif /* * doh2ai() * * This function returns a pointer to the first element of a newly allocated * Curl_addrinfo struct linked list filled with the data from a set of DOH * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for * a IPv6 stack, but usable also for IPv4, all hosts and environments. * * The memory allocated by this function *MUST* be free'd later on calling * Curl_freeaddrinfo(). For each successful call to this function there * must be an associated call later to Curl_freeaddrinfo(). */ static Curl_addrinfo * doh2ai(const struct dohentry *de, const char *hostname, int port) { Curl_addrinfo *ai; Curl_addrinfo *prevai = NULL; Curl_addrinfo *firstai = NULL; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; #endif CURLcode result = CURLE_OK; int i; if(!de) /* no input == no output! */ return NULL; for(i = 0; i < de->numaddr; i++) { size_t ss_size; CURL_SA_FAMILY_T addrtype; if(de->addr[i].type == DNS_TYPE_AAAA) { #ifndef ENABLE_IPV6 /* we can't handle IPv6 addresses */ continue; #else ss_size = sizeof(struct sockaddr_in6); addrtype = AF_INET6; #endif } else { ss_size = sizeof(struct sockaddr_in); addrtype = AF_INET; } ai = calloc(1, sizeof(Curl_addrinfo)); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } ai->ai_canonname = strdup(hostname); if(!ai->ai_canonname) { result = CURLE_OUT_OF_MEMORY; free(ai); break; } ai->ai_addr = calloc(1, ss_size); if(!ai->ai_addr) { result = CURLE_OUT_OF_MEMORY; free(ai->ai_canonname); free(ai); break; } if(!firstai) /* store the pointer we want to return from this function */ firstai = ai; if(prevai) /* make the previous entry point to this */ prevai->ai_next = ai; ai->ai_family = addrtype; /* we return all names as STREAM, so when using this address for TFTP the type must be ignored and conn->socktype be used instead! */ ai->ai_socktype = SOCK_STREAM; ai->ai_addrlen = (curl_socklen_t)ss_size; /* leave the rest of the struct filled with zero */ switch(ai->ai_family) { case AF_INET: addr = (void *)ai->ai_addr; /* storage area for this info */ DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4)); memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr)); addr->sin_family = (CURL_SA_FAMILY_T)addrtype; addr->sin_port = htons((unsigned short)port); break; #ifdef ENABLE_IPV6 case AF_INET6: addr6 = (void *)ai->ai_addr; /* storage area for this info */ DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6)); memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr)); addr6->sin6_family = (CURL_SA_FAMILY_T)addrtype; addr6->sin6_port = htons((unsigned short)port); break; #endif } prevai = ai; } if(result) { Curl_freeaddrinfo(firstai); firstai = NULL; } return firstai; } #ifndef CURL_DISABLE_VERBOSE_STRINGS static const char *type2name(DNStype dnstype) { return (dnstype == DNS_TYPE_A)?"A":"AAAA"; } #endif UNITTEST void de_cleanup(struct dohentry *d) { int i = 0; for(i = 0; i < d->numcname; i++) { free(d->cname[i].alloc); } } CURLcode Curl_doh_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dnsp) { CURLcode result; struct Curl_easy *data = conn->data; *dnsp = NULL; /* defaults to no response */ if(!data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4].easy && !data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6].easy) { failf(data, "Could not DOH-resolve: %s", conn->async.hostname); return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: CURLE_COULDNT_RESOLVE_HOST; } else if(!data->req.doh.pending) { DOHcode rc[DOH_PROBE_SLOTS]; struct dohentry de; int slot; /* remove DOH handles from multi handle and close them */ for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { curl_multi_remove_handle(data->multi, data->req.doh.probe[slot].easy); Curl_close(&data->req.doh.probe[slot].easy); } /* parse the responses, create the struct and return it! */ init_dohentry(&de); for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { rc[slot] = doh_decode(data->req.doh.probe[slot].serverdoh.memory, data->req.doh.probe[slot].serverdoh.size, data->req.doh.probe[slot].dnstype, &de); Curl_safefree(data->req.doh.probe[slot].serverdoh.memory); if(rc[slot]) { infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]), type2name(data->req.doh.probe[slot].dnstype), data->req.doh.host); } } /* next slot */ result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */ if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) { /* we have an address, of one kind or other */ struct Curl_dns_entry *dns; struct Curl_addrinfo *ai; infof(data, "DOH Host name: %s\n", data->req.doh.host); showdoh(data, &de); ai = doh2ai(&de, data->req.doh.host, data->req.doh.port); if(!ai) { de_cleanup(&de); return CURLE_OUT_OF_MEMORY; } if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ dns = Curl_cache_addr(data, ai, data->req.doh.host, data->req.doh.port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { /* returned failure, bail out nicely */ Curl_freeaddrinfo(ai); } else { conn->async.dns = dns; *dnsp = dns; result = CURLE_OK; /* address resolution OK */ } } /* address processing done */ /* Now process any build-specific attributes retrieved from DNS */ /* All done */ de_cleanup(&de); return result; } /* !data->req.doh.pending */ /* else wait for pending DOH transactions to complete */ return CURLE_OK; } #endif /* CURL_DISABLE_DOH */ davix-0.8.0/deps/curl/lib/urldata.h0000644000000000000000000023410314121063461015604 0ustar rootroot#ifndef HEADER_CURL_URLDATA_H #define HEADER_CURL_URLDATA_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* This file is for lib internal stuff */ #include "curl_setup.h" #define PORT_FTP 21 #define PORT_FTPS 990 #define PORT_TELNET 23 #define PORT_HTTP 80 #define PORT_HTTPS 443 #define PORT_DICT 2628 #define PORT_LDAP 389 #define PORT_LDAPS 636 #define PORT_TFTP 69 #define PORT_SSH 22 #define PORT_IMAP 143 #define PORT_IMAPS 993 #define PORT_POP3 110 #define PORT_POP3S 995 #define PORT_SMB 445 #define PORT_SMBS 445 #define PORT_SMTP 25 #define PORT_SMTPS 465 /* sometimes called SSMTP */ #define PORT_RTSP 554 #define PORT_RTMP 1935 #define PORT_RTMPT PORT_HTTP #define PORT_RTMPS PORT_HTTPS #define PORT_GOPHER 70 #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" #define DICT_MATCH3 "/FIND:" #define DICT_DEFINE "/DEFINE:" #define DICT_DEFINE2 "/D:" #define DICT_DEFINE3 "/LOOKUP:" #define CURL_DEFAULT_USER "anonymous" #define CURL_DEFAULT_PASSWORD "ftp@example.com" /* Convenience defines for checking protocols or their SSL based version. Each protocol handler should only ever have a single CURLPROTO_ in its protocol field. */ #define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) #define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) #define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) #define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) #define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS) #define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP) #define DEFAULT_CONNCACHE_SIZE 5 /* length of longest IPv6 address string including the trailing null */ #define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") /* Default FTP/IMAP etc response timeout in milliseconds. Symbian OS panics when given a timeout much greater than 1/2 hour. */ #define RESP_TIMEOUT (120*1000) /* Max string intput length is a precaution against abuse and to detect junk input easier and better. */ #define CURL_MAX_INPUT_LENGTH 8000000 #include "cookie.h" #include "psl.h" #include "formdata.h" #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN6_H #include #endif #include "timeval.h" #include #include "http_chunks.h" /* for the structs and enum stuff */ #include "hostip.h" #include "hash.h" #include "splay.h" /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ int sockindex, /* socketindex */ const void *buf, /* data to write */ size_t len, /* max amount to write */ CURLcode *err); /* error to return */ /* return the count of bytes read, or -1 on error */ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ int sockindex, /* socketindex */ char *buf, /* store data here */ size_t len, /* max amount to read */ CURLcode *err); /* error to return */ #include "mime.h" #include "imap.h" #include "pop3.h" #include "smtp.h" #include "ftp.h" #include "file.h" #include "vssh/ssh.h" #include "http.h" #include "rtsp.h" #include "smb.h" #include "wildcard.h" #include "multihandle.h" #include "quic.h" #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU # include # elif defined HAVE_GSSAPI_GSSAPI_H # include # else # include # endif # ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H # include # endif #endif #ifdef HAVE_LIBSSH2_H #include #include #endif /* HAVE_LIBSSH2_H */ /* Initial size of the buffer to store headers in, it'll be enlarged in case of need. */ #define HEADERSIZE 256 #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU #define GOOD_EASY_HANDLE(x) \ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) /* the type we use for storing a single boolean bit */ #ifdef _MSC_VER typedef bool bit; #define BIT(x) bool x #else typedef unsigned int bit; #define BIT(x) bit x:1 #endif #ifdef HAVE_GSSAPI /* Types needed for krb5-ftp connections */ struct krb5buffer { void *data; size_t size; size_t index; BIT(eof_flag); }; enum protection_level { PROT_NONE, /* first in list */ PROT_CLEAR, PROT_SAFE, PROT_CONFIDENTIAL, PROT_PRIVATE, PROT_CMD, PROT_LAST /* last in list */ }; #endif /* enum for the nonblocking SSL connection state machine */ typedef enum { ssl_connect_1, ssl_connect_2, ssl_connect_2_reading, ssl_connect_2_writing, ssl_connect_3, ssl_connect_done } ssl_connect_state; typedef enum { ssl_connection_none, ssl_connection_negotiating, ssl_connection_complete } ssl_connection_state; /* SSL backend-specific data; declared differently by each SSL backend */ struct ssl_backend_data; /* struct for data related to each SSL connection */ struct ssl_connect_data { /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm but at least asked to or meaning to use it. See 'state' for the exact current state of the connection. */ ssl_connection_state state; ssl_connect_state connecting_state; #if defined(USE_SSL) struct ssl_backend_data *backend; #endif BIT(use); }; struct ssl_primary_config { long version; /* what version the client wants to use */ long version_max; /* max supported version the client wants to use*/ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ char *clientcert; char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ char *pinned_key; BIT(verifypeer); /* set TRUE if this is desired */ BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ BIT(verifystatus); /* set TRUE if certificate status must be checked */ BIT(sessionid); /* cache session IDs or not */ }; struct ssl_config_data { struct ssl_primary_config primary; long certverifyresult; /* result from the certificate verification */ char *CRLfile; /* CRL to check certificate revocation */ char *issuercert;/* optional issuer certificate filename */ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ void *fsslctxp; /* parameter for call back */ char *cert; /* client certificate file name */ char *cert_type; /* format for certificate (default: PEM)*/ char *key; /* private key file name */ char *key_type; /* format for private key (default: PEM) */ char *key_passwd; /* plain text private key password */ #ifdef USE_TLS_SRP char *username; /* TLS username (for, e.g., SRP) */ char *password; /* TLS password (for, e.g., SRP) */ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */ #endif BIT(certinfo); /* gather lots of certificate info */ BIT(falsestart); BIT(enable_beast); /* allow this flaw for interoperability's sake*/ BIT(no_revoke); /* disable SSL certificate revocation checks */ BIT(no_partialchain); /* don't accept partial certificate chains */ }; struct ssl_general_config { size_t max_ssl_sessions; /* SSL session id cache size */ }; /* information stored about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ char *conn_to_host; /* host name for the connection (may be NULL) */ const char *scheme; /* protocol scheme used */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ int remote_port; /* remote port */ int conn_to_port; /* remote port for the connection (may be -1) */ struct ssl_primary_config ssl_config; /* setup for this session */ }; #ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" #endif /* Struct used for Digest challenge-response authentication */ struct digestdata { #if defined(USE_WINDOWS_SSPI) BYTE *input_token; size_t input_token_len; CtxtHandle *http_context; /* copy of user/passwd used to make the identity for http_context. either may be NULL. */ char *user; char *passwd; #else char *nonce; char *cnonce; char *realm; int algo; char *opaque; char *qop; char *algorithm; int nc; /* nounce count */ BIT(stale); /* set true for re-negotiation */ BIT(userhash); #endif }; typedef enum { NTLMSTATE_NONE, NTLMSTATE_TYPE1, NTLMSTATE_TYPE2, NTLMSTATE_TYPE3, NTLMSTATE_LAST } curlntlm; typedef enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT, GSS_AUTHDONE, GSS_AUTHSUCC } curlnegotiate; #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) #include #endif /* Struct used for GSSAPI (Kerberos V5) authentication */ #if defined(USE_KERBEROS5) struct kerberos5data { #if defined(USE_WINDOWS_SSPI) CredHandle *credentials; CtxtHandle *context; TCHAR *spn; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; size_t token_max; BYTE *output_token; #else gss_ctx_id_t context; gss_name_t spn; #endif }; #endif /* Struct used for NTLM challenge-response authentication */ #if defined(USE_NTLM) struct ntlmdata { #ifdef USE_WINDOWS_SSPI /* The sslContext is used for the Schannel bindings. The * api is available on the Windows 7 SDK and later. */ #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS CtxtHandle *sslContext; #endif CredHandle *credentials; CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; size_t token_max; BYTE *output_token; BYTE *input_token; size_t input_token_len; TCHAR *spn; #else unsigned int flags; unsigned char nonce[8]; void *target_info; /* TargetInfo received in the ntlm type-2 message */ unsigned int target_info_len; #if defined(NTLM_WB_ENABLED) /* used for communication with Samba's winbind daemon helper ntlm_auth */ curl_socket_t ntlm_auth_hlpr_socket; pid_t ntlm_auth_hlpr_pid; char *challenge; /* The received base64 encoded ntlm type-2 message */ char *response; /* The generated base64 ntlm type-1/type-3 message */ #endif #endif }; #endif /* Struct used for Negotiate (SPNEGO) authentication */ #ifdef USE_SPNEGO struct negotiatedata { #ifdef HAVE_GSSAPI OM_uint32 status; gss_ctx_id_t context; gss_name_t spn; gss_buffer_desc output_token; #else #ifdef USE_WINDOWS_SSPI #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS CtxtHandle *sslContext; #endif DWORD status; CredHandle *credentials; CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; TCHAR *spn; size_t token_max; BYTE *output_token; size_t output_token_length; #endif #endif BIT(noauthpersist); BIT(havenoauthpersist); BIT(havenegdata); BIT(havemultiplerequests); }; #endif /* * Boolean values that concerns this connection. */ struct ConnectBits { /* always modify bits.close with the connclose() and connkeep() macros! */ bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy is complete */ bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set the first time on the first connect function call */ BIT(close); /* if set, we close the connection after this request */ BIT(reuse); /* if set, this is a re-used connection */ BIT(altused); /* this is an alt-svc "redirect" */ BIT(conn_to_host); /* if set, this connection has a "connect to host" that overrides the host in the URL */ BIT(conn_to_port); /* if set, this connection has a "connect to port" that overrides the port in the URL (remote port) */ BIT(proxy); /* if set, this transfer is done through a proxy - any type */ BIT(httpproxy); /* if set, this transfer is done through a http proxy */ BIT(socksproxy); /* if set, this transfer is done through a socks proxy */ BIT(user_passwd); /* do we use user+password for this connection? */ BIT(proxy_user_passwd); /* user+password for the proxy? */ BIT(ipv6_ip); /* we communicate with a remote site specified with pure IPv6 IP address */ BIT(ipv6); /* we communicate with a site using an IPv6 address */ BIT(do_more); /* this is set TRUE if the ->curl_do_more() function is supposed to be called, after ->curl_do() */ BIT(protoconnstart);/* the protocol layer has STARTED its operation after the TCP layer connect */ BIT(retry); /* this connection is about to get closed and then re-attempted at another connection. */ BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy. This is implicit when SSL-protocols are used through proxies, but can also be enabled explicitly by apps */ BIT(authneg); /* TRUE when the auth phase has started, which means that we are creating a request with an auth header, but it is not the final request in the auth negotiation. */ BIT(rewindaftersend);/* TRUE when the sending couldn't be stopped even though it will be discarded. When the whole send operation is done, we must call the data rewind callback. */ #ifndef CURL_DISABLE_FTP BIT(ftp_use_epsv); /* As set with CURLOPT_FTP_USE_EPSV, but if we find out EPSV doesn't work we disable it for the forthcoming requests */ BIT(ftp_use_eprt); /* As set with CURLOPT_FTP_USE_EPRT, but if we find out EPRT doesn't work we disable it for the forthcoming requests */ BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */ #endif BIT(netrc); /* name+password provided by netrc */ BIT(userpwd_in_url); /* name+password found in url */ BIT(stream_was_rewound); /* The stream was rewound after a request read past the end of its response byte boundary */ BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection in a CONNECT request with auth, so that libcurl should reconnect and continue. */ BIT(bound); /* set true if bind() has already been done on this socket/ connection */ BIT(type_set); /* type= was used in the URL */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ BIT(connect_only); }; struct hostname { char *rawalloc; /* allocated "raw" version of the name */ char *encalloc; /* allocated IDN-encoded version of the name */ char *name; /* name to use internally, might be encoded, might be raw */ const char *dispname; /* name to display, as 'name' might be encoded */ }; /* * Flags on the keepon member of the Curl_transfer_keeper */ #define KEEP_NONE 0 #define KEEP_RECV (1<<0) /* there is or may be data to read */ #define KEEP_SEND (1<<1) /* there is or may be data to write */ #define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there might still be data to read */ #define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there might still be data to write */ #define KEEP_RECV_PAUSE (1<<4) /* reading is paused */ #define KEEP_SEND_PAUSE (1<<5) /* writing is paused */ #define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE) #define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE) struct Curl_async { char *hostname; int port; struct Curl_dns_entry *dns; int status; /* if done is TRUE, this is the status from the callback */ void *os_specific; /* 'struct thread_data' for Windows */ BIT(done); /* set TRUE when the lookup is complete */ }; #define FIRSTSOCKET 0 #define SECONDARYSOCKET 1 /* These function pointer types are here only to allow easier typecasting within the source when we need to cast between data pointers (such as NULL) and function pointers. */ typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *); typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool); enum expect100 { EXP100_SEND_DATA, /* enough waiting, just send the body now */ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */ EXP100_SENDING_REQUEST, /* still sending the request but will wait for the 100 header once done with the request */ EXP100_FAILED /* used on 417 Expectation Failed */ }; enum upgrade101 { UPGR101_INIT, /* default state */ UPGR101_REQUESTED, /* upgrade requested */ UPGR101_RECEIVED, /* response received */ UPGR101_WORKING /* talking upgraded protocol */ }; enum doh_slots { /* Explicit values for first two symbols so as to match hard-coded * constants in existing code */ DOH_PROBE_SLOT_IPADDR_V4 = 0, /* make 'V4' stand out for readability */ DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */ /* Space here for (possibly build-specific) additional slot definitions */ /* for example */ /* #ifdef WANT_DOH_FOOBAR_TXT */ /* DOH_PROBE_SLOT_FOOBAR_TXT, */ /* #endif */ /* AFTER all slot definitions, establish how many we have */ DOH_PROBE_SLOTS }; struct dohresponse { unsigned char *memory; size_t size; }; /* one of these for each DoH request */ struct dnsprobe { CURL *easy; int dnstype; unsigned char dohbuffer[512]; size_t dohlen; struct dohresponse serverdoh; }; struct dohdata { struct curl_slist *headers; struct dnsprobe probe[DOH_PROBE_SLOTS]; unsigned int pending; /* still outstanding requests */ const char *host; int port; }; /* * Request specific data in the easy handle (Curl_easy). Previously, * these members were on the connectdata struct but since a conn struct may * now be shared between different Curl_easys, we store connection-specific * data here. This struct only keeps stuff that's interesting for *this* * request, as it will be cleared between multiple ones */ struct SingleRequest { curl_off_t size; /* -1 if unknown at this point */ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, -1 means unlimited */ curl_off_t bytecount; /* total number of bytes read */ curl_off_t writebytecount; /* number of bytes written */ curl_off_t headerbytecount; /* only count received headers */ curl_off_t deductheadercount; /* this amount of bytes doesn't count when we check if anything has been transferred at the end of a connection. We use this counter to make only a 100 reply (without a following second response code) result in a CURLE_GOT_NOTHING error code */ struct curltime start; /* transfer started at this time */ struct curltime now; /* current time */ enum { HEADER_NORMAL, /* no bad header at all */ HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest is normal data */ HEADER_ALLBAD /* all was believed to be header */ } badheader; /* the header was deemed bad and will be written as body */ int headerline; /* counts header lines to better track the first one */ char *hbufp; /* points at *end* of header line */ size_t hbuflen; char *str; /* within buf */ char *str_start; /* within buf */ char *end_ptr; /* within buf */ char *p; /* within headerbuff */ curl_off_t offset; /* possible resume offset read from the Content-Range: header */ int httpcode; /* error code from the 'HTTP/1.? XXX' or 'RTSP/1.? XXX' line */ struct curltime start100; /* time stamp to wait for the 100 code from */ enum expect100 exp100; /* expect 100 continue state */ enum upgrade101 upgr101; /* 101 upgrade state */ struct contenc_writer_s *writer_stack; /* Content unencoding stack. */ /* See sec 3.5, RFC2616. */ time_t timeofdoc; long bodywrites; char *buf; int keepon; char *location; /* This points to an allocated version of the Location: header data */ char *newurl; /* Set to the new URL to use when a redirect or a retry is wanted */ /* 'upload_present' is used to keep a byte counter of how much data there is still left in the buffer, aimed for upload. */ ssize_t upload_present; /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a buffer, so the next read should read from where this pointer points to, and the 'upload_present' contains the number of bytes available at this position */ char *upload_fromhere; void *protop; /* Allocated protocol-specific data. Each protocol handler makes sure this points to data it needs. */ #ifndef CURL_DISABLE_DOH struct dohdata doh; /* DoH specific data for this request */ #endif BIT(header); /* incoming data has HTTP header */ BIT(content_range); /* set TRUE if Content-Range: was found */ BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding upload and we're uploading the last chunk */ BIT(ignorebody); /* we read a response-body but we ignore it! */ BIT(http_bodyless); /* HTTP response status code is between 100 and 199, 204 or 304 */ BIT(chunk); /* if set, this is a chunked transfer-encoding */ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding on upload */ BIT(getheader); /* TRUE if header parsing is wanted */ BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for specific upload buffers. See readmoredata() in http.c for details. */ }; /* * Specific protocol handler. */ struct Curl_handler { const char *scheme; /* URL scheme name. */ /* Complement to setup_connection_internals(). */ CURLcode (*setup_connection)(struct connectdata *); /* These two functions MUST be set to be protocol dependent */ CURLcode (*do_it)(struct connectdata *, bool *done); Curl_done_func done; /* If the curl_do() function is better made in two halves, this * curl_do_more() function will be called afterwards, if set. For example * for doing the FTP stuff after the PASV/PORT command. */ Curl_do_more_func do_more; /* This function *MAY* be set to a protocol-dependent function that is run * after the connect() and everything is done, as a step in the connection. * The 'done' pointer points to a bool that should be set to TRUE if the * function completes before return. If it doesn't complete, the caller * should call the curl_connecting() function until it is. */ CURLcode (*connect_it)(struct connectdata *, bool *done); /* See above. */ CURLcode (*connecting)(struct connectdata *, bool *done); CURLcode (*doing)(struct connectdata *, bool *done); /* Called from the multi interface during the PROTOCONNECT phase, and it should then return a proper fd set */ int (*proto_getsock)(struct connectdata *conn, curl_socket_t *socks); /* Called from the multi interface during the DOING phase, and it should then return a proper fd set */ int (*doing_getsock)(struct connectdata *conn, curl_socket_t *socks); /* Called from the multi interface during the DO_MORE phase, and it should then return a proper fd set */ int (*domore_getsock)(struct connectdata *conn, curl_socket_t *socks); /* Called from the multi interface during the DO_DONE, PERFORM and WAITPERFORM phases, and it should then return a proper fd set. Not setting this will make libcurl use the generic default one. */ int (*perform_getsock)(const struct connectdata *conn, curl_socket_t *socks); /* This function *MAY* be set to a protocol-dependent function that is run * by the curl_disconnect(), as a step in the disconnection. If the handler * is called because the connection has been considered dead, dead_connection * is set to TRUE. */ CURLcode (*disconnect)(struct connectdata *, bool dead_connection); /* If used, this function gets called from transfer.c:readwrite_data() to allow the protocol to do extra reads/writes */ CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); /* This function can perform various checks on the connection. See CONNCHECK_* for more information about the checks that can be performed, and CONNRESULT_* for the results that can be returned. */ unsigned int (*connection_check)(struct connectdata *conn, unsigned int checks_to_perform); long defport; /* Default port. */ unsigned int protocol; /* See CURLPROTO_* - this needs to be the single specific protocol bit */ unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ }; #define PROTOPT_NONE 0 /* nothing extra */ #define PROTOPT_SSL (1<<0) /* uses SSL */ #define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */ #define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */ /* some protocols will have to call the underlying functions without regard to what exact state the socket signals. IE even if the socket says "readable", the send function might need to be called while uploading, or vice versa. */ #define PROTOPT_DIRLOCK (1<<3) #define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */ #define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it gets a default */ #define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle url query strings (?foo=bar) ! */ #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ #define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ #define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ #define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field of the URL */ #define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a HTTP proxy as HTTP proxies may know this protocol and act as a gateway */ #define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */ #define CONNCHECK_NONE 0 /* No checks */ #define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ #define CONNCHECK_KEEPALIVE (1<<1) /* Perform any keepalive function. */ #define CONNRESULT_NONE 0 /* No extra information. */ #define CONNRESULT_DEAD (1<<0) /* The connection is dead. */ #ifdef USE_RECV_BEFORE_SEND_WORKAROUND struct postponed_data { char *buffer; /* Temporal store for received data during sending, must be freed */ size_t allocated_size; /* Size of temporal store */ size_t recv_size; /* Size of received data during sending */ size_t recv_processed; /* Size of processed part of postponed data */ #ifdef DEBUGBUILD curl_socket_t bindsock;/* Structure must be bound to specific socket, used only for DEBUGASSERT */ #endif /* DEBUGBUILD */ }; #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct proxy_info { struct hostname host; long port; curl_proxytype proxytype; /* what kind of proxy that is in use */ char *user; /* proxy user name string, allocated */ char *passwd; /* proxy password string, allocated */ }; #define CONNECT_BUFFER_SIZE 16384 /* struct for HTTP CONNECT state data */ struct http_connect_state { char connect_buffer[CONNECT_BUFFER_SIZE]; int perline; /* count bytes per line */ int keepon; char *line_start; char *ptr; /* where to store more data */ curl_off_t cl; /* size of content to read and ignore */ enum { TUNNEL_INIT, /* init/default/no tunnel state */ TUNNEL_CONNECT, /* CONNECT has been sent off */ TUNNEL_COMPLETE /* CONNECT response received completely */ } tunnel_state; BIT(chunked_encoding); BIT(close_connection); }; struct ldapconninfo; /* for the (SOCKS) connect state machine */ enum connect_t { CONNECT_INIT, CONNECT_SOCKS_INIT, /* 1 */ CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */ CONNECT_SOCKS_READ_INIT, /* 3 set up read */ CONNECT_SOCKS_READ, /* 4 read server response */ CONNECT_GSSAPI_INIT, /* 5 */ CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */ CONNECT_AUTH_SEND, /* 7 send auth */ CONNECT_AUTH_READ, /* 8 read auth response */ CONNECT_REQ_INIT, /* 9 init SOCKS "request" */ CONNECT_RESOLVING, /* 10 */ CONNECT_RESOLVED, /* 11 */ CONNECT_RESOLVE_REMOTE, /* 12 */ CONNECT_REQ_SEND, /* 13 */ CONNECT_REQ_SENDING, /* 14 */ CONNECT_REQ_READ, /* 15 */ CONNECT_REQ_READ_MORE, /* 16 */ CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ }; #define SOCKS_STATE(x) (((x) >= CONNECT_SOCKS_INIT) && \ ((x) < CONNECT_DONE)) #define SOCKS_REQUEST_BUFSIZE 600 /* room for large user/pw (255 max each) */ struct connstate { enum connect_t state; unsigned char socksreq[SOCKS_REQUEST_BUFSIZE]; /* CONNECT_SOCKS_SEND */ ssize_t outstanding; /* send this many bytes more */ unsigned char *outp; /* send from this pointer */ }; /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. */ struct connectdata { /* 'data' is the CURRENT Curl_easy using this connection -- take great caution that this might very well vary between different times this connection is used! */ struct Curl_easy *data; struct connstate cnnct; struct curl_llist_element bundle_node; /* conncache */ /* chunk is for HTTP chunked encoding, but is in the general connectdata struct only because we can do just about any protocol through a HTTP proxy and a HTTP proxy may in fact respond using chunked encoding */ struct Curl_chunker chunk; curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ void *closesocket_client; /* This is used by the connection cache logic. If this returns TRUE, this handle is still used by one or more easy handles and can only used by any other easy handle without careful consideration (== only for multiplexing) and it cannot be used by another multi handle! */ #define CONN_INUSE(c) ((c)->easyq.size) /**** Fields set when inited and not modified again */ long connection_id; /* Contains a unique number to make it easier to track the connections in the log output */ /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in Curl_done(). This entry will be NULL if the connection is re-used as then there is no name resolve done. */ struct Curl_dns_entry *dns_entry; /* 'ip_addr' is the particular IP we connected to. It points to a struct within the DNS cache, so this pointer is only valid as long as the DNS cache entry remains locked. It gets unlocked in Curl_done() */ Curl_addrinfo *ip_addr; Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ /* 'ip_addr_str' is the ip_addr data as a human readable string. It remains available as long as the connection does, which is longer than the ip_addr itself. */ char ip_addr_str[MAX_IPADR_LEN]; unsigned int scope_id; /* Scope id for IPv6 */ enum { TRNSPRT_TCP = 3, TRNSPRT_UDP = 4, TRNSPRT_QUIC = 5 } transport; #ifdef ENABLE_QUIC struct quicsocket hequic[2]; /* two, for happy eyeballs! */ struct quicsocket *quic; #endif struct hostname host; char *hostname_resolve; /* host name to resolve to address, allocated */ char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ struct proxy_info socks_proxy; struct proxy_info http_proxy; long port; /* which port to use locally */ int remote_port; /* the remote port, not the proxy port! */ int conn_to_port; /* the remote port to connect to. valid only if bits.conn_to_port is set */ unsigned short secondary_port; /* secondary socket remote port to connect to (ftp) */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is *attempted* from the primary socket to a remote address. When more than one address is tried for a connection these will hold data for the last attempt. When the connection is actually established these are updated with data which comes directly from the socket. */ char primary_ip[MAX_IPADR_LEN]; long primary_port; /* 'local_ip' and 'local_port' get filled with local's numerical ip address and port number whenever an outgoing connection is **established** from the primary socket to a remote address. */ char local_ip[MAX_IPADR_LEN]; long local_port; char *user; /* user name string, allocated */ char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ char *sasl_authzid; /* authorisation identity string, allocated */ int httpversion; /* the HTTP version*10 reported by the server */ int rtspversion; /* the RTSP version*10 reported by the server */ struct curltime now; /* "current" time */ struct curltime created; /* creation time */ struct curltime lastused; /* when returned to the connection cache */ curl_socket_t sock[2]; /* two sockets, the second is used for the data transfer when doing FTP */ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ Curl_recv *recv[2]; Curl_send *send[2]; #ifdef USE_RECV_BEFORE_SEND_WORKAROUND struct postponed_data postponed[2]; /* two buffers for two sockets */ #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */ #ifdef USE_SSL void *ssl_extra; /* separately allocated backend-specific data */ #endif struct ssl_primary_config ssl_config; struct ssl_primary_config proxy_ssl_config; struct ConnectBits bits; /* various state-flags for this connection */ /* connecttime: when connect() is called on the current IP address. Used to be able to track when to move on to try next IP - but only when the multi interface is used. */ struct curltime connecttime; /* The two fields below get set in Curl_connecthost */ int num_addr; /* number of addresses to try to connect to */ timediff_t timeoutms_per_addr; /* how long time in milliseconds to spend on trying to connect to each IP address */ const struct Curl_handler *handler; /* Connection's protocol handler */ const struct Curl_handler *given; /* The protocol first given */ long ip_version; /* copied from the Curl_easy at creation time */ /* Protocols can use a custom keepalive mechanism to keep connections alive. This allows those protocols to track the last time the keepalive mechanism was used on this connection. */ struct curltime keepalive; long upkeep_interval_ms; /* Time between calls for connection upkeep. */ /**** curl_get() phase fields */ curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ curl_socket_t writesockfd; /* socket to write to, it may very well be the same we read from. CURL_SOCKET_BAD disables */ /** Dynamically allocated strings, MUST be freed before this **/ /** struct is killed. **/ struct dynamically_allocated_data { char *proxyuserpwd; char *uagent; char *accept_encoding; char *userpwd; char *rangeline; char *ref; char *host; char *cookiehost; char *rtsp_transport; char *te; /* TE: request header */ } allocptr; #ifdef HAVE_GSSAPI BIT(sec_complete); /* if Kerberos is enabled for this connection */ enum protection_level command_prot; enum protection_level data_prot; enum protection_level request_data_prot; size_t buffer_size; struct krb5buffer in_buffer; void *app_data; const struct Curl_sec_client_mech *mech; struct sockaddr_in local_addr; #endif #if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ struct kerberos5data krb5; /* variables into the structure definition, */ #endif /* however, some of them are ftp specific. */ struct curl_llist easyq; /* List of easy handles using this connection */ curl_seek_callback seek_func; /* function that seeks the input */ void *seek_client; /* pointer to pass to the seek() above */ /*************** Request - specific items ************/ #if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS) CtxtHandle *sslContext; #endif #if defined(USE_NTLM) curlntlm http_ntlm_state; curlntlm proxy_ntlm_state; struct ntlmdata ntlm; /* NTLM differs from other authentication schemes because it authenticates connections, not single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ #endif #ifdef USE_SPNEGO curlnegotiate http_negotiate_state; curlnegotiate proxy_negotiate_state; struct negotiatedata negotiate; /* state data for host Negotiate auth */ struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ #endif /* data used for the asynch name resolve callback */ struct Curl_async async; /* These three are used for chunked-encoding trailer support */ char *trailer; /* allocated buffer to store trailer in */ int trlMax; /* allocated buffer size */ int trlPos; /* index of where to store data */ union { struct ftp_conn ftpc; struct http_conn httpc; struct ssh_conn sshc; struct tftp_state_data *tftpc; struct imap_conn imapc; struct pop3_conn pop3c; struct smtp_conn smtpc; struct rtsp_conn rtspc; struct smb_conn smbc; void *rtmp; struct ldapconninfo *ldapc; } proto; int cselect_bits; /* bitmask of socket events */ int waitfor; /* current READ/WRITE bits to wait for */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) int socks5_gssapi_enctype; #endif /* When this connection is created, store the conditions for the local end bind. This is stored before the actual bind and before any connection is made and will serve the purpose of being used for comparison reasons so that subsequent bound-requested connections aren't accidentally re-using wrong connections. */ char *localdev; unsigned short localport; int localportrange; struct http_connect_state *connect_state; /* for HTTP CONNECT */ struct connectbundle *bundle; /* The bundle we are member of */ int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; BIT(abstract_unix_socket); #endif BIT(tls_upgraded); /* the two following *_inuse fields are only flags, not counters in any way. If TRUE it means the channel is in use, and if FALSE it means the channel is up for grabs by one. */ BIT(readchannel_inuse); /* whether the read channel is in use by an easy handle */ BIT(writechannel_inuse); /* whether the write channel is in use by an easy handle */ BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with accept() */ }; /* The end of connectdata. */ /* * Struct to keep statistical and informational data. * All variables in this struct must be initialized/reset in Curl_initinfo(). */ struct PureInfo { int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ int httpproxycode; /* response code from proxy when received separate */ int httpversion; /* the http version number X.Y = X*10+Y */ time_t filetime; /* If requested, this is might get set. Set to -1 if the time was unretrievable. */ curl_off_t header_size; /* size of read header(s) in bytes */ curl_off_t request_size; /* the amount of bytes sent in the request(s) */ unsigned long proxyauthavail; /* what proxy auth types were announced */ unsigned long httpauthavail; /* what host auth types were announced */ long numconnects; /* how many new connection did libcurl created */ char *contenttype; /* the content type of the object */ char *wouldredirect; /* URL this would've been redirected to if asked to */ curl_off_t retry_after; /* info from Retry-After: header */ /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip' and, 'conn_local_port' are copied over from the connectdata struct in order to allow curl_easy_getinfo() to return this information even when the session handle is no longer associated with a connection, and also allow curl_easy_reset() to clear this information from the session handle without disturbing information which is still alive, and that might be reused, in the connection cache. */ char conn_primary_ip[MAX_IPADR_LEN]; long conn_primary_port; char conn_local_ip[MAX_IPADR_LEN]; long conn_local_port; const char *conn_scheme; unsigned int conn_protocol; struct curl_certinfo certs; /* info about the certs, only populated in OpenSSL, GnuTLS, Schannel, NSS and GSKit builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ BIT(timecond); /* set to TRUE if the time condition didn't match, which thus made the document NOT get fetched */ }; struct Progress { time_t lastshow; /* time() of the last displayed progress meter or NULL to force redraw at next call */ curl_off_t size_dl; /* total expected size */ curl_off_t size_ul; /* total expected size */ curl_off_t downloaded; /* transferred so far */ curl_off_t uploaded; /* transferred so far */ curl_off_t current_speed; /* uses the currently fastest transfer */ int width; /* screen width at download start */ int flags; /* see progress.h */ timediff_t timespent; curl_off_t dlspeed; curl_off_t ulspeed; timediff_t t_nslookup; timediff_t t_connect; timediff_t t_appconnect; timediff_t t_pretransfer; timediff_t t_starttransfer; timediff_t t_redirect; struct curltime start; struct curltime t_startsingle; struct curltime t_startop; struct curltime t_acceptdata; /* upload speed limit */ struct curltime ul_limit_start; curl_off_t ul_limit_size; /* download speed limit */ struct curltime dl_limit_start; curl_off_t dl_limit_size; #define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; struct curltime speeder_time[ CURR_TIME ]; int speeder_c; BIT(callback); /* set when progress callback is used */ BIT(is_t_startransfer_set); }; typedef enum { HTTPREQ_NONE, /* first in list */ HTTPREQ_GET, HTTPREQ_POST, HTTPREQ_POST_FORM, /* we make a difference internally */ HTTPREQ_POST_MIME, /* we make a difference internally */ HTTPREQ_PUT, HTTPREQ_HEAD, HTTPREQ_OPTIONS, HTTPREQ_LAST /* last in list */ } Curl_HttpReq; typedef enum { RTSPREQ_NONE, /* first in list */ RTSPREQ_OPTIONS, RTSPREQ_DESCRIBE, RTSPREQ_ANNOUNCE, RTSPREQ_SETUP, RTSPREQ_PLAY, RTSPREQ_PAUSE, RTSPREQ_TEARDOWN, RTSPREQ_GET_PARAMETER, RTSPREQ_SET_PARAMETER, RTSPREQ_RECORD, RTSPREQ_RECEIVE, RTSPREQ_LAST /* last in list */ } Curl_RtspReq; /* * Values that are generated, temporary or calculated internally for a * "session handle" must be defined within the 'struct UrlState'. This struct * will be used within the Curl_easy struct. When the 'Curl_easy' * struct is cloned, this data MUST NOT be copied. * * Remember that any "state" information goes globally for the curl handle. * Session-data MUST be put in the connectdata struct and here. */ #define MAX_CURL_USER_LENGTH 256 #define MAX_CURL_PASSWORD_LENGTH 256 struct auth { unsigned long want; /* Bitmask set to the authentication methods wanted by app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ unsigned long picked; unsigned long avail; /* Bitmask for what the server reports to support for this resource */ BIT(done); /* TRUE when the auth phase is done and ready to do the actual request */ BIT(multipass); /* TRUE if this is not yet authenticated but within the auth multipass negotiation */ BIT(iestyle); /* TRUE if digest should be done IE-style or FALSE if it should be RFC compliant */ }; struct Curl_http2_dep { struct Curl_http2_dep *next; struct Curl_easy *data; }; /* * This struct is for holding data that was attempted to get sent to the user's * callback but is held due to pausing. One instance per type (BOTH, HEADER, * BODY). */ struct tempbuf { char *buf; /* allocated buffer to keep data in when a write callback returns to make the connection paused */ size_t len; /* size of the 'tempwrite' allocated buffer */ int type; /* type of the 'tempwrite' buffer as a bitmask that is used with Curl_client_write() */ }; /* Timers */ typedef enum { EXPIRE_100_TIMEOUT, EXPIRE_ASYNC_NAME, EXPIRE_CONNECTTIMEOUT, EXPIRE_DNS_PER_NAME, EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */ EXPIRE_HAPPY_EYEBALLS, EXPIRE_MULTI_PENDING, EXPIRE_RUN_NOW, EXPIRE_SPEEDCHECK, EXPIRE_TIMEOUT, EXPIRE_TOOFAST, EXPIRE_QUIC, EXPIRE_LAST /* not an actual timer, used as a marker only */ } expire_id; typedef enum { TRAILERS_NONE, TRAILERS_INITIALIZED, TRAILERS_SENDING, TRAILERS_DONE } trailers_state; /* * One instance for each timeout an easy handle can set. */ struct time_node { struct curl_llist_element list; struct curltime time; expire_id eid; }; /* individual pieces of the URL */ struct urlpieces { char *scheme; char *hostname; char *port; char *user; char *password; char *options; char *path; char *query; }; struct UrlState { /* Points to the connection cache */ struct conncache *conn_cache; /* buffers to store authentication data in, as parsed from input options */ struct curltime keeps_speed; /* for the progress meter really */ struct connectdata *lastconnect; /* The last connection, NULL if undefined */ char *headerbuff; /* allocated buffer to store headers in */ size_t headersize; /* size of the allocation */ char *buffer; /* download buffer */ char *ulbuf; /* allocated upload buffer or NULL */ curl_off_t current_speed; /* the ProgressShow() function sets this, bytes / second */ char *first_host; /* host name of the first (not followed) request. if set, this should be the host name that we will sent authorization to, no else. Used to make Location: following not keep sending user+password... This is strdup() data. */ int first_remote_port; /* remote port of the first (not followed) request */ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ long sessionage; /* number of the most recent session */ unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */ int os_errno; /* filled in with errno whenever an error occurs */ #ifdef HAVE_SIGNAL /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ void (*prev_signal)(int sig); #endif struct digestdata digest; /* state data for host Digest auth */ struct digestdata proxydigest; /* state data for proxy Digest auth */ struct auth authhost; /* auth details for host */ struct auth authproxy; /* auth details for proxy */ void *resolver; /* resolver state, if it is used in the URL state - ares_channel f.e. */ #if defined(USE_OPENSSL) /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ void *engine; #endif /* USE_OPENSSL */ struct curltime expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ struct curl_llist timeoutlist; /* list of pending timeouts */ struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */ /* a place to store the most recently set FTP entrypath */ char *most_recent_ftp_entrypath; int httpversion; /* the lowest HTTP version*10 reported by any server involved in this request */ #if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \ !defined(__SYMBIAN32__) /* do FTP line-end conversions on most platforms */ #define CURL_DO_LINEEND_CONV /* for FTP downloads: track CRLF sequences that span blocks */ BIT(prev_block_had_trailing_cr); /* for FTP downloads: how many CRLFs did we converted to LFs? */ curl_off_t crlf_conversions; #endif char *range; /* range, if used. See README for detailed specification on this syntax. */ curl_off_t resume_from; /* continue [ftp] transfer from here */ /* This RTSP state information survives requests and connections */ long rtsp_next_client_CSeq; /* the session's next client CSeq */ long rtsp_next_server_CSeq; /* the session's next server CSeq */ long rtsp_CSeq_recv; /* most recent CSeq received */ curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ size_t drain; /* Increased when this stream has data to read, even if its socket is not necessarily is readable. Decreased when checked. */ curl_read_callback fread_func; /* read callback/function */ void *in; /* CURLOPT_READDATA */ struct Curl_easy *stream_depends_on; int stream_weight; CURLU *uh; /* URL handle for the current parsed URL */ struct urlpieces up; #ifndef CURL_DISABLE_HTTP size_t trailers_bytes_sent; Curl_send_buffer *trailers_buf; /* a buffer containing the compiled trailing headers */ #endif trailers_state trailers_state; /* whether we are sending trailers and what stage are we at */ #ifdef CURLDEBUG BIT(conncache_lock); #endif /* when curl_easy_perform() is called, the multi handle is "owned" by the easy handle so curl_easy_cleanup() on such an easy handle will also close the multi handle! */ BIT(multi_owned_by_easy); BIT(this_is_a_follow); /* this is a followed Location: request */ BIT(refused_stream); /* this was refused, try again */ BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in. This must be set to FALSE every time _easy_perform() is called. */ BIT(allow_port); /* Is set.use_port allowed to take effect or not. This is always set TRUE when curl_easy_perform() is called. */ BIT(authproblem); /* TRUE if there's some problem authenticating */ /* set after initial USER failure, to prevent an authentication loop */ BIT(ftp_trying_alternative); BIT(wildcardmatch); /* enable wildcard matching */ BIT(expect100header); /* TRUE if we added Expect: 100-continue */ BIT(disableexpect); /* TRUE if Expect: is disabled due to a previous 417 response */ BIT(use_range); BIT(rangestringalloc); /* the range string is malloc()'ed */ BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE when multi_done() is called, to prevent multi_done() to get invoked twice when the multi interface is used. */ BIT(stream_depends_e); /* set or don't set the Exclusive bit */ BIT(previouslypending); /* this transfer WAS in the multi->pending queue */ BIT(cookie_engine); }; /* * This 'DynamicStatic' struct defines dynamic states that actually change * values in the 'UserDefined' area, which MUST be taken into consideration * if the UserDefined struct is cloned or similar. You can probably just * copy these, but each one indicate a special action on other data. */ struct DynamicStatic { char *url; /* work URL, copied from UserDefined */ char *referer; /* referer string */ struct curl_slist *cookielist; /* list of cookie files set by curl_easy_setopt(COOKIEFILE) calls */ struct curl_slist *resolve; /* set to point to the set.resolve list when this should be dealt with in pretransfer */ BIT(url_alloc); /* URL string is malloc()'ed */ BIT(referer_alloc); /* referer string is malloc()ed */ BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */ }; /* * This 'UserDefined' struct must only contain data that is set once to go * for many (perhaps) independent connections. Values that are generated or * calculated internally for the "session handle" MUST be defined within the * 'struct UrlState' instead. The only exceptions MUST note the changes in * the 'DynamicStatic' struct. * Character pointer fields point to dynamic storage, unless otherwise stated. */ struct Curl_multi; /* declared and used only in multi.c */ /* * This enumeration MUST not use conditional directives (#ifdefs), new * null terminated strings MUST be added to the enumeration immediately * before STRING_LASTZEROTERMINATED, binary fields immediately before * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c * test is updated and applicable changes for EBCDIC to ASCII conversion * are catered for in curl_easy_setopt_ccsid() */ enum dupstring { STRING_CERT_ORIG, /* client certificate file name */ STRING_CERT_PROXY, /* client certificate file name */ STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/ STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/ STRING_COOKIE, /* HTTP cookie string to send */ STRING_COOKIEJAR, /* dump all cookies to this file */ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */ STRING_DEVICE, /* local network interface/address to use */ STRING_ENCODING, /* Accept-Encoding string */ STRING_FTP_ACCOUNT, /* ftp account data */ STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ STRING_KEY_ORIG, /* private key file name */ STRING_KEY_PROXY, /* private key file name */ STRING_KEY_PASSWD_ORIG, /* plain text private key password */ STRING_KEY_PASSWD_PROXY, /* plain text private key password */ STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */ STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */ STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ STRING_PROXY, /* proxy to use */ STRING_PRE_PROXY, /* pre socks proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ STRING_SET_URL, /* what original URL to work on */ STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */ STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */ STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */ STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */ STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */ STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */ STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */ STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */ STRING_SSL_CIPHER13_LIST_ORIG, /* list of TLS 1.3 ciphers to use */ STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ STRING_USERAGENT, /* User-Agent string */ STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */ STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */ STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */ STRING_SSL_ENGINE, /* name of ssl engine */ STRING_USERNAME, /* , if used */ STRING_PASSWORD, /* , if used */ STRING_OPTIONS, /* , if used */ STRING_PROXYUSERNAME, /* Proxy , if used */ STRING_PROXYPASSWORD, /* Proxy , if used */ STRING_NOPROXY, /* List of hosts which should not use the proxy, if used */ STRING_RTSP_SESSION_ID, /* Session ID to use */ STRING_RTSP_STREAM_URI, /* Stream URI for this request */ STRING_RTSP_TRANSPORT, /* Transport for this session */ STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ STRING_PROXY_SERVICE_NAME, /* Proxy service name */ STRING_SERVICE_NAME, /* Service name */ STRING_MAIL_FROM, STRING_MAIL_AUTH, STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth */ STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth */ STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ STRING_BEARER, /* , if used */ STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */ STRING_TARGET, /* CURLOPT_REQUEST_TARGET */ STRING_DOH, /* CURLOPT_DOH_URL */ STRING_ALTSVC, /* CURLOPT_ALTSVC */ STRING_SASL_AUTHZID, /* CURLOPT_SASL_AUTHZID */ STRING_TEMP_URL, /* temp URL storage for proxy use */ /* -- end of zero-terminated strings -- */ STRING_LASTZEROTERMINATED, /* -- below this are pointers to binary data that cannot be strdup'ed. --- */ STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */ STRING_LAST /* not used, just an end-of-list marker */ }; /* callback that gets called when this easy handle is completed within a multi handle. Only used for internally created transfers, like for example DoH. */ typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result); struct UserDefined { FILE *err; /* the stderr user data goes here */ void *debugdata; /* the data that will be passed to fdebug */ char *errorbuffer; /* (Static) store failure messages in here */ long proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ void *out; /* CURLOPT_WRITEDATA */ void *in_set; /* CURLOPT_READDATA */ void *writeheader; /* write the header to this if non-NULL */ void *rtp_out; /* write RTP to this if non-NULL */ long use_port; /* which port to use (when not using default) */ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ long followlocation; /* as in HTTP Location: */ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ int keep_post; /* keep POSTs as POSTs after a 30x request; each bit represents a request, from 301 to 303 */ void *postfields; /* if POST, set the fields' values here */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead of strlen(), and then the data *may* be binary (contain zero bytes) */ unsigned short localport; /* local port number to bind to */ int localportrange; /* number of additional port numbers to test in case the 'localport' one can't be bind()ed */ curl_write_callback fwrite_func; /* function that stores the output */ curl_write_callback fwrite_header; /* function that stores headers */ curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */ curl_read_callback fread_func_set; /* function that reads the input */ curl_progress_callback fprogress; /* OLD and deprecated progress callback */ curl_xferinfo_callback fxferinfo; /* progress callback */ curl_debug_callback fdebug; /* function that write informational data */ curl_ioctl_callback ioctl_func; /* function for I/O control */ curl_sockopt_callback fsockopt; /* function for setting socket options */ void *sockopt_client; /* pointer to pass to the socket options callback */ curl_opensocket_callback fopensocket; /* function for checking/translating the address and opening the socket */ void *opensocket_client; curl_closesocket_callback fclosesocket; /* function for closing the socket */ void *closesocket_client; void *seek_client; /* pointer to pass to the seek callback */ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ /* function to convert from the network encoding: */ curl_conv_callback convfromnetwork; /* function to convert to the network encoding: */ curl_conv_callback convtonetwork; /* function to convert from UTF-8 encoding: */ curl_conv_callback convfromutf8; void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ long timeout; /* in milliseconds, 0 means no timeout */ long connecttimeout; /* in milliseconds, 0 means no timeout */ long accepttimeout; /* in milliseconds, 0 means no timeout */ long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */ long server_response_timeout; /* in milliseconds, 0 means no timeout */ long maxage_conn; /* in seconds, max idle time to allow a connection that is to be reused */ long tftp_blksize; /* in bytes, 0 means use default */ curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */ struct curl_slist *headers; /* linked list of extra headers */ struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ struct curl_httppost *httppost; /* linked list of old POST data */ curl_mimepart mimepost; /* MIME/POST data. */ struct curl_slist *quote; /* after connection is established */ struct curl_slist *postquote; /* after the transfer */ struct curl_slist *prequote; /* before the transfer, after type */ struct curl_slist *source_quote; /* 3rd party quote */ struct curl_slist *source_prequote; /* in 3rd party transfer mode - before the transfer on source host */ struct curl_slist *source_postquote; /* in 3rd party transfer mode - after the transfer on source host */ struct curl_slist *telnet_options; /* linked list of telnet options */ struct curl_slist *resolve; /* list of names to add/remove from DNS cache */ struct curl_slist *connect_to; /* list of host:port mappings to override the hostname and port to connect to */ curl_TimeCond timecondition; /* kind of time/date comparison */ time_t timevalue; /* what time to compare with */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ struct ssl_config_data ssl; /* user defined SSL stuff */ struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ size_t upload_buffer_size; /* size of upload buffer to use, keep it >= CURL_MAX_WRITE_SIZE */ void *private_data; /* application-private data */ struct curl_slist *http200aliases; /* linked list of aliases for http200 */ long ipver; /* the CURL_IPRESOLVE_* defines in the public header file 0 - whatever, 1 - v2, 2 - v6 */ curl_off_t max_filesize; /* Maximum file size to download */ #ifndef CURL_DISABLE_FTP curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ curl_ftpccc ftp_ccc; /* FTP CCC options */ #endif int ftp_create_missing_dirs; /* 1 - create directories that don't exist 2 - the same but also allow MKD to fail once */ curl_sshkeycallback ssh_keyfunc; /* key matching callback */ void *ssh_keyfunc_userp; /* custom pointer to callback */ enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or IMAP or POP3 or others! */ long new_file_perms; /* Permissions to use when creating remote files */ long new_directory_perms; /* Permissions to use when creating remote dirs */ long ssh_auth_types; /* allowed SSH auth types */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ unsigned int scope_id; /* Scope id for IPv6 */ long allowed_protocols; long redir_protocols; struct curl_slist *mail_rcpt; /* linked list of mail recipients */ /* Common RTSP header options */ Curl_RtspReq rtspreq; /* RTSP request type */ long rtspversion; /* like httpversion, for RTSP */ curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer starts */ curl_chunk_end_callback chunk_end; /* called after part transferring stopped */ curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; long gssapi_delegation; /* GSS-API credential delegation, see the documentation of CURLOPT_GSSAPI_DELEGATION */ long tcp_keepidle; /* seconds in idle before sending keepalive probe */ long tcp_keepintvl; /* seconds between TCP keepalive probes */ size_t maxconnects; /* Max idle connections in the connection cache */ long expect_100_timeout; /* in milliseconds */ struct Curl_easy *stream_depends_on; int stream_weight; struct Curl_http2_dep *stream_dependents; curl_resolver_start_callback resolver_start; /* optional callback called before resolver start */ void *resolver_start_client; /* pointer to pass to resolver start callback */ long upkeep_interval_ms; /* Time between calls for connection upkeep. */ multidone_func fmultidone; struct Curl_easy *dohfor; /* this is a DoH request for that transfer */ CURLU *uh; /* URL handle for the current parsed URL */ void *trailer_data; /* pointer to pass to trailer data callback */ curl_trailer_callback trailer_callback; /* trailing data callback */ BIT(is_fread_set); /* has read callback been set to non-NULL? */ BIT(is_fwrite_set); /* has write callback been set to non-NULL? */ BIT(free_referer); /* set TRUE if 'referer' points to a string we allocated */ BIT(tftp_no_options); /* do not send TFTP options requests */ BIT(sep_headers); /* handle host and proxy headers separately */ BIT(cookiesession); /* new cookie session? */ BIT(crlf); /* convert crlf on ftp upload(?) */ BIT(strip_path_slash); /* strip off initial slash from path */ BIT(ssh_compression); /* enable SSH compression */ /* Here follows boolean settings that define how to behave during this session. They are STATIC, set by libcurl users or at least initially and they don't change during operations. */ BIT(get_filetime); /* get the time and get of the remote file */ BIT(tunnel_thru_httpproxy); /* use CONNECT through a HTTP proxy */ BIT(prefer_ascii); /* ASCII rather than binary */ BIT(ftp_append); /* append, not overwrite, on upload */ BIT(ftp_list_only); /* switch FTP command for listing directories */ #ifndef CURL_DISABLE_FTP BIT(ftp_use_port); /* use the FTP PORT command */ BIT(ftp_use_epsv); /* if EPSV is to be attempted or not */ BIT(ftp_use_eprt); /* if EPRT is to be attempted or not */ BIT(ftp_use_pret); /* if PRET is to be used before PASV or not */ BIT(ftp_skip_ip); /* skip the IP address the FTP server passes on to us */ #endif BIT(hide_progress); /* don't use the progress meter */ BIT(http_fail_on_error); /* fail on HTTP error codes >= 400 */ BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */ BIT(http_follow_location); /* follow HTTP redirects */ BIT(http_transfer_encoding); /* request compressed HTTP transfer-encoding */ BIT(allow_auth_to_other_hosts); BIT(include_header); /* include received protocol headers in data output */ BIT(http_set_referer); /* is a custom referer used */ BIT(http_auto_referer); /* set "correct" referer when following location: */ BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ BIT(upload); /* upload request */ BIT(verbose); /* output verbosity */ BIT(krb); /* Kerberos connection requested */ BIT(reuse_forbid); /* forbidden to be reused, close after use */ BIT(reuse_fresh); /* do not re-use an existing connection */ BIT(no_signal); /* do not use any signal/alarm handler */ BIT(tcp_nodelay); /* whether to enable TCP_NODELAY or not */ BIT(ignorecl); /* ignore content length */ BIT(connect_only); /* make connection, let application use the socket */ BIT(http_te_skip); /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ BIT(http_ce_skip); /* pass the raw body data to the user, even when content-encoded (chunked, compressed) */ BIT(proxy_transfer_mode); /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) BIT(socks5_gssapi_nec); /* Flag to support NEC SOCKS5 server */ #endif BIT(sasl_ir); /* Enable/disable SASL initial response */ BIT(wildcard_enabled); /* enable wildcard matching */ BIT(tcp_keepalive); /* use TCP keepalives */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(ssl_enable_npn); /* TLS NPN extension? */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new connection */ BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers from user callbacks */ BIT(dns_shuffle_addresses); /* whether to shuffle addresses before use */ BIT(stream_depends_e); /* set or don't set the Exclusive bit */ BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1 header */ BIT(abstract_unix_socket); BIT(disallow_username_in_url); /* disallow username in url */ BIT(doh); /* DNS-over-HTTPS enabled */ BIT(doh_get); /* use GET for DoH requests, instead of POST */ BIT(http09_allowed); /* allow HTTP/0.9 responses */ BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some recipients */ }; struct Names { struct curl_hash *hostcache; enum { HCACHE_NONE, /* not pointing to anything */ HCACHE_MULTI, /* points to a shared one in the multi handle */ HCACHE_SHARED /* points to a shared one in a shared object */ } hostcachetype; }; /* * The 'connectdata' struct MUST have all the connection oriented stuff as we * may have several simultaneous connections and connection structs in memory. * * The 'struct UserDefined' must only contain data that is set once to go for * many (perhaps) independent connections. Values that are generated or * calculated internally for the "session handle" must be defined within the * 'struct UrlState' instead. */ struct Curl_easy { /* first, two fields for the linked list of these */ struct Curl_easy *next; struct Curl_easy *prev; struct connectdata *conn; struct curl_llist_element connect_queue; struct curl_llist_element conn_queue; /* list per connectdata */ CURLMstate mstate; /* the handle's state */ CURLcode result; /* previous result */ struct Curl_message msg; /* A single posted message. */ /* Array with the plain socket numbers this handle takes care of, in no particular order. Note that all sockets are added to the sockhash, where the state etc are also kept. This array is mostly used to detect when a socket is to be removed from the hash. See singlesocket(). */ curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; int actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in sockets[] */ int numsocks; struct Names dns; struct Curl_multi *multi; /* if non-NULL, points to the multi handle struct to which this "belongs" when used by the multi interface */ struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle struct to which this "belongs" when used by the easy interface */ struct Curl_share *share; /* Share, handles global variable mutexing */ #ifdef USE_LIBPSL struct PslCache *psl; /* The associated PSL cache. */ #endif struct SingleRequest req; /* Request-specific data */ struct UserDefined set; /* values set by the libcurl user */ struct DynamicStatic change; /* possibly modified userdefined data */ struct CookieInfo *cookies; /* the cookies, read from files and servers. NOTE that the 'cookie' field in the UserDefined struct defines if the "engine" is to be used or not. */ #ifdef USE_ALTSVC struct altsvcinfo *asi; /* the alt-svc cache */ #endif struct Progress progress; /* for all the progress meter data */ struct UrlState state; /* struct for fields used for state info and other dynamic purposes */ #ifndef CURL_DISABLE_FTP struct WildcardData wildcard; /* wildcard download state info */ #endif struct PureInfo info; /* stats, reports and info data */ struct curl_tlssessioninfo tsi; /* Information about the TLS session, only valid after a client has asked for it */ #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) iconv_t outbound_cd; /* for translating to the network encoding */ iconv_t inbound_cd; /* for translating from the network encoding */ iconv_t utf8_cd; /* for translating to UTF8 */ #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */ }; #define LIBCURL_NAME "libcurl" #endif /* HEADER_CURL_URLDATA_H */ davix-0.8.0/deps/curl/lib/socketpair.h0000644000000000000000000000264214121063461016315 0ustar rootroot#ifndef HEADER_CURL_SOCKETPAIR_H #define HEADER_CURL_SOCKETPAIR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef HAVE_SOCKETPAIR int Curl_socketpair(int domain, int type, int protocol, curl_socket_t socks[2]); #else #define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d) #endif /* Defined here to allow specific build configs to disable it completely */ #define USE_SOCKETPAIR 1 #endif /* HEADER_CURL_SOCKETPAIR_H */ davix-0.8.0/deps/curl/lib/Makefile.netware0000644000000000000000000005412614121063461017110 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2004 - 2015, Guenter Knauf # Copyright (C) 2001 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** ################################################################# # ## Makefile for building libcurl.nlm (NetWare version - gnu make) ## ## Use: make -f Makefile.netware # ################################################################# # Edit the path below to point to the base of your Novell NDK. ifndef NDKBASE NDKBASE = c:/novell endif # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH ZLIB_PATH = ../../zlib-1.2.8 endif # Edit the path below to point to the base of your OpenSSL package. ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-1.0.2a endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH LIBSSH2_PATH = ../../libssh2-1.5.0 endif # Edit the path below to point to the base of your libidn package. ifndef LIBIDN_PATH LIBIDN_PATH = ../../libidn-1.18 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.3 endif # Edit the path below to point to the base of your nghttp2 package. ifndef NGHTTP2_PATH NGHTTP2_PATH = ../../nghttp2-0.6.7 endif # Edit the path below to point to the base of your fbopenssl package. ifndef FBOPENSSL_PATH FBOPENSSL_PATH = ../../fbopenssl-0.4 endif # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = ../ares endif ifndef INSTDIR INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw endif # Edit the vars below to change NLM target settings. TARGET = libcurl VERSION = $(LIBCURL_VERSION) COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) DESCR = curl libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se MTSAFE = YES STACK = 64000 SCREEN = none EXPORTF = $(TARGET).imp EXPORTS = @$(EXPORTF) # Uncomment the next line to enable linking with POSIX semantics. # POSIXFL = 1 # Edit the var below to point to your lib architecture. ifndef LIBARCH LIBARCH = LIBC endif # must be equal to NDEBUG or DEBUG, CURLDEBUG ifndef DB DB = NDEBUG endif # Optimization: -O or debugging: -g ifeq ($(DB),NDEBUG) OPT = -O2 OBJDIR = release else OPT = -g OBJDIR = debug endif # The following lines defines your compiler. ifdef CWFolder METROWERKS = $(CWFolder) endif ifdef METROWERKS # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support CC = mwccnlm else CC = gcc endif PERL = perl # Here you can find a native Win32 binary of the original awk: # http://www.gknw.net/development/prgtools/awk-20100523.zip AWK = awk CP = cp -afv MKDIR = mkdir # RM = rm -f # If you want to mark the target as MTSAFE you will need a tool for # generating the xdc data for the linker; here's a minimal tool: # http://www.gknw.net/development/prgtools/mkxdc.zip MPKXDC = mkxdc # LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH)) LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH)) # Include the version info retrieved from curlver.h -include $(OBJDIR)/version.inc # Global flags for all compilers CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc ifeq ($(CC),mwccnlm) LD = mwldnlm LDFLAGS = -nostdlib $(PRELUDE) $(OBJL) -o $@ -commandfile AR = mwldnlm ARFLAGS = -nostdlib -type library -o LIBEXT = lib #RANLIB = CFLAGS += -msgstyle gcc -gccinc -inline off -opt nointrinsics -proc 586 CFLAGS += -relax_pointers #CFLAGS += -w on ifeq ($(LIBARCH),LIBC) ifeq ($(POSIXFL),1) PRELUDE = $(NDK_LIBC)/imports/posixpre.o else PRELUDE = $(NDK_LIBC)/imports/libcpre.o endif CFLAGS += -align 4 else # PRELUDE = $(NDK_CLIB)/imports/clibpre.o # to avoid the __init_* / __deinit_* woes don't use prelude from NDK PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj" # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h" CFLAGS += -align 1 endif else LD = nlmconv LDFLAGS = -T AR = ar ARFLAGS = -cq LIBEXT = a RANLIB = ranlib CFLAGS += -m32 CFLAGS += -fno-builtin -fno-strict-aliasing ifeq ($(findstring gcc,$(CC)),gcc) CFLAGS += -fpcc-struct-return endif CFLAGS += -Wall # -pedantic ifeq ($(LIBARCH),LIBC) ifeq ($(POSIXFL),1) PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o else PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o endif else PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o # to avoid the __init_* / __deinit_* woes don't use prelude from NDK # http://www.gknw.net/development/mk_nlm/gcc_pre.zip # PRELUDE = $(NDK_ROOT)/pre/prelude.o CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h endif endif NDK_ROOT = $(NDKBASE)/ndk ifndef NDK_CLIB NDK_CLIB = $(NDK_ROOT)/nwsdk endif ifndef NDK_LIBC NDK_LIBC = $(NDK_ROOT)/libc endif ifndef NDK_LDAP NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware endif CURL_INC = ../include CURL_LIB = ../lib INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) ifeq ($(findstring -static,$(CFG)),-static) LINK_STATIC = 1 endif ifeq ($(findstring -ares,$(CFG)),-ares) WITH_ARES = 1 endif ifeq ($(findstring -rtmp,$(CFG)),-rtmp) WITH_RTMP = 1 WITH_SSL = 1 WITH_ZLIB = 1 endif ifeq ($(findstring -ssh2,$(CFG)),-ssh2) WITH_SSH2 = 1 WITH_SSL = 1 WITH_ZLIB = 1 endif ifeq ($(findstring -ssl,$(CFG)),-ssl) WITH_SSL = 1 ifeq ($(findstring -srp,$(CFG)),-srp) ifeq "$(wildcard $(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)/openssl/srp.h)" "$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)/openssl/srp.h" WITH_SRP = 1 endif endif endif ifeq ($(findstring -zlib,$(CFG)),-zlib) WITH_ZLIB = 1 endif ifeq ($(findstring -idn,$(CFG)),-idn) WITH_IDN = 1 endif ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) WITH_NGHTTP2 = 1 endif ifeq ($(findstring -ipv6,$(CFG)),-ipv6) ENABLE_IPV6 = 1 endif ifdef WITH_ARES INCLUDES += -I$(LIBCARES_PATH) LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) endif ifdef WITH_SSH2 INCLUDES += -I$(LIBSSH2_PATH)/include ifdef LINK_STATIC LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) else MODULES += libssh2.nlm IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp endif endif ifdef WITH_RTMP INCLUDES += -I$(LIBRTMP_PATH) LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT) endif ifdef WITH_SSL INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) IMPORTS += GetProcessSwitchCount RunningProcess INSTDEP += ca-bundle.crt else endif ifdef WITH_ZLIB INCLUDES += -I$(ZLIB_PATH) ifdef LINK_STATIC LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT) else MODULES += libz.nlm IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp endif endif ifdef WITH_IDN INCLUDES += -I$(LIBIDN_PATH)/include LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT) endif ifdef WITH_NGHTTP2 INCLUDES += -I$(NGHTTP2_PATH)/include LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT) endif ifeq ($(LIBARCH),LIBC) INCLUDES += -I$(NDK_LIBC)/include # INCLUDES += -I$(NDK_LIBC)/include/nks # INCLUDES += -I$(NDK_LIBC)/include/winsock CFLAGS += -D_POSIX_SOURCE else INCLUDES += -I$(NDK_CLIB)/include/nlm # INCLUDES += -I$(NDK_CLIB)/include/nlm/obsolete # INCLUDES += -I$(NDK_CLIB)/include endif ifndef DISABLE_LDAP INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc endif CFLAGS += $(INCLUDES) ifeq ($(MTSAFE),YES) XDCOPT = -n endif ifeq ($(MTSAFE),NO) XDCOPT = -u endif ifdef XDCOPT XDCDATA = $(OBJDIR)/$(TARGET).xdc endif ifeq ($(findstring /sh,$(SHELL)),/sh) DL = ' DS = / PCT = % #-include $(NDKBASE)/nlmconv/ncpfs.inc else DS = \\ PCT = %% endif # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(notdir $(CSOURCES)))) $(OBJDIR)/nwos.o OBJL = $(OBJS) $(OBJDIR)/nwlib.o $(LDLIBS) vpath %.c . vauth vtls all: lib nlm nlm: prebuild $(TARGET).nlm lib: prebuild $(TARGET).$(LIBEXT) prebuild: $(OBJDIR) $(OBJDIR)/version.inc curl_config.h $(OBJDIR)/%.o: %.c # @echo Compiling $< $(CC) $(CFLAGS) -c $< -o $@ $(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR) @echo Creating $@ @$(AWK) -f ../packages/NetWare/get_ver.awk $< > $@ install: $(INSTDIR) all $(INSTDEP) @$(CP) $(TARGET).nlm $(INSTDIR) @$(CP) $(TARGET).$(LIBEXT) $(INSTDIR) @$(CP) ../CHANGES $(INSTDIR) @$(CP) ../COPYING $(INSTDIR) @$(CP) ../README $(INSTDIR) @$(CP) ../RELEASE-NOTES $(INSTDIR) ifdef WITH_SSL @-$(CP) ca-bundle.crt $(INSTDIR)/ca-bundle.crt endif clean: -$(RM) curl_config.h -$(RM) -r $(OBJDIR) distclean vclean: clean -$(RM) $(TARGET).$(LIBEXT) $(TARGET).nlm $(TARGET).imp -$(RM) certdata.txt ca-bundle.crt $(OBJDIR) $(INSTDIR): @$(MKDIR) $@ $(TARGET).$(LIBEXT): $(OBJS) @echo Creating $@ @-$(RM) $@ @$(AR) $(ARFLAGS) $@ $^ ifdef RANLIB @$(RANLIB) $@ endif $(TARGET).nlm: $(OBJDIR)/$(TARGET).def $(OBJL) $(EXPORTF) $(XDCDATA) @echo Linking $@ @-$(RM) $@ @$(LD) $(LDFLAGS) $< $(OBJDIR)/%.xdc: Makefile.netware @echo Creating $@ @$(MPKXDC) $(XDCOPT) $@ $(OBJDIR)/%.def: Makefile.netware @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@ @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@ @echo $(DL)# All your changes will be lost!!$(DL) >> $@ @echo $(DL)#$(DL) >> $@ @echo $(DL)copyright "$(COPYR)"$(DL) >> $@ @echo $(DL)description "$(DESCR)"$(DL) >> $@ @echo $(DL)version $(VERSION)$(DL) >> $@ ifdef NLMTYPE @echo $(DL)type $(NLMTYPE)$(DL) >> $@ endif ifdef STACK @echo $(DL)stack $(STACK)$(DL) >> $@ endif ifdef SCREEN @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@ else @echo $(DL)screenname "DEFAULT"$(DL) >> $@ endif ifneq ($(DB),NDEBUG) @echo $(DL)debug$(DL) >> $@ endif @echo $(DL)threadname "$(TARGET)"$(DL) >> $@ ifdef XDCDATA @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@ endif @echo $(DL)flag_on 64$(DL) >> $@ ifeq ($(LIBARCH),CLIB) @echo $(DL)start _Prelude$(DL) >> $@ @echo $(DL)exit _Stop$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@ @echo $(DL)module clib$(DL) >> $@ ifndef DISABLE_LDAP @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@ # @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@ @echo $(DL)module ldapsdk ldapssl$(DL) >> $@ endif else ifeq ($(POSIXFL),1) @echo $(DL)flag_on 4194304$(DL) >> $@ endif @echo $(DL)pseudopreemption$(DL) >> $@ ifeq ($(findstring posixpre,$(PRELUDE)),posixpre) @echo $(DL)start POSIX_Start$(DL) >> $@ @echo $(DL)exit POSIX_Stop$(DL) >> $@ @echo $(DL)check POSIX_CheckUnload$(DL) >> $@ else @echo $(DL)start _LibCPrelude$(DL) >> $@ @echo $(DL)exit _LibCPostlude$(DL) >> $@ @echo $(DL)check _LibCCheckUnload$(DL) >> $@ endif @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@ @echo $(DL)module libc$(DL) >> $@ ifndef DISABLE_LDAP @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@ # @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@ @echo $(DL)module lldapsdk lldapssl$(DL) >> $@ endif endif ifdef MODULES @echo $(DL)module $(MODULES)$(DL) >> $@ endif ifdef EXPORTS @echo $(DL)export $(EXPORTS)$(DL) >> $@ endif ifdef IMPORTS @echo $(DL)import $(IMPORTS)$(DL) >> $@ endif ifeq ($(findstring nlmconv,$(LD)),nlmconv) @echo $(DL)input $(PRELUDE)$(DL) >> $@ @echo $(DL)input $(OBJL)$(DL) >> $@ #ifdef LDLIBS # @echo $(DL)input $(LDLIBS)$(DL) >> $@ #endif @echo $(DL)output $(TARGET).nlm$(DL) >> $@ endif curl_config.h: Makefile.netware @echo Creating $@ @echo $(DL)/* $@ for NetWare target.$(DL) > $@ @echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@ @echo $(DL)** All your changes will be lost!!$(DL) >> $@ @echo $(DL)*/$(DL) >> $@ @echo $(DL)#ifndef NETWARE$(DL) >> $@ @echo $(DL)#error This $(notdir $@) is created for NetWare platform!$(DL) >> $@ @echo $(DL)#endif$(DL) >> $@ @echo $(DL)#define VERSION "$(LIBCURL_VERSION_STR)"$(DL) >> $@ @echo $(DL)#define PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/"$(DL) >> $@ ifeq ($(LIBARCH),CLIB) @echo $(DL)#define OS "i586-pc-clib-NetWare"$(DL) >> $@ @echo $(DL)#define NETDB_USE_INTERNET 1$(DL) >> $@ @echo $(DL)#define HAVE_STRICMP 1$(DL) >> $@ @echo $(DL)#define HAVE_STRNICMP 1$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG2 char *$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG3 int$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define RECV_TYPE_RETV int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG2 char$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG3 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG5 struct sockaddr$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG6 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_RETV int$(DL) >> $@ @echo $(DL)#define SEND_QUAL_ARG2$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG2 char *$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG3 int$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define SEND_TYPE_RETV int$(DL) >> $@ @echo $(DL)#define SIZEOF_SIZE_T 4$(DL) >> $@ @echo $(DL)#define pressanykey PressAnyKeyToContinue$(DL) >> $@ else @echo $(DL)#define OS "i586-pc-libc-NetWare"$(DL) >> $@ @echo $(DL)#define HAVE_FTRUNCATE 1$(DL) >> $@ @echo $(DL)#define HAVE_GETTIMEOFDAY 1$(DL) >> $@ @echo $(DL)#define HAVE_INTTYPES_H 1$(DL) >> $@ @echo $(DL)#define HAVE_LONGLONG 1$(DL) >> $@ @echo $(DL)#define HAVE_STDINT_H 1$(DL) >> $@ @echo $(DL)#define HAVE_STRCASECMP 1$(DL) >> $@ @echo $(DL)#define HAVE_STRLCAT 1$(DL) >> $@ @echo $(DL)#define HAVE_STRLCPY 1$(DL) >> $@ @echo $(DL)#define HAVE_STRTOLL 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_PARAM_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_SELECT_H 1$(DL) >> $@ @echo $(DL)#define HAVE_TERMIOS_H 1$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG2 void *$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG3 size_t$(DL) >> $@ @echo $(DL)#define RECV_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define RECV_TYPE_RETV ssize_t$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG2 void$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG3 size_t$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG5 struct sockaddr$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG6 size_t$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_RETV ssize_t$(DL) >> $@ @echo $(DL)#define RECVFROM_TYPE_ARG2_IS_VOID 1$(DL) >> $@ @echo $(DL)#define SEND_QUAL_ARG2$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG1 int$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG2 void *$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG3 size_t$(DL) >> $@ @echo $(DL)#define SEND_TYPE_ARG4 int$(DL) >> $@ @echo $(DL)#define SEND_TYPE_RETV ssize_t$(DL) >> $@ @echo $(DL)#define SIZEOF_OFF_T 8$(DL) >> $@ @echo $(DL)#define SIZEOF_SIZE_T 8$(DL) >> $@ @echo $(DL)#define _LARGEFILE 1$(DL) >> $@ ifdef ENABLE_IPV6 @echo $(DL)#define ENABLE_IPV6 1$(DL) >> $@ @echo $(DL)#define HAVE_AF_INET6 1$(DL) >> $@ @echo $(DL)#define HAVE_PF_INET6 1$(DL) >> $@ @echo $(DL)#define HAVE_FREEADDRINFO 1$(DL) >> $@ @echo $(DL)#define HAVE_GETADDRINFO 1$(DL) >> $@ @echo $(DL)#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1$(DL) >> $@ @echo $(DL)#define HAVE_STRUCT_ADDRINFO 1$(DL) >> $@ @echo $(DL)#define HAVE_STRUCT_IN6_ADDR 1$(DL) >> $@ @echo $(DL)#define HAVE_STRUCT_SOCKADDR_IN6 1$(DL) >> $@ @echo $(DL)#define SIZEOF_STRUCT_IN6_ADDR 16$(DL) >> $@ endif endif @echo $(DL)#define USE_MANUAL 1$(DL) >> $@ @echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@ @echo $(DL)#define HAVE_GETHOSTBYNAME 1$(DL) >> $@ @echo $(DL)#define HAVE_GETPROTOBYNAME 1$(DL) >> $@ @echo $(DL)#define HAVE_GMTIME_R 1$(DL) >> $@ @echo $(DL)#define HAVE_INET_ADDR 1$(DL) >> $@ @echo $(DL)#define HAVE_IOCTL 1$(DL) >> $@ @echo $(DL)#define HAVE_IOCTL_FIONBIO 1$(DL) >> $@ @echo $(DL)#define HAVE_LL 1$(DL) >> $@ @echo $(DL)#define HAVE_LOCALE_H 1$(DL) >> $@ @echo $(DL)#define HAVE_LOCALTIME_R 1$(DL) >> $@ @echo $(DL)#define HAVE_MALLOC_H 1$(DL) >> $@ @echo $(DL)#define HAVE_NETINET_IN_H 1$(DL) >> $@ @echo $(DL)#define HAVE_RECV 1$(DL) >> $@ @echo $(DL)#define HAVE_RECVFROM 1$(DL) >> $@ @echo $(DL)#define HAVE_SELECT 1$(DL) >> $@ @echo $(DL)#define HAVE_SEND 1$(DL) >> $@ @echo $(DL)#define HAVE_SETJMP_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SETLOCALE 1$(DL) >> $@ @echo $(DL)#define HAVE_SIGNAL 1$(DL) >> $@ @echo $(DL)#define HAVE_SIGNAL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SIG_ATOMIC_T 1$(DL) >> $@ @echo $(DL)#define HAVE_SOCKET 1$(DL) >> $@ @echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@ @echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@ @echo $(DL)#define HAVE_STRFTIME 1$(DL) >> $@ @echo $(DL)#define HAVE_STRING_H 1$(DL) >> $@ @echo $(DL)#define HAVE_STRSTR 1$(DL) >> $@ @echo $(DL)#define HAVE_STRUCT_TIMEVAL 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_IOCTL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_STAT_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_TIME_H 1$(DL) >> $@ @echo $(DL)#define HAVE_TIME_H 1$(DL) >> $@ @echo $(DL)#define HAVE_UNAME 1$(DL) >> $@ @echo $(DL)#define HAVE_UNISTD_H 1$(DL) >> $@ @echo $(DL)#define HAVE_UTIME 1$(DL) >> $@ @echo $(DL)#define HAVE_UTIME_H 1$(DL) >> $@ @echo $(DL)#define HAVE_WRITEV 1$(DL) >> $@ @echo $(DL)#define RETSIGTYPE void$(DL) >> $@ @echo $(DL)#define SIZEOF_INT 4$(DL) >> $@ @echo $(DL)#define SIZEOF_SHORT 2$(DL) >> $@ @echo $(DL)#define SIZEOF_STRUCT_IN_ADDR 4$(DL) >> $@ @echo $(DL)#define STDC_HEADERS 1$(DL) >> $@ @echo $(DL)#define TIME_WITH_SYS_TIME 1$(DL) >> $@ ifdef DISABLE_LDAP @echo $(DL)#define CURL_DISABLE_LDAP 1$(DL) >> $@ else @echo $(DL)#define CURL_HAS_NOVELL_LDAPSDK 1$(DL) >> $@ ifndef DISABLE_LDAPS @echo $(DL)#define HAVE_LDAP_SSL 1$(DL) >> $@ endif @echo $(DL)#define HAVE_LDAP_SSL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_LDAP_URL_PARSE 1$(DL) >> $@ endif ifdef NW_WINSOCK @echo $(DL)#define HAVE_CLOSESOCKET 1$(DL) >> $@ else @echo $(DL)#define USE_BSD_SOCKETS 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_TYPES_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_SOCKET_H 1$(DL) >> $@ @echo $(DL)#define HAVE_SYS_SOCKIO_H 1$(DL) >> $@ @echo $(DL)#define HAVE_NETDB_H 1$(DL) >> $@ endif ifdef WITH_ARES @echo $(DL)#define USE_ARES 1$(DL) >> $@ endif ifdef WITH_ZLIB @echo $(DL)#define HAVE_ZLIB_H 1$(DL) >> $@ @echo $(DL)#define HAVE_LIBZ 1$(DL) >> $@ endif ifdef WITH_SSL @echo $(DL)#define USE_OPENSSL 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_X509_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_SSL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_RSA_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_PEM_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_OPENSSL_CRYPTO_H 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ ifdef WITH_SRP @echo $(DL)#define USE_TLS_SRP 1$(DL) >> $@ endif ifdef WITH_SPNEGO @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ endif else endif ifdef WITH_SSH2 @echo $(DL)#define USE_LIBSSH2 1$(DL) >> $@ @echo $(DL)#define HAVE_LIBSSH2_H 1$(DL) >> $@ endif ifdef WITH_IDN @echo $(DL)#define HAVE_LIBIDN 1$(DL) >> $@ @echo $(DL)#define HAVE_TLD_H 1$(DL) >> $@ endif ifdef WITH_RTMP @echo $(DL)#define USE_LIBRTMP 1$(DL) >> $@ endif ifdef WITH_NGHTTP2 @echo $(DL)#define USE_NGHTTP2 1$(DL) >> $@ endif @echo $(DL)#ifdef __GNUC__$(DL) >> $@ @echo $(DL)#define HAVE_VARIADIC_MACROS_GCC 1$(DL) >> $@ @echo $(DL)#else$(DL) >> $@ @echo $(DL)#define HAVE_VARIADIC_MACROS_C99 1$(DL) >> $@ @echo $(DL)#endif$(DL) >> $@ ifdef CABUNDLE @echo $(DL)#define CURL_CA_BUNDLE "$(CABUNDLE)"$(DL) >> $@ else @echo $(DL)#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")$(DL) >> $@ endif $(EXPORTF): $(CURL_INC)/curl/curl.h $(CURL_INC)/curl/easy.h $(CURL_INC)/curl/multi.h $(CURL_INC)/curl/mprintf.h @echo Creating $@ @$(AWK) -f ../packages/NetWare/get_exp.awk $^ > $@ FORCE: ; info: $(OBJDIR)/version.inc @echo Configured to build $(TARGET) with these options: @echo libarchitecture: $(LIBARCH) @echo curl version: $(LIBCURL_VERSION_STR) @echo compiler/linker: $(CC) / $(LD) ifdef CABUNDLE @echo ca-bundle path: $(CABUNDLE) endif ifdef WITH_SSL @echo SSL support: enabled (OpenSSL) else @echo SSL support: no endif ifdef WITH_SRP @echo SRP support: enabled else @echo SRP support: no endif ifdef WITH_SSH2 @echo SSH2 support: enabled (libssh2) else @echo SSH2 support: no endif ifdef WITH_ZLIB @echo zlib support: enabled else @echo zlib support: no endif ifdef WITH_NGHTTP2 @echo http2 support: enabled else @echo http2 support: no endif ifdef WITH_ARES @echo c-ares support: enabled else @echo c-ares support: no endif ifdef ENABLE_IPV6 @echo IPv6 support: enabled else @echo IPv6 support: no endif $(LIBCARES_PATH)/libcares.$(LIBEXT): $(MAKE) -C $(LIBCARES_PATH) -f Makefile.netware lib ca-bundle.crt: mk-ca-bundle.pl @echo Creating $@ @-$(PERL) $< -b -n $@ davix-0.8.0/deps/curl/lib/imap.h0000644000000000000000000000754514121063461015106 0ustar rootroot#ifndef HEADER_CURL_IMAP_H #define HEADER_CURL_IMAP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2009 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "pingpong.h" #include "curl_sasl.h" /**************************************************************************** * IMAP unique setup ***************************************************************************/ typedef enum { IMAP_STOP, /* do nothing state, stops the state machine */ IMAP_SERVERGREET, /* waiting for the initial greeting immediately after a connect */ IMAP_CAPABILITY, IMAP_STARTTLS, IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ IMAP_AUTHENTICATE, IMAP_LOGIN, IMAP_LIST, IMAP_SELECT, IMAP_FETCH, IMAP_FETCH_FINAL, IMAP_APPEND, IMAP_APPEND_FINAL, IMAP_SEARCH, IMAP_LOGOUT, IMAP_LAST /* never used */ } imapstate; /* This IMAP struct is used in the Curl_easy. All IMAP data that is connection-oriented must be in imap_conn to properly deal with the fact that perhaps the Curl_easy is changed between the times the connection is used. */ struct IMAP { curl_pp_transfer transfer; char *mailbox; /* Mailbox to select */ char *uidvalidity; /* UIDVALIDITY to check in select */ char *uid; /* Message UID to fetch */ char *mindex; /* Index in mail box of mail to fetch */ char *section; /* Message SECTION to fetch */ char *partial; /* Message PARTIAL to fetch */ char *query; /* Query to search for */ char *custom; /* Custom request */ char *custom_params; /* Parameters for the custom request */ }; /* imap_conn is used for struct connection-oriented data in the connectdata struct */ struct imap_conn { struct pingpong pp; imapstate state; /* Always use imap.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ bool preauth; /* Is this connection PREAUTH? */ struct SASL sasl; /* SASL-related parameters */ unsigned int preftype; /* Preferred authentication type */ int cmdid; /* Last used command ID */ char resptag[5]; /* Response tag to wait for */ bool tls_supported; /* StartTLS capability supported by server */ bool login_disabled; /* LOGIN command disabled by server */ bool ir_supported; /* Initial response supported by server */ char *mailbox; /* The last selected mailbox */ char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ }; extern const struct Curl_handler Curl_handler_imap; extern const struct Curl_handler Curl_handler_imaps; /* Authentication type flags */ #define IMAP_TYPE_CLEARTEXT (1 << 0) #define IMAP_TYPE_SASL (1 << 1) /* Authentication type values */ #define IMAP_TYPE_NONE 0 #define IMAP_TYPE_ANY ~0U #endif /* HEADER_CURL_IMAP_H */ davix-0.8.0/deps/curl/lib/x509asn1.c0000644000000000000000000010646214121063461015441 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ defined(USE_WOLFSSL) || defined(USE_SCHANNEL) #include #include "urldata.h" #include "strcase.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" #include "inet_pton.h" #include "curl_base64.h" #include "x509asn1.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* ASN.1 OIDs. */ static const char cnOID[] = "2.5.4.3"; /* Common name. */ static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */ static const curl_OID OIDtable[] = { { "1.2.840.10040.4.1", "dsa" }, { "1.2.840.10040.4.3", "dsa-with-sha1" }, { "1.2.840.10045.2.1", "ecPublicKey" }, { "1.2.840.10045.3.0.1", "c2pnb163v1" }, { "1.2.840.10045.4.1", "ecdsa-with-SHA1" }, { "1.2.840.10046.2.1", "dhpublicnumber" }, { "1.2.840.113549.1.1.1", "rsaEncryption" }, { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" }, { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" }, { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" }, { "1.2.840.113549.1.1.10", "RSASSA-PSS" }, { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" }, { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" }, { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" }, { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" }, { "1.2.840.113549.2.2", "md2" }, { "1.2.840.113549.2.5", "md5" }, { "1.3.14.3.2.26", "sha1" }, { cnOID, "CN" }, { "2.5.4.4", "SN" }, { "2.5.4.5", "serialNumber" }, { "2.5.4.6", "C" }, { "2.5.4.7", "L" }, { "2.5.4.8", "ST" }, { "2.5.4.9", "streetAddress" }, { "2.5.4.10", "O" }, { "2.5.4.11", "OU" }, { "2.5.4.12", "title" }, { "2.5.4.13", "description" }, { "2.5.4.17", "postalCode" }, { "2.5.4.41", "name" }, { "2.5.4.42", "givenName" }, { "2.5.4.43", "initials" }, { "2.5.4.44", "generationQualifier" }, { "2.5.4.45", "X500UniqueIdentifier" }, { "2.5.4.46", "dnQualifier" }, { "2.5.4.65", "pseudonym" }, { "1.2.840.113549.1.9.1", "emailAddress" }, { "2.5.4.72", "role" }, { sanOID, "subjectAltName" }, { "2.5.29.18", "issuerAltName" }, { "2.5.29.19", "basicConstraints" }, { "2.16.840.1.101.3.4.2.4", "sha224" }, { "2.16.840.1.101.3.4.2.1", "sha256" }, { "2.16.840.1.101.3.4.2.2", "sha384" }, { "2.16.840.1.101.3.4.2.3", "sha512" }, { (const char *) NULL, (const char *) NULL } }; /* * Lightweight ASN.1 parser. * In particular, it does not check for syntactic/lexical errors. * It is intended to support certificate information gathering for SSL backends * that offer a mean to get certificates as a whole, but do not supply * entry points to get particular certificate sub-fields. * Please note there is no pretention here to rewrite a full SSL library. */ static const char *getASN1Element(curl_asn1Element *elem, const char *beg, const char *end) WARN_UNUSED_RESULT; static const char *getASN1Element(curl_asn1Element *elem, const char *beg, const char *end) { unsigned char b; unsigned long len; curl_asn1Element lelem; /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' ending at `end'. Returns a pointer in source string after the parsed element, or NULL if an error occurs. */ if(!beg || !end || beg >= end || !*beg || (size_t)(end - beg) > CURL_ASN1_MAX) return NULL; /* Process header byte. */ elem->header = beg; b = (unsigned char) *beg++; elem->constructed = (b & 0x20) != 0; elem->class = (b >> 6) & 3; b &= 0x1F; if(b == 0x1F) return NULL; /* Long tag values not supported here. */ elem->tag = b; /* Process length. */ if(beg >= end) return NULL; b = (unsigned char) *beg++; if(!(b & 0x80)) len = b; else if(!(b &= 0x7F)) { /* Unspecified length. Since we have all the data, we can determine the effective length by skipping element until an end element is found. */ if(!elem->constructed) return NULL; elem->beg = beg; while(beg < end && *beg) { beg = getASN1Element(&lelem, beg, end); if(!beg) return NULL; } if(beg >= end) return NULL; elem->end = beg; return beg + 1; } else if((unsigned)b > (size_t)(end - beg)) return NULL; /* Does not fit in source. */ else { /* Get long length. */ len = 0; do { if(len & 0xFF000000L) return NULL; /* Lengths > 32 bits are not supported. */ len = (len << 8) | (unsigned char) *beg++; } while(--b); } if(len > (size_t)(end - beg)) return NULL; /* Element data does not fit in source. */ elem->beg = beg; elem->end = beg + len; return elem->end; } /* * Search the null terminated OID or OID identifier in local table. * Return the table entry pointer or NULL if not found. */ static const curl_OID * searchOID(const char *oid) { const curl_OID *op; for(op = OIDtable; op->numoid; op++) if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) return op; return NULL; } /* * Convert an ASN.1 Boolean value into its string representation. Return the * dynamically allocated string, or NULL if source is not an ASN.1 Boolean * value. */ static const char *bool2str(const char *beg, const char *end) { if(end - beg != 1) return NULL; return strdup(*beg? "TRUE": "FALSE"); } /* * Convert an ASN.1 octet string to a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *octet2str(const char *beg, const char *end) { size_t n = end - beg; char *buf = NULL; if(n <= (SIZE_T_MAX - 1) / 3) { buf = malloc(3 * n + 1); if(buf) for(n = 0; beg < end; n += 3) msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); } return buf; } static const char *bit2str(const char *beg, const char *end) { /* Convert an ASN.1 bit string to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ if(++beg > end) return NULL; return octet2str(beg, end); } /* * Convert an ASN.1 integer value into its string representation. * Return the dynamically allocated string, or NULL if source is not an * ASN.1 integer value. */ static const char *int2str(const char *beg, const char *end) { unsigned long val = 0; size_t n = end - beg; if(!n) return NULL; if(n > 4) return octet2str(beg, end); /* Represent integers <= 32-bit as a single value. */ if(*beg & 0x80) val = ~val; do val = (val << 8) | *(const unsigned char *) beg++; while(beg < end); return curl_maprintf("%s%lx", val >= 10? "0x": "", val); } /* * Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the * destination buffer dynamically. The allocation size will normally be too * large: this is to avoid buffer overflows. * Terminate the string with a nul byte and return the converted * string length. */ static ssize_t utf8asn1str(char **to, int type, const char *from, const char *end) { size_t inlength = end - from; int size = 1; size_t outlength; char *buf; *to = NULL; switch(type) { case CURL_ASN1_BMP_STRING: size = 2; break; case CURL_ASN1_UNIVERSAL_STRING: size = 4; break; case CURL_ASN1_NUMERIC_STRING: case CURL_ASN1_PRINTABLE_STRING: case CURL_ASN1_TELETEX_STRING: case CURL_ASN1_IA5_STRING: case CURL_ASN1_VISIBLE_STRING: case CURL_ASN1_UTF8_STRING: break; default: return -1; /* Conversion not supported. */ } if(inlength % size) return -1; /* Length inconsistent with character size. */ if(inlength / size > (SIZE_T_MAX - 1) / 4) return -1; /* Too big. */ buf = malloc(4 * (inlength / size) + 1); if(!buf) return -1; /* Not enough memory. */ if(type == CURL_ASN1_UTF8_STRING) { /* Just copy. */ outlength = inlength; if(outlength) memcpy(buf, from, outlength); } else { for(outlength = 0; from < end;) { int charsize; unsigned int wc; wc = 0; switch(size) { case 4: wc = (wc << 8) | *(const unsigned char *) from++; wc = (wc << 8) | *(const unsigned char *) from++; /* FALLTHROUGH */ case 2: wc = (wc << 8) | *(const unsigned char *) from++; /* FALLTHROUGH */ default: /* case 1: */ wc = (wc << 8) | *(const unsigned char *) from++; } charsize = 1; if(wc >= 0x00000080) { if(wc >= 0x00000800) { if(wc >= 0x00010000) { if(wc >= 0x00200000) { free(buf); return -1; /* Invalid char. size for target encoding. */ } buf[outlength + 3] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x00010000; charsize++; } buf[outlength + 2] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x00000800; charsize++; } buf[outlength + 1] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x000000C0; charsize++; } buf[outlength] = (char) wc; outlength += charsize; } } buf[outlength] = '\0'; *to = buf; return outlength; } /* * Convert an ASN.1 String into its UTF-8 string representation. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *string2str(int type, const char *beg, const char *end) { char *buf; if(utf8asn1str(&buf, type, beg, end) < 0) return NULL; return buf; } /* * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at * buf. Return the total number of encoded digits, even if larger than * `buflen'. */ static size_t encodeUint(char *buf, size_t buflen, unsigned int x) { size_t i = 0; unsigned int y = x / 10; if(y) { i = encodeUint(buf, buflen, y); x -= y * 10; } if(i < buflen) buf[i] = (char) ('0' + x); i++; if(i < buflen) buf[i] = '\0'; /* Store a terminator if possible. */ return i; } /* * Convert an ASN.1 OID into its dotted string representation. * Store the result in th `n'-byte buffer at `buf'. * Return the converted string length, or 0 on errors. */ static size_t encodeOID(char *buf, size_t buflen, const char *beg, const char *end) { size_t i; unsigned int x; unsigned int y; /* Process the first two numbers. */ y = *(const unsigned char *) beg++; x = y / 40; y -= x * 40; i = encodeUint(buf, buflen, x); if(i < buflen) buf[i] = '.'; i++; if(i >= buflen) i += encodeUint(NULL, 0, y); else i += encodeUint(buf + i, buflen - i, y); /* Process the trailing numbers. */ while(beg < end) { if(i < buflen) buf[i] = '.'; i++; x = 0; do { if(x & 0xFF000000) return 0; y = *(const unsigned char *) beg++; x = (x << 7) | (y & 0x7F); } while(y & 0x80); if(i >= buflen) i += encodeUint(NULL, 0, x); else i += encodeUint(buf + i, buflen - i, x); } if(i < buflen) buf[i] = '\0'; return i; } /* * Convert an ASN.1 OID into its dotted or symbolic string representation. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *OID2str(const char *beg, const char *end, bool symbolic) { char *buf = NULL; if(beg < end) { size_t buflen = encodeOID(NULL, 0, beg, end); if(buflen) { buf = malloc(buflen + 1); /* one extra for the zero byte */ if(buf) { encodeOID(buf, buflen, beg, end); buf[buflen] = '\0'; if(symbolic) { const curl_OID *op = searchOID(buf); if(op) { free(buf); buf = strdup(op->textoid); } } } } } return buf; } static const char *GTime2str(const char *beg, const char *end) { const char *tzp; const char *fracp; char sec1, sec2; size_t fracl; size_t tzl; const char *sep = ""; /* Convert an ASN.1 Generalized time to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++) ; /* Get seconds digits. */ sec1 = '0'; switch(fracp - beg - 12) { case 0: sec2 = '0'; break; case 2: sec1 = fracp[-2]; /* FALLTHROUGH */ case 1: sec2 = fracp[-1]; break; default: return NULL; } /* Scan for timezone, measure fractional seconds. */ tzp = fracp; fracl = 0; if(fracp < end && (*fracp == '.' || *fracp == ',')) { fracp++; do tzp++; while(tzp < end && *tzp >= '0' && *tzp <= '9'); /* Strip leading zeroes in fractional seconds. */ for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--) ; } /* Process timezone. */ if(tzp >= end) ; /* Nothing to do. */ else if(*tzp == 'Z') { tzp = " GMT"; end = tzp + 4; } else { sep = " "; tzp++; } tzl = end - tzp; return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", beg, beg + 4, beg + 6, beg + 8, beg + 10, sec1, sec2, fracl? ".": "", fracl, fracp, sep, tzl, tzp); } /* * Convert an ASN.1 UTC time to a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *UTime2str(const char *beg, const char *end) { const char *tzp; size_t tzl; const char *sec; for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++) ; /* Get the seconds. */ sec = beg + 10; switch(tzp - sec) { case 0: sec = "00"; case 2: break; default: return NULL; } /* Process timezone. */ if(tzp >= end) return NULL; if(*tzp == 'Z') { tzp = "GMT"; end = tzp + 3; } else tzp++; tzl = end - tzp; return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", 20 - (*beg >= '5'), beg, beg + 2, beg + 4, beg + 6, beg + 8, sec, tzl, tzp); } /* * Convert an ASN.1 element to a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *ASN1tostr(curl_asn1Element *elem, int type) { if(elem->constructed) return NULL; /* No conversion of structured elements. */ if(!type) type = elem->tag; /* Type not forced: use element tag as type. */ switch(type) { case CURL_ASN1_BOOLEAN: return bool2str(elem->beg, elem->end); case CURL_ASN1_INTEGER: case CURL_ASN1_ENUMERATED: return int2str(elem->beg, elem->end); case CURL_ASN1_BIT_STRING: return bit2str(elem->beg, elem->end); case CURL_ASN1_OCTET_STRING: return octet2str(elem->beg, elem->end); case CURL_ASN1_NULL: return strdup(""); case CURL_ASN1_OBJECT_IDENTIFIER: return OID2str(elem->beg, elem->end, TRUE); case CURL_ASN1_UTC_TIME: return UTime2str(elem->beg, elem->end); case CURL_ASN1_GENERALIZED_TIME: return GTime2str(elem->beg, elem->end); case CURL_ASN1_UTF8_STRING: case CURL_ASN1_NUMERIC_STRING: case CURL_ASN1_PRINTABLE_STRING: case CURL_ASN1_TELETEX_STRING: case CURL_ASN1_IA5_STRING: case CURL_ASN1_VISIBLE_STRING: case CURL_ASN1_UNIVERSAL_STRING: case CURL_ASN1_BMP_STRING: return string2str(type, elem->beg, elem->end); } return NULL; /* Unsupported. */ } /* * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at * `buf'. Return the total string length, even if larger than `buflen'. */ static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn) { curl_asn1Element rdn; curl_asn1Element atv; curl_asn1Element oid; curl_asn1Element value; size_t l = 0; const char *p1; const char *p2; const char *p3; const char *str; for(p1 = dn->beg; p1 < dn->end;) { p1 = getASN1Element(&rdn, p1, dn->end); if(!p1) return -1; for(p2 = rdn.beg; p2 < rdn.end;) { p2 = getASN1Element(&atv, p2, rdn.end); if(!p2) return -1; p3 = getASN1Element(&oid, atv.beg, atv.end); if(!p3) return -1; if(!getASN1Element(&value, p3, atv.end)) return -1; str = ASN1tostr(&oid, 0); if(!str) return -1; /* Encode delimiter. If attribute has a short uppercase name, delimiter is ", ". */ if(l) { for(p3 = str; isupper(*p3); p3++) ; for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { if(l < buflen) buf[l] = *p3; l++; } } /* Encode attribute name. */ for(p3 = str; *p3; p3++) { if(l < buflen) buf[l] = *p3; l++; } free((char *) str); /* Generate equal sign. */ if(l < buflen) buf[l] = '='; l++; /* Generate value. */ str = ASN1tostr(&value, 0); if(!str) return -1; for(p3 = str; *p3; p3++) { if(l < buflen) buf[l] = *p3; l++; } free((char *) str); } } return l; } /* * Convert an ASN.1 distinguished name into a printable string. * Return the dynamically allocated string, or NULL if an error occurs. */ static const char *DNtostr(curl_asn1Element *dn) { char *buf = NULL; ssize_t buflen = encodeDN(NULL, 0, dn); if(buflen >= 0) { buf = malloc(buflen + 1); if(buf) { encodeDN(buf, buflen + 1, dn); buf[buflen] = '\0'; } } return buf; } /* * ASN.1 parse an X509 certificate into structure subfields. * Syntax is assumed to have already been checked by the SSL backend. * See RFC 5280. */ int Curl_parseX509(curl_X509certificate *cert, const char *beg, const char *end) { curl_asn1Element elem; curl_asn1Element tbsCertificate; const char *ccp; static const char defaultVersion = 0; /* v1. */ cert->certificate.header = NULL; cert->certificate.beg = beg; cert->certificate.end = end; /* Get the sequence content. */ if(!getASN1Element(&elem, beg, end)) return -1; /* Invalid bounds/size. */ beg = elem.beg; end = elem.end; /* Get tbsCertificate. */ beg = getASN1Element(&tbsCertificate, beg, end); if(!beg) return -1; /* Skip the signatureAlgorithm. */ beg = getASN1Element(&cert->signatureAlgorithm, beg, end); if(!beg) return -1; /* Get the signatureValue. */ if(!getASN1Element(&cert->signature, beg, end)) return -1; /* Parse TBSCertificate. */ beg = tbsCertificate.beg; end = tbsCertificate.end; /* Get optional version, get serialNumber. */ cert->version.header = NULL; cert->version.beg = &defaultVersion; cert->version.end = &defaultVersion + sizeof(defaultVersion); beg = getASN1Element(&elem, beg, end); if(!beg) return -1; if(elem.tag == 0) { if(!getASN1Element(&cert->version, elem.beg, elem.end)) return -1; beg = getASN1Element(&elem, beg, end); if(!beg) return -1; } cert->serialNumber = elem; /* Get signature algorithm. */ beg = getASN1Element(&cert->signatureAlgorithm, beg, end); /* Get issuer. */ beg = getASN1Element(&cert->issuer, beg, end); if(!beg) return -1; /* Get notBefore and notAfter. */ beg = getASN1Element(&elem, beg, end); if(!beg) return -1; ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end); if(!ccp) return -1; if(!getASN1Element(&cert->notAfter, ccp, elem.end)) return -1; /* Get subject. */ beg = getASN1Element(&cert->subject, beg, end); if(!beg) return -1; /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */ beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end); if(!beg) return -1; ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm, cert->subjectPublicKeyInfo.beg, cert->subjectPublicKeyInfo.end); if(!ccp) return -1; if(!getASN1Element(&cert->subjectPublicKey, ccp, cert->subjectPublicKeyInfo.end)) return -1; /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; cert->extensions.tag = elem.tag = 0; cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; cert->extensions.header = NULL; cert->extensions.beg = cert->extensions.end = ""; if(beg < end) { beg = getASN1Element(&elem, beg, end); if(!beg) return -1; } if(elem.tag == 1) { cert->issuerUniqueID = elem; if(beg < end) { beg = getASN1Element(&elem, beg, end); if(!beg) return -1; } } if(elem.tag == 2) { cert->subjectUniqueID = elem; if(beg < end) { beg = getASN1Element(&elem, beg, end); if(!beg) return -1; } } if(elem.tag == 3) if(!getASN1Element(&cert->extensions, elem.beg, elem.end)) return -1; return 0; } /* * Copy at most 64-characters, terminate with a newline and returns the * effective number of stored characters. */ static size_t copySubstring(char *to, const char *from) { size_t i; for(i = 0; i < 64; i++) { to[i] = *from; if(!*from++) break; } to[i++] = '\n'; return i; } static const char *dumpAlgo(curl_asn1Element *param, const char *beg, const char *end) { curl_asn1Element oid; /* Get algorithm parameters and return algorithm name. */ beg = getASN1Element(&oid, beg, end); if(!beg) return NULL; param->header = NULL; param->tag = 0; param->beg = param->end = end; if(beg < end) if(!getASN1Element(param, beg, end)) return NULL; return OID2str(oid.beg, oid.end, TRUE); } static void do_pubkey_field(struct Curl_easy *data, int certnum, const char *label, curl_asn1Element *elem) { const char *output; /* Generate a certificate information record for the public key. */ output = ASN1tostr(elem, 0); if(output) { if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, label, output); if(!certnum) infof(data, " %s: %s\n", label, output); free((char *) output); } } static void do_pubkey(struct Curl_easy *data, int certnum, const char *algo, curl_asn1Element *param, curl_asn1Element *pubkey) { curl_asn1Element elem; curl_asn1Element pk; const char *p; /* Generate all information records for the public key. */ /* Get the public key (single element). */ if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end)) return; if(strcasecompare(algo, "rsaEncryption")) { const char *q; unsigned long len; p = getASN1Element(&elem, pk.beg, pk.end); if(!p) return; /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) ; len = (unsigned long)((elem.end - q) * 8); if(len) { unsigned int i; for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1) len--; } if(len > 32) elem.beg = q; /* Strip leading zero bytes. */ if(!certnum) infof(data, " RSA Public Key (%lu bits)\n", len); if(data->set.ssl.certinfo) { q = curl_maprintf("%lu", len); if(q) { Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q); free((char *) q); } } /* Generate coefficients. */ do_pubkey_field(data, certnum, "rsa(n)", &elem); if(!getASN1Element(&elem, p, pk.end)) return; do_pubkey_field(data, certnum, "rsa(e)", &elem); } else if(strcasecompare(algo, "dsa")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { do_pubkey_field(data, certnum, "dsa(p)", &elem); p = getASN1Element(&elem, p, param->end); if(p) { do_pubkey_field(data, certnum, "dsa(q)", &elem); if(getASN1Element(&elem, p, param->end)) { do_pubkey_field(data, certnum, "dsa(g)", &elem); do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); } } } } else if(strcasecompare(algo, "dhpublicnumber")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { do_pubkey_field(data, certnum, "dh(p)", &elem); if(getASN1Element(&elem, param->beg, param->end)) { do_pubkey_field(data, certnum, "dh(g)", &elem); do_pubkey_field(data, certnum, "dh(pub_key)", &pk); } } } } CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, const char *beg, const char *end) { curl_X509certificate cert; struct Curl_easy *data = conn->data; curl_asn1Element param; const char *ccp; char *cp1; size_t cl1; char *cp2; CURLcode result; unsigned long version; size_t i; size_t j; if(!data->set.ssl.certinfo) if(certnum) return CURLE_OK; /* Prepare the certificate information for curl_easy_getinfo(). */ /* Extract the certificate ASN.1 elements. */ if(Curl_parseX509(&cert, beg, end)) return CURLE_PEER_FAILED_VERIFICATION; /* Subject. */ ccp = DNtostr(&cert.subject); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Subject", ccp); if(!certnum) infof(data, "%2d Subject: %s\n", certnum, ccp); free((char *) ccp); /* Issuer. */ ccp = DNtostr(&cert.issuer); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp); if(!certnum) infof(data, " Issuer: %s\n", ccp); free((char *) ccp); /* Version (always fits in less than 32 bits). */ version = 0; for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) version = (version << 8) | *(const unsigned char *) ccp; if(data->set.ssl.certinfo) { ccp = curl_maprintf("%lx", version); if(!ccp) return CURLE_OUT_OF_MEMORY; Curl_ssl_push_certinfo(data, certnum, "Version", ccp); free((char *) ccp); } if(!certnum) infof(data, " Version: %lu (0x%lx)\n", version + 1, version); /* Serial number. */ ccp = ASN1tostr(&cert.serialNumber, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp); if(!certnum) infof(data, " Serial Number: %s\n", ccp); free((char *) ccp); /* Signature algorithm .*/ ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, cert.signatureAlgorithm.end); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); if(!certnum) infof(data, " Signature Algorithm: %s\n", ccp); free((char *) ccp); /* Start Date. */ ccp = ASN1tostr(&cert.notBefore, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp); if(!certnum) infof(data, " Start Date: %s\n", ccp); free((char *) ccp); /* Expire Date. */ ccp = ASN1tostr(&cert.notAfter, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp); if(!certnum) infof(data, " Expire Date: %s\n", ccp); free((char *) ccp); /* Public Key Algorithm. */ ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, cert.subjectPublicKeyAlgorithm.end); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp); if(!certnum) infof(data, " Public Key Algorithm: %s\n", ccp); do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); free((char *) ccp); /* Signature. */ ccp = ASN1tostr(&cert.signature, 0); if(!ccp) return CURLE_OUT_OF_MEMORY; if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Signature", ccp); if(!certnum) infof(data, " Signature: %s\n", ccp); free((char *) ccp); /* Generate PEM certificate. */ result = Curl_base64_encode(data, cert.certificate.beg, cert.certificate.end - cert.certificate.beg, &cp1, &cl1); if(result) return result; /* Compute the number of characters in final certificate string. Format is: -----BEGIN CERTIFICATE-----\n \n . . . -----END CERTIFICATE-----\n */ i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; cp2 = malloc(i + 1); if(!cp2) { free(cp1); return CURLE_OUT_OF_MEMORY; } /* Build the certificate string. */ i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); for(j = 0; j < cl1; j += 64) i += copySubstring(cp2 + i, cp1 + j); i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); cp2[i] = '\0'; free(cp1); if(data->set.ssl.certinfo) Curl_ssl_push_certinfo(data, certnum, "Cert", cp2); if(!certnum) infof(data, "%s\n", cp2); free(cp2); return CURLE_OK; } #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */ #if defined(USE_GSKIT) static const char *checkOID(const char *beg, const char *end, const char *oid) { curl_asn1Element e; const char *ccp; const char *p; bool matched; /* Check if first ASN.1 element at `beg' is the given OID. Return a pointer in the source after the OID if found, else NULL. */ ccp = getASN1Element(&e, beg, end); if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) return NULL; p = OID2str(e.beg, e.end, FALSE); if(!p) return NULL; matched = !strcmp(p, oid); free((char *) p); return matched? ccp: NULL; } CURLcode Curl_verifyhost(struct connectdata *conn, const char *beg, const char *end) { struct Curl_easy *data = conn->data; curl_X509certificate cert; curl_asn1Element dn; curl_asn1Element elem; curl_asn1Element ext; curl_asn1Element name; const char *p; const char *q; char *dnsname; int matched = -1; size_t addrlen = (size_t) -1; ssize_t len; const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: conn->host.name; const char * const dispname = SSL_IS_PROXY()? conn->http_proxy.host.dispname: conn->host.dispname; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif /* Verify that connection server matches info in X509 certificate at `beg'..`end'. */ if(!SSL_CONN_CONFIG(verifyhost)) return CURLE_OK; if(Curl_parseX509(&cert, beg, end)) return CURLE_PEER_FAILED_VERIFICATION; /* Get the server IP address. */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) addrlen = sizeof(struct in6_addr); else #endif if(Curl_inet_pton(AF_INET, hostname, &addr)) addrlen = sizeof(struct in_addr); /* Process extensions. */ for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { p = getASN1Element(&ext, p, cert.extensions.end); if(!p) return CURLE_PEER_FAILED_VERIFICATION; /* Check if extension is a subjectAlternativeName. */ ext.beg = checkOID(ext.beg, ext.end, sanOID); if(ext.beg) { ext.beg = getASN1Element(&elem, ext.beg, ext.end); if(!ext.beg) return CURLE_PEER_FAILED_VERIFICATION; /* Skip critical if present. */ if(elem.tag == CURL_ASN1_BOOLEAN) { ext.beg = getASN1Element(&elem, ext.beg, ext.end); if(!ext.beg) return CURLE_PEER_FAILED_VERIFICATION; } /* Parse the octet string contents: is a single sequence. */ if(!getASN1Element(&elem, elem.beg, elem.end)) return CURLE_PEER_FAILED_VERIFICATION; /* Check all GeneralNames. */ for(q = elem.beg; matched != 1 && q < elem.end;) { q = getASN1Element(&name, q, elem.end); if(!q) break; switch(name.tag) { case 2: /* DNS name. */ len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); if(len > 0 && (size_t)len == strlen(dnsname)) matched = Curl_cert_hostcheck(dnsname, hostname); else matched = 0; free(dnsname); break; case 7: /* IP address. */ matched = (size_t) (name.end - name.beg) == addrlen && !memcmp(&addr, name.beg, addrlen); break; } } } } switch(matched) { case 1: /* an alternative name matched the server hostname */ infof(data, "\t subjectAltName: %s matched\n", dispname); return CURLE_OK; case 0: /* an alternative name field existed, but didn't match and then we MUST fail */ infof(data, "\t subjectAltName does not match %s\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } /* Process subject. */ name.header = NULL; name.beg = name.end = ""; q = cert.subject.beg; /* we have to look to the last occurrence of a commonName in the distinguished one to get the most significant one. */ while(q < cert.subject.end) { q = getASN1Element(&dn, q, cert.subject.end); if(!q) break; for(p = dn.beg; p < dn.end;) { p = getASN1Element(&elem, p, dn.end); if(!p) return CURLE_PEER_FAILED_VERIFICATION; /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ elem.beg = checkOID(elem.beg, elem.end, cnOID); if(elem.beg) name = elem; /* Latch CN. */ } } /* Check the CN if found. */ if(!getASN1Element(&elem, name.beg, name.end)) failf(data, "SSL: unable to obtain common name from peer certificate"); else { len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); if(len < 0) { free(dnsname); return CURLE_OUT_OF_MEMORY; } if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ failf(data, "SSL: illegal cert name field"); else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { infof(data, "\t common name: %s (matched)\n", dnsname); free(dnsname); return CURLE_OK; } else failf(data, "SSL: certificate subject name '%s' does not match " "target host name '%s'", dnsname, dispname); free(dnsname); } return CURLE_PEER_FAILED_VERIFICATION; } #endif /* USE_GSKIT */ davix-0.8.0/deps/curl/lib/nwlib.c0000644000000000000000000002265514121063461015265 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to register as a real lib. */ #include #include #include #include #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct { int _errno; void *twentybytes; } libthreaddata_t; typedef struct { int x; int y; int z; void *tenbytes; NXKey_t perthreadkey; /* if -1, no key obtained... */ NXMutex_t *lock; } libdata_t; int gLibId = -1; void *gLibHandle = (void *) NULL; rtag_t gAllocTag = (rtag_t) NULL; NXMutex_t *gLibLock = (NXMutex_t *) NULL; /* internal library function prototypes... */ int DisposeLibraryData(void *); void DisposeThreadData(void *); int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); int _NonAppStart(void *NLMHandle, void *errorScreen, const char *cmdLine, const char *loadDirPath, size_t uninitializedDataLength, void *NLMFileHandle, int (*readRoutineP)(int conn, void *fileHandle, size_t offset, size_t nbytes, size_t *bytesRead, void *buffer), size_t customDataOffset, size_t customDataSize, int messageCount, const char **messages) { NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); #ifndef __GNUC__ #pragma unused(cmdLine) #pragma unused(loadDirPath) #pragma unused(uninitializedDataLength) #pragma unused(NLMFileHandle) #pragma unused(readRoutineP) #pragma unused(customDataOffset) #pragma unused(customDataSize) #pragma unused(messageCount) #pragma unused(messages) #endif /* * Here we process our command line, post errors (to the error screen), * perform initializations and anything else we need to do before being able * to accept calls into us. If we succeed, we return non-zero and the NetWare * Loader will leave us up, otherwise we fail to load and get dumped. */ gAllocTag = AllocateResourceTag(NLMHandle, " memory allocations", AllocSignature); if(!gAllocTag) { OutputToScreen(errorScreen, "Unable to allocate resource tag for " "library memory allocations.\n"); return -1; } gLibId = register_library(DisposeLibraryData); if(gLibId < -1) { OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); return -1; } gLibHandle = NLMHandle; gLibLock = NXMutexAlloc(0, 0, &liblock); if(!gLibLock) { OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); return -1; } return 0; } /* * Here we clean up any resources we allocated. Resource tags is a big part * of what we created, but NetWare doesn't ask us to free those. */ void _NonAppStop(void) { (void) unregister_library(gLibId); NXMutexFree(gLibLock); } /* * This function cannot be the first in the file for if the file is linked * first, then the check-unload function's offset will be nlmname.nlm+0 * which is how to tell that there isn't one. When the check function is * first in the linked objects, it is ambiguous. For this reason, we will * put it inside this file after the stop function. * * Here we check to see if it's alright to ourselves to be unloaded. If not, * we return a non-zero value. Right now, there isn't any reason not to allow * it. */ int _NonAppCheckUnload(void) { return 0; } int GetOrSetUpData(int id, libdata_t **appData, libthreaddata_t **threadData) { int err; libdata_t *app_data; libthreaddata_t *thread_data; NXKey_t key; NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); err = 0; thread_data = (libthreaddata_t *) NULL; /* * Attempt to get our data for the application calling us. This is where we * store whatever application-specific information we need to carry in * support of calling applications. */ app_data = (libdata_t *) get_app_data(id); if(!app_data) { /* * This application hasn't called us before; set up application AND * per-thread data. Of course, just in case a thread from this same * application is calling us simultaneously, we better lock our application * data-creation mutex. We also need to recheck for data after we acquire * the lock because WE might be that other thread that was too late to * create the data and the first thread in will have created it. */ NXLock(gLibLock); app_data = (libdata_t *) get_app_data(id); if(!app_data) { app_data = calloc(1, sizeof(libdata_t)); if(app_data) { app_data->tenbytes = malloc(10); app_data->lock = NXMutexAlloc(0, 0, &liblock); if(!app_data->tenbytes || !app_data->lock) { if(app_data->lock) NXMutexFree(app_data->lock); free(app_data->tenbytes); free(app_data); app_data = (libdata_t *) NULL; err = ENOMEM; } if(app_data) { /* * Here we burn in the application data that we were trying to get * by calling get_app_data(). Next time we call the first function, * we'll get this data we're just now setting. We also go on here to * establish the per-thread data for the calling thread, something * we'll have to do on each application thread the first time * it calls us. */ err = set_app_data(gLibId, app_data); if(err) { if(app_data->lock) NXMutexFree(app_data->lock); free(app_data->tenbytes); free(app_data); app_data = (libdata_t *) NULL; err = ENOMEM; } else { /* create key for thread-specific data... */ err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); if(err) /* (no more keys left?) */ key = -1; app_data->perthreadkey = key; } } } } NXUnlock(gLibLock); } if(app_data) { key = app_data->perthreadkey; if(key != -1 /* couldn't create a key? no thread data */ && !(err = NXKeyGetValue(key, (void **) &thread_data)) && !thread_data) { /* * Allocate the per-thread data for the calling thread. Regardless of * whether there was already application data or not, this may be the * first call by a new thread. The fact that we allocation 20 bytes on * a pointer is not very important, this just helps to demonstrate that * we can have arbitrarily complex per-thread data. */ thread_data = malloc(sizeof(libthreaddata_t)); if(thread_data) { thread_data->_errno = 0; thread_data->twentybytes = malloc(20); if(!thread_data->twentybytes) { free(thread_data); thread_data = (libthreaddata_t *) NULL; err = ENOMEM; } err = NXKeySetValue(key, thread_data); if(err) { free(thread_data->twentybytes); free(thread_data); thread_data = (libthreaddata_t *) NULL; } } } } if(appData) *appData = app_data; if(threadData) *threadData = thread_data; return err; } int DisposeLibraryData(void *data) { if(data) { void *tenbytes = ((libdata_t *) data)->tenbytes; free(tenbytes); free(data); } return 0; } void DisposeThreadData(void *data) { if(data) { void *twentybytes = ((libthreaddata_t *) data)->twentybytes; free(twentybytes); free(data); } } #else /* __NOVELL_LIBC__ */ /* For native CLib-based NLM seems we can do a bit more simple. */ #include int main(void) { /* initialize any globals here... */ /* do this if any global initializing was done SynchronizeStart(); */ ExitThread(TSR_THREAD, 0); return 0; } #endif /* __NOVELL_LIBC__ */ #else /* NETWARE */ #ifdef __POCC__ # pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ #endif #endif /* NETWARE */ davix-0.8.0/deps/curl/lib/url.c0000644000000000000000000037067414121063461014763 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_IPHLPAPI_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_SYS_UN_H #include #endif #ifndef HAVE_SOCKET #error "We can't compile without socket() support!" #endif #include #ifdef USE_LIBIDN2 #include #elif defined(USE_WIN32_IDN) /* prototype for curl_win32_idn_to_ascii() */ bool curl_win32_idn_to_ascii(const char *in, char **out); #endif /* USE_LIBIDN2 */ #include "urldata.h" #include "netrc.h" #include "formdata.h" #include "mime.h" #include "vtls/vtls.h" #include "hostip.h" #include "transfer.h" #include "sendf.h" #include "progress.h" #include "cookie.h" #include "strcase.h" #include "strerror.h" #include "escape.h" #include "strtok.h" #include "share.h" #include "content_encoding.h" #include "http_digest.h" #include "http_negotiate.h" #include "select.h" #include "multiif.h" #include "easyif.h" #include "speedcheck.h" #include "warnless.h" #include "non-ascii.h" #include "inet_pton.h" #include "getinfo.h" #include "urlapi-int.h" #include "system_win32.h" /* And now for the protocols */ #include "ftp.h" #include "dict.h" #include "telnet.h" #include "tftp.h" #include "http.h" #include "http2.h" #include "file.h" #include "curl_ldap.h" #include "vssh/ssh.h" #include "imap.h" #include "url.h" #include "connect.h" #include "inet_ntop.h" #include "http_ntlm.h" #include "curl_rtmp.h" #include "gopher.h" #include "http_proxy.h" #include "conncache.h" #include "multihandle.h" #include "dotdot.h" #include "strdup.h" #include "setopt.h" #include "altsvc.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static void conn_free(struct connectdata *conn); static unsigned int get_protocol_family(unsigned int protocol); /* Some parts of the code (e.g. chunked encoding) assume this buffer has at * more than just a few bytes to play with. Don't let it become too small or * bad things will happen. */ #if READBUFFER_SIZE < READBUFFER_MIN # error READBUFFER_SIZE is too small #endif /* * Protocol table. */ static const struct Curl_handler * const protocols[] = { #ifndef CURL_DISABLE_HTTP &Curl_handler_http, #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) &Curl_handler_https, #endif #ifndef CURL_DISABLE_FTP &Curl_handler_ftp, #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) &Curl_handler_ftps, #endif #ifndef CURL_DISABLE_TELNET &Curl_handler_telnet, #endif #ifndef CURL_DISABLE_DICT &Curl_handler_dict, #endif #ifndef CURL_DISABLE_LDAP &Curl_handler_ldap, #if !defined(CURL_DISABLE_LDAPS) && \ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) &Curl_handler_ldaps, #endif #endif #ifndef CURL_DISABLE_FILE &Curl_handler_file, #endif #ifndef CURL_DISABLE_TFTP &Curl_handler_tftp, #endif #if defined(USE_SSH) && !defined(USE_WOLFSSH) &Curl_handler_scp, #endif #if defined(USE_SSH) &Curl_handler_sftp, #endif #ifndef CURL_DISABLE_IMAP &Curl_handler_imap, #ifdef USE_SSL &Curl_handler_imaps, #endif #endif #ifndef CURL_DISABLE_POP3 &Curl_handler_pop3, #ifdef USE_SSL &Curl_handler_pop3s, #endif #endif #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ (CURL_SIZEOF_CURL_OFF_T > 4) && \ (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)) &Curl_handler_smb, #ifdef USE_SSL &Curl_handler_smbs, #endif #endif #ifndef CURL_DISABLE_SMTP &Curl_handler_smtp, #ifdef USE_SSL &Curl_handler_smtps, #endif #endif #ifndef CURL_DISABLE_RTSP &Curl_handler_rtsp, #endif #ifndef CURL_DISABLE_GOPHER &Curl_handler_gopher, #endif #ifdef USE_LIBRTMP &Curl_handler_rtmp, &Curl_handler_rtmpt, &Curl_handler_rtmpe, &Curl_handler_rtmpte, &Curl_handler_rtmps, &Curl_handler_rtmpts, #endif (struct Curl_handler *) NULL }; /* * Dummy handler for undefined protocol schemes. */ static const struct Curl_handler Curl_handler_dummy = { "", /* scheme */ ZERO_NULL, /* setup_connection */ ZERO_NULL, /* do_it */ ZERO_NULL, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ 0, /* defport */ 0, /* protocol */ PROTOPT_NONE /* flags */ }; void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; for(i = (enum dupstring)0; i < STRING_LAST; i++) { Curl_safefree(data->set.str[i]); } if(data->change.referer_alloc) { Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } data->change.referer = NULL; if(data->change.url_alloc) { Curl_safefree(data->change.url); data->change.url_alloc = FALSE; } data->change.url = NULL; Curl_mime_cleanpart(&data->set.mimepost); } /* free the URL pieces */ static void up_free(struct Curl_easy *data) { struct urlpieces *up = &data->state.up; Curl_safefree(up->scheme); Curl_safefree(up->hostname); Curl_safefree(up->port); Curl_safefree(up->user); Curl_safefree(up->password); Curl_safefree(up->options); Curl_safefree(up->path); Curl_safefree(up->query); curl_url_cleanup(data->state.uh); data->state.uh = NULL; } /* * This is the internal function curl_easy_cleanup() calls. This should * cleanup and free all resources associated with this sessionhandle. * * NOTE: if we ever add something that attempts to write to a socket or * similar here, we must ignore SIGPIPE first. It is currently only done * when curl_easy_perform() is invoked. */ CURLcode Curl_close(struct Curl_easy **datap) { struct Curl_multi *m; struct Curl_easy *data; if(!datap || !*datap) return CURLE_OK; data = *datap; *datap = NULL; Curl_expire_clear(data); /* shut off timers */ m = data->multi; if(m) /* This handle is still part of a multi handle, take care of this first and detach this handle from there. */ curl_multi_remove_handle(data->multi, data); if(data->multi_easy) { /* when curl_easy_perform() is used, it creates its own multi handle to use and this is the one */ curl_multi_cleanup(data->multi_easy); data->multi_easy = NULL; } /* Destroy the timeout list that is held in the easy handle. It is /normally/ done by curl_multi_remove_handle() but this is "just in case" */ Curl_llist_destroy(&data->state.timeoutlist, NULL); data->magic = 0; /* force a clear AFTER the possibly enforced removal from the multi handle, since that function uses the magic field! */ if(data->state.rangestringalloc) free(data->state.range); /* freed here just in case DONE wasn't called */ Curl_free_request_state(data); /* Close down all open SSL info and sessions */ Curl_ssl_close_all(data); Curl_safefree(data->state.first_host); Curl_safefree(data->state.scratch); Curl_ssl_free_certinfo(data); /* Cleanup possible redirect junk */ free(data->req.newurl); data->req.newurl = NULL; if(data->change.referer_alloc) { Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } data->change.referer = NULL; up_free(data); Curl_safefree(data->state.buffer); Curl_safefree(data->state.headerbuff); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); #ifdef USE_ALTSVC Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_cleanup(data->asi); data->asi = NULL; #endif #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) Curl_http_auth_cleanup_digest(data); #endif Curl_safefree(data->info.contenttype); Curl_safefree(data->info.wouldredirect); /* this destroys the channel and we cannot use it anymore after this */ Curl_resolver_cleanup(data->state.resolver); Curl_http2_cleanup_dependencies(data); Curl_convert_close(data); /* No longer a dirty share, if it exists */ if(data->share) { Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); data->share->dirty--; Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } #ifndef CURL_DISABLE_DOH free(data->req.doh.probe[0].serverdoh.memory); free(data->req.doh.probe[1].serverdoh.memory); curl_slist_free_all(data->req.doh.headers); #endif /* destruct wildcard structures if it is needed */ Curl_wildcard_dtor(&data->wildcard); Curl_freeset(data); free(data); return CURLE_OK; } /* * Initialize the UserDefined fields within a Curl_easy. * This may be safely called on a new or existing Curl_easy. */ CURLcode Curl_init_userdefined(struct Curl_easy *data) { struct UserDefined *set = &data->set; CURLcode result = CURLE_OK; set->out = stdout; /* default output to stdout */ set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; /* use fread as default function to read input */ set->fread_func_set = (curl_read_callback)fread; set->is_fread_set = 0; set->is_fwrite_set = 0; set->seek_func = ZERO_NULL; set->seek_client = ZERO_NULL; /* conversion callbacks for non-ASCII hosts */ set->convfromnetwork = ZERO_NULL; set->convtonetwork = ZERO_NULL; set->convfromutf8 = ZERO_NULL; set->filesize = -1; /* we don't know the size */ set->postfieldsize = -1; /* unknown size */ set->maxredirs = -1; /* allow any amount by default */ set->httpreq = HTTPREQ_GET; /* Default HTTP request */ set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ #ifndef CURL_DISABLE_FTP set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */ set->ftp_filemethod = FTPFILE_MULTICWD; #endif set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ /* Set the default size of the SSL session ID cache */ set->general_ssl.max_ssl_sessions = 5; set->proxyport = 0; set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ /* SOCKS5 proxy auth defaults to username/password + GSS-API */ set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; /* make libcurl quiet by default: */ set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ Curl_mime_initpart(&set->mimepost, data); /* * libcurl 7.10 introduced SSL verification *by default*! This needs to be * switched off unless wanted. */ set->ssl.primary.verifypeer = TRUE; set->ssl.primary.verifyhost = TRUE; #ifdef USE_TLS_SRP set->ssl.authtype = CURL_TLSAUTH_NONE; #endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by default */ set->proxy_ssl = set->ssl; set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ /* for the *protocols fields we don't use the CURLPROTO_ALL convenience define since we internally only use the lower 16 bits for the passed in bitmask to not conflict with the private bits */ set->allowed_protocols = CURLPROTO_ALL; set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* * disallow unprotected protection negotiation NEC reference implementation * seem not to follow rfc1961 section 4.3/4.4 */ set->socks5_gssapi_nec = FALSE; #endif /* Set the default CA cert bundle/path detected/specified at build time. * * If Schannel is the selected SSL backend then these locations are * ignored. We allow setting CA location for schannel only when explicitly * specified by the user via CURLOPT_CAINFO / --cacert. */ if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { #if defined(CURL_CA_BUNDLE) result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); if(result) return result; result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE); if(result) return result; #endif #if defined(CURL_CA_PATH) result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); if(result) return result; result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); if(result) return result; #endif } set->wildcard_enabled = FALSE; set->chunk_bgn = ZERO_NULL; set->chunk_end = ZERO_NULL; set->tcp_keepalive = FALSE; set->tcp_keepintvl = 60; set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; set->tcp_nodelay = TRUE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ set->buffer_size = READBUFFER_SIZE; set->upload_buffer_size = UPLOADBUFFER_DEFAULT; set->happy_eyeballs_timeout = CURL_HET_DEFAULT; set->fnmatch = ZERO_NULL; set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ set->maxage_conn = 118; set->http09_allowed = FALSE; set->httpversion = #ifdef USE_NGHTTP2 CURL_HTTP_VERSION_2TLS #else CURL_HTTP_VERSION_1_1 #endif ; Curl_http2_init_userset(set); return result; } /** * Curl_open() * * @param curl is a pointer to a sessionhandle pointer that gets set by this * function. * @return CURLcode */ CURLcode Curl_open(struct Curl_easy **curl) { CURLcode result; struct Curl_easy *data; /* Very simple start-up: alloc the struct, init it with zeroes and return */ data = calloc(1, sizeof(struct Curl_easy)); if(!data) { /* this is a very serious error */ DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); return CURLE_OUT_OF_MEMORY; } data->magic = CURLEASY_MAGIC_NUMBER; result = Curl_resolver_init(data, &data->state.resolver); if(result) { DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); free(data); return result; } /* We do some initial setup here, all those fields that can't be just 0 */ data->state.buffer = malloc(READBUFFER_SIZE + 1); if(!data->state.buffer) { DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n")); result = CURLE_OUT_OF_MEMORY; } else { data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); result = CURLE_OUT_OF_MEMORY; } else { result = Curl_init_userdefined(data); data->state.headersize = HEADERSIZE; Curl_convert_init(data); Curl_initinfo(data); /* most recent connection is not yet defined */ data->state.lastconnect = NULL; data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ } } if(result) { Curl_resolver_cleanup(data->state.resolver); free(data->state.buffer); free(data->state.headerbuff); Curl_freeset(data); free(data); data = NULL; } else *curl = data; return result; } #ifdef USE_RECV_BEFORE_SEND_WORKAROUND static void conn_reset_postponed_data(struct connectdata *conn, int num) { struct postponed_data * const psnd = &(conn->postponed[num]); if(psnd->buffer) { DEBUGASSERT(psnd->allocated_size > 0); DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); DEBUGASSERT(psnd->recv_size ? (psnd->recv_processed < psnd->recv_size) : (psnd->recv_processed == 0)); DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD); free(psnd->buffer); psnd->buffer = NULL; psnd->allocated_size = 0; psnd->recv_size = 0; psnd->recv_processed = 0; #ifdef DEBUGBUILD psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */ #endif /* DEBUGBUILD */ } else { DEBUGASSERT(psnd->allocated_size == 0); DEBUGASSERT(psnd->recv_size == 0); DEBUGASSERT(psnd->recv_processed == 0); DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD); } } static void conn_reset_all_postponed_data(struct connectdata *conn) { conn_reset_postponed_data(conn, 0); conn_reset_postponed_data(conn, 1); } #else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ /* Use "do-nothing" macro instead of function when workaround not used */ #define conn_reset_all_postponed_data(c) do {} while(0) #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ static void conn_shutdown(struct connectdata *conn) { if(!conn) return; infof(conn->data, "Closing connection %ld\n", conn->connection_id); DEBUGASSERT(conn->data); /* possible left-overs from the async name resolvers */ Curl_resolver_cancel(conn); /* close the SSL stuff before we close any sockets since they will/may write to the sockets */ Curl_ssl_close(conn, FIRSTSOCKET); Curl_ssl_close(conn, SECONDARYSOCKET); /* close possibly still open sockets */ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) Curl_closesocket(conn, conn->sock[FIRSTSOCKET]); if(CURL_SOCKET_BAD != conn->tempsock[0]) Curl_closesocket(conn, conn->tempsock[0]); if(CURL_SOCKET_BAD != conn->tempsock[1]) Curl_closesocket(conn, conn->tempsock[1]); /* unlink ourselves. this should be called last since other shutdown procedures need a valid conn->data and this may clear it. */ Curl_conncache_remove_conn(conn->data, conn, TRUE); } static void conn_free(struct connectdata *conn) { if(!conn) return; Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->conn_to_host); Curl_free_idnconverted_hostname(&conn->http_proxy.host); Curl_free_idnconverted_hostname(&conn->socks_proxy.host); Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->sasl_authzid); Curl_safefree(conn->options); Curl_safefree(conn->http_proxy.user); Curl_safefree(conn->socks_proxy.user); Curl_safefree(conn->http_proxy.passwd); Curl_safefree(conn->socks_proxy.passwd); Curl_safefree(conn->allocptr.proxyuserpwd); Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.userpwd); Curl_safefree(conn->allocptr.accept_encoding); Curl_safefree(conn->allocptr.te); Curl_safefree(conn->allocptr.rangeline); Curl_safefree(conn->allocptr.ref); Curl_safefree(conn->allocptr.host); Curl_safefree(conn->allocptr.cookiehost); Curl_safefree(conn->allocptr.rtsp_transport); Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->hostname_resolve); Curl_safefree(conn->secondaryhostname); Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ Curl_safefree(conn->connect_state); conn_reset_all_postponed_data(conn); Curl_llist_destroy(&conn->easyq, NULL); Curl_safefree(conn->localdev); Curl_free_primary_ssl_config(&conn->ssl_config); Curl_free_primary_ssl_config(&conn->proxy_ssl_config); #ifdef USE_UNIX_SOCKETS Curl_safefree(conn->unix_domain_socket); #endif #ifdef USE_SSL Curl_safefree(conn->ssl_extra); #endif free(conn); /* free all the connection oriented data */ } /* * Disconnects the given connection. Note the connection may not be the * primary connection, like when freeing room in the connection cache or * killing of a dead old connection. * * A connection needs an easy handle when closing down. We support this passed * in separately since the connection to get closed here is often already * disassociated from an easy handle. * * This function MUST NOT reset state in the Curl_easy struct if that * isn't strictly bound to the life-time of *this* particular connection. * */ CURLcode Curl_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { if(!conn) return CURLE_OK; /* this is closed and fine already */ if(!data) { DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n")); return CURLE_OK; } /* * If this connection isn't marked to force-close, leave it open if there * are other users of it */ if(CONN_INUSE(conn) && !dead_connection) { DEBUGF(infof(data, "Curl_disconnect when inuse: %zu\n", CONN_INUSE(conn))); return CURLE_OK; } if(conn->dns_entry != NULL) { Curl_resolv_unlock(data, conn->dns_entry); conn->dns_entry = NULL; } Curl_hostcache_prune(data); /* kill old DNS cache entries */ #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); #endif #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) /* Cleanup NEGOTIATE connection-related data */ Curl_http_auth_cleanup_negotiate(conn); #endif /* the protocol specific disconnect handler and conn_shutdown need a transfer for the connection! */ conn->data = data; if(conn->bits.connect_only) /* treat the connection as dead in CONNECT_ONLY situations */ dead_connection = TRUE; if(conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ conn->handler->disconnect(conn, dead_connection); conn_shutdown(conn); conn_free(conn); return CURLE_OK; } /* * This function should return TRUE if the socket is to be assumed to * be dead. Most commonly this happens when the server has closed the * connection due to inactivity. */ static bool SocketIsDead(curl_socket_t sock) { int sval; bool ret_val = TRUE; sval = SOCKET_READABLE(sock, 0); if(sval == 0) /* timeout */ ret_val = FALSE; return ret_val; } /* * IsMultiplexingPossible() * * Return a bitmask with the available multiplexing options for the given * requested connection. */ static int IsMultiplexingPossible(const struct Curl_easy *handle, const struct connectdata *conn) { int avail = 0; /* If a HTTP protocol and multiplexing is enabled */ if((conn->handler->protocol & PROTO_FAMILY_HTTP) && (!conn->bits.protoconnstart || !conn->bits.close)) { if(Curl_multiplex_wanted(handle->multi) && (handle->set.httpversion >= CURL_HTTP_VERSION_2)) /* allows HTTP/2 */ avail |= CURLPIPE_MULTIPLEX; } return avail; } #ifndef CURL_DISABLE_PROXY static bool proxy_info_matches(const struct proxy_info* data, const struct proxy_info* needle) { if((data->proxytype == needle->proxytype) && (data->port == needle->port) && Curl_safe_strcasecompare(data->host.name, needle->host.name)) return TRUE; return FALSE; } static bool socks_proxy_info_matches(const struct proxy_info* data, const struct proxy_info* needle) { if(!proxy_info_matches(data, needle)) return FALSE; /* the user information is case-sensitive or at least it is not defined as case-insensitive see https://tools.ietf.org/html/rfc3986#section-3.2.1 */ if((data->user == NULL) != (needle->user == NULL)) return FALSE; /* curl_strequal does a case insentive comparison, so do not use it here! */ if(data->user && needle->user && strcmp(data->user, needle->user) != 0) return FALSE; if((data->passwd == NULL) != (needle->passwd == NULL)) return FALSE; /* curl_strequal does a case insentive comparison, so do not use it here! */ if(data->passwd && needle->passwd && strcmp(data->passwd, needle->passwd) != 0) return FALSE; return TRUE; } #else /* disabled, won't get called */ #define proxy_info_matches(x,y) FALSE #define socks_proxy_info_matches(x,y) FALSE #endif /* A connection has to have been idle for a shorter time than 'maxage_conn' to be subject for reuse. The success rate is just too low after this. */ static bool conn_maxage(struct Curl_easy *data, struct connectdata *conn, struct curltime now) { if(!conn->data) { timediff_t idletime = Curl_timediff(now, conn->lastused); idletime /= 1000; /* integer seconds is fine */ if(idletime > data->set.maxage_conn) { infof(data, "Too old connection (%ld seconds), disconnect it\n", idletime); return TRUE; } } return FALSE; } /* * This function checks if the given connection is dead and extracts it from * the connection cache if so. * * When this is called as a Curl_conncache_foreach() callback, the connection * cache lock is held! * * Returns TRUE if the connection was dead and extracted. */ static bool extract_if_dead(struct connectdata *conn, struct Curl_easy *data) { if(!CONN_INUSE(conn) && !conn->data) { /* The check for a dead socket makes sense only if the connection isn't in use */ bool dead; struct curltime now = Curl_now(); if(conn_maxage(data, conn, now)) { dead = TRUE; } else if(conn->handler->connection_check) { /* The protocol has a special method for checking the state of the connection. Use it to check if the connection is dead. */ unsigned int state; struct Curl_easy *olddata = conn->data; conn->data = data; /* use this transfer for now */ state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD); conn->data = olddata; dead = (state & CONNRESULT_DEAD); } else { /* Use the general method for determining the death of a connection */ dead = SocketIsDead(conn->sock[FIRSTSOCKET]); } if(dead) { infof(data, "Connection %ld seems to be dead!\n", conn->connection_id); Curl_conncache_remove_conn(data, conn, FALSE); return TRUE; } } return FALSE; } struct prunedead { struct Curl_easy *data; struct connectdata *extracted; }; /* * Wrapper to use extract_if_dead() function in Curl_conncache_foreach() * */ static int call_extract_if_dead(struct connectdata *conn, void *param) { struct prunedead *p = (struct prunedead *)param; if(extract_if_dead(conn, p->data)) { /* stop the iteration here, pass back the connection that was extracted */ p->extracted = conn; return 1; } return 0; /* continue iteration */ } /* * This function scans the connection cache for half-open/dead connections, * closes and removes them. * The cleanup is done at most once per second. */ static void prune_dead_connections(struct Curl_easy *data) { struct curltime now = Curl_now(); timediff_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup); if(elapsed >= 1000L) { struct prunedead prune; prune.data = data; prune.extracted = NULL; while(Curl_conncache_foreach(data, data->state.conn_cache, &prune, call_extract_if_dead)) { /* disconnect it */ (void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE); } data->state.conn_cache->last_cleanup = now; } } /* * Given one filled in connection struct (named needle), this function should * detect if there already is one that has all the significant details * exactly the same and thus should be used instead. * * If there is a match, this function returns TRUE - and has marked the * connection as 'in-use'. It must later be called with ConnectionDone() to * return back to 'idle' (unused) state. * * The force_reuse flag is set if the connection must be used. */ static bool ConnectionExists(struct Curl_easy *data, struct connectdata *needle, struct connectdata **usethis, bool *force_reuse, bool *waitpipe) { struct connectdata *check; struct connectdata *chosen = 0; bool foundPendingCandidate = FALSE; bool canmultiplex = IsMultiplexingPossible(data, needle); struct connectbundle *bundle; const char *hostbundle; #ifdef USE_NTLM bool wantNTLMhttp = ((data->state.authhost.want & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && (needle->handler->protocol & PROTO_FAMILY_HTTP)); bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd && ((data->state.authproxy.want & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && (needle->handler->protocol & PROTO_FAMILY_HTTP))); #endif *force_reuse = FALSE; *waitpipe = FALSE; /* Look up the bundle with all the connections to this particular host. Locks the connection cache, beware of early returns! */ bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache, &hostbundle); if(bundle) { /* Max pipe length is zero (unlimited) for multiplexed connections */ struct curl_llist_element *curr; infof(data, "Found bundle for host %s: %p [%s]\n", hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ? "can multiplex" : "serially")); /* We can't multiplex if we don't know anything about the server */ if(canmultiplex) { if(bundle->multiuse == BUNDLE_UNKNOWN) { if(data->set.pipewait) { infof(data, "Server doesn't support multiplex yet, wait\n"); *waitpipe = TRUE; Curl_conncache_unlock(data); return FALSE; /* no re-use */ } infof(data, "Server doesn't support multiplex (yet)\n"); canmultiplex = FALSE; } if((bundle->multiuse == BUNDLE_MULTIPLEX) && !Curl_multiplex_wanted(data->multi)) { infof(data, "Could multiplex, but not asked to!\n"); canmultiplex = FALSE; } if(bundle->multiuse == BUNDLE_NO_MULTIUSE) { infof(data, "Can not multiplex, even if we wanted to!\n"); canmultiplex = FALSE; } } curr = bundle->conn_list.head; while(curr) { bool match = FALSE; size_t multiplexed = 0; /* * Note that if we use a HTTP proxy in normal mode (no tunneling), we * check connections to that proxy and not to the actual remote server. */ check = curr->ptr; curr = curr->next; if(check->bits.connect_only || check->bits.close) /* connect-only or to-be-closed connections will not be reused */ continue; if(bundle->multiuse == BUNDLE_MULTIPLEX) multiplexed = CONN_INUSE(check); if(canmultiplex) { ; } else { if(multiplexed) { /* can only happen within multi handles, and means that another easy handle is using this connection */ continue; } if(Curl_resolver_asynch()) { /* ip_addr_str[0] is NUL only if the resolving of the name hasn't completed yet and until then we don't re-use this connection */ if(!check->ip_addr_str[0]) { infof(data, "Connection #%ld is still name resolving, can't reuse\n", check->connection_id); continue; } } if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) { foundPendingCandidate = TRUE; /* Don't pick a connection that hasn't connected yet */ infof(data, "Connection #%ld isn't open enough, can't reuse\n", check->connection_id); continue; } } #ifdef USE_UNIX_SOCKETS if(needle->unix_domain_socket) { if(!check->unix_domain_socket) continue; if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) continue; if(needle->abstract_unix_socket != check->abstract_unix_socket) continue; } else if(check->unix_domain_socket) continue; #endif if((needle->handler->flags&PROTOPT_SSL) != (check->handler->flags&PROTOPT_SSL)) /* don't do mixed SSL and non-SSL connections */ if(get_protocol_family(check->handler->protocol) != needle->handler->protocol || !check->tls_upgraded) /* except protocols that have been upgraded via TLS */ continue; if(needle->bits.httpproxy != check->bits.httpproxy || needle->bits.socksproxy != check->bits.socksproxy) continue; if(needle->bits.socksproxy && !socks_proxy_info_matches(&needle->socks_proxy, &check->socks_proxy)) continue; if(needle->bits.conn_to_host != check->bits.conn_to_host) /* don't mix connections that use the "connect to host" feature and * connections that don't use this feature */ continue; if(needle->bits.conn_to_port != check->bits.conn_to_port) /* don't mix connections that use the "connect to port" feature and * connections that don't use this feature */ continue; if(needle->bits.httpproxy) { if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) continue; if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy) continue; if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) { /* use https proxy */ if(needle->handler->flags&PROTOPT_SSL) { /* use double layer ssl */ if(!Curl_ssl_config_matches(&needle->proxy_ssl_config, &check->proxy_ssl_config)) continue; if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete) continue; } else { if(!Curl_ssl_config_matches(&needle->ssl_config, &check->ssl_config)) continue; if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) continue; } } } DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data)); if(!canmultiplex && check->data) /* this request can't be multiplexed but the checked connection is already in use so we skip it */ continue; if(check->data && (check->data->multi != needle->data->multi)) /* this could be subject for multiplex use, but only if they belong to * the same multi handle */ continue; if(needle->localdev || needle->localport) { /* If we are bound to a specific local end (IP+port), we must not re-use a random other one, although if we didn't ask for a particular one we can reuse one that was bound. This comparison is a bit rough and too strict. Since the input parameters can be specified in numerous ways and still end up the same it would take a lot of processing to make it really accurate. Instead, this matching will assume that re-uses of bound connections will most likely also re-use the exact same binding parameters and missing out a few edge cases shouldn't hurt anyone very much. */ if((check->localport != needle->localport) || (check->localportrange != needle->localportrange) || (needle->localdev && (!check->localdev || strcmp(check->localdev, needle->localdev)))) continue; } if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ if(strcmp(needle->user, check->user) || strcmp(needle->passwd, check->passwd)) { /* one of them was different */ continue; } } if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || needle->bits.tunnel_proxy) { /* The requested connection does not use a HTTP proxy or it uses SSL or it is a non-SSL protocol tunneled or it is a non-SSL protocol which is allowed to be upgraded via TLS */ if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && (!needle->bits.conn_to_host || strcasecompare( needle->conn_to_host.name, check->conn_to_host.name)) && (!needle->bits.conn_to_port || needle->conn_to_port == check->conn_to_port) && strcasecompare(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { /* The schemes match or the protocol family is the same and the previous connection was TLS upgraded, and the hostname and host port match */ if(needle->handler->flags & PROTOPT_SSL) { /* This is a SSL connection so verify that we're using the same SSL options as well */ if(!Curl_ssl_config_matches(&needle->ssl_config, &check->ssl_config)) { DEBUGF(infof(data, "Connection #%ld has different SSL parameters, " "can't reuse\n", check->connection_id)); continue; } if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { foundPendingCandidate = TRUE; DEBUGF(infof(data, "Connection #%ld has not started SSL connect, " "can't reuse\n", check->connection_id)); continue; } } match = TRUE; } } else { /* The requested connection is using the same HTTP proxy in normal mode (no tunneling) */ match = TRUE; } if(match) { #if defined(USE_NTLM) /* If we are looking for an HTTP+NTLM connection, check if this is already authenticating with the right credentials. If not, keep looking so that we can reuse NTLM connections if possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { if(strcmp(needle->user, check->user) || strcmp(needle->passwd, check->passwd)) { /* we prefer a credential match, but this is at least a connection that can be reused and "upgraded" to NTLM */ if(check->http_ntlm_state == NTLMSTATE_NONE) chosen = check; continue; } } else if(check->http_ntlm_state != NTLMSTATE_NONE) { /* Connection is using NTLM auth but we don't want NTLM */ continue; } /* Same for Proxy NTLM authentication */ if(wantProxyNTLMhttp) { /* Both check->http_proxy.user and check->http_proxy.passwd can be * NULL */ if(!check->http_proxy.user || !check->http_proxy.passwd) continue; if(strcmp(needle->http_proxy.user, check->http_proxy.user) || strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) continue; } else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { /* Proxy connection is using NTLM auth but we don't want NTLM */ continue; } if(wantNTLMhttp || wantProxyNTLMhttp) { /* Credentials are already checked, we can use this connection */ chosen = check; if((wantNTLMhttp && (check->http_ntlm_state != NTLMSTATE_NONE)) || (wantProxyNTLMhttp && (check->proxy_ntlm_state != NTLMSTATE_NONE))) { /* We must use this connection, no other */ *force_reuse = TRUE; break; } /* Continue look up for a better connection */ continue; } #endif if(canmultiplex) { /* We can multiplex if we want to. Let's continue looking for the optimal connection to use. */ if(!multiplexed) { /* We have the optimal connection. Let's stop looking. */ chosen = check; break; } #ifdef USE_NGHTTP2 /* If multiplexed, make sure we don't go over concurrency limit */ if(check->bits.multiplex) { /* Multiplexed connections can only be HTTP/2 for now */ struct http_conn *httpc = &check->proto.httpc; if(multiplexed >= httpc->settings.max_concurrent_streams) { infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n", multiplexed); continue; } else if(multiplexed >= Curl_multi_max_concurrent_streams(needle->data->multi)) { infof(data, "client side MAX_CONCURRENT_STREAMS reached" ", skip (%zu)\n", multiplexed); continue; } } #endif /* When not multiplexed, we have a match here! */ chosen = check; infof(data, "Multiplexed connection found!\n"); break; } else { /* We have found a connection. Let's stop searching. */ chosen = check; break; } } } } if(chosen) { /* mark it as used before releasing the lock */ chosen->data = data; /* own it! */ Curl_conncache_unlock(data); *usethis = chosen; return TRUE; /* yes, we found one to use! */ } Curl_conncache_unlock(data); if(foundPendingCandidate && data->set.pipewait) { infof(data, "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n"); *waitpipe = TRUE; } return FALSE; /* no matching connecting exists */ } /* * verboseconnect() displays verbose information after a connect */ #ifndef CURL_DISABLE_VERBOSE_STRINGS void Curl_verboseconnect(struct connectdata *conn) { if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); } #endif /* * Helpers for IDNA conversions. */ bool Curl_is_ASCII_name(const char *hostname) { /* get an UNSIGNED local version of the pointer */ const unsigned char *ch = (const unsigned char *)hostname; if(!hostname) /* bad input, consider it ASCII! */ return TRUE; while(*ch) { if(*ch++ & 0x80) return FALSE; } return TRUE; } /* * Strip single trailing dot in the hostname, * primarily for SNI and http host header. */ static void strip_trailing_dot(struct hostname *host) { size_t len; if(!host || !host->name) return; len = strlen(host->name); if(len && (host->name[len-1] == '.')) host->name[len-1] = 0; } /* * Perform any necessary IDN conversion of hostname */ CURLcode Curl_idnconvert_hostname(struct connectdata *conn, struct hostname *host) { struct Curl_easy *data = conn->data; #ifndef USE_LIBIDN2 (void)data; (void)conn; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) (void)conn; #endif /* set the name we use to display the host name */ host->dispname = host->name; /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!Curl_is_ASCII_name(host->name)) { #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; #if IDN2_VERSION_NUMBER >= 0x00140000 /* IDN2_NFC_INPUT: Normalize input string using normalization form C. IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional processing. */ int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL; #else int flags = IDN2_NFC_INPUT; #endif int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags); if(rc == IDN2_OK) { host->encalloc = (char *)ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } else { failf(data, "Failed to convert %s to ACE; %s\n", host->name, idn2_strerror(rc)); return CURLE_URL_MALFORMAT; } } #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { host->encalloc = ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } else { char buffer[STRERROR_LEN]; failf(data, "Failed to convert %s to ACE; %s\n", host->name, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); return CURLE_URL_MALFORMAT; } #else infof(data, "IDN support not present, can't parse Unicode domains\n"); #endif } return CURLE_OK; } /* * Frees data allocated by idnconvert_hostname() */ void Curl_free_idnconverted_hostname(struct hostname *host) { #if defined(USE_LIBIDN2) if(host->encalloc) { idn2_free(host->encalloc); /* must be freed with idn2_free() since this was allocated by libidn */ host->encalloc = NULL; } #elif defined(USE_WIN32_IDN) free(host->encalloc); /* must be freed with free() since this was allocated by curl_win32_idn_to_ascii */ host->encalloc = NULL; #else (void)host; #endif } /* * Allocate and initialize a new connectdata object. */ static struct connectdata *allocate_conn(struct Curl_easy *data) { struct connectdata *conn = calloc(1, sizeof(struct connectdata)); if(!conn) return NULL; #ifdef USE_SSL /* The SSL backend-specific data (ssl_backend_data) objects are allocated as a separate array to ensure suitable alignment. Note that these backend pointers can be swapped by vtls (eg ssl backend data becomes proxy backend data). */ { size_t sslsize = Curl_ssl->sizeof_ssl_backend_data; char *ssl = calloc(4, sslsize); if(!ssl) { free(conn); return NULL; } conn->ssl_extra = ssl; conn->ssl[0].backend = (void *)ssl; conn->ssl[1].backend = (void *)(ssl + sslsize); conn->proxy_ssl[0].backend = (void *)(ssl + 2 * sslsize); conn->proxy_ssl[1].backend = (void *)(ssl + 3 * sslsize); } #endif conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined already from start to avoid NULL situations and checks */ /* and we setup a few fields in case we end up actually using this struct */ conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->tempsock[0] = CURL_SOCKET_BAD; /* no file descriptor */ conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown at this point */ #if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ #endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */ /* Default protocol-independent behavior doesn't support persistent connections, so we set this to force-close. Protocols that support this need to set this to FALSE in their "curl_do" functions. */ connclose(conn, "Default to force-close"); /* Store creation time to help future close decision making */ conn->created = Curl_now(); /* Store current time to give a baseline to keepalive connection times. */ conn->keepalive = Curl_now(); /* Store off the configured connection upkeep time. */ conn->upkeep_interval_ms = data->set.upkeep_interval_ms; conn->data = data; /* Setup the association between this connection and the Curl_easy */ conn->http_proxy.proxytype = data->set.proxytype; conn->socks_proxy.proxytype = CURLPROXY_SOCKS4; #if !defined(CURL_DISABLE_PROXY) /* note that these two proxy bits are now just on what looks to be requested, they may be altered down the road */ conn->bits.proxy = (data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) ? TRUE : FALSE; conn->bits.httpproxy = (conn->bits.proxy && (conn->http_proxy.proxytype == CURLPROXY_HTTP || conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 || conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ? TRUE : FALSE; conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy) ? TRUE : FALSE; if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) { conn->bits.proxy = TRUE; conn->bits.socksproxy = TRUE; } conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE; #ifndef CURL_DISABLE_FTP conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; #endif conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; conn->proxy_ssl_config.verifystatus = data->set.proxy_ssl.primary.verifystatus; conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; conn->ip_version = data->set.ipver; conn->bits.connect_only = data->set.connect_only; conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; #endif /* Initialize the easy handle list */ Curl_llist_init(&conn->easyq, NULL); #ifdef HAVE_GSSAPI conn->data_prot = PROT_CLEAR; #endif /* Store the local bind parameters that will be used for this connection */ if(data->set.str[STRING_DEVICE]) { conn->localdev = strdup(data->set.str[STRING_DEVICE]); if(!conn->localdev) goto error; } conn->localportrange = data->set.localportrange; conn->localport = data->set.localport; /* the close socket stuff needs to be copied to the connection struct as it may live on without (this specific) Curl_easy */ conn->fclosesocket = data->set.fclosesocket; conn->closesocket_client = data->set.closesocket_client; conn->lastused = Curl_now(); /* used now */ return conn; error: Curl_llist_destroy(&conn->easyq, NULL); free(conn->localdev); #ifdef USE_SSL free(conn->ssl_extra); #endif free(conn); return NULL; } /* returns the handler if the given scheme is built-in */ const struct Curl_handler *Curl_builtin_scheme(const char *scheme) { const struct Curl_handler * const *pp; const struct Curl_handler *p; /* Scan protocol handler table and match against 'scheme'. The handler may be changed later when the protocol specific setup function is called. */ for(pp = protocols; (p = *pp) != NULL; pp++) if(strcasecompare(p->scheme, scheme)) /* Protocol found in table. Check if allowed */ return p; return NULL; /* not found */ } static CURLcode findprotocol(struct Curl_easy *data, struct connectdata *conn, const char *protostr) { const struct Curl_handler *p = Curl_builtin_scheme(protostr); if(p && /* Protocol found in table. Check if allowed */ (data->set.allowed_protocols & p->protocol)) { /* it is allowed for "normal" request, now do an extra check if this is the result of a redirect */ if(data->state.this_is_a_follow && !(data->set.redir_protocols & p->protocol)) /* nope, get out */ ; else { /* Perform setup complement if some. */ conn->handler = conn->given = p; /* 'port' and 'remote_port' are set in setup_connection_internals() */ return CURLE_OK; } } /* The protocol was not found in the table, but we don't have to assign it to anything since it is already assigned to a dummy-struct in the create_conn() function when the connectdata struct is allocated. */ failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME, protostr); return CURLE_UNSUPPORTED_PROTOCOL; } CURLcode Curl_uc_to_curlcode(CURLUcode uc) { switch(uc) { default: return CURLE_URL_MALFORMAT; case CURLUE_UNSUPPORTED_SCHEME: return CURLE_UNSUPPORTED_PROTOCOL; case CURLUE_OUT_OF_MEMORY: return CURLE_OUT_OF_MEMORY; case CURLUE_USER_NOT_ALLOWED: return CURLE_LOGIN_DENIED; } } /* * If the URL was set with an IPv6 numerical address with a zone id part, set * the scope_id based on that! */ static void zonefrom_url(CURLU *uh, struct connectdata *conn) { char *zoneid; CURLUcode uc; uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0); if(!uc && zoneid) { char *endp; unsigned long scope = strtoul(zoneid, &endp, 10); if(!*endp && (scope < UINT_MAX)) /* A plain number, use it directly as a scope id. */ conn->scope_id = (unsigned int)scope; #if defined(HAVE_IF_NAMETOINDEX) else { #elif defined(WIN32) else if(Curl_if_nametoindex) { #endif #if defined(HAVE_IF_NAMETOINDEX) || defined(WIN32) /* Zone identifier is not numeric */ unsigned int scopeidx = 0; #if defined(WIN32) scopeidx = Curl_if_nametoindex(zoneid); #else scopeidx = if_nametoindex(zoneid); #endif if(!scopeidx) infof(conn->data, "Invalid zoneid: %s; %s\n", zoneid, strerror(errno)); else conn->scope_id = scopeidx; } #endif /* HAVE_IF_NAMETOINDEX || WIN32 */ free(zoneid); } } /* * Parse URL and fill in the relevant members of the connection struct. */ static CURLcode parseurlandfillconn(struct Curl_easy *data, struct connectdata *conn) { CURLcode result; CURLU *uh; CURLUcode uc; char *hostname; up_free(data); /* cleanup previous leftovers first */ /* parse the URL */ if(data->set.uh) { uh = data->state.uh = curl_url_dup(data->set.uh); } else { uh = data->state.uh = curl_url(); } if(!uh) return CURLE_OUT_OF_MEMORY; if(data->set.str[STRING_DEFAULT_PROTOCOL] && !Curl_is_absolute_url(data->change.url, NULL, MAX_SCHEME_LEN)) { char *url; if(data->change.url_alloc) free(data->change.url); url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], data->change.url); if(!url) return CURLE_OUT_OF_MEMORY; data->change.url = url; data->change.url_alloc = TRUE; } if(!data->set.uh) { char *newurl; uc = curl_url_set(uh, CURLUPART_URL, data->change.url, CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME | (data->set.disallow_username_in_url ? CURLU_DISALLOW_USER : 0) | (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); if(uc) { DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url)); return Curl_uc_to_curlcode(uc); } /* after it was parsed, get the generated normalized version */ uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0); if(uc) return Curl_uc_to_curlcode(uc); if(data->change.url_alloc) free(data->change.url); data->change.url = newurl; data->change.url_alloc = TRUE; } uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0); if(uc) return Curl_uc_to_curlcode(uc); result = findprotocol(data, conn, data->state.up.scheme); if(result) return result; uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, CURLU_URLDECODE); if(!uc) { conn->user = strdup(data->state.up.user); if(!conn->user) return CURLE_OUT_OF_MEMORY; conn->bits.user_passwd = TRUE; } else if(uc != CURLUE_NO_USER) return Curl_uc_to_curlcode(uc); uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, CURLU_URLDECODE); if(!uc) { conn->passwd = strdup(data->state.up.password); if(!conn->passwd) return CURLE_OUT_OF_MEMORY; conn->bits.user_passwd = TRUE; } else if(uc != CURLUE_NO_PASSWORD) return Curl_uc_to_curlcode(uc); uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options, CURLU_URLDECODE); if(!uc) { conn->options = strdup(data->state.up.options); if(!conn->options) return CURLE_OUT_OF_MEMORY; } else if(uc != CURLUE_NO_OPTIONS) return Curl_uc_to_curlcode(uc); uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0); if(uc) { if(!strcasecompare("file", data->state.up.scheme)) return CURLE_OUT_OF_MEMORY; } uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, 0); if(uc) return Curl_uc_to_curlcode(uc); uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port, CURLU_DEFAULT_PORT); if(uc) { if(!strcasecompare("file", data->state.up.scheme)) return CURLE_OUT_OF_MEMORY; } else { unsigned long port = strtoul(data->state.up.port, NULL, 10); conn->port = conn->remote_port = curlx_ultous(port); } (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); hostname = data->state.up.hostname; if(hostname && hostname[0] == '[') { /* This looks like an IPv6 address literal. See if there is an address scope. */ size_t hlen; conn->bits.ipv6_ip = TRUE; /* cut off the brackets! */ hostname++; hlen = strlen(hostname); hostname[hlen - 1] = 0; zonefrom_url(uh, conn); } /* make sure the connect struct gets its own copy of the host name */ conn->host.rawalloc = strdup(hostname ? hostname : ""); if(!conn->host.rawalloc) return CURLE_OUT_OF_MEMORY; conn->host.name = conn->host.rawalloc; if(data->set.scope_id) /* Override any scope that was set above. */ conn->scope_id = data->set.scope_id; return CURLE_OK; } /* * If we're doing a resumed transfer, we need to setup our stuff * properly. */ static CURLcode setup_range(struct Curl_easy *data) { struct UrlState *s = &data->state; s->resume_from = data->set.set_resume_from; if(s->resume_from || data->set.str[STRING_SET_RANGE]) { if(s->rangestringalloc) free(s->range); if(s->resume_from) s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from); else s->range = strdup(data->set.str[STRING_SET_RANGE]); s->rangestringalloc = (s->range) ? TRUE : FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; /* tell ourselves to fetch this range */ s->use_range = TRUE; /* enable range download */ } else s->use_range = FALSE; /* disable range download */ return CURLE_OK; } /* * setup_connection_internals() - * * Setup connection internals specific to the requested protocol in the * Curl_easy. This is inited and setup before the connection is made but * is about the particular protocol that is to be used. * * This MUST get called after proxy magic has been figured out. */ static CURLcode setup_connection_internals(struct connectdata *conn) { const struct Curl_handler * p; CURLcode result; /* Perform setup complement if some. */ p = conn->handler; if(p->setup_connection) { result = (*p->setup_connection)(conn); if(result) return result; p = conn->handler; /* May have changed. */ } if(conn->port < 0) /* we check for -1 here since if proxy was detected already, this was very likely already set to the proxy port */ conn->port = p->defport; return CURLE_OK; } /* * Curl_free_request_state() should free temp data that was allocated in the * Curl_easy for this single request. */ void Curl_free_request_state(struct Curl_easy *data) { Curl_safefree(data->req.protop); Curl_safefree(data->req.newurl); #ifndef CURL_DISABLE_DOH Curl_close(&data->req.doh.probe[0].easy); Curl_close(&data->req.doh.probe[1].easy); #endif } #ifndef CURL_DISABLE_PROXY /**************************************************************** * Checks if the host is in the noproxy list. returns true if it matches * and therefore the proxy should NOT be used. ****************************************************************/ static bool check_noproxy(const char *name, const char *no_proxy) { /* no_proxy=domain1.dom,host.domain2.dom * (a comma-separated list of hosts which should * not be proxied, or an asterisk to override * all proxy variables) */ if(no_proxy && no_proxy[0]) { size_t tok_start; size_t tok_end; const char *separator = ", "; size_t no_proxy_len; size_t namelen; char *endptr; if(strcasecompare("*", no_proxy)) { return TRUE; } /* NO_PROXY was specified and it wasn't just an asterisk */ no_proxy_len = strlen(no_proxy); if(name[0] == '[') { /* IPv6 numerical address */ endptr = strchr(name, ']'); if(!endptr) return FALSE; name++; namelen = endptr - name; } else namelen = strlen(name); for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { while(tok_start < no_proxy_len && strchr(separator, no_proxy[tok_start]) != NULL) { /* Look for the beginning of the token. */ ++tok_start; } if(tok_start == no_proxy_len) break; /* It was all trailing separator chars, no more tokens. */ for(tok_end = tok_start; tok_end < no_proxy_len && strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) /* Look for the end of the token. */ ; /* To match previous behaviour, where it was necessary to specify * ".local.com" to prevent matching "notlocal.com", we will leave * the '.' off. */ if(no_proxy[tok_start] == '.') ++tok_start; if((tok_end - tok_start) <= namelen) { /* Match the last part of the name to the domain we are checking. */ const char *checkn = name + namelen - (tok_end - tok_start); if(strncasecompare(no_proxy + tok_start, checkn, tok_end - tok_start)) { if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { /* We either have an exact match, or the previous character is a . * so it is within the same domain, so no proxy for this host. */ return TRUE; } } } /* if((tok_end - tok_start) <= namelen) */ } /* for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) */ } /* NO_PROXY was specified and it wasn't just an asterisk */ return FALSE; } #ifndef CURL_DISABLE_HTTP /**************************************************************** * Detect what (if any) proxy to use. Remember that this selects a host * name and is not limited to HTTP proxies only. * The returned pointer must be freed by the caller (unless NULL) ****************************************************************/ static char *detect_proxy(struct connectdata *conn) { char *proxy = NULL; /* If proxy was not specified, we check for default proxy environment * variables, to enable i.e Lynx compliance: * * http_proxy=http://some.server.dom:port/ * https_proxy=http://some.server.dom:port/ * ftp_proxy=http://some.server.dom:port/ * no_proxy=domain1.dom,host.domain2.dom * (a comma-separated list of hosts which should * not be proxied, or an asterisk to override * all proxy variables) * all_proxy=http://some.server.dom:port/ * (seems to exist for the CERN www lib. Probably * the first to check for.) * * For compatibility, the all-uppercase versions of these variables are * checked if the lowercase versions don't exist. */ char proxy_env[128]; const char *protop = conn->handler->scheme; char *envp = proxy_env; char *prox; /* Now, build _proxy and check for such a one to use */ while(*protop) *envp++ = (char)tolower((int)*protop++); /* append _proxy */ strcpy(envp, "_proxy"); /* read the protocol proxy: */ prox = curl_getenv(proxy_env); /* * We don't try the uppercase version of HTTP_PROXY because of * security reasons: * * When curl is used in a webserver application * environment (cgi or php), this environment variable can * be controlled by the web server user by setting the * http header 'Proxy:' to some value. * * This can cause 'internal' http/ftp requests to be * arbitrarily redirected by any external attacker. */ if(!prox && !strcasecompare("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); prox = curl_getenv(proxy_env); } envp = proxy_env; if(prox) { proxy = prox; /* use this */ } else { envp = (char *)"all_proxy"; proxy = curl_getenv(envp); /* default proxy to use */ if(!proxy) { envp = (char *)"ALL_PROXY"; proxy = curl_getenv(envp); } } if(proxy) infof(conn->data, "Uses proxy env variable %s == '%s'\n", envp, proxy); return proxy; } #endif /* CURL_DISABLE_HTTP */ /* * If this is supposed to use a proxy, we need to figure out the proxy * host name, so that we can re-use an existing connection * that may exist registered to the same proxy host. */ static CURLcode parse_proxy(struct Curl_easy *data, struct connectdata *conn, char *proxy, curl_proxytype proxytype) { char *portptr = NULL; long port = -1; char *proxyuser = NULL; char *proxypasswd = NULL; char *host; bool sockstype; CURLUcode uc; struct proxy_info *proxyinfo; CURLU *uhp = curl_url(); CURLcode result = CURLE_OK; char *scheme = NULL; /* When parsing the proxy, allowing non-supported schemes since we have these made up ones for proxies. Guess scheme for URLs without it. */ uc = curl_url_set(uhp, CURLUPART_URL, proxy, CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME); if(!uc) { /* parsed okay as a URL */ uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0); if(uc) { result = CURLE_OUT_OF_MEMORY; goto error; } if(strcasecompare("https", scheme)) proxytype = CURLPROXY_HTTPS; else if(strcasecompare("socks5h", scheme)) proxytype = CURLPROXY_SOCKS5_HOSTNAME; else if(strcasecompare("socks5", scheme)) proxytype = CURLPROXY_SOCKS5; else if(strcasecompare("socks4a", scheme)) proxytype = CURLPROXY_SOCKS4A; else if(strcasecompare("socks4", scheme) || strcasecompare("socks", scheme)) proxytype = CURLPROXY_SOCKS4; else if(strcasecompare("http", scheme)) ; /* leave it as HTTP or HTTP/1.0 */ else { /* Any other xxx:// reject! */ failf(data, "Unsupported proxy scheme for \'%s\'", proxy); result = CURLE_COULDNT_CONNECT; goto error; } } else { failf(data, "Unsupported proxy syntax in \'%s\'", proxy); result = CURLE_COULDNT_RESOLVE_PROXY; goto error; } #ifdef USE_SSL if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY)) #endif if(proxytype == CURLPROXY_HTTPS) { failf(data, "Unsupported proxy \'%s\', libcurl is built without the " "HTTPS-proxy support.", proxy); result = CURLE_NOT_BUILT_IN; goto error; } sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || proxytype == CURLPROXY_SOCKS5 || proxytype == CURLPROXY_SOCKS4A || proxytype == CURLPROXY_SOCKS4; proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy; proxyinfo->proxytype = proxytype; /* Is there a username and password given in this proxy url? */ curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE); curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE); if(proxyuser || proxypasswd) { Curl_safefree(proxyinfo->user); proxyinfo->user = proxyuser; Curl_safefree(proxyinfo->passwd); if(!proxypasswd) { proxypasswd = strdup(""); if(!proxypasswd) { result = CURLE_OUT_OF_MEMORY; goto error; } } proxyinfo->passwd = proxypasswd; conn->bits.proxy_user_passwd = TRUE; /* enable it */ } curl_url_get(uhp, CURLUPART_PORT, &portptr, 0); if(portptr) { port = strtol(portptr, NULL, 10); free(portptr); } else { if(data->set.proxyport) /* None given in the proxy string, then get the default one if it is given */ port = data->set.proxyport; else { if(proxytype == CURLPROXY_HTTPS) port = CURL_DEFAULT_HTTPS_PROXY_PORT; else port = CURL_DEFAULT_PROXY_PORT; } } if(port >= 0) { proxyinfo->port = port; if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc) conn->port = port; } /* now, clone the proxy host name */ uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE); if(uc) { result = CURLE_OUT_OF_MEMORY; goto error; } Curl_safefree(proxyinfo->host.rawalloc); proxyinfo->host.rawalloc = host; if(host[0] == '[') { /* this is a numerical IPv6, strip off the brackets */ size_t len = strlen(host); host[len-1] = 0; /* clear the trailing bracket */ host++; zonefrom_url(uhp, conn); } proxyinfo->host.name = host; error: free(scheme); curl_url_cleanup(uhp); return result; } /* * Extract the user and password from the authentication string */ static CURLcode parse_proxy_auth(struct Curl_easy *data, struct connectdata *conn) { char proxyuser[MAX_CURL_USER_LENGTH]=""; char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; CURLcode result; if(data->set.str[STRING_PROXYUSERNAME] != NULL) { strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], MAX_CURL_USER_LENGTH); proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/ } if(data->set.str[STRING_PROXYPASSWORD] != NULL) { strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD], MAX_CURL_PASSWORD_LENGTH); proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ } result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, FALSE); if(!result) result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, NULL, FALSE); return result; } /* create_conn helper to parse and init proxy values. to be called after unix socket init but before any proxy vars are evaluated. */ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn) { char *proxy = NULL; char *socksproxy = NULL; char *no_proxy = NULL; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; /************************************************************* * Extract the user and password from the authentication string *************************************************************/ if(conn->bits.proxy_user_passwd) { result = parse_proxy_auth(data, conn); if(result) goto out; } /************************************************************* * Detect what (if any) proxy to use *************************************************************/ if(data->set.str[STRING_PROXY]) { proxy = strdup(data->set.str[STRING_PROXY]); /* if global proxy is set, this is it */ if(NULL == proxy) { failf(data, "memory shortage"); result = CURLE_OUT_OF_MEMORY; goto out; } } if(data->set.str[STRING_PRE_PROXY]) { socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); /* if global socks proxy is set, this is it */ if(NULL == socksproxy) { failf(data, "memory shortage"); result = CURLE_OUT_OF_MEMORY; goto out; } } if(!data->set.str[STRING_NOPROXY]) { const char *p = "no_proxy"; no_proxy = curl_getenv(p); if(!no_proxy) { p = "NO_PROXY"; no_proxy = curl_getenv(p); } if(no_proxy) { infof(conn->data, "Uses proxy env variable %s == '%s'\n", p, no_proxy); } } if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? data->set.str[STRING_NOPROXY] : no_proxy)) { Curl_safefree(proxy); Curl_safefree(socksproxy); } #ifndef CURL_DISABLE_HTTP else if(!proxy && !socksproxy) /* if the host is not in the noproxy list, detect proxy. */ proxy = detect_proxy(conn); #endif /* CURL_DISABLE_HTTP */ Curl_safefree(no_proxy); #ifdef USE_UNIX_SOCKETS /* For the time being do not mix proxy and unix domain sockets. See #1274 */ if(proxy && conn->unix_domain_socket) { free(proxy); proxy = NULL; } #endif if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { free(proxy); /* Don't bother with an empty proxy string or if the protocol doesn't work with network */ proxy = NULL; } if(socksproxy && (!*socksproxy || (conn->handler->flags & PROTOPT_NONETWORK))) { free(socksproxy); /* Don't bother with an empty socks proxy string or if the protocol doesn't work with network */ socksproxy = NULL; } /*********************************************************************** * If this is supposed to use a proxy, we need to figure out the proxy host * name, proxy type and port number, so that we can re-use an existing * connection that may exist registered to the same proxy host. ***********************************************************************/ if(proxy || socksproxy) { if(proxy) { result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); Curl_safefree(proxy); /* parse_proxy copies the proxy string */ if(result) goto out; } if(socksproxy) { result = parse_proxy(data, conn, socksproxy, conn->socks_proxy.proxytype); /* parse_proxy copies the socks proxy string */ Curl_safefree(socksproxy); if(result) goto out; } if(conn->http_proxy.host.rawalloc) { #ifdef CURL_DISABLE_HTTP /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ result = CURLE_UNSUPPORTED_PROTOCOL; goto out; #else /* force this connection's protocol to become HTTP if compatible */ if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) { if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) && !conn->bits.tunnel_proxy) conn->handler = &Curl_handler_http; else /* if not converting to HTTP over the proxy, enforce tunneling */ conn->bits.tunnel_proxy = TRUE; } conn->bits.httpproxy = TRUE; #endif } else { conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ } if(conn->socks_proxy.host.rawalloc) { if(!conn->http_proxy.host.rawalloc) { /* once a socks proxy */ if(!conn->socks_proxy.user) { conn->socks_proxy.user = conn->http_proxy.user; conn->http_proxy.user = NULL; Curl_safefree(conn->socks_proxy.passwd); conn->socks_proxy.passwd = conn->http_proxy.passwd; conn->http_proxy.passwd = NULL; } } conn->bits.socksproxy = TRUE; } else conn->bits.socksproxy = FALSE; /* not a socks proxy */ } else { conn->bits.socksproxy = FALSE; conn->bits.httpproxy = FALSE; } conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; if(!conn->bits.proxy) { /* we aren't using the proxy after all... */ conn->bits.proxy = FALSE; conn->bits.httpproxy = FALSE; conn->bits.socksproxy = FALSE; conn->bits.proxy_user_passwd = FALSE; conn->bits.tunnel_proxy = FALSE; } out: free(socksproxy); free(proxy); return result; } #endif /* CURL_DISABLE_PROXY */ /* * Curl_parse_login_details() * * This is used to parse a login string for user name, password and options in * the following formats: * * user * user:password * user:password;options * user;options * user;options:password * :password * :password;options * ;options * ;options:password * * Parameters: * * login [in] - The login string. * len [in] - The length of the login string. * userp [in/out] - The address where a pointer to newly allocated memory * holding the user will be stored upon completion. * passwdp [in/out] - The address where a pointer to newly allocated memory * holding the password will be stored upon completion. * optionsp [in/out] - The address where a pointer to newly allocated memory * holding the options will be stored upon completion. * * Returns CURLE_OK on success. */ CURLcode Curl_parse_login_details(const char *login, const size_t len, char **userp, char **passwdp, char **optionsp) { CURLcode result = CURLE_OK; char *ubuf = NULL; char *pbuf = NULL; char *obuf = NULL; const char *psep = NULL; const char *osep = NULL; size_t ulen; size_t plen; size_t olen; /* Attempt to find the password separator */ if(passwdp) { psep = strchr(login, ':'); /* Within the constraint of the login string */ if(psep >= login + len) psep = NULL; } /* Attempt to find the options separator */ if(optionsp) { osep = strchr(login, ';'); /* Within the constraint of the login string */ if(osep >= login + len) osep = NULL; } /* Calculate the portion lengths */ ulen = (psep ? (size_t)(osep && psep > osep ? osep - login : psep - login) : (osep ? (size_t)(osep - login) : len)); plen = (psep ? (osep && osep > psep ? (size_t)(osep - psep) : (size_t)(login + len - psep)) - 1 : 0); olen = (osep ? (psep && psep > osep ? (size_t)(psep - osep) : (size_t)(login + len - osep)) - 1 : 0); /* Allocate the user portion buffer */ if(userp && ulen) { ubuf = malloc(ulen + 1); if(!ubuf) result = CURLE_OUT_OF_MEMORY; } /* Allocate the password portion buffer */ if(!result && passwdp && plen) { pbuf = malloc(plen + 1); if(!pbuf) { free(ubuf); result = CURLE_OUT_OF_MEMORY; } } /* Allocate the options portion buffer */ if(!result && optionsp && olen) { obuf = malloc(olen + 1); if(!obuf) { free(pbuf); free(ubuf); result = CURLE_OUT_OF_MEMORY; } } if(!result) { /* Store the user portion if necessary */ if(ubuf) { memcpy(ubuf, login, ulen); ubuf[ulen] = '\0'; Curl_safefree(*userp); *userp = ubuf; } /* Store the password portion if necessary */ if(pbuf) { memcpy(pbuf, psep + 1, plen); pbuf[plen] = '\0'; Curl_safefree(*passwdp); *passwdp = pbuf; } /* Store the options portion if necessary */ if(obuf) { memcpy(obuf, osep + 1, olen); obuf[olen] = '\0'; Curl_safefree(*optionsp); *optionsp = obuf; } } return result; } /************************************************************* * Figure out the remote port number and fix it in the URL * * No matter if we use a proxy or not, we have to figure out the remote * port number of various reasons. * * The port number embedded in the URL is replaced, if necessary. *************************************************************/ static CURLcode parse_remote_port(struct Curl_easy *data, struct connectdata *conn) { if(data->set.use_port && data->state.allow_port) { /* if set, we use this instead of the port possibly given in the URL */ char portbuf[16]; CURLUcode uc; conn->remote_port = (unsigned short)data->set.use_port; msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); if(uc) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } /* * Override the login details from the URL with that in the CURLOPT_USERPWD * option or a .netrc file, if applicable. */ static CURLcode override_login(struct Curl_easy *data, struct connectdata *conn, char **userp, char **passwdp, char **optionsp) { bool user_changed = FALSE; bool passwd_changed = FALSE; CURLUcode uc; if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) { /* ignore user+password in the URL */ if(*userp) { Curl_safefree(*userp); user_changed = TRUE; } if(*passwdp) { Curl_safefree(*passwdp); passwd_changed = TRUE; } conn->bits.user_passwd = FALSE; /* disable user+password */ } if(data->set.str[STRING_USERNAME]) { free(*userp); *userp = strdup(data->set.str[STRING_USERNAME]); if(!*userp) return CURLE_OUT_OF_MEMORY; conn->bits.user_passwd = TRUE; /* enable user+password */ user_changed = TRUE; } if(data->set.str[STRING_PASSWORD]) { free(*passwdp); *passwdp = strdup(data->set.str[STRING_PASSWORD]); if(!*passwdp) return CURLE_OUT_OF_MEMORY; conn->bits.user_passwd = TRUE; /* enable user+password */ passwd_changed = TRUE; } if(data->set.str[STRING_OPTIONS]) { free(*optionsp); *optionsp = strdup(data->set.str[STRING_OPTIONS]); if(!*optionsp) return CURLE_OUT_OF_MEMORY; } conn->bits.netrc = FALSE; if(data->set.use_netrc != CURL_NETRC_IGNORED && (!*userp || !**userp || !*passwdp || !**passwdp)) { bool netrc_user_changed = FALSE; bool netrc_passwd_changed = FALSE; int ret; ret = Curl_parsenetrc(conn->host.name, userp, passwdp, &netrc_user_changed, &netrc_passwd_changed, data->set.str[STRING_NETRC_FILE]); if(ret > 0) { infof(data, "Couldn't find host %s in the .netrc file; using defaults\n", conn->host.name); } else if(ret < 0) { return CURLE_OUT_OF_MEMORY; } else { /* set bits.netrc TRUE to remember that we got the name from a .netrc file, so that it is safe to use even if we followed a Location: to a different host or similar. */ conn->bits.netrc = TRUE; conn->bits.user_passwd = TRUE; /* enable user+password */ if(netrc_user_changed) { user_changed = TRUE; } if(netrc_passwd_changed) { passwd_changed = TRUE; } } } /* for updated strings, we update them in the URL */ if(user_changed) { uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0); if(uc) return Curl_uc_to_curlcode(uc); } if(passwd_changed) { uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0); if(uc) return Curl_uc_to_curlcode(uc); } return CURLE_OK; } /* * Set the login details so they're available in the connection */ static CURLcode set_login(struct connectdata *conn) { CURLcode result = CURLE_OK; const char *setuser = CURL_DEFAULT_USER; const char *setpasswd = CURL_DEFAULT_PASSWORD; /* If our protocol needs a password and we have none, use the defaults */ if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) ; else { setuser = ""; setpasswd = ""; } /* Store the default user */ if(!conn->user) { conn->user = strdup(setuser); if(!conn->user) return CURLE_OUT_OF_MEMORY; } /* Store the default password */ if(!conn->passwd) { conn->passwd = strdup(setpasswd); if(!conn->passwd) result = CURLE_OUT_OF_MEMORY; } return result; } /* * Parses a "host:port" string to connect to. * The hostname and the port may be empty; in this case, NULL is returned for * the hostname and -1 for the port. */ static CURLcode parse_connect_to_host_port(struct Curl_easy *data, const char *host, char **hostname_result, int *port_result) { char *host_dup; char *hostptr; char *host_portno; char *portptr; int port = -1; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif *hostname_result = NULL; *port_result = -1; if(!host || !*host) return CURLE_OK; host_dup = strdup(host); if(!host_dup) return CURLE_OUT_OF_MEMORY; hostptr = host_dup; /* start scanning for port number at this point */ portptr = hostptr; /* detect and extract RFC6874-style IPv6-addresses */ if(*hostptr == '[') { #ifdef ENABLE_IPV6 char *ptr = ++hostptr; /* advance beyond the initial bracket */ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) ptr++; if(*ptr == '%') { /* There might be a zone identifier */ if(strncmp("%25", ptr, 3)) infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); ptr++; /* Allow unreserved characters as defined in RFC 3986 */ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) ptr++; } if(*ptr == ']') /* yeps, it ended nicely with a bracket as well */ *ptr++ = '\0'; else infof(data, "Invalid IPv6 address format\n"); portptr = ptr; /* Note that if this didn't end with a bracket, we still advanced the * hostptr first, but I can't see anything wrong with that as no host * name nor a numeric can legally start with a bracket. */ #else failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in!"); free(host_dup); return CURLE_NOT_BUILT_IN; #endif } /* Get port number off server.com:1080 */ host_portno = strchr(portptr, ':'); if(host_portno) { char *endp = NULL; *host_portno = '\0'; /* cut off number from host name */ host_portno++; if(*host_portno) { long portparse = strtol(host_portno, &endp, 10); if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { infof(data, "No valid port number in connect to host string (%s)\n", host_portno); hostptr = NULL; port = -1; } else port = (int)portparse; /* we know it will fit */ } } /* now, clone the cleaned host name */ if(hostptr) { *hostname_result = strdup(hostptr); if(!*hostname_result) { free(host_dup); return CURLE_OUT_OF_MEMORY; } } *port_result = port; free(host_dup); return CURLE_OK; } /* * Parses one "connect to" string in the form: * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". */ static CURLcode parse_connect_to_string(struct Curl_easy *data, struct connectdata *conn, const char *conn_to_host, char **host_result, int *port_result) { CURLcode result = CURLE_OK; const char *ptr = conn_to_host; int host_match = FALSE; int port_match = FALSE; *host_result = NULL; *port_result = -1; if(*ptr == ':') { /* an empty hostname always matches */ host_match = TRUE; ptr++; } else { /* check whether the URL's hostname matches */ size_t hostname_to_match_len; char *hostname_to_match = aprintf("%s%s%s", conn->bits.ipv6_ip ? "[" : "", conn->host.name, conn->bits.ipv6_ip ? "]" : ""); if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); host_match = strncasecompare(ptr, hostname_to_match, hostname_to_match_len); free(hostname_to_match); ptr += hostname_to_match_len; host_match = host_match && *ptr == ':'; ptr++; } if(host_match) { if(*ptr == ':') { /* an empty port always matches */ port_match = TRUE; ptr++; } else { /* check whether the URL's port matches */ char *ptr_next = strchr(ptr, ':'); if(ptr_next) { char *endp = NULL; long port_to_match = strtol(ptr, &endp, 10); if((endp == ptr_next) && (port_to_match == conn->remote_port)) { port_match = TRUE; ptr = ptr_next + 1; } } } } if(host_match && port_match) { /* parse the hostname and port to connect to */ result = parse_connect_to_host_port(data, ptr, host_result, port_result); } return result; } /* * Processes all strings in the "connect to" slist, and uses the "connect * to host" and "connect to port" of the first string that matches. */ static CURLcode parse_connect_to_slist(struct Curl_easy *data, struct connectdata *conn, struct curl_slist *conn_to_host) { CURLcode result = CURLE_OK; char *host = NULL; int port = -1; while(conn_to_host && !host && port == -1) { result = parse_connect_to_string(data, conn, conn_to_host->data, &host, &port); if(result) return result; if(host && *host) { conn->conn_to_host.rawalloc = host; conn->conn_to_host.name = host; conn->bits.conn_to_host = TRUE; infof(data, "Connecting to hostname: %s\n", host); } else { /* no "connect to host" */ conn->bits.conn_to_host = FALSE; Curl_safefree(host); } if(port >= 0) { conn->conn_to_port = port; conn->bits.conn_to_port = TRUE; infof(data, "Connecting to port: %d\n", port); } else { /* no "connect to port" */ conn->bits.conn_to_port = FALSE; port = -1; } conn_to_host = conn_to_host->next; } #ifdef USE_ALTSVC if(data->asi && !host && (port == -1) && (conn->handler->protocol == CURLPROTO_HTTPS)) { /* no connect_to match, try alt-svc! */ enum alpnid srcalpnid; bool hit; struct altsvc *as; const int allowed_versions = ( ALPN_h1 #ifdef USE_NGHTTP2 | ALPN_h2 #endif #ifdef ENABLE_QUIC | ALPN_h3 #endif ) & data->asi->flags; host = conn->host.rawalloc; #ifdef USE_NGHTTP2 /* with h2 support, check that first */ srcalpnid = ALPN_h2; hit = Curl_altsvc_lookup(data->asi, srcalpnid, host, conn->remote_port, /* from */ &as /* to */, allowed_versions); if(!hit) #endif { srcalpnid = ALPN_h1; hit = Curl_altsvc_lookup(data->asi, srcalpnid, host, conn->remote_port, /* from */ &as /* to */, allowed_versions); } if(hit) { char *hostd = strdup((char *)as->dst.host); if(!hostd) return CURLE_OUT_OF_MEMORY; conn->conn_to_host.rawalloc = hostd; conn->conn_to_host.name = hostd; conn->bits.conn_to_host = TRUE; conn->conn_to_port = as->dst.port; conn->bits.conn_to_port = TRUE; conn->bits.altused = TRUE; infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n", Curl_alpnid2str(srcalpnid), host, conn->remote_port, Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port); if(srcalpnid != as->dst.alpnid) { /* protocol version switch */ switch(as->dst.alpnid) { case ALPN_h1: conn->httpversion = 11; break; case ALPN_h2: conn->httpversion = 20; break; case ALPN_h3: conn->transport = TRNSPRT_QUIC; conn->httpversion = 30; break; default: /* shouldn't be possible */ break; } } } } #endif return result; } /************************************************************* * Resolve the address of the server or proxy *************************************************************/ static CURLcode resolve_server(struct Curl_easy *data, struct connectdata *conn, bool *async) { CURLcode result = CURLE_OK; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); DEBUGASSERT(conn); DEBUGASSERT(data); /************************************************************* * Resolve the name of the server or proxy *************************************************************/ if(conn->bits.reuse) /* We're reusing the connection - no need to resolve anything, and idnconvert_hostname() was called already in create_conn() for the re-use case. */ *async = FALSE; else { /* this is a fresh connect */ int rc; struct Curl_dns_entry *hostaddr; #ifdef USE_UNIX_SOCKETS if(conn->unix_domain_socket) { /* Unix domain sockets are local. The host gets ignored, just use the * specified domain socket address. Do not cache "DNS entries". There is * no DNS involved and we already have the filesystem path available */ const char *path = conn->unix_domain_socket; hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); if(!hostaddr) result = CURLE_OUT_OF_MEMORY; else { bool longpath = FALSE; hostaddr->addr = Curl_unix2addr(path, &longpath, conn->abstract_unix_socket); if(hostaddr->addr) hostaddr->inuse++; else { /* Long paths are not supported for now */ if(longpath) { failf(data, "Unix socket path too long: '%s'", path); result = CURLE_COULDNT_RESOLVE_HOST; } else result = CURLE_OUT_OF_MEMORY; free(hostaddr); hostaddr = NULL; } } } else #endif if(!conn->bits.proxy) { struct hostname *connhost; if(conn->bits.conn_to_host) connhost = &conn->conn_to_host; else connhost = &conn->host; /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ if(conn->bits.conn_to_port) conn->port = conn->conn_to_port; else conn->port = conn->remote_port; /* Resolve target host right on */ conn->hostname_resolve = strdup(connhost->name); if(!conn->hostname_resolve) return CURLE_OUT_OF_MEMORY; rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; else if(rc == CURLRESOLV_TIMEDOUT) result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { failf(data, "Couldn't resolve host '%s'", connhost->dispname); result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ } } else { /* This is a proxy that hasn't been resolved yet. */ struct hostname * const host = conn->bits.socksproxy ? &conn->socks_proxy.host : &conn->http_proxy.host; /* resolve proxy */ conn->hostname_resolve = strdup(host->name); if(!conn->hostname_resolve) return CURLE_OUT_OF_MEMORY; rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; else if(rc == CURLRESOLV_TIMEDOUT) result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { failf(data, "Couldn't resolve proxy '%s'", host->dispname); result = CURLE_COULDNT_RESOLVE_PROXY; /* don't return yet, we need to clean up the timeout first */ } } DEBUGASSERT(conn->dns_entry == NULL); conn->dns_entry = hostaddr; } return result; } /* * Cleanup the connection just allocated before we can move along and use the * previously existing one. All relevant data is copied over and old_conn is * ready for freeing once this function returns. */ static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { Curl_free_idnconverted_hostname(&old_conn->http_proxy.host); Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ Curl_free_primary_ssl_config(&old_conn->ssl_config); Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); conn->data = old_conn->data; /* get the user+password information from the old_conn struct since it may * be new for this request even when we re-use an existing connection */ conn->bits.user_passwd = old_conn->bits.user_passwd; if(conn->bits.user_passwd) { /* use the new user name and password though */ Curl_safefree(conn->user); Curl_safefree(conn->passwd); conn->user = old_conn->user; conn->passwd = old_conn->passwd; old_conn->user = NULL; old_conn->passwd = NULL; } conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; if(conn->bits.proxy_user_passwd) { /* use the new proxy user name and proxy password though */ Curl_safefree(conn->http_proxy.user); Curl_safefree(conn->socks_proxy.user); Curl_safefree(conn->http_proxy.passwd); Curl_safefree(conn->socks_proxy.passwd); conn->http_proxy.user = old_conn->http_proxy.user; conn->socks_proxy.user = old_conn->socks_proxy.user; conn->http_proxy.passwd = old_conn->http_proxy.passwd; conn->socks_proxy.passwd = old_conn->socks_proxy.passwd; old_conn->http_proxy.user = NULL; old_conn->socks_proxy.user = NULL; old_conn->http_proxy.passwd = NULL; old_conn->socks_proxy.passwd = NULL; } /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); Curl_safefree(conn->conn_to_host.rawalloc); conn->host = old_conn->host; conn->conn_to_host = old_conn->conn_to_host; conn->conn_to_port = old_conn->conn_to_port; conn->remote_port = old_conn->remote_port; Curl_safefree(conn->hostname_resolve); conn->hostname_resolve = old_conn->hostname_resolve; old_conn->hostname_resolve = NULL; /* persist connection info in session handle */ Curl_persistconninfo(conn); conn_reset_all_postponed_data(old_conn); /* free buffers */ /* re-use init */ conn->bits.reuse = TRUE; /* yes, we're re-using here */ Curl_safefree(old_conn->user); Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->options); Curl_safefree(old_conn->http_proxy.user); Curl_safefree(old_conn->socks_proxy.user); Curl_safefree(old_conn->http_proxy.passwd); Curl_safefree(old_conn->socks_proxy.passwd); Curl_safefree(old_conn->localdev); Curl_llist_destroy(&old_conn->easyq, NULL); #ifdef USE_UNIX_SOCKETS Curl_safefree(old_conn->unix_domain_socket); #endif } /** * create_conn() sets up a new connectdata struct, or re-uses an already * existing one, and resolves host name. * * if this function returns CURLE_OK and *async is set to TRUE, the resolve * response will be coming asynchronously. If *async is FALSE, the name is * already resolved. * * @param data The sessionhandle pointer * @param in_connect is set to the next connection data pointer * @param async is set TRUE when an async DNS resolution is pending * @see Curl_setup_conn() * * *NOTE* this function assigns the conn->data pointer! */ static CURLcode create_conn(struct Curl_easy *data, struct connectdata **in_connect, bool *async) { CURLcode result = CURLE_OK; struct connectdata *conn; struct connectdata *conn_temp = NULL; bool reuse; bool connections_available = TRUE; bool force_reuse = FALSE; bool waitpipe = FALSE; size_t max_host_connections = Curl_multi_max_host_connections(data->multi); size_t max_total_connections = Curl_multi_max_total_connections(data->multi); *async = FALSE; *in_connect = NULL; /************************************************************* * Check input data *************************************************************/ if(!data->change.url) { result = CURLE_URL_MALFORMAT; goto out; } /* First, split up the current URL in parts so that we can use the parts for checking against the already present connections. In order to not have to modify everything at once, we allocate a temporary connection data struct and fill in for comparison purposes. */ conn = allocate_conn(data); if(!conn) { result = CURLE_OUT_OF_MEMORY; goto out; } /* We must set the return variable as soon as possible, so that our parent can cleanup any possible allocs we may have done before any failure */ *in_connect = conn; result = parseurlandfillconn(data, conn); if(result) goto out; if(data->set.str[STRING_SASL_AUTHZID]) { conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]); if(!conn->sasl_authzid) { result = CURLE_OUT_OF_MEMORY; goto out; } } #ifdef USE_UNIX_SOCKETS if(data->set.str[STRING_UNIX_SOCKET_PATH]) { conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); if(conn->unix_domain_socket == NULL) { result = CURLE_OUT_OF_MEMORY; goto out; } conn->abstract_unix_socket = data->set.abstract_unix_socket; } #endif /* After the unix socket init but before the proxy vars are used, parse and initialize the proxy vars */ #ifndef CURL_DISABLE_PROXY result = create_conn_helper_init_proxy(conn); if(result) goto out; #endif /************************************************************* * If the protocol is using SSL and HTTP proxy is used, we set * the tunnel_proxy bit. *************************************************************/ if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) conn->bits.tunnel_proxy = TRUE; /************************************************************* * Figure out the remote port number and fix it in the URL *************************************************************/ result = parse_remote_port(data, conn); if(result) goto out; /* Check for overridden login details and set them accordingly so they they are known when protocol->setup_connection is called! */ result = override_login(data, conn, &conn->user, &conn->passwd, &conn->options); if(result) goto out; result = set_login(conn); /* default credentials */ if(result) goto out; /************************************************************* * Process the "connect to" linked list of hostname/port mappings. * Do this after the remote port number has been fixed in the URL. *************************************************************/ result = parse_connect_to_slist(data, conn, data->set.connect_to); if(result) goto out; /************************************************************* * IDN-convert the hostnames *************************************************************/ result = Curl_idnconvert_hostname(conn, &conn->host); if(result) goto out; if(conn->bits.conn_to_host) { result = Curl_idnconvert_hostname(conn, &conn->conn_to_host); if(result) goto out; } if(conn->bits.httpproxy) { result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host); if(result) goto out; } if(conn->bits.socksproxy) { result = Curl_idnconvert_hostname(conn, &conn->socks_proxy.host); if(result) goto out; } /************************************************************* * Check whether the host and the "connect to host" are equal. * Do this after the hostnames have been IDN-converted. *************************************************************/ if(conn->bits.conn_to_host && strcasecompare(conn->conn_to_host.name, conn->host.name)) { conn->bits.conn_to_host = FALSE; } /************************************************************* * Check whether the port and the "connect to port" are equal. * Do this after the remote port number has been fixed in the URL. *************************************************************/ if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { conn->bits.conn_to_port = FALSE; } /************************************************************* * If the "connect to" feature is used with an HTTP proxy, * we set the tunnel_proxy bit. *************************************************************/ if((conn->bits.conn_to_host || conn->bits.conn_to_port) && conn->bits.httpproxy) conn->bits.tunnel_proxy = TRUE; /************************************************************* * Setup internals depending on protocol. Needs to be done after * we figured out what/if proxy to use. *************************************************************/ result = setup_connection_internals(conn); if(result) goto out; conn->recv[FIRSTSOCKET] = Curl_recv_plain; conn->send[FIRSTSOCKET] = Curl_send_plain; conn->recv[SECONDARYSOCKET] = Curl_recv_plain; conn->send[SECONDARYSOCKET] = Curl_send_plain; conn->bits.tcp_fastopen = data->set.tcp_fastopen; /*********************************************************************** * file: is a special case in that it doesn't need a network connection ***********************************************************************/ #ifndef CURL_DISABLE_FILE if(conn->handler->flags & PROTOPT_NONETWORK) { bool done; /* this is supposed to be the connect function so we better at least check that the file is present here! */ DEBUGASSERT(conn->handler->connect_it); Curl_persistconninfo(conn); result = conn->handler->connect_it(conn, &done); /* Setup a "faked" transfer that'll do nothing */ if(!result) { conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ result = Curl_conncache_add_conn(data->state.conn_cache, conn); if(result) goto out; /* * Setup whatever necessary for a resumed transfer */ result = setup_range(data); if(result) { DEBUGASSERT(conn->handler->done); /* we ignore the return code for the protocol-specific DONE */ (void)conn->handler->done(conn, result, FALSE); goto out; } Curl_attach_connnection(data, conn); Curl_setup_transfer(data, -1, -1, FALSE, -1); } /* since we skip do_init() */ Curl_init_do(data, conn); goto out; } #endif /* Get a cloned copy of the SSL config situation stored in the connection struct. But to get this going nicely, we must first make sure that the strings in the master copy are pointing to the correct strings in the session handle strings array! Keep in mind that the pointers in the master copy are pointing to strings that will be freed as part of the Curl_easy struct, but all cloned copies will be separately allocated. */ data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG]; data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; data->set.proxy_ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.ssl.primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_ORIG]; data->set.proxy_ssl.primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; data->set.ssl.primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_ORIG]; data->set.proxy_ssl.primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; data->set.ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; data->set.proxy_ssl.primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; #ifdef USE_TLS_SRP data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; #endif if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, &conn->ssl_config)) { result = CURLE_OUT_OF_MEMORY; goto out; } if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, &conn->proxy_ssl_config)) { result = CURLE_OUT_OF_MEMORY; goto out; } prune_dead_connections(data); /************************************************************* * Check the current list of connections to see if we can * re-use an already existing one or if we have to create a * new one. *************************************************************/ DEBUGASSERT(conn->user); DEBUGASSERT(conn->passwd); /* reuse_fresh is TRUE if we are told to use a new connection by force, but we only acknowledge this option if this is not a re-used connection already (which happens due to follow-location or during a HTTP authentication phase). CONNECT_ONLY transfers also refuse reuse. */ if((data->set.reuse_fresh && !data->state.this_is_a_follow) || data->set.connect_only) reuse = FALSE; else reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); if(reuse) { /* * We already have a connection for this, we got the former connection * in the conn_temp variable and thus we need to cleanup the one we * just allocated before we can move along and use the previously * existing one. */ reuse_conn(conn, conn_temp); #ifdef USE_SSL free(conn->ssl_extra); #endif free(conn); /* we don't need this anymore */ conn = conn_temp; *in_connect = conn; infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, conn->bits.proxy?"proxy":"host", conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : conn->http_proxy.host.name ? conn->http_proxy.host.dispname : conn->host.dispname); } else { /* We have decided that we want a new connection. However, we may not be able to do that if we have reached the limit of how many connections we are allowed to open. */ if(conn->handler->flags & PROTOPT_ALPN_NPN) { /* The protocol wants it, so set the bits if enabled in the easy handle (default) */ if(data->set.ssl_enable_alpn) conn->bits.tls_enable_alpn = TRUE; if(data->set.ssl_enable_npn) conn->bits.tls_enable_npn = TRUE; } if(waitpipe) /* There is a connection that *might* become usable for multiplexing "soon", and we wait for that */ connections_available = FALSE; else { /* this gets a lock on the conncache */ const char *bundlehost; struct connectbundle *bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, &bundlehost); if(max_host_connections > 0 && bundle && (bundle->num_connections >= max_host_connections)) { struct connectdata *conn_candidate; /* The bundle is full. Extract the oldest connection. */ conn_candidate = Curl_conncache_extract_bundle(data, bundle); Curl_conncache_unlock(data); if(conn_candidate) (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE); else { infof(data, "No more connections allowed to host %s: %zu\n", bundlehost, max_host_connections); connections_available = FALSE; } } else Curl_conncache_unlock(data); } if(connections_available && (max_total_connections > 0) && (Curl_conncache_size(data) >= max_total_connections)) { struct connectdata *conn_candidate; /* The cache is full. Let's see if we can kill a connection. */ conn_candidate = Curl_conncache_extract_oldest(data); if(conn_candidate) (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE); else { infof(data, "No connections available in cache\n"); connections_available = FALSE; } } if(!connections_available) { infof(data, "No connections available.\n"); conn_free(conn); *in_connect = NULL; result = CURLE_NO_CONNECTION_AVAILABLE; goto out; } else { /* * This is a brand new connection, so let's store it in the connection * cache of ours! */ result = Curl_conncache_add_conn(data->state.conn_cache, conn); if(result) goto out; } #if defined(USE_NTLM) /* If NTLM is requested in a part of this connection, make sure we don't assume the state is fine as this is a fresh connection and NTLM is connection based. */ if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && data->state.authhost.done) { infof(data, "NTLM picked AND auth done set, clear picked!\n"); data->state.authhost.picked = CURLAUTH_NONE; data->state.authhost.done = FALSE; } if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) && data->state.authproxy.done) { infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n"); data->state.authproxy.picked = CURLAUTH_NONE; data->state.authproxy.done = FALSE; } #endif } /* Setup and init stuff before DO starts, in preparing for the transfer. */ Curl_init_do(data, conn); /* * Setup whatever necessary for a resumed transfer */ result = setup_range(data); if(result) goto out; /* Continue connectdata initialization here. */ /* * Inherit the proper values from the urldata struct AFTER we have arranged * the persistent connection stuff */ conn->seek_func = data->set.seek_func; conn->seek_client = data->set.seek_client; /************************************************************* * Resolve the address of the server or proxy *************************************************************/ result = resolve_server(data, conn, async); /* Strip trailing dots. resolve_server copied the name. */ strip_trailing_dot(&conn->host); if(conn->bits.httpproxy) strip_trailing_dot(&conn->http_proxy.host); if(conn->bits.socksproxy) strip_trailing_dot(&conn->socks_proxy.host); if(conn->bits.conn_to_host) strip_trailing_dot(&conn->conn_to_host); out: return result; } /* Curl_setup_conn() is called after the name resolve initiated in * create_conn() is all done. * * Curl_setup_conn() also handles reused connections * * conn->data MUST already have been setup fine (in create_conn) */ CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); if(conn->handler->flags & PROTOPT_NONETWORK) { /* nothing to setup when not using a network */ *protocol_done = TRUE; return result; } *protocol_done = FALSE; /* default to not done */ /* set proxy_connect_closed to false unconditionally already here since it is used strictly to provide extra information to a parent function in the case of proxy CONNECT failures and we must make sure we don't have it lingering set from a previous invoke */ conn->bits.proxy_connect_closed = FALSE; /* * Set user-agent. Used for HTTP, but since we can attempt to tunnel * basically anything through a http proxy we can't limit this based on * protocol. */ if(data->set.str[STRING_USERAGENT]) { Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); if(!conn->allocptr.uagent) return CURLE_OUT_OF_MEMORY; } data->req.headerbytecount = 0; #ifdef CURL_DO_LINEEND_CONV data->state.crlf_conversions = 0; /* reset CRLF conversion counter */ #endif /* CURL_DO_LINEEND_CONV */ /* set start time here for timeout purposes in the connect procedure, it is later set again for the progress meter purpose */ conn->now = Curl_now(); if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) { conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; result = Curl_connecthost(conn, conn->dns_entry); if(result) return result; } else { Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ if(conn->ssl[FIRSTSOCKET].use || (conn->handler->protocol & PROTO_FAMILY_SSH)) Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; *protocol_done = TRUE; Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); Curl_verboseconnect(conn); } conn->now = Curl_now(); /* time this *after* the connect is done, we set this here perhaps a second time */ return result; } CURLcode Curl_connect(struct Curl_easy *data, bool *asyncp, bool *protocol_done) { CURLcode result; struct connectdata *conn; *asyncp = FALSE; /* assume synchronous resolves by default */ /* init the single-transfer specific data */ Curl_free_request_state(data); memset(&data->req, 0, sizeof(struct SingleRequest)); data->req.maxdownload = -1; /* call the stuff that needs to be called */ result = create_conn(data, &conn, asyncp); if(!result) { if(CONN_INUSE(conn)) /* multiplexed */ *protocol_done = TRUE; else if(!*asyncp) { /* DNS resolution is done: that's either because this is a reused connection, in which case DNS was unnecessary, or because DNS really did finish already (synch resolver/fast async resolve) */ result = Curl_setup_conn(conn, protocol_done); } } if(result == CURLE_NO_CONNECTION_AVAILABLE) { return result; } else if(result && conn) { /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ Curl_disconnect(data, conn, TRUE); } else if(!result && !data->conn) /* FILE: transfers already have the connection attached */ Curl_attach_connnection(data, conn); return result; } /* * Curl_init_do() inits the readwrite session. This is inited each time (in * the DO function before the protocol-specific DO functions are invoked) for * a transfer, sometimes multiple times on the same Curl_easy. Make sure * nothing in here depends on stuff that are setup dynamically for the * transfer. * * Allow this function to get called with 'conn' set to NULL. */ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) { struct SingleRequest *k = &data->req; if(conn) { conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */ /* if the protocol used doesn't support wildcards, switch it off */ if(data->state.wildcardmatch && !(conn->handler->flags & PROTOPT_WILDCARD)) data->state.wildcardmatch = FALSE; } data->state.done = FALSE; /* *_done() is not called yet */ data->state.expect100header = FALSE; if(data->set.opt_no_body) /* in HTTP lingo, no body means using the HEAD request... */ data->set.httpreq = HTTPREQ_HEAD; else if(HTTPREQ_HEAD == data->set.httpreq) /* ... but if unset there really is no perfect method that is the "opposite" of HEAD but in reality most people probably think GET then. The important thing is that we can't let it remain HEAD if the opt_no_body is set FALSE since then we'll behave wrong when getting HTTP. */ data->set.httpreq = HTTPREQ_GET; k->start = Curl_now(); /* start time */ k->now = k->start; /* current time is now */ k->header = TRUE; /* assume header */ k->bytecount = 0; k->buf = data->state.buffer; k->hbufp = data->state.headerbuff; k->ignorebody = FALSE; Curl_speedinit(data); Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); return CURLE_OK; } /* * get_protocol_family() * * This is used to return the protocol family for a given protocol. * * Parameters: * * protocol [in] - A single bit protocol identifier such as HTTP or HTTPS. * * Returns the family as a single bit protocol identifier. */ static unsigned int get_protocol_family(unsigned int protocol) { unsigned int family; switch(protocol) { case CURLPROTO_HTTP: case CURLPROTO_HTTPS: family = CURLPROTO_HTTP; break; case CURLPROTO_FTP: case CURLPROTO_FTPS: family = CURLPROTO_FTP; break; case CURLPROTO_SCP: family = CURLPROTO_SCP; break; case CURLPROTO_SFTP: family = CURLPROTO_SFTP; break; case CURLPROTO_TELNET: family = CURLPROTO_TELNET; break; case CURLPROTO_LDAP: case CURLPROTO_LDAPS: family = CURLPROTO_LDAP; break; case CURLPROTO_DICT: family = CURLPROTO_DICT; break; case CURLPROTO_FILE: family = CURLPROTO_FILE; break; case CURLPROTO_TFTP: family = CURLPROTO_TFTP; break; case CURLPROTO_IMAP: case CURLPROTO_IMAPS: family = CURLPROTO_IMAP; break; case CURLPROTO_POP3: case CURLPROTO_POP3S: family = CURLPROTO_POP3; break; case CURLPROTO_SMTP: case CURLPROTO_SMTPS: family = CURLPROTO_SMTP; break; case CURLPROTO_RTSP: family = CURLPROTO_RTSP; break; case CURLPROTO_RTMP: case CURLPROTO_RTMPS: family = CURLPROTO_RTMP; break; case CURLPROTO_RTMPT: case CURLPROTO_RTMPTS: family = CURLPROTO_RTMPT; break; case CURLPROTO_RTMPE: family = CURLPROTO_RTMPE; break; case CURLPROTO_RTMPTE: family = CURLPROTO_RTMPTE; break; case CURLPROTO_GOPHER: family = CURLPROTO_GOPHER; break; case CURLPROTO_SMB: case CURLPROTO_SMBS: family = CURLPROTO_SMB; break; default: family = 0; break; } return family; } davix-0.8.0/deps/curl/lib/curl_rtmp.h0000644000000000000000000000265214121063461016161 0ustar rootroot#ifndef HEADER_CURL_RTMP_H #define HEADER_CURL_RTMP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2019, Howard Chu, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifdef USE_LIBRTMP extern const struct Curl_handler Curl_handler_rtmp; extern const struct Curl_handler Curl_handler_rtmpt; extern const struct Curl_handler Curl_handler_rtmpe; extern const struct Curl_handler Curl_handler_rtmpte; extern const struct Curl_handler Curl_handler_rtmps; extern const struct Curl_handler Curl_handler_rtmpts; #endif #endif /* HEADER_CURL_RTMP_H */ davix-0.8.0/deps/curl/lib/Makefile.Watcom0000644000000000000000000001470414121063461016673 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2005 - 2009, Gisle Vanem . # Copyright (C) 2005 - 2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # # Watcom / OpenWatcom / Win32 makefile for libcurl. # .ERASE !if $(__VERSION__) < 1280 !message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !message ! This Open Watcom version is too old and is no longer supported ! !message ! Please download latest version from www.openwatcom.org ! !message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !error Unsupported version of Open Watcom !endif !ifndef %watcom !error WATCOM environment variable not set! !endif # In order to process Makefile.inc wmake must be called with -u switch! !ifndef %MAKEFLAGS !error You MUST call wmake with the -u switch! !endif !ifdef %libname LIBNAME = $(%libname) !else LIBNAME = libcurl !endif TARGETS = $(LIBNAME).dll $(LIBNAME).lib CC = wcc386 LD = wlink AR = wlib RC = wrc !ifdef __LOADDLL__ ! loaddll wcc386 wccd386 ! loaddll wpp386 wppd386 ! loaddll wlib wlibd ! loaddll wlink wlinkd !endif !ifdef __LINUX__ CP = cp MD = mkdir -p !else CP = copy 2>NUL MD = mkdir !endif !if $(__VERSION__) > 1290 RD = rm -rf !else ifdef __UNIX__ RD = rm -rf !else RD = rmdir /q /s 2>NUL !endif SYS_INCL = -I"$(%watcom)/h/nt" -I"$(%watcom)/h" CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -zc -s -fr=con -w2 -fpi -oilrtfm & -wcd=201 -bt=nt -d+ -dWIN32 & -dBUILDING_LIBCURL -I. -I"../include" $(SYS_INCL) !ifdef %debug DEBUG = -dDEBUG=1 -dDEBUGBUILD CFLAGS += -d3 $(DEBUG) !else CFLAGS += -d0 !endif !ifdef %use_ipv6 CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6 !endif !ifdef %use_sspi CFLAGS += -dUSE_WINDOWS_SSPI !endif !ifdef %use_winssl CFLAGS += -dUSE_WINDOWS_SSPI CFLAGS += -DUSE_SCHANNEL !endif !ifdef %use_winidn CFLAGS += -dWINVER=0x0600 -dUSE_WIN32_IDN ! if $(__VERSION__) <= 1290 CFLAGS += -dWANT_IDN_PROTOTYPES ! endif !endif # # Change to suite. # !ifdef %zlib_root ZLIB_ROOT = $(%zlib_root) !else ZLIB_ROOT = ../../zlib-1.2.8 !endif !ifdef %libssh2_root LIBSSH2_ROOT = $(%libssh2_root) !else LIBSSH2_ROOT = ../../libssh2-1.5.0 !endif !ifdef %librtmp_root LIBRTMP_ROOT = $(%librtmp_root) !else LIBRTMP_ROOT = ../../rtmpdump-2.3 !endif !ifdef %openssl_root OPENSSL_ROOT = $(%openssl_root) !else OPENSSL_ROOT = ../../openssl-1.0.2a !endif !ifdef %ares_root ARES_ROOT = $(%ares_root) !else ARES_ROOT = ../ares !endif !ifdef %use_zlib CFLAGS += -dHAVE_ZLIB_H -dHAVE_LIBZ -I"$(ZLIB_ROOT)" !endif !ifdef %use_rtmp CFLAGS += -dUSE_LIBRTMP -I"$(LIBRTMP_ROOT)" !endif !ifdef %use_ssh2 CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H -I"$(LIBSSH2_ROOT)/include" -I"$(LIBSSH2_ROOT)/win32" !endif !ifdef %use_ssl CFLAGS += -wcd=138 -dUSE_OPENSSL -I"$(OPENSSL_ROOT)/inc32" !endif !ifdef %use_ares CFLAGS += -dUSE_ARES -I"$(ARES_ROOT)" !endif !ifdef %use_watt32 CFLAGS += -dUSE_WATT32 -I"$(%watt_root)/inc" !endif OBJ_BASE = WC_Win32.obj !if $(__VERSION__) > 1290 OBJ_STAT = $(OBJ_BASE)/stat OBJ_DYN = $(OBJ_BASE)/dyn !else ifdef __UNIX__ OBJ_STAT = $(OBJ_BASE)/stat OBJ_DYN = $(OBJ_BASE)/dyn !else OBJ_STAT = $(OBJ_BASE)\stat OBJ_DYN = $(OBJ_BASE)\dyn !endif LINK_ARG = $(OBJ_DYN)/wlink.arg LIB_ARG = $(OBJ_STAT)/wlib.arg !include Makefile.inc OBJS1 = ./$(CSOURCES:.c=.obj) OBJS2 = $(OBJS1:vtls/=) OBJS3 = $(OBJS2:vauth/=) OBJS4 = $(OBJS3: = ./) OBJS_STAT = $(OBJS4:./=$(OBJ_STAT)/) OBJS_DYN = $(OBJS4:./=$(OBJ_DYN)/) RESOURCE = $(OBJ_DYN)/libcurl.res DIRS = $(OBJ_BASE) $(OBJ_BASE)/stat $(OBJ_BASE)/dyn .c : vauth vtls all: $(DIRS) $(TARGETS) .SYMBOLIC @echo Welcome to libcurl clean: .SYMBOLIC -rm -f $(OBJS_STAT) -rm -f $(OBJS_DYN) -rm -f $(RESOURCE) $(LINK_ARG) $(LIB_ARG) vclean distclean: clean .SYMBOLIC -rm -f $(TARGETS) $(LIBNAME).map $(LIBNAME).sym -$(RD) $(OBJ_STAT) -$(RD) $(OBJ_DYN) -$(RD) $(OBJ_BASE) $(DIRS): -$(MD) $^@ $(LIBNAME).dll: $(OBJS_DYN) $(RESOURCE) $(__MAKEFILES__) %create $(LINK_ARG) @%append $(LINK_ARG) system nt dll !ifdef %debug @%append $(LINK_ARG) debug all @%append $(LINK_ARG) option symfile !endif @%append $(LINK_ARG) option quiet, caseexact, eliminate @%append $(LINK_ARG) option map=$(OBJ_DYN)/$(LIBNAME).map @%append $(LINK_ARG) option implib=$(LIBNAME)_imp.lib @%append $(LINK_ARG) option res=$(RESOURCE) @for %f in ($(OBJS_DYN)) do @%append $(LINK_ARG) file %f @%append $(LINK_ARG) library wldap32.lib !ifdef %use_watt32 @%append $(LINK_ARG) library '$(%watt_root)/lib/wattcpw_imp.lib' !else @%append $(LINK_ARG) library ws2_32.lib !endif !ifdef %use_zlib @%append $(LINK_ARG) library '$(ZLIB_ROOT)/zlib.lib' !endif !ifdef %use_rtmp @%append $(LINK_ARG) library '$(LIBRTMP_ROOT)/librtmp/librtmp.lib' !endif !ifdef %use_ssh2 @%append $(LINK_ARG) library '$(LIBSSH2_ROOT)/win32/libssh2.lib' !endif !ifdef %use_ssl @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/libeay32.lib' @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/ssleay32.lib' !endif !ifdef %use_ares @%append $(LINK_ARG) library '$(ARES_ROOT)/cares.lib' !endif !ifdef %use_winidn ! if $(__VERSION__) > 1290 @%append $(LINK_ARG) library normaliz.lib ! else @%append $(LINK_ARG) import '_IdnToAscii@20' 'NORMALIZ.DLL'.'IdnToAscii' @%append $(LINK_ARG) import '_IdnToUnicode@20' 'NORMALIZ.DLL'.'IdnToUnicode' ! endif !endif $(LD) name $^@ @$(LINK_ARG) $(LIBNAME).lib: $(OBJS_STAT) %create $(LIB_ARG) @for %f in ($<) do @%append $(LIB_ARG) +- %f $(AR) -q -b -c -pa $^@ @$(LIB_ARG) $(RESOURCE): libcurl.rc $(RC) $(DEBUG) -q -r -zm -bt=nt -I"../include" $(SYS_INCL) $[@ -fo=$^@ .c{$(OBJ_DYN)}.obj: $(CC) $(CFLAGS) -bd -br $[@ -fo=$^@ .c{$(OBJ_STAT)}.obj: $(CC) $(CFLAGS) -DCURL_STATICLIB $[@ -fo=$^@ davix-0.8.0/deps/curl/lib/sendf.h0000644000000000000000000000660314121063461015251 0ustar rootroot#ifndef HEADER_CURL_SENDF_H #define HEADER_CURL_SENDF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, const char *fmt, ...); void Curl_infof(struct Curl_easy *, const char *fmt, ...); void Curl_failf(struct Curl_easy *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(HAVE_VARIADIC_MACROS_C99) #define infof(...) Curl_nop_stmt #elif defined(HAVE_VARIADIC_MACROS_GCC) #define infof(x...) Curl_nop_stmt #else #error "missing VARIADIC macro define, fix and rebuild!" #endif #else /* CURL_DISABLE_VERBOSE_STRINGS */ #define infof Curl_infof #endif /* CURL_DISABLE_VERBOSE_STRINGS */ #define failf Curl_failf #define CLIENTWRITE_BODY (1<<0) #define CLIENTWRITE_HEADER (1<<1) #define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len) WARN_UNUSED_RESULT; bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex); /* internal read-function, does plain socket only */ CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, size_t bytesfromsocket, ssize_t *n); ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, size_t len, CURLcode *code); ssize_t Curl_send_plain(struct connectdata *conn, int num, const void *mem, size_t len, CURLcode *code); /* internal read-function, does plain socket, SSL and krb4 */ CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd, char *buf, size_t buffersize, ssize_t *n); /* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */ CURLcode Curl_write(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written); /* internal write-function, does plain sockets ONLY */ CURLcode Curl_write_plain(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written); /* the function used to output verbose information */ int Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size); #endif /* HEADER_CURL_SENDF_H */ davix-0.8.0/deps/curl/lib/config-tpf.h0000644000000000000000000005176414121063461016216 0ustar rootroot#ifndef HEADER_CURL_CONFIG_TPF_H #define HEADER_CURL_CONFIG_TPF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for TPF */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* FEATURES, FUNCTIONS, and DEFINITIONS */ /* ---------------------------------------------------------------- */ /* NOTE: Refer also to the .mak file for some of the flags below */ /* to disable cookies support */ /* #undef CURL_DISABLE_COOKIES */ /* to disable cryptographic authentication */ /* #undef CURL_DISABLE_CRYPTO_AUTH */ /* to disable DICT */ /* #undef CURL_DISABLE_DICT */ /* to disable FILE */ /* #undef CURL_DISABLE_FILE */ /* to disable FTP */ /* #undef CURL_DISABLE_FTP */ /* to disable HTTP */ /* #undef CURL_DISABLE_HTTP */ /* to disable LDAP */ /* #undef CURL_DISABLE_LDAP */ /* to disable TELNET */ /* #undef CURL_DISABLE_TELNET */ /* to disable TFTP */ /* #undef CURL_DISABLE_TFTP */ /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ /* lber dynamic library file */ /* #undef DL_LBER_FILE */ /* ldap dynamic library file */ /* #undef DL_LDAP_FILE */ /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ /* Define if you want to enable IPv6 support */ /* #undef ENABLE_IPV6 */ /* Define if struct sockaddr_in6 has the sin6_scope_id member */ /* #undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */ /* Define to the type of arg 1 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG1 */ /* Define to the type of arg 2 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG2 */ /* Define to the type of args 4 and 6 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG46 */ /* Define to the type of arg 7 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG7 */ /* Define to 1 if you have the alarm function. */ #define HAVE_ALARM 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_TFTP_H */ /* Define to 1 if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define to 1 if you have the `basename' function. */ #define HAVE_BASENAME 1 /* Define to 1 if you have the `closesocket' function. */ /* #undef HAVE_CLOSESOCKET */ /* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ /* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_H */ #define HAVE_CRYPTO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_DES_H */ #define HAVE_DES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ERR_H */ #define HAVE_ERR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the fcntl function. */ #define HAVE_FCNTL 1 /* Define to 1 if you have a working fcntl O_NONBLOCK function. */ #define HAVE_FCNTL_O_NONBLOCK 1 /* Define to 1 if you have the `fork' function. */ /* #undef HAVE_FORK */ #define HAVE_FORK 1 /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 /* Define if getaddrinfo exists and works */ /* #undef HAVE_GETADDRINFO */ /* Define to 1 if you have the `geteuid' function. */ #define HAVE_GETEUID 1 /* Define to 1 if you have the `gethostbyaddr' function. */ #define HAVE_GETHOSTBYADDR 1 /* If you have gethostbyname */ #define HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the `gethostbyname_r' function. */ /* #undef HAVE_GETHOSTBYNAME_R */ /* gethostbyname_r() takes 3 args */ /* #undef HAVE_GETHOSTBYNAME_R_3 */ /* gethostbyname_r() takes 5 args */ /* #undef HAVE_GETHOSTBYNAME_R_5 */ /* gethostbyname_r() takes 6 args */ /* #undef HAVE_GETHOSTBYNAME_R_6 1 */ /* Define to 1 if you have the getnameinfo function. */ /* #undef HAVE_GETNAMEINFO */ /* Define to 1 if you have the `getpass_r' function. */ /* #undef HAVE_GETPASS_R */ /* Define to 1 if you have the `getprotobyname' function. */ /* #undef HAVE_GETPROTOBYNAME */ /* Define to 1 if you have the `getpwuid' function. */ #define HAVE_GETPWUID 1 /* Define to 1 if you have the `getrlimit' function. */ /* #undef HAVE_GETRLIMIT */ /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* we have a glibc-style strerror_r() */ /* #undef HAVE_GLIBC_STRERROR_R */ #define HAVE_GLIBC_STRERROR_R 1 /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* if you have the gssapi libraries */ /* #undef HAVE_GSSAPI */ /* if you have the GNU gssapi libraries */ /* #undef HAVE_GSSGNU */ /* if you have the Heimdal gssapi libraries */ /* #undef HAVE_GSSHEIMDAL */ /* if you have the MIT gssapi libraries */ /* #undef HAVE_GSSMIT */ /* Define to 1 if you have the `iconv' functions. */ #define HAVE_ICONV 1 /* Define to 1 if you have the `idna_strerror' function. */ /* #undef HAVE_IDNA_STRERROR */ /* Define to 1 if you have the `idn_free' function. */ /* #undef HAVE_IDN_FREE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IDN_FREE_H */ /* Define to 1 if you have the `inet_addr' function. */ #define HAVE_INET_ADDR 1 /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ /* #undef HAVE_INET_NTOP */ /* Define to 1 if you have a IPv6 capable working inet_pton function. */ /* #undef HAVE_INET_PTON */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the ioctl function. */ #define HAVE_IOCTL 1 /* Define to 1 if you have a working ioctl FIONBIO function. */ #define HAVE_IOCTL_FIONBIO 1 /* Define to 1 if you have the ioctlsocket function. */ /* #undef HAVE_IOCTLSOCKET */ /* Define to 1 if you have a working ioctlsocket FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_FIONBIO */ /* Define to 1 if you have the IoctlSocket camel case function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL */ /* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IO_H */ /* if you have the Kerberos4 libraries (including -ldes) */ /* #undef HAVE_KRB4 */ /* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ /* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KRB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBGEN_H 1 */ /* Define to 1 if you have the `idn' library (-lidn). */ /* #undef HAVE_LIBIDN */ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `resolve' library (-lresolve). */ /* #undef HAVE_LIBRESOLVE */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* if zlib is available */ /* #undef HAVE_LIBZ */ /* if your compiler supports LL */ #define HAVE_LL 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if the compiler supports the 'long long' data type. */ #define HAVE_LONGLONG 1 /* Define to 1 if you need the malloc.h header file even with stdlib.h */ /* #undef NEED_MALLOC_H */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* undef HAVE_NETINET_TCP_H */ /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 /* Define if NI_WITHSCOPEID exists and works */ /* #undef HAVE_NI_WITHSCOPEID */ /* we have no strerror_r() proto */ /* #undef HAVE_NO_STRERROR_R_DECL */ /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_CRYPTO_H */ #define HAVE_OPENSSL_CRYPTO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_ERR_H */ #define HAVE_OPENSSL_ERR_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_PEM_H */ #define HAVE_OPENSSL_PEM_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_PKCS12_H */ #define HAVE_OPENSSL_PKCS12_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_RSA_H */ #define HAVE_OPENSSL_RSA_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_SSL_H */ #define HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_OPENSSL_X509_H */ #define HAVE_OPENSSL_X509_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_PEM_H */ #define HAVE_PEM_H 1 /* Define to 1 if you have the `perror' function. */ #define HAVE_PERROR 1 /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `poll' function. */ /* #undef HAVE_POLL */ /* If you have a fine poll */ /* #undef HAVE_POLL_FINE */ /* we have a POSIX-style strerror_r() */ /* #undef HAVE_POSIX_STRERROR_R */ /* Define to 1 if you have the header file. */ #define HAVE_PWD_H 1 /* Define to 1 if you have the `RAND_egd' function. */ /* #undef HAVE_RAND_EGD */ #define HAVE_RAND_EGD 1 /* Define to 1 if you have the `RAND_screen' function. */ /* #undef HAVE_RAND_SCREEN */ /* Define to 1 if you have the `RAND_status' function. */ /* #undef HAVE_RAND_STATUS */ #define HAVE_RAND_STATUS 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_RSA_H */ #define HAVE_RSA_H 1 /* Define to 1 if you have the `select' function. */ #define HAVE_SELECT 1 /* Define to 1 if you have the header file. */ #define HAVE_SETJMP_H 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the setsockopt function. */ /* #undef HAVE_SETSOCKOPT */ /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ /* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SGTTY_H 1 */ /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `siginterrupt' function. */ /* #undef HAVE_SIGINTERRUPT */ /* Define to 1 if you have the `signal' function. */ #define HAVE_SIGNAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define to 1 if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 /* Define to 1 if sig_atomic_t is already defined as volatile. */ /* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ /* If you have sigsetjmp */ /* #undef HAVE_SIGSETJMP */ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SSL_H */ #define HAVE_SSL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror_r' function. */ #define HAVE_STRERROR_R 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ #define HAVE_STRICMP 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if you have the `strtok_r' function. */ #define HAVE_STRTOK_R 1 /* Define to 1 if you have the `strtoll' function. */ #define HAVE_STRTOLL 1 /* if struct sockaddr_storage is defined */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE */ /* Define this if you have struct timeval */ #define HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKIO_H */ #define HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UTIME_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TERMIOS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TERMIO_H */ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TLD_H */ /* Define to 1 if you have the `tld_strerror' function. */ /* #undef HAVE_TLD_STRERROR */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_WINSOCK2_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_WINSOCK_H */ /* Define this symbol if your OS supports changing the contents of argv */ /* #undef HAVE_WRITABLE_ARGV */ /* Define to 1 if you have the ws2tcpip.h header file. */ /* #undef HAVE_WS2TCPIP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_X509_H */ /* if you have the zlib.h header file */ /* #undef HAVE_ZLIB_H */ /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ /* #undef NEED_REENTRANT */ /* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ /* #undef NEED_THREAD_SAFE */ /* cpu-machine-OS */ #define OS "s390x-ibm-tpf" /* Name of package */ #define PACKAGE "curl" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT \ "a suitable curl mailing list => https://curl.haxx.se/mail/" /* Define to the full name of this package. */ #define PACKAGE_NAME "curl" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "curl -" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "curl" /* Define to the version of this package. */ #define PACKAGE_VERSION "-" /* a suitable file to read random data from */ /* #undef RANDOM_FILE */ /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the type of arg 1 for `select'. */ #define SELECT_TYPE_ARG1 int /* Define to the type of args 2, 3 and 4 for `select'. */ #define SELECT_TYPE_ARG234 (fd_set *) /* Define to the type of arg 5 for `select'. */ #define SELECT_TYPE_ARG5 (struct timeval *) /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* Define to the size of `long', as computed by sizeof. */ #define SIZEOF_LONG 8 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 8 /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 8 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you want to enable ares support */ /* #undef USE_ARES */ /* Define to disable non-blocking sockets */ /* #undef USE_BLOCKING_SOCKETS */ /* if GnuTLS is enabled */ /* #undef USE_GNUTLS */ /* If you want to build curl with the built-in manual */ /* #undef USE_MANUAL */ /* if OpenSSL is in use */ /* #undef USE_OPENSSL */ /* if SSL is enabled */ /* #undef USE_OPENSSL */ /* to enable SSPI support */ /* #undef USE_WINDOWS_SSPI */ /* Version number of package */ #define VERSION "not-used" /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* type to use in place of in_addr_t if not defined */ /* #undef in_addr_t */ /* Define to `unsigned' if does not define. */ /* #undef size_t */ /* the signed version of size_t */ /* #undef ssize_t */ /* Define to 1 if you have the getnameinfo function. */ /* #undef HAVE_GETNAMEINFO 1 */ /* Define to the type qualifier of arg 1 for getnameinfo. */ /* #undef GETNAMEINFO_QUAL_ARG1 const */ /* Define to the type of arg 1 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG1 struct sockaddr * */ /* Define to the type of arg 2 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG2 socklen_t */ /* Define to the type of args 4 and 6 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG46 size_t */ /* Define to the type of arg 7 for getnameinfo. */ /* #undef GETNAMEINFO_TYPE_ARG7 int */ /* Define to 1 if you have the recv function. */ #define HAVE_RECV 1 /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 int /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 char * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 int /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV int /* Define to 1 if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 int /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 char /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 int /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 int /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV int /* Define to 1 if you have the send function. */ #define HAVE_SEND 1 /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 int /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 const /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 char * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 int /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV int #define CURL_DOES_CONVERSIONS #ifndef CURL_ICONV_CODESET_OF_HOST #define CURL_ICONV_CODESET_OF_HOST "IBM-1047" #endif #endif /* HEADER_CURL_CONFIG_TPF_H */ davix-0.8.0/deps/curl/lib/curl_threads.h0000644000000000000000000000514514121063461016631 0ustar rootroot#ifndef HEADER_CURL_THREADS_H #define HEADER_CURL_THREADS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_THREADS_POSIX) # define CURL_STDCALL # define curl_mutex_t pthread_mutex_t # define curl_thread_t pthread_t * # define curl_thread_t_null (pthread_t *)0 # define Curl_mutex_init(m) pthread_mutex_init(m, NULL) # define Curl_mutex_acquire(m) pthread_mutex_lock(m) # define Curl_mutex_release(m) pthread_mutex_unlock(m) # define Curl_mutex_destroy(m) pthread_mutex_destroy(m) #elif defined(USE_THREADS_WIN32) # define CURL_STDCALL __stdcall # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 # if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) # define Curl_mutex_init(m) InitializeCriticalSection(m) # else # define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) # endif # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) #endif #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) /* !checksrc! disable SPACEBEFOREPAREN 1 */ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), void *arg); void Curl_thread_destroy(curl_thread_t hnd); int Curl_thread_join(curl_thread_t *hnd); #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ #endif /* HEADER_CURL_THREADS_H */ davix-0.8.0/deps/curl/lib/Makefile.inc0000644000000000000000000001200414121063461016201 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ vauth/spnego_gssapi.c vauth/spnego_sspi.c LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \ vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \ vtls/mesalink.c vtls/bearssl.c LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \ vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \ vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \ vtls/bearssl.h LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c LIB_VSSH_HFILES = vssh/ssh.h LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ curl_addrinfo.c socks_gssapi.c socks_sspi.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ curl_multibyte.c hostcheck.c conncache.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \ doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ socks.h curl_base64.h curl_addrinfo.h curl_sspi.h \ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h dotdot.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \ curl_get_line.h altsvc.h quic.h socketpair.h rename.h LIB_RCFILES = libcurl.rc CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \ $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \ $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES) davix-0.8.0/deps/curl/lib/curl_sha256.h0000644000000000000000000000253414121063461016206 0ustar rootroot#ifndef HEADER_CURL_SHA256_H #define HEADER_CURL_SHA256_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2017, Florin Petriuc, * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH #define SHA256_DIGEST_LENGTH 32 void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, const size_t len); #endif #endif /* HEADER_CURL_SHA256_H */ davix-0.8.0/deps/curl/lib/http_digest.h0000644000000000000000000000334414121063461016467 0ustar rootroot#ifndef HEADER_CURL_HTTP_DIGEST_H #define HEADER_CURL_HTTP_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) /* this is for digest header input */ CURLcode Curl_input_digest(struct connectdata *conn, bool proxy, const char *header); /* this is for creating digest header output */ CURLcode Curl_output_digest(struct connectdata *conn, bool proxy, const unsigned char *request, const unsigned char *uripath); void Curl_http_auth_cleanup_digest(struct Curl_easy *data); #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_CRYPTO_AUTH */ #endif /* HEADER_CURL_HTTP_DIGEST_H */ davix-0.8.0/deps/curl/lib/curl_range.h0000644000000000000000000000227214121063461016271 0ustar rootroot#ifndef HEADER_CURL_RANGE_H #define HEADER_CURL_RANGE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" CURLcode Curl_range(struct connectdata *conn); #endif /* HEADER_CURL_RANGE_H */ davix-0.8.0/deps/curl/lib/curl_ntlm_core.c0000644000000000000000000005253414121063461017160 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_NTLM) /* * NTLM details: * * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ /* Please keep the SSL backend-specific #if branches in this order: 1. USE_OPENSSL 2. USE_GNUTLS_NETTLE 3. USE_GNUTLS 4. USE_NSS 5. USE_MBEDTLS 6. USE_SECTRANSP 7. USE_OS400CRYPTO 8. USE_WIN32_CRYPTO This ensures that: - the same SSL branch gets activated throughout this source file even if multiple backends are enabled at the same time. - OpenSSL and NSS have higher priority than Windows Crypt, due to issues with the latter supporting NTLM2Session responses in NTLM type-3 messages. */ #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) #ifdef USE_OPENSSL # include # include # include # include # if (OPENSSL_VERSION_NUMBER < 0x00907001L) # define DES_key_schedule des_key_schedule # define DES_cblock des_cblock # define DES_set_odd_parity des_set_odd_parity # define DES_set_key des_set_key # define DES_ecb_encrypt des_ecb_encrypt # define DESKEY(x) x # define DESKEYARG(x) x # else # define DESKEYARG(x) *x # define DESKEY(x) &x # endif #elif defined(USE_GNUTLS_NETTLE) # include #elif defined(USE_GNUTLS) # include # define MD5_DIGEST_LENGTH 16 #elif defined(USE_NSS) # include # include # include # define MD5_DIGEST_LENGTH MD5_LENGTH #elif defined(USE_MBEDTLS) # include # include "curl_md4.h" #elif defined(USE_SECTRANSP) # include # include #elif defined(USE_OS400CRYPTO) # include "cipher.mih" /* mih/cipher */ #elif defined(USE_WIN32_CRYPTO) # include #else # error "Can't compile NTLM support without a crypto library." #endif #include "urldata.h" #include "non-ascii.h" #include "strcase.h" #include "curl_ntlm_core.h" #include "curl_md5.h" #include "curl_hmac.h" #include "warnless.h" #include "curl_endian.h" #include "curl_des.h" #include "curl_md4.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" #define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) /* * Turns a 56-bit key into being 64-bit wide. */ static void extend_key_56_to_64(const unsigned char *key_56, char *key) { key[0] = key_56[0]; key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); } #ifdef USE_OPENSSL /* * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The * key schedule ks is also set. */ static void setup_des_key(const unsigned char *key_56, DES_key_schedule DESKEYARG(ks)) { DES_cblock key; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, (char *) &key); /* Set the key parity to odd */ DES_set_odd_parity(&key); /* Set the key */ DES_set_key(&key, ks); } #elif defined(USE_GNUTLS_NETTLE) static void setup_des_key(const unsigned char *key_56, struct des_ctx *des) { char key[8]; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); /* Set the key */ des_set_key(des, (const uint8_t *) key); } #elif defined(USE_GNUTLS) /* * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. */ static void setup_des_key(const unsigned char *key_56, gcry_cipher_hd_t *des) { char key[8]; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); /* Set the key */ gcry_cipher_setkey(*des, key, sizeof(key)); } #elif defined(USE_NSS) /* * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using * the expanded key. The caller is responsible for giving 64 bit of valid * data is IN and (at least) 64 bit large buffer as OUT. */ static bool encrypt_des(const unsigned char *in, unsigned char *out, const unsigned char *key_56) { const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ char key[8]; /* expanded 64 bit key */ SECItem key_item; PK11SymKey *symkey = NULL; SECItem *param = NULL; PK11Context *ctx = NULL; int out_len; /* not used, required by NSS */ bool rv = FALSE; /* use internal slot for DES encryption (requires NSS to be initialized) */ PK11SlotInfo *slot = PK11_GetInternalKeySlot(); if(!slot) return FALSE; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); /* Import the key */ key_item.data = (unsigned char *)key; key_item.len = sizeof(key); symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); if(!symkey) goto fail; /* Create the DES encryption context */ param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); if(!param) goto fail; ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); if(!ctx) goto fail; /* Perform the encryption */ if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, (unsigned char *)in, /* inbuflen */ 8) && SECSuccess == PK11_Finalize(ctx)) rv = /* all OK */ TRUE; fail: /* cleanup */ if(ctx) PK11_DestroyContext(ctx, PR_TRUE); if(symkey) PK11_FreeSymKey(symkey); if(param) SECITEM_FreeItem(param, PR_TRUE); PK11_FreeSlot(slot); return rv; } #elif defined(USE_MBEDTLS) static bool encrypt_des(const unsigned char *in, unsigned char *out, const unsigned char *key_56) { mbedtls_des_context ctx; char key[8]; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); /* Set the key parity to odd */ mbedtls_des_key_set_parity((unsigned char *) key); /* Perform the encryption */ mbedtls_des_init(&ctx); mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; } #elif defined(USE_SECTRANSP) static bool encrypt_des(const unsigned char *in, unsigned char *out, const unsigned char *key_56) { char key[8]; size_t out_len; CCCryptorStatus err; /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); /* Perform the encryption */ err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, 8 /* outbuflen */, &out_len); return err == kCCSuccess; } #elif defined(USE_OS400CRYPTO) static bool encrypt_des(const unsigned char *in, unsigned char *out, const unsigned char *key_56) { char key[8]; _CIPHER_Control_T ctl; /* Setup the cipher control structure */ ctl.Func_ID = ENCRYPT_ONLY; ctl.Data_Len = sizeof(key); /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, ctl.Crypto_Key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len); /* Perform the encryption */ _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in); return TRUE; } #elif defined(USE_WIN32_CRYPTO) static bool encrypt_des(const unsigned char *in, unsigned char *out, const unsigned char *key_56) { HCRYPTPROV hprov; HCRYPTKEY hkey; struct { BLOBHEADER hdr; unsigned int len; char key[8]; } blob; DWORD len = 8; /* Acquire the crypto provider */ if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return FALSE; /* Setup the key blob structure */ memset(&blob, 0, sizeof(blob)); blob.hdr.bType = PLAINTEXTKEYBLOB; blob.hdr.bVersion = 2; blob.hdr.aiKeyAlg = CALG_DES; blob.len = sizeof(blob.key); /* Expand the 56-bit key to 64-bits */ extend_key_56_to_64(key_56, blob.key); /* Set the key parity to odd */ Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key)); /* Import the key */ if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) { CryptReleaseContext(hprov, 0); return FALSE; } memcpy(out, in, 8); /* Perform the encryption */ CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len); CryptDestroyKey(hkey); CryptReleaseContext(hprov, 0); return TRUE; } #endif /* defined(USE_WIN32_CRYPTO) */ /* * takes a 21 byte array and treats it as 3 56-bit DES keys. The * 8 byte plaintext is encrypted with each key and the resulting 24 * bytes are stored in the results array. */ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results) { #ifdef USE_OPENSSL DES_key_schedule ks; setup_des_key(keys, DESKEY(ks)); DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, DESKEY(ks), DES_ENCRYPT); setup_des_key(keys + 7, DESKEY(ks)); DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), DESKEY(ks), DES_ENCRYPT); setup_des_key(keys + 14, DESKEY(ks)); DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), DESKEY(ks), DES_ENCRYPT); #elif defined(USE_GNUTLS_NETTLE) struct des_ctx des; setup_des_key(keys, &des); des_encrypt(&des, 8, results, plaintext); setup_des_key(keys + 7, &des); des_encrypt(&des, 8, results + 8, plaintext); setup_des_key(keys + 14, &des); des_encrypt(&des, 8, results + 16, plaintext); #elif defined(USE_GNUTLS) gcry_cipher_hd_t des; gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); setup_des_key(keys, &des); gcry_cipher_encrypt(des, results, 8, plaintext, 8); gcry_cipher_close(des); gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); setup_des_key(keys + 7, &des); gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8); gcry_cipher_close(des); gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); setup_des_key(keys + 14, &des); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_close(des); #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 16, keys + 14); #endif } /* * Set up lanmanager hashed password */ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */) { CURLcode result; unsigned char pw[14]; static const unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ }; size_t len = CURLMIN(strlen(password), 14); Curl_strntoupper((char *)pw, password, len); memset(&pw[len], 0, 14 - len); /* * The LanManager hashed password needs to be created using the * password in the network encoding not the host encoding. */ result = Curl_convert_to_network(data, (char *)pw, 14); if(result) return result; { /* Create LanManager hashed password. */ #ifdef USE_OPENSSL DES_key_schedule ks; setup_des_key(pw, DESKEY(ks)); DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, DESKEY(ks), DES_ENCRYPT); setup_des_key(pw + 7, DESKEY(ks)); DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), DESKEY(ks), DES_ENCRYPT); #elif defined(USE_GNUTLS_NETTLE) struct des_ctx des; setup_des_key(pw, &des); des_encrypt(&des, 8, lmbuffer, magic); setup_des_key(pw + 7, &des); des_encrypt(&des, 8, lmbuffer + 8, magic); #elif defined(USE_GNUTLS) gcry_cipher_hd_t des; gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); setup_des_key(pw, &des); gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); gcry_cipher_close(des); gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif memset(lmbuffer + 16, 0, 21 - 16); } return CURLE_OK; } #ifdef USE_NTRESPONSES static void ascii_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) { size_t i; for(i = 0; i < srclen; i++) { dest[2 * i] = (unsigned char)src[i]; dest[2 * i + 1] = '\0'; } } #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) static void ascii_uppercase_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) { size_t i; for(i = 0; i < srclen; i++) { dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i])); dest[2 * i + 1] = '\0'; } } #endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ /* * Set up nt hashed passwords * @unittest: 1600 */ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */) { size_t len = strlen(password); unsigned char *pw; CURLcode result; if(len > SIZE_T_MAX/2) /* avoid integer overflow */ return CURLE_OUT_OF_MEMORY; pw = len ? malloc(len * 2) : (unsigned char *)strdup(""); if(!pw) return CURLE_OUT_OF_MEMORY; ascii_to_unicode_le(pw, password, len); /* * The NT hashed password needs to be created using the password in the * network encoding not the host encoding. */ result = Curl_convert_to_network(data, (char *)pw, len * 2); if(result) return result; /* Create NT hashed password. */ Curl_md4it(ntbuffer, pw, 2 * len); memset(ntbuffer + 16, 0, 21 - 16); free(pw); return CURLE_OK; } #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode * (uppercase UserName + Domain) as the data */ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen, const char *domain, size_t domlen, unsigned char *ntlmhash, unsigned char *ntlmv2hash) { /* Unicode representation */ size_t identity_len; unsigned char *identity; CURLcode result = CURLE_OK; /* we do the length checks below separately to avoid integer overflow risk on extreme data lengths */ if((userlen > SIZE_T_MAX/2) || (domlen > SIZE_T_MAX/2) || ((userlen + domlen) > SIZE_T_MAX/2)) return CURLE_OUT_OF_MEMORY; identity_len = (userlen + domlen) * 2; identity = malloc(identity_len); if(!identity) return CURLE_OUT_OF_MEMORY; ascii_uppercase_to_unicode_le(identity, user, userlen); ascii_to_unicode_le(identity + (userlen << 1), domain, domlen); result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len, ntlmv2hash); free(identity); return result; } /* * Curl_ntlm_core_mk_ntlmv2_resp() * * This creates the NTLMv2 response as set in the ntlm type-3 message. * * Parameters: * * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) * challenge_client [in] - The client nonce (8 bytes) * ntlm [in] - The ntlm data struct being used to read TargetInfo and Server challenge received in the type-2 message * ntresp [out] - The address where a pointer to newly allocated * memory holding the NTLMv2 response. * ntresp_len [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, unsigned char *challenge_client, struct ntlmdata *ntlm, unsigned char **ntresp, unsigned int *ntresp_len) { /* NTLMv2 response structure : ------------------------------------------------------------------------------ 0 HMAC MD5 16 bytes ------BLOB-------------------------------------------------------------------- 16 Signature 0x01010000 20 Reserved long (0x00000000) 24 Timestamp LE, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. 32 Client Nonce 8 bytes 40 Unknown 4 bytes 44 Target Info N bytes (from the type-2 message) 44+N Unknown 4 bytes ------------------------------------------------------------------------------ */ unsigned int len = 0; unsigned char *ptr = NULL; unsigned char hmac_output[HMAC_MD5_LENGTH]; curl_off_t tw; CURLcode result = CURLE_OK; #if CURL_SIZEOF_CURL_OFF_T < 8 #error "this section needs 64bit support to work" #endif /* Calculate the timestamp */ #ifdef DEBUGBUILD char *force_timestamp = getenv("CURL_FORCETIME"); if(force_timestamp) tw = CURL_OFF_T_C(11644473600) * 10000000; else #endif tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000; /* Calculate the response len */ len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN; /* Allocate the response */ ptr = calloc(1, len); if(!ptr) return CURLE_OUT_OF_MEMORY; /* Create the BLOB structure */ msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN, "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ "%c%c%c%c", /* Reserved = 0 */ NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], 0, 0, 0, 0); Curl_write64_le(tw, ptr + 24); memcpy(ptr + 32, challenge_client, 8); memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len); /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */ memcpy(ptr + 8, &ntlm->nonce[0], 8); result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8, NTLMv2_BLOB_LEN + 8, hmac_output); if(result) { free(ptr); return result; } /* Concatenate the HMAC MD5 output with the BLOB */ memcpy(ptr, hmac_output, HMAC_MD5_LENGTH); /* Return the response */ *ntresp = ptr; *ntresp_len = len; return result; } /* * Curl_ntlm_core_mk_lmv2_resp() * * This creates the LMv2 response as used in the ntlm type-3 message. * * Parameters: * * ntlmv2hash [in] - The ntlmv2 hash (16 bytes) * challenge_client [in] - The client nonce (8 bytes) * challenge_client [in] - The server challenge (8 bytes) * lmresp [out] - The LMv2 response (24 bytes) * * Returns CURLE_OK on success. */ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash, unsigned char *challenge_client, unsigned char *challenge_server, unsigned char *lmresp) { unsigned char data[16]; unsigned char hmac_output[16]; CURLcode result = CURLE_OK; memcpy(&data[0], challenge_server, 8); memcpy(&data[8], challenge_client, 8); result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16, hmac_output); if(result) return result; /* Concatenate the HMAC MD5 output with the client nonce */ memcpy(lmresp, hmac_output, 16); memcpy(lmresp + 16, challenge_client, 8); return result; } #endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */ #endif /* USE_NTRESPONSES */ #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ #endif /* USE_NTLM */ davix-0.8.0/deps/curl/lib/transfer.h0000644000000000000000000000617514121063461016002 0ustar rootroot#ifndef HEADER_CURL_TRANSFER_H #define HEADER_CURL_TRANSFER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #define Curl_headersep(x) ((((x)==':') || ((x)==';'))) char *Curl_checkheaders(const struct connectdata *conn, const char *thisheader); void Curl_init_CONNECT(struct Curl_easy *data); CURLcode Curl_pretransfer(struct Curl_easy *data); CURLcode Curl_posttransfer(struct Curl_easy *data); typedef enum { FOLLOW_NONE, /* not used within the function, just a placeholder to allow initing to this */ FOLLOW_FAKE, /* only records stuff, not actually following */ FOLLOW_RETRY, /* set if this is a request retry as opposed to a real redirect following */ FOLLOW_REDIR, /* a full true redirect */ FOLLOW_LAST /* never used */ } followtype; CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); CURLcode Curl_readwrite(struct connectdata *conn, struct Curl_easy *data, bool *done, bool *comeback); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks); CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, size_t *nreadp); CURLcode Curl_retry_request(struct connectdata *conn, char **url); bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); CURLcode Curl_get_upload_buffer(struct Curl_easy *data); CURLcode Curl_done_sending(struct connectdata *conn, struct SingleRequest *k); /* This sets up a forthcoming transfer */ void Curl_setup_transfer (struct Curl_easy *data, int sockindex, /* socket index to read from or -1 */ curl_off_t size, /* -1 if unknown at this point */ bool getheader, /* TRUE if header parsing is wanted */ int writesockindex /* socket index to write to. May be the same we read from. -1 disables */ ); #endif /* HEADER_CURL_TRANSFER_H */ davix-0.8.0/deps/curl/lib/smb.c0000644000000000000000000007050414121063461014727 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel , Exacq Technologies * Copyright (C) 2016-2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ (CURL_SIZEOF_CURL_OFF_T > 4) #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) #define BUILDING_CURL_SMB_C #ifdef HAVE_PROCESS_H #include #ifdef CURL_WINDOWS_APP #define getpid GetCurrentProcessId #elif !defined(MSDOS) #define getpid _getpid #endif #endif #include "smb.h" #include "urldata.h" #include "sendf.h" #include "multiif.h" #include "connect.h" #include "progress.h" #include "transfer.h" #include "vtls/vtls.h" #include "curl_ntlm_core.h" #include "escape.h" #include "curl_endian.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* Local API functions */ static CURLcode smb_setup_connection(struct connectdata *conn); static CURLcode smb_connect(struct connectdata *conn, bool *done); static CURLcode smb_connection_state(struct connectdata *conn, bool *done); static CURLcode smb_do(struct connectdata *conn, bool *done); static CURLcode smb_request_state(struct connectdata *conn, bool *done); static CURLcode smb_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode smb_disconnect(struct connectdata *conn, bool dead); static int smb_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode smb_parse_url_path(struct connectdata *conn); /* * SMB handler interface */ const struct Curl_handler Curl_handler_smb = { "SMB", /* scheme */ smb_setup_connection, /* setup_connection */ smb_do, /* do_it */ smb_done, /* done */ ZERO_NULL, /* do_more */ smb_connect, /* connect_it */ smb_connection_state, /* connecting */ smb_request_state, /* doing */ smb_getsock, /* proto_getsock */ smb_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SMB, /* defport */ CURLPROTO_SMB, /* protocol */ PROTOPT_NONE /* flags */ }; #ifdef USE_SSL /* * SMBS handler interface */ const struct Curl_handler Curl_handler_smbs = { "SMBS", /* scheme */ smb_setup_connection, /* setup_connection */ smb_do, /* do_it */ smb_done, /* done */ ZERO_NULL, /* do_more */ smb_connect, /* connect_it */ smb_connection_state, /* connecting */ smb_request_state, /* doing */ smb_getsock, /* proto_getsock */ smb_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_SMBS, /* defport */ CURLPROTO_SMBS, /* protocol */ PROTOPT_SSL /* flags */ }; #endif #define MAX_PAYLOAD_SIZE 0x8000 #define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) #define CLIENTNAME "curl" #define SERVICENAME "?????" /* Append a string to an SMB message */ #define MSGCAT(str) \ strcpy(p, (str)); \ p += strlen(str); /* Append a null-terminated string to an SMB message */ #define MSGCATNULL(str) \ strcpy(p, (str)); \ p += strlen(str) + 1; /* SMB is mostly little endian */ #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ defined(__OS400__) static unsigned short smb_swap16(unsigned short x) { return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); } static unsigned int smb_swap32(unsigned int x) { return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff); } static curl_off_t smb_swap64(curl_off_t x) { return ((curl_off_t) smb_swap32((unsigned int) x) << 32) | smb_swap32((unsigned int) (x >> 32)); } #else # define smb_swap16(x) (x) # define smb_swap32(x) (x) # define smb_swap64(x) (x) #endif /* SMB request state */ enum smb_req_state { SMB_REQUESTING, SMB_TREE_CONNECT, SMB_OPEN, SMB_DOWNLOAD, SMB_UPLOAD, SMB_CLOSE, SMB_TREE_DISCONNECT, SMB_DONE }; /* SMB request data */ struct smb_request { enum smb_req_state state; char *path; unsigned short tid; /* Even if we connect to the same tree as another */ unsigned short fid; /* request, the tid will be different */ CURLcode result; }; static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) { struct smb_conn *smbc = &conn->proto.smbc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* For debug purposes */ static const char * const names[] = { "SMB_NOT_CONNECTED", "SMB_CONNECTING", "SMB_NEGOTIATE", "SMB_SETUP", "SMB_CONNECTED", /* LAST */ }; if(smbc->state != newstate) infof(conn->data, "SMB conn %p state change from %s to %s\n", (void *)smbc, names[smbc->state], names[newstate]); #endif smbc->state = newstate; } static void request_state(struct connectdata *conn, enum smb_req_state newstate) { struct smb_request *req = conn->data->req.protop; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* For debug purposes */ static const char * const names[] = { "SMB_REQUESTING", "SMB_TREE_CONNECT", "SMB_OPEN", "SMB_DOWNLOAD", "SMB_UPLOAD", "SMB_CLOSE", "SMB_TREE_DISCONNECT", "SMB_DONE", /* LAST */ }; if(req->state != newstate) infof(conn->data, "SMB request %p state change from %s to %s\n", (void *)req, names[req->state], names[newstate]); #endif req->state = newstate; } /* this should setup things in the connection, not in the easy handle */ static CURLcode smb_setup_connection(struct connectdata *conn) { struct smb_request *req; /* Initialize the request state */ conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); if(!req) return CURLE_OUT_OF_MEMORY; /* Parse the URL path */ return smb_parse_url_path(conn); } static CURLcode smb_connect(struct connectdata *conn, bool *done) { struct smb_conn *smbc = &conn->proto.smbc; char *slash; (void) done; /* Check we have a username and password to authenticate with */ if(!conn->bits.user_passwd) return CURLE_LOGIN_DENIED; /* Initialize the connection state */ smbc->state = SMB_CONNECTING; smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); if(!smbc->recv_buf) return CURLE_OUT_OF_MEMORY; /* Multiple requests are allowed with this connection */ connkeep(conn, "SMB default"); /* Parse the username, domain, and password */ slash = strchr(conn->user, '/'); if(!slash) slash = strchr(conn->user, '\\'); if(slash) { smbc->user = slash + 1; smbc->domain = strdup(conn->user); if(!smbc->domain) return CURLE_OUT_OF_MEMORY; smbc->domain[slash - conn->user] = 0; } else { smbc->user = conn->user; smbc->domain = strdup(conn->host.name); if(!smbc->domain) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } static CURLcode smb_recv_message(struct connectdata *conn, void **msg) { struct smb_conn *smbc = &conn->proto.smbc; char *buf = smbc->recv_buf; ssize_t bytes_read; size_t nbt_size; size_t msg_size; size_t len = MAX_MESSAGE_SIZE - smbc->got; CURLcode result; result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); if(result) return result; if(!bytes_read) return CURLE_OK; smbc->got += bytes_read; /* Check for a 32-bit nbt header */ if(smbc->got < sizeof(unsigned int)) return CURLE_OK; nbt_size = Curl_read16_be((const unsigned char *) (buf + sizeof(unsigned short))) + sizeof(unsigned int); if(smbc->got < nbt_size) return CURLE_OK; msg_size = sizeof(struct smb_header); if(nbt_size >= msg_size + 1) { /* Add the word count */ msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); if(nbt_size >= msg_size + sizeof(unsigned short)) { /* Add the byte count */ msg_size += sizeof(unsigned short) + Curl_read16_le((const unsigned char *)&buf[msg_size]); if(nbt_size < msg_size) return CURLE_READ_ERROR; } } *msg = buf; return CURLE_OK; } static void smb_pop_message(struct connectdata *conn) { struct smb_conn *smbc = &conn->proto.smbc; smbc->got = 0; } static void smb_format_message(struct connectdata *conn, struct smb_header *h, unsigned char cmd, size_t len) { struct smb_conn *smbc = &conn->proto.smbc; struct smb_request *req = conn->data->req.protop; unsigned int pid; memset(h, 0, sizeof(*h)); h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + len)); memcpy((char *)h->magic, "\xffSMB", 4); h->command = cmd; h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); h->uid = smb_swap16(smbc->uid); h->tid = smb_swap16(req->tid); pid = getpid(); h->pid_high = smb_swap16((unsigned short)(pid >> 16)); h->pid = smb_swap16((unsigned short) pid); } static CURLcode smb_send(struct connectdata *conn, ssize_t len, size_t upload_size) { struct smb_conn *smbc = &conn->proto.smbc; ssize_t bytes_written; CURLcode result; result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf, len, &bytes_written); if(result) return result; if(bytes_written != len) { smbc->send_size = len; smbc->sent = bytes_written; } smbc->upload_size = upload_size; return CURLE_OK; } static CURLcode smb_flush(struct connectdata *conn) { struct smb_conn *smbc = &conn->proto.smbc; ssize_t bytes_written; ssize_t len = smbc->send_size - smbc->sent; CURLcode result; if(!smbc->send_size) return CURLE_OK; result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf + smbc->sent, len, &bytes_written); if(result) return result; if(bytes_written != len) smbc->sent += bytes_written; else smbc->send_size = 0; return CURLE_OK; } static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd, const void *msg, size_t msg_len) { CURLcode result = Curl_get_upload_buffer(conn->data); if(result) return result; smb_format_message(conn, (struct smb_header *)conn->data->state.ulbuf, cmd, msg_len); memcpy(conn->data->state.ulbuf + sizeof(struct smb_header), msg, msg_len); return smb_send(conn, sizeof(struct smb_header) + msg_len, 0); } static CURLcode smb_send_negotiate(struct connectdata *conn) { const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15); } static CURLcode smb_send_setup(struct connectdata *conn) { struct smb_conn *smbc = &conn->proto.smbc; struct smb_setup msg; char *p = msg.bytes; unsigned char lm_hash[21]; unsigned char lm[24]; unsigned char nt_hash[21]; unsigned char nt[24]; size_t byte_count = sizeof(lm) + sizeof(nt); byte_count += strlen(smbc->user) + strlen(smbc->domain); byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ if(byte_count > sizeof(msg.bytes)) return CURLE_FILESIZE_EXCEEDED; Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); #ifdef USE_NTRESPONSES Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); #else memset(nt, 0, sizeof(nt)); #endif memset(&msg, 0, sizeof(msg)); msg.word_count = SMB_WC_SETUP_ANDX; msg.andx.command = SMB_COM_NO_ANDX_COMMAND; msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); msg.max_mpx_count = smb_swap16(1); msg.vc_number = smb_swap16(1); msg.session_key = smb_swap32(smbc->session_key); msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); msg.lengths[0] = smb_swap16(sizeof(lm)); msg.lengths[1] = smb_swap16(sizeof(nt)); memcpy(p, lm, sizeof(lm)); p += sizeof(lm); memcpy(p, nt, sizeof(nt)); p += sizeof(nt); MSGCATNULL(smbc->user); MSGCATNULL(smbc->domain); MSGCATNULL(OS); MSGCATNULL(CLIENTNAME); byte_count = p - msg.bytes; msg.byte_count = smb_swap16((unsigned short)byte_count); return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg, sizeof(msg) - sizeof(msg.bytes) + byte_count); } static CURLcode smb_send_tree_connect(struct connectdata *conn) { struct smb_tree_connect msg; struct smb_conn *smbc = &conn->proto.smbc; char *p = msg.bytes; size_t byte_count = strlen(conn->host.name) + strlen(smbc->share); byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ if(byte_count > sizeof(msg.bytes)) return CURLE_FILESIZE_EXCEEDED; memset(&msg, 0, sizeof(msg)); msg.word_count = SMB_WC_TREE_CONNECT_ANDX; msg.andx.command = SMB_COM_NO_ANDX_COMMAND; msg.pw_len = 0; MSGCAT("\\\\"); MSGCAT(conn->host.name); MSGCAT("\\"); MSGCATNULL(smbc->share); MSGCATNULL(SERVICENAME); /* Match any type of service */ byte_count = p - msg.bytes; msg.byte_count = smb_swap16((unsigned short)byte_count); return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg, sizeof(msg) - sizeof(msg.bytes) + byte_count); } static CURLcode smb_send_open(struct connectdata *conn) { struct smb_request *req = conn->data->req.protop; struct smb_nt_create msg; size_t byte_count; if((strlen(req->path) + 1) > sizeof(msg.bytes)) return CURLE_FILESIZE_EXCEEDED; memset(&msg, 0, sizeof(msg)); msg.word_count = SMB_WC_NT_CREATE_ANDX; msg.andx.command = SMB_COM_NO_ANDX_COMMAND; byte_count = strlen(req->path); msg.name_length = smb_swap16((unsigned short)byte_count); msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); if(conn->data->set.upload) { msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); } else { msg.access = smb_swap32(SMB_GENERIC_READ); msg.create_disposition = smb_swap32(SMB_FILE_OPEN); } msg.byte_count = smb_swap16((unsigned short) ++byte_count); strcpy(msg.bytes, req->path); return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg, sizeof(msg) - sizeof(msg.bytes) + byte_count); } static CURLcode smb_send_close(struct connectdata *conn) { struct smb_request *req = conn->data->req.protop; struct smb_close msg; memset(&msg, 0, sizeof(msg)); msg.word_count = SMB_WC_CLOSE; msg.fid = smb_swap16(req->fid); return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg)); } static CURLcode smb_send_tree_disconnect(struct connectdata *conn) { struct smb_tree_disconnect msg; memset(&msg, 0, sizeof(msg)); return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); } static CURLcode smb_send_read(struct connectdata *conn) { struct smb_request *req = conn->data->req.protop; curl_off_t offset = conn->data->req.offset; struct smb_read msg; memset(&msg, 0, sizeof(msg)); msg.word_count = SMB_WC_READ_ANDX; msg.andx.command = SMB_COM_NO_ANDX_COMMAND; msg.fid = smb_swap16(req->fid); msg.offset = smb_swap32((unsigned int) offset); msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg)); } static CURLcode smb_send_write(struct connectdata *conn) { struct smb_write *msg; struct smb_request *req = conn->data->req.protop; curl_off_t offset = conn->data->req.offset; curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount; CURLcode result = Curl_get_upload_buffer(conn->data); if(result) return result; msg = (struct smb_write *)conn->data->state.ulbuf; if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ upload_size = MAX_PAYLOAD_SIZE - 1; memset(msg, 0, sizeof(*msg)); msg->word_count = SMB_WC_WRITE_ANDX; msg->andx.command = SMB_COM_NO_ANDX_COMMAND; msg->fid = smb_swap16(req->fid); msg->offset = smb_swap32((unsigned int) offset); msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); msg->data_length = smb_swap16((unsigned short) upload_size); msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX, sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); return smb_send(conn, sizeof(*msg), (size_t) upload_size); } static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) { struct smb_conn *smbc = &conn->proto.smbc; CURLcode result; *msg = NULL; /* if it returns early */ /* Check if there is data in the transfer buffer */ if(!smbc->send_size && smbc->upload_size) { size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ? conn->data->set.upload_buffer_size : smbc->upload_size; conn->data->req.upload_fromhere = conn->data->state.ulbuf; result = Curl_fillreadbuffer(conn, nread, &nread); if(result && result != CURLE_AGAIN) return result; if(!nread) return CURLE_OK; smbc->upload_size -= nread; smbc->send_size = nread; smbc->sent = 0; } /* Check if there is data to send */ if(smbc->send_size) { result = smb_flush(conn); if(result) return result; } /* Check if there is still data to be sent */ if(smbc->send_size || smbc->upload_size) return CURLE_AGAIN; return smb_recv_message(conn, msg); } static CURLcode smb_connection_state(struct connectdata *conn, bool *done) { struct smb_conn *smbc = &conn->proto.smbc; struct smb_negotiate_response *nrsp; struct smb_header *h; CURLcode result; void *msg = NULL; if(smbc->state == SMB_CONNECTING) { #ifdef USE_SSL if((conn->handler->flags & PROTOPT_SSL)) { bool ssl_done = FALSE; result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done); if(result && result != CURLE_AGAIN) return result; if(!ssl_done) return CURLE_OK; } #endif result = smb_send_negotiate(conn); if(result) { connclose(conn, "SMB: failed to send negotiate message"); return result; } conn_state(conn, SMB_NEGOTIATE); } /* Send the previous message and check for a response */ result = smb_send_and_recv(conn, &msg); if(result && result != CURLE_AGAIN) { connclose(conn, "SMB: failed to communicate"); return result; } if(!msg) return CURLE_OK; h = msg; switch(smbc->state) { case SMB_NEGOTIATE: if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) || h->status) { connclose(conn, "SMB: negotiation failed"); return CURLE_COULDNT_CONNECT; } nrsp = msg; memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); smbc->session_key = smb_swap32(nrsp->session_key); result = smb_send_setup(conn); if(result) { connclose(conn, "SMB: failed to send setup message"); return result; } conn_state(conn, SMB_SETUP); break; case SMB_SETUP: if(h->status) { connclose(conn, "SMB: authentication failed"); return CURLE_LOGIN_DENIED; } smbc->uid = smb_swap16(h->uid); conn_state(conn, SMB_CONNECTED); *done = true; break; default: smb_pop_message(conn); return CURLE_OK; /* ignore */ } smb_pop_message(conn); return CURLE_OK; } /* * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601) * to Posix time. Cap the output to fit within a time_t. */ static void get_posix_time(time_t *out, curl_off_t timestamp) { timestamp -= 116444736000000000; timestamp /= 10000000; #if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T if(timestamp > TIME_T_MAX) *out = TIME_T_MAX; else if(timestamp < TIME_T_MIN) *out = TIME_T_MIN; else #endif *out = (time_t) timestamp; } static CURLcode smb_request_state(struct connectdata *conn, bool *done) { struct smb_request *req = conn->data->req.protop; struct smb_header *h; struct smb_conn *smbc = &conn->proto.smbc; enum smb_req_state next_state = SMB_DONE; unsigned short len; unsigned short off; CURLcode result; void *msg = NULL; const struct smb_nt_create_response *smb_m; /* Start the request */ if(req->state == SMB_REQUESTING) { result = smb_send_tree_connect(conn); if(result) { connclose(conn, "SMB: failed to send tree connect message"); return result; } request_state(conn, SMB_TREE_CONNECT); } /* Send the previous message and check for a response */ result = smb_send_and_recv(conn, &msg); if(result && result != CURLE_AGAIN) { connclose(conn, "SMB: failed to communicate"); return result; } if(!msg) return CURLE_OK; h = msg; switch(req->state) { case SMB_TREE_CONNECT: if(h->status) { req->result = CURLE_REMOTE_FILE_NOT_FOUND; if(h->status == smb_swap32(SMB_ERR_NOACCESS)) req->result = CURLE_REMOTE_ACCESS_DENIED; break; } req->tid = smb_swap16(h->tid); next_state = SMB_OPEN; break; case SMB_OPEN: if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { req->result = CURLE_REMOTE_FILE_NOT_FOUND; if(h->status == smb_swap32(SMB_ERR_NOACCESS)) req->result = CURLE_REMOTE_ACCESS_DENIED; next_state = SMB_TREE_DISCONNECT; break; } smb_m = (const struct smb_nt_create_response*) msg; req->fid = smb_swap16(smb_m->fid); conn->data->req.offset = 0; if(conn->data->set.upload) { conn->data->req.size = conn->data->state.infilesize; Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); next_state = SMB_UPLOAD; } else { smb_m = (const struct smb_nt_create_response*) msg; conn->data->req.size = smb_swap64(smb_m->end_of_file); if(conn->data->req.size < 0) { req->result = CURLE_WEIRD_SERVER_REPLY; next_state = SMB_CLOSE; } else { Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); if(conn->data->set.get_filetime) get_posix_time(&conn->data->info.filetime, smb_m->last_change_time); next_state = SMB_DOWNLOAD; } } break; case SMB_DOWNLOAD: if(h->status || smbc->got < sizeof(struct smb_header) + 14) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; } len = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 11); off = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 13); if(len > 0) { if(off + sizeof(unsigned int) + len > smbc->got) { failf(conn->data, "Invalid input packet"); result = CURLE_RECV_ERROR; } else result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)msg + off + sizeof(unsigned int), len); if(result) { req->result = result; next_state = SMB_CLOSE; break; } } conn->data->req.bytecount += len; conn->data->req.offset += len; Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; break; case SMB_UPLOAD: if(h->status || smbc->got < sizeof(struct smb_header) + 6) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; } len = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 5); conn->data->req.bytecount += len; conn->data->req.offset += len; Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); if(conn->data->req.bytecount >= conn->data->req.size) next_state = SMB_CLOSE; else next_state = SMB_UPLOAD; break; case SMB_CLOSE: /* We don't care if the close failed, proceed to tree disconnect anyway */ next_state = SMB_TREE_DISCONNECT; break; case SMB_TREE_DISCONNECT: next_state = SMB_DONE; break; default: smb_pop_message(conn); return CURLE_OK; /* ignore */ } smb_pop_message(conn); switch(next_state) { case SMB_OPEN: result = smb_send_open(conn); break; case SMB_DOWNLOAD: result = smb_send_read(conn); break; case SMB_UPLOAD: result = smb_send_write(conn); break; case SMB_CLOSE: result = smb_send_close(conn); break; case SMB_TREE_DISCONNECT: result = smb_send_tree_disconnect(conn); break; case SMB_DONE: result = req->result; *done = true; break; default: break; } if(result) { connclose(conn, "SMB: failed to send message"); return result; } request_state(conn, next_state); return CURLE_OK; } static CURLcode smb_done(struct connectdata *conn, CURLcode status, bool premature) { (void) premature; Curl_safefree(conn->data->req.protop); return status; } static CURLcode smb_disconnect(struct connectdata *conn, bool dead) { struct smb_conn *smbc = &conn->proto.smbc; (void) dead; Curl_safefree(smbc->share); Curl_safefree(smbc->domain); Curl_safefree(smbc->recv_buf); return CURLE_OK; } static int smb_getsock(struct connectdata *conn, curl_socket_t *socks) { socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); } static CURLcode smb_do(struct connectdata *conn, bool *done) { struct smb_conn *smbc = &conn->proto.smbc; *done = FALSE; if(smbc->share) { return CURLE_OK; } return CURLE_URL_MALFORMAT; } static CURLcode smb_parse_url_path(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct smb_request *req = data->req.protop; struct smb_conn *smbc = &conn->proto.smbc; char *path; char *slash; /* URL decode the path */ CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, TRUE); if(result) return result; /* Parse the path for the share */ smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); free(path); if(!smbc->share) return CURLE_OUT_OF_MEMORY; slash = strchr(smbc->share, '/'); if(!slash) slash = strchr(smbc->share, '\\'); /* The share must be present */ if(!slash) { Curl_safefree(smbc->share); return CURLE_URL_MALFORMAT; } /* Parse the path for the file path converting any forward slashes into backslashes */ *slash++ = 0; req->path = slash; for(; *slash; slash++) { if(*slash == '/') *slash = '\\'; } return CURLE_OK; } #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ #endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ davix-0.8.0/deps/curl/lib/curl_range.c0000644000000000000000000000626114121063461016266 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "curl_range.h" #include "sendf.h" #include "strtoofft.h" /* Only include this function if one or more of FTP, FILE are enabled. */ #if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE) /* Check if this is a range download, and if so, set the internal variables properly. */ CURLcode Curl_range(struct connectdata *conn) { curl_off_t from, to; char *ptr; char *ptr2; struct Curl_easy *data = conn->data; if(data->state.use_range && data->state.range) { CURLofft from_t; CURLofft to_t; from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; if((to_t == CURL_OFFT_INVAL) && !from_t) { /* X - */ data->state.resume_from = from; DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n", from)); } else if((from_t == CURL_OFFT_INVAL) && !to_t) { /* -Y */ data->req.maxdownload = to; data->state.resume_from = -to; DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n", to)); } else { /* X-Y */ curl_off_t totalsize; /* Ensure the range is sensible - to should follow from. */ if(from > to) return CURLE_RANGE_ERROR; totalsize = to - from; if(totalsize == CURL_OFF_T_MAX) return CURLE_RANGE_ERROR; data->req.maxdownload = totalsize + 1; /* include last byte */ data->state.resume_from = from; DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, data->req.maxdownload)); } DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T " to %" CURL_FORMAT_CURL_OFF_T ", totally %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, to, data->req.maxdownload)); } else data->req.maxdownload = -1; return CURLE_OK; } #endif davix-0.8.0/deps/curl/lib/setup-os400.h0000644000000000000000000002453614121063461016162 0ustar rootroot#ifndef HEADER_CURL_SETUP_OS400_H #define HEADER_CURL_SETUP_OS400_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* OS/400 netdb.h does not define NI_MAXHOST. */ #define NI_MAXHOST 1025 /* OS/400 netdb.h does not define NI_MAXSERV. */ #define NI_MAXSERV 32 /* No OS/400 header file defines u_int32_t. */ typedef unsigned long u_int32_t; /* System API wrapper prototypes & definitions to support ASCII parameters. */ #include #include #include #include #include extern int Curl_getaddrinfo_a(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); #define getaddrinfo Curl_getaddrinfo_a extern int Curl_getnameinfo_a(const struct sockaddr *sa, curl_socklen_t salen, char *nodename, curl_socklen_t nodenamelen, char *servname, curl_socklen_t servnamelen, int flags); #define getnameinfo Curl_getnameinfo_a /* GSKit wrappers. */ extern int Curl_gsk_environment_open(gsk_handle * my_env_handle); #define gsk_environment_open Curl_gsk_environment_open extern int Curl_gsk_secure_soc_open(gsk_handle my_env_handle, gsk_handle * my_session_handle); #define gsk_secure_soc_open Curl_gsk_secure_soc_open extern int Curl_gsk_environment_close(gsk_handle * my_env_handle); #define gsk_environment_close Curl_gsk_environment_close extern int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle); #define gsk_secure_soc_close Curl_gsk_secure_soc_close extern int Curl_gsk_environment_init(gsk_handle my_env_handle); #define gsk_environment_init Curl_gsk_environment_init extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle); #define gsk_secure_soc_init Curl_gsk_secure_soc_init extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, const char *buffer, int bufSize); #define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a extern int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID, GSK_ENUM_VALUE enumValue); #define gsk_attribute_set_enum Curl_gsk_attribute_set_enum extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle, GSK_NUM_ID numID, int numValue); #define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle, GSK_CALLBACK_ID callBackID, void *callBackAreaPtr); #define gsk_attribute_set_callback Curl_gsk_attribute_set_callback extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, const char **buffer, int *bufSize); #define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID, GSK_ENUM_VALUE *enumValue); #define gsk_attribute_get_enum Curl_gsk_attribute_get_enum extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle, GSK_NUM_ID numID, int *numValue); #define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle, GSK_CERT_ID certID, const gsk_cert_data_elem **certDataElem, int *certDataElementCount); #define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, GSK_MISC_ID miscID); #define gsk_secure_soc_misc Curl_gsk_secure_soc_misc extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle, char *readBuffer, int readBufSize, int *amtRead); #define gsk_secure_soc_read Curl_gsk_secure_soc_read extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle, char *writeBuffer, int writeBufSize, int *amtWritten); #define gsk_secure_soc_write Curl_gsk_secure_soc_write extern const char * Curl_gsk_strerror_a(int gsk_return_value); #define gsk_strerror Curl_gsk_strerror_a extern int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle, int IOCompletionPort, Qso_OverlappedIO_t * communicationsArea); #define gsk_secure_soc_startInit Curl_gsk_secure_soc_startInit /* GSSAPI wrappers. */ extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status, gss_buffer_t in_name, gss_OID in_name_type, gss_name_t * out_name); #define gss_import_name Curl_gss_import_name_a extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status, OM_uint32 status_value, int status_type, gss_OID mech_type, gss_msg_ctx_t * message_context, gss_buffer_t status_string); #define gss_display_status Curl_gss_display_status_a extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status, gss_cred_id_t cred_handle, gss_ctx_id_t * context_handle, gss_name_t target_name, gss_OID mech_type, gss_flags_t req_flags, OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, gss_flags_t * ret_flags, OM_uint32 * time_rec); #define gss_init_sec_context Curl_gss_init_sec_context_a extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, gss_buffer_t output_token); #define gss_delete_sec_context Curl_gss_delete_sec_context_a /* LDAP wrappers. */ #define BerValue struct berval #define ldap_url_parse ldap_url_parse_utf8 #define ldap_init Curl_ldap_init_a #define ldap_simple_bind_s Curl_ldap_simple_bind_s_a #define ldap_search_s Curl_ldap_search_s_a #define ldap_get_values_len Curl_ldap_get_values_len_a #define ldap_err2string Curl_ldap_err2string_a #define ldap_get_dn Curl_ldap_get_dn_a #define ldap_first_attribute Curl_ldap_first_attribute_a #define ldap_next_attribute Curl_ldap_next_attribute_a /* Some socket functions must be wrapped to process textual addresses like AF_UNIX. */ extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen); extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen); extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, struct sockaddr * dstaddr, int addrlen); extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, struct sockaddr *fromaddr, int *addrlen); extern int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen); extern int Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen); #define connect Curl_os400_connect #define bind Curl_os400_bind #define sendto Curl_os400_sendto #define recvfrom Curl_os400_recvfrom #define getpeername Curl_os400_getpeername #define getsockname Curl_os400_getsockname #ifdef HAVE_LIBZ #define zlibVersion Curl_os400_zlibVersion #define inflateInit_ Curl_os400_inflateInit_ #define inflateInit2_ Curl_os400_inflateInit2_ #define inflate Curl_os400_inflate #define inflateEnd Curl_os400_inflateEnd #endif #endif /* HEADER_CURL_SETUP_OS400_H */ davix-0.8.0/deps/curl/lib/curl_des.h0000644000000000000000000000247114121063461015751 0ustar rootroot#ifndef HEADER_CURL_DES_H #define HEADER_CURL_DES_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2015 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_NTLM) && !defined(USE_OPENSSL) /* Applies odd parity to the given byte array */ void Curl_des_set_odd_parity(unsigned char *bytes, size_t length); #endif /* USE_NTLM && !USE_OPENSSL */ #endif /* HEADER_CURL_DES_H */ davix-0.8.0/deps/curl/lib/amigaos.h0000644000000000000000000000267614121063461015600 0ustar rootroot#ifndef HEADER_CURL_AMIGAOS_H #define HEADER_CURL_AMIGAOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(__AMIGA__) && defined(HAVE_BSDSOCKET_H) && !defined(USE_AMISSL) bool Curl_amiga_init(); void Curl_amiga_cleanup(); #else #define Curl_amiga_init() 1 #define Curl_amiga_cleanup() Curl_nop_stmt #endif #ifdef USE_AMISSL #include void Curl_amiga_X509_free(X509 *a); #endif /* USE_AMISSL */ #endif /* HEADER_CURL_AMIGAOS_H */ davix-0.8.0/deps/curl/lib/curl_ldap.h0000644000000000000000000000260014121063461016110 0ustar rootroot#ifndef HEADER_CURL_LDAP_H #define HEADER_CURL_LDAP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_LDAP extern const struct Curl_handler Curl_handler_ldap; #if !defined(CURL_DISABLE_LDAPS) && \ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) extern const struct Curl_handler Curl_handler_ldaps; #endif #endif #endif /* HEADER_CURL_LDAP_H */ davix-0.8.0/deps/curl/lib/ftplistparser.c0000644000000000000000000007502314121063461017051 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /** * Now implemented: * * 1) Unix version 1 * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog * 2) Unix version 2 * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog * 3) Unix version 3 * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog * 4) Unix symlink * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000 * 5) DOS style * 01-29-97 11:32PM prog */ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #include #include "urldata.h" #include "fileinfo.h" #include "llist.h" #include "strtoofft.h" #include "ftp.h" #include "ftplistparser.h" #include "curl_fnmatch.h" #include "curl_memory.h" #include "multiif.h" /* The last #include file should be: */ #include "memdebug.h" /* allocs buffer which will contain one line of LIST command response */ #define FTP_BUFFER_ALLOCSIZE 160 typedef enum { PL_UNIX_TOTALSIZE = 0, PL_UNIX_FILETYPE, PL_UNIX_PERMISSION, PL_UNIX_HLINKS, PL_UNIX_USER, PL_UNIX_GROUP, PL_UNIX_SIZE, PL_UNIX_TIME, PL_UNIX_FILENAME, PL_UNIX_SYMLINK } pl_unix_mainstate; typedef union { enum { PL_UNIX_TOTALSIZE_INIT = 0, PL_UNIX_TOTALSIZE_READING } total_dirsize; enum { PL_UNIX_HLINKS_PRESPACE = 0, PL_UNIX_HLINKS_NUMBER } hlinks; enum { PL_UNIX_USER_PRESPACE = 0, PL_UNIX_USER_PARSING } user; enum { PL_UNIX_GROUP_PRESPACE = 0, PL_UNIX_GROUP_NAME } group; enum { PL_UNIX_SIZE_PRESPACE = 0, PL_UNIX_SIZE_NUMBER } size; enum { PL_UNIX_TIME_PREPART1 = 0, PL_UNIX_TIME_PART1, PL_UNIX_TIME_PREPART2, PL_UNIX_TIME_PART2, PL_UNIX_TIME_PREPART3, PL_UNIX_TIME_PART3 } time; enum { PL_UNIX_FILENAME_PRESPACE = 0, PL_UNIX_FILENAME_NAME, PL_UNIX_FILENAME_WINDOWSEOL } filename; enum { PL_UNIX_SYMLINK_PRESPACE = 0, PL_UNIX_SYMLINK_NAME, PL_UNIX_SYMLINK_PRETARGET1, PL_UNIX_SYMLINK_PRETARGET2, PL_UNIX_SYMLINK_PRETARGET3, PL_UNIX_SYMLINK_PRETARGET4, PL_UNIX_SYMLINK_TARGET, PL_UNIX_SYMLINK_WINDOWSEOL } symlink; } pl_unix_substate; typedef enum { PL_WINNT_DATE = 0, PL_WINNT_TIME, PL_WINNT_DIRORSIZE, PL_WINNT_FILENAME } pl_winNT_mainstate; typedef union { enum { PL_WINNT_TIME_PRESPACE = 0, PL_WINNT_TIME_TIME } time; enum { PL_WINNT_DIRORSIZE_PRESPACE = 0, PL_WINNT_DIRORSIZE_CONTENT } dirorsize; enum { PL_WINNT_FILENAME_PRESPACE = 0, PL_WINNT_FILENAME_CONTENT, PL_WINNT_FILENAME_WINEOL } filename; } pl_winNT_substate; /* This struct is used in wildcard downloading - for parsing LIST response */ struct ftp_parselist_data { enum { OS_TYPE_UNKNOWN = 0, OS_TYPE_UNIX, OS_TYPE_WIN_NT } os_type; union { struct { pl_unix_mainstate main; pl_unix_substate sub; } UNIX; struct { pl_winNT_mainstate main; pl_winNT_substate sub; } NT; } state; CURLcode error; struct fileinfo *file_data; unsigned int item_length; size_t item_offset; struct { size_t filename; size_t user; size_t group; size_t time; size_t perm; size_t symlink_target; } offsets; }; struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) { return calloc(1, sizeof(struct ftp_parselist_data)); } void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp) { struct ftp_parselist_data *parser = *parserp; if(parser) Curl_fileinfo_cleanup(parser->file_data); free(parser); *parserp = NULL; } CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data) { return pl_data->error; } #define FTP_LP_MALFORMATED_PERM 0x01000000 static int ftp_pl_get_permission(const char *str) { int permissions = 0; /* USER */ if(str[0] == 'r') permissions |= 1 << 8; else if(str[0] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[1] == 'w') permissions |= 1 << 7; else if(str[1] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[2] == 'x') permissions |= 1 << 6; else if(str[2] == 's') { permissions |= 1 << 6; permissions |= 1 << 11; } else if(str[2] == 'S') permissions |= 1 << 11; else if(str[2] != '-') permissions |= FTP_LP_MALFORMATED_PERM; /* GROUP */ if(str[3] == 'r') permissions |= 1 << 5; else if(str[3] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[4] == 'w') permissions |= 1 << 4; else if(str[4] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[5] == 'x') permissions |= 1 << 3; else if(str[5] == 's') { permissions |= 1 << 3; permissions |= 1 << 10; } else if(str[5] == 'S') permissions |= 1 << 10; else if(str[5] != '-') permissions |= FTP_LP_MALFORMATED_PERM; /* others */ if(str[6] == 'r') permissions |= 1 << 2; else if(str[6] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[7] == 'w') permissions |= 1 << 1; else if(str[7] != '-') permissions |= FTP_LP_MALFORMATED_PERM; if(str[8] == 'x') permissions |= 1; else if(str[8] == 't') { permissions |= 1; permissions |= 1 << 9; } else if(str[8] == 'T') permissions |= 1 << 9; else if(str[8] != '-') permissions |= FTP_LP_MALFORMATED_PERM; return permissions; } static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, struct fileinfo *infop) { curl_fnmatch_callback compare; struct WildcardData *wc = &conn->data->wildcard; struct ftp_wc *ftpwc = wc->protdata; struct curl_llist *llist = &wc->filelist; struct ftp_parselist_data *parser = ftpwc->parser; bool add = TRUE; struct curl_fileinfo *finfo = &infop->info; /* move finfo pointers to b_data */ char *str = finfo->b_data; finfo->filename = str + parser->offsets.filename; finfo->strings.group = parser->offsets.group ? str + parser->offsets.group : NULL; finfo->strings.perm = parser->offsets.perm ? str + parser->offsets.perm : NULL; finfo->strings.target = parser->offsets.symlink_target ? str + parser->offsets.symlink_target : NULL; finfo->strings.time = str + parser->offsets.time; finfo->strings.user = parser->offsets.user ? str + parser->offsets.user : NULL; /* get correct fnmatch callback */ compare = conn->data->set.fnmatch; if(!compare) compare = Curl_fnmatch; /* filter pattern-corresponding filenames */ Curl_set_in_callback(conn->data, true); if(compare(conn->data->set.fnmatch_data, wc->pattern, finfo->filename) == 0) { /* discard symlink which is containing multiple " -> " */ if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target && (strstr(finfo->strings.target, " -> "))) { add = FALSE; } } else { add = FALSE; } Curl_set_in_callback(conn->data, false); if(add) { Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list); } else { Curl_fileinfo_cleanup(infop); } ftpwc->parser->file_data = NULL; return CURLE_OK; } size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr) { size_t bufflen = size*nmemb; struct connectdata *conn = (struct connectdata *)connptr; struct ftp_wc *ftpwc = conn->data->wildcard.protdata; struct ftp_parselist_data *parser = ftpwc->parser; struct fileinfo *infop; struct curl_fileinfo *finfo; unsigned long i = 0; CURLcode result; size_t retsize = bufflen; if(parser->error) { /* error in previous call */ /* scenario: * 1. call => OK.. * 2. call => OUT_OF_MEMORY (or other error) * 3. (last) call => is skipped RIGHT HERE and the error is hadled later * in wc_statemach() */ goto fail; } if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) { /* considering info about FILE response format */ parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ? OS_TYPE_WIN_NT : OS_TYPE_UNIX; } while(i < bufflen) { /* FSM */ char c = buffer[i]; if(!parser->file_data) { /* tmp file data is not allocated yet */ parser->file_data = Curl_fileinfo_alloc(); if(!parser->file_data) { parser->error = CURLE_OUT_OF_MEMORY; goto fail; } parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE); if(!parser->file_data->info.b_data) { parser->error = CURLE_OUT_OF_MEMORY; goto fail; } parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE; parser->item_offset = 0; parser->item_length = 0; } infop = parser->file_data; finfo = &infop->info; finfo->b_data[finfo->b_used++] = c; if(finfo->b_used >= finfo->b_size - 1) { /* if it is important, extend buffer space for file data */ char *tmp = realloc(finfo->b_data, finfo->b_size + FTP_BUFFER_ALLOCSIZE); if(tmp) { finfo->b_size += FTP_BUFFER_ALLOCSIZE; finfo->b_data = tmp; } else { Curl_fileinfo_cleanup(parser->file_data); parser->file_data = NULL; parser->error = CURLE_OUT_OF_MEMORY; goto fail; } } switch(parser->os_type) { case OS_TYPE_UNIX: switch(parser->state.UNIX.main) { case PL_UNIX_TOTALSIZE: switch(parser->state.UNIX.sub.total_dirsize) { case PL_UNIX_TOTALSIZE_INIT: if(c == 't') { parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; parser->item_length++; } else { parser->state.UNIX.main = PL_UNIX_FILETYPE; /* start FSM again not considering size of directory */ finfo->b_used = 0; continue; } break; case PL_UNIX_TOTALSIZE_READING: parser->item_length++; if(c == '\r') { parser->item_length--; finfo->b_used--; } else if(c == '\n') { finfo->b_data[parser->item_length - 1] = 0; if(strncmp("total ", finfo->b_data, 6) == 0) { char *endptr = finfo->b_data + 6; /* here we can deal with directory size, pass the leading white spaces and then the digits */ while(ISSPACE(*endptr)) endptr++; while(ISDIGIT(*endptr)) endptr++; if(*endptr != 0) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } parser->state.UNIX.main = PL_UNIX_FILETYPE; finfo->b_used = 0; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; } break; case PL_UNIX_FILETYPE: switch(c) { case '-': finfo->filetype = CURLFILETYPE_FILE; break; case 'd': finfo->filetype = CURLFILETYPE_DIRECTORY; break; case 'l': finfo->filetype = CURLFILETYPE_SYMLINK; break; case 'p': finfo->filetype = CURLFILETYPE_NAMEDPIPE; break; case 's': finfo->filetype = CURLFILETYPE_SOCKET; break; case 'c': finfo->filetype = CURLFILETYPE_DEVICE_CHAR; break; case 'b': finfo->filetype = CURLFILETYPE_DEVICE_BLOCK; break; case 'D': finfo->filetype = CURLFILETYPE_DOOR; break; default: parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } parser->state.UNIX.main = PL_UNIX_PERMISSION; parser->item_length = 0; parser->item_offset = 1; break; case PL_UNIX_PERMISSION: parser->item_length++; if(parser->item_length <= 9) { if(!strchr("rwx-tTsS", c)) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } else if(parser->item_length == 10) { unsigned int perm; if(c != ' ') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } finfo->b_data[10] = 0; /* terminate permissions */ perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset); if(perm & FTP_LP_MALFORMATED_PERM) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; parser->file_data->info.perm = perm; parser->offsets.perm = parser->item_offset; parser->item_length = 0; parser->state.UNIX.main = PL_UNIX_HLINKS; parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; } break; case PL_UNIX_HLINKS: switch(parser->state.UNIX.sub.hlinks) { case PL_UNIX_HLINKS_PRESPACE: if(c != ' ') { if(c >= '0' && c <= '9') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; case PL_UNIX_HLINKS_NUMBER: parser->item_length ++; if(c == ' ') { char *p; long int hlinks; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10); if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) { parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; parser->file_data->info.hardlinks = hlinks; } parser->item_length = 0; parser->item_offset = 0; parser->state.UNIX.main = PL_UNIX_USER; parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; } else if(c < '0' || c > '9') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; case PL_UNIX_USER: switch(parser->state.UNIX.sub.user) { case PL_UNIX_USER_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; } break; case PL_UNIX_USER_PARSING: parser->item_length++; if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.user = parser->item_offset; parser->state.UNIX.main = PL_UNIX_GROUP; parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; parser->item_offset = 0; parser->item_length = 0; } break; } break; case PL_UNIX_GROUP: switch(parser->state.UNIX.sub.group) { case PL_UNIX_GROUP_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; } break; case PL_UNIX_GROUP_NAME: parser->item_length++; if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.group = parser->item_offset; parser->state.UNIX.main = PL_UNIX_SIZE; parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; parser->item_offset = 0; parser->item_length = 0; } break; } break; case PL_UNIX_SIZE: switch(parser->state.UNIX.sub.size) { case PL_UNIX_SIZE_PRESPACE: if(c != ' ') { if(c >= '0' && c <= '9') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; case PL_UNIX_SIZE_NUMBER: parser->item_length++; if(c == ' ') { char *p; curl_off_t fsize; finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; if(!curlx_strtoofft(finfo->b_data + parser->item_offset, &p, 10, &fsize)) { if(p[0] == '\0' && fsize != CURL_OFF_T_MAX && fsize != CURL_OFF_T_MIN) { parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; parser->file_data->info.size = fsize; } parser->item_length = 0; parser->item_offset = 0; parser->state.UNIX.main = PL_UNIX_TIME; parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; } } else if(!ISDIGIT(c)) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; case PL_UNIX_TIME: switch(parser->state.UNIX.sub.time) { case PL_UNIX_TIME_PREPART1: if(c != ' ') { if(ISALNUM(c)) { parser->item_offset = finfo->b_used -1; parser->item_length = 1; parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; case PL_UNIX_TIME_PART1: parser->item_length++; if(c == ' ') { parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; } else if(!ISALNUM(c) && c != '.') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; case PL_UNIX_TIME_PREPART2: parser->item_length++; if(c != ' ') { if(ISALNUM(c)) { parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; case PL_UNIX_TIME_PART2: parser->item_length++; if(c == ' ') { parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; } else if(!ISALNUM(c) && c != '.') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; case PL_UNIX_TIME_PREPART3: parser->item_length++; if(c != ' ') { if(ISALNUM(c)) { parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } break; case PL_UNIX_TIME_PART3: parser->item_length++; if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length -1] = 0; parser->offsets.time = parser->item_offset; /* if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) { parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME; } */ if(finfo->filetype == CURLFILETYPE_SYMLINK) { parser->state.UNIX.main = PL_UNIX_SYMLINK; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; } else { parser->state.UNIX.main = PL_UNIX_FILENAME; parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; } } else if(!ISALNUM(c) && c != '.' && c != ':') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; case PL_UNIX_FILENAME: switch(parser->state.UNIX.sub.filename) { case PL_UNIX_FILENAME_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; } break; case PL_UNIX_FILENAME_NAME: parser->item_length++; if(c == '\r') { parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; } else if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } } break; case PL_UNIX_FILENAME_WINDOWSEOL: if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.filename = parser->item_offset; parser->state.UNIX.main = PL_UNIX_FILETYPE; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; case PL_UNIX_SYMLINK: switch(parser->state.UNIX.sub.symlink) { case PL_UNIX_SYMLINK_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; } break; case PL_UNIX_SYMLINK_NAME: parser->item_length++; if(c == ' ') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; } else if(c == '\r' || c == '\n') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; case PL_UNIX_SYMLINK_PRETARGET1: parser->item_length++; if(c == '-') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; } else if(c == '\r' || c == '\n') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } else { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; } break; case PL_UNIX_SYMLINK_PRETARGET2: parser->item_length++; if(c == '>') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; } else if(c == '\r' || c == '\n') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } else { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; } break; case PL_UNIX_SYMLINK_PRETARGET3: parser->item_length++; if(c == ' ') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; /* now place where is symlink following */ finfo->b_data[parser->item_offset + parser->item_length - 4] = 0; parser->offsets.filename = parser->item_offset; parser->item_length = 0; parser->item_offset = 0; } else if(c == '\r' || c == '\n') { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } else { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; } break; case PL_UNIX_SYMLINK_PRETARGET4: if(c != '\r' && c != '\n') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; parser->item_offset = finfo->b_used - 1; parser->item_length = 1; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; case PL_UNIX_SYMLINK_TARGET: parser->item_length++; if(c == '\r') { parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; } else if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } parser->state.UNIX.main = PL_UNIX_FILETYPE; } break; case PL_UNIX_SYMLINK_WINDOWSEOL: if(c == '\n') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; parser->offsets.symlink_target = parser->item_offset; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } parser->state.UNIX.main = PL_UNIX_FILETYPE; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; } break; case OS_TYPE_WIN_NT: switch(parser->state.NT.main) { case PL_WINNT_DATE: parser->item_length++; if(parser->item_length < 9) { if(!strchr("0123456789-", c)) { /* only simple control */ parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } else if(parser->item_length == 9) { if(c == ' ') { parser->state.NT.main = PL_WINNT_TIME; parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; case PL_WINNT_TIME: parser->item_length++; switch(parser->state.NT.sub.time) { case PL_WINNT_TIME_PRESPACE: if(!ISSPACE(c)) { parser->state.NT.sub.time = PL_WINNT_TIME_TIME; } break; case PL_WINNT_TIME_TIME: if(c == ' ') { parser->offsets.time = parser->item_offset; finfo->b_data[parser->item_offset + parser->item_length -1] = 0; parser->state.NT.main = PL_WINNT_DIRORSIZE; parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE; parser->item_length = 0; } else if(!strchr("APM0123456789:", c)) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; case PL_WINNT_DIRORSIZE: switch(parser->state.NT.sub.dirorsize) { case PL_WINNT_DIRORSIZE_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used - 1; parser->item_length = 1; parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT; } break; case PL_WINNT_DIRORSIZE_CONTENT: parser->item_length ++; if(c == ' ') { finfo->b_data[parser->item_offset + parser->item_length - 1] = 0; if(strcmp("", finfo->b_data + parser->item_offset) == 0) { finfo->filetype = CURLFILETYPE_DIRECTORY; finfo->size = 0; } else { char *endptr; if(curlx_strtoofft(finfo->b_data + parser->item_offset, &endptr, 10, &finfo->size)) { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } /* correct file type */ parser->file_data->info.filetype = CURLFILETYPE_FILE; } parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; parser->item_length = 0; parser->state.NT.main = PL_WINNT_FILENAME; parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; } break; } break; case PL_WINNT_FILENAME: switch(parser->state.NT.sub.filename) { case PL_WINNT_FILENAME_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used -1; parser->item_length = 1; parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT; } break; case PL_WINNT_FILENAME_CONTENT: parser->item_length++; if(c == '\r') { parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL; finfo->b_data[finfo->b_used - 1] = 0; } else if(c == '\n') { parser->offsets.filename = parser->item_offset; finfo->b_data[finfo->b_used - 1] = 0; parser->offsets.filename = parser->item_offset; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } parser->state.NT.main = PL_WINNT_DATE; parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; } break; case PL_WINNT_FILENAME_WINEOL: if(c == '\n') { parser->offsets.filename = parser->item_offset; result = ftp_pl_insert_finfo(conn, infop); if(result) { parser->error = result; goto fail; } parser->state.NT.main = PL_WINNT_DATE; parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE; } else { parser->error = CURLE_FTP_BAD_FILE_LIST; goto fail; } break; } break; } break; default: retsize = bufflen + 1; goto fail; } i++; } return retsize; fail: /* Clean up any allocated memory. */ if(parser->file_data) { Curl_fileinfo_cleanup(parser->file_data); parser->file_data = NULL; } return retsize; } #endif /* CURL_DISABLE_FTP */ davix-0.8.0/deps/curl/lib/wildcard.c0000644000000000000000000000363314121063461015736 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #include "wildcard.h" #include "llist.h" #include "fileinfo.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static void fileinfo_dtor(void *user, void *element) { (void)user; Curl_fileinfo_cleanup(element); } CURLcode Curl_wildcard_init(struct WildcardData *wc) { Curl_llist_init(&wc->filelist, fileinfo_dtor); wc->state = CURLWC_INIT; return CURLE_OK; } void Curl_wildcard_dtor(struct WildcardData *wc) { if(!wc) return; if(wc->dtor) { wc->dtor(wc->protdata); wc->dtor = ZERO_NULL; wc->protdata = NULL; } DEBUGASSERT(wc->protdata == NULL); Curl_llist_destroy(&wc->filelist, NULL); free(wc->path); wc->path = NULL; free(wc->pattern); wc->pattern = NULL; wc->customptr = NULL; wc->state = CURLWC_INIT; } #endif /* if disabled */ davix-0.8.0/deps/curl/lib/hash.c0000644000000000000000000002030214121063461015060 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "hash.h" #include "llist.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" static void hash_element_dtor(void *user, void *element) { struct curl_hash *h = (struct curl_hash *) user; struct curl_hash_element *e = (struct curl_hash_element *) element; if(e->ptr) { h->dtor(e->ptr); e->ptr = NULL; } e->key_len = 0; free(e); } /* Initializes a hash structure. * Return 1 on error, 0 is fine. * * @unittest: 1602 * @unittest: 1603 */ int Curl_hash_init(struct curl_hash *h, int slots, hash_function hfunc, comp_function comparator, curl_hash_dtor dtor) { if(!slots || !hfunc || !comparator ||!dtor) { return 1; /* failure */ } h->hash_func = hfunc; h->comp_func = comparator; h->dtor = dtor; h->size = 0; h->slots = slots; h->table = malloc(slots * sizeof(struct curl_llist)); if(h->table) { int i; for(i = 0; i < slots; ++i) Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor); return 0; /* fine */ } h->slots = 0; return 1; /* failure */ } static struct curl_hash_element * mk_hash_element(const void *key, size_t key_len, const void *p) { /* allocate the struct plus memory after it to store the key */ struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) + key_len); if(he) { /* copy the key */ memcpy(he->key, key, key_len); he->key_len = key_len; he->ptr = (void *) p; } return he; } #define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)] /* Insert the data in the hash. If there already was a match in the hash, * that data is replaced. * * @unittest: 1305 * @unittest: 1602 * @unittest: 1603 */ void * Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) { struct curl_hash_element *he; struct curl_llist_element *le; struct curl_llist *l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { he = (struct curl_hash_element *) le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { Curl_llist_remove(l, le, (void *)h); --h->size; break; } } he = mk_hash_element(key, key_len, p); if(he) { Curl_llist_insert_next(l, l->tail, he, &he->list); ++h->size; return p; /* return the new entry */ } return NULL; /* failure */ } /* Remove the identified hash entry. * Returns non-zero on failure. * * @unittest: 1603 */ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) { struct curl_llist_element *le; struct curl_llist *l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { struct curl_hash_element *he = le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { Curl_llist_remove(l, le, (void *) h); --h->size; return 0; } } return 1; } /* Retrieves a hash element. * * @unittest: 1603 */ void * Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len) { struct curl_llist_element *le; struct curl_llist *l; if(h) { l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { struct curl_hash_element *he = le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { return he->ptr; } } } return NULL; } #if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST) void Curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *user, void *ptr)) { struct curl_llist_element *le; int i; for(i = 0; i < h->slots; ++i) { for(le = (h->table[i])->head; le; le = le->next) { curl_hash_element *el = le->ptr; cb(user, el->ptr); } } } #endif /* Destroys all the entries in the given hash and resets its attributes, * prepping the given hash for [static|dynamic] deallocation. * * @unittest: 1305 * @unittest: 1602 * @unittest: 1603 */ void Curl_hash_destroy(struct curl_hash *h) { int i; for(i = 0; i < h->slots; ++i) { Curl_llist_destroy(&h->table[i], (void *) h); } Curl_safefree(h->table); h->size = 0; h->slots = 0; } /* Removes all the entries in the given hash. * * @unittest: 1602 */ void Curl_hash_clean(struct curl_hash *h) { Curl_hash_clean_with_criterium(h, NULL, NULL); } /* Cleans all entries that pass the comp function criteria. */ void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)) { struct curl_llist_element *le; struct curl_llist_element *lnext; struct curl_llist *list; int i; if(!h) return; for(i = 0; i < h->slots; ++i) { list = &h->table[i]; le = list->head; /* get first list entry */ while(le) { struct curl_hash_element *he = le->ptr; lnext = le->next; /* ask the callback function if we shall remove this entry or not */ if(comp == NULL || comp(user, he->ptr)) { Curl_llist_remove(list, le, (void *) h); --h->size; /* one less entry in the hash now */ } le = lnext; } } } size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num) { const char *key_str = (const char *) key; const char *end = key_str + key_length; size_t h = 5381; while(key_str < end) { h += h << 5; h ^= *key_str++; } return (h % slots_num); } size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, size_t key2_len) { if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) return 1; return 0; } void Curl_hash_start_iterate(struct curl_hash *hash, struct curl_hash_iterator *iter) { iter->hash = hash; iter->slot_index = 0; iter->current_element = NULL; } struct curl_hash_element * Curl_hash_next_element(struct curl_hash_iterator *iter) { struct curl_hash *h = iter->hash; /* Get the next element in the current list, if any */ if(iter->current_element) iter->current_element = iter->current_element->next; /* If we have reached the end of the list, find the next one */ if(!iter->current_element) { int i; for(i = iter->slot_index; i < h->slots; i++) { if(h->table[i].head) { iter->current_element = h->table[i].head; iter->slot_index = i + 1; break; } } } if(iter->current_element) { struct curl_hash_element *he = iter->current_element->ptr; return he; } iter->current_element = NULL; return NULL; } #if 0 /* useful function for debugging hashes and their contents */ void Curl_hash_print(struct curl_hash *h, void (*func)(void *)) { struct curl_hash_iterator iter; struct curl_hash_element *he; int last_index = -1; if(!h) return; fprintf(stderr, "=Hash dump=\n"); Curl_hash_start_iterate(h, &iter); he = Curl_hash_next_element(&iter); while(he) { if(iter.slot_index != last_index) { fprintf(stderr, "index %d:", iter.slot_index); if(last_index >= 0) { fprintf(stderr, "\n"); } last_index = iter.slot_index; } if(func) func(he->ptr); else fprintf(stderr, " [%p]", (void *)he->ptr); he = Curl_hash_next_element(&iter); } fprintf(stderr, "\n"); } #endif davix-0.8.0/deps/curl/lib/openldap.c0000644000000000000000000005172314121063461015752 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Howard Chu, * Copyright (C) 2011 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP) /* * Notice that USE_OPENLDAP is only a source code selection switch. When * libcurl is built with USE_OPENLDAP defined the libcurl source code that * gets compiled is the code from openldap.c, otherwise the code that gets * compiled is the code from ldap.c. * * When USE_OPENLDAP is defined a recent version of the OpenLDAP library * might be required for compilation and runtime. In order to use ancient * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ #include #include "urldata.h" #include #include "sendf.h" #include "vtls/vtls.h" #include "transfer.h" #include "curl_ldap.h" #include "curl_base64.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Uncommenting this will enable the built-in debug logging of the openldap * library. The debug log level can be set using the CURL_OPENLDAP_TRACE * environment variable. The debug output is written to stderr. * * The library supports the following debug flags: * LDAP_DEBUG_NONE 0x0000 * LDAP_DEBUG_TRACE 0x0001 * LDAP_DEBUG_CONSTRUCT 0x0002 * LDAP_DEBUG_DESTROY 0x0004 * LDAP_DEBUG_PARAMETER 0x0008 * LDAP_DEBUG_ANY 0xffff * * For example, use CURL_OPENLDAP_TRACE=0 for no debug, * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only, * CURL_OPENLDAP_TRACE=65535 for all debug message levels. */ /* #define CURL_OPENLDAP_DEBUG */ #ifndef _LDAP_PVT_H extern int ldap_pvt_url_scheme2proto(const char *); extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld); #endif static CURLcode ldap_setup_connection(struct connectdata *conn); static CURLcode ldap_do(struct connectdata *conn, bool *done); static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool); static CURLcode ldap_connect(struct connectdata *conn, bool *done); static CURLcode ldap_connecting(struct connectdata *conn, bool *done); static CURLcode ldap_disconnect(struct connectdata *conn, bool dead); static Curl_recv ldap_recv; /* * LDAP protocol handler. */ const struct Curl_handler Curl_handler_ldap = { "LDAP", /* scheme */ ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ ldap_connect, /* connect_it */ ldap_connecting, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_NONE /* flags */ }; #ifdef USE_SSL /* * LDAPS protocol handler. */ const struct Curl_handler Curl_handler_ldaps = { "LDAPS", /* scheme */ ldap_setup_connection, /* setup_connection */ ldap_do, /* do_it */ ldap_done, /* done */ ZERO_NULL, /* do_more */ ldap_connect, /* connect_it */ ldap_connecting, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_LDAPS, /* defport */ CURLPROTO_LDAP, /* protocol */ PROTOPT_SSL /* flags */ }; #endif static const char *url_errs[] = { "success", "out of memory", "bad parameter", "unrecognized scheme", "unbalanced delimiter", "bad URL", "bad host or port", "bad or missing attributes", "bad or missing scope", "bad or missing filter", "bad or missing extensions" }; struct ldapconninfo { LDAP *ld; Curl_recv *recv; /* for stacking SSL handler */ Curl_send *send; int proto; int msgid; bool ssldone; bool sslinst; bool didbind; }; typedef struct ldapreqinfo { int msgid; int nument; } ldapreqinfo; static CURLcode ldap_setup_connection(struct connectdata *conn) { struct ldapconninfo *li; LDAPURLDesc *lud; struct Curl_easy *data = conn->data; int rc, proto; CURLcode status; rc = ldap_url_parse(data->change.url, &lud); if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; status = CURLE_URL_MALFORMAT; if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { if(rc == LDAP_URL_ERR_MEM) status = CURLE_OUT_OF_MEMORY; msg = url_errs[rc]; } failf(conn->data, "LDAP local: %s", msg); return status; } proto = ldap_pvt_url_scheme2proto(lud->lud_scheme); ldap_free_urldesc(lud); li = calloc(1, sizeof(struct ldapconninfo)); if(!li) return CURLE_OUT_OF_MEMORY; li->proto = proto; conn->proto.ldapc = li; connkeep(conn, "OpenLDAP default"); return CURLE_OK; } #ifdef USE_SSL static Sockbuf_IO ldapsb_tls; #endif static CURLcode ldap_connect(struct connectdata *conn, bool *done) { struct ldapconninfo *li = conn->proto.ldapc; struct Curl_easy *data = conn->data; int rc, proto = LDAP_VERSION3; char hosturl[1024]; char *ptr; (void)done; strcpy(hosturl, "ldap"); ptr = hosturl + 4; if(conn->handler->flags & PROTOPT_SSL) *ptr++ = 's'; msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", conn->host.name, conn->remote_port); #ifdef CURL_OPENLDAP_DEBUG static int do_trace = 0; const char *env = getenv("CURL_OPENLDAP_TRACE"); do_trace = (env && strtol(env, NULL, 10) > 0); if(do_trace) { ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); } #endif rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); if(rc) { failf(data, "LDAP local: Cannot connect to %s, %s", hosturl, ldap_err2string(rc)); return CURLE_COULDNT_CONNECT; } ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); #ifdef USE_SSL if(conn->handler->flags & PROTOPT_SSL) { CURLcode result; result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); if(result) return result; } #endif return CURLE_OK; } static CURLcode ldap_connecting(struct connectdata *conn, bool *done) { struct ldapconninfo *li = conn->proto.ldapc; struct Curl_easy *data = conn->data; LDAPMessage *msg = NULL; struct timeval tv = {0, 1}, *tvp; int rc, err; char *info = NULL; #ifdef USE_SSL if(conn->handler->flags & PROTOPT_SSL) { /* Is the SSL handshake complete yet? */ if(!li->ssldone) { CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); if(result || !li->ssldone) return result; } /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ if(!li->sslinst) { Sockbuf *sb; ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn); li->sslinst = TRUE; li->recv = conn->recv[FIRSTSOCKET]; li->send = conn->send[FIRSTSOCKET]; } } #endif tvp = &tv; retry: if(!li->didbind) { char *binddn; struct berval passwd; if(conn->bits.user_passwd) { binddn = conn->user; passwd.bv_val = conn->passwd; passwd.bv_len = strlen(passwd.bv_val); } else { binddn = NULL; passwd.bv_val = NULL; passwd.bv_len = 0; } rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &li->msgid); if(rc) return CURLE_LDAP_CANNOT_BIND; li->didbind = TRUE; if(tvp) return CURLE_OK; } rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); if(rc < 0) { failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; } if(rc == 0) { /* timed out */ return CURLE_OK; } rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); if(rc) { failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); return CURLE_LDAP_CANNOT_BIND; } /* Try to fallback to LDAPv2? */ if(err == LDAP_PROTOCOL_ERROR) { int proto; ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); if(proto == LDAP_VERSION3) { if(info) { ldap_memfree(info); info = NULL; } proto = LDAP_VERSION2; ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); li->didbind = FALSE; goto retry; } } if(err) { failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc), info ? info : ""); if(info) ldap_memfree(info); return CURLE_LOGIN_DENIED; } if(info) ldap_memfree(info); conn->recv[FIRSTSOCKET] = ldap_recv; *done = TRUE; return CURLE_OK; } static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection) { struct ldapconninfo *li = conn->proto.ldapc; (void) dead_connection; if(li) { if(li->ld) { ldap_unbind_ext(li->ld, NULL, NULL); li->ld = NULL; } conn->proto.ldapc = NULL; free(li); } return CURLE_OK; } static CURLcode ldap_do(struct connectdata *conn, bool *done) { struct ldapconninfo *li = conn->proto.ldapc; ldapreqinfo *lr; CURLcode status = CURLE_OK; int rc = 0; LDAPURLDesc *ludp = NULL; int msgid; struct Curl_easy *data = conn->data; connkeep(conn, "OpenLDAP do"); infof(data, "LDAP local: %s\n", data->change.url); rc = ldap_url_parse(data->change.url, &ludp); if(rc != LDAP_URL_SUCCESS) { const char *msg = "url parsing problem"; status = CURLE_URL_MALFORMAT; if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { if(rc == LDAP_URL_ERR_MEM) status = CURLE_OUT_OF_MEMORY; msg = url_errs[rc]; } failf(conn->data, "LDAP local: %s", msg); return status; } rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, NULL, NULL, NULL, 0, &msgid); ldap_free_urldesc(ludp); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); return CURLE_LDAP_SEARCH_FAILED; } lr = calloc(1, sizeof(ldapreqinfo)); if(!lr) return CURLE_OUT_OF_MEMORY; lr->msgid = msgid; data->req.protop = lr; Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); *done = TRUE; return CURLE_OK; } static CURLcode ldap_done(struct connectdata *conn, CURLcode res, bool premature) { ldapreqinfo *lr = conn->data->req.protop; (void)res; (void)premature; if(lr) { /* if there was a search in progress, abandon it */ if(lr->msgid) { struct ldapconninfo *li = conn->proto.ldapc; ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL); lr->msgid = 0; } conn->data->req.protop = NULL; free(lr); } return CURLE_OK; } static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { struct ldapconninfo *li = conn->proto.ldapc; struct Curl_easy *data = conn->data; ldapreqinfo *lr = data->req.protop; int rc, ret; LDAPMessage *msg = NULL; LDAPMessage *ent; BerElement *ber = NULL; struct timeval tv = {0, 1}; (void)len; (void)buf; (void)sockindex; rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); if(rc < 0) { failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); *err = CURLE_RECV_ERROR; return -1; } *err = CURLE_AGAIN; ret = -1; /* timed out */ if(!msg) return ret; for(ent = ldap_first_message(li->ld, msg); ent; ent = ldap_next_message(li->ld, ent)) { struct berval bv, *bvals; int binary = 0, msgtype; CURLcode writeerr; msgtype = ldap_msgtype(ent); if(msgtype == LDAP_RES_SEARCH_RESULT) { int code; char *info = NULL; rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0); if(rc) { failf(data, "LDAP local: search ldap_parse_result %s", ldap_err2string(rc)); *err = CURLE_LDAP_SEARCH_FAILED; } else if(code && code != LDAP_SIZELIMIT_EXCEEDED) { failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc), info ? info : ""); *err = CURLE_LDAP_SEARCH_FAILED; } else { /* successful */ if(code == LDAP_SIZELIMIT_EXCEEDED) infof(data, "There are more than %d entries\n", lr->nument); data->req.size = data->req.bytecount; *err = CURLE_OK; ret = 0; } lr->msgid = 0; ldap_memfree(info); break; } else if(msgtype != LDAP_RES_SEARCH_ENTRY) continue; lr->nument++; rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv); if(rc < 0) { *err = CURLE_RECV_ERROR; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount += bv.bv_len + 5; for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals); rc == LDAP_SUCCESS; rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) { int i; if(bv.bv_val == NULL) break; if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7)) binary = 1; else binary = 0; if(bvals == NULL) { writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount += bv.bv_len + 3; continue; } for(i = 0; bvals[i].bv_val != NULL; i++) { int binval = 0; writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount += bv.bv_len + 2; if(!binary) { /* check for leading or trailing whitespace */ if(ISSPACE(bvals[i].bv_val[0]) || ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1])) binval = 1; else { /* check for unprintable characters */ unsigned int j; for(j = 0; jreq.bytecount += 2; if(val_b64_sz > 0) { writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); if(writeerr) { *err = writeerr; return -1; } free(val_b64); data->req.bytecount += val_b64_sz; } } else { writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1); if(writeerr) { *err = writeerr; return -1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val, bvals[i].bv_len); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount += bvals[i].bv_len + 1; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount++; } ber_memfree(bvals); writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount++; } writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); if(writeerr) { *err = writeerr; return -1; } data->req.bytecount++; ber_free(ber, 0); } ldap_msgfree(msg); return ret; } #ifdef USE_SSL static int ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg) { sbiod->sbiod_pvt = arg; return 0; } static int ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod) { sbiod->sbiod_pvt = NULL; return 0; } /* We don't need to do anything because libcurl does it already */ static int ldapsb_tls_close(Sockbuf_IO_Desc *sbiod) { (void)sbiod; return 0; } static int ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg) { (void)arg; if(opt == LBER_SB_OPT_DATA_READY) { struct connectdata *conn = sbiod->sbiod_pvt; return Curl_ssl_data_pending(conn, FIRSTSOCKET); } return 0; } static ber_slen_t ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct connectdata *conn = sbiod->sbiod_pvt; struct ldapconninfo *li = conn->proto.ldapc; ber_slen_t ret; CURLcode err = CURLE_RECV_ERROR; ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err); if(ret < 0 && err == CURLE_AGAIN) { SET_SOCKERRNO(EWOULDBLOCK); } return ret; } static ber_slen_t ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct connectdata *conn = sbiod->sbiod_pvt; struct ldapconninfo *li = conn->proto.ldapc; ber_slen_t ret; CURLcode err = CURLE_SEND_ERROR; ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err); if(ret < 0 && err == CURLE_AGAIN) { SET_SOCKERRNO(EWOULDBLOCK); } return ret; } static Sockbuf_IO ldapsb_tls = { ldapsb_tls_setup, ldapsb_tls_remove, ldapsb_tls_ctrl, ldapsb_tls_read, ldapsb_tls_write, ldapsb_tls_close }; #endif /* USE_SSL */ #endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */ davix-0.8.0/deps/curl/lib/curl_sasl.h0000644000000000000000000001244214121063461016137 0ustar rootroot#ifndef HEADER_CURL_SASL_H #define HEADER_CURL_SASL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include struct Curl_easy; struct connectdata; /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) #define SASL_MECH_CRAM_MD5 (1 << 2) #define SASL_MECH_DIGEST_MD5 (1 << 3) #define SASL_MECH_GSSAPI (1 << 4) #define SASL_MECH_EXTERNAL (1 << 5) #define SASL_MECH_NTLM (1 << 6) #define SASL_MECH_XOAUTH2 (1 << 7) #define SASL_MECH_OAUTHBEARER (1 << 8) /* Authentication mechanism values */ #define SASL_AUTH_NONE 0 #define SASL_AUTH_ANY ~0U #define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) /* Authentication mechanism strings */ #define SASL_MECH_STRING_LOGIN "LOGIN" #define SASL_MECH_STRING_PLAIN "PLAIN" #define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" #define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" #define SASL_MECH_STRING_GSSAPI "GSSAPI" #define SASL_MECH_STRING_EXTERNAL "EXTERNAL" #define SASL_MECH_STRING_NTLM "NTLM" #define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" #define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" /* SASL machine states */ typedef enum { SASL_STOP, SASL_PLAIN, SASL_LOGIN, SASL_LOGIN_PASSWD, SASL_EXTERNAL, SASL_CRAMMD5, SASL_DIGESTMD5, SASL_DIGESTMD5_RESP, SASL_NTLM, SASL_NTLM_TYPE2MSG, SASL_GSSAPI, SASL_GSSAPI_TOKEN, SASL_GSSAPI_NO_DATA, SASL_OAUTH2, SASL_OAUTH2_RESP, SASL_CANCEL, SASL_FINAL } saslstate; /* Progress indicator */ typedef enum { SASL_IDLE, SASL_INPROGRESS, SASL_DONE } saslprogress; /* Protocol dependent SASL parameters */ struct SASLproto { const char *service; /* The service name */ int contcode; /* Code to receive when continuation is expected */ int finalcode; /* Code to receive upon authentication success */ size_t maxirlen; /* Maximum initial response length */ CURLcode (*sendauth)(struct connectdata *conn, const char *mech, const char *ir); /* Send authentication command */ CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); /* Send authentication continuation */ void (*getmessage)(char *buffer, char **outptr); /* Get SASL response message */ }; /* Per-connection parameters */ struct SASL { const struct SASLproto *params; /* Protocol dependent parameters */ saslstate state; /* Current machine state */ unsigned int authmechs; /* Accepted authentication mechanisms */ unsigned int prefmech; /* Preferred authentication mechanism */ unsigned int authused; /* Auth mechanism used for the connection */ bool resetprefs; /* For URL auth option parsing. */ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ bool force_ir; /* Protocol always supports initial response */ }; /* This is used to test whether the line starts with the given mechanism */ #define sasl_mech_equal(line, wordlen, mech) \ (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ !memcmp(line, mech, wordlen)) /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); /* Convert a mechanism name to a token */ unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len); /* Parse the URL login options */ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, const char *value, size_t len); /* Initializes an SASL structure */ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); /* Check if we have enough auth data and capabilities to authenticate */ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); /* Calculate the required login details for SASL authentication */ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, bool force_ir, saslprogress *progress); /* Continue an SASL authentication */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress); #endif /* HEADER_CURL_SASL_H */ davix-0.8.0/deps/curl/lib/splay.h0000644000000000000000000000516314121063461015302 0ustar rootroot#ifndef HEADER_CURL_SPLAY_H #define HEADER_CURL_SPLAY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1997 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "timeval.h" struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ struct Curl_tree *larger; /* larger node */ struct Curl_tree *samen; /* points to the next node with identical key */ struct Curl_tree *samep; /* points to the prev node with identical key */ struct curltime key; /* this node's "sort" key */ void *payload; /* data the splay code doesn't care about */ }; struct Curl_tree *Curl_splay(struct curltime i, struct Curl_tree *t); struct Curl_tree *Curl_splayinsert(struct curltime key, struct Curl_tree *t, struct Curl_tree *newnode); #if 0 struct Curl_tree *Curl_splayremove(struct curltime key, struct Curl_tree *t, struct Curl_tree **removed); #endif struct Curl_tree *Curl_splaygetbest(struct curltime key, struct Curl_tree *t, struct Curl_tree **removed); int Curl_splayremovebyaddr(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot); #define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) #endif /* HEADER_CURL_SPLAY_H */ davix-0.8.0/deps/curl/lib/curl_multibyte.c0000644000000000000000000000474314121063461017213 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ defined(USE_WIN32_LDAP)) && defined(UNICODE)) /* * MultiByte conversions using Windows kernel32 library. */ #include "curl_multibyte.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8) { wchar_t *str_w = NULL; if(str_utf8) { int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str_utf8, -1, NULL, 0); if(str_w_len > 0) { str_w = malloc(str_w_len * sizeof(wchar_t)); if(str_w) { if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w, str_w_len) == 0) { free(str_w); return NULL; } } } } return str_w; } char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w) { char *str_utf8 = NULL; if(str_w) { int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL, 0, NULL, NULL); if(bytes > 0) { str_utf8 = malloc(bytes); if(str_utf8) { if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes, NULL, NULL) == 0) { free(str_utf8); return NULL; } } } } return str_utf8; } #endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ davix-0.8.0/deps/curl/lib/netrc.h0000644000000000000000000000335514121063461015266 0ustar rootroot#ifndef HEADER_CURL_NETRC_H #define HEADER_CURL_NETRC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_NETRC /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, bool *login_changed, bool *password_changed, char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine * section in the netrc. * If (*loginp)[0] != 0, search for password within machine and login. */ #else /* disabled */ #define Curl_parsenetrc(a,b,c,d,e,f) 1 #endif #endif /* HEADER_CURL_NETRC_H */ davix-0.8.0/deps/curl/lib/ftplistparser.h0000644000000000000000000000317714121063461017057 0ustar rootroot#ifndef HEADER_CURL_FTPLISTPARSER_H #define HEADER_CURL_FTPLISTPARSER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP /* WRITEFUNCTION callback for parsing LIST responses */ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, void *connptr); struct ftp_parselist_data; /* defined inside ftplibparser.c */ CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data); struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void); void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data); #endif /* CURL_DISABLE_FTP */ #endif /* HEADER_CURL_FTPLISTPARSER_H */ davix-0.8.0/deps/curl/lib/rename.c0000644000000000000000000000371414121063461015414 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "rename.h" #include "curl_setup.h" #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \ defined(USE_ALTSVC) #include "timeval.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* return 0 on success, 1 on error */ int Curl_rename(const char *oldpath, const char *newpath) { #ifdef WIN32 /* rename() on Windows doesn't overwrite, so we can't use it here. MoveFileExA() will overwrite and is usually atomic, however it fails when there are open handles to the file. */ const int max_wait_ms = 1000; struct curltime start = Curl_now(); for(;;) { timediff_t diff; if(MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) break; diff = Curl_timediff(Curl_now(), start); if(diff < 0 || diff > max_wait_ms) return 1; Sleep(1); } #else if(rename(oldpath, newpath)) return 1; #endif return 0; } #endif davix-0.8.0/deps/curl/lib/strcase.c0000644000000000000000000001351214121063461015606 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "strcase.h" static char raw_tolower(char in); /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ char Curl_raw_toupper(char in) { #if !defined(CURL_DOES_CONVERSIONS) if(in >= 'a' && in <= 'z') return (char)('A' + in - 'a'); #else switch(in) { case 'a': return 'A'; case 'b': return 'B'; case 'c': return 'C'; case 'd': return 'D'; case 'e': return 'E'; case 'f': return 'F'; case 'g': return 'G'; case 'h': return 'H'; case 'i': return 'I'; case 'j': return 'J'; case 'k': return 'K'; case 'l': return 'L'; case 'm': return 'M'; case 'n': return 'N'; case 'o': return 'O'; case 'p': return 'P'; case 'q': return 'Q'; case 'r': return 'R'; case 's': return 'S'; case 't': return 'T'; case 'u': return 'U'; case 'v': return 'V'; case 'w': return 'W'; case 'x': return 'X'; case 'y': return 'Y'; case 'z': return 'Z'; } #endif return in; } /* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because its behavior is altered by the current locale. */ static char raw_tolower(char in) { #if !defined(CURL_DOES_CONVERSIONS) if(in >= 'A' && in <= 'Z') return (char)('a' + in - 'A'); #else switch(in) { case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; case 'Y': return 'y'; case 'Z': return 'z'; } #endif return in; } /* * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is * meant to be locale independent and only compare strings we know are safe * for this. See * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some * further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for * non-ascii. * * @unittest: 1301 */ int Curl_strcasecompare(const char *first, const char *second) { while(*first && *second) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) /* get out of the loop as soon as they don't match */ break; first++; second++; } /* we do the comparison here (possibly again), just to make sure that if the loop above is skipped because one of the strings reached zero, we must not return this as a successful match */ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } int Curl_safe_strcasecompare(const char *first, const char *second) { if(first && second) /* both pointers point to something then compare them */ return Curl_strcasecompare(first, second); /* if both pointers are NULL then treat them as equal */ return (NULL == first && NULL == second); } /* * @unittest: 1301 */ int Curl_strncasecompare(const char *first, const char *second, size_t max) { while(*first && *second && max) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { break; } max--; first++; second++; } if(0 == max) return 1; /* they are equal this far */ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); } /* Copy an upper case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be * NUL-terminated if that limit is reached. */ void Curl_strntoupper(char *dest, const char *src, size_t n) { if(n < 1) return; do { *dest++ = Curl_raw_toupper(*src); } while(*src++ && --n); } /* Copy a lower case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be * NUL-terminated if that limit is reached. */ void Curl_strntolower(char *dest, const char *src, size_t n) { if(n < 1) return; do { *dest++ = raw_tolower(*src); } while(*src++ && --n); } /* --- public functions --- */ int curl_strequal(const char *first, const char *second) { return Curl_strcasecompare(first, second); } int curl_strnequal(const char *first, const char *second, size_t max) { return Curl_strncasecompare(first, second, max); } davix-0.8.0/deps/curl/lib/netrc.c0000644000000000000000000001747714121063461015273 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_NETRC #ifdef HAVE_PWD_H #include #endif #include #include "netrc.h" #include "strtok.h" #include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Get user and password from .netrc when given a machine name */ enum host_lookup_state { NOTHING, HOSTFOUND, /* the 'machine' keyword was found */ HOSTVALID /* this is "our" machine! */ }; #define NETRC_FILE_MISSING 1 #define NETRC_FAILED -1 #define NETRC_SUCCESS 0 /* * Returns zero on success. */ static int parsenetrc(const char *host, char **loginp, char **passwordp, bool *login_changed, bool *password_changed, char *netrcfile) { FILE *file; int retcode = NETRC_FILE_MISSING; char *login = *loginp; char *password = *passwordp; bool specific_login = (login && *login != 0); bool login_alloc = FALSE; bool password_alloc = FALSE; enum host_lookup_state state = NOTHING; char state_login = 0; /* Found a login keyword */ char state_password = 0; /* Found a password keyword */ int state_our_login = FALSE; /* With specific_login, found *our* login name */ DEBUGASSERT(netrcfile); file = fopen(netrcfile, FOPEN_READTEXT); if(file) { char *tok; char *tok_buf; bool done = FALSE; char netrcbuffer[4096]; int netrcbuffsize = (int)sizeof(netrcbuffer); while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { tok = strtok_r(netrcbuffer, " \t\n", &tok_buf); if(tok && *tok == '#') /* treat an initial hash as a comment line */ continue; while(tok) { if((login && *login) && (password && *password)) { done = TRUE; break; } switch(state) { case NOTHING: if(strcasecompare("machine", tok)) { /* the next tok is the machine name, this is in itself the delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ state = HOSTFOUND; } else if(strcasecompare("default", tok)) { state = HOSTVALID; retcode = NETRC_SUCCESS; /* we did find our host */ } break; case HOSTFOUND: if(strcasecompare(host, tok)) { /* and yes, this is our host! */ state = HOSTVALID; retcode = NETRC_SUCCESS; /* we did find our host */ } else /* not our host */ state = NOTHING; break; case HOSTVALID: /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { state_our_login = strcasecompare(login, tok); } else if(!login || strcmp(login, tok)) { if(login_alloc) { free(login); login_alloc = FALSE; } login = strdup(tok); if(!login) { retcode = NETRC_FAILED; /* allocation failed */ goto out; } login_alloc = TRUE; } state_login = 0; } else if(state_password) { if((state_our_login || !specific_login) && (!password || strcmp(password, tok))) { if(password_alloc) { free(password); password_alloc = FALSE; } password = strdup(tok); if(!password) { retcode = NETRC_FAILED; /* allocation failed */ goto out; } password_alloc = TRUE; } state_password = 0; } else if(strcasecompare("login", tok)) state_login = 1; else if(strcasecompare("password", tok)) state_password = 1; else if(strcasecompare("machine", tok)) { /* ok, there's machine here go => */ state = HOSTFOUND; state_our_login = FALSE; } break; } /* switch (state) */ tok = strtok_r(NULL, " \t\n", &tok_buf); } /* while(tok) */ } /* while fgets() */ out: if(!retcode) { /* success */ *login_changed = FALSE; *password_changed = FALSE; if(login_alloc) { if(*loginp) free(*loginp); *loginp = login; *login_changed = TRUE; } if(password_alloc) { if(*passwordp) free(*passwordp); *passwordp = password; *password_changed = TRUE; } } else { if(login_alloc) free(login); if(password_alloc) free(password); } fclose(file); } return retcode; } /* * @unittest: 1304 * * *loginp and *passwordp MUST be allocated if they aren't NULL when passed * in. */ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, bool *login_changed, bool *password_changed, char *netrcfile) { int retcode = 1; char *filealloc = NULL; if(!netrcfile) { char *home = NULL; char *homea = curl_getenv("HOME"); /* portable environment reader */ if(homea) { home = homea; #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) } else { struct passwd pw, *pw_res; char pwbuf[1024]; if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && pw_res) { home = pw.pw_dir; } #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) } else { struct passwd *pw; pw = getpwuid(geteuid()); if(pw) { home = pw->pw_dir; } #endif } if(!home) return retcode; /* no home directory found (or possibly out of memory) */ filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR); if(!filealloc) { free(homea); return -1; } retcode = parsenetrc(host, loginp, passwordp, login_changed, password_changed, filealloc); free(filealloc); #ifdef WIN32 if(retcode == NETRC_FILE_MISSING) { /* fallback to the old-style "_netrc" file */ filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR); if(!filealloc) { free(homea); return -1; } retcode = parsenetrc(host, loginp, passwordp, login_changed, password_changed, filealloc); free(filealloc); } #endif free(homea); } else retcode = parsenetrc(host, loginp, passwordp, login_changed, password_changed, netrcfile); return retcode; } #endif davix-0.8.0/deps/curl/lib/url.h0000644000000000000000000000734714121063461014762 0ustar rootroot#ifndef HEADER_CURL_URL_H #define HEADER_CURL_URL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #define READBUFFER_SIZE CURL_MAX_WRITE_SIZE #define READBUFFER_MAX CURL_MAX_READ_SIZE #define READBUFFER_MIN 1024 /* The default upload buffer size, should not be smaller than CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in a write callback. The size was 16KB for many years but was bumped to 64KB because it makes libcurl able to do significantly faster uploads in some circumstances. Even larger buffers can help further, but this is deemed a fair memory/speed compromise. */ #define UPLOADBUFFER_DEFAULT 65536 #define UPLOADBUFFER_MAX (2*1024*1024) #define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE /* * Prototypes for library-wide functions provided by url.c */ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); CURLcode Curl_open(struct Curl_easy **curl); CURLcode Curl_init_userdefined(struct Curl_easy *data); void Curl_freeset(struct Curl_easy * data); CURLcode Curl_uc_to_curlcode(CURLUcode uc); CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */ CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect); CURLcode Curl_disconnect(struct Curl_easy *data, struct connectdata *, bool dead_connection); CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done); void Curl_free_request_state(struct Curl_easy *data); CURLcode Curl_parse_login_details(const char *login, const size_t len, char **userptr, char **passwdptr, char **optionsptr); const struct Curl_handler *Curl_builtin_scheme(const char *scheme); bool Curl_is_ASCII_name(const char *hostname); CURLcode Curl_idnconvert_hostname(struct connectdata *conn, struct hostname *host); void Curl_free_idnconverted_hostname(struct hostname *host); #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */ #ifdef CURL_DISABLE_VERBOSE_STRINGS #define Curl_verboseconnect(x) Curl_nop_stmt #else void Curl_verboseconnect(struct connectdata *conn); #endif #define CONNECT_PROXY_SSL()\ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ !conn->bits.proxy_ssl_connected[sockindex]) #define CONNECT_FIRSTSOCKET_PROXY_SSL()\ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ !conn->bits.proxy_ssl_connected[FIRSTSOCKET]) #define CONNECT_SECONDARYSOCKET_PROXY_SSL()\ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ !conn->bits.proxy_ssl_connected[SECONDARYSOCKET]) #endif /* HEADER_CURL_URL_H */ davix-0.8.0/deps/curl/lib/file.h0000644000000000000000000000313614121063461015067 0ustar rootroot#ifndef HEADER_CURL_FILE_H #define HEADER_CURL_FILE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /**************************************************************************** * FILE unique setup ***************************************************************************/ struct FILEPROTO { char *path; /* the path we operate on */ char *freepath; /* pointer to the allocated block we must free, this might differ from the 'path' pointer */ int fd; /* open file descriptor to read from! */ }; #ifndef CURL_DISABLE_FILE extern const struct Curl_handler Curl_handler_file; #endif #endif /* HEADER_CURL_FILE_H */ davix-0.8.0/deps/curl/lib/file.c0000644000000000000000000003622114121063461015063 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FILE #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #include "strtoofft.h" #include "urldata.h" #include #include "progress.h" #include "sendf.h" #include "escape.h" #include "file.h" #include "speedcheck.h" #include "getinfo.h" #include "transfer.h" #include "url.h" #include "parsedate.h" /* for the week day and month names */ #include "warnless.h" #include "curl_range.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ defined(__SYMBIAN32__) #define DOS_FILESYSTEM 1 #endif #ifdef OPEN_NEEDS_ARG3 # define open_readonly(p,f) open((p),(f),(0)) #else # define open_readonly(p,f) open((p),(f)) #endif /* * Forward declarations. */ static CURLcode file_do(struct connectdata *, bool *done); static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode file_connect(struct connectdata *conn, bool *done); static CURLcode file_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode file_setup_connection(struct connectdata *conn); /* * FILE scheme handler. */ const struct Curl_handler Curl_handler_file = { "FILE", /* scheme */ file_setup_connection, /* setup_connection */ file_do, /* do_it */ file_done, /* done */ ZERO_NULL, /* do_more */ file_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ file_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ 0, /* defport */ CURLPROTO_FILE, /* protocol */ PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ }; static CURLcode file_setup_connection(struct connectdata *conn) { /* allocate the FILE specific struct */ conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO)); if(!conn->data->req.protop) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } /* * file_connect() gets called from Curl_protocol_connect() to allow us to * do protocol-specific actions at connect-time. We emulate a * connect-then-transfer protocol and "connect" to the file here */ static CURLcode file_connect(struct connectdata *conn, bool *done) { struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; int fd = -1; #ifdef DOS_FILESYSTEM size_t i; char *actual_path; #endif size_t real_path_len; CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path, &real_path_len, FALSE); if(result) return result; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's something that looks like a drive at the beginning of the path, skip the slash. If we remove the initial slash in all cases, paths without drive letters end up relative to the current directory which isn't how browsers work. Some browsers accept | instead of : as the drive letter separator, so we do too. On other platforms, we need the slash to indicate an absolute pathname. On Windows, absolute paths start with a drive letter. */ actual_path = real_path; if((actual_path[0] == '/') && actual_path[1] && (actual_path[2] == ':' || actual_path[2] == '|')) { actual_path[2] = ':'; actual_path++; real_path_len--; } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ for(i = 0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; else if(!actual_path[i]) { /* binary zero */ Curl_safefree(real_path); return CURLE_URL_MALFORMAT; } if(strncmp("\\\\", actual_path, 2)) /* refuse to open path that starts with two backslashes */ fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else if(memchr(real_path, 0, real_path_len)) { /* binary zeroes indicate foul play */ Curl_safefree(real_path); return CURLE_URL_MALFORMAT; } fd = open_readonly(real_path, O_RDONLY); file->path = real_path; #endif file->freepath = real_path; /* free this when done */ file->fd = fd; if(!data->set.upload && (fd == -1)) { failf(data, "Couldn't open file %s", data->state.up.path); file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); return CURLE_FILE_COULDNT_READ_FILE; } *done = TRUE; return CURLE_OK; } static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature) { struct FILEPROTO *file = conn->data->req.protop; (void)status; /* not used */ (void)premature; /* not used */ if(file) { Curl_safefree(file->freepath); file->path = NULL; if(file->fd != -1) close(file->fd); file->fd = -1; } return CURLE_OK; } static CURLcode file_disconnect(struct connectdata *conn, bool dead_connection) { struct FILEPROTO *file = conn->data->req.protop; (void)dead_connection; /* not used */ if(file) { Curl_safefree(file->freepath); file->path = NULL; if(file->fd != -1) close(file->fd); file->fd = -1; } return CURLE_OK; } #ifdef DOS_FILESYSTEM #define DIRSEP '\\' #else #define DIRSEP '/' #endif static CURLcode file_upload(struct connectdata *conn) { struct FILEPROTO *file = conn->data->req.protop; const char *dir = strchr(file->path, DIRSEP); int fd; int mode; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; struct_stat file_stat; const char *buf2; /* * Since FILE: doesn't do the full init, we need to provide some extra * assignments here. */ conn->data->req.upload_fromhere = buf; if(!dir) return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ if(!dir[1]) return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ #ifdef O_BINARY #define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY #else #define MODE_DEFAULT O_WRONLY|O_CREAT #endif if(data->state.resume_from) mode = MODE_DEFAULT|O_APPEND; else mode = MODE_DEFAULT|O_TRUNC; fd = open(file->path, mode, conn->data->set.new_file_perms); if(fd < 0) { failf(data, "Can't open %s for writing", file->path); return CURLE_WRITE_ERROR; } if(-1 != data->state.infilesize) /* known size of data to "upload" */ Curl_pgrsSetUploadSize(data, data->state.infilesize); /* treat the negative resume offset value as the case of "-" */ if(data->state.resume_from < 0) { if(fstat(fd, &file_stat)) { close(fd); failf(data, "Can't get the size of %s", file->path); return CURLE_WRITE_ERROR; } data->state.resume_from = (curl_off_t)file_stat.st_size; } while(!result) { size_t nread; size_t nwrite; size_t readcount; result = Curl_fillreadbuffer(conn, data->set.buffer_size, &readcount); if(result) break; if(!readcount) break; nread = readcount; /*skip bytes before resume point*/ if(data->state.resume_from) { if((curl_off_t)nread <= data->state.resume_from) { data->state.resume_from -= nread; nread = 0; buf2 = buf; } else { buf2 = buf + data->state.resume_from; nread -= (size_t)data->state.resume_from; data->state.resume_from = 0; } } else buf2 = buf; /* write the data to the target */ nwrite = write(fd, buf2, nread); if(nwrite != nread) { result = CURLE_SEND_ERROR; break; } bytecount += nread; Curl_pgrsSetUploadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(data, Curl_now()); } if(!result && Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; close(fd); return result; } /* * file_do() is the protocol-specific function for the do-phase, separated * from the connect-phase above. Other protocols merely setup the transfer in * the do-phase, to have it done in the main transfer loop but since some * platforms we support don't allow select()ing etc on file handles (as * opposed to sockets) we instead perform the whole do-operation in this * function. */ static CURLcode file_do(struct connectdata *conn, bool *done) { /* This implementation ignores the host name in conformance with RFC 1738. Only local files (reachable via the standard file system) are supported. This means that files on remotely mounted directories (via NFS, Samba, NT sharing) can be accessed through a file:// URL */ CURLcode result = CURLE_OK; struct_stat statbuf; /* struct_stat instead of struct stat just to allow the Windows version to have a different struct without having to redefine the simple word 'stat' */ curl_off_t expected_size = 0; bool size_known; bool fstated = FALSE; struct Curl_easy *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; int fd; struct FILEPROTO *file; *done = TRUE; /* unconditionally */ Curl_pgrsStartNow(data); if(data->set.upload) return file_upload(conn); file = conn->data->req.protop; /* get the fd from the connection phase */ fd = file->fd; /* VMS: This only works reliable for STREAMLF files */ if(-1 != fstat(fd, &statbuf)) { /* we could stat it, then read out the size */ expected_size = statbuf.st_size; /* and store the modification time */ data->info.filetime = statbuf.st_mtime; fstated = TRUE; } if(fstated && !data->state.range && data->set.timecondition) { if(!Curl_meets_timecondition(data, data->info.filetime)) { *done = TRUE; return CURLE_OK; } } if(fstated) { time_t filetime; struct tm buffer; const struct tm *tm = &buffer; char header[80]; msnprintf(header, sizeof(header), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0); if(result) return result; result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"Accept-ranges: bytes\r\n", 0); if(result) return result; filetime = (time_t)statbuf.st_mtime; result = Curl_gmtime(filetime, &buffer); if(result) return result; /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ msnprintf(header, sizeof(header), "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s", Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, Curl_month[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, data->set.opt_no_body ? "": "\r\n"); result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0); if(result) return result; /* set the file size to make it available post transfer */ Curl_pgrsSetDownloadSize(data, expected_size); if(data->set.opt_no_body) return result; } /* Check whether file range has been specified */ result = Curl_range(conn); if(result) return result; /* Adjust the start offset in case we want to get the N last bytes * of the stream if the filesize could be determined */ if(data->state.resume_from < 0) { if(!fstated) { failf(data, "Can't get the size of file."); return CURLE_READ_ERROR; } data->state.resume_from += (curl_off_t)statbuf.st_size; } if(data->state.resume_from <= expected_size) expected_size -= data->state.resume_from; else { failf(data, "failed to resume file:// transfer"); return CURLE_BAD_DOWNLOAD_RESUME; } /* A high water mark has been specified so we obey... */ if(data->req.maxdownload > 0) expected_size = data->req.maxdownload; if(!fstated || (expected_size == 0)) size_known = FALSE; else size_known = TRUE; /* The following is a shortcut implementation of file reading this is both more efficient than the former call to download() and it avoids problems with select() and recv() on file descriptors in Winsock */ if(fstated) Curl_pgrsSetDownloadSize(data, expected_size); if(data->state.resume_from) { if(data->state.resume_from != lseek(fd, data->state.resume_from, SEEK_SET)) return CURLE_BAD_DOWNLOAD_RESUME; } Curl_pgrsTime(data, TIMER_STARTTRANSFER); while(!result) { ssize_t nread; /* Don't fill a whole buffer if we want less than all data */ size_t bytestoread; if(size_known) { bytestoread = (expected_size < data->set.buffer_size) ? curlx_sotouz(expected_size) : (size_t)data->set.buffer_size; } else bytestoread = data->set.buffer_size-1; nread = read(fd, buf, bytestoread); if(nread > 0) buf[nread] = 0; if(nread <= 0 || (size_known && (expected_size == 0))) break; bytecount += nread; if(size_known) expected_size -= nread; result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread); if(result) return result; Curl_pgrsSetDownloadCounter(data, bytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(data, Curl_now()); } if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; return result; } #endif davix-0.8.0/deps/curl/lib/curl_printf.h0000644000000000000000000000314714121063461016501 0ustar rootroot#ifndef HEADER_CURL_PRINTF_H #define HEADER_CURL_PRINTF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * This header should be included by ALL code in libcurl that uses any * *rintf() functions. */ #include # undef printf # undef fprintf # undef msnprintf # undef vprintf # undef vfprintf # undef vsnprintf # undef aprintf # undef vaprintf # define printf curl_mprintf # define fprintf curl_mfprintf # define msnprintf curl_msnprintf # define vprintf curl_mvprintf # define vfprintf curl_mvfprintf # define mvsnprintf curl_mvsnprintf # define aprintf curl_maprintf # define vaprintf curl_mvaprintf #endif /* HEADER_CURL_PRINTF_H */ davix-0.8.0/deps/curl/lib/md5.c0000644000000000000000000004236514121063461014637 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_CRYPTO_AUTH #include #include "curl_md5.h" #include "curl_hmac.h" #include "warnless.h" #ifdef USE_MBEDTLS #include #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS #endif #endif /* USE_MBEDTLS */ #if defined(USE_GNUTLS_NETTLE) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct md5_ctx MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { md5_init(ctx); } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { md5_update(ctx, inputLen, input); } static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { md5_digest(ctx, 16, digest); } #elif defined(USE_GNUTLS) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef gcry_md_hd_t MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_MD5, 0); } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { gcry_md_write(*ctx, input, inputLen); } static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), 16); gcry_md_close(*ctx); } #elif defined(USE_OPENSSL) && !defined(USE_AMISSL) /* When OpenSSL is available we use the MD5-function from OpenSSL */ #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #elif defined(USE_MBEDTLS) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef mbedtls_md5_context MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md5_starts(ctx); #else (void) mbedtls_md5_starts_ret(ctx); #endif } static void MD5_Update(MD5_CTX *ctx, const unsigned char *data, unsigned int length) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md5_update(ctx, data, length); #else (void) mbedtls_md5_update_ret(ctx, data, length); #endif } static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md5_finish(ctx, digest); #else (void) mbedtls_md5_finish_ret(ctx, digest); #endif } #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) /* For Apple operating systems: CommonCrypto has the functions we need. These functions are available on Tiger and later, as well as iOS 2.0 and later. If you're building for an older cat, well, sorry. Declaring the functions as static like this seems to be a bit more reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ # include # define MD5_CTX CC_MD5_CTX #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" static void MD5_Init(MD5_CTX *ctx) { CC_MD5_Init(ctx); } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { CC_MD5_Update(ctx, input, inputLen); } static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { CC_MD5_Final(digest, ctx); } #elif defined(USE_WIN32_CRYPTO) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; } MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { unsigned long length = 0; CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); if(length == 16) CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); if(ctx->hHash) CryptDestroyHash(ctx->hHash); if(ctx->hCryptProv) CryptReleaseContext(ctx->hCryptProv, 0); } #else /* When no other crypto library is available we use this code segment */ /* * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. * MD5 Message-Digest Algorithm (RFC 1321). * * Homepage: https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 * * Author: * Alexander Peslyak, better known as Solar Designer * * This software was written by Alexander Peslyak in 2001. No copyright is * claimed, and the software is hereby placed in the public domain. * In case this attempt to disclaim copyright and place the software in the * public domain is deemed null and void, then the software is * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the * general public under the following terms: * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. * * (This is a heavily cut-down "BSD license".) * * This differs from Colin Plumb's older public domain implementation in that * no exactly 32-bit integer data type is required (any 32-bit or wider * unsigned integer data type will do), there's no compile-time endianness * configuration, and the function prototypes match OpenSSL's. No code from * Colin Plumb's implementation has been reused; this comment merely compares * the properties of the two independent implementations. * * The primary goals of this implementation are portability and ease of use. * It is meant to be fast, but not as fast as possible. Some known * optimizations are not included to reduce source code size and avoid * compile-time configuration. */ #include /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* Any 32-bit or wider unsigned integer data type will do */ typedef unsigned int MD5_u32plus; typedef struct { MD5_u32plus lo, hi; MD5_u32plus a, b, c, d; unsigned char buffer[64]; MD5_u32plus block[16]; } MD5_CTX; static void MD5_Init(MD5_CTX *ctx); static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); static void MD5_Final(unsigned char *result, MD5_CTX *ctx); /* * The basic MD5 functions. * * F and G are optimized compared to their RFC 1321 definitions for * architectures that lack an AND-NOT instruction, just like in Colin Plumb's * implementation. */ #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) #define H(x, y, z) (((x) ^ (y)) ^ (z)) #define H2(x, y, z) ((x) ^ ((y) ^ (z))) #define I(x, y, z) ((y) ^ ((x) | ~(z))) /* * The MD5 transformation for all four rounds. */ #define STEP(f, a, b, c, d, x, t, s) \ (a) += f((b), (c), (d)) + (x) + (t); \ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ (a) += (b); /* * SET reads 4 input bytes in little-endian byte order and stores them * in a properly aligned word in host byte order. * * The check for little-endian architectures that tolerate unaligned * memory accesses is just an optimization. Nothing will break if it * doesn't work. */ #if defined(__i386__) || defined(__x86_64__) || defined(__vax__) #define SET(n) \ (*(MD5_u32plus *)(void *)&ptr[(n) * 4]) #define GET(n) \ SET(n) #else #define SET(n) \ (ctx->block[(n)] = \ (MD5_u32plus)ptr[(n) * 4] | \ ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) #define GET(n) \ (ctx->block[(n)]) #endif /* * This processes one or more 64-byte data blocks, but does NOT update * the bit counters. There are no alignment requirements. */ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) { const unsigned char *ptr; MD5_u32plus a, b, c, d; ptr = (const unsigned char *)data; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; do { MD5_u32plus saved_a, saved_b, saved_c, saved_d; saved_a = a; saved_b = b; saved_c = c; saved_d = d; /* Round 1 */ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) STEP(F, c, d, a, b, SET(2), 0x242070db, 17) STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) /* Round 2 */ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) STEP(G, d, a, b, c, GET(10), 0x02441453, 9) STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) /* Round 3 */ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) /* Round 4 */ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) a += saved_a; b += saved_b; c += saved_c; d += saved_d; ptr += 64; } while(size -= 64); ctx->a = a; ctx->b = b; ctx->c = c; ctx->d = d; return ptr; } static void MD5_Init(MD5_CTX *ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; ctx->c = 0x98badcfe; ctx->d = 0x10325476; ctx->lo = 0; ctx->hi = 0; } static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) { MD5_u32plus saved_lo; unsigned long used; saved_lo = ctx->lo; ctx->lo = (saved_lo + size) & 0x1fffffff; if(ctx->lo < saved_lo) ctx->hi++; ctx->hi += (MD5_u32plus)size >> 29; used = saved_lo & 0x3f; if(used) { unsigned long available = 64 - used; if(size < available) { memcpy(&ctx->buffer[used], data, size); return; } memcpy(&ctx->buffer[used], data, available); data = (const unsigned char *)data + available; size -= available; body(ctx, ctx->buffer, 64); } if(size >= 64) { data = body(ctx, data, size & ~(unsigned long)0x3f); size &= 0x3f; } memcpy(ctx->buffer, data, size); } static void MD5_Final(unsigned char *result, MD5_CTX *ctx) { unsigned long used, available; used = ctx->lo & 0x3f; ctx->buffer[used++] = 0x80; available = 64 - used; if(available < 8) { memset(&ctx->buffer[used], 0, available); body(ctx, ctx->buffer, 64); used = 0; available = 64; } memset(&ctx->buffer[used], 0, available - 8); ctx->lo <<= 3; ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff); ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff); ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff); ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24); ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff); ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff); ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff); ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24); body(ctx, ctx->buffer, 64); result[0] = curlx_ultouc((ctx->a)&0xff); result[1] = curlx_ultouc((ctx->a >> 8)&0xff); result[2] = curlx_ultouc((ctx->a >> 16)&0xff); result[3] = curlx_ultouc(ctx->a >> 24); result[4] = curlx_ultouc((ctx->b)&0xff); result[5] = curlx_ultouc((ctx->b >> 8)&0xff); result[6] = curlx_ultouc((ctx->b >> 16)&0xff); result[7] = curlx_ultouc(ctx->b >> 24); result[8] = curlx_ultouc((ctx->c)&0xff); result[9] = curlx_ultouc((ctx->c >> 8)&0xff); result[10] = curlx_ultouc((ctx->c >> 16)&0xff); result[11] = curlx_ultouc(ctx->c >> 24); result[12] = curlx_ultouc((ctx->d)&0xff); result[13] = curlx_ultouc((ctx->d >> 8)&0xff); result[14] = curlx_ultouc((ctx->d >> 16)&0xff); result[15] = curlx_ultouc(ctx->d >> 24); memset(ctx, 0, sizeof(*ctx)); } #endif /* CRYPTO LIBS */ const HMAC_params Curl_HMAC_MD5[] = { { /* Hash initialization function. */ CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init), /* Hash update function. */ CURLX_FUNCTION_CAST(HMAC_hupdate_func, MD5_Update), /* Hash computation end function. */ CURLX_FUNCTION_CAST(HMAC_hfinal_func, MD5_Final), /* Size of hash context structure. */ sizeof(MD5_CTX), /* Maximum key length. */ 64, /* Result size. */ 16 } }; const MD5_params Curl_DIGEST_MD5[] = { { /* Digest initialization function */ CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init), /* Digest update function */ CURLX_FUNCTION_CAST(Curl_MD5_update_func, MD5_Update), /* Digest computation end function */ CURLX_FUNCTION_CAST(Curl_MD5_final_func, MD5_Final), /* Size of digest context struct */ sizeof(MD5_CTX), /* Result size */ 16 } }; /* * @unittest: 1601 */ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input, const size_t len) { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, input, curlx_uztoui(len)); MD5_Final(outbuffer, &ctx); } MD5_context *Curl_MD5_init(const MD5_params *md5params) { MD5_context *ctxt; /* Create MD5 context */ ctxt = malloc(sizeof(*ctxt)); if(!ctxt) return ctxt; ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize); if(!ctxt->md5_hashctx) { free(ctxt); return NULL; } ctxt->md5_hash = md5params; (*md5params->md5_init_func)(ctxt->md5_hashctx); return ctxt; } CURLcode Curl_MD5_update(MD5_context *context, const unsigned char *data, unsigned int len) { (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len); return CURLE_OK; } CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result) { (*context->md5_hash->md5_final_func)(result, context->md5_hashctx); free(context->md5_hashctx); free(context); return CURLE_OK; } #endif /* CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/speedcheck.h0000644000000000000000000000245014121063461016244 0ustar rootroot#ifndef HEADER_CURL_SPEEDCHECK_H #define HEADER_CURL_SPEEDCHECK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "timeval.h" void Curl_speedinit(struct Curl_easy *data); CURLcode Curl_speedcheck(struct Curl_easy *data, struct curltime now); #endif /* HEADER_CURL_SPEEDCHECK_H */ davix-0.8.0/deps/curl/lib/rtsp.h0000644000000000000000000000433114121063461015136 0ustar rootroot#ifndef HEADER_CURL_RTSP_H #define HEADER_CURL_RTSP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_RTSP extern const struct Curl_handler Curl_handler_rtsp; CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header); #else /* disabled */ #define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN #endif /* CURL_DISABLE_RTSP */ /* * RTSP Connection data * * Currently, only used for tracking incomplete RTP data reads */ struct rtsp_conn { char *rtp_buf; ssize_t rtp_bufsize; int rtp_channel; }; /**************************************************************************** * RTSP unique setup ***************************************************************************/ struct RTSP { /* * http_wrapper MUST be the first element of this structure for the wrap * logic to work. In this way, we get a cheap polymorphism because * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec * * HTTP functions can safely treat this as an HTTP struct, but RTSP aware * functions can also index into the later elements. */ struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */ long CSeq_sent; /* CSeq of this request */ long CSeq_recv; /* CSeq received */ }; #endif /* HEADER_CURL_RTSP_H */ davix-0.8.0/deps/curl/lib/curl_hmac.h0000644000000000000000000000550114121063461016103 0ustar rootroot#ifndef HEADER_CURL_HMAC_H #define HEADER_CURL_HMAC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH #define HMAC_MD5_LENGTH 16 typedef void (* HMAC_hinit_func)(void *context); typedef void (* HMAC_hupdate_func)(void *context, const unsigned char *data, unsigned int len); typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context); /* Per-hash function HMAC parameters. */ typedef struct { HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */ HMAC_hupdate_func hmac_hupdate; /* Update context with data. */ HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */ unsigned int hmac_ctxtsize; /* Context structure size. */ unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */ unsigned int hmac_resultlen; /* Result length (bytes). */ } HMAC_params; /* HMAC computation context. */ typedef struct { const HMAC_params *hmac_hash; /* Hash function definition. */ void *hmac_hashctxt1; /* Hash function context 1. */ void *hmac_hashctxt2; /* Hash function context 2. */ } HMAC_context; /* Prototypes. */ HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams, const unsigned char *key, unsigned int keylen); int Curl_HMAC_update(HMAC_context *context, const unsigned char *data, unsigned int len); int Curl_HMAC_final(HMAC_context *context, unsigned char *result); CURLcode Curl_hmacit(const HMAC_params *hashparams, const unsigned char *key, const size_t keylen, const unsigned char *data, const size_t datalen, unsigned char *output); #endif #endif /* HEADER_CURL_HMAC_H */ davix-0.8.0/deps/curl/lib/progress.h0000644000000000000000000000465314121063461016021 0ustar rootroot#ifndef HEADER_CURL_PROGRESS_H #define HEADER_CURL_PROGRESS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "timeval.h" typedef enum { TIMER_NONE, TIMER_STARTOP, TIMER_STARTSINGLE, TIMER_NAMELOOKUP, TIMER_CONNECT, TIMER_APPCONNECT, TIMER_PRETRANSFER, TIMER_STARTTRANSFER, TIMER_POSTRANSFER, TIMER_STARTACCEPT, TIMER_REDIRECT, TIMER_LAST /* must be last */ } timerid; int Curl_pgrsDone(struct connectdata *); void Curl_pgrsStartNow(struct Curl_easy *data); void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); void Curl_ratelimit(struct Curl_easy *data, struct curltime now); int Curl_pgrsUpdate(struct connectdata *); void Curl_pgrsResetTransferSizes(struct Curl_easy *data); void Curl_pgrsTime(struct Curl_easy *data, timerid timer); timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, curl_off_t startsize, curl_off_t limit, struct curltime start, struct curltime now); #define PGRS_HIDE (1<<4) #define PGRS_UL_SIZE_KNOWN (1<<5) #define PGRS_DL_SIZE_KNOWN (1<<6) #define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */ #endif /* HEADER_CURL_PROGRESS_H */ davix-0.8.0/deps/curl/lib/psl.c0000644000000000000000000000632114121063461014740 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #ifdef USE_LIBPSL #include "psl.h" #include "share.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" void Curl_psl_destroy(struct PslCache *pslcache) { if(pslcache->psl) { if(pslcache->dynamic) psl_free((psl_ctx_t *) pslcache->psl); pslcache->psl = NULL; pslcache->dynamic = FALSE; } } static time_t now_seconds(void) { struct curltime now = Curl_now(); return now.tv_sec; } const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy) { struct PslCache *pslcache = easy->psl; const psl_ctx_t *psl; time_t now; if(!pslcache) return NULL; Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED); now = now_seconds(); if(!pslcache->psl || pslcache->expires <= now) { /* Let a chance to other threads to do the job: avoids deadlock. */ Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); /* Update cache: this needs an exclusive lock. */ Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE); /* Recheck in case another thread did the job. */ now = now_seconds(); if(!pslcache->psl || pslcache->expires <= now) { bool dynamic = FALSE; time_t expires = TIME_T_MAX; #if defined(PSL_VERSION_NUMBER) && PSL_VERSION_NUMBER >= 0x001000 psl = psl_latest(NULL); dynamic = psl != NULL; /* Take care of possible time computation overflow. */ expires = now < TIME_T_MAX - PSL_TTL? now + PSL_TTL: TIME_T_MAX; /* Only get the built-in PSL if we do not already have the "latest". */ if(!psl && !pslcache->dynamic) #endif psl = psl_builtin(); if(psl) { Curl_psl_destroy(pslcache); pslcache->psl = psl; pslcache->dynamic = dynamic; pslcache->expires = expires; } } Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); /* Release exclusive lock. */ Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED); } psl = pslcache->psl; if(!psl) Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); return psl; } void Curl_psl_release(struct Curl_easy *easy) { Curl_share_unlock(easy, CURL_LOCK_DATA_PSL); } #endif /* USE_LIBPSL */ davix-0.8.0/deps/curl/lib/hostasyn.c0000644000000000000000000000747514121063461016025 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /*********************************************************************** * Only for builds using asynchronous name resolves **********************************************************************/ #ifdef CURLRES_ASYNCH #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_PROCESS_H #include #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread() * or getaddrinfo_thread() when we got the name resolved (or not!). * * If the status argument is CURL_ASYNC_SUCCESS, this function takes * ownership of the Curl_addrinfo passed, storing the resolved data * in the DNS cache. * * The storage operation locks and unlocks the DNS cache. */ CURLcode Curl_addrinfo_callback(struct connectdata *conn, int status, struct Curl_addrinfo *ai) { struct Curl_dns_entry *dns = NULL; CURLcode result = CURLE_OK; conn->async.status = status; if(CURL_ASYNC_SUCCESS == status) { if(ai) { struct Curl_easy *data = conn->data; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = Curl_cache_addr(data, ai, conn->async.hostname, conn->async.port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { /* failed to store, cleanup and return error */ Curl_freeaddrinfo(ai); result = CURLE_OUT_OF_MEMORY; } } else { result = CURLE_OUT_OF_MEMORY; } } conn->async.dns = dns; /* Set async.done TRUE last in this function since it may be used multi- threaded and once this is TRUE the other thread may read fields from the async struct */ conn->async.done = TRUE; /* IPv4: The input hostent struct will be freed by ares when we return from this function */ return result; } /* * Curl_getaddrinfo() is the generic low-level name resolve API within this * source file. There are several versions of this function - for different * name resolve layers (selected at build-time). They all take this same set * of arguments */ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { return Curl_resolver_getaddrinfo(conn, hostname, port, waitp); } #endif /* CURLRES_ASYNCH */ davix-0.8.0/deps/curl/lib/conncache.h0000644000000000000000000001103014121063461016061 0ustar rootroot#ifndef HEADER_CURL_CONNCACHE_H #define HEADER_CURL_CONNCACHE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2015 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * All accesses to struct fields and changing of data in the connection cache * and connectbundles must be done with the conncache LOCKED. The cache might * be shared. */ struct conncache { struct curl_hash hash; size_t num_conn; long next_connection_id; struct curltime last_cleanup; /* handle used for closing cached connections */ struct Curl_easy *closure_handle; }; #define BUNDLE_NO_MULTIUSE -1 #define BUNDLE_UNKNOWN 0 /* initial value */ #define BUNDLE_MULTIPLEX 2 #ifdef CURLDEBUG /* the debug versions of these macros make extra certain that the lock is never doubly locked or unlocked */ #define CONN_LOCK(x) if((x)->share) { \ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \ DEBUGASSERT(!(x)->state.conncache_lock); \ (x)->state.conncache_lock = TRUE; \ } #define CONN_UNLOCK(x) if((x)->share) { \ DEBUGASSERT((x)->state.conncache_lock); \ (x)->state.conncache_lock = FALSE; \ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \ } #else #define CONN_LOCK(x) if((x)->share) \ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE) #define CONN_UNLOCK(x) if((x)->share) \ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT) #endif struct connectbundle { int multiuse; /* supports multi-use */ size_t num_connections; /* Number of connections in the bundle */ struct curl_llist conn_list; /* The connectdata members of the bundle */ }; /* returns 1 on error, 0 is fine */ int Curl_conncache_init(struct conncache *, int size); void Curl_conncache_destroy(struct conncache *connc); /* return the correct bundle, to a host or a proxy */ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, struct conncache *connc, const char **hostp); void Curl_conncache_unlock(struct Curl_easy *data); /* returns number of connections currently held in the connection cache */ size_t Curl_conncache_size(struct Curl_easy *data); bool Curl_conncache_return_conn(struct Curl_easy *data, struct connectdata *conn); CURLcode Curl_conncache_add_conn(struct conncache *connc, struct connectdata *conn) WARN_UNUSED_RESULT; void Curl_conncache_remove_conn(struct Curl_easy *data, struct connectdata *conn, bool lock); bool Curl_conncache_foreach(struct Curl_easy *data, struct conncache *connc, void *param, int (*func)(struct connectdata *conn, void *param)); struct connectdata * Curl_conncache_find_first_connection(struct conncache *connc); struct connectdata * Curl_conncache_extract_bundle(struct Curl_easy *data, struct connectbundle *bundle); struct connectdata * Curl_conncache_extract_oldest(struct Curl_easy *data); void Curl_conncache_close_all_connections(struct conncache *connc); void Curl_conncache_print(struct conncache *connc); #endif /* HEADER_CURL_CONNCACHE_H */ davix-0.8.0/deps/curl/lib/config-vxworks.h0000644000000000000000000006225014121063461017140 0ustar rootroot#ifndef HEADER_CURL_CONFIG_VXWORKS_H #define HEADER_CURL_CONFIG_VXWORKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* =============================================================== */ /* Hand crafted config file for VxWorks */ /* =============================================================== */ /* Location of default ca bundle */ /* #undef CURL_CA_BUNDLE */ /* Location of default ca path */ /* #undef CURL_CA_PATH */ /* to disable cookies support */ /* #undef CURL_DISABLE_COOKIES */ /* to disable cryptographic authentication */ /* #undef CURL_DISABLE_CRYPTO_AUTH */ /* to disable DICT */ /* #undef CURL_DISABLE_DICT */ /* to disable FILE */ /* #undef CURL_DISABLE_FILE */ /* to disable FTP */ #define CURL_DISABLE_FTP 1 /* to disable HTTP */ /* #undef CURL_DISABLE_HTTP */ /* to disable LDAP */ #define CURL_DISABLE_LDAP 1 /* to disable LDAPS */ #define CURL_DISABLE_LDAPS 1 /* to disable NTLM authentication */ #define CURL_DISABLE_NTLM 1 /* to disable proxies */ /* #undef CURL_DISABLE_PROXY */ /* to disable TELNET */ #define CURL_DISABLE_TELNET 1 /* to disable TFTP */ #define CURL_DISABLE_TFTP 1 /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ /* Definition to make a library symbol externally visible. */ /* #undef CURL_EXTERN_SYMBOL */ /* Use Windows LDAP implementation */ /* #undef USE_WIN32_LDAP */ /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ /* Define if you want to enable IPv6 support */ #define ENABLE_IPV6 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 size_t /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 unsigned int /* Specifies the number of arguments to getservbyport_r */ #define GETSERVBYPORT_R_ARGS 6 /* Specifies the size of the buffer to pass to getservbyport_r */ #define GETSERVBYPORT_R_BUFSIZE 4096 /* Define to 1 if you have the alarm function. */ #define HAVE_ALARM 1 /* Define to 1 if you have the header file. */ #define HAVE_ALLOCA_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_TFTP_H */ /* Define to 1 if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define to 1 if you have the `basename' function. */ /* #undef HAVE_BASENAME */ /* Define to 1 if bool is an available type. */ #define HAVE_BOOL_T 1 /* Define to 1 if you have the clock_gettime function and monotonic timer. */ /* #undef HAVE_CLOCK_GETTIME_MONOTONIC */ /* Define to 1 if you have the `closesocket' function. */ /* #undef HAVE_CLOSESOCKET */ /* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DES_H */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ERR_H */ /* Define to 1 if you have the fcntl function. */ #define HAVE_FCNTL 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have a working fcntl O_NONBLOCK function. */ #define HAVE_FCNTL_O_NONBLOCK 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the freeaddrinfo function. */ #define HAVE_FREEADDRINFO 1 /* Define to 1 if you have the freeifaddrs function. */ #define HAVE_FREEIFADDRS 1 /* Define to 1 if you have the ftruncate function. */ #define HAVE_FTRUNCATE 1 /* Define to 1 if you have a working getaddrinfo function. */ #define HAVE_GETADDRINFO 1 /* Define to 1 if you have the `geteuid' function. */ /* #undef HAVE_GETEUID */ /* Define to 1 if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 /* Define to 1 if you have the gethostbyaddr_r function. */ #define HAVE_GETHOSTBYADDR_R 1 /* gethostbyaddr_r() takes 5 args */ /* #undef HAVE_GETHOSTBYADDR_R_5 */ /* gethostbyaddr_r() takes 7 args */ /* #undef HAVE_GETHOSTBYADDR_R_7 */ /* gethostbyaddr_r() takes 8 args */ #define HAVE_GETHOSTBYADDR_R_8 1 /* Define to 1 if you have the gethostbyname function. */ #define HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the gethostbyname_r function. */ /* #undef HAVE_GETHOSTBYNAME_R */ /* gethostbyname_r() takes 3 args */ /* #undef HAVE_GETHOSTBYNAME_R_3 */ /* gethostbyname_r() takes 5 args */ /* #undef HAVE_GETHOSTBYNAME_R_5 */ /* gethostbyname_r() takes 6 args */ /* #undef HAVE_GETHOSTBYNAME_R_6 */ /* Define to 1 if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 /* Define to 1 if you have a working getifaddrs function. */ /* #undef HAVE_GETIFADDRS */ /* Define to 1 if you have the getnameinfo function. */ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getpass_r' function. */ /* #undef HAVE_GETPASS_R */ /* Define to 1 if you have the `getppid' function. */ #define HAVE_GETPPID 1 /* Define to 1 if you have the `getprotobyname' function. */ #define HAVE_GETPROTOBYNAME 1 /* Define to 1 if you have the `getpwuid' function. */ /* #undef HAVE_GETPWUID */ /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 /* Define to 1 if you have the getservbyport_r function. */ /* #undef HAVE_GETSERVBYPORT_R */ /* Define to 1 if you have the `gettimeofday' function. */ /* #undef HAVE_GETTIMEOFDAY */ /* Define to 1 if you have a working glibc-style strerror_r function. */ /* #undef HAVE_GLIBC_STRERROR_R */ /* Define to 1 if you have a working gmtime_r function. */ #define HAVE_GMTIME_R 1 /* if you have the gssapi libraries */ /* #undef HAVE_GSSAPI */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */ /* if you have the GNU gssapi libraries */ /* #undef HAVE_GSSGNU */ /* if you have the Heimdal gssapi libraries */ /* #undef HAVE_GSSHEIMDAL */ /* if you have the MIT gssapi libraries */ /* #undef HAVE_GSSMIT */ /* Define to 1 if you have the `idna_strerror' function. */ /* #undef HAVE_IDNA_STRERROR */ /* Define to 1 if you have the `idn_free' function. */ /* #undef HAVE_IDN_FREE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IDN_FREE_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IFADDRS_H */ /* Define to 1 if you have the `inet_addr' function. */ #define HAVE_INET_ADDR 1 /* Define to 1 if you have the inet_ntoa_r function. */ /* #undef HAVE_INET_NTOA_R */ /* inet_ntoa_r() takes 2 args */ /* #undef HAVE_INET_NTOA_R_2 */ /* inet_ntoa_r() takes 3 args */ /* #undef HAVE_INET_NTOA_R_3 */ /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ /* #undef HAVE_INET_NTOP */ /* Define to 1 if you have a IPv6 capable working inet_pton function. */ /* #undef HAVE_INET_PTON */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the ioctl function. */ #define HAVE_IOCTL 1 /* Define to 1 if you have the ioctlsocket function. */ /* #undef HAVE_IOCTLSOCKET */ /* Define to 1 if you have the IoctlSocket camel case function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL */ /* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ /* Define to 1 if you have a working ioctlsocket FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_FIONBIO */ /* Define to 1 if you have a working ioctl FIONBIO function. */ #define HAVE_IOCTL_FIONBIO 1 /* Define to 1 if you have a working ioctl SIOCGIFADDR function. */ #define HAVE_IOCTL_SIOCGIFADDR 1 /* Define to 1 if you have the header file. */ #define HAVE_IO_H 1 /* if you have the Kerberos4 libraries (including -ldes) */ /* #undef HAVE_KRB4 */ /* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ /* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KRB_H */ /* Define to 1 if you have the lber.h header file. */ /* #undef HAVE_LBER_H */ /* Define to 1 if you have the ldapssl.h header file. */ /* #undef HAVE_LDAPSSL_H */ /* Define to 1 if you have the ldap.h header file. */ /* #undef HAVE_LDAP_H */ /* Use LDAPS implementation */ /* #undef HAVE_LDAP_SSL */ /* Define to 1 if you have the ldap_ssl.h header file. */ /* #undef HAVE_LDAP_SSL_H */ /* Define to 1 if you have the `ldap_url_parse' function. */ /* #undef HAVE_LDAP_URL_PARSE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBGEN_H */ /* Define to 1 if you have the `idn' library (-lidn). */ /* #undef HAVE_LIBIDN */ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `resolve' library (-lresolve). */ /* #undef HAVE_LIBRESOLVE */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Define to 1 if you have the `ssh2' library (-lssh2). */ /* #undef HAVE_LIBSSH2 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBSSH2_H */ /* Define to 1 if you have the `libssh2_version' function. */ /* #undef HAVE_LIBSSH2_VERSION */ /* if zlib is available */ #define HAVE_LIBZ 1 /* if your compiler supports LL */ #define HAVE_LL 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have a working localtime_r function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if the compiler supports the 'long long' data type. */ #define HAVE_LONGLONG 1 /* Define to 1 if you have the malloc.h header file. */ #define HAVE_MALLOC_H 1 /* Define to 1 if you have the memory.h header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the MSG_NOSIGNAL flag. */ /* #undef HAVE_MSG_NOSIGNAL */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_TCP_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 /* Define to 1 if NI_WITHSCOPEID exists and works. */ /* #undef HAVE_NI_WITHSCOPEID */ /* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ /* #undef HAVE_OLD_GSSMIT */ /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_CRYPTO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_ERR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_PEM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_PKCS12_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_RSA_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_SSL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_X509_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_PEM_H */ /* Define to 1 if you have the `perror' function. */ #define HAVE_PERROR 1 /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have a working poll function. */ /* #undef HAVE_POLL */ /* If you have a fine poll */ /* #undef HAVE_POLL_FINE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ /* Define to 1 if you have a working POSIX-style strerror_r function. */ /* #undef HAVE_POSIX_STRERROR_R */ /* Define to 1 if you have the header file. */ /* #undef HAVE_PWD_H */ /* Define to 1 if you have the `RAND_egd' function. */ #define HAVE_RAND_EGD 1 /* Define to 1 if you have the `RAND_screen' function. */ /* #undef HAVE_RAND_SCREEN */ /* Define to 1 if you have the `RAND_status' function. */ #define HAVE_RAND_STATUS 1 /* Define to 1 if you have the recv function. */ #define HAVE_RECV 1 /* Define to 1 if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_RSA_H */ /* Define to 1 if you have the select function. */ #define HAVE_SELECT 1 /* Define to 1 if you have the send function. */ #define HAVE_SEND 1 /* Define to 1 if you have the header file. */ #define HAVE_SETJMP_H 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setmode' function. */ #define HAVE_SETMODE 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define to 1 if you have the setsockopt function. */ #define HAVE_SETSOCKOPT 1 /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ /* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SGTTY_H */ /* Define to 1 if you have the sigaction function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the siginterrupt function. */ #define HAVE_SIGINTERRUPT 1 /* Define to 1 if you have the signal function. */ #define HAVE_SIGNAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define to 1 if you have the sigsetjmp function or macro. */ /* #undef HAVE_SIGSETJMP */ /* Define to 1 if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 /* Define to 1 if sig_atomic_t is already defined as volatile. */ /* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SSL_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STDINT_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the strdup function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the strerror_r function. */ #define HAVE_STRERROR_R 1 /* Define to 1 if you have the stricmp function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ /* Define to 1 if you have the strncasecmp function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the strncmpi function. */ /* #undef HAVE_STRNCMPI */ /* Define to 1 if you have the strnicmp function. */ /* #undef HAVE_STRNICMP */ /* Define to 1 if you have the header file. */ /* #undef HAVE_STROPTS_H */ /* Define to 1 if you have the strstr function. */ #define HAVE_STRSTR 1 /* Define to 1 if you have the strtok_r function. */ #define HAVE_STRTOK_R 1 /* Define to 1 if you have the strtoll function. */ /* #undef HAVE_STRTOLL */ /* if struct sockaddr_storage is defined */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if you have the timeval struct. */ #define HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FILIO_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PARAM_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SELECT_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKIO_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIME_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UTIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TERMIOS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TERMIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TLD_H */ /* Define to 1 if you have the `tld_strerror' function. */ /* #undef HAVE_TLD_STRERROR */ /* Define to 1 if you have the `uname' function. */ #define HAVE_UNAME 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* Define to 1 if compiler supports C99 variadic macro style. */ #define HAVE_VARIADIC_MACROS_C99 1 /* Define to 1 if compiler supports old gcc variadic macro style. */ #define HAVE_VARIADIC_MACROS_GCC 1 /* Define to 1 if you have a working vxworks-style strerror_r function. */ #define HAVE_VXWORKS_STRERROR_R 1 /* Define to 1 if you have the winber.h header file. */ /* #undef HAVE_WINBER_H */ /* Define to 1 if you have the windows.h header file. */ /* #undef HAVE_WINDOWS_H */ /* Define to 1 if you have the winldap.h header file. */ /* #undef HAVE_WINLDAP_H */ /* Define to 1 if you have the winsock2.h header file. */ /* #undef HAVE_WINSOCK2_H */ /* Define to 1 if you have the winsock.h header file. */ /* #undef HAVE_WINSOCK_H */ /* Define this symbol if your OS supports changing the contents of argv */ #define HAVE_WRITABLE_ARGV 1 /* Define to 1 if you have the writev function. */ #define HAVE_WRITEV 1 /* Define to 1 if you have the ws2tcpip.h header file. */ /* #undef HAVE_WS2TCPIP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_X509_H */ /* if you have the zlib.h header file */ #define HAVE_ZLIB_H 1 /* Define to 1 if you need the lber.h header file even with ldap.h */ /* #undef NEED_LBER_H */ /* Define to 1 if you need the malloc.h header file even with stdlib.h */ /* #undef NEED_MALLOC_H */ /* Define to 1 if you need the memory.h header file even with stdlib.h */ /* #undef NEED_MEMORY_H */ /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ /* #undef NEED_REENTRANT */ /* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ /* #undef NEED_THREAD_SAFE */ /* Define to 1 if the open function requires three arguments. */ #define OPEN_NEEDS_ARG3 1 /* cpu-machine-OS */ #define OS "unknown-unknown-vxworks" /* Name of package */ #define PACKAGE "curl" /* a suitable file to read random data from */ #define RANDOM_FILE "/dev/urandom" /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 int /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 void /* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ #define RECVFROM_TYPE_ARG2_IS_VOID 1 /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 size_t /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ /* #undef RECVFROM_TYPE_ARG5_IS_VOID */ /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 socklen_t /* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ /* #undef RECVFROM_TYPE_ARG6_IS_VOID */ /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV int /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 int /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 void * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 size_t /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV int /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the type qualifier of arg 5 for select. */ #define SELECT_QUAL_ARG5 /* Define to the type of arg 1 for select. */ #define SELECT_TYPE_ARG1 int /* Define to the type of args 2, 3 and 4 for select. */ #define SELECT_TYPE_ARG234 fd_set * /* Define to the type of arg 5 for select. */ #define SELECT_TYPE_ARG5 struct timeval * /* Define to the function return type for select. */ #define SELECT_TYPE_RETV int /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 const /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 int /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 void * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 size_t /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV int /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 4 /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 4 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to the type of arg 3 for strerror_r. */ /* #undef STRERROR_R_TYPE_ARG3 */ /* Define to 1 if you can safely include both and . */ /* #undef TIME_WITH_SYS_TIME */ /* Define if you want to enable c-ares support */ /* #undef USE_ARES */ /* Define to disable non-blocking sockets. */ /* #undef USE_BLOCKING_SOCKETS */ /* if GnuTLS is enabled */ /* #undef USE_GNUTLS */ /* if libSSH2 is in use */ /* #undef USE_LIBSSH2 */ /* If you want to build curl with the built-in manual */ #define USE_MANUAL 1 /* if NSS is enabled */ /* #undef USE_NSS */ /* if OpenSSL is in use */ #define USE_OPENSSL 1 /* Define to 1 if you are building a Windows target without large file support. */ /* #undef USE_WIN32_LARGE_FILES */ /* to enable SSPI support */ /* #undef USE_WINDOWS_SSPI */ /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ /* #undef USE_YASSLEMUL */ /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ /* Define to 1 if OS is AIX. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Type to use in place of in_addr_t when system does not provide it. */ /* #undef in_addr_t */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* the signed version of size_t */ /* #undef ssize_t */ #endif /* HEADER_CURL_CONFIG_VXWORKS_H */ davix-0.8.0/deps/curl/lib/curl_addrinfo.c0000644000000000000000000003736214121063461016766 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_NETINET_IN6_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif #ifdef __VMS # include # include #endif #if defined(NETWARE) && defined(__NOVELL_LIBC__) # undef in_addr_t # define in_addr_t unsigned long #endif #if defined(WIN32) && defined(USE_UNIX_SOCKETS) #include #endif #include #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Curl_freeaddrinfo() * * This is used to free a linked list of Curl_addrinfo structs along * with all its associated allocated storage. This function should be * called once for each successful call to Curl_getaddrinfo_ex() or to * any function call which actually allocates a Curl_addrinfo struct. */ #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) /* workaround icc 9.1 optimizer issue */ # define vqualifier volatile #else # define vqualifier #endif void Curl_freeaddrinfo(Curl_addrinfo *cahead) { Curl_addrinfo *vqualifier canext; Curl_addrinfo *ca; for(ca = cahead; ca != NULL; ca = canext) { free(ca->ai_addr); free(ca->ai_canonname); canext = ca->ai_next; free(ca); } } #ifdef HAVE_GETADDRINFO /* * Curl_getaddrinfo_ex() * * This is a wrapper function around system's getaddrinfo(), with * the only difference that instead of returning a linked list of * addrinfo structs this one returns a linked list of Curl_addrinfo * ones. The memory allocated by this function *MUST* be free'd with * Curl_freeaddrinfo(). For each successful call to this function * there must be an associated call later to Curl_freeaddrinfo(). * * There should be no single call to system's getaddrinfo() in the * whole library, any such call should be 'routed' through this one. */ int Curl_getaddrinfo_ex(const char *nodename, const char *servname, const struct addrinfo *hints, Curl_addrinfo **result) { const struct addrinfo *ai; struct addrinfo *aihead; Curl_addrinfo *cafirst = NULL; Curl_addrinfo *calast = NULL; Curl_addrinfo *ca; size_t ss_size; int error; *result = NULL; /* assume failure */ error = getaddrinfo(nodename, servname, hints, &aihead); if(error) return error; /* traverse the addrinfo list */ for(ai = aihead; ai != NULL; ai = ai->ai_next) { /* ignore elements with unsupported address family, */ /* settle family-specific sockaddr structure size. */ if(ai->ai_family == AF_INET) ss_size = sizeof(struct sockaddr_in); #ifdef ENABLE_IPV6 else if(ai->ai_family == AF_INET6) ss_size = sizeof(struct sockaddr_in6); #endif else continue; /* ignore elements without required address info */ if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0)) continue; /* ignore elements with bogus address size */ if((size_t)ai->ai_addrlen < ss_size) continue; ca = malloc(sizeof(Curl_addrinfo)); if(!ca) { error = EAI_MEMORY; break; } /* copy each structure member individually, member ordering, */ /* size, or padding might be different for each platform. */ ca->ai_flags = ai->ai_flags; ca->ai_family = ai->ai_family; ca->ai_socktype = ai->ai_socktype; ca->ai_protocol = ai->ai_protocol; ca->ai_addrlen = (curl_socklen_t)ss_size; ca->ai_addr = NULL; ca->ai_canonname = NULL; ca->ai_next = NULL; ca->ai_addr = malloc(ss_size); if(!ca->ai_addr) { error = EAI_MEMORY; free(ca); break; } memcpy(ca->ai_addr, ai->ai_addr, ss_size); if(ai->ai_canonname != NULL) { ca->ai_canonname = strdup(ai->ai_canonname); if(!ca->ai_canonname) { error = EAI_MEMORY; free(ca->ai_addr); free(ca); break; } } /* if the return list is empty, this becomes the first element */ if(!cafirst) cafirst = ca; /* add this element last in the return list */ if(calast) calast->ai_next = ca; calast = ca; } /* destroy the addrinfo list */ if(aihead) freeaddrinfo(aihead); /* if we failed, also destroy the Curl_addrinfo list */ if(error) { Curl_freeaddrinfo(cafirst); cafirst = NULL; } else if(!cafirst) { #ifdef EAI_NONAME /* rfc3493 conformant */ error = EAI_NONAME; #else /* rfc3493 obsoleted */ error = EAI_NODATA; #endif #ifdef USE_WINSOCK SET_SOCKERRNO(error); #endif } *result = cafirst; /* This is not a CURLcode */ return error; } #endif /* HAVE_GETADDRINFO */ /* * Curl_he2ai() * * This function returns a pointer to the first element of a newly allocated * Curl_addrinfo struct linked list filled with the data of a given hostent. * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 * stack, but usable also for IPv4, all hosts and environments. * * The memory allocated by this function *MUST* be free'd later on calling * Curl_freeaddrinfo(). For each successful call to this function there * must be an associated call later to Curl_freeaddrinfo(). * * Curl_addrinfo defined in "lib/curl_addrinfo.h" * * struct Curl_addrinfo { * int ai_flags; * int ai_family; * int ai_socktype; * int ai_protocol; * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * * char *ai_canonname; * struct sockaddr *ai_addr; * struct Curl_addrinfo *ai_next; * }; * typedef struct Curl_addrinfo Curl_addrinfo; * * hostent defined in * * struct hostent { * char *h_name; * char **h_aliases; * int h_addrtype; * int h_length; * char **h_addr_list; * }; * * for backward compatibility: * * #define h_addr h_addr_list[0] */ Curl_addrinfo * Curl_he2ai(const struct hostent *he, int port) { Curl_addrinfo *ai; Curl_addrinfo *prevai = NULL; Curl_addrinfo *firstai = NULL; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; #endif CURLcode result = CURLE_OK; int i; char *curr; if(!he) /* no input == no output! */ return NULL; DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { size_t ss_size; #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) ss_size = sizeof(struct sockaddr_in6); else #endif ss_size = sizeof(struct sockaddr_in); ai = calloc(1, sizeof(Curl_addrinfo)); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } ai->ai_canonname = strdup(he->h_name); if(!ai->ai_canonname) { result = CURLE_OUT_OF_MEMORY; free(ai); break; } ai->ai_addr = calloc(1, ss_size); if(!ai->ai_addr) { result = CURLE_OUT_OF_MEMORY; free(ai->ai_canonname); free(ai); break; } if(!firstai) /* store the pointer we want to return from this function */ firstai = ai; if(prevai) /* make the previous entry point to this */ prevai->ai_next = ai; ai->ai_family = he->h_addrtype; /* we return all names as STREAM, so when using this address for TFTP the type must be ignored and conn->socktype be used instead! */ ai->ai_socktype = SOCK_STREAM; ai->ai_addrlen = (curl_socklen_t)ss_size; /* leave the rest of the struct filled with zero */ switch(ai->ai_family) { case AF_INET: addr = (void *)ai->ai_addr; /* storage area for this info */ memcpy(&addr->sin_addr, curr, sizeof(struct in_addr)); addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype); addr->sin_port = htons((unsigned short)port); break; #ifdef ENABLE_IPV6 case AF_INET6: addr6 = (void *)ai->ai_addr; /* storage area for this info */ memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr)); addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype); addr6->sin6_port = htons((unsigned short)port); break; #endif } prevai = ai; } if(result) { Curl_freeaddrinfo(firstai); firstai = NULL; } return firstai; } struct namebuff { struct hostent hostentry; union { struct in_addr ina4; #ifdef ENABLE_IPV6 struct in6_addr ina6; #endif } addrentry; char *h_addr_list[2]; }; /* * Curl_ip2addr() * * This function takes an internet address, in binary form, as input parameter * along with its address family and the string version of the address, and it * returns a Curl_addrinfo chain filled in correctly with information for the * given address/host */ Curl_addrinfo * Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) { Curl_addrinfo *ai; #if defined(__VMS) && \ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) #pragma pointer_size save #pragma pointer_size short #pragma message disable PTRMISMATCH #endif struct hostent *h; struct namebuff *buf; char *addrentry; char *hoststr; size_t addrsize; DEBUGASSERT(inaddr && hostname); buf = malloc(sizeof(struct namebuff)); if(!buf) return NULL; hoststr = strdup(hostname); if(!hoststr) { free(buf); return NULL; } switch(af) { case AF_INET: addrsize = sizeof(struct in_addr); addrentry = (void *)&buf->addrentry.ina4; memcpy(addrentry, inaddr, sizeof(struct in_addr)); break; #ifdef ENABLE_IPV6 case AF_INET6: addrsize = sizeof(struct in6_addr); addrentry = (void *)&buf->addrentry.ina6; memcpy(addrentry, inaddr, sizeof(struct in6_addr)); break; #endif default: free(hoststr); free(buf); return NULL; } h = &buf->hostentry; h->h_name = hoststr; h->h_aliases = NULL; h->h_addrtype = (short)af; h->h_length = (short)addrsize; h->h_addr_list = &buf->h_addr_list[0]; h->h_addr_list[0] = addrentry; h->h_addr_list[1] = NULL; /* terminate list of entries */ #if defined(__VMS) && \ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) #pragma pointer_size restore #pragma message enable PTRMISMATCH #endif ai = Curl_he2ai(h, port); free(hoststr); free(buf); return ai; } /* * Given an IPv4 or IPv6 dotted string address, this converts it to a proper * allocated Curl_addrinfo struct and returns it. */ Curl_addrinfo *Curl_str2addr(char *address, int port) { struct in_addr in; if(Curl_inet_pton(AF_INET, address, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ return Curl_ip2addr(AF_INET, &in, address, port); #ifdef ENABLE_IPV6 { struct in6_addr in6; if(Curl_inet_pton(AF_INET6, address, &in6) > 0) /* This is a dotted IPv6 address ::1-style */ return Curl_ip2addr(AF_INET6, &in6, address, port); } #endif return NULL; /* bad input format */ } #ifdef USE_UNIX_SOCKETS /** * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo * struct initialized with this path. * Set '*longpath' to TRUE if the error is a too long path. */ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) { Curl_addrinfo *ai; struct sockaddr_un *sa_un; size_t path_len; *longpath = FALSE; ai = calloc(1, sizeof(Curl_addrinfo)); if(!ai) return NULL; ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); if(!ai->ai_addr) { free(ai); return NULL; } sa_un = (void *) ai->ai_addr; sa_un->sun_family = AF_UNIX; /* sun_path must be able to store the NUL-terminated path */ path_len = strlen(path) + 1; if(path_len > sizeof(sa_un->sun_path)) { free(ai->ai_addr); free(ai); *longpath = TRUE; return NULL; } ai->ai_family = AF_UNIX; ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ ai->ai_addrlen = (curl_socklen_t) ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); /* Abstract Unix domain socket have NULL prefix instead of suffix */ if(abstract) memcpy(sa_un->sun_path + 1, path, path_len - 1); else memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ return ai; } #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ defined(HAVE_FREEADDRINFO) /* * curl_dbg_freeaddrinfo() * * This is strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they * require a bunch of structs I didn't want to include in memdebug.c */ void curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source) { curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n", source, line, (void *)freethis); #ifdef USE_LWIPSOCK lwip_freeaddrinfo(freethis); #else (freeaddrinfo)(freethis); #endif } #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) /* * curl_dbg_getaddrinfo() * * This is strictly for memory tracing and are using the same style as the * family otherwise present in memdebug.c. I put these ones here since they * require a bunch of structs I didn't want to include in memdebug.c */ int curl_dbg_getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result, int line, const char *source) { #ifdef USE_LWIPSOCK int res = lwip_getaddrinfo(hostname, service, hints, result); #else int res = (getaddrinfo)(hostname, service, hints, result); #endif if(0 == res) /* success */ curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n", source, line, (void *)*result); else curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n", source, line); return res; } #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) /* * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X * 10.11.5. */ void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) { Curl_addrinfo *ca; struct sockaddr_in *addr; #ifdef ENABLE_IPV6 struct sockaddr_in6 *addr6; #endif for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { switch(ca->ai_family) { case AF_INET: addr = (void *)ca->ai_addr; /* storage area for this info */ addr->sin_port = htons((unsigned short)port); break; #ifdef ENABLE_IPV6 case AF_INET6: addr6 = (void *)ca->ai_addr; /* storage area for this info */ addr6->sin6_port = htons((unsigned short)port); break; #endif } } } #endif davix-0.8.0/deps/curl/lib/if2ip.h0000644000000000000000000000567414121063461015172 0ustar rootroot#ifndef HEADER_CURL_IF2IP_H #define HEADER_CURL_IF2IP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* IPv6 address scopes. */ #define IPV6_SCOPE_GLOBAL 0 /* Global scope. */ #define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */ #define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */ #define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */ #define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */ unsigned int Curl_ipv6_scope(const struct sockaddr *sa); typedef enum { IF2IP_NOT_FOUND = 0, /* Interface not found */ IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */ IF2IP_FOUND = 2 /* The address has been stored in "buf" */ } if2ip_result_t; if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int local_scope_id, const char *interf, char *buf, int buf_size); #ifdef __INTERIX /* Nedelcho Stanev's work-around for SFU 3.0 */ struct ifreq { #define IFNAMSIZ 16 #define IFHWADDRLEN 6 union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_metric; int ifru_mtu; } ifr_ifru; }; /* This define was added by Daniel to avoid an extra #ifdef INTERIX in the C code. */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ #endif /* __INTERIX */ #endif /* HEADER_CURL_IF2IP_H */ davix-0.8.0/deps/curl/lib/socks_sspi.c0000644000000000000000000005463614121063461016336 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY) #include "urldata.h" #include "sendf.h" #include "connect.h" #include "strerror.h" #include "timeval.h" #include "socks.h" #include "curl_sspi.h" #include "curl_multibyte.h" #include "warnless.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Helper sspi error functions. */ static int check_sspi_err(struct connectdata *conn, SECURITY_STATUS status, const char *function) { if(status != SEC_E_OK && status != SEC_I_COMPLETE_AND_CONTINUE && status != SEC_I_COMPLETE_NEEDED && status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; failf(conn->data, "SSPI error: %s failed: %s", function, Curl_sspi_strerror(status, buffer, sizeof(buffer))); return 1; } return 0; } /* This is the SSPI-using version of this function */ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; ssize_t written; int result; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; unsigned char gss_enc; SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; SecBufferDesc input_desc, output_desc, wrap_desc; SecPkgContext_Sizes sspi_sizes; CredHandle cred_handle; CtxtHandle sspi_context; PCtxtHandle context_handle = NULL; SecPkgCredentials_Names names; TimeStamp expiry; char *service_name = NULL; unsigned short us_length; unsigned long qop; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; const size_t service_length = strlen(service); /* GSS-API request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ * | 1 | 1 | 2 | up to 2^16 - 1 | * +----+------+-----+----------------+ */ /* prepare service name */ if(strchr(service, '/')) { service_name = strdup(service); if(!service_name) return CURLE_OUT_OF_MEMORY; } else { service_name = malloc(service_length + strlen(conn->socks_proxy.host.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; msnprintf(service_name, service_length + strlen(conn->socks_proxy.host.name) + 2, "%s/%s", service, conn->socks_proxy.host.name); } input_desc.cBuffers = 1; input_desc.pBuffers = &sspi_recv_token; input_desc.ulVersion = SECBUFFER_VERSION; sspi_recv_token.BufferType = SECBUFFER_TOKEN; sspi_recv_token.cbBuffer = 0; sspi_recv_token.pvBuffer = NULL; output_desc.cBuffers = 1; output_desc.pBuffers = &sspi_send_token; output_desc.ulVersion = SECBUFFER_VERSION; sspi_send_token.BufferType = SECBUFFER_TOKEN; sspi_send_token.cbBuffer = 0; sspi_send_token.pvBuffer = NULL; wrap_desc.cBuffers = 3; wrap_desc.pBuffers = sspi_w_token; wrap_desc.ulVersion = SECBUFFER_VERSION; cred_handle.dwLower = 0; cred_handle.dwUpper = 0; status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT("Kerberos"), SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, &cred_handle, &expiry); if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); return CURLE_COULDNT_CONNECT; } (void)curlx_nonblock(sock, FALSE); /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { TCHAR *sname; sname = Curl_convert_UTF8_to_tchar(service_name); if(!sname) return CURLE_OUT_OF_MEMORY; status = s_pSecFn->InitializeSecurityContext(&cred_handle, context_handle, sname, ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT, 0, SECURITY_NATIVE_DREP, &input_desc, 0, &sspi_context, &output_desc, &sspi_ret_flags, &expiry); Curl_unicodefree(sname); if(sspi_recv_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); sspi_recv_token.pvBuffer = NULL; sspi_recv_token.cbBuffer = 0; } if(check_sspi_err(conn, status, "InitializeSecurityContext")) { free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); if(sspi_recv_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); failf(data, "Failed to initialise security context."); return CURLE_COULDNT_CONNECT; } if(sspi_send_token.cbBuffer != 0) { socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)sspi_send_token.cbBuffer); memcpy(socksreq + 2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { failf(data, "Failed to send SSPI authentication request."); free(service_name); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(sspi_recv_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI authentication token."); free(service_name); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(sspi_recv_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } } if(sspi_send_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); sspi_send_token.pvBuffer = NULL; } sspi_send_token.cbBuffer = 0; if(sspi_recv_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); sspi_recv_token.pvBuffer = NULL; } sspi_recv_token.cbBuffer = 0; if(status != SEC_I_CONTINUE_NEEDED) break; /* analyse response */ /* GSS-API response looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ * | 1 | 1 | 2 | up to 2^16 - 1 | * +----+------+-----+----------------+ */ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 1) { /* status / messgae type */ failf(data, "Invalid SSPI authentication response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); sspi_recv_token.cbBuffer = us_length; sspi_recv_token.pvBuffer = malloc(us_length); if(!sspi_recv_token.pvBuffer) { free(service_name); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, sspi_recv_token.cbBuffer, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); free(service_name); if(sspi_recv_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); s_pSecFn->FreeCredentialsHandle(&cred_handle); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } context_handle = &sspi_context; } free(service_name); /* Everything is good so far, user was authenticated! */ status = s_pSecFn->QueryCredentialsAttributes(&cred_handle, SECPKG_CRED_ATTR_NAMES, &names); s_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(conn, status, "QueryCredentialAttributes")) { s_pSecFn->DeleteSecurityContext(&sspi_context); s_pSecFn->FreeContextBuffer(names.sUserName); failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n", names.sUserName); s_pSecFn->FreeContextBuffer(names.sUserName); /* Do encryption */ socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 2; /* encryption message type */ gss_enc = 0; /* no data protection */ /* do confidentiality protection if supported */ if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY) gss_enc = 2; /* else do integrity protection */ else if(sspi_ret_flags & ISC_REQ_INTEGRITY) gss_enc = 1; infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") ); /* force to no data protection, avoid encryption/decryption for now */ gss_enc = 0; /* * Sending the encryption type in clear seems wrong. It should be * protected with gss_seal()/gss_wrap(). See RFC1961 extract below * The NEC reference implementations on which this is based is * therefore at fault * * +------+------+------+.......................+ * + ver | mtyp | len | token | * +------+------+------+.......................+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | * +------+------+------+.......................+ * * Where: * * - "ver" is the protocol version number, here 1 to represent the * first version of the SOCKS/GSS-API protocol * * - "mtyp" is the message type, here 2 to represent a protection * -level negotiation message * * - "len" is the length of the "token" field in octets * * - "token" is the GSS-API encapsulated protection level * * The token is produced by encapsulating an octet containing the * required protection level using gss_seal()/gss_wrap() with conf_req * set to FALSE. The token is verified using gss_unseal()/ * gss_unwrap(). * */ if(data->set.socks5_gssapi_nec) { us_length = htons((short)1); memcpy(socksreq + 2, &us_length, sizeof(short)); } else { status = s_pSecFn->QueryContextAttributes(&sspi_context, SECPKG_ATTR_SIZES, &sspi_sizes); if(check_sspi_err(conn, status, "QueryContextAttributes")) { s_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); return CURLE_COULDNT_CONNECT; } sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; sspi_w_token[0].BufferType = SECBUFFER_TOKEN; sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); if(!sspi_w_token[0].pvBuffer) { s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } sspi_w_token[1].cbBuffer = 1; sspi_w_token[1].pvBuffer = malloc(1); if(!sspi_w_token[1].pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); sspi_w_token[2].BufferType = SECBUFFER_PADDING; sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); if(!sspi_w_token[2].pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } status = s_pSecFn->EncryptMessage(&sspi_context, KERB_WRAP_NO_ENCRYPT, &wrap_desc, 0); if(check_sspi_err(conn, status, "EncryptMessage")) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); return CURLE_COULDNT_CONNECT; } sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer + sspi_w_token[2].cbBuffer; sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); if(!sspi_send_token.pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); memcpy((PUCHAR) sspi_send_token.pvBuffer + sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer, sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); sspi_w_token[0].pvBuffer = NULL; sspi_w_token[0].cbBuffer = 0; s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); sspi_w_token[1].pvBuffer = NULL; sspi_w_token[1].cbBuffer = 0; s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); sspi_w_token[2].pvBuffer = NULL; sspi_w_token[2].cbBuffer = 0; us_length = htons((short)sspi_send_token.cbBuffer); memcpy(socksreq + 2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { failf(data, "Failed to send SSPI encryption request."); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written); if(code || (1 != written)) { failf(data, "Failed to send SSPI encryption type."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } } else { code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer, sspi_send_token.cbBuffer, &written); if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI encryption type."); if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(sspi_send_token.pvBuffer) s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); } result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 2) { /* status / message type */ failf(data, "Invalid SSPI encryption response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); sspi_w_token[0].cbBuffer = us_length; sspi_w_token[0].pvBuffer = malloc(us_length); if(!sspi_w_token[0].pvBuffer) { s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } if(!data->set.socks5_gssapi_nec) { wrap_desc.cBuffers = 2; sspi_w_token[0].BufferType = SECBUFFER_STREAM; sspi_w_token[1].BufferType = SECBUFFER_DATA; sspi_w_token[1].cbBuffer = 0; sspi_w_token[1].pvBuffer = NULL; status = s_pSecFn->DecryptMessage(&sspi_context, &wrap_desc, 0, &qop); if(check_sspi_err(conn, status, "DecryptMessage")) { if(sspi_w_token[0].pvBuffer) s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); if(sspi_w_token[1].pvBuffer) s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); return CURLE_COULDNT_CONNECT; } if(sspi_w_token[1].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[1].cbBuffer); if(sspi_w_token[0].pvBuffer) s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); if(sspi_w_token[1].pvBuffer) s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); } else { if(sspi_w_token[0].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_COULDNT_CONNECT; } memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); } (void)curlx_nonblock(sock, TRUE); infof(data, "SOCKS5 access with%s protection granted.\n", (socksreq[0] == 0)?"out GSS-API data": ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); /* For later use if encryption is required conn->socks5_gssapi_enctype = socksreq[0]; if(socksreq[0] != 0) conn->socks5_sspi_context = sspi_context; else { s_pSecFn->DeleteSecurityContext(&sspi_context); conn->socks5_sspi_context = sspi_context; } */ return CURLE_OK; } #endif davix-0.8.0/deps/curl/lib/curl_sspi.c0000644000000000000000000001567414121063461016160 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_WINDOWS_SSPI #include #include "curl_sspi.h" #include "curl_multibyte.h" #include "system_win32.h" #include "warnless.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* We use our own typedef here since some headers might lack these */ typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); /* See definition of SECURITY_ENTRYPOINT in sspi.h */ #ifdef UNICODE # ifdef _WIN32_WCE # define SECURITYENTRYPOINT L"InitSecurityInterfaceW" # else # define SECURITYENTRYPOINT "InitSecurityInterfaceW" # endif #else # define SECURITYENTRYPOINT "InitSecurityInterfaceA" #endif /* Handle of security.dll or secur32.dll, depending on Windows version */ HMODULE s_hSecDll = NULL; /* Pointer to SSPI dispatch table */ PSecurityFunctionTable s_pSecFn = NULL; /* * Curl_sspi_global_init() * * This is used to load the Security Service Provider Interface (SSPI) * dynamic link library portably across all Windows versions, without * the need to directly link libcurl, nor the application using it, at * build time. * * Once this function has been executed, Windows SSPI functions can be * called through the Security Service Provider Interface dispatch table. * * Parameters: * * None. * * Returns CURLE_OK on success. */ CURLcode Curl_sspi_global_init(void) { INITSECURITYINTERFACE_FN pInitSecurityInterface; /* If security interface is not yet initialized try to do this */ if(!s_hSecDll) { /* Security Service Provider Interface (SSPI) functions are located in * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP * have both these DLLs (security.dll forwards calls to secur32.dll) */ /* Load SSPI dll into the address space of the calling process */ if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) s_hSecDll = Curl_load_library(TEXT("security.dll")); else s_hSecDll = Curl_load_library(TEXT("secur32.dll")); if(!s_hSecDll) return CURLE_FAILED_INIT; /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ pInitSecurityInterface = CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN, (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT))); if(!pInitSecurityInterface) return CURLE_FAILED_INIT; /* Get pointer to Security Service Provider Interface dispatch table */ s_pSecFn = pInitSecurityInterface(); if(!s_pSecFn) return CURLE_FAILED_INIT; } return CURLE_OK; } /* * Curl_sspi_global_cleanup() * * This deinitializes the Security Service Provider Interface from libcurl. * * Parameters: * * None. */ void Curl_sspi_global_cleanup(void) { if(s_hSecDll) { FreeLibrary(s_hSecDll); s_hSecDll = NULL; s_pSecFn = NULL; } } /* * Curl_create_sspi_identity() * * This is used to populate a SSPI identity structure based on the supplied * username and password. * * Parameters: * * userp [in] - The user name in the format User or Domain\User. * passwdp [in] - The user's password. * identity [in/out] - The identity structure. * * Returns CURLE_OK on success. */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, SEC_WINNT_AUTH_IDENTITY *identity) { xcharp_u useranddomain; xcharp_u user, dup_user; xcharp_u domain, dup_domain; xcharp_u passwd, dup_passwd; size_t domlen = 0; domain.const_tchar_ptr = TEXT(""); /* Initialize the identity */ memset(identity, 0, sizeof(*identity)); useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp); if(!useranddomain.tchar_ptr) return CURLE_OUT_OF_MEMORY; user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\')); if(!user.const_tchar_ptr) user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/')); if(user.tchar_ptr) { domain.tchar_ptr = useranddomain.tchar_ptr; domlen = user.tchar_ptr - useranddomain.tchar_ptr; user.tchar_ptr++; } else { user.tchar_ptr = useranddomain.tchar_ptr; domain.const_tchar_ptr = TEXT(""); domlen = 0; } /* Setup the identity's user and length */ dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); if(!dup_user.tchar_ptr) { Curl_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } identity->User = dup_user.tbyte_ptr; identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr)); dup_user.tchar_ptr = NULL; /* Setup the identity's domain and length */ dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1)); if(!dup_domain.tchar_ptr) { Curl_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen); *(dup_domain.tchar_ptr + domlen) = TEXT('\0'); identity->Domain = dup_domain.tbyte_ptr; identity->DomainLength = curlx_uztoul(domlen); dup_domain.tchar_ptr = NULL; Curl_unicodefree(useranddomain.tchar_ptr); /* Setup the identity's password and length */ passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp); if(!passwd.tchar_ptr) return CURLE_OUT_OF_MEMORY; dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); if(!dup_passwd.tchar_ptr) { Curl_unicodefree(passwd.tchar_ptr); return CURLE_OUT_OF_MEMORY; } identity->Password = dup_passwd.tbyte_ptr; identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); dup_passwd.tchar_ptr = NULL; Curl_unicodefree(passwd.tchar_ptr); /* Setup the identity's flags */ identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; return CURLE_OK; } /* * Curl_sspi_free_identity() * * This is used to free the contents of a SSPI identifier structure. * * Parameters: * * identity [in/out] - The identity structure. */ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) { if(identity) { Curl_safefree(identity->User); Curl_safefree(identity->Password); Curl_safefree(identity->Domain); } } #endif /* USE_WINDOWS_SSPI */ davix-0.8.0/deps/curl/lib/warnless.h0000644000000000000000000000574314121063461016014 0ustar rootroot#ifndef HEADER_CURL_WARNLESS_H #define HEADER_CURL_WARNLESS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifdef USE_WINSOCK #include /* for curl_socket_t */ #endif #define CURLX_FUNCTION_CAST(target_type, func) \ (target_type)(void (*) (void))(func) unsigned short curlx_ultous(unsigned long ulnum); unsigned char curlx_ultouc(unsigned long ulnum); int curlx_ultosi(unsigned long ulnum); int curlx_uztosi(size_t uznum); curl_off_t curlx_uztoso(size_t uznum); unsigned long curlx_uztoul(size_t uznum); unsigned int curlx_uztoui(size_t uznum); int curlx_sltosi(long slnum); unsigned int curlx_sltoui(long slnum); unsigned short curlx_sltous(long slnum); ssize_t curlx_uztosz(size_t uznum); size_t curlx_sotouz(curl_off_t sonum); int curlx_sztosi(ssize_t sznum); unsigned short curlx_uitous(unsigned int uinum); size_t curlx_sitouz(int sinum); #ifdef USE_WINSOCK int curlx_sktosi(curl_socket_t s); curl_socket_t curlx_sitosk(int i); #endif /* USE_WINSOCK */ #if defined(WIN32) || defined(_WIN32) ssize_t curlx_read(int fd, void *buf, size_t count); ssize_t curlx_write(int fd, const void *buf, size_t count); #ifndef BUILDING_WARNLESS_C # undef read # define read(fd, buf, count) curlx_read(fd, buf, count) # undef write # define write(fd, buf, count) curlx_write(fd, buf, count) #endif #endif /* WIN32 || _WIN32 */ #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset); void curlx_FD_SET(int fd, fd_set *fdset); void curlx_FD_ZERO(fd_set *fdset); unsigned short curlx_htons(unsigned short usnum); unsigned short curlx_ntohs(unsigned short usnum); #ifndef BUILDING_WARNLESS_C # undef FD_ISSET # define FD_ISSET(a,b) curlx_FD_ISSET((a),(b)) # undef FD_SET # define FD_SET(a,b) curlx_FD_SET((a),(b)) # undef FD_ZERO # define FD_ZERO(a) curlx_FD_ZERO((a)) # undef htons # define htons(a) curlx_htons((a)) # undef ntohs # define ntohs(a) curlx_ntohs((a)) #endif #endif /* __INTEL_COMPILER && __unix__ */ #endif /* HEADER_CURL_WARNLESS_H */ davix-0.8.0/deps/curl/lib/curl_ntlm_wb.c0000644000000000000000000003402414121063461016632 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) /* * NTLM details: * * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_PWD_H #include #endif #include "urldata.h" #include "sendf.h" #include "select.h" #include "vauth/ntlm.h" #include "curl_ntlm_core.h" #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" #include "strdup.h" #include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if DEBUG_ME # define DEBUG_OUT(x) x #else # define DEBUG_OUT(x) Curl_nop_stmt #endif /* Portable 'sclose_nolog' used only in child process instead of 'sclose' to avoid fooling the socket leak detector */ #if defined(HAVE_CLOSESOCKET) # define sclose_nolog(x) closesocket((x)) #elif defined(HAVE_CLOSESOCKET_CAMEL) # define sclose_nolog(x) CloseSocket((x)) #else # define sclose_nolog(x) close((x)) #endif static void ntlm_wb_cleanup(struct ntlmdata *ntlm) { if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { sclose(ntlm->ntlm_auth_hlpr_socket); ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; } if(ntlm->ntlm_auth_hlpr_pid) { int i; for(i = 0; i < 4; i++) { pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG); if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD) break; switch(i) { case 0: kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM); break; case 1: /* Give the process another moment to shut down cleanly before bringing down the axe */ Curl_wait_ms(1); break; case 2: kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL); break; case 3: break; } } ntlm->ntlm_auth_hlpr_pid = 0; } Curl_safefree(ntlm->challenge); Curl_safefree(ntlm->response); } static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm, const char *userp) { curl_socket_t sockfds[2]; pid_t child_pid; const char *username; char *slash, *domain = NULL; const char *ntlm_auth = NULL; char *ntlm_auth_alloc = NULL; #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) struct passwd pw, *pw_res; char pwbuf[1024]; #endif char buffer[STRERROR_LEN]; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif /* Return if communication with ntlm_auth already set up */ if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || ntlm->ntlm_auth_hlpr_pid) return CURLE_OK; username = userp; /* The real ntlm_auth really doesn't like being invoked with an empty username. It won't make inferences for itself, and expects the client to do so (mostly because it's really designed for servers like squid to use for auth, and client support is an afterthought for it). So try hard to provide a suitable username if we don't already have one. But if we can't, provide the empty one anyway. Perhaps they have an implementation of the ntlm_auth helper which *doesn't* need it so we might as well try */ if(!username || !username[0]) { username = getenv("NTLMUSER"); if(!username || !username[0]) username = getenv("LOGNAME"); if(!username || !username[0]) username = getenv("USER"); #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) if((!username || !username[0]) && !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && pw_res) { username = pw.pw_name; } #endif if(!username || !username[0]) username = userp; } slash = strpbrk(username, "\\/"); if(slash) { domain = strdup(username); if(!domain) return CURLE_OUT_OF_MEMORY; slash = domain + (slash - username); *slash = '\0'; username = username + (slash - domain) + 1; } /* For testing purposes, when DEBUGBUILD is defined and environment variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform NTLM challenge/response which only accepts commands and output strings pre-written in test case definitions */ #ifdef DEBUGBUILD ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); if(ntlm_auth_alloc) ntlm_auth = ntlm_auth_alloc; else #endif ntlm_auth = NTLM_WB_FILE; if(access(ntlm_auth, X_OK) != 0) { failf(data, "Could not access ntlm_auth: %s errno %d: %s", ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { failf(data, "Could not open socket pair. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } child_pid = fork(); if(child_pid == -1) { sclose(sockfds[0]); sclose(sockfds[1]); failf(data, "Could not fork. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); goto done; } else if(!child_pid) { /* * child process */ /* Don't use sclose in the child since it fools the socket leak detector */ sclose_nolog(sockfds[0]); if(dup2(sockfds[1], STDIN_FILENO) == -1) { failf(data, "Could not redirect child stdin. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } if(dup2(sockfds[1], STDOUT_FILENO) == -1) { failf(data, "Could not redirect child stdout. errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } if(domain) execl(ntlm_auth, ntlm_auth, "--helper-protocol", "ntlmssp-client-1", "--use-cached-creds", "--username", username, "--domain", domain, NULL); else execl(ntlm_auth, ntlm_auth, "--helper-protocol", "ntlmssp-client-1", "--use-cached-creds", "--username", username, NULL); sclose_nolog(sockfds[1]); failf(data, "Could not execl(). errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); exit(1); } sclose(sockfds[1]); ntlm->ntlm_auth_hlpr_socket = sockfds[0]; ntlm->ntlm_auth_hlpr_pid = child_pid; free(domain); free(ntlm_auth_alloc); return CURLE_OK; done: free(domain); free(ntlm_auth_alloc); return CURLE_REMOTE_ACCESS_DENIED; } /* if larger than this, something is seriously wrong */ #define MAX_NTLM_WB_RESPONSE 100000 static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, const char *input, curlntlm state) { char *buf = malloc(NTLM_BUFSIZE); size_t len_in = strlen(input), len_out = 0; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; #endif if(!buf) return CURLE_OUT_OF_MEMORY; while(len_in > 0) { ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in); if(written == -1) { /* Interrupted by a signal, retry it */ if(errno == EINTR) continue; /* write failed if other errors happen */ goto done; } input += written; len_in -= written; } /* Read one line */ while(1) { ssize_t size; char *newbuf; size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); if(size == -1) { if(errno == EINTR) continue; goto done; } else if(size == 0) goto done; len_out += size; if(buf[len_out - 1] == '\n') { buf[len_out - 1] = '\0'; break; } if(len_out > MAX_NTLM_WB_RESPONSE) { failf(data, "too large ntlm_wb response!"); free(buf); return CURLE_OUT_OF_MEMORY; } newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE); if(!newbuf) return CURLE_OUT_OF_MEMORY; buf = newbuf; } /* Samba/winbind installed but not configured */ if(state == NTLMSTATE_TYPE1 && len_out == 3 && buf[0] == 'P' && buf[1] == 'W') goto done; /* invalid response */ if(len_out < 4) goto done; if(state == NTLMSTATE_TYPE1 && (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) goto done; if(state == NTLMSTATE_TYPE2 && (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) goto done; ntlm->response = aprintf("%.*s", len_out - 4, buf + 3); free(buf); if(!ntlm->response) return CURLE_OUT_OF_MEMORY; return CURLE_OK; done: free(buf); return CURLE_REMOTE_ACCESS_DENIED; } CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy, const char *header) { struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; if(!checkprefix("NTLM", header)) return CURLE_BAD_CONTENT_ENCODING; header += strlen("NTLM"); while(*header && ISSPACE(*header)) header++; if(*header) { ntlm->challenge = strdup(header); if(!ntlm->challenge) return CURLE_OUT_OF_MEMORY; *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ } else { if(*state == NTLMSTATE_LAST) { infof(conn->data, "NTLM auth restarted\n"); Curl_http_auth_cleanup_ntlm_wb(conn); } else if(*state == NTLMSTATE_TYPE3) { infof(conn->data, "NTLM handshake rejected\n"); Curl_http_auth_cleanup_ntlm_wb(conn); *state = NTLMSTATE_NONE; return CURLE_REMOTE_ACCESS_DENIED; } else if(*state >= NTLMSTATE_TYPE1) { infof(conn->data, "NTLM handshake failure (internal error)\n"); return CURLE_REMOTE_ACCESS_DENIED; } *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ } return CURLE_OK; } /* * This is for creating ntlm header output by delegating challenge/response * to Samba's winbind daemon helper ntlm_auth. */ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy) { /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; /* point to the name and password for this */ const char *userp; struct ntlmdata *ntlm; curlntlm *state; struct auth *authp; CURLcode res = CURLE_OK; DEBUGASSERT(conn); DEBUGASSERT(conn->data); if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; ntlm = &conn->ntlm; state = &conn->http_ntlm_state; authp = &conn->data->state.authhost; } authp->done = FALSE; /* not set means empty */ if(!userp) userp = ""; switch(*state) { case NTLMSTATE_TYPE1: default: /* Use Samba's 'winbind' daemon to support NTLM authentication, * by delegating the NTLM challenge/response protocol to a helper * in ntlm_auth. * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute * filename of ntlm_auth helper. * If NTLM authentication using winbind fails, go back to original * request handling process. */ /* Create communication with ntlm_auth */ res = ntlm_wb_init(conn->data, ntlm, userp); if(res) return res; res = ntlm_wb_response(conn->data, ntlm, "YR\n", *state); if(res) return res; free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", ntlm->response); DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); Curl_safefree(ntlm->response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; break; case NTLMSTATE_TYPE2: { char *input = aprintf("TT %s\n", ntlm->challenge); if(!input) return CURLE_OUT_OF_MEMORY; res = ntlm_wb_response(conn->data, ntlm, input, *state); free(input); if(res) return res; free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", ntlm->response); DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); *state = NTLMSTATE_TYPE3; /* we sent a type-3 */ authp->done = TRUE; Curl_http_auth_cleanup_ntlm_wb(conn); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; break; } case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ *state = NTLMSTATE_LAST; /* FALLTHROUGH */ case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; break; } return CURLE_OK; } void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn) { ntlm_wb_cleanup(&conn->ntlm); ntlm_wb_cleanup(&conn->proxyntlm); } #endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */ davix-0.8.0/deps/curl/lib/warnless.c0000644000000000000000000002731514121063461016006 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(__INTEL_COMPILER) && defined(__unix__) #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #endif /* __INTEL_COMPILER && __unix__ */ #define BUILDING_WARNLESS_C 1 #include "warnless.h" #define CURL_MASK_SCHAR 0x7F #define CURL_MASK_UCHAR 0xFF #if (SIZEOF_SHORT == 2) # define CURL_MASK_SSHORT 0x7FFF # define CURL_MASK_USHORT 0xFFFF #elif (SIZEOF_SHORT == 4) # define CURL_MASK_SSHORT 0x7FFFFFFF # define CURL_MASK_USHORT 0xFFFFFFFF #elif (SIZEOF_SHORT == 8) # define CURL_MASK_SSHORT 0x7FFFFFFFFFFFFFFF # define CURL_MASK_USHORT 0xFFFFFFFFFFFFFFFF #else # error "SIZEOF_SHORT not defined" #endif #if (SIZEOF_INT == 2) # define CURL_MASK_SINT 0x7FFF # define CURL_MASK_UINT 0xFFFF #elif (SIZEOF_INT == 4) # define CURL_MASK_SINT 0x7FFFFFFF # define CURL_MASK_UINT 0xFFFFFFFF #elif (SIZEOF_INT == 8) # define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFF # define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFF #elif (SIZEOF_INT == 16) # define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF # define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF #else # error "SIZEOF_INT not defined" #endif #if (SIZEOF_LONG == 2) # define CURL_MASK_SLONG 0x7FFFL # define CURL_MASK_ULONG 0xFFFFUL #elif (SIZEOF_LONG == 4) # define CURL_MASK_SLONG 0x7FFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFUL #elif (SIZEOF_LONG == 8) # define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL #elif (SIZEOF_LONG == 16) # define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL # define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL #else # error "SIZEOF_LONG not defined" #endif #if (SIZEOF_CURL_OFF_T == 2) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF) #elif (SIZEOF_CURL_OFF_T == 4) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF) #elif (SIZEOF_CURL_OFF_T == 8) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF) #elif (SIZEOF_CURL_OFF_T == 16) # define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) # define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) #else # error "SIZEOF_CURL_OFF_T not defined" #endif #if (SIZEOF_SIZE_T == SIZEOF_SHORT) # define CURL_MASK_SSIZE_T CURL_MASK_SSHORT # define CURL_MASK_USIZE_T CURL_MASK_USHORT #elif (SIZEOF_SIZE_T == SIZEOF_INT) # define CURL_MASK_SSIZE_T CURL_MASK_SINT # define CURL_MASK_USIZE_T CURL_MASK_UINT #elif (SIZEOF_SIZE_T == SIZEOF_LONG) # define CURL_MASK_SSIZE_T CURL_MASK_SLONG # define CURL_MASK_USIZE_T CURL_MASK_ULONG #elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T) # define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT # define CURL_MASK_USIZE_T CURL_MASK_UCOFFT #else # error "SIZEOF_SIZE_T not defined" #endif /* ** unsigned long to unsigned short */ unsigned short curlx_ultous(unsigned long ulnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned long to unsigned char */ unsigned char curlx_ultouc(unsigned long ulnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR); return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned long to signed int */ int curlx_ultosi(unsigned long ulnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT); return (int)(ulnum & (unsigned long) CURL_MASK_SINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned size_t to signed curl_off_t */ curl_off_t curlx_uztoso(size_t uznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #elif defined(_MSC_VER) # pragma warning(push) # pragma warning(disable:4310) /* cast truncates constant value */ #endif DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT); return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT); #if defined(__INTEL_COMPILER) || defined(_MSC_VER) # pragma warning(pop) #endif } /* ** unsigned size_t to signed int */ int curlx_uztosi(size_t uznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT); return (int)(uznum & (size_t) CURL_MASK_SINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned size_t to unsigned long */ unsigned long curlx_uztoul(size_t uznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif #if (SIZEOF_LONG < SIZEOF_SIZE_T) DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); #endif return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned size_t to unsigned int */ unsigned int curlx_uztoui(size_t uznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif #if (SIZEOF_INT < SIZEOF_SIZE_T) DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT); #endif return (unsigned int)(uznum & (size_t) CURL_MASK_UINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed long to signed int */ int curlx_sltosi(long slnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(slnum >= 0); #if (SIZEOF_INT < SIZEOF_LONG) DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT); #endif return (int)(slnum & (long) CURL_MASK_SINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed long to unsigned int */ unsigned int curlx_sltoui(long slnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(slnum >= 0); #if (SIZEOF_INT < SIZEOF_LONG) DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT); #endif return (unsigned int)(slnum & (long) CURL_MASK_UINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed long to unsigned short */ unsigned short curlx_sltous(long slnum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(slnum >= 0); DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT); return (unsigned short)(slnum & (long) CURL_MASK_USHORT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned size_t to signed ssize_t */ ssize_t curlx_uztosz(size_t uznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T); return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed curl_off_t to unsigned size_t */ size_t curlx_sotouz(curl_off_t sonum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(sonum >= 0); return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed ssize_t to signed int */ int curlx_sztosi(ssize_t sznum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(sznum >= 0); #if (SIZEOF_INT < SIZEOF_SIZE_T) DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT); #endif return (int)(sznum & (ssize_t) CURL_MASK_SINT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** unsigned int to unsigned short */ unsigned short curlx_uitous(unsigned int uinum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT); return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } /* ** signed int to unsigned size_t */ size_t curlx_sitouz(int sinum) { #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif DEBUGASSERT(sinum >= 0); return (size_t) sinum; #ifdef __INTEL_COMPILER # pragma warning(pop) #endif } #ifdef USE_WINSOCK /* ** curl_socket_t to signed int */ int curlx_sktosi(curl_socket_t s) { return (int)((ssize_t) s); } /* ** signed int to curl_socket_t */ curl_socket_t curlx_sitosk(int i) { return (curl_socket_t)((ssize_t) i); } #endif /* USE_WINSOCK */ #if defined(WIN32) || defined(_WIN32) ssize_t curlx_read(int fd, void *buf, size_t count) { return (ssize_t)read(fd, buf, curlx_uztoui(count)); } ssize_t curlx_write(int fd, const void *buf, size_t count) { return (ssize_t)write(fd, buf, curlx_uztoui(count)); } #endif /* WIN32 || _WIN32 */ #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset) { #pragma warning(push) #pragma warning(disable:1469) /* clobber ignored */ return FD_ISSET(fd, fdset); #pragma warning(pop) } void curlx_FD_SET(int fd, fd_set *fdset) { #pragma warning(push) #pragma warning(disable:1469) /* clobber ignored */ FD_SET(fd, fdset); #pragma warning(pop) } void curlx_FD_ZERO(fd_set *fdset) { #pragma warning(push) #pragma warning(disable:593) /* variable was set but never used */ FD_ZERO(fdset); #pragma warning(pop) } unsigned short curlx_htons(unsigned short usnum) { #if (__INTEL_COMPILER == 910) && defined(__i386__) return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); #else #pragma warning(push) #pragma warning(disable:810) /* conversion may lose significant bits */ return htons(usnum); #pragma warning(pop) #endif } unsigned short curlx_ntohs(unsigned short usnum) { #if (__INTEL_COMPILER == 910) && defined(__i386__) return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); #else #pragma warning(push) #pragma warning(disable:810) /* conversion may lose significant bits */ return ntohs(usnum); #pragma warning(pop) #endif } #endif /* __INTEL_COMPILER && __unix__ */ davix-0.8.0/deps/curl/lib/asyn-ares.c0000644000000000000000000006220514121063461016047 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /*********************************************************************** * Only for ares-enabled builds * And only for functions that fulfill the asynch resolver backend API * as defined in asyn.h, nothing else belongs in this file! **********************************************************************/ #ifdef CURLRES_ARES #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_PROCESS_H #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" #include "multiif.h" #include "inet_pton.h" #include "connect.h" #include "select.h" #include "progress.h" # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(__SYMBIAN32__)) # define CARES_STATICLIB # endif # include # include /* really old c-ares didn't include this by itself */ #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" struct ResolverResults { int num_pending; /* number of ares_gethostbyname() requests */ Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ int last_status; struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ }; /* How long we are willing to wait for additional parallel responses after obtaining a "definitive" one. This is intended to equal the c-ares default timeout. cURL always uses that default value. Unfortunately, c-ares doesn't expose its default timeout in its API, but it is officially documented as 5 seconds. See query_completed_cb() for an explanation of how this is used. */ #define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 /* * Curl_resolver_global_init() - the generic low-level asynchronous name * resolve API. Called from curl_global_init() to initialize global resolver * environment. Initializes ares library. */ int Curl_resolver_global_init(void) { #ifdef CARES_HAVE_ARES_LIBRARY_INIT if(ares_library_init(ARES_LIB_INIT_ALL)) { return CURLE_FAILED_INIT; } #endif return CURLE_OK; } /* * Curl_resolver_global_cleanup() * * Called from curl_global_cleanup() to destroy global resolver environment. * Deinitializes ares library. */ void Curl_resolver_global_cleanup(void) { #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP ares_library_cleanup(); #endif } static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd, int readable, int writable) { struct Curl_easy *easy = data; if(!readable && !writable) { DEBUGASSERT(easy); Curl_multi_closed(easy, socket_fd); } } /* * Curl_resolver_init() * * Called from curl_easy_init() -> Curl_open() to initialize resolver * URL-state specific environment ('resolver' member of the UrlState * structure). Fills the passed pointer by the initialized ares_channel. */ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) { int status; struct ares_options options; int optmask = ARES_OPT_SOCK_STATE_CB; options.sock_state_cb = Curl_ares_sock_state_cb; options.sock_state_cb_data = easy; status = ares_init_options((ares_channel*)resolver, &options, optmask); if(status != ARES_SUCCESS) { if(status == ARES_ENOMEM) return CURLE_OUT_OF_MEMORY; else return CURLE_FAILED_INIT; } return CURLE_OK; /* make sure that all other returns from this function should destroy the ares channel before returning error! */ } /* * Curl_resolver_cleanup() * * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver * URL-state specific environment ('resolver' member of the UrlState * structure). Destroys the ares channel. */ void Curl_resolver_cleanup(void *resolver) { ares_destroy((ares_channel)resolver); } /* * Curl_resolver_duphandle() * * Called from curl_easy_duphandle() to duplicate resolver URL-state specific * environment ('resolver' member of the UrlState structure). Duplicates the * 'from' ares channel and passes the resulting channel to the 'to' pointer. */ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) { (void)from; /* * it would be better to call ares_dup instead, but right now * it is not possible to set 'sock_state_cb_data' outside of * ares_init_options */ return Curl_resolver_init(easy, to); } static void destroy_async_data(struct Curl_async *async); /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_resolver_cancel(struct connectdata *conn) { if(conn->data && conn->data->state.resolver) ares_cancel((ares_channel)conn->data->state.resolver); destroy_async_data(&conn->async); } /* * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We * never block. */ void Curl_resolver_kill(struct connectdata *conn) { /* We don't need to check the resolver state because we can be called safely at any time and we always do the same thing. */ Curl_resolver_cancel(conn); } /* * destroy_async_data() cleans up async resolver data. */ static void destroy_async_data(struct Curl_async *async) { free(async->hostname); if(async->os_specific) { struct ResolverResults *res = (struct ResolverResults *)async->os_specific; if(res) { if(res->temp_ai) { Curl_freeaddrinfo(res->temp_ai); res->temp_ai = NULL; } free(res); } async->os_specific = NULL; } async->hostname = NULL; } /* * Curl_resolver_getsock() is called when someone from the outside world * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking * with ares. The caller must make sure that this function is only called when * we have a working ares channel. * * Returns: sockets-in-use-bitmap */ int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *socks) { struct timeval maxtime; struct timeval timebuf; struct timeval *timeout; long milli; int max = ares_getsock((ares_channel)conn->data->state.resolver, (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; maxtime.tv_usec = 0; timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime, &timebuf); milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000); if(milli == 0) milli += 10; Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME); return max; } /* * waitperform() * * 1) Ask ares what sockets it currently plays with, then * 2) wait for the timeout period to check for action on ares' sockets. * 3) tell ares to act on all the sockets marked as "with action" * * return number of sockets it worked on */ static int waitperform(struct connectdata *conn, int timeout_ms) { struct Curl_easy *data = conn->data; int nfds; int bitmask; ares_socket_t socks[ARES_GETSOCK_MAXNUM]; struct pollfd pfd[ARES_GETSOCK_MAXNUM]; int i; int num = 0; bitmask = ares_getsock((ares_channel)data->state.resolver, socks, ARES_GETSOCK_MAXNUM); for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; pfd[i].revents = 0; if(ARES_GETSOCK_READABLE(bitmask, i)) { pfd[i].fd = socks[i]; pfd[i].events |= POLLRDNORM|POLLIN; } if(ARES_GETSOCK_WRITABLE(bitmask, i)) { pfd[i].fd = socks[i]; pfd[i].events |= POLLWRNORM|POLLOUT; } if(pfd[i].events != 0) num++; else break; } if(num) nfds = Curl_poll(pfd, num, timeout_ms); else nfds = 0; if(!nfds) /* Call ares_process() unconditonally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD, ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ for(i = 0; i < num; i++) ares_process_fd((ares_channel)data->state.resolver, (pfd[i].revents & (POLLRDNORM|POLLIN))? pfd[i].fd:ARES_SOCKET_BAD, (pfd[i].revents & (POLLWRNORM|POLLOUT))? pfd[i].fd:ARES_SOCKET_BAD); } return nfds; } /* * Curl_resolver_is_resolved() is called repeatedly to check if a previous * name resolve request has completed. It should also make sure to time-out if * the operation seems to take too long. * * Returns normal CURLcode errors. */ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { struct Curl_easy *data = conn->data; struct ResolverResults *res = (struct ResolverResults *) conn->async.os_specific; CURLcode result = CURLE_OK; if(dns) *dns = NULL; waitperform(conn, 0); /* Now that we've checked for any last minute results above, see if there are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer expires. */ if(res && res->num_pending /* This is only set to non-zero if the timer was started. */ && (res->happy_eyeballs_dns_time.tv_sec || res->happy_eyeballs_dns_time.tv_usec) && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time) >= HAPPY_EYEBALLS_DNS_TIMEOUT)) { /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer running. */ memset( &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time)); /* Cancel the raw c-ares request, which will fire query_completed_cb() with ARES_ECANCELLED synchronously for all pending responses. This will leave us with res->num_pending == 0, which is perfect for the next block. */ ares_cancel((ares_channel)data->state.resolver); DEBUGASSERT(res->num_pending == 0); } if(res && !res->num_pending) { if(dns) { (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); /* temp_ai ownership is moved to the connection, so we need not free-up them */ res->temp_ai = NULL; } if(!conn->async.dns) { failf(data, "Could not resolve: %s (%s)", conn->async.hostname, ares_strerror(conn->async.status)); result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: CURLE_COULDNT_RESOLVE_HOST; } else if(dns) *dns = conn->async.dns; destroy_async_data(&conn->async); } return result; } /* * Curl_resolver_wait_resolv() * * Waits for a resolve to finish. This function should be avoided since using * this risk getting the multi interface to "hang". * * If 'entry' is non-NULL, make it point to the resolved dns entry * * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. */ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; timediff_t timeout; struct curltime now = Curl_now(); struct Curl_dns_entry *temp_entry; if(entry) *entry = NULL; /* clear on entry */ timeout = Curl_timeleft(data, &now, TRUE); if(timeout < 0) { /* already expired! */ connclose(conn, "Timed out before name resolve started"); return CURLE_OPERATION_TIMEDOUT; } if(!timeout) timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ /* Wait for the name resolve query to complete. */ while(!result) { struct timeval *tvp, tv, store; int itimeout; int timeout_ms; itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; store.tv_sec = itimeout/1000; store.tv_usec = (itimeout%1000)*1000; tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv); /* use the timeout period ares returned to us above if less than one second is left, otherwise just use 1000ms to make sure the progress callback gets called frequent enough */ if(!tvp->tv_sec) timeout_ms = (int)(tvp->tv_usec/1000); else timeout_ms = 1000; waitperform(conn, timeout_ms); result = Curl_resolver_is_resolved(conn, entry?&temp_entry:NULL); if(result || conn->async.done) break; if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else { struct curltime now2 = Curl_now(); timediff_t timediff = Curl_timediff(now2, now); /* spent time */ if(timediff <= 0) timeout -= 1; /* always deduct at least 1 */ else if(timediff > timeout) timeout = -1; else timeout -= (long)timediff; now = now2; /* for next loop */ } if(timeout < 0) result = CURLE_OPERATION_TIMEDOUT; } if(result) /* failure, so we cancel the ares operation */ ares_cancel((ares_channel)data->state.resolver); /* Operation complete, if the lookup was successful we now have the entry in the cache. */ if(entry) *entry = conn->async.dns; if(result) /* close the connection, since we can't return failure here without cleaning up this connection properly. */ connclose(conn, "c-ares resolve failed"); return result; } /* Connects results to the list */ static void compound_results(struct ResolverResults *res, Curl_addrinfo *ai) { Curl_addrinfo *ai_tail; if(!ai) return; ai_tail = ai; while(ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ ai_tail->ai_next = res->temp_ai; res->temp_ai = ai; } /* * ares_query_completed_cb() is the callback that ares will call when * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), * when using ares, is completed either successfully or with failure. */ static void query_completed_cb(void *arg, /* (struct connectdata *) */ int status, #ifdef HAVE_CARES_CALLBACK_TIMEOUTS int timeouts, #endif struct hostent *hostent) { struct connectdata *conn = (struct connectdata *)arg; struct ResolverResults *res; #ifdef HAVE_CARES_CALLBACK_TIMEOUTS (void)timeouts; /* ignored */ #endif if(ARES_EDESTRUCTION == status) /* when this ares handle is getting destroyed, the 'arg' pointer may not be valid so only defer it when we know the 'status' says its fine! */ return; res = (struct ResolverResults *)conn->async.os_specific; if(res) { res->num_pending--; if(CURL_ASYNC_SUCCESS == status) { Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); if(ai) { compound_results(res, ai); } } /* A successful result overwrites any previous error */ if(res->last_status != ARES_SUCCESS) res->last_status = status; /* If there are responses still pending, we presume they must be the complementary IPv4 or IPv6 lookups that we started in parallel in Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a "definitive" response from one of a set of parallel queries, we need to think about how long we're willing to wait for more responses. */ if(res->num_pending /* Only these c-ares status values count as "definitive" for these purposes. For example, ARES_ENODATA is what we expect when there is no IPv6 entry for a domain name, and that's not a reason to get more aggressive in our timeouts for the other response. Other errors are either a result of bad input (which should affect all parallel requests), local or network conditions, non-definitive server responses, or us cancelling the request. */ && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) { /* Right now, there can only be up to two parallel queries, so don't bother handling any other cases. */ DEBUGASSERT(res->num_pending == 1); /* It's possible that one of these parallel queries could succeed quickly, but the other could always fail or timeout (when we're talking to a pool of DNS servers that can only successfully resolve IPv4 address, for example). It's also possible that the other request could always just take longer because it needs more time or only the second DNS server can fulfill it successfully. But, to align with the philosophy of Happy Eyeballs, we don't want to wait _too_ long or users will think requests are slow when IPv6 lookups don't actually work (but IPv4 ones do). So, now that we have a usable answer (some IPv4 addresses, some IPv6 addresses, or "no such domain"), we start a timeout for the remaining pending responses. Even though it is typical that this resolved request came back quickly, that needn't be the case. It might be that this completing request didn't get a result from the first DNS server or even the first round of the whole DNS server pool. So it could already be quite some time after we issued the DNS queries in the first place. Without modifying c-ares, we can't know exactly where in its retry cycle we are. We could guess based on how much time has gone by, but it doesn't really matter. Happy Eyeballs tells us that, given usable information in hand, we simply don't want to wait "too much longer" after we get a result. We simply wait an additional amount of time equal to the default c-ares query timeout. That is enough time for a typical parallel response to arrive without being "too long". Even on a network where one of the two types of queries is failing or timing out constantly, this will usually mean we wait a total of the default c-ares timeout (5 seconds) plus the round trip time for the successful request, which seems bearable. The downside is that c-ares might race with us to issue one more retry just before we give up, but it seems better to "waste" that request instead of trying to guess the perfect timeout to prevent it. After all, we don't even know where in the c-ares retry cycle each request is. */ res->happy_eyeballs_dns_time = Curl_now(); Curl_expire( conn->data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS); } } } /* * Curl_resolver_getaddrinfo() - when using ares * * Returns name information about the given hostname and port number. If * successful, the 'hostent' is returned and the forth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { char *bufp; struct Curl_easy *data = conn->data; int family = PF_INET; *waitp = 0; /* default to synchronous response */ #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ switch(conn->ip_version) { default: #if ARES_VERSION >= 0x010601 family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older c-ares versions this just falls through and defaults to PF_INET */ break; #endif case CURL_IPRESOLVE_V4: family = PF_INET; break; case CURL_IPRESOLVE_V6: family = PF_INET6; break; } #endif /* CURLRES_IPV6 */ bufp = strdup(hostname); if(bufp) { struct ResolverResults *res = NULL; free(conn->async.hostname); conn->async.hostname = bufp; conn->async.port = port; conn->async.done = FALSE; /* not done */ conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ res = calloc(sizeof(struct ResolverResults), 1); if(!res) { free(conn->async.hostname); conn->async.hostname = NULL; return NULL; } conn->async.os_specific = res; /* initial status - failed */ res->last_status = ARES_ENOTFOUND; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ if(family == PF_UNSPEC) { if(Curl_ipv6works(conn)) { res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, query_completed_cb, conn); ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6, query_completed_cb, conn); } else { res->num_pending = 1; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, query_completed_cb, conn); } } else #endif /* CURLRES_IPV6 */ { res->num_pending = 1; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, query_completed_cb, conn); } *waitp = 1; /* expect asynchronous response */ } return NULL; /* no struct yet */ } CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { CURLcode result = CURLE_NOT_BUILT_IN; int ares_result; /* If server is NULL or empty, this would purge all DNS servers * from ares library, which will cause any and all queries to fail. * So, just return OK if none are configured and don't actually make * any changes to c-ares. This lets c-ares use it's defaults, which * it gets from the OS (for instance from /etc/resolv.conf on Linux). */ if(!(servers && servers[0])) return CURLE_OK; #if (ARES_VERSION >= 0x010704) #if (ARES_VERSION >= 0x010b00) ares_result = ares_set_servers_ports_csv(data->state.resolver, servers); #else ares_result = ares_set_servers_csv(data->state.resolver, servers); #endif switch(ares_result) { case ARES_SUCCESS: result = CURLE_OK; break; case ARES_ENOMEM: result = CURLE_OUT_OF_MEMORY; break; case ARES_ENOTINITIALIZED: case ARES_ENODATA: case ARES_EBADSTR: default: result = CURLE_BAD_FUNCTION_ARGUMENT; break; } #else /* too old c-ares version! */ (void)data; (void)(ares_result); #endif return result; } CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { #if (ARES_VERSION >= 0x010704) if(!interf) interf = ""; ares_set_local_dev((ares_channel)data->state.resolver, interf); return CURLE_OK; #else /* c-ares version too old! */ (void)data; (void)interf; return CURLE_NOT_BUILT_IN; #endif } CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { #if (ARES_VERSION >= 0x010704) struct in_addr a4; if((!local_ip4) || (local_ip4[0] == 0)) { a4.s_addr = 0; /* disabled: do not bind to a specific address */ } else { if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { return CURLE_BAD_FUNCTION_ARGUMENT; } } ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr)); return CURLE_OK; #else /* c-ares version too old! */ (void)data; (void)local_ip4; return CURLE_NOT_BUILT_IN; #endif } CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) unsigned char a6[INET6_ADDRSTRLEN]; if((!local_ip6) || (local_ip6[0] == 0)) { /* disabled: do not bind to a specific address */ memset(a6, 0, sizeof(a6)); } else { if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { return CURLE_BAD_FUNCTION_ARGUMENT; } } ares_set_local_ip6((ares_channel)data->state.resolver, a6); return CURLE_OK; #else /* c-ares version too old! */ (void)data; (void)local_ip6; return CURLE_NOT_BUILT_IN; #endif } #endif /* CURLRES_ARES */ davix-0.8.0/deps/curl/lib/nwos.c0000644000000000000000000000507514121063461015135 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ int netware_init(void) { return 0; } #else /* __NOVELL_LIBC__ */ /* For native CLib-based NLM we need to initialize the LONG namespace. */ #include #include #include /* Make the CLIB Ctx stuff link */ #include NETDB_DEFINE_CONTEXT /* Make the CLIB Inet stuff link */ #include #include NETINET_DEFINE_CONTEXT int netware_init(void) { int rc = 0; unsigned int myHandle = GetNLMHandle(); /* import UnAugmentAsterisk dynamically for NW4.x compatibility */ void (*pUnAugmentAsterisk)(int) = (void(*)(int)) ImportSymbol(myHandle, "UnAugmentAsterisk"); /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */ void (*pUseAccurateCaseForPaths)(int) = (void(*)(int)) ImportSymbol(myHandle, "UseAccurateCaseForPaths"); if(pUnAugmentAsterisk) pUnAugmentAsterisk(1); if(pUseAccurateCaseForPaths) pUseAccurateCaseForPaths(1); UnimportSymbol(myHandle, "UnAugmentAsterisk"); UnimportSymbol(myHandle, "UseAccurateCaseForPaths"); /* set long name space */ if((SetCurrentNameSpace(4) == 255)) { rc = 1; } if((SetTargetNameSpace(4) == 255)) { rc = rc + 2; } return rc; } /* dummy function to satisfy newer prelude */ int __init_environment(void) { return 0; } /* dummy function to satisfy newer prelude */ int __deinit_environment(void) { return 0; } #endif /* __NOVELL_LIBC__ */ #endif /* NETWARE */ davix-0.8.0/deps/curl/lib/hmac.c0000644000000000000000000001204714121063461015054 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2104 Keyed-Hashing for Message Authentication * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_CRYPTO_AUTH #include #include "curl_hmac.h" #include "curl_memory.h" #include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" /* * Generic HMAC algorithm. * * This module computes HMAC digests based on any hash function. Parameters * and computing procedures are set-up dynamically at HMAC computation * context initialisation. */ static const unsigned char hmac_ipad = 0x36; static const unsigned char hmac_opad = 0x5C; HMAC_context * Curl_HMAC_init(const HMAC_params * hashparams, const unsigned char *key, unsigned int keylen) { size_t i; HMAC_context *ctxt; unsigned char *hkey; unsigned char b; /* Create HMAC context. */ i = sizeof(*ctxt) + 2 * hashparams->hmac_ctxtsize + hashparams->hmac_resultlen; ctxt = malloc(i); if(!ctxt) return ctxt; ctxt->hmac_hash = hashparams; ctxt->hmac_hashctxt1 = (void *) (ctxt + 1); ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 + hashparams->hmac_ctxtsize); /* If the key is too long, replace it by its hash digest. */ if(keylen > hashparams->hmac_maxkeylen) { (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen); hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize; (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1); key = hkey; keylen = hashparams->hmac_resultlen; } /* Prime the two hash contexts with the modified key. */ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2); for(i = 0; i < keylen; i++) { b = (unsigned char)(*key ^ hmac_ipad); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1); b = (unsigned char)(*key++ ^ hmac_opad); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1); } for(; i < hashparams->hmac_maxkeylen; i++) { (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1); } /* Done, return pointer to HMAC context. */ return ctxt; } int Curl_HMAC_update(HMAC_context * ctxt, const unsigned char *data, unsigned int len) { /* Update first hash calculation. */ (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len); return 0; } int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) { const HMAC_params * hashparams = ctxt->hmac_hash; /* Do not get result if called with a null parameter: only release storage. */ if(!result) result = (unsigned char *) ctxt->hmac_hashctxt2 + ctxt->hmac_hash->hmac_ctxtsize; (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1); (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, result, hashparams->hmac_resultlen); (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2); free((char *) ctxt); return 0; } /* * Curl_hmacit() * * This is used to generate a HMAC hash, for the specified input data, given * the specified hash function and key. * * Parameters: * * hashparams [in] - The hash function (Curl_HMAC_MD5). * key [in] - The key to use. * keylen [in] - The length of the key. * data [in] - The data to encrypt. * datalen [in] - The length of the data. * output [in/out] - The output buffer. * * Returns CURLE_OK on success. */ CURLcode Curl_hmacit(const HMAC_params *hashparams, const unsigned char *key, const size_t keylen, const unsigned char *data, const size_t datalen, unsigned char *output) { HMAC_context *ctxt = Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen)); if(!ctxt) return CURLE_OUT_OF_MEMORY; /* Update the digest with the given challenge */ Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen)); /* Finalise the digest */ Curl_HMAC_final(ctxt, output); return CURLE_OK; } #endif /* CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/strerror.h0000644000000000000000000000270614121063461016034 0ustar rootroot#ifndef HEADER_CURL_STRERROR_H #define HEADER_CURL_STRERROR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "urldata.h" #define STRERROR_LEN 256 /* a suitable length */ const char *Curl_strerror(int err, char *buf, size_t buflen); #if defined(WIN32) || defined(_WIN32_WCE) const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen); #endif #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror(int err, char *buf, size_t buflen); #endif #endif /* HEADER_CURL_STRERROR_H */ davix-0.8.0/deps/curl/lib/slist.c0000644000000000000000000000754414121063461015310 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "slist.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* returns last node in linked list */ static struct curl_slist *slist_get_last(struct curl_slist *list) { struct curl_slist *item; /* if caller passed us a NULL, return now */ if(!list) return NULL; /* loop through to find the last item */ item = list; while(item->next) { item = item->next; } return item; } /* * Curl_slist_append_nodup() appends a string to the linked list. Rather than * copying the string in dynamic storage, it takes its ownership. The string * should have been malloc()ated. Curl_slist_append_nodup always returns * the address of the first record, so that you can use this function as an * initialization function as well as an append function. * If an error occurs, NULL is returned and the string argument is NOT * released. */ struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data) { struct curl_slist *last; struct curl_slist *new_item; DEBUGASSERT(data); new_item = malloc(sizeof(struct curl_slist)); if(!new_item) return NULL; new_item->next = NULL; new_item->data = data; /* if this is the first item, then new_item *is* the list */ if(!list) return new_item; last = slist_get_last(list); last->next = new_item; return list; } /* * curl_slist_append() appends a string to the linked list. It always returns * the address of the first record, so that you can use this function as an * initialization function as well as an append function. If you find this * bothersome, then simply create a separate _init function and call it * appropriately from within the program. */ struct curl_slist *curl_slist_append(struct curl_slist *list, const char *data) { char *dupdata = strdup(data); if(!dupdata) return NULL; list = Curl_slist_append_nodup(list, dupdata); if(!list) free(dupdata); return list; } /* * Curl_slist_duplicate() duplicates a linked list. It always returns the * address of the first record of the cloned list or NULL in case of an * error (or if the input list was NULL). */ struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist) { struct curl_slist *outlist = NULL; struct curl_slist *tmp; while(inlist) { tmp = curl_slist_append(outlist, inlist->data); if(!tmp) { curl_slist_free_all(outlist); return NULL; } outlist = tmp; inlist = inlist->next; } return outlist; } /* be nice and clean up resources */ void curl_slist_free_all(struct curl_slist *list) { struct curl_slist *next; struct curl_slist *item; if(!list) return; item = list; do { next = item->next; Curl_safefree(item->data); free(item); item = next; } while(next); } davix-0.8.0/deps/curl/lib/curl_path.c0000644000000000000000000001464514121063461016133 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_SSH) #include #include "curl_memory.h" #include "curl_path.h" #include "escape.h" #include "memdebug.h" /* figure out the path to work with in this particular request */ CURLcode Curl_getworkingpath(struct connectdata *conn, char *homedir, /* when SFTP is used */ char **path) /* returns the allocated real path to work with */ { struct Curl_easy *data = conn->data; char *real_path = NULL; char *working_path; size_t working_path_len; CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &working_path, &working_path_len, FALSE); if(result) return result; /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { real_path = malloc(working_path_len + 1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) /* It is referenced to the home directory, so strip the leading '/~/' */ memcpy(real_path, working_path + 3, working_path_len - 2); else memcpy(real_path, working_path, 1 + working_path_len); } else if(conn->handler->protocol & CURLPROTO_SFTP) { if((working_path_len > 1) && (working_path[1] == '~')) { size_t homelen = strlen(homedir); real_path = malloc(homelen + working_path_len + 1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } /* It is referenced to the home directory, so strip the leading '/' */ memcpy(real_path, homedir, homelen); real_path[homelen] = '/'; real_path[homelen + 1] = '\0'; if(working_path_len > 3) { memcpy(real_path + homelen + 1, working_path + 3, 1 + working_path_len -3); } } else { real_path = malloc(working_path_len + 1); if(real_path == NULL) { free(working_path); return CURLE_OUT_OF_MEMORY; } memcpy(real_path, working_path, 1 + working_path_len); } } free(working_path); /* store the pointer for the caller to receive */ *path = real_path; return CURLE_OK; } /* The get_pathname() function is being borrowed from OpenSSH sftp.c version 4.6p1. */ /* * Copyright (c) 2001-2004 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) { const char *cp = *cpp, *end; char quot; unsigned int i, j; size_t fullPathLength, pathLength; bool relativePath = false; static const char WHITESPACE[] = " \t\r\n"; if(!*cp) { *cpp = NULL; *path = NULL; return CURLE_QUOTE_ERROR; } /* Ignore leading whitespace */ cp += strspn(cp, WHITESPACE); /* Allocate enough space for home directory and filename + separator */ fullPathLength = strlen(cp) + strlen(homedir) + 2; *path = malloc(fullPathLength); if(*path == NULL) return CURLE_OUT_OF_MEMORY; /* Check for quoted filenames */ if(*cp == '\"' || *cp == '\'') { quot = *cp++; /* Search for terminating quote, unescape some chars */ for(i = j = 0; i <= strlen(cp); i++) { if(cp[i] == quot) { /* Found quote */ i++; (*path)[j] = '\0'; break; } if(cp[i] == '\0') { /* End of string */ /*error("Unterminated quote");*/ goto fail; } if(cp[i] == '\\') { /* Escaped characters */ i++; if(cp[i] != '\'' && cp[i] != '\"' && cp[i] != '\\') { /*error("Bad escaped character '\\%c'", cp[i]);*/ goto fail; } } (*path)[j++] = cp[i]; } if(j == 0) { /*error("Empty quotes");*/ goto fail; } *cpp = cp + i + strspn(cp + i, WHITESPACE); } else { /* Read to end of filename - either to white space or terminator */ end = strpbrk(cp, WHITESPACE); if(end == NULL) end = strchr(cp, '\0'); /* return pointer to second parameter if it exists */ *cpp = end + strspn(end, WHITESPACE); pathLength = 0; relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/'); /* Handling for relative path - prepend home directory */ if(relativePath) { strcpy(*path, homedir); pathLength = strlen(homedir); (*path)[pathLength++] = '/'; (*path)[pathLength] = '\0'; cp += 3; } /* Copy path name up until first "white space" */ memcpy(&(*path)[pathLength], cp, (int)(end - cp)); pathLength += (int)(end - cp); (*path)[pathLength] = '\0'; } return CURLE_OK; fail: Curl_safefree(*path); return CURLE_QUOTE_ERROR; } #endif /* if SSH is used */ davix-0.8.0/deps/curl/lib/parsedate.c0000644000000000000000000004211114121063461016107 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* A brief summary of the date string formats this parser groks: RFC 2616 3.3.1 Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format we support dates without week day name: 06 Nov 1994 08:49:37 GMT 06-Nov-94 08:49:37 GMT Nov 6 08:49:37 1994 without the time zone: 06 Nov 1994 08:49:37 06-Nov-94 08:49:37 weird order: 1994 Nov 6 08:49:37 (GNU date fails) GMT 08:49:37 06-Nov-94 Sunday 94 6 Nov 08:49:37 (GNU date fails) time left out: 1994 Nov 6 06-Nov-94 Sun Nov 6 94 unusual separators: 1994.Nov.6 Sun/Nov/6/94/GMT commonly used time zone names: Sun, 06 Nov 1994 08:49:37 CET 06 Nov 1994 08:49:37 EST time zones specified using RFC822 style: Sun, 12 Sep 2004 15:05:58 -0700 Sat, 11 Sep 2004 21:32:11 +0200 compact numerical date strings: 20040912 15:05:58 -0700 20040911 +0200 */ #include "curl_setup.h" #include #include #include "strcase.h" #include "warnless.h" #include "parsedate.h" /* * parsedate() * * Returns: * * PARSEDATE_OK - a fine conversion * PARSEDATE_FAIL - failed to convert * PARSEDATE_LATER - time overflow at the far end of time_t * PARSEDATE_SOONER - time underflow at the low end of time_t */ static int parsedate(const char *date, time_t *output); #define PARSEDATE_OK 0 #define PARSEDATE_FAIL -1 #define PARSEDATE_LATER 1 #define PARSEDATE_SOONER 2 #if !defined(CURL_DISABLE_PARSEDATE) || !defined(CURL_DISABLE_FTP) || \ !defined(CURL_DISABLE_FILE) /* These names are also used by FTP and FILE code */ const char * const Curl_wkday[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; const char * const Curl_month[]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; #endif #ifndef CURL_DISABLE_PARSEDATE static const char * const weekday[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; struct tzinfo { char name[5]; int offset; /* +/- in minutes */ }; /* Here's a bunch of frequently used time zone names. These were supported by the old getdate parser. */ #define tDAYZONE -60 /* offset for daylight savings time */ static const struct tzinfo tz[]= { {"GMT", 0}, /* Greenwich Mean */ {"UT", 0}, /* Universal Time */ {"UTC", 0}, /* Universal (Coordinated) */ {"WET", 0}, /* Western European */ {"BST", 0 tDAYZONE}, /* British Summer */ {"WAT", 60}, /* West Africa */ {"AST", 240}, /* Atlantic Standard */ {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */ {"EST", 300}, /* Eastern Standard */ {"EDT", 300 tDAYZONE}, /* Eastern Daylight */ {"CST", 360}, /* Central Standard */ {"CDT", 360 tDAYZONE}, /* Central Daylight */ {"MST", 420}, /* Mountain Standard */ {"MDT", 420 tDAYZONE}, /* Mountain Daylight */ {"PST", 480}, /* Pacific Standard */ {"PDT", 480 tDAYZONE}, /* Pacific Daylight */ {"YST", 540}, /* Yukon Standard */ {"YDT", 540 tDAYZONE}, /* Yukon Daylight */ {"HST", 600}, /* Hawaii Standard */ {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */ {"CAT", 600}, /* Central Alaska */ {"AHST", 600}, /* Alaska-Hawaii Standard */ {"NT", 660}, /* Nome */ {"IDLW", 720}, /* International Date Line West */ {"CET", -60}, /* Central European */ {"MET", -60}, /* Middle European */ {"MEWT", -60}, /* Middle European Winter */ {"MEST", -60 tDAYZONE}, /* Middle European Summer */ {"CEST", -60 tDAYZONE}, /* Central European Summer */ {"MESZ", -60 tDAYZONE}, /* Middle European Summer */ {"FWT", -60}, /* French Winter */ {"FST", -60 tDAYZONE}, /* French Summer */ {"EET", -120}, /* Eastern Europe, USSR Zone 1 */ {"WAST", -420}, /* West Australian Standard */ {"WADT", -420 tDAYZONE}, /* West Australian Daylight */ {"CCT", -480}, /* China Coast, USSR Zone 7 */ {"JST", -540}, /* Japan Standard, USSR Zone 8 */ {"EAST", -600}, /* Eastern Australian Standard */ {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */ {"GST", -600}, /* Guam Standard, USSR Zone 9 */ {"NZT", -720}, /* New Zealand */ {"NZST", -720}, /* New Zealand Standard */ {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */ {"IDLE", -720}, /* International Date Line East */ /* Next up: Military timezone names. RFC822 allowed these, but (as noted in RFC 1123) had their signs wrong. Here we use the correct signs to match actual military usage. */ {"A", 1 * 60}, /* Alpha */ {"B", 2 * 60}, /* Bravo */ {"C", 3 * 60}, /* Charlie */ {"D", 4 * 60}, /* Delta */ {"E", 5 * 60}, /* Echo */ {"F", 6 * 60}, /* Foxtrot */ {"G", 7 * 60}, /* Golf */ {"H", 8 * 60}, /* Hotel */ {"I", 9 * 60}, /* India */ /* "J", Juliet is not used as a timezone, to indicate the observer's local time */ {"K", 10 * 60}, /* Kilo */ {"L", 11 * 60}, /* Lima */ {"M", 12 * 60}, /* Mike */ {"N", -1 * 60}, /* November */ {"O", -2 * 60}, /* Oscar */ {"P", -3 * 60}, /* Papa */ {"Q", -4 * 60}, /* Quebec */ {"R", -5 * 60}, /* Romeo */ {"S", -6 * 60}, /* Sierra */ {"T", -7 * 60}, /* Tango */ {"U", -8 * 60}, /* Uniform */ {"V", -9 * 60}, /* Victor */ {"W", -10 * 60}, /* Whiskey */ {"X", -11 * 60}, /* X-ray */ {"Y", -12 * 60}, /* Yankee */ {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */ }; /* returns: -1 no day 0 monday - 6 sunday */ static int checkday(const char *check, size_t len) { int i; const char * const *what; bool found = FALSE; if(len > 3) what = &weekday[0]; else what = &Curl_wkday[0]; for(i = 0; i<7; i++) { if(strcasecompare(check, what[0])) { found = TRUE; break; } what++; } return found?i:-1; } static int checkmonth(const char *check) { int i; const char * const *what; bool found = FALSE; what = &Curl_month[0]; for(i = 0; i<12; i++) { if(strcasecompare(check, what[0])) { found = TRUE; break; } what++; } return found?i:-1; /* return the offset or -1, no real offset is -1 */ } /* return the time zone offset between GMT and the input one, in number of seconds or -1 if the timezone wasn't found/legal */ static int checktz(const char *check) { unsigned int i; const struct tzinfo *what; bool found = FALSE; what = tz; for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { if(strcasecompare(check, what->name)) { found = TRUE; break; } what++; } return found?what->offset*60:-1; } static void skip(const char **date) { /* skip everything that aren't letters or digits */ while(**date && !ISALNUM(**date)) (*date)++; } enum assume { DATE_MDAY, DATE_YEAR, DATE_TIME }; /* this is a clone of 'struct tm' but with all fields we don't need or use cut out */ struct my_tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; /* full year */ }; /* struct tm to time since epoch in GMT time zone. * This is similar to the standard mktime function but for GMT only, and * doesn't suffer from the various bugs and portability problems that * some systems' implementations have. * * Returns 0 on success, otherwise non-zero. */ static void my_timegm(struct my_tm *tm, time_t *t) { static const int month_days_cumulative [12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int month, year, leap_days; year = tm->tm_year; month = tm->tm_mon; if(month < 0) { year += (11 - month) / 12; month = 11 - (11 - month) % 12; } else if(month >= 12) { year -= month / 12; month = month % 12; } leap_days = year - (tm->tm_mon <= 1); leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400) - (1969 / 4) + (1969 / 100) - (1969 / 400)); *t = ((((time_t) (year - 1970) * 365 + leap_days + month_days_cumulative[month] + tm->tm_mday - 1) * 24 + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; } /* * parsedate() * * Returns: * * PARSEDATE_OK - a fine conversion * PARSEDATE_FAIL - failed to convert * PARSEDATE_LATER - time overflow at the far end of time_t * PARSEDATE_SOONER - time underflow at the low end of time_t */ static int parsedate(const char *date, time_t *output) { time_t t = 0; int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ int monnum = -1; /* month of the year number, 0-11 */ int mdaynum = -1; /* day of month, 1 - 31 */ int hournum = -1; int minnum = -1; int secnum = -1; int yearnum = -1; int tzoff = -1; struct my_tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { bool found = FALSE; skip(&date); if(ISALPHA(*date)) { /* a name coming up */ char buf[32]=""; size_t len; if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz]", buf)) len = strlen(buf); else len = 0; if(wdaynum == -1) { wdaynum = checkday(buf, len); if(wdaynum != -1) found = TRUE; } if(!found && (monnum == -1)) { monnum = checkmonth(buf); if(monnum != -1) found = TRUE; } if(!found && (tzoff == -1)) { /* this just must be a time zone string */ tzoff = checktz(buf); if(tzoff != -1) found = TRUE; } if(!found) return PARSEDATE_FAIL; /* bad string */ date += len; } else if(ISDIGIT(*date)) { /* a digit */ int val; char *end; int len = 0; if((secnum == -1) && (3 == sscanf(date, "%02d:%02d:%02d%n", &hournum, &minnum, &secnum, &len))) { /* time stamp! */ date += len; } else if((secnum == -1) && (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ date += len; secnum = 0; } else { long lval; int error; int old_errno; old_errno = errno; errno = 0; lval = strtol(date, &end, 10); error = errno; if(errno != old_errno) errno = old_errno; if(error) return PARSEDATE_FAIL; #if LONG_MAX != INT_MAX if((lval > (long)INT_MAX) || (lval < (long)INT_MIN)) return PARSEDATE_FAIL; #endif val = curlx_sltosi(lval); if((tzoff == -1) && ((end - date) == 4) && (val <= 1400) && (indate< date) && ((date[-1] == '+' || date[-1] == '-'))) { /* four digits and a value less than or equal to 1400 (to take into account all sorts of funny time zone diffs) and it is preceded with a plus or minus. This is a time zone indication. 1400 is picked since +1300 is frequently used and +1400 is mentioned as an edge number in the document "ISO C 200X Proposal: Timezone Functions" at http://david.tribble.com/text/c0xtimezone.html If anyone has a more authoritative source for the exact maximum time zone offsets, please speak up! */ found = TRUE; tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, this we need their reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } if(((end - date) == 8) && (yearnum == -1) && (monnum == -1) && (mdaynum == -1)) { /* 8 digits, no year, month or day yet. This is YYYYMMDD */ found = TRUE; yearnum = val/10000; monnum = (val%10000)/100-1; /* month is 0 - 11 */ mdaynum = val%100; } if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) { if((val > 0) && (val<32)) { mdaynum = val; found = TRUE; } dignext = DATE_YEAR; } if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; if(yearnum < 100) { if(yearnum > 70) yearnum += 1900; else yearnum += 2000; } if(mdaynum == -1) dignext = DATE_MDAY; } if(!found) return PARSEDATE_FAIL; date = end; } } part++; } if(-1 == secnum) secnum = minnum = hournum = 0; /* no time, make it zero */ if((-1 == mdaynum) || (-1 == monnum) || (-1 == yearnum)) /* lacks vital info, fail */ return PARSEDATE_FAIL; #ifdef HAVE_TIME_T_UNSIGNED if(yearnum < 1970) { /* only positive numbers cannot return earlier */ *output = TIME_T_MIN; return PARSEDATE_SOONER; } #endif #if (SIZEOF_TIME_T < 5) #ifdef HAVE_TIME_T_UNSIGNED /* an unsigned 32 bit time_t can only hold dates to 2106 */ if(yearnum > 2105) { *output = TIME_T_MAX; return PARSEDATE_LATER; } #else /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */ if(yearnum > 2037) { *output = TIME_T_MAX; return PARSEDATE_LATER; } if(yearnum < 1903) { *output = TIME_T_MIN; return PARSEDATE_SOONER; } #endif #else /* The Gregorian calendar was introduced 1582 */ if(yearnum < 1583) return PARSEDATE_FAIL; #endif if((mdaynum > 31) || (monnum > 11) || (hournum > 23) || (minnum > 59) || (secnum > 60)) return PARSEDATE_FAIL; /* clearly an illegal date */ tm.tm_sec = secnum; tm.tm_min = minnum; tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; tm.tm_year = yearnum; /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on architectures that feature 64 bit 'long' but ultimately time_t is the correct data type to use. */ my_timegm(&tm, &t); /* Add the time zone diff between local time zone and GMT. */ if(tzoff == -1) tzoff = 0; if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) { *output = TIME_T_MAX; return PARSEDATE_LATER; /* time_t overflow */ } t += tzoff; *output = t; return PARSEDATE_OK; } #else /* disabled */ static int parsedate(const char *date, time_t *output) { (void)date; *output = 0; return PARSEDATE_OK; /* a lie */ } #endif time_t curl_getdate(const char *p, const time_t *now) { time_t parsed = -1; int rc = parsedate(p, &parsed); (void)now; /* legacy argument from the past that we ignore */ if(rc == PARSEDATE_OK) { if(parsed == -1) /* avoid returning -1 for a working scenario */ parsed++; return parsed; } /* everything else is fail */ return -1; } /* Curl_getdate_capped() differs from curl_getdate() in that this will return TIME_T_MAX in case the parsed time value was too big, instead of an error. */ time_t Curl_getdate_capped(const char *p) { time_t parsed = -1; int rc = parsedate(p, &parsed); switch(rc) { case PARSEDATE_OK: if(parsed == -1) /* avoid returning -1 for a working scenario */ parsed++; return parsed; case PARSEDATE_LATER: /* this returns the maximum time value */ return parsed; default: return -1; /* everything else is fail */ } /* UNREACHABLE */ } /* * Curl_gmtime() is a gmtime() replacement for portability. Do not use the * gmtime_r() or gmtime() functions anywhere else but here. * */ CURLcode Curl_gmtime(time_t intime, struct tm *store) { const struct tm *tm; #ifdef HAVE_GMTIME_R /* thread-safe version */ tm = (struct tm *)gmtime_r(&intime, store); #else tm = gmtime(&intime); if(tm) *store = *tm; /* copy the pointed struct to the local copy */ #endif if(!tm) return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_OK; } davix-0.8.0/deps/curl/lib/curl_endian.h0000644000000000000000000000325114121063461016431 0ustar rootroot#ifndef HEADER_CURL_ENDIAN_H #define HEADER_CURL_ENDIAN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Converts a 16-bit integer from little endian */ unsigned short Curl_read16_le(const unsigned char *buf); /* Converts a 32-bit integer from little endian */ unsigned int Curl_read32_le(const unsigned char *buf); /* Converts a 16-bit integer from big endian */ unsigned short Curl_read16_be(const unsigned char *buf); #if (CURL_SIZEOF_CURL_OFF_T > 4) /* Converts a 64-bit integer to little endian */ #if defined(HAVE_LONGLONG) void Curl_write64_le(const long long value, unsigned char *buffer); #else void Curl_write64_le(const __int64 value, unsigned char *buffer); #endif #endif #endif /* HEADER_CURL_ENDIAN_H */ davix-0.8.0/deps/curl/lib/tftp.h0000644000000000000000000000225614121063461015127 0ustar rootroot#ifndef HEADER_CURL_TFTP_H #define HEADER_CURL_TFTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifndef CURL_DISABLE_TFTP extern const struct Curl_handler Curl_handler_tftp; #endif #endif /* HEADER_CURL_TFTP_H */ davix-0.8.0/deps/curl/lib/config-win32ce.h0000644000000000000000000003263014121063461016666 0ustar rootroot#ifndef HEADER_CURL_CONFIG_WIN32CE_H #define HEADER_CURL_CONFIG_WIN32CE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* lib/config-win32ce.h - Hand crafted config file for windows ce */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ /* Define if you have the header file. */ /* #define HAVE_ARPA_INET_H 1 */ /* Define if you have the header file. */ /* #define HAVE_ASSERT_H 1 */ /* Define if you have the header file. */ /* #define HAVE_CRYPTO_H 1 */ /* Define if you have the header file. */ /* #define HAVE_ERRNO_H 1 */ /* Define if you have the header file. */ /* #define HAVE_ERR_H 1 */ /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ /* #define HAVE_GETOPT_H 1 */ /* Define if you have the header file. */ #define HAVE_IO_H 1 /* Define if you need the malloc.h header header file even with stdlib.h */ #define NEED_MALLOC_H 1 /* Define if you have the header file. */ /* #define HAVE_NETDB_H 1 */ /* Define if you have the header file. */ /* #define HAVE_NETINET_IN_H 1 */ /* Define if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define if you have the header file. */ /* #define HAVE_SGTTY_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SSL_H 1 */ /* Define if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define if you have the header file. */ /* #define HAVE_PROCESS_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_PARAM_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SELECT_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SOCKET_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ /* Define if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define if you have the header file */ /* #define HAVE_SYS_TIME_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_TYPES_H 1 */ /* Define if you have the header file */ #define HAVE_SYS_UTIME_H 1 /* Define if you have the header file. */ /* #define HAVE_TERMIO_H 1 */ /* Define if you have the header file. */ /* #define HAVE_TERMIOS_H 1 */ /* Define if you have the header file. */ #define HAVE_TIME_H 1 /* Define if you have the header file. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) #define HAVE_UNISTD_H 1 #endif /* Define if you have the header file. */ #define HAVE_WINDOWS_H 1 /* Define if you have the header file. */ #define HAVE_WINSOCK_H 1 /* Define if you have the header file. */ /* #define HAVE_WINSOCK2_H 1 */ /* Define if you have the header file. */ /* #define HAVE_WS2TCPIP_H 1 */ /* ---------------------------------------------------------------- */ /* OTHER HEADER INFO */ /* ---------------------------------------------------------------- */ /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ /* #define TIME_WITH_SYS_TIME 1 */ /* ---------------------------------------------------------------- */ /* FUNCTIONS */ /* ---------------------------------------------------------------- */ /* Define if you have the closesocket function. */ #define HAVE_CLOSESOCKET 1 /* Define if you don't have vprintf but do have _doprnt. */ /* #define HAVE_DOPRNT 1 */ /* Define if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 /* Define if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 /* Define if you have the getpass function. */ /* #define HAVE_GETPASS 1 */ /* Define if you have the getservbyname function. */ #define HAVE_GETSERVBYNAME 1 /* Define if you have the gettimeofday function. */ /* #define HAVE_GETTIMEOFDAY 1 */ /* Define if you have the inet_addr function. */ #define HAVE_INET_ADDR 1 /* Define if you have the ioctlsocket function. */ #define HAVE_IOCTLSOCKET 1 /* Define if you have a working ioctlsocket FIONBIO function. */ #define HAVE_IOCTLSOCKET_FIONBIO 1 /* Define if you have the perror function. */ #define HAVE_PERROR 1 /* Define if you have the RAND_screen function when using SSL */ #define HAVE_RAND_SCREEN 1 /* Define if you have the `RAND_status' function when using SSL. */ #define HAVE_RAND_STATUS 1 /* Define if you have the select function. */ #define HAVE_SELECT 1 /* Define if you have the setvbuf function. */ #define HAVE_SETVBUF 1 /* Define if you have the socket function. */ #define HAVE_SOCKET 1 /* Define if you have the strcasecmp function. */ /* #define HAVE_STRCASECMP 1 */ /* Define if you have the strdup function. */ /* #define HAVE_STRDUP 1 */ /* Define if you have the strftime function. */ /* #define HAVE_STRFTIME 1 */ /* Define if you have the stricmp function. */ /* #define HAVE_STRICMP 1 */ /* Define if you have the strncasecmp function. */ /* #define HAVE_STRNCASECMP 1 */ /* Define if you have the strnicmp function. */ /* #define HAVE_STRNICMP 1 */ /* Define if you have the strstr function. */ #define HAVE_STRSTR 1 /* Define if you have the strtoll function. */ #if defined(__MINGW32__) || defined(__WATCOMC__) #define HAVE_STRTOLL 1 #endif /* Define if you have the tcgetattr function. */ /* #define HAVE_TCGETATTR 1 */ /* Define if you have the tcsetattr function. */ /* #define HAVE_TCSETATTR 1 */ /* Define if you have the utime function */ #define HAVE_UTIME 1 /* Define if you have the getnameinfo function. */ #define HAVE_GETNAMEINFO 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 DWORD /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 int /* Define if you have the recv function. */ #define HAVE_RECV 1 /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 SOCKET /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 char * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 int /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV int /* Define if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 SOCKET /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 char /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 int /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 int /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV int /* Define if you have the send function. */ #define HAVE_SEND 1 /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 SOCKET /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 const /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 char * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 int /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV int /* ---------------------------------------------------------------- */ /* TYPEDEF REPLACEMENTS */ /* ---------------------------------------------------------------- */ /* Define this if in_addr_t is not an available 'typedefed' type */ #define in_addr_t unsigned long /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define ssize_t if it is not an available 'typedefed' type */ #if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || defined(__POCC__) #elif defined(_WIN64) #define ssize_t __int64 #else #define ssize_t int #endif /* ---------------------------------------------------------------- */ /* TYPE SIZES */ /* ---------------------------------------------------------------- */ /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 16 /* The size of `long long', as computed by sizeof. */ /* #define SIZEOF_LONG_LONG 8 */ /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* Define to the size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `size_t', as computed by sizeof. */ #if defined(_WIN64) # define SIZEOF_SIZE_T 8 #else # define SIZEOF_SIZE_T 4 #endif /* ---------------------------------------------------------------- */ /* STRUCT RELATED */ /* ---------------------------------------------------------------- */ /* Define this if you have struct sockaddr_storage */ /* #define HAVE_STRUCT_SOCKADDR_STORAGE 1 */ /* Define this if you have struct timeval */ #define HAVE_STRUCT_TIMEVAL 1 /* Define this if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* ---------------------------------------------------------------- */ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ /* Undef keyword 'const' if it does not work. */ /* #undef const */ /* Define to avoid VS2005 complaining about portable C functions */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif /* VS2005 and later default size for time_t is 64-bit, unless */ /* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) # ifndef _USE_32BIT_TIME_T # define SIZEOF_TIME_T 8 # else # define SIZEOF_TIME_T 4 # endif #endif /* ---------------------------------------------------------------- */ /* LARGE FILE SUPPORT */ /* ---------------------------------------------------------------- */ #if defined(_MSC_VER) && !defined(_WIN32_WCE) # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) # define USE_WIN32_LARGE_FILES # else # define USE_WIN32_SMALL_FILES # endif #endif #if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) # define USE_WIN32_SMALL_FILES #endif /* ---------------------------------------------------------------- */ /* LDAP SUPPORT */ /* ---------------------------------------------------------------- */ #define USE_WIN32_LDAP 1 #undef HAVE_LDAP_URL_PARSE /* ---------------------------------------------------------------- */ /* ADDITIONAL DEFINITIONS */ /* ---------------------------------------------------------------- */ /* Define cpu-machine-OS */ #undef OS #define OS "i386-pc-win32ce" /* Name of package */ #define PACKAGE "curl" /* ---------------------------------------------------------------- */ /* WinCE */ /* ---------------------------------------------------------------- */ #ifndef UNICODE # define UNICODE #endif #ifndef _UNICODE # define _UNICODE #endif #define CURL_DISABLE_FILE 1 #define CURL_DISABLE_TELNET 1 #define CURL_DISABLE_LDAP 1 #define ENOSPC 1 #define ENOMEM 2 #define EAGAIN 3 extern int stat(const char *path, struct stat *buffer); #endif /* HEADER_CURL_CONFIG_WIN32CE_H */ davix-0.8.0/deps/curl/lib/formdata.h0000644000000000000000000000405514121063461015746 0ustar rootroot#ifndef HEADER_CURL_FORMDATA_H #define HEADER_CURL_FORMDATA_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_MIME /* used by FormAdd for temporary storage */ typedef struct FormInfo { char *name; bool name_alloc; size_t namelength; char *value; bool value_alloc; curl_off_t contentslength; char *contenttype; bool contenttype_alloc; long flags; char *buffer; /* pointer to existing buffer used for file upload */ size_t bufferlength; char *showfilename; /* The file name to show. If not set, the actual file name will be used */ bool showfilename_alloc; char *userp; /* pointer for the read callback */ struct curl_slist *contentheader; struct FormInfo *more; } FormInfo; CURLcode Curl_getformdata(struct Curl_easy *data, curl_mimepart *, struct curl_httppost *post, curl_read_callback fread_func); #else /* disabled */ #define Curl_getformdata(a,b,c,d) CURLE_NOT_BUILT_IN #endif #endif /* HEADER_CURL_FORMDATA_H */ davix-0.8.0/deps/curl/lib/inet_pton.h0000644000000000000000000000262414121063461016150 0ustar rootroot#ifndef HEADER_CURL_INET_PTON_H #define HEADER_CURL_INET_PTON_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" int Curl_inet_pton(int, const char *, void *); #ifdef HAVE_INET_PTON #ifdef HAVE_ARPA_INET_H #include #elif defined(HAVE_WS2TCPIP_H) /* inet_pton() exists in Vista or later */ #include #endif #define Curl_inet_pton(x,y,z) inet_pton(x,y,z) #endif #endif /* HEADER_CURL_INET_PTON_H */ davix-0.8.0/deps/curl/lib/share.h0000644000000000000000000000407414121063461015254 0ustar rootroot#ifndef HEADER_CURL_SHARE_H #define HEADER_CURL_SHARE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "cookie.h" #include "psl.h" #include "urldata.h" #include "conncache.h" /* SalfordC says "A structure member may not be volatile". Hence: */ #ifdef __SALFORDC__ #define CURL_VOLATILE #else #define CURL_VOLATILE volatile #endif /* this struct is libcurl-private, don't export details */ struct Curl_share { unsigned int specifier; CURL_VOLATILE unsigned int dirty; curl_lock_function lockfunc; curl_unlock_function unlockfunc; void *clientdata; struct conncache conn_cache; struct curl_hash hostcache; #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) struct CookieInfo *cookies; #endif #ifdef USE_LIBPSL struct PslCache psl; #endif struct curl_ssl_session *sslsession; size_t max_ssl_sessions; long sessionage; }; CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, curl_lock_access); CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data); #endif /* HEADER_CURL_SHARE_H */ davix-0.8.0/deps/curl/lib/config-amigaos.h0000644000000000000000000001064514121063461017036 0ustar rootroot#ifndef HEADER_CURL_CONFIG_AMIGAOS_H #define HEADER_CURL_CONFIG_AMIGAOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for AmigaOS */ /* ================================================================ */ #ifdef __AMIGA__ /* Any AmigaOS flavour */ #define HAVE_ARPA_INET_H 1 #define HAVE_CLOSESOCKET_CAMEL 1 #define HAVE_ERRNO_H 1 #define HAVE_GETHOSTBYADDR 1 #define HAVE_INET_ADDR 1 #define HAVE_INTTYPES_H 1 #define HAVE_IOCTLSOCKET_CAMEL 1 #define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1 #define HAVE_LIBZ 1 #define HAVE_LONGLONG 1 #define HAVE_MALLOC_H 1 #define HAVE_MEMORY_H 1 #define HAVE_NETDB_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_NET_IF_H 1 #define HAVE_OPENSSL_CRYPTO_H 1 #define HAVE_OPENSSL_ERR_H 1 #define HAVE_OPENSSL_PEM_H 1 #define HAVE_OPENSSL_RSA_H 1 #define HAVE_OPENSSL_SSL_H 1 #define HAVE_OPENSSL_X509_H 1 #define HAVE_PERROR 1 #define HAVE_PWD_H 1 #define HAVE_RAND_EGD 1 #define HAVE_RAND_STATUS 1 #define HAVE_SELECT 1 #define HAVE_SETJMP_H 1 #define HAVE_SGTTY_H 1 #define HAVE_SIGNAL 1 #define HAVE_SIGNAL_H 1 #define HAVE_SIG_ATOMIC_T 1 #define HAVE_SOCKET 1 #define HAVE_STRCASECMP 1 #define HAVE_STRDUP 1 #define HAVE_STRFTIME 1 #define HAVE_STRICMP 1 #define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_STRSTR 1 #define HAVE_STRUCT_TIMEVAL 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_SOCKIO_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_TIME_H 1 #define HAVE_UNAME 1 #define HAVE_UNISTD_H 1 #define HAVE_UTIME 1 #define HAVE_UTIME_H 1 #define HAVE_WRITABLE_ARGV 1 #define HAVE_ZLIB_H 1 #define HAVE_SYS_IOCTL_H 1 #define NEED_MALLOC_H 1 #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_SIZE_T 4 #define USE_MANUAL 1 #define USE_OPENSSL 1 #define CURL_DISABLE_LDAP 1 #define OS "AmigaOS" #define PACKAGE "curl" #define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.haxx.se/mail/" #define PACKAGE_NAME "curl" #define PACKAGE_STRING "curl -" #define PACKAGE_TARNAME "curl" #define PACKAGE_VERSION "-" #define CURL_CA_BUNDLE "s:curl-ca-bundle.crt" #define RETSIGTYPE void #define SELECT_TYPE_ARG1 int #define SELECT_TYPE_ARG234 (fd_set *) #define SELECT_TYPE_ARG5 (struct timeval *) #define STDC_HEADERS 1 #define TIME_WITH_SYS_TIME 1 #define in_addr_t int #ifndef F_OK # define F_OK 0 #endif #ifndef O_RDONLY # define O_RDONLY 0x0000 #endif #ifndef LONG_MAX # define LONG_MAX 0x7fffffffL #endif #ifndef LONG_MIN # define LONG_MIN (-0x7fffffffL-1) #endif #define HAVE_GETNAMEINFO 1 #define GETNAMEINFO_QUAL_ARG1 const #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * #define GETNAMEINFO_TYPE_ARG2 int #define GETNAMEINFO_TYPE_ARG46 size_t #define GETNAMEINFO_TYPE_ARG7 int #define HAVE_RECV 1 #define RECV_TYPE_ARG1 long #define RECV_TYPE_ARG2 char * #define RECV_TYPE_ARG3 long #define RECV_TYPE_ARG4 long #define RECV_TYPE_RETV long #define HAVE_RECVFROM 1 #define RECVFROM_TYPE_ARG1 long #define RECVFROM_TYPE_ARG2 char #define RECVFROM_TYPE_ARG3 long #define RECVFROM_TYPE_ARG4 long #define RECVFROM_TYPE_ARG5 struct sockaddr #define RECVFROM_TYPE_ARG6 long #define RECVFROM_TYPE_RETV long #define HAVE_SEND 1 #define SEND_TYPE_ARG1 int #define SEND_QUAL_ARG2 const #define SEND_TYPE_ARG2 char * #define SEND_TYPE_ARG3 int #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV int #endif /* __AMIGA__ */ #endif /* HEADER_CURL_CONFIG_AMIGAOS_H */ davix-0.8.0/deps/curl/lib/smb.h0000644000000000000000000001525214121063461014733 0ustar rootroot#ifndef HEADER_CURL_SMB_H #define HEADER_CURL_SMB_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel , Exacq Technologies * Copyright (C) 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ enum smb_conn_state { SMB_NOT_CONNECTED = 0, SMB_CONNECTING, SMB_NEGOTIATE, SMB_SETUP, SMB_CONNECTED }; struct smb_conn { enum smb_conn_state state; char *user; char *domain; char *share; unsigned char challenge[8]; unsigned int session_key; unsigned short uid; char *recv_buf; size_t upload_size; size_t send_size; size_t sent; size_t got; }; /* * Definitions for SMB protocol data structures */ #ifdef BUILDING_CURL_SMB_C #if defined(_MSC_VER) || defined(__ILEC400__) # define PACK # pragma pack(push) # pragma pack(1) #elif defined(__GNUC__) # define PACK __attribute__((packed)) #else # define PACK #endif #define SMB_COM_CLOSE 0x04 #define SMB_COM_READ_ANDX 0x2e #define SMB_COM_WRITE_ANDX 0x2f #define SMB_COM_TREE_DISCONNECT 0x71 #define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_SETUP_ANDX 0x73 #define SMB_COM_TREE_CONNECT_ANDX 0x75 #define SMB_COM_NT_CREATE_ANDX 0xa2 #define SMB_COM_NO_ANDX_COMMAND 0xff #define SMB_WC_CLOSE 0x03 #define SMB_WC_READ_ANDX 0x0c #define SMB_WC_WRITE_ANDX 0x0e #define SMB_WC_SETUP_ANDX 0x0d #define SMB_WC_TREE_CONNECT_ANDX 0x04 #define SMB_WC_NT_CREATE_ANDX 0x18 #define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 #define SMB_FLAGS_CASELESS_PATHNAMES 0x08 #define SMB_FLAGS2_UNICODE_STRINGS 0x8000 #define SMB_FLAGS2_IS_LONG_NAME 0x0040 #define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 #define SMB_CAP_LARGE_FILES 0x08 #define SMB_GENERIC_WRITE 0x40000000 #define SMB_GENERIC_READ 0x80000000 #define SMB_FILE_SHARE_ALL 0x07 #define SMB_FILE_OPEN 0x01 #define SMB_FILE_OVERWRITE_IF 0x05 #define SMB_ERR_NOACCESS 0x00050001 struct smb_header { unsigned char nbt_type; unsigned char nbt_flags; unsigned short nbt_length; unsigned char magic[4]; unsigned char command; unsigned int status; unsigned char flags; unsigned short flags2; unsigned short pid_high; unsigned char signature[8]; unsigned short pad; unsigned short tid; unsigned short pid; unsigned short uid; unsigned short mid; } PACK; struct smb_negotiate_response { struct smb_header h; unsigned char word_count; unsigned short dialect_index; unsigned char security_mode; unsigned short max_mpx_count; unsigned short max_number_vcs; unsigned int max_buffer_size; unsigned int max_raw_size; unsigned int session_key; unsigned int capabilities; unsigned int system_time_low; unsigned int system_time_high; unsigned short server_time_zone; unsigned char encryption_key_length; unsigned short byte_count; char bytes[1]; } PACK; struct andx { unsigned char command; unsigned char pad; unsigned short offset; } PACK; struct smb_setup { unsigned char word_count; struct andx andx; unsigned short max_buffer_size; unsigned short max_mpx_count; unsigned short vc_number; unsigned int session_key; unsigned short lengths[2]; unsigned int pad; unsigned int capabilities; unsigned short byte_count; char bytes[1024]; } PACK; struct smb_tree_connect { unsigned char word_count; struct andx andx; unsigned short flags; unsigned short pw_len; unsigned short byte_count; char bytes[1024]; } PACK; struct smb_nt_create { unsigned char word_count; struct andx andx; unsigned char pad; unsigned short name_length; unsigned int flags; unsigned int root_fid; unsigned int access; curl_off_t allocation_size; unsigned int ext_file_attributes; unsigned int share_access; unsigned int create_disposition; unsigned int create_options; unsigned int impersonation_level; unsigned char security_flags; unsigned short byte_count; char bytes[1024]; } PACK; struct smb_nt_create_response { struct smb_header h; unsigned char word_count; struct andx andx; unsigned char op_lock_level; unsigned short fid; unsigned int create_disposition; curl_off_t create_time; curl_off_t last_access_time; curl_off_t last_write_time; curl_off_t last_change_time; unsigned int ext_file_attributes; curl_off_t allocation_size; curl_off_t end_of_file; } PACK; struct smb_read { unsigned char word_count; struct andx andx; unsigned short fid; unsigned int offset; unsigned short max_bytes; unsigned short min_bytes; unsigned int timeout; unsigned short remaining; unsigned int offset_high; unsigned short byte_count; } PACK; struct smb_write { struct smb_header h; unsigned char word_count; struct andx andx; unsigned short fid; unsigned int offset; unsigned int timeout; unsigned short write_mode; unsigned short remaining; unsigned short pad; unsigned short data_length; unsigned short data_offset; unsigned int offset_high; unsigned short byte_count; unsigned char pad2; } PACK; struct smb_close { unsigned char word_count; unsigned short fid; unsigned int last_mtime; unsigned short byte_count; } PACK; struct smb_tree_disconnect { unsigned char word_count; unsigned short byte_count; } PACK; #if defined(_MSC_VER) || defined(__ILEC400__) # pragma pack(pop) #endif #endif /* BUILDING_CURL_SMB_C */ #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ (CURL_SIZEOF_CURL_OFF_T > 4) #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) extern const struct Curl_handler Curl_handler_smb; extern const struct Curl_handler Curl_handler_smbs; #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ #endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ #endif /* HEADER_CURL_SMB_H */ davix-0.8.0/deps/curl/lib/dotdot.c0000644000000000000000000001204214121063461015434 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "dotdot.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * "Remove Dot Segments" * https://tools.ietf.org/html/rfc3986#section-5.2.4 */ /* * Curl_dedotdotify() * @unittest: 1395 * * This function gets a zero-terminated path with dot and dotdot sequences * passed in and strips them off according to the rules in RFC 3986 section * 5.2.4. * * The function handles a query part ('?' + stuff) appended but it expects * that fragments ('#' + stuff) have already been cut off. * * RETURNS * * an allocated dedotdotified output string */ char *Curl_dedotdotify(const char *input) { size_t inlen = strlen(input); char *clone; size_t clen = inlen; /* the length of the cloned input */ char *out = malloc(inlen + 1); char *outptr; char *orgclone; char *queryp; if(!out) return NULL; /* out of memory */ *out = 0; /* zero terminates, for inputs like "./" */ /* get a cloned copy of the input */ clone = strdup(input); if(!clone) { free(out); return NULL; } orgclone = clone; outptr = out; if(!*clone) { /* zero length string, return that */ free(out); return clone; } /* * To handle query-parts properly, we must find it and remove it during the * dotdot-operation and then append it again at the end to the output * string. */ queryp = strchr(clone, '?'); if(queryp) *queryp = 0; do { /* A. If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, */ if(!strncmp("./", clone, 2)) { clone += 2; clen -= 2; } else if(!strncmp("../", clone, 3)) { clone += 3; clen -= 3; } /* B. if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, */ else if(!strncmp("/./", clone, 3)) { clone += 2; clen -= 2; } else if(!strcmp("/.", clone)) { clone[1]='/'; clone++; clen -= 1; } /* C. if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, */ else if(!strncmp("/../", clone, 4)) { clone += 3; clen -= 3; /* remove the last segment from the output buffer */ while(outptr > out) { outptr--; if(*outptr == '/') break; } *outptr = 0; /* zero-terminate where it stops */ } else if(!strcmp("/..", clone)) { clone[2]='/'; clone += 2; clen -= 2; /* remove the last segment from the output buffer */ while(outptr > out) { outptr--; if(*outptr == '/') break; } *outptr = 0; /* zero-terminate where it stops */ } /* D. if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, */ else if(!strcmp(".", clone) || !strcmp("..", clone)) { *clone = 0; *out = 0; } else { /* E. move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer. */ do { *outptr++ = *clone++; clen--; } while(*clone && (*clone != '/')); *outptr = 0; } } while(*clone); if(queryp) { size_t qlen; /* There was a query part, append that to the output. The 'clone' string may now have been altered so we copy from the original input string from the correct index. */ size_t oindex = queryp - orgclone; qlen = strlen(&input[oindex]); memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */ } free(orgclone); return out; } davix-0.8.0/deps/curl/lib/share.c0000644000000000000000000001425214121063461015246 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "share.h" #include "psl.h" #include "vtls/vtls.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" struct Curl_share * curl_share_init(void) { struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); if(share) { share->specifier |= (1<hostcache)) { free(share); return NULL; } } return share; } #undef curl_share_setopt CURLSHcode curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) { va_list param; int type; curl_lock_function lockfunc; curl_unlock_function unlockfunc; void *ptr; CURLSHcode res = CURLSHE_OK; if(share->dirty) /* don't allow setting options while one or more handles are already using this share */ return CURLSHE_IN_USE; va_start(param, option); switch(option) { case CURLSHOPT_SHARE: /* this is a type this share will share */ type = va_arg(param, int); share->specifier |= (1<cookies) { share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); if(!share->cookies) res = CURLSHE_NOMEM; } #else /* CURL_DISABLE_HTTP */ res = CURLSHE_NOT_BUILT_IN; #endif break; case CURL_LOCK_DATA_SSL_SESSION: #ifdef USE_SSL if(!share->sslsession) { share->max_ssl_sessions = 8; share->sslsession = calloc(share->max_ssl_sessions, sizeof(struct curl_ssl_session)); share->sessionage = 0; if(!share->sslsession) res = CURLSHE_NOMEM; } #else res = CURLSHE_NOT_BUILT_IN; #endif break; case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ if(Curl_conncache_init(&share->conn_cache, 103)) res = CURLSHE_NOMEM; break; case CURL_LOCK_DATA_PSL: #ifndef USE_LIBPSL res = CURLSHE_NOT_BUILT_IN; #endif break; default: res = CURLSHE_BAD_OPTION; } break; case CURLSHOPT_UNSHARE: /* this is a type this share will no longer share */ type = va_arg(param, int); share->specifier &= ~(1<cookies) { Curl_cookie_cleanup(share->cookies); share->cookies = NULL; } #else /* CURL_DISABLE_HTTP */ res = CURLSHE_NOT_BUILT_IN; #endif break; case CURL_LOCK_DATA_SSL_SESSION: #ifdef USE_SSL Curl_safefree(share->sslsession); #else res = CURLSHE_NOT_BUILT_IN; #endif break; case CURL_LOCK_DATA_CONNECT: break; default: res = CURLSHE_BAD_OPTION; break; } break; case CURLSHOPT_LOCKFUNC: lockfunc = va_arg(param, curl_lock_function); share->lockfunc = lockfunc; break; case CURLSHOPT_UNLOCKFUNC: unlockfunc = va_arg(param, curl_unlock_function); share->unlockfunc = unlockfunc; break; case CURLSHOPT_USERDATA: ptr = va_arg(param, void *); share->clientdata = ptr; break; default: res = CURLSHE_BAD_OPTION; break; } va_end(param); return res; } CURLSHcode curl_share_cleanup(struct Curl_share *share) { if(share == NULL) return CURLSHE_INVALID; if(share->lockfunc) share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE, share->clientdata); if(share->dirty) { if(share->unlockfunc) share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); return CURLSHE_IN_USE; } Curl_conncache_close_all_connections(&share->conn_cache); Curl_conncache_destroy(&share->conn_cache); Curl_hash_destroy(&share->hostcache); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) Curl_cookie_cleanup(share->cookies); #endif #ifdef USE_SSL if(share->sslsession) { size_t i; for(i = 0; i < share->max_ssl_sessions; i++) Curl_ssl_kill_session(&(share->sslsession[i])); free(share->sslsession); } #endif Curl_psl_destroy(&share->psl); if(share->unlockfunc) share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); free(share); return CURLSHE_OK; } CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type, curl_lock_access accesstype) { struct Curl_share *share = data->share; if(share == NULL) return CURLSHE_INVALID; if(share->specifier & (1<lockfunc) /* only call this if set! */ share->lockfunc(data, type, accesstype, share->clientdata); } /* else if we don't share this, pretend successful lock */ return CURLSHE_OK; } CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) { struct Curl_share *share = data->share; if(share == NULL) return CURLSHE_INVALID; if(share->specifier & (1<unlockfunc) /* only call this if set! */ share->unlockfunc (data, type, share->clientdata); } return CURLSHE_OK; } davix-0.8.0/deps/curl/lib/config-dos.h0000644000000000000000000001231414121063461016176 0ustar rootroot#ifndef HEADER_CURL_CONFIG_DOS_H #define HEADER_CURL_CONFIG_DOS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* lib/config-dos.h - Hand crafted config file for DOS */ /* ================================================================ */ #if defined(DJGPP) #define OS "MSDOS/djgpp" #elif defined(__HIGHC__) #define OS "MSDOS/HighC" #elif defined(__WATCOMC__) #define OS "MSDOS/Watcom" #else #define OS "MSDOS/?" #endif #define PACKAGE "curl" #define HAVE_ARPA_INET_H 1 #define HAVE_ASSERT_H 1 #define HAVE_ERRNO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_FREEADDRINFO 1 #define HAVE_GETADDRINFO 1 #define HAVE_GETNAMEINFO 1 #define HAVE_GETPROTOBYNAME 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_IO_H 1 #define HAVE_IOCTL 1 #define HAVE_IOCTL_FIONBIO 1 #define HAVE_IOCTLSOCKET 1 #define HAVE_IOCTLSOCKET_FIONBIO 1 #define HAVE_LOCALE_H 1 #define HAVE_LONGLONG 1 #define HAVE_MEMORY_H 1 #define HAVE_NETDB_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_NETINET_TCP_H 1 #define HAVE_NET_IF_H 1 #define HAVE_PROCESS_H 1 #define HAVE_RECV 1 #define HAVE_RECVFROM 1 #define HAVE_SELECT 1 #define HAVE_SEND 1 #define HAVE_SETJMP_H 1 #define HAVE_SETLOCALE 1 #define HAVE_SETMODE 1 #define HAVE_SIGNAL 1 #define HAVE_SOCKET 1 #define HAVE_STRDUP 1 #define HAVE_STRICMP 1 #define HAVE_STRTOLL 1 #define HAVE_STRUCT_TIMEVAL 1 #define HAVE_STRUCT_IN6_ADDR 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_TIME_H 1 #define HAVE_UNISTD_H 1 #define NEED_MALLOC_H 1 #define RETSIGTYPE void #define SIZEOF_INT 4 #define SIZEOF_LONG 4 #define SIZEOF_LONG_DOUBLE 16 #define SIZEOF_SHORT 2 #define SIZEOF_SIZE_T 4 #define SIZEOF_CURL_OFF_T 4 #define STDC_HEADERS 1 #define TIME_WITH_SYS_TIME 1 /* Qualifiers for send(), recv(), recvfrom() and getnameinfo(). */ #define SEND_TYPE_ARG1 int #define SEND_QUAL_ARG2 const #define SEND_TYPE_ARG2 void * #define SEND_TYPE_ARG3 int #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV int #define RECV_TYPE_ARG1 int #define RECV_TYPE_ARG2 void * #define RECV_TYPE_ARG3 int #define RECV_TYPE_ARG4 int #define RECV_TYPE_RETV int #define RECVFROM_TYPE_ARG1 int #define RECVFROM_TYPE_ARG2 void #define RECVFROM_TYPE_ARG3 int #define RECVFROM_TYPE_ARG4 int #define RECVFROM_TYPE_ARG5 struct sockaddr #define RECVFROM_TYPE_ARG6 int #define RECVFROM_TYPE_RETV int #define RECVFROM_TYPE_ARG2_IS_VOID 1 #define GETNAMEINFO_QUAL_ARG1 const #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * #define GETNAMEINFO_TYPE_ARG2 int #define GETNAMEINFO_TYPE_ARG46 int #define GETNAMEINFO_TYPE_ARG7 int #define BSD /* CURLDEBUG definition enables memory tracking */ /* #define CURLDEBUG */ /* USE_ZLIB on cmd-line */ #ifdef USE_ZLIB #define HAVE_ZLIB_H 1 #define HAVE_LIBZ 1 #endif /* USE_OPENSSL on cmd-line */ #ifdef USE_OPENSSL #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 #define OPENSSL_NO_KRB5 1 #endif /* to disable LDAP */ #define CURL_DISABLE_LDAP 1 #define in_addr_t u_long #if defined(__HIGHC__) || \ (defined(__GNUC__) && (__GNUC__ < 4)) #define ssize_t int #endif #define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE") /* Target HAVE_x section */ #if defined(DJGPP) #define HAVE_BASENAME 1 #define HAVE_STRCASECMP 1 #define HAVE_SIGACTION 1 #define HAVE_SIGSETJMP 1 #define HAVE_SYS_TIME_H 1 #define HAVE_TERMIOS_H 1 #define HAVE_VARIADIC_MACROS_GCC 1 #elif defined(__WATCOMC__) #define HAVE_STRCASECMP 1 #elif defined(__HIGHC__) #define HAVE_SYS_TIME_H 1 #define strerror(e) strerror_s_((e)) #endif #ifdef MSDOS /* Watt-32 */ #define HAVE_CLOSE_S 1 #endif #undef word #undef byte #endif /* HEADER_CURL_CONFIG_DOS_H */ davix-0.8.0/deps/curl/lib/select.c0000644000000000000000000003302414121063461015421 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_SYS_SELECT_H #include #endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) #error "We can't compile without select() or poll() support." #endif #if defined(__BEOS__) && !defined(__HAIKU__) /* BeOS has FD_SET defined in socket.h */ #include #endif #ifdef MSDOS #include /* delay() */ #endif #ifdef __VXWORKS__ #include /* bzero() in FD_SET */ #endif #include #include "urldata.h" #include "connect.h" #include "select.h" #include "warnless.h" /* Convenience local macros */ #define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv) /* * Internal function used for waiting a specific amount of ms * in Curl_socket_check() and Curl_poll() when no file descriptor * is provided to wait on, just being used to delay execution. * WinSock select() and poll() timeout mechanisms need a valid * socket descriptor in a not null file descriptor set to work. * Waiting indefinitely with this function is not allowed, a * zero or negative timeout value will return immediately. * Timeout resolution, accuracy, as well as maximum supported * value is system dependent, neither factor is a citical issue * for the intended use of this function in the library. * * Return values: * -1 = system call error, invalid timeout value, or interrupted * 0 = specified timeout has elapsed */ int Curl_wait_ms(int timeout_ms) { int r = 0; if(!timeout_ms) return 0; if(timeout_ms < 0) { SET_SOCKERRNO(EINVAL); return -1; } #if defined(MSDOS) delay(timeout_ms); #elif defined(USE_WINSOCK) Sleep(timeout_ms); #else #if defined(HAVE_POLL_FINE) r = poll(NULL, 0, timeout_ms); #else { struct timeval pending_tv; pending_tv.tv_sec = timeout_ms / 1000; pending_tv.tv_usec = (timeout_ms % 1000) * 1000; r = select(0, NULL, NULL, NULL, &pending_tv); } #endif /* HAVE_POLL_FINE */ #endif /* USE_WINSOCK */ if(r) r = -1; return r; } /* * Wait for read or write events on a set of file descriptors. It uses poll() * when a fine poll() is available, in order to avoid limits with FD_SETSIZE, * otherwise select() is used. An error is returned if select() is being used * and a file descriptor is too large for FD_SETSIZE. * * A negative timeout value makes this function wait indefinitely, * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: * -1 = system call error or fd >= FD_SETSIZE * 0 = timeout * [bitmask] = action as described below * * CURL_CSELECT_IN - first socket is readable * CURL_CSELECT_IN2 - second socket is readable * CURL_CSELECT_OUT - write socket is writable * CURL_CSELECT_ERR - an error condition occurred */ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t readfd1, curl_socket_t writefd, /* socket to write to */ time_t timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE struct pollfd pfd[3]; int num; #else struct timeval pending_tv; struct timeval *ptimeout; fd_set fds_read; fd_set fds_write; fd_set fds_err; curl_socket_t maxfd; #endif int pending_ms = 0; int r; int ret; #if SIZEOF_TIME_T != SIZEOF_INT /* wrap-around precaution */ if(timeout_ms >= INT_MAX) timeout_ms = INT_MAX; #endif if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ r = Curl_wait_ms((int)timeout_ms); return r; } /* Avoid initial timestamp, avoid Curl_now() call, when elapsed time in this function does not need to be measured. This happens when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ if(timeout_ms > 0) { pending_ms = (int)timeout_ms; } #ifdef HAVE_POLL_FINE num = 0; if(readfd0 != CURL_SOCKET_BAD) { pfd[num].fd = readfd0; pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; pfd[num].revents = 0; num++; } if(readfd1 != CURL_SOCKET_BAD) { pfd[num].fd = readfd1; pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; pfd[num].revents = 0; num++; } if(writefd != CURL_SOCKET_BAD) { pfd[num].fd = writefd; pfd[num].events = POLLWRNORM|POLLOUT; pfd[num].revents = 0; num++; } if(timeout_ms < 0) pending_ms = -1; else if(!timeout_ms) pending_ms = 0; r = poll(pfd, num, pending_ms); if(r < 0) return -1; if(r == 0) return 0; ret = 0; num = 0; if(readfd0 != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) ret |= CURL_CSELECT_IN; if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) ret |= CURL_CSELECT_ERR; num++; } if(readfd1 != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) ret |= CURL_CSELECT_IN2; if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) ret |= CURL_CSELECT_ERR; num++; } if(writefd != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLWRNORM|POLLOUT)) ret |= CURL_CSELECT_OUT; if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL)) ret |= CURL_CSELECT_ERR; } return ret; #else /* HAVE_POLL_FINE */ FD_ZERO(&fds_err); maxfd = (curl_socket_t)-1; FD_ZERO(&fds_read); if(readfd0 != CURL_SOCKET_BAD) { VERIFY_SOCK(readfd0); FD_SET(readfd0, &fds_read); FD_SET(readfd0, &fds_err); maxfd = readfd0; } if(readfd1 != CURL_SOCKET_BAD) { VERIFY_SOCK(readfd1); FD_SET(readfd1, &fds_read); FD_SET(readfd1, &fds_err); if(readfd1 > maxfd) maxfd = readfd1; } FD_ZERO(&fds_write); if(writefd != CURL_SOCKET_BAD) { VERIFY_SOCK(writefd); FD_SET(writefd, &fds_write); FD_SET(writefd, &fds_err); if(writefd > maxfd) maxfd = writefd; } ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; if(timeout_ms > 0) { pending_tv.tv_sec = pending_ms / 1000; pending_tv.tv_usec = (pending_ms % 1000) * 1000; } else if(!timeout_ms) { pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } /* WinSock select() must not be called with an fd_set that contains zero fd flags, or it will return WSAEINVAL. But, it also can't be called with no fd_sets at all! From the documentation: Any two of the parameters, readfds, writefds, or exceptfds, can be given as null. At least one must be non-null, and any non-null descriptor set must contain at least one handle to a socket. We know that we have at least one bit set in at least two fd_sets in this case, but we may have no bits set in either fds_read or fd_write, so check for that and handle it. Luckily, with WinSock, we can _also_ ask how many bits are set on an fd_set. It is unclear why WinSock doesn't just handle this for us instead of calling this an error. Note also that WinSock ignores the first argument, so we don't worry about the fact that maxfd is computed incorrectly with WinSock (since curl_socket_t is unsigned in such cases and thus -1 is the largest value). */ #ifdef USE_WINSOCK r = select((int)maxfd + 1, fds_read.fd_count ? &fds_read : NULL, fds_write.fd_count ? &fds_write : NULL, &fds_err, ptimeout); #else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); #endif if(r < 0) return -1; if(r == 0) return 0; ret = 0; if(readfd0 != CURL_SOCKET_BAD) { if(FD_ISSET(readfd0, &fds_read)) ret |= CURL_CSELECT_IN; if(FD_ISSET(readfd0, &fds_err)) ret |= CURL_CSELECT_ERR; } if(readfd1 != CURL_SOCKET_BAD) { if(FD_ISSET(readfd1, &fds_read)) ret |= CURL_CSELECT_IN2; if(FD_ISSET(readfd1, &fds_err)) ret |= CURL_CSELECT_ERR; } if(writefd != CURL_SOCKET_BAD) { if(FD_ISSET(writefd, &fds_write)) ret |= CURL_CSELECT_OUT; if(FD_ISSET(writefd, &fds_err)) ret |= CURL_CSELECT_ERR; } return ret; #endif /* HAVE_POLL_FINE */ } /* * This is a wrapper around poll(). If poll() does not exist, then * select() is used instead. An error is returned if select() is * being used and a file descriptor is too large for FD_SETSIZE. * A negative timeout value makes this function wait indefinitely, * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: * -1 = system call error or fd >= FD_SETSIZE * 0 = timeout * N = number of structures with non zero revent fields */ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) { #ifndef HAVE_POLL_FINE struct timeval pending_tv; struct timeval *ptimeout; fd_set fds_read; fd_set fds_write; fd_set fds_err; curl_socket_t maxfd; #endif bool fds_none = TRUE; unsigned int i; int pending_ms = 0; int r; if(ufds) { for(i = 0; i < nfds; i++) { if(ufds[i].fd != CURL_SOCKET_BAD) { fds_none = FALSE; break; } } } if(fds_none) { r = Curl_wait_ms(timeout_ms); return r; } /* Avoid initial timestamp, avoid Curl_now() call, when elapsed time in this function does not need to be measured. This happens when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ if(timeout_ms > 0) { pending_ms = timeout_ms; } #ifdef HAVE_POLL_FINE if(timeout_ms < 0) pending_ms = -1; else if(!timeout_ms) pending_ms = 0; r = poll(ufds, nfds, pending_ms); if(r < 0) return -1; if(r == 0) return 0; for(i = 0; i < nfds; i++) { if(ufds[i].fd == CURL_SOCKET_BAD) continue; if(ufds[i].revents & POLLHUP) ufds[i].revents |= POLLIN; if(ufds[i].revents & POLLERR) ufds[i].revents |= (POLLIN|POLLOUT); } #else /* HAVE_POLL_FINE */ FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_err); maxfd = (curl_socket_t)-1; for(i = 0; i < nfds; i++) { ufds[i].revents = 0; if(ufds[i].fd == CURL_SOCKET_BAD) continue; VERIFY_SOCK(ufds[i].fd); if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI| POLLRDNORM|POLLWRNORM|POLLRDBAND)) { if(ufds[i].fd > maxfd) maxfd = ufds[i].fd; if(ufds[i].events & (POLLRDNORM|POLLIN)) FD_SET(ufds[i].fd, &fds_read); if(ufds[i].events & (POLLWRNORM|POLLOUT)) FD_SET(ufds[i].fd, &fds_write); if(ufds[i].events & (POLLRDBAND|POLLPRI)) FD_SET(ufds[i].fd, &fds_err); } } #ifdef USE_WINSOCK /* WinSock select() can't handle zero events. See the comment about this in Curl_check_socket(). */ if(fds_read.fd_count == 0 && fds_write.fd_count == 0 && fds_err.fd_count == 0) { r = Curl_wait_ms(timeout_ms); return r; } #endif ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; if(timeout_ms > 0) { pending_tv.tv_sec = pending_ms / 1000; pending_tv.tv_usec = (pending_ms % 1000) * 1000; } else if(!timeout_ms) { pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } #ifdef USE_WINSOCK r = select((int)maxfd + 1, /* WinSock select() can't handle fd_sets with zero bits set, so don't give it such arguments. See the comment about this in Curl_check_socket(). */ fds_read.fd_count ? &fds_read : NULL, fds_write.fd_count ? &fds_write : NULL, fds_err.fd_count ? &fds_err : NULL, ptimeout); #else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); #endif if(r < 0) return -1; if(r == 0) return 0; r = 0; for(i = 0; i < nfds; i++) { ufds[i].revents = 0; if(ufds[i].fd == CURL_SOCKET_BAD) continue; if(FD_ISSET(ufds[i].fd, &fds_read)) ufds[i].revents |= POLLIN; if(FD_ISSET(ufds[i].fd, &fds_write)) ufds[i].revents |= POLLOUT; if(FD_ISSET(ufds[i].fd, &fds_err)) ufds[i].revents |= POLLPRI; if(ufds[i].revents != 0) r++; } #endif /* HAVE_POLL_FINE */ return r; } #ifdef TPF /* * This is a replacement for select() on the TPF platform. * It is used whenever libcurl calls select(). * The call below to tpf_process_signals() is required because * TPF's select calls are not signal interruptible. * * Return values are the same as select's. */ int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes, fd_set *excepts, struct timeval *tv) { int rc; rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); tpf_process_signals(); return rc; } #endif /* TPF */ davix-0.8.0/deps/curl/lib/connect.c0000644000000000000000000013716514121063461015606 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H #include /* may need it */ #endif #ifdef HAVE_SYS_UN_H #include /* for sockaddr_un */ #endif #ifdef HAVE_LINUX_TCP_H #include #elif defined(HAVE_NETINET_TCP_H) #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include #endif #ifdef NETWARE #undef in_addr_t #define in_addr_t unsigned long #endif #ifdef __VMS #include #include #endif #include "urldata.h" #include "sendf.h" #include "if2ip.h" #include "strerror.h" #include "connect.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ #include "multiif.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "inet_ntop.h" #include "inet_pton.h" #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */ #include "progress.h" #include "warnless.h" #include "conncache.h" #include "multihandle.h" #include "system_win32.h" #include "quic.h" #include "socks.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifdef __SYMBIAN32__ /* This isn't actually supported under Symbian OS */ #undef SO_NOSIGPIPE #endif static bool verifyconnect(curl_socket_t sockfd, int *error); #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H) /* DragonFlyBSD and Windows use millisecond units */ #define KEEPALIVE_FACTOR(x) (x *= 1000) #else #define KEEPALIVE_FACTOR(x) #endif #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS) #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) struct tcp_keepalive { u_long onoff; u_long keepalivetime; u_long keepaliveinterval; }; #endif static void tcpkeepalive(struct Curl_easy *data, curl_socket_t sockfd) { int optval = data->set.tcp_keepalive?1:0; /* only set IDLE and INTVL if setting KEEPALIVE is successful */ if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof(optval)) < 0) { infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd); } else { #if defined(SIO_KEEPALIVE_VALS) struct tcp_keepalive vals; DWORD dummy; vals.onoff = 1; optval = curlx_sltosi(data->set.tcp_keepidle); KEEPALIVE_FACTOR(optval); vals.keepalivetime = optval; optval = curlx_sltosi(data->set.tcp_keepintvl); KEEPALIVE_FACTOR(optval); vals.keepaliveinterval = optval; if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), NULL, 0, &dummy, NULL, NULL) != 0) { infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n", (int)sockfd, WSAGetLastError()); } #else #ifdef TCP_KEEPIDLE optval = curlx_sltosi(data->set.tcp_keepidle); KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&optval, sizeof(optval)) < 0) { infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd); } #endif #ifdef TCP_KEEPINTVL optval = curlx_sltosi(data->set.tcp_keepintvl); KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&optval, sizeof(optval)) < 0) { infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd); } #endif #ifdef TCP_KEEPALIVE /* Mac OS X style */ optval = curlx_sltosi(data->set.tcp_keepidle); KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, (void *)&optval, sizeof(optval)) < 0) { infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd); } #endif #endif } } static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, /* start connecting to this */ int sockindex); /* 0 or 1 among the temp ones */ /* * Curl_timeleft() returns the amount of milliseconds left allowed for the * transfer/connection. If the value is negative, the timeout time has already * elapsed. * * The start time is stored in progress.t_startsingle - as set with * Curl_pgrsTime(..., TIMER_STARTSINGLE); * * If 'nowp' is non-NULL, it points to the current time. * 'duringconnect' is FALSE if not during a connect, as then of course the * connect timeout is not taken into account! * * @unittest: 1303 */ timediff_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect) { int timeout_set = 0; timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; struct curltime now; /* if a timeout is set, use the most restrictive one */ if(data->set.timeout > 0) timeout_set |= 1; if(duringconnect && (data->set.connecttimeout > 0)) timeout_set |= 2; switch(timeout_set) { case 1: timeout_ms = data->set.timeout; break; case 2: timeout_ms = data->set.connecttimeout; break; case 3: if(data->set.timeout < data->set.connecttimeout) timeout_ms = data->set.timeout; else timeout_ms = data->set.connecttimeout; break; default: /* use the default */ if(!duringconnect) /* if we're not during connect, there's no default timeout so if we're at zero we better just return zero and not make it a negative number by the math below */ return 0; break; } if(!nowp) { now = Curl_now(); nowp = &now; } /* subtract elapsed time */ if(duringconnect) /* since this most recent connect started */ timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle); else /* since the entire operation started */ timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ return -1; return timeout_ms; } static CURLcode bindlocal(struct connectdata *conn, curl_socket_t sockfd, int af, unsigned int scope) { struct Curl_easy *data = conn->data; struct Curl_sockaddr_storage sa; struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */ struct sockaddr_in *si4 = (struct sockaddr_in *)&sa; #ifdef ENABLE_IPV6 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa; #endif struct Curl_dns_entry *h = NULL; unsigned short port = data->set.localport; /* use this port number, 0 for "random" */ /* how many port numbers to try to bind to, increasing one at a time */ int portnum = data->set.localportrange; const char *dev = data->set.str[STRING_DEVICE]; int error; /************************************************************* * Select device to bind socket to *************************************************************/ if(!dev && !port) /* no local kind of binding was requested */ return CURLE_OK; memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); if(dev && (strlen(dev)<255) ) { char myhost[256] = ""; int done = 0; /* -1 for error, 1 for address found */ bool is_interface = FALSE; bool is_host = FALSE; static const char *if_prefix = "if!"; static const char *host_prefix = "host!"; if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) { dev += strlen(if_prefix); is_interface = TRUE; } else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) { dev += strlen(host_prefix); is_host = TRUE; } /* interface */ if(!is_host) { #ifdef SO_BINDTODEVICE /* I am not sure any other OSs than Linux that provide this feature, * and at the least I cannot test. --Ben * * This feature allows one to tightly bind the local socket to a * particular interface. This will force even requests to other * local interfaces to go out the external interface. * * * Only bind to the interface when specified as interface, not just * as a hostname or ip address. * * interface might be a VRF, eg: vrf-blue, which means it cannot be * converted to an IP address and would fail Curl_if2ip. Simply try * to use it straight away. */ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, dev, (curl_socklen_t)strlen(dev) + 1) == 0) { /* This is typically "errno 1, error: Operation not permitted" if * you're not running as root or another suitable privileged * user. * If it succeeds it means the parameter was a valid interface and * not an IP address. Return immediately. */ return CURLE_OK; } #endif switch(Curl_if2ip(af, scope, conn->scope_id, dev, myhost, sizeof(myhost))) { case IF2IP_NOT_FOUND: if(is_interface) { /* Do not fall back to treating it as a host name */ failf(data, "Couldn't bind to interface '%s'", dev); return CURLE_INTERFACE_FAILED; } break; case IF2IP_AF_NOT_SUPPORTED: /* Signal the caller to try another address family if available */ return CURLE_UNSUPPORTED_PROTOCOL; case IF2IP_FOUND: is_interface = TRUE; /* * We now have the numerical IP address in the 'myhost' buffer */ infof(data, "Local Interface %s is ip %s using address family %i\n", dev, myhost, af); done = 1; break; } } if(!is_interface) { /* * This was not an interface, resolve the name as a host name * or IP number * * Temporarily force name resolution to use only the address type * of the connection. The resolve functions should really be changed * to take a type parameter instead. */ long ipver = conn->ip_version; int rc; if(af == AF_INET) conn->ip_version = CURL_IPRESOLVE_V4; #ifdef ENABLE_IPV6 else if(af == AF_INET6) conn->ip_version = CURL_IPRESOLVE_V6; #endif rc = Curl_resolv(conn, dev, 0, FALSE, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_resolver_wait_resolv(conn, &h); conn->ip_version = ipver; if(h) { /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ Curl_printable_address(h->addr, myhost, sizeof(myhost)); infof(data, "Name '%s' family %i resolved to '%s' family %i\n", dev, af, myhost, h->addr->ai_family); Curl_resolv_unlock(data, h); if(af != h->addr->ai_family) { /* bad IP version combo, signal the caller to try another address family if available */ return CURLE_UNSUPPORTED_PROTOCOL; } done = 1; } else { /* * provided dev was no interface (or interfaces are not supported * e.g. solaris) no ip address and no domain we fail here */ done = -1; } } if(done > 0) { #ifdef ENABLE_IPV6 /* IPv6 address */ if(af == AF_INET6) { #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID char *scope_ptr = strchr(myhost, '%'); if(scope_ptr) *(scope_ptr++) = 0; #endif if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { si6->sin6_family = AF_INET6; si6->sin6_port = htons(port); #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID if(scope_ptr) /* The "myhost" string either comes from Curl_if2ip or from Curl_printable_address. The latter returns only numeric scope IDs and the former returns none at all. So the scope ID, if present, is known to be numeric */ si6->sin6_scope_id = atoi(scope_ptr); #endif } sizeof_sa = sizeof(struct sockaddr_in6); } else #endif /* IPv4 address */ if((af == AF_INET) && (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) { si4->sin_family = AF_INET; si4->sin_port = htons(port); sizeof_sa = sizeof(struct sockaddr_in); } } if(done < 1) { /* errorbuf is set false so failf will overwrite any message already in the error buffer, so the user receives this error message instead of a generic resolve error. */ data->state.errorbuf = FALSE; failf(data, "Couldn't bind to '%s'", dev); return CURLE_INTERFACE_FAILED; } } else { /* no device was given, prepare sa to match af's needs */ #ifdef ENABLE_IPV6 if(af == AF_INET6) { si6->sin6_family = AF_INET6; si6->sin6_port = htons(port); sizeof_sa = sizeof(struct sockaddr_in6); } else #endif if(af == AF_INET) { si4->sin_family = AF_INET; si4->sin_port = htons(port); sizeof_sa = sizeof(struct sockaddr_in); } } for(;;) { if(bind(sockfd, sock, sizeof_sa) >= 0) { /* we succeeded to bind */ struct Curl_sockaddr_storage add; curl_socklen_t size = sizeof(add); memset(&add, 0, sizeof(struct Curl_sockaddr_storage)); if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) { char buffer[STRERROR_LEN]; data->state.os_errno = error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", error, Curl_strerror(error, buffer, sizeof(buffer))); return CURLE_INTERFACE_FAILED; } infof(data, "Local port: %hu\n", port); conn->bits.bound = TRUE; return CURLE_OK; } if(--portnum > 0) { infof(data, "Bind to local port %hu failed, trying next\n", port); port++; /* try next port */ /* We re-use/clobber the port variable here below */ if(sock->sa_family == AF_INET) si4->sin_port = ntohs(port); #ifdef ENABLE_IPV6 else si6->sin6_port = ntohs(port); #endif } else break; } { char buffer[STRERROR_LEN]; data->state.os_errno = error = SOCKERRNO; failf(data, "bind failed with errno %d: %s", error, Curl_strerror(error, buffer, sizeof(buffer))); } return CURLE_INTERFACE_FAILED; } /* * verifyconnect() returns TRUE if the connect really has happened. */ static bool verifyconnect(curl_socket_t sockfd, int *error) { bool rc = TRUE; #ifdef SO_ERROR int err = 0; curl_socklen_t errSize = sizeof(err); #ifdef WIN32 /* * In October 2003 we effectively nullified this function on Windows due to * problems with it using all CPU in multi-threaded cases. * * In May 2004, we bring it back to offer more info back on connect failures. * Gisle Vanem could reproduce the former problems with this function, but * could avoid them by adding this SleepEx() call below: * * "I don't have Rational Quantify, but the hint from his post was * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe * just Sleep(0) would be enough?) would release whatever * mutex/critical-section the ntdll call is waiting on. * * Someone got to verify this on Win-NT 4.0, 2000." */ #ifdef _WIN32_WCE Sleep(0); #else SleepEx(0, FALSE); #endif #endif if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) err = SOCKERRNO; #ifdef _WIN32_WCE /* Old WinCE versions don't support SO_ERROR */ if(WSAENOPROTOOPT == err) { SET_SOCKERRNO(0); err = 0; } #endif #if defined(EBADIOCTL) && defined(__minix) /* Minix 3.1.x doesn't support getsockopt on UDP sockets */ if(EBADIOCTL == err) { SET_SOCKERRNO(0); err = 0; } #endif if((0 == err) || (EISCONN == err)) /* we are connected, awesome! */ rc = TRUE; else /* This wasn't a successful connect */ rc = FALSE; if(error) *error = err; #else (void)sockfd; if(error) *error = SOCKERRNO; #endif return rc; } /* Used within the multi interface. Try next IP address, return TRUE if no more address exists or error */ static CURLcode trynextip(struct connectdata *conn, int sockindex, int tempindex) { const int other = tempindex ^ 1; CURLcode result = CURLE_COULDNT_CONNECT; /* First clean up after the failed socket. Don't close it yet to ensure that the next IP's socket gets a different file descriptor, which can prevent bugs when the curl_multi_socket_action interface is used with certain select() replacements such as kqueue. */ curl_socket_t fd_to_close = conn->tempsock[tempindex]; conn->tempsock[tempindex] = CURL_SOCKET_BAD; if(sockindex == FIRSTSOCKET) { Curl_addrinfo *ai = NULL; int family = AF_UNSPEC; if(conn->tempaddr[tempindex]) { /* find next address in the same protocol family */ family = conn->tempaddr[tempindex]->ai_family; ai = conn->tempaddr[tempindex]->ai_next; } #ifdef ENABLE_IPV6 else if(conn->tempaddr[0]) { /* happy eyeballs - try the other protocol family */ int firstfamily = conn->tempaddr[0]->ai_family; family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET; ai = conn->tempaddr[0]->ai_next; } #endif while(ai) { if(conn->tempaddr[other]) { /* we can safely skip addresses of the other protocol family */ while(ai && ai->ai_family != family) ai = ai->ai_next; } if(ai) { result = singleipconnect(conn, ai, tempindex); if(result == CURLE_COULDNT_CONNECT) { ai = ai->ai_next; continue; } conn->tempaddr[tempindex] = ai; } break; } } if(fd_to_close != CURL_SOCKET_BAD) Curl_closesocket(conn, fd_to_close); return result; } /* Copies connection info into the session handle to make it available when the session handle is no longer associated with a connection. */ void Curl_persistconninfo(struct connectdata *conn) { memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN); memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN); conn->data->info.conn_scheme = conn->handler->scheme; conn->data->info.conn_protocol = conn->handler->protocol; conn->data->info.conn_primary_port = conn->primary_port; conn->data->info.conn_local_port = conn->local_port; } /* retrieves ip address and port from a sockaddr structure. note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, char *addr, long *port) { struct sockaddr_in *si = NULL; #ifdef ENABLE_IPV6 struct sockaddr_in6 *si6 = NULL; #endif #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) struct sockaddr_un *su = NULL; #else (void)salen; #endif switch(sa->sa_family) { case AF_INET: si = (struct sockaddr_in *)(void *) sa; if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { unsigned short us_port = ntohs(si->sin_port); *port = us_port; return TRUE; } break; #ifdef ENABLE_IPV6 case AF_INET6: si6 = (struct sockaddr_in6 *)(void *) sa; if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) { unsigned short us_port = ntohs(si6->sin6_port); *port = us_port; return TRUE; } break; #endif #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) case AF_UNIX: if(salen > (curl_socklen_t)sizeof(sa_family_t)) { su = (struct sockaddr_un*)sa; msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); } else addr[0] = 0; /* socket with no name */ *port = 0; return TRUE; #endif default: break; } addr[0] = '\0'; *port = 0; errno = EAFNOSUPPORT; return FALSE; } /* retrieves the start/end point information of a socket of an established connection */ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) { if(conn->transport != TRNSPRT_TCP) /* there's no TCP connection! */ return; #if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME) if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { struct Curl_easy *data = conn->data; char buffer[STRERROR_LEN]; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; curl_socklen_t plen; curl_socklen_t slen; #ifdef HAVE_GETPEERNAME plen = sizeof(struct Curl_sockaddr_storage); if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) { int error = SOCKERRNO; failf(data, "getpeername() failed with errno %d: %s", error, Curl_strerror(error, buffer, sizeof(buffer))); return; } #endif #ifdef HAVE_GETSOCKNAME slen = sizeof(struct Curl_sockaddr_storage); memset(&ssloc, 0, sizeof(ssloc)); if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) { int error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", error, Curl_strerror(error, buffer, sizeof(buffer))); return; } #endif #ifdef HAVE_GETPEERNAME if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, conn->primary_ip, &conn->primary_port)) { failf(data, "ssrem inet_ntop() failed with errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); return; } memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); #endif #ifdef HAVE_GETSOCKNAME if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, conn->local_ip, &conn->local_port)) { failf(data, "ssloc inet_ntop() failed with errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); return; } #endif } #else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */ (void)sockfd; /* unused */ #endif /* persist connection info in session handle */ Curl_persistconninfo(conn); } /* After a TCP connection to the proxy has been verified, this function does the next magic steps. If 'done' isn't set TRUE, it is not done yet and must be called again. Note: this function's sub-functions call failf() */ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex, bool *done) { CURLcode result = CURLE_OK; if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ const char * const host = conn->bits.httpproxy ? conn->http_proxy.host.name : conn->bits.conn_to_host ? conn->conn_to_host.name : sockindex == SECONDARYSOCKET ? conn->secondaryhostname : conn->host.name; const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : sockindex == SECONDARYSOCKET ? conn->secondary_port : conn->bits.conn_to_port ? conn->conn_to_port : conn->remote_port; switch(conn->socks_proxy.proxytype) { case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd, host, port, sockindex, conn, done); break; case CURLPROXY_SOCKS4: case CURLPROXY_SOCKS4A: result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex, conn, done); break; default: failf(conn->data, "unknown proxytype option given"); result = CURLE_COULDNT_CONNECT; } /* switch proxytype */ #else (void)sockindex; #endif /* CURL_DISABLE_PROXY */ } else *done = TRUE; /* no SOCKS proxy, so consider us connected */ return result; } /* * post_SOCKS() is called after a successful connect to the peer, which * *could* be a SOCKS proxy */ static void post_SOCKS(struct connectdata *conn, int sockindex, bool *connected) { conn->bits.tcpconnect[sockindex] = TRUE; *connected = TRUE; if(sockindex == FIRSTSOCKET) Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */ Curl_updateconninfo(conn, conn->sock[sockindex]); Curl_verboseconnect(conn); } /* * Curl_is_connected() checks if the socket has connected. */ CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; timediff_t allow; int error = 0; struct curltime now; int rc; int i; DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET); *connected = FALSE; /* a very negative world view is best */ if(conn->bits.tcpconnect[sockindex]) { /* we are connected already! */ *connected = TRUE; return CURLE_OK; } now = Curl_now(); /* figure out how long time we have left to connect */ allow = Curl_timeleft(data, &now, TRUE); if(allow < 0) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } if(SOCKS_STATE(conn->cnnct.state)) { /* still doing SOCKS */ result = connect_SOCKS(conn, sockindex, connected); if(!result && *connected) post_SOCKS(conn, sockindex, connected); return result; } for(i = 0; i<2; i++) { const int other = i ^ 1; if(conn->tempsock[i] == CURL_SOCKET_BAD) continue; #ifdef ENABLE_QUIC if(conn->transport == TRNSPRT_QUIC) { result = Curl_quic_is_connected(conn, i, connected); if(result) { error = SOCKERRNO; goto error; } if(*connected) { /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; connkeep(conn, "HTTP/3 default"); } return result; } #endif #ifdef mpeix /* Call this function once now, and ignore the results. We do this to "clear" the error state on the socket so that we can later read it reliably. This is reported necessary on the MPE/iX operating system. */ (void)verifyconnect(conn->tempsock[i], NULL); #endif /* check socket for connect */ rc = SOCKET_WRITABLE(conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ error = 0; if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %" CURL_FORMAT_TIMEDIFF_T "ms connect time, move on!\n", conn->timeoutms_per_addr); error = ETIMEDOUT; } /* should we try another protocol family? */ if(i == 0 && conn->tempaddr[1] == NULL && (Curl_timediff(now, conn->connecttime) >= data->set.happy_eyeballs_timeout)) { trynextip(conn, sockindex, 1); } } else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) { if(verifyconnect(conn->tempsock[i], &error)) { /* we are connected with TCP, awesome! */ /* use this socket from now on */ conn->sock[sockindex] = conn->tempsock[i]; conn->ip_addr = conn->tempaddr[i]; conn->tempsock[i] = CURL_SOCKET_BAD; #ifdef ENABLE_IPV6 conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE; #endif /* close the other socket, if open */ if(conn->tempsock[other] != CURL_SOCKET_BAD) { Curl_closesocket(conn, conn->tempsock[other]); conn->tempsock[other] = CURL_SOCKET_BAD; } /* see if we need to kick off any SOCKS proxy magic once we connected */ result = connect_SOCKS(conn, sockindex, connected); if(result || !*connected) return result; post_SOCKS(conn, sockindex, connected); return CURLE_OK; } infof(data, "Connection failed\n"); } else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); #ifdef ENABLE_QUIC error: #endif /* * The connection failed here, we should attempt to connect to the "next * address" for the given host. But first remember the latest error. */ if(error) { data->state.os_errno = error; SET_SOCKERRNO(error); if(conn->tempaddr[i]) { CURLcode status; #ifndef CURL_DISABLE_VERBOSE_STRINGS char ipaddress[MAX_IPADR_LEN]; char buffer[STRERROR_LEN]; Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN); #endif infof(data, "connect to %s port %ld failed: %s\n", ipaddress, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ? allow : allow / 2; status = trynextip(conn, sockindex, i); if((status != CURLE_COULDNT_CONNECT) || conn->tempsock[other] == CURL_SOCKET_BAD) /* the last attempt failed and no other sockets remain open */ result = status; } } } if(result) { /* no more addresses to try */ const char *hostname; char buffer[STRERROR_LEN]; /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ if(conn->tempaddr[1] == NULL) { result = trynextip(conn, sockindex, 1); if(!result) return result; } if(conn->bits.socksproxy) hostname = conn->socks_proxy.host.name; else if(conn->bits.httpproxy) hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; failf(data, "Failed to connect to %s port %ld: %s", hostname, conn->port, Curl_strerror(error, buffer, sizeof(buffer))); #ifdef WSAETIMEDOUT if(WSAETIMEDOUT == data->state.os_errno) result = CURLE_OPERATION_TIMEDOUT; #elif defined(ETIMEDOUT) if(ETIMEDOUT == data->state.os_errno) result = CURLE_OPERATION_TIMEDOUT; #endif } return result; } static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) { #if defined(TCP_NODELAY) curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) struct Curl_easy *data = conn->data; char buffer[STRERROR_LEN]; #else (void) conn; #endif if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); #else (void)conn; (void)sockfd; #endif } #ifdef SO_NOSIGPIPE /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when sending data to a dead peer (instead of relying on the 4th argument to send being MSG_NOSIGNAL). Possibly also existing and in use on other BSD systems? */ static void nosigpipe(struct connectdata *conn, curl_socket_t sockfd) { struct Curl_easy *data = conn->data; int onoff = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff)) < 0) { char buffer[STRERROR_LEN]; infof(data, "Could not set SO_NOSIGPIPE: %s\n", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); } } #else #define nosigpipe(x,y) Curl_nop_stmt #endif #ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. https://support.microsoft.com/kb/823764 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size The problem described in this knowledge-base is applied only to pre-Vista Windows. Following function trying to detect OS version and skips SO_SNDBUF adjustment for Windows Vista and above. */ #define DETECT_OS_NONE 0 #define DETECT_OS_PREVISTA 1 #define DETECT_OS_VISTA_OR_LATER 2 void Curl_sndbufset(curl_socket_t sockfd) { int val = CURL_MAX_WRITE_SIZE + 32; int curval = 0; int curlen = sizeof(curval); static int detectOsState = DETECT_OS_NONE; if(detectOsState == DETECT_OS_NONE) { if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) detectOsState = DETECT_OS_VISTA_OR_LATER; else detectOsState = DETECT_OS_PREVISTA; } if(detectOsState == DETECT_OS_VISTA_OR_LATER) return; if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0) if(curval > val) return; setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val)); } #endif /* * singleipconnect() * * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to * CURL_SOCKET_BAD. Other errors will however return proper errors. * * singleipconnect() connects to the given IP only, and it may return without * having connected. */ static CURLcode singleipconnect(struct connectdata *conn, const Curl_addrinfo *ai, int sockindex) { struct Curl_sockaddr_ex addr; int rc = -1; int error = 0; bool isconnected = FALSE; struct Curl_easy *data = conn->data; curl_socket_t sockfd; CURLcode result; char ipaddress[MAX_IPADR_LEN]; long port; bool is_tcp; #ifdef TCP_FASTOPEN_CONNECT int optval = 1; #endif char buffer[STRERROR_LEN]; curl_socket_t *sockp = &conn->tempsock[sockindex]; *sockp = CURL_SOCKET_BAD; result = Curl_socket(conn, ai, &addr, &sockfd); if(result) /* Failed to create the socket, but still return OK since we signal the lack of socket as well. This allows the parent function to keep looping over alternative addresses/socket families etc. */ return CURLE_OK; /* store remote address and port used in this connection attempt */ if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen, ipaddress, &port)) { /* malformed address or bug in inet_ntop, try next address */ failf(data, "sa_addr inet_ntop() failed with errno %d: %s", errno, Curl_strerror(errno, buffer, sizeof(buffer))); Curl_closesocket(conn, sockfd); return CURLE_OK; } infof(data, " Trying %s:%ld...\n", ipaddress, port); #ifdef ENABLE_IPV6 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && addr.socktype == SOCK_STREAM; #else is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM; #endif if(is_tcp && data->set.tcp_nodelay) tcpnodelay(conn, sockfd); nosigpipe(conn, sockfd); Curl_sndbufset(sockfd); if(is_tcp && data->set.tcp_keepalive) tcpkeepalive(data, sockfd); if(data->set.fsockopt) { /* activate callback for setting socket options */ Curl_set_in_callback(data, true); error = data->set.fsockopt(data->set.sockopt_client, sockfd, CURLSOCKTYPE_IPCXN); Curl_set_in_callback(data, false); if(error == CURL_SOCKOPT_ALREADY_CONNECTED) isconnected = TRUE; else if(error) { Curl_closesocket(conn, sockfd); /* close the socket and bail out */ return CURLE_ABORTED_BY_CALLBACK; } } /* possibly bind the local end to an IP, interface or port */ if(addr.family == AF_INET #ifdef ENABLE_IPV6 || addr.family == AF_INET6 #endif ) { result = bindlocal(conn, sockfd, addr.family, Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr)); if(result) { Curl_closesocket(conn, sockfd); /* close socket and bail out */ if(result == CURLE_UNSUPPORTED_PROTOCOL) { /* The address family is not supported on this interface. We can continue trying addresses */ return CURLE_COULDNT_CONNECT; } return result; } } /* set socket non-blocking */ (void)curlx_nonblock(sockfd, TRUE); conn->connecttime = Curl_now(); if(conn->num_addr > 1) Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME); /* Connect TCP and QUIC sockets */ if(!isconnected && (conn->transport != TRNSPRT_UDP)) { if(conn->bits.tcp_fastopen) { #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */ # if defined(HAVE_BUILTIN_AVAILABLE) /* while connectx function is available since macOS 10.11 / iOS 9, it did not have the interface declared correctly until Xcode 9 / macOS SDK 10.13 */ if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) { sa_endpoints_t endpoints; endpoints.sae_srcif = 0; endpoints.sae_srcaddr = NULL; endpoints.sae_srcaddrlen = 0; endpoints.sae_dstaddr = &addr.sa_addr; endpoints.sae_dstaddrlen = addr.addrlen; rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); } else { rc = connect(sockfd, &addr.sa_addr, addr.addrlen); } # else rc = connect(sockfd, &addr.sa_addr, addr.addrlen); # endif /* HAVE_BUILTIN_AVAILABLE */ #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */ if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd); rc = connect(sockfd, &addr.sa_addr, addr.addrlen); #elif defined(MSG_FASTOPEN) /* old Linux */ if(conn->given->flags & PROTOPT_SSL) rc = connect(sockfd, &addr.sa_addr, addr.addrlen); else rc = 0; /* Do nothing */ #endif } else { rc = connect(sockfd, &addr.sa_addr, addr.addrlen); } if(-1 == rc) error = SOCKERRNO; #ifdef ENABLE_QUIC else if(conn->transport == TRNSPRT_QUIC) { /* pass in 'sockfd' separately since it hasn't been put into the tempsock array at this point */ result = Curl_quic_connect(conn, sockfd, sockindex, &addr.sa_addr, addr.addrlen); if(result) error = SOCKERRNO; } #endif } else { *sockp = sockfd; return CURLE_OK; } if(-1 == rc) { switch(error) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) #if (EAGAIN) != (EWOULDBLOCK) /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence * the odd #if */ case EAGAIN: #endif #endif result = CURLE_OK; break; default: /* unknown error, fallthrough and try another address! */ infof(data, "Immediate connect fail for %s: %s\n", ipaddress, Curl_strerror(error, buffer, sizeof(buffer))); data->state.os_errno = error; /* connect failed */ Curl_closesocket(conn, sockfd); result = CURLE_COULDNT_CONNECT; } } if(!result) *sockp = sockfd; return result; } /* * TCP connect to the given host with timeout, proxy or remote doesn't matter. * There might be more than one IP address to try out. Fill in the passed * pointer with the connected socket. */ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost) { struct Curl_easy *data = conn->data; struct curltime before = Curl_now(); CURLcode result = CURLE_COULDNT_CONNECT; timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; } conn->num_addr = Curl_num_addresses(remotehost->addr); conn->tempaddr[0] = remotehost->addr; conn->tempaddr[1] = NULL; conn->tempsock[0] = CURL_SOCKET_BAD; conn->tempsock[1] = CURL_SOCKET_BAD; /* Max time for the next connection attempt */ conn->timeoutms_per_addr = conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2; /* start connecting to first IP */ while(conn->tempaddr[0]) { result = singleipconnect(conn, conn->tempaddr[0], 0); if(!result) break; conn->tempaddr[0] = conn->tempaddr[0]->ai_next; } if(conn->tempsock[0] == CURL_SOCKET_BAD) { if(!result) result = CURLE_COULDNT_CONNECT; return result; } data->info.numconnects++; /* to track the number of connections made */ Curl_expire(conn->data, data->set.happy_eyeballs_timeout, EXPIRE_HAPPY_EYEBALLS); return CURLE_OK; } struct connfind { struct connectdata *tofind; bool found; }; static int conn_is_conn(struct connectdata *conn, void *param) { struct connfind *f = (struct connfind *)param; if(conn == f->tofind) { f->found = TRUE; return 1; } return 0; } /* * Used to extract socket and connectdata struct for the most recent * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp) { DEBUGASSERT(data); /* this works for an easy handle: * - that has been used for curl_easy_perform() * - that is associated with a multi handle, and whose connection * was detached with CURLOPT_CONNECT_ONLY */ if(data->state.lastconnect && (data->multi_easy || data->multi)) { struct connectdata *c = data->state.lastconnect; struct connfind find; find.tofind = data->state.lastconnect; find.found = FALSE; Curl_conncache_foreach(data, data->multi_easy? &data->multi_easy->conn_cache: &data->multi->conn_cache, &find, conn_is_conn); if(!find.found) { data->state.lastconnect = NULL; return CURL_SOCKET_BAD; } if(connp) { /* only store this if the caller cares for it */ *connp = c; c->data = data; } return c->sock[FIRSTSOCKET]; } else return CURL_SOCKET_BAD; } /* * Check if a connection seems to be alive. */ bool Curl_connalive(struct connectdata *conn) { /* First determine if ssl */ if(conn->ssl[FIRSTSOCKET].use) { /* use the SSL context */ if(!Curl_ssl_check_cxn(conn)) return false; /* FIN received */ } /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ #ifdef MSG_PEEK else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) return false; else { /* use the socket */ char buf; if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { return false; /* FIN received */ } } #endif return true; } /* * Close a socket. * * 'conn' can be NULL, beware! */ int Curl_closesocket(struct connectdata *conn, curl_socket_t sock) { if(conn && conn->fclosesocket) { if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted) /* if this socket matches the second socket, and that was created with accept, then we MUST NOT call the callback but clear the accepted status */ conn->sock_accepted = FALSE; else { int rc; Curl_multi_closed(conn->data, sock); Curl_set_in_callback(conn->data, true); rc = conn->fclosesocket(conn->closesocket_client, sock); Curl_set_in_callback(conn->data, false); return rc; } } if(conn) /* tell the multi-socket code about this */ Curl_multi_closed(conn->data, sock); sclose(sock); return 0; } /* * Create a socket based on info from 'conn' and 'ai'. * * 'addr' should be a pointer to the correct struct to get data back, or NULL. * 'sockfd' must be a pointer to a socket descriptor. * * If the open socket callback is set, used that! * */ CURLcode Curl_socket(struct connectdata *conn, const Curl_addrinfo *ai, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd) { struct Curl_easy *data = conn->data; struct Curl_sockaddr_ex dummy; if(!addr) /* if the caller doesn't want info back, use a local temp copy */ addr = &dummy; /* * The Curl_sockaddr_ex structure is basically libcurl's external API * curl_sockaddr structure with enough space available to directly hold * any protocol-specific address structures. The variable declared here * will be used to pass / receive data to/from the fopensocket callback * if this has been set, before that, it is initialized from parameters. */ addr->family = ai->ai_family; addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP : ai->ai_protocol; addr->addrlen = ai->ai_addrlen; if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) addr->addrlen = sizeof(struct Curl_sockaddr_storage); memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen); if(data->set.fopensocket) { /* * If the opensocket callback is set, all the destination address * information is passed to the callback. Depending on this information the * callback may opt to abort the connection, this is indicated returning * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When * the callback returns a valid socket the destination address information * might have been changed and this 'new' address will actually be used * here to connect. */ Curl_set_in_callback(data, true); *sockfd = data->set.fopensocket(data->set.opensocket_client, CURLSOCKTYPE_IPCXN, (struct curl_sockaddr *)addr); Curl_set_in_callback(data, false); } else /* opensocket callback not set, so simply create the socket now */ *sockfd = socket(addr->family, addr->socktype, addr->protocol); if(*sockfd == CURL_SOCKET_BAD) /* no socket, no connection */ return CURLE_COULDNT_CONNECT; if(conn->transport == TRNSPRT_QUIC) { /* QUIC sockets need to be nonblocking */ (void)curlx_nonblock(*sockfd, TRUE); } #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) if(conn->scope_id && (addr->family == AF_INET6)) { struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr; sa6->sin6_scope_id = conn->scope_id; } #endif return CURLE_OK; } /* * Curl_conncontrol() marks streams or connection for closure. */ void Curl_conncontrol(struct connectdata *conn, int ctrl /* see defines in header */ #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) , const char *reason #endif ) { /* close if a connection, or a stream that isn't multiplexed */ bool closeit = (ctrl == CONNCTRL_CONNECTION) || ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); if((ctrl == CONNCTRL_STREAM) && (conn->handler->flags & PROTOPT_STREAM)) DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); else if((bit)closeit != conn->bits.close) { DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", reason)); conn->bits.close = closeit; /* the only place in the source code that should assign this bit */ } } /* Data received can be cached at various levels, so check them all here. */ bool Curl_conn_data_pending(struct connectdata *conn, int sockindex) { int readable; if(Curl_ssl_data_pending(conn, sockindex) || Curl_recv_has_postponed_data(conn, sockindex)) return true; readable = SOCKET_READABLE(conn->sock[sockindex], 0); return (readable > 0 && (readable & CURL_CSELECT_IN)); } davix-0.8.0/deps/curl/lib/vquic/0000755000000000000000000000000014121063461015123 5ustar rootrootdavix-0.8.0/deps/curl/lib/vquic/ngtcp2.c0000644000000000000000000014552714121063461016502 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGTCP2 #include #include #include #include #include "urldata.h" #include "sendf.h" #include "strdup.h" #include "rand.h" #include "ngtcp2.h" #include "multiif.h" #include "strcase.h" #include "connect.h" #include "strerror.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* #define DEBUG_NGTCP2 */ #ifdef CURLDEBUG #define DEBUG_HTTP3 #endif #ifdef DEBUG_HTTP3 #define H3BUGF(x) x #else #define H3BUGF(x) do { } while(0) #endif /* * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked. * It is used as a circular buffer. Add new bytes at the end until it reaches * the far end, then start over at index 0 again. */ #define H3_SEND_SIZE (20*1024) struct h3out { uint8_t buf[H3_SEND_SIZE]; size_t used; /* number of bytes used in the buffer */ size_t windex; /* index in the buffer where to start writing the next data block */ }; #define QUIC_MAX_STREAMS (256*1024) #define QUIC_MAX_DATA (1*1024*1024) #define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */ #define QUIC_CIPHERS \ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:X25519:P-384:P-521" static CURLcode ng_process_ingress(struct connectdata *conn, curl_socket_t sockfd, struct quicsocket *qs); static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, struct quicsocket *qs); static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, size_t datalen, void *user_data, void *stream_user_data); static ngtcp2_tstamp timestamp(void) { struct curltime ct = Curl_now(); return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS; } #ifdef DEBUG_NGTCP2 static void quic_printf(void *user_data, const char *fmt, ...) { va_list ap; (void)user_data; /* TODO, use this to do infof() instead long-term */ va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } #endif static ngtcp2_crypto_level quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) { switch(ossl_level) { case ssl_encryption_initial: return NGTCP2_CRYPTO_LEVEL_INITIAL; case ssl_encryption_early_data: return NGTCP2_CRYPTO_LEVEL_EARLY; case ssl_encryption_handshake: return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; case ssl_encryption_application: return NGTCP2_CRYPTO_LEVEL_APP; default: assert(0); } } static int setup_initial_crypto_context(struct quicsocket *qs) { const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn); if(ngtcp2_crypto_derive_and_install_initial_key( qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid, NGTCP2_CRYPTO_SIDE_CLIENT) != 0) return -1; return 0; } static void quic_settings(ngtcp2_settings *s, uint64_t stream_buffer_size) { ngtcp2_settings_default(s); #ifdef DEBUG_NGTCP2 s->log_printf = quic_printf; #else s->log_printf = NULL; #endif s->initial_ts = timestamp(); s->transport_params.initial_max_stream_data_bidi_local = stream_buffer_size; s->transport_params.initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS; s->transport_params.initial_max_stream_data_uni = QUIC_MAX_STREAMS; s->transport_params.initial_max_data = QUIC_MAX_DATA; s->transport_params.initial_max_streams_bidi = 1; s->transport_params.initial_max_streams_uni = 3; s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT; } static FILE *keylog_file; /* not thread-safe */ static void keylog_callback(const SSL *ssl, const char *line) { (void)ssl; fputs(line, keylog_file); fputc('\n', keylog_file); fflush(keylog_file); } static int init_ngh3_conn(struct quicsocket *qs); static int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *rx_secret, const uint8_t *tx_secret, size_t secretlen) { struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); int level = quic_from_ossl_level(ossl_level); if(ngtcp2_crypto_derive_and_install_key( qs->qconn, ssl, NULL, NULL, NULL, NULL, NULL, NULL, level, rx_secret, tx_secret, secretlen, NGTCP2_CRYPTO_SIDE_CLIENT) != 0) return 0; if(level == NGTCP2_CRYPTO_LEVEL_APP) { if(init_ngh3_conn(qs) != CURLE_OK) return 0; } return 1; } static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *data, size_t len) { struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); struct quic_handshake *crypto_data; ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); int rv; crypto_data = &qs->crypto_data[level]; if(crypto_data->buf == NULL) { crypto_data->buf = malloc(4096); if(!crypto_data->buf) return 0; crypto_data->alloclen = 4096; } /* TODO Just pretend that handshake does not grow more than 4KiB for now */ assert(crypto_data->len + len <= crypto_data->alloclen); memcpy(&crypto_data->buf[crypto_data->len], data, len); crypto_data->len += len; rv = ngtcp2_conn_submit_crypto_data( qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len), len); if(rv) { H3BUGF(fprintf(stderr, "write_client_handshake failed\n")); } assert(0 == rv); return 1; } static int quic_flush_flight(SSL *ssl) { (void)ssl; return 1; } static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) { struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); (void)level; qs->tls_alert = alert; return 1; } static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets, quic_add_handshake_data, quic_flush_flight, quic_send_alert}; static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) { SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); const char *keylog_filename; SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_default_verify_paths(ssl_ctx); if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) { char error_buffer[256]; ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer); return NULL; } if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) { failf(data, "SSL_CTX_set1_groups_list failed"); return NULL; } SSL_CTX_set_quic_method(ssl_ctx, &quic_method); keylog_filename = getenv("SSLKEYLOGFILE"); if(keylog_filename) { keylog_file = fopen(keylog_filename, "wb"); if(keylog_file) { SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); } } return ssl_ctx; } /** SSL callbacks ***/ static int quic_init_ssl(struct quicsocket *qs) { const uint8_t *alpn = NULL; size_t alpnlen = 0; /* this will need some attention when HTTPS proxy over QUIC get fixed */ const char * const hostname = qs->conn->host.name; if(qs->ssl) SSL_free(qs->ssl); qs->ssl = SSL_new(qs->sslctx); SSL_set_app_data(qs->ssl, qs); SSL_set_connect_state(qs->ssl); switch(qs->version) { #ifdef NGTCP2_PROTO_VER case NGTCP2_PROTO_VER: alpn = (const uint8_t *)NGTCP2_ALPN_H3; alpnlen = sizeof(NGTCP2_ALPN_H3) - 1; break; #endif } if(alpn) SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen); /* set SNI */ SSL_set_tlsext_host_name(qs->ssl, hostname); return 0; } static int cb_initial(ngtcp2_conn *quic, void *user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; if(ngtcp2_crypto_read_write_crypto_data( quic, qs->ssl, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } static int cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; (void)offset; if(ngtcp2_crypto_read_write_crypto_data(tconn, qs->ssl, crypto_level, data, datalen) != 0) return NGTCP2_ERR_CRYPTO; return 0; } static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; (void)tconn; infof(qs->conn->data, "QUIC handshake is completed\n"); return 0; } static void extend_stream_window(ngtcp2_conn *tconn, struct HTTP *stream) { size_t thismuch = stream->unacked_window; ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch); ngtcp2_conn_extend_max_offset(tconn, thismuch); stream->unacked_window = 0; } static int cb_recv_stream_data(ngtcp2_conn *tconn, int64_t stream_id, int fin, uint64_t offset, const uint8_t *buf, size_t buflen, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; ssize_t nconsumed; (void)offset; (void)stream_user_data; nconsumed = nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin); if(nconsumed < 0) { failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s\n", nghttp3_strerror((int)nconsumed)); return NGTCP2_ERR_CALLBACK_FAILURE; } /* number of bytes inside buflen which consists of framing overhead * including QPACK HEADERS. In other words, it does not consume payload of * DATA frame. */ ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed); ngtcp2_conn_extend_max_offset(tconn, nconsumed); return 0; } static int cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id, uint64_t offset, size_t datalen, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; int rv; (void)stream_id; (void)tconn; (void)offset; (void)datalen; (void)stream_user_data; rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen); if(rv != 0) { failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s\n", nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; int rv; (void)tconn; (void)stream_user_data; /* stream is closed... */ rv = nghttp3_conn_close_stream(qs->h3conn, stream_id, app_error_code); if(rv != 0) { failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s\n", nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id, uint64_t final_size, uint64_t app_error_code, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; int rv; (void)tconn; (void)final_size; (void)app_error_code; (void)stream_user_data; rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id); if(rv != 0) { failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s\n", nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } static int cb_recv_retry(ngtcp2_conn *tconn, const ngtcp2_pkt_hd *hd, const ngtcp2_pkt_retry *retry, void *user_data) { /* Re-generate handshake secrets here because connection ID might change. */ struct quicsocket *qs = (struct quicsocket *)user_data; (void)tconn; (void)hd; (void)retry; setup_initial_crypto_context(qs); return 0; } static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn, uint64_t max_streams, void *user_data) { (void)tconn; (void)max_streams; (void)user_data; return 0; } static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, uint64_t max_data, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; int rv; (void)tconn; (void)max_data; (void)stream_user_data; rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id); if(rv != 0) { failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s\n", nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, void *user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; CURLcode result; (void)tconn; result = Curl_rand(qs->conn->data, cid->data, cidlen); if(result) return NGTCP2_ERR_CALLBACK_FAILURE; cid->datalen = cidlen; result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN); if(result) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } static ngtcp2_conn_callbacks ng_callbacks = { cb_initial, NULL, /* recv_client_initial */ cb_recv_crypto_data, cb_handshake_completed, NULL, /* recv_version_negotiation */ ngtcp2_crypto_encrypt_cb, ngtcp2_crypto_decrypt_cb, ngtcp2_crypto_hp_mask_cb, cb_recv_stream_data, NULL, /* acked_crypto_offset */ cb_acked_stream_data_offset, NULL, /* stream_open */ cb_stream_close, NULL, /* recv_stateless_reset */ cb_recv_retry, cb_extend_max_local_streams_bidi, NULL, /* extend_max_local_streams_uni */ NULL, /* rand */ cb_get_new_connection_id, NULL, /* remove_connection_id */ ngtcp2_crypto_update_key_cb, /* update_key */ NULL, /* path_validation */ NULL, /* select_preferred_addr */ cb_stream_reset, NULL, /* extend_max_remote_streams_bidi */ NULL, /* extend_max_remote_streams_uni */ cb_extend_max_stream_data, NULL, /* dcid_status */ NULL /* handshake_confirmed */ }; /* * Might be called twice for happy eyeballs. */ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, int sockindex, const struct sockaddr *addr, socklen_t addrlen) { int rc; int rv; CURLcode result; ngtcp2_path path; /* TODO: this must be initialized properly */ struct Curl_easy *data = conn->data; struct quicsocket *qs = &conn->hequic[sockindex]; char ipbuf[40]; long port; uint8_t paramsbuf[64]; ngtcp2_transport_params params; ssize_t nwrite; qs->conn = conn; /* extract the used address as a string */ if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) { char buffer[STRERROR_LEN]; failf(data, "ssrem inet_ntop() failed with errno %d: %s", SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_BAD_FUNCTION_ARGUMENT; } infof(data, "Connect socket %d over QUIC to %s:%ld\n", sockfd, ipbuf, port); qs->version = NGTCP2_PROTO_VER; qs->sslctx = quic_ssl_ctx(data); if(!qs->sslctx) return CURLE_QUIC_CONNECT_ERROR; if(quic_init_ssl(qs)) return CURLE_QUIC_CONNECT_ERROR; qs->dcid.datalen = NGTCP2_MAX_CIDLEN; result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN); if(result) return result; qs->scid.datalen = NGTCP2_MAX_CIDLEN; result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN); if(result) return result; quic_settings(&qs->settings, data->set.buffer_size); qs->local_addrlen = sizeof(qs->local_addr); rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr, &qs->local_addrlen); if(rv == -1) return CURLE_QUIC_CONNECT_ERROR; ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen, NULL); ngtcp2_addr_init(&path.remote, (uint8_t*)addr, addrlen, NULL); #ifdef NGTCP2_PROTO_VER #define QUICVER NGTCP2_PROTO_VER #else #error "unsupported ngtcp2 version" #endif rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, QUICVER, &ng_callbacks, &qs->settings, NULL, qs); if(rc) return CURLE_QUIC_CONNECT_ERROR; ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); nwrite = ngtcp2_encode_transport_params( paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, ¶ms); if(nwrite < 0) { failf(data, "ngtcp2_encode_transport_params: %s\n", ngtcp2_strerror((int)nwrite)); return CURLE_QUIC_CONNECT_ERROR; } if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite)) return CURLE_QUIC_CONNECT_ERROR; rc = setup_initial_crypto_context(qs); if(rc) return CURLE_QUIC_CONNECT_ERROR; return CURLE_OK; } /* * Store ngtp2 version info in this buffer, Prefix with a space. Return total * length written. */ int Curl_quic_ver(char *p, size_t len) { ngtcp2_info *ng2 = ngtcp2_version(0); nghttp3_info *ht3 = nghttp3_version(0); return msnprintf(p, len, " ngtcp2/%s nghttp3/%s", ng2->version_str, ht3->version_str); } static int ng_getsock(struct connectdata *conn, curl_socket_t *socks) { struct SingleRequest *k = &conn->data->req; int bitmap = GETSOCK_BLANK; socks[0] = conn->sock[FIRSTSOCKET]; /* in a HTTP/2 connection we can basically always get a frame so we should always be ready for one */ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); /* we're still uploading or the HTTP/2 layer wants to send data */ if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; } static int ng_perform_getsock(const struct connectdata *conn, curl_socket_t *socks) { return ng_getsock((struct connectdata *)conn, socks); } static CURLcode ng_disconnect(struct connectdata *conn, bool dead_connection) { int i; struct quicsocket *qs = &conn->hequic[0]; (void)dead_connection; if(qs->ssl) SSL_free(qs->ssl); for(i = 0; i < 3; i++) free(qs->crypto_data[i].buf); nghttp3_conn_del(qs->h3conn); ngtcp2_conn_del(qs->qconn); SSL_CTX_free(qs->sslctx); return CURLE_OK; } static unsigned int ng_conncheck(struct connectdata *conn, unsigned int checks_to_perform) { (void)conn; (void)checks_to_perform; return CONNRESULT_NONE; } static const struct Curl_handler Curl_handler_http3 = { "HTTPS", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ng_getsock, /* proto_getsock */ ng_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ng_perform_getsock, /* perform_getsock */ ng_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ng_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.protop; (void)conn; (void)stream_id; (void)app_error_code; (void)user_data; H3BUGF(infof(data, "cb_h3_stream_close CALLED\n")); stream->closed = TRUE; Curl_expire(data, 0, EXPIRE_QUIC); /* make sure that ngh3_stream_recv is called again to complete the transfer even if there are no more packets to be received from the server. */ data->state.drain = 1; return 0; } /* Minimum size of the overflow buffer */ #define OVERFLOWSIZE 1024 /* * allocate_overflow() ensures that there is room for incoming data in the * overflow buffer, growing it to accommodate the new data if necessary. We * may need to use the overflow buffer because we can't precisely limit the * amount of HTTP/3 header data we receive using QUIC flow control mechanisms. */ static CURLcode allocate_overflow(struct Curl_easy *data, struct HTTP *stream, size_t length) { size_t maxleft; size_t newsize; /* length can be arbitrarily large, so take care not to overflow newsize */ maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen; if(length > maxleft) { /* The reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a highly compressed list of headers that will cause our overflow buffer to grow too large */ failf(data, "Rejected %zu bytes of overflow data (max is %d)!", stream->overflow_buflen + length, CURL_MAX_READ_SIZE); return CURLE_OUT_OF_MEMORY; } newsize = stream->overflow_buflen + length; if(newsize > stream->overflow_bufsize) { /* We enlarge the overflow buffer as it is too small */ char *newbuff; newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2); newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE); newbuff = realloc(stream->overflow_buf, newsize); if(!newbuff) { failf(data, "Failed to alloc memory for overflow buffer!"); return CURLE_OUT_OF_MEMORY; } stream->overflow_buf = newbuff; stream->overflow_bufsize = newsize; infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize); } return CURLE_OK; } /* * write_data() copies data to the stream's receive buffer. If not enough * space is available in the receive buffer, it copies the rest to the * stream's overflow buffer. */ static CURLcode write_data(struct Curl_easy *data, struct HTTP *stream, const void *mem, size_t memlen) { CURLcode result = CURLE_OK; const char *buf = mem; size_t ncopy = memlen; /* copy as much as possible to the receive buffer */ if(stream->len) { size_t len = CURLMIN(ncopy, stream->len); #if 0 /* extra debugging of incoming h3 data */ fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n", len, stream->mem, stream->memlen); #endif memcpy(stream->mem, buf, len); stream->len -= len; stream->memlen += len; stream->mem += len; buf += len; ncopy -= len; } /* copy the rest to the overflow buffer */ if(ncopy) { result = allocate_overflow(data, stream, ncopy); if(result) { return result; } #if 0 /* extra debugging of incoming h3 data */ fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n", ncopy, stream->overflow_buf, stream->overflow_buflen); #endif memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy); stream->overflow_buflen += ncopy; } #if 0 /* extra debugging of incoming h3 data */ { size_t i; for(i = 0; i < memlen; i++) { fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]); } } #endif return result; } static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *buf, size_t buflen, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.protop; CURLcode result = CURLE_OK; (void)conn; result = write_data(data, stream, buf, buflen); if(result) { return -1; } stream->unacked_window += buflen; (void)stream_id; (void)user_data; return 0; } static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id, size_t consumed, void *user_data, void *stream_user_data) { struct quicsocket *qs = user_data; (void)conn; (void)stream_user_data; (void)stream_id; ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed); ngtcp2_conn_extend_max_offset(qs->qconn, consumed); return 0; } /* Decode HTTP status code. Returns -1 if no valid status code was decoded. (duplicate from http2.c) */ static int decode_status_code(const uint8_t *value, size_t len) { int i; int res; if(len != 3) { return -1; } res = 0; for(i = 0; i < 3; ++i) { char c = value[i]; if(c < '0' || c > '9') { return -1; } res *= 10; res += c - '0'; } return res; } static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.protop; CURLcode result = CURLE_OK; (void)conn; (void)stream_id; (void)user_data; /* add a CRLF only if we've received some headers */ if(stream->firstheader) { result = write_data(data, stream, "\r\n", 2); if(result) { return -1; } } return 0; } static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token, nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags, void *user_data, void *stream_user_data) { nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name); nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value); struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.protop; CURLcode result = CURLE_OK; (void)conn; (void)stream_id; (void)token; (void)flags; (void)user_data; if(h3name.len == sizeof(":status") - 1 && !memcmp(":status", h3name.base, h3name.len)) { char line[14]; /* status line is always 13 characters long */ size_t ncopy; int status = decode_status_code(h3val.base, h3val.len); DEBUGASSERT(status != -1); ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status); result = write_data(data, stream, line, ncopy); if(result) { return -1; } } else { /* store as a HTTP1-style header */ result = write_data(data, stream, h3name.base, h3name.len); if(result) { return -1; } result = write_data(data, stream, ": ", 2); if(result) { return -1; } result = write_data(data, stream, h3val.base, h3val.len); if(result) { return -1; } result = write_data(data, stream, "\r\n", 2); if(result) { return -1; } } stream->firstheader = TRUE; return 0; } static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { (void)conn; (void)stream_id; (void)app_error_code; (void)user_data; (void)stream_user_data; return 0; } static nghttp3_conn_callbacks ngh3_callbacks = { cb_h3_acked_stream_data, /* acked_stream_data */ cb_h3_stream_close, cb_h3_recv_data, cb_h3_deferred_consume, NULL, /* begin_headers */ cb_h3_recv_header, cb_h3_end_headers, NULL, /* begin_trailers */ cb_h3_recv_header, NULL, /* end_trailers */ NULL, /* http_begin_push_promise */ NULL, /* http_recv_push_promise */ NULL, /* http_end_push_promise */ NULL, /* http_cancel_push */ cb_h3_send_stop_sending, NULL, /* push_stream */ NULL, /* end_stream */ }; static int init_ngh3_conn(struct quicsocket *qs) { CURLcode result; int rc; int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id; if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) { failf(qs->conn->data, "too few available QUIC streams"); return CURLE_QUIC_CONNECT_ERROR; } nghttp3_conn_settings_default(&qs->h3settings); rc = nghttp3_conn_client_new(&qs->h3conn, &ngh3_callbacks, &qs->h3settings, nghttp3_mem_default(), qs); if(rc) { result = CURLE_OUT_OF_MEMORY; goto fail; } rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL); if(rc) { result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id); if(rc) { result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL); if(rc) { result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL); if(rc) { result = CURLE_QUIC_CONNECT_ERROR; goto fail; } rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id, qpack_dec_stream_id); if(rc) { result = CURLE_QUIC_CONNECT_ERROR; goto fail; } return CURLE_OK; fail: return result; } static Curl_recv ngh3_stream_recv; static Curl_send ngh3_stream_send; static size_t drain_overflow_buffer(struct HTTP *stream) { size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len); if(ncopy > 0) { memcpy(stream->mem, stream->overflow_buf, ncopy); stream->len -= ncopy; stream->mem += ncopy; stream->memlen += ncopy; stream->overflow_buflen -= ncopy; memmove(stream->overflow_buf, stream->overflow_buf + ncopy, stream->overflow_buflen); } return ncopy; } /* incoming data frames on the h3 stream */ static ssize_t ngh3_stream_recv(struct connectdata *conn, int sockindex, char *buf, size_t buffersize, CURLcode *curlcode) { curl_socket_t sockfd = conn->sock[sockindex]; struct HTTP *stream = conn->data->req.protop; struct quicsocket *qs = conn->quic; if(!stream->memlen) { /* remember where to store incoming data for this stream and how big the buffer is */ stream->mem = buf; stream->len = buffersize; } /* else, there's data in the buffer already */ /* if there's data in the overflow buffer from a previous call, copy as much as possible to the receive buffer before receiving more */ drain_overflow_buffer(stream); if(ng_process_ingress(conn, sockfd, qs)) { *curlcode = CURLE_RECV_ERROR; return -1; } if(ng_flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } if(stream->memlen) { ssize_t memlen = stream->memlen; /* data arrived */ *curlcode = CURLE_OK; /* reset to allow more data to come */ stream->memlen = 0; stream->mem = buf; stream->len = buffersize; /* extend the stream window with the data we're consuming and send out any additional packets to tell the server that we can receive more */ extend_stream_window(qs->qconn, stream); if(ng_flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } return memlen; } if(stream->closed) { *curlcode = CURLE_OK; return 0; } infof(conn->data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n"); *curlcode = CURLE_AGAIN; return -1; } /* this amount of data has now been acked on this stream */ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, size_t datalen, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.protop; (void)conn; (void)stream_id; (void)user_data; if(!data->set.postfields) { stream->h3out->used -= datalen; H3BUGF(infof(data, "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n", datalen, stream->h3out->used)); DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE); } return 0; } static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, size_t veccnt, uint32_t *pflags, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; size_t nread; struct HTTP *stream = data->req.protop; (void)conn; (void)stream_id; (void)user_data; (void)veccnt; if(data->set.postfields) { vec[0].base = data->set.postfields; vec[0].len = data->state.infilesize; *pflags = NGHTTP3_DATA_FLAG_EOF; return 1; } nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used); if(nread > 0) { /* nghttp3 wants us to hold on to the data until it tells us it is okay to delete it. Append the data at the end of the h3out buffer. Since we can only return consecutive data, copy the amount that fits and the next part comes in next invoke. */ struct h3out *out = stream->h3out; if(nread + out->windex > H3_SEND_SIZE) nread = H3_SEND_SIZE - out->windex; memcpy(&out->buf[out->windex], stream->upload_mem, nread); out->windex += nread; out->used += nread; /* that's the chunk we return to nghttp3 */ vec[0].base = &out->buf[out->windex]; vec[0].len = nread; if(out->windex == H3_SEND_SIZE) out->windex = 0; /* wrap */ stream->upload_mem += nread; stream->upload_len -= nread; if(data->state.infilesize != -1) { stream->upload_left -= nread; if(!stream->upload_left) *pflags = NGHTTP3_DATA_FLAG_EOF; } H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)\n", nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", out->used)); } if(stream->upload_done && !stream->upload_len && (stream->upload_left <= 0)) { H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n")); *pflags = NGHTTP3_DATA_FLAG_EOF; return 0; } else if(!nread) { return NGHTTP3_ERR_WOULDBLOCK; } return 1; } /* Index where :authority header field will appear in request header field list. */ #define AUTHORITY_DST_IDX 3 static CURLcode http_request(struct connectdata *conn, const void *mem, size_t len) { struct HTTP *stream = conn->data->req.protop; size_t nheader; size_t i; size_t authority_idx; char *hdbuf = (char *)mem; char *end, *line_end; struct quicsocket *qs = conn->quic; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; nghttp3_nv *nva = NULL; int64_t stream3_id; int rc; struct h3out *h3out = NULL; rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL); if(rc) { failf(conn->data, "can get bidi streams"); result = CURLE_SEND_ERROR; goto fail; } stream->stream3_id = stream3_id; stream->h3req = TRUE; /* senf off! */ /* Calculate number of headers contained in [mem, mem + len). Assumes a correctly generated HTTP header field block. */ nheader = 0; for(i = 1; i < len; ++i) { if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { ++nheader; ++i; } } if(nheader < 2) goto fail; /* We counted additional 2 \r\n in the first and last line. We need 3 new headers: :method, :path and :scheme. Therefore we need one more space. */ nheader += 1; nva = malloc(sizeof(nghttp3_nv) * nheader); if(!nva) { result = CURLE_OUT_OF_MEMORY; goto fail; } /* Extract :method, :path from request line We do line endings with CRLF so checking for CR is enough */ line_end = memchr(hdbuf, '\r', len); if(!line_end) { result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */ goto fail; } /* Method does not contain spaces */ end = memchr(hdbuf, ' ', line_end - hdbuf); if(!end || end == hdbuf) goto fail; nva[0].name = (unsigned char *)":method"; nva[0].namelen = strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; nva[0].valuelen = (size_t)(end - hdbuf); nva[0].flags = NGHTTP3_NV_FLAG_NONE; hdbuf = end + 1; /* Path may contain spaces so scan backwards */ end = NULL; for(i = (size_t)(line_end - hdbuf); i; --i) { if(hdbuf[i - 1] == ' ') { end = &hdbuf[i - 1]; break; } } if(!end || end == hdbuf) goto fail; nva[1].name = (unsigned char *)":path"; nva[1].namelen = strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; nva[1].valuelen = (size_t)(end - hdbuf); nva[1].flags = NGHTTP3_NV_FLAG_NONE; nva[2].name = (unsigned char *)":scheme"; nva[2].namelen = strlen((char *)nva[2].name); if(conn->handler->flags & PROTOPT_SSL) nva[2].value = (unsigned char *)"https"; else nva[2].value = (unsigned char *)"http"; nva[2].valuelen = strlen((char *)nva[2].value); nva[2].flags = NGHTTP3_NV_FLAG_NONE; authority_idx = 0; i = 3; while(i < nheader) { size_t hlen; hdbuf = line_end + 2; /* check for next CR, but only within the piece of data left in the given buffer */ line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem)); if(!line_end || (line_end == hdbuf)) goto fail; /* header continuation lines are not supported */ if(*hdbuf == ' ' || *hdbuf == '\t') goto fail; for(end = hdbuf; end < line_end && *end != ':'; ++end) ; if(end == hdbuf || end == line_end) goto fail; hlen = end - hdbuf; if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].namelen = strlen((char *)nva[i].name); } else { nva[i].namelen = (size_t)(end - hdbuf); /* Lower case the header name for HTTP/3 */ Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen); nva[i].name = (unsigned char *)hdbuf; } nva[i].flags = NGHTTP3_NV_FLAG_NONE; hdbuf = end + 1; while(*hdbuf == ' ' || *hdbuf == '\t') ++hdbuf; end = line_end; #if 0 /* This should probably go in more or less like this */ switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, end - hdbuf)) { case HEADERINST_IGNORE: /* skip header fields prohibited by HTTP/2 specification. */ --nheader; continue; case HEADERINST_TE_TRAILERS: nva[i].value = (uint8_t*)"trailers"; nva[i].value_len = sizeof("trailers") - 1; break; default: nva[i].value = (unsigned char *)hdbuf; nva[i].value_len = (size_t)(end - hdbuf); } #endif nva[i].value = (unsigned char *)hdbuf; nva[i].valuelen = (size_t)(end - hdbuf); nva[i].flags = NGHTTP3_NV_FLAG_NONE; ++i; } /* :authority must come before non-pseudo header fields */ if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { nghttp3_nv authority = nva[authority_idx]; for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { nva[i] = nva[i - 1]; } nva[i] = authority; } /* Warn stream may be rejected if cumulative length of headers is too large. */ #define MAX_ACC 60000 /* <64KB to account for some overhead */ { size_t acc = 0; for(i = 0; i < nheader; ++i) acc += nva[i].namelen + nva[i].valuelen; if(acc > MAX_ACC) { infof(data, "http_request: Warning: The cumulative length of all " "headers exceeds %zu bytes and that could cause the " "stream to be rejected.\n", MAX_ACC); } } switch(data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: case HTTPREQ_PUT: { nghttp3_data_reader data_reader; if(data->state.infilesize != -1) stream->upload_left = data->state.infilesize; else /* data sending without specifying the data amount up front */ stream->upload_left = -1; /* unknown, but not zero */ data_reader.read_data = cb_h3_readfunction; h3out = calloc(sizeof(struct h3out), 1); if(!h3out) { result = CURLE_OUT_OF_MEMORY; goto fail; } stream->h3out = h3out; rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id, nva, nheader, &data_reader, conn->data); if(rc) { result = CURLE_SEND_ERROR; goto fail; } break; } default: stream->upload_left = 0; /* nothing left to send */ rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id, nva, nheader, NULL, /* no body! */ conn->data); if(rc) { result = CURLE_SEND_ERROR; goto fail; } break; } Curl_safefree(nva); infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n", stream3_id, (void *)data); return CURLE_OK; fail: free(nva); return result; } static ssize_t ngh3_stream_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { ssize_t sent; struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; struct HTTP *stream = conn->data->req.protop; if(!stream->h3req) { CURLcode result = http_request(conn, mem, len); if(result) { *curlcode = CURLE_SEND_ERROR; return -1; } sent = len; } else { H3BUGF(infof(conn->data, "ngh3_stream_send() wants to send %zd bytes\n", len)); if(!stream->upload_len) { stream->upload_mem = mem; stream->upload_len = len; (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id); sent = len; } else { *curlcode = CURLE_AGAIN; return -1; } } if(ng_flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } *curlcode = CURLE_OK; return sent; } static void ng_has_connected(struct connectdata *conn, int tempindex) { conn->recv[FIRSTSOCKET] = ngh3_stream_recv; conn->send[FIRSTSOCKET] = ngh3_stream_send; conn->handler = &Curl_handler_http3; conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 30; conn->bundle->multiuse = BUNDLE_MULTIPLEX; conn->quic = &conn->hequic[tempindex]; DEBUGF(infof(conn->data, "ngtcp2 established connection!\n")); } /* * There can be multiple connection attempts going on in parallel. */ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; struct quicsocket *qs = &conn->hequic[sockindex]; curl_socket_t sockfd = conn->tempsock[sockindex]; result = ng_process_ingress(conn, sockfd, qs); if(result) return result; result = ng_flush_egress(conn, sockfd, qs); if(result) return result; if(ngtcp2_conn_get_handshake_completed(qs->qconn)) { *done = TRUE; ng_has_connected(conn, sockindex); } return result; } static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd, struct quicsocket *qs) { ssize_t recvd; int rv; uint8_t buf[65536]; size_t bufsize = sizeof(buf); struct sockaddr_storage remote_addr; socklen_t remote_addrlen; ngtcp2_path path; ngtcp2_tstamp ts = timestamp(); for(;;) { remote_addrlen = sizeof(remote_addr); while((recvd = recvfrom(sockfd, buf, bufsize, 0, (struct sockaddr *)&remote_addr, &remote_addrlen)) == -1 && SOCKERRNO == EINTR) ; if(recvd == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) break; failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %d", recvd); return CURLE_RECV_ERROR; } ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen, NULL); ngtcp2_addr_init(&path.remote, (uint8_t *)&remote_addr, remote_addrlen, NULL); rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts); if(rv != 0) { /* TODO Send CONNECTION_CLOSE if possible */ return CURLE_RECV_ERROR; } } return CURLE_OK; } static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, struct quicsocket *qs) { int rv; ssize_t sent; ssize_t outlen; uint8_t out[NGTCP2_MAX_PKTLEN_IPV4]; size_t pktlen; ngtcp2_path_storage ps; ngtcp2_tstamp ts = timestamp(); struct sockaddr_storage remote_addr; ngtcp2_tstamp expiry; ngtcp2_duration timeout; int64_t stream_id; ssize_t veccnt; int fin; nghttp3_vec vec[16]; ssize_t ndatalen; switch(qs->local_addr.ss_family) { case AF_INET: pktlen = NGTCP2_MAX_PKTLEN_IPV4; break; #ifdef ENABLE_IPV6 case AF_INET6: pktlen = NGTCP2_MAX_PKTLEN_IPV6; break; #endif default: assert(0); } rv = ngtcp2_conn_handle_expiry(qs->qconn, ts); if(rv != 0) { failf(conn->data, "ngtcp2_conn_handle_expiry returned error: %s\n", ngtcp2_strerror(rv)); return CURLE_SEND_ERROR; } ngtcp2_path_storage_zero(&ps); for(;;) { outlen = -1; if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) { veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec, sizeof(vec) / sizeof(vec[0])); if(veccnt < 0) { failf(conn->data, "nghttp3_conn_writev_stream returned error: %s\n", nghttp3_strerror((int)veccnt)); return CURLE_SEND_ERROR; } else if(veccnt > 0) { outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, out, pktlen, &ndatalen, NGTCP2_WRITE_STREAM_FLAG_MORE, stream_id, fin, (const ngtcp2_vec *)vec, veccnt, ts); if(outlen == 0) { break; } if(outlen < 0) { if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED || outlen == NGTCP2_ERR_STREAM_SHUT_WR) { rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); if(rv != 0) { failf(conn->data, "nghttp3_conn_block_stream returned error: %s\n", nghttp3_strerror(rv)); return CURLE_SEND_ERROR; } continue; } else if(outlen == NGTCP2_ERR_WRITE_STREAM_MORE) { assert(ndatalen > 0); rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); if(rv != 0) { failf(conn->data, "nghttp3_conn_add_write_offset returned error: %s\n", nghttp3_strerror(rv)); return CURLE_SEND_ERROR; } continue; } else { failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n", ngtcp2_strerror((int)outlen)); return CURLE_SEND_ERROR; } } else if(ndatalen >= 0) { rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); if(rv != 0) { failf(conn->data, "nghttp3_conn_add_write_offset returned error: %s\n", nghttp3_strerror(rv)); return CURLE_SEND_ERROR; } } } } if(outlen < 0) { outlen = ngtcp2_conn_write_pkt(qs->qconn, &ps.path, out, pktlen, ts); if(outlen < 0) { failf(conn->data, "ngtcp2_conn_write_pkt returned error: %s\n", ngtcp2_strerror((int)outlen)); return CURLE_SEND_ERROR; } if(outlen == 0) break; } memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen); while((sent = send(sockfd, out, outlen, 0)) == -1 && SOCKERRNO == EINTR) ; if(sent == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { /* TODO Cache packet */ break; } else { failf(conn->data, "send() returned %zd (errno %d)\n", sent, SOCKERRNO); return CURLE_SEND_ERROR; } } } expiry = ngtcp2_conn_get_expiry(qs->qconn); if(expiry != UINT64_MAX) { if(expiry <= ts) { timeout = NGTCP2_MILLISECONDS; } else { timeout = expiry - ts; } Curl_expire(conn->data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); } return CURLE_OK; } /* * Called from transfer.c:done_sending when we stop HTTP/3 uploading. */ CURLcode Curl_quic_done_sending(struct connectdata *conn) { if(conn->handler == &Curl_handler_http3) { /* only for HTTP/3 transfers */ struct HTTP *stream = conn->data->req.protop; struct quicsocket *qs = conn->quic; stream->upload_done = TRUE; (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id); } return CURLE_OK; } /* * Called from http.c:Curl_http_done when a request completes. */ void Curl_quic_done(struct Curl_easy *data, bool premature) { (void)premature; if(data->conn->handler == &Curl_handler_http3) { /* only for HTTP/3 transfers */ struct HTTP *stream = data->req.protop; Curl_safefree(stream->overflow_buf); } } /* * Called from transfer.c:data_pending to know if we should keep looping * to receive more data from the connection. */ bool Curl_quic_data_pending(const struct Curl_easy *data) { /* We may have received more data than we're able to hold in the receive buffer and allocated an overflow buffer. Since it's possible that there's no more data coming on the socket, we need to keep reading until the overflow buffer is empty. */ const struct HTTP *stream = data->req.protop; return stream->overflow_buflen > 0; } #endif davix-0.8.0/deps/curl/lib/vquic/quiche.h0000644000000000000000000000311714121063461016554 0ustar rootroot#ifndef HEADER_CURL_VQUIC_QUICHE_H #define HEADER_CURL_VQUIC_QUICHE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_QUICHE #include struct quic_handshake { char *buf; /* pointer to the buffer */ size_t alloclen; /* size of allocation */ size_t len; /* size of content in buffer */ size_t nread; /* how many bytes have been read */ }; struct quicsocket { quiche_config *cfg; quiche_conn *conn; quiche_h3_conn *h3c; quiche_h3_config *h3config; uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; uint32_t version; }; #endif #endif /* HEADER_CURL_VQUIC_QUICHE_H */ davix-0.8.0/deps/curl/lib/vquic/quiche.c0000644000000000000000000005557214121063461016563 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_QUICHE #include #include #include "urldata.h" #include "sendf.h" #include "strdup.h" #include "rand.h" #include "quic.h" #include "strcase.h" #include "multiif.h" #include "connect.h" #include "strerror.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define DEBUG_HTTP3 /* #define DEBUG_QUICHE */ #ifdef DEBUG_HTTP3 #define H3BUGF(x) x #else #define H3BUGF(x) do { } while(0) #endif #define QUIC_MAX_STREAMS (256*1024) #define QUIC_MAX_DATA (1*1024*1024) #define QUIC_IDLE_TIMEOUT (60 * 1000) /* milliseconds */ static CURLcode process_ingress(struct connectdata *conn, curl_socket_t sockfd, struct quicsocket *qs); static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd, struct quicsocket *qs); static CURLcode http_request(struct connectdata *conn, const void *mem, size_t len); static Curl_recv h3_stream_recv; static Curl_send h3_stream_send; static int quiche_getsock(struct connectdata *conn, curl_socket_t *socks) { struct SingleRequest *k = &conn->data->req; int bitmap = GETSOCK_BLANK; socks[0] = conn->sock[FIRSTSOCKET]; /* in a HTTP/2 connection we can basically always get a frame so we should always be ready for one */ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); /* we're still uploading or the HTTP/2 layer wants to send data */ if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; } static int quiche_perform_getsock(const struct connectdata *conn, curl_socket_t *socks) { return quiche_getsock((struct connectdata *)conn, socks); } static CURLcode quiche_disconnect(struct connectdata *conn, bool dead_connection) { struct quicsocket *qs = conn->quic; (void)dead_connection; quiche_h3_config_free(qs->h3config); quiche_h3_conn_free(qs->h3c); quiche_config_free(qs->cfg); quiche_conn_free(qs->conn); return CURLE_OK; } static unsigned int quiche_conncheck(struct connectdata *conn, unsigned int checks_to_perform) { (void)conn; (void)checks_to_perform; return CONNRESULT_NONE; } static CURLcode quiche_do(struct connectdata *conn, bool *done) { struct HTTP *stream = conn->data->req.protop; stream->h3req = FALSE; /* not sent */ return Curl_http(conn, done); } static const struct Curl_handler Curl_handler_http3 = { "HTTPS", /* scheme */ ZERO_NULL, /* setup_connection */ quiche_do, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ quiche_getsock, /* proto_getsock */ quiche_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ quiche_perform_getsock, /* perform_getsock */ quiche_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ quiche_conncheck, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; #ifdef DEBUG_QUICHE static void quiche_debug_log(const char *line, void *argp) { (void)argp; fprintf(stderr, "%s\n", line); } #endif CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, int sockindex, const struct sockaddr *addr, socklen_t addrlen) { CURLcode result; struct quicsocket *qs = &conn->hequic[sockindex]; struct Curl_easy *data = conn->data; #ifdef DEBUG_QUICHE /* initialize debug log callback only once */ static int debug_log_init = 0; if(!debug_log_init) { quiche_enable_debug_logging(quiche_debug_log, NULL); debug_log_init = 1; } #endif (void)addr; (void)addrlen; qs->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION); if(!qs->cfg) { failf(data, "can't create quiche config"); return CURLE_FAILED_INIT; } quiche_config_set_max_idle_timeout(qs->cfg, QUIC_IDLE_TIMEOUT); quiche_config_set_initial_max_data(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_stream_data_bidi_local(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_stream_data_bidi_remote(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_stream_data_uni(qs->cfg, QUIC_MAX_DATA); quiche_config_set_initial_max_streams_bidi(qs->cfg, QUIC_MAX_STREAMS); quiche_config_set_initial_max_streams_uni(qs->cfg, QUIC_MAX_STREAMS); quiche_config_set_application_protos(qs->cfg, (uint8_t *) QUICHE_H3_APPLICATION_PROTOCOL, sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1); result = Curl_rand(data, qs->scid, sizeof(qs->scid)); if(result) return result; if(getenv("SSLKEYLOGFILE")) quiche_config_log_keys(qs->cfg); qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid, sizeof(qs->scid), qs->cfg); if(!qs->conn) { failf(data, "can't create quiche connection"); return CURLE_OUT_OF_MEMORY; } result = flush_egress(conn, sockfd, qs); if(result) return result; /* store the used address as a string */ if(!Curl_addr2string((struct sockaddr*)addr, addrlen, conn->primary_ip, &conn->primary_port)) { char buffer[STRERROR_LEN]; failf(data, "ssrem inet_ntop() failed with errno %d: %s", SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_BAD_FUNCTION_ARGUMENT; } memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); Curl_persistconninfo(conn); /* for connection reuse purposes: */ conn->ssl[FIRSTSOCKET].state = ssl_connection_complete; infof(data, "Sent QUIC client Initial, ALPN: %s\n", QUICHE_H3_APPLICATION_PROTOCOL + 1); return CURLE_OK; } static CURLcode quiche_has_connected(struct connectdata *conn, int sockindex, int tempindex) { CURLcode result; struct quicsocket *qs = conn->quic = &conn->hequic[tempindex]; conn->recv[sockindex] = h3_stream_recv; conn->send[sockindex] = h3_stream_send; conn->handler = &Curl_handler_http3; conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 30; conn->bundle->multiuse = BUNDLE_MULTIPLEX; qs->h3config = quiche_h3_config_new(); if(!qs->h3config) return CURLE_OUT_OF_MEMORY; /* Create a new HTTP/3 connection on the QUIC connection. */ qs->h3c = quiche_h3_conn_new_with_transport(qs->conn, qs->h3config); if(!qs->h3c) { result = CURLE_OUT_OF_MEMORY; goto fail; } if(conn->hequic[1-tempindex].cfg) { qs = &conn->hequic[1-tempindex]; quiche_config_free(qs->cfg); quiche_conn_free(qs->conn); qs->cfg = NULL; qs->conn = NULL; } return CURLE_OK; fail: quiche_h3_config_free(qs->h3config); quiche_h3_conn_free(qs->h3c); return result; } /* * This function gets polled to check if this QUIC connection has connected. */ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; struct quicsocket *qs = &conn->hequic[sockindex]; curl_socket_t sockfd = conn->tempsock[sockindex]; result = process_ingress(conn, sockfd, qs); if(result) return result; result = flush_egress(conn, sockfd, qs); if(result) return result; if(quiche_conn_is_established(qs->conn)) { *done = TRUE; result = quiche_has_connected(conn, 0, sockindex); DEBUGF(infof(conn->data, "quiche established connection!\n")); } return result; } static CURLcode process_ingress(struct connectdata *conn, int sockfd, struct quicsocket *qs) { ssize_t recvd; struct Curl_easy *data = conn->data; uint8_t *buf = (uint8_t *)data->state.buffer; size_t bufsize = data->set.buffer_size; /* in case the timeout expired */ quiche_conn_on_timeout(qs->conn); do { recvd = recv(sockfd, buf, bufsize, 0); if((recvd < 0) && ((SOCKERRNO == EAGAIN) || (SOCKERRNO == EWOULDBLOCK))) break; if(recvd < 0) { failf(conn->data, "quiche: recv() unexpectedly returned %d " "(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd); return CURLE_RECV_ERROR; } recvd = quiche_conn_recv(qs->conn, buf, recvd); if(recvd == QUICHE_ERR_DONE) break; if(recvd < 0) { failf(conn->data, "quiche_conn_recv() == %d", recvd); return CURLE_RECV_ERROR; } } while(1); return CURLE_OK; } /* * flush_egress drains the buffers and sends off data. * Calls failf() on errors. */ static CURLcode flush_egress(struct connectdata *conn, int sockfd, struct quicsocket *qs) { ssize_t sent; static uint8_t out[1200]; int64_t timeout_ns; do { sent = quiche_conn_send(qs->conn, out, sizeof(out)); if(sent == QUICHE_ERR_DONE) break; if(sent < 0) { failf(conn->data, "quiche_conn_send returned %zd\n", sent); return CURLE_SEND_ERROR; } sent = send(sockfd, out, sent, 0); if(sent < 0) { failf(conn->data, "send() returned %zd\n", sent); return CURLE_SEND_ERROR; } } while(1); /* time until the next timeout event, as nanoseconds. */ timeout_ns = quiche_conn_timeout_as_nanos(qs->conn); if(timeout_ns) /* expire uses milliseconds */ Curl_expire(conn->data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC); return CURLE_OK; } struct h3h1header { char *dest; size_t destlen; /* left to use */ size_t nlen; /* used */ }; static int cb_each_header(uint8_t *name, size_t name_len, uint8_t *value, size_t value_len, void *argp) { struct h3h1header *headers = (struct h3h1header *)argp; size_t olen = 0; if((name_len == 7) && !strncmp(":status", (char *)name, 7)) { msnprintf(headers->dest, headers->destlen, "HTTP/3 %.*s\n", (int) value_len, value); } else if(!headers->nlen) { return CURLE_HTTP3; } else { msnprintf(headers->dest, headers->destlen, "%.*s: %.*s\n", (int)name_len, name, (int) value_len, value); } olen = strlen(headers->dest); headers->destlen -= olen; headers->nlen += olen; headers->dest += olen; return 0; } static ssize_t h3_stream_recv(struct connectdata *conn, int sockindex, char *buf, size_t buffersize, CURLcode *curlcode) { ssize_t recvd = -1; ssize_t rcode; struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; quiche_h3_event *ev; int rc; struct h3h1header headers; struct Curl_easy *data = conn->data; struct HTTP *stream = data->req.protop; headers.dest = buf; headers.destlen = buffersize; headers.nlen = 0; if(process_ingress(conn, sockfd, qs)) { infof(data, "h3_stream_recv returns on ingress\n"); *curlcode = CURLE_RECV_ERROR; return -1; } while(recvd < 0) { int64_t s = quiche_h3_conn_poll(qs->h3c, qs->conn, &ev); if(s < 0) /* nothing more to do */ break; if(s != stream->stream3_id) { /* another transfer, ignore for now */ infof(data, "Got h3 for stream %u, expects %u\n", s, stream->stream3_id); continue; } switch(quiche_h3_event_type(ev)) { case QUICHE_H3_EVENT_HEADERS: rc = quiche_h3_event_for_each_header(ev, cb_each_header, &headers); if(rc) { *curlcode = rc; failf(data, "Error in HTTP/3 response header"); break; } recvd = headers.nlen; break; case QUICHE_H3_EVENT_DATA: if(!stream->firstbody) { /* add a header-body separator CRLF */ buf[0] = '\r'; buf[1] = '\n'; buf += 2; buffersize -= 2; stream->firstbody = TRUE; recvd = 2; /* two bytes already */ } else recvd = 0; rcode = quiche_h3_recv_body(qs->h3c, qs->conn, s, (unsigned char *)buf, buffersize); if(rcode <= 0) { recvd = -1; break; } recvd += rcode; break; case QUICHE_H3_EVENT_FINISHED: streamclose(conn, "End of stream"); recvd = 0; /* end of stream */ break; default: break; } quiche_h3_event_free(ev); } if(flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } *curlcode = (-1 == recvd)? CURLE_AGAIN : CURLE_OK; if(recvd >= 0) /* Get this called again to drain the event queue */ Curl_expire(data, 0, EXPIRE_QUIC); data->state.drain = (recvd >= 0) ? 1 : 0; return recvd; } static ssize_t h3_stream_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { ssize_t sent; struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; struct HTTP *stream = conn->data->req.protop; if(!stream->h3req) { CURLcode result = http_request(conn, mem, len); if(result) { *curlcode = CURLE_SEND_ERROR; return -1; } sent = len; } else { H3BUGF(infof(conn->data, "Pass on %zd body bytes to quiche\n", len)); sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id, (uint8_t *)mem, len, FALSE); if(sent < 0) { *curlcode = CURLE_SEND_ERROR; return -1; } } if(flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } *curlcode = CURLE_OK; return sent; } /* * Store quiche version info in this buffer, Prefix with a space. Return total * length written. */ int Curl_quic_ver(char *p, size_t len) { return msnprintf(p, len, " quiche/%s", quiche_version()); } /* Index where :authority header field will appear in request header field list. */ #define AUTHORITY_DST_IDX 3 static CURLcode http_request(struct connectdata *conn, const void *mem, size_t len) { /* */ struct HTTP *stream = conn->data->req.protop; size_t nheader; size_t i; size_t authority_idx; char *hdbuf = (char *)mem; char *end, *line_end; int64_t stream3_id; quiche_h3_header *nva = NULL; struct quicsocket *qs = conn->quic; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; stream->h3req = TRUE; /* senf off! */ /* Calculate number of headers contained in [mem, mem + len). Assumes a correctly generated HTTP header field block. */ nheader = 0; for(i = 1; i < len; ++i) { if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { ++nheader; ++i; } } if(nheader < 2) goto fail; /* We counted additional 2 \r\n in the first and last line. We need 3 new headers: :method, :path and :scheme. Therefore we need one more space. */ nheader += 1; nva = malloc(sizeof(quiche_h3_header) * nheader); if(!nva) { result = CURLE_OUT_OF_MEMORY; goto fail; } /* Extract :method, :path from request line We do line endings with CRLF so checking for CR is enough */ line_end = memchr(hdbuf, '\r', len); if(!line_end) { result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */ goto fail; } /* Method does not contain spaces */ end = memchr(hdbuf, ' ', line_end - hdbuf); if(!end || end == hdbuf) goto fail; nva[0].name = (unsigned char *)":method"; nva[0].name_len = strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; nva[0].value_len = (size_t)(end - hdbuf); hdbuf = end + 1; /* Path may contain spaces so scan backwards */ end = NULL; for(i = (size_t)(line_end - hdbuf); i; --i) { if(hdbuf[i - 1] == ' ') { end = &hdbuf[i - 1]; break; } } if(!end || end == hdbuf) goto fail; nva[1].name = (unsigned char *)":path"; nva[1].name_len = strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; nva[1].value_len = (size_t)(end - hdbuf); nva[2].name = (unsigned char *)":scheme"; nva[2].name_len = strlen((char *)nva[2].name); if(conn->handler->flags & PROTOPT_SSL) nva[2].value = (unsigned char *)"https"; else nva[2].value = (unsigned char *)"http"; nva[2].value_len = strlen((char *)nva[2].value); authority_idx = 0; i = 3; while(i < nheader) { size_t hlen; hdbuf = line_end + 2; /* check for next CR, but only within the piece of data left in the given buffer */ line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem)); if(!line_end || (line_end == hdbuf)) goto fail; /* header continuation lines are not supported */ if(*hdbuf == ' ' || *hdbuf == '\t') goto fail; for(end = hdbuf; end < line_end && *end != ':'; ++end) ; if(end == hdbuf || end == line_end) goto fail; hlen = end - hdbuf; if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].name_len = strlen((char *)nva[i].name); } else { nva[i].name_len = (size_t)(end - hdbuf); /* Lower case the header name for HTTP/3 */ Curl_strntolower((char *)hdbuf, hdbuf, nva[i].name_len); nva[i].name = (unsigned char *)hdbuf; } hdbuf = end + 1; while(*hdbuf == ' ' || *hdbuf == '\t') ++hdbuf; end = line_end; #if 0 /* This should probably go in more or less like this */ switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, end - hdbuf)) { case HEADERINST_IGNORE: /* skip header fields prohibited by HTTP/2 specification. */ --nheader; continue; case HEADERINST_TE_TRAILERS: nva[i].value = (uint8_t*)"trailers"; nva[i].value_len = sizeof("trailers") - 1; break; default: nva[i].value = (unsigned char *)hdbuf; nva[i].value_len = (size_t)(end - hdbuf); } #endif nva[i].value = (unsigned char *)hdbuf; nva[i].value_len = (size_t)(end - hdbuf); ++i; } /* :authority must come before non-pseudo header fields */ if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { quiche_h3_header authority = nva[authority_idx]; for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { nva[i] = nva[i - 1]; } nva[i] = authority; } /* Warn stream may be rejected if cumulative length of headers is too large. */ #define MAX_ACC 60000 /* <64KB to account for some overhead */ { size_t acc = 0; for(i = 0; i < nheader; ++i) { acc += nva[i].name_len + nva[i].value_len; H3BUGF(infof(data, "h3 [%.*s: %.*s]\n", nva[i].name_len, nva[i].name, nva[i].value_len, nva[i].value)); } if(acc > MAX_ACC) { infof(data, "http_request: Warning: The cumulative length of all " "headers exceeds %zu bytes and that could cause the " "stream to be rejected.\n", MAX_ACC); } } switch(data->set.httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_POST_MIME: case HTTPREQ_PUT: if(data->state.infilesize != -1) stream->upload_left = data->state.infilesize; else /* data sending without specifying the data amount up front */ stream->upload_left = -1; /* unknown, but not zero */ stream3_id = quiche_h3_send_request(qs->h3c, qs->conn, nva, nheader, stream->upload_left ? FALSE: TRUE); if((stream3_id >= 0) && data->set.postfields) { ssize_t sent = quiche_h3_send_body(qs->h3c, qs->conn, stream3_id, (uint8_t *)data->set.postfields, stream->upload_left, TRUE); if(sent <= 0) { failf(data, "quiche_h3_send_body failed!"); result = CURLE_SEND_ERROR; } stream->upload_left = 0; /* nothing left to send */ } break; default: stream3_id = quiche_h3_send_request(qs->h3c, qs->conn, nva, nheader, TRUE); break; } Curl_safefree(nva); if(stream3_id < 0) { H3BUGF(infof(data, "quiche_h3_send_request returned %d\n", stream3_id)); result = CURLE_SEND_ERROR; goto fail; } infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n", stream3_id, (void *)data); stream->stream3_id = stream3_id; return CURLE_OK; fail: free(nva); return result; } /* * Called from transfer.c:done_sending when we stop HTTP/3 uploading. */ CURLcode Curl_quic_done_sending(struct connectdata *conn) { if(conn->handler == &Curl_handler_http3) { /* only for HTTP/3 transfers */ ssize_t sent; struct HTTP *stream = conn->data->req.protop; struct quicsocket *qs = conn->quic; fprintf(stderr, "!!! Curl_quic_done_sending\n"); stream->upload_done = TRUE; sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id, NULL, 0, TRUE); if(sent < 0) return CURLE_SEND_ERROR; } return CURLE_OK; } /* * Called from http.c:Curl_http_done when a request completes. */ void Curl_quic_done(struct Curl_easy *data, bool premature) { (void)data; (void)premature; } /* * Called from transfer.c:data_pending to know if we should keep looping * to receive more data from the connection. */ bool Curl_quic_data_pending(const struct Curl_easy *data) { (void)data; return FALSE; } #endif davix-0.8.0/deps/curl/lib/vquic/ngtcp2.h0000644000000000000000000000372214121063461016475 0ustar rootroot#ifndef HEADER_CURL_VQUIC_NGTCP2_H #define HEADER_CURL_VQUIC_NGTCP2_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGTCP2 #include #include #include struct quic_handshake { char *buf; /* pointer to the buffer */ size_t alloclen; /* size of allocation */ size_t len; /* size of content in buffer */ size_t nread; /* how many bytes have been read */ }; struct quicsocket { struct connectdata *conn; /* point back to the connection */ ngtcp2_conn *qconn; ngtcp2_cid dcid; ngtcp2_cid scid; uint32_t version; ngtcp2_settings settings; SSL_CTX *sslctx; SSL *ssl; struct quic_handshake crypto_data[3]; /* the last TLS alert description generated by the local endpoint */ uint8_t tls_alert; struct sockaddr_storage local_addr; socklen_t local_addrlen; nghttp3_conn *h3conn; nghttp3_conn_settings h3settings; }; #include "urldata.h" #endif #endif /* HEADER_CURL_VQUIC_NGTCP2_H */ davix-0.8.0/deps/curl/lib/hostsyn.c0000644000000000000000000000553014121063461015652 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /*********************************************************************** * Only for builds using synchronous name resolves **********************************************************************/ #ifdef CURLRES_SYNCH #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_PROCESS_H #include #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* * Function provided by the resolver backend to set DNS servers to use. */ CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; (void)servers; return CURLE_NOT_BUILT_IN; } /* * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; (void)interf; return CURLE_NOT_BUILT_IN; } /* * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; (void)local_ip4; return CURLE_NOT_BUILT_IN; } /* * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; (void)local_ip6; return CURLE_NOT_BUILT_IN; } #endif /* truly sync */ davix-0.8.0/deps/curl/lib/http_ntlm.c0000644000000000000000000001610614121063461016155 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) /* * NTLM details: * * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 #include "urldata.h" #include "sendf.h" #include "strcase.h" #include "http_ntlm.h" #include "curl_ntlm_core.h" #include "curl_ntlm_wb.h" #include "vauth/vauth.h" #include "url.h" /* SSL backend-specific #if branches in this file must be kept in the order documented in curl_ntlm_core. */ #if defined(USE_WINDOWS_SSPI) #include "curl_sspi.h" #endif /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #if DEBUG_ME # define DEBUG_OUT(x) x #else # define DEBUG_OUT(x) Curl_nop_stmt #endif CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, /* if proxy or not */ const char *header) /* rest of the www-authenticate: header */ { /* point to the correct struct with this */ struct ntlmdata *ntlm; curlntlm *state; CURLcode result = CURLE_OK; ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; if(checkprefix("NTLM", header)) { header += strlen("NTLM"); while(*header && ISSPACE(*header)) header++; if(*header) { result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm); if(result) return result; *state = NTLMSTATE_TYPE2; /* We got a type-2 message */ } else { if(*state == NTLMSTATE_LAST) { infof(conn->data, "NTLM auth restarted\n"); Curl_http_auth_cleanup_ntlm(conn); } else if(*state == NTLMSTATE_TYPE3) { infof(conn->data, "NTLM handshake rejected\n"); Curl_http_auth_cleanup_ntlm(conn); *state = NTLMSTATE_NONE; return CURLE_REMOTE_ACCESS_DENIED; } else if(*state >= NTLMSTATE_TYPE1) { infof(conn->data, "NTLM handshake failure (internal error)\n"); return CURLE_REMOTE_ACCESS_DENIED; } *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ } } return result; } /* * This is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) { char *base64 = NULL; size_t len = 0; CURLcode result; /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; /* point to the username, password, service and host */ const char *userp; const char *passwdp; const char *service = NULL; const char *hostname = NULL; /* point to the correct struct with this */ struct ntlmdata *ntlm; curlntlm *state; struct auth *authp; DEBUGASSERT(conn); DEBUGASSERT(conn->data); if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ? conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; hostname = conn->http_proxy.host.name; ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; service = conn->data->set.str[STRING_SERVICE_NAME] ? conn->data->set.str[STRING_SERVICE_NAME] : "HTTP"; hostname = conn->host.name; ntlm = &conn->ntlm; state = &conn->http_ntlm_state; authp = &conn->data->state.authhost; } authp->done = FALSE; /* not set means empty */ if(!userp) userp = ""; if(!passwdp) passwdp = ""; #ifdef USE_WINDOWS_SSPI if(s_hSecDll == NULL) { /* not thread safe and leaks - use curl_global_init() to avoid */ CURLcode err = Curl_sspi_global_init(); if(s_hSecDll == NULL) return err; } #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS ntlm->sslContext = conn->sslContext; #endif #endif switch(*state) { case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, service, hostname, ntlm, &base64, &len); if(result) return result; if(base64) { free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); } break; case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, ntlm, &base64, &len); if(result) return result; if(base64) { free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); *state = NTLMSTATE_TYPE3; /* we send a type-3 */ authp->done = TRUE; } break; case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ *state = NTLMSTATE_LAST; /* FALLTHROUGH */ case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; break; } return CURLE_OK; } void Curl_http_auth_cleanup_ntlm(struct connectdata *conn) { Curl_auth_cleanup_ntlm(&conn->ntlm); Curl_auth_cleanup_ntlm(&conn->proxyntlm); #if defined(NTLM_WB_ENABLED) Curl_http_auth_cleanup_ntlm_wb(conn); #endif } #endif /* !CURL_DISABLE_HTTP && USE_NTLM */ davix-0.8.0/deps/curl/lib/makefile.dj0000644000000000000000000000346414121063461016077 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2003 - 2008, Gisle Vanem . # Copyright (C) 2003 - 2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # # Adapted for djgpp2 / Watt-32 / DOS # DEPEND_PREREQ = curl_config.h VPATH = vtls vauth TOPDIR = .. include ../packages/DOS/common.dj include Makefile.inc CFLAGS += -DBUILDING_LIBCURL SOURCES = $(sort $(CSOURCES)) OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:.c=.o))) CURL_LIB = libcurl.a all: $(OBJ_DIR) curl_config.h $(CURL_LIB) $(CURL_LIB): $(OBJECTS) ar rs $@ $? curl_config.h: config-dos.h $(COPY) $^ $@ # clean generated files # genclean: - $(DELETE) curl_config.h # clean object files and subdir # objclean: genclean - $(DELETE) $(OBJ_DIR)$(DS)*.o - $(RMDIR) $(OBJ_DIR) # clean without removing built library # clean: objclean - $(DELETE) depend.dj # clean everything # realclean vclean: clean - $(DELETE) $(CURL_LIB) -include depend.dj davix-0.8.0/deps/curl/lib/strtoofft.h0000644000000000000000000000411114121063461016174 0ustar rootroot#ifndef HEADER_CURL_STRTOOFFT_H #define HEADER_CURL_STRTOOFFT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* * Determine which string to integral data type conversion function we use * to implement string conversion to our curl_off_t integral data type. * * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use * an underlying data type which might be 'long', 'int64_t', 'long long' or * '__int64' and more remotely other data types. * * On systems where the size of curl_off_t is greater than the size of 'long' * the conversion function to use is strtoll() if it is available, otherwise, * we emulate its functionality with our own clone. * * On systems where the size of curl_off_t is smaller or equal than the size * of 'long' the conversion function to use is strtol(). */ typedef enum { CURL_OFFT_OK, /* parsed fine */ CURL_OFFT_FLOW, /* over or underflow */ CURL_OFFT_INVAL /* nothing was parsed */ } CURLofft; CURLofft curlx_strtoofft(const char *str, char **endp, int base, curl_off_t *num); #endif /* HEADER_CURL_STRTOOFFT_H */ davix-0.8.0/deps/curl/lib/quic.h0000644000000000000000000000407414121063461015113 0ustar rootroot#ifndef HEADER_CURL_QUIC_H #define HEADER_CURL_QUIC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef ENABLE_QUIC #ifdef USE_NGTCP2 #include "vquic/ngtcp2.h" #endif #ifdef USE_QUICHE #include "vquic/quiche.h" #endif #include "urldata.h" /* functions provided by the specific backends */ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, int sockindex, const struct sockaddr *addr, socklen_t addrlen); CURLcode Curl_quic_is_connected(struct connectdata *conn, curl_socket_t sockfd, bool *connected); int Curl_quic_ver(char *p, size_t len); CURLcode Curl_quic_done_sending(struct connectdata *conn); void Curl_quic_done(struct Curl_easy *data, bool premature); bool Curl_quic_data_pending(const struct Curl_easy *data); #else /* ENABLE_QUIC */ #define Curl_quic_done_sending(x) #define Curl_quic_done(x,y) #define Curl_quic_data_pending(x) #endif /* !ENABLE_QUIC */ #endif /* HEADER_CURL_QUIC_H */ davix-0.8.0/deps/curl/lib/content_encoding.h0000644000000000000000000000447514121063461017477 0ustar rootroot#ifndef HEADER_CURL_CONTENT_ENCODING_H #define HEADER_CURL_CONTENT_ENCODING_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* Decoding writer. */ typedef struct contenc_writer_s contenc_writer; typedef struct content_encoding_s content_encoding; struct contenc_writer_s { const content_encoding *handler; /* Encoding handler. */ contenc_writer *downstream; /* Downstream writer. */ void *params; /* Encoding-specific storage (variable length). */ }; /* Content encoding writer. */ struct content_encoding_s { const char *name; /* Encoding name. */ const char *alias; /* Encoding name alias. */ CURLcode (*init_writer)(struct connectdata *conn, contenc_writer *writer); CURLcode (*unencode_write)(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes); void (*close_writer)(struct connectdata *conn, contenc_writer *writer); size_t paramsize; }; CURLcode Curl_build_unencoding_stack(struct connectdata *conn, const char *enclist, int maybechunked); CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes); void Curl_unencode_cleanup(struct connectdata *conn); char *Curl_all_content_encodings(void); #endif /* HEADER_CURL_CONTENT_ENCODING_H */ davix-0.8.0/deps/curl/lib/curl_ctype.h0000644000000000000000000000617114121063461016323 0ustar rootroot#ifndef HEADER_CURL_CTYPE_H #define HEADER_CURL_CTYPE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef CURL_DOES_CONVERSIONS /* * Uppercase macro versions of ANSI/ISO is*() functions/macros which * avoid negative number inputs with argument byte codes > 127. * * For non-ASCII platforms the C library character classification routines * are used despite being locale-dependent, because this is better than * not to work at all. */ #include #define ISSPACE(x) (isspace((int) ((unsigned char)x))) #define ISDIGIT(x) (isdigit((int) ((unsigned char)x))) #define ISALNUM(x) (isalnum((int) ((unsigned char)x))) #define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x))) #define ISGRAPH(x) (isgraph((int) ((unsigned char)x))) #define ISALPHA(x) (isalpha((int) ((unsigned char)x))) #define ISPRINT(x) (isprint((int) ((unsigned char)x))) #define ISUPPER(x) (isupper((int) ((unsigned char)x))) #define ISLOWER(x) (islower((int) ((unsigned char)x))) #define ISCNTRL(x) (iscntrl((int) ((unsigned char)x))) #define ISASCII(x) (isascii((int) ((unsigned char)x))) #else int Curl_isspace(int c); int Curl_isdigit(int c); int Curl_isalnum(int c); int Curl_isxdigit(int c); int Curl_isgraph(int c); int Curl_isprint(int c); int Curl_isalpha(int c); int Curl_isupper(int c); int Curl_islower(int c); int Curl_iscntrl(int c); #define ISSPACE(x) (Curl_isspace((int) ((unsigned char)x))) #define ISDIGIT(x) (Curl_isdigit((int) ((unsigned char)x))) #define ISALNUM(x) (Curl_isalnum((int) ((unsigned char)x))) #define ISXDIGIT(x) (Curl_isxdigit((int) ((unsigned char)x))) #define ISGRAPH(x) (Curl_isgraph((int) ((unsigned char)x))) #define ISALPHA(x) (Curl_isalpha((int) ((unsigned char)x))) #define ISPRINT(x) (Curl_isprint((int) ((unsigned char)x))) #define ISUPPER(x) (Curl_isupper((int) ((unsigned char)x))) #define ISLOWER(x) (Curl_islower((int) ((unsigned char)x))) #define ISCNTRL(x) (Curl_iscntrl((int) ((unsigned char)x))) #define ISASCII(x) (((x) >= 0) && ((x) <= 0x80)) #endif #define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ (((unsigned char)x) == '\t')) #endif /* HEADER_CURL_CTYPE_H */ davix-0.8.0/deps/curl/lib/timeval.c0000644000000000000000000001333314121063461015604 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "timeval.h" #if defined(WIN32) && !defined(MSDOS) /* set in win32_init() */ extern LARGE_INTEGER Curl_freq; extern bool Curl_isVistaOrGreater; /* In case of bug fix this function has a counterpart in tool_util.c */ struct curltime Curl_now(void) { struct curltime now; if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ LARGE_INTEGER count; QueryPerformanceCounter(&count); now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart); now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 / Curl_freq.QuadPart); } else { /* Disable /analyze warning that GetTickCount64 is preferred */ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:28159) #endif DWORD milliseconds = GetTickCount(); #if defined(_MSC_VER) #pragma warning(pop) #endif now.tv_sec = milliseconds / 1000; now.tv_usec = (milliseconds % 1000) * 1000; } return now; } #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) struct curltime Curl_now(void) { /* ** clock_gettime() is granted to be increased monotonically when the ** monotonic clock is queried. Time starting point is unspecified, it ** could be the system start-up time, the Epoch, or something else, ** in any case the time starting point does not change once that the ** system has started up. */ #ifdef HAVE_GETTIMEOFDAY struct timeval now; #endif struct curltime cnow; struct timespec tsnow; /* ** clock_gettime() may be defined by Apple's SDK as weak symbol thus ** code compiles but fails during run-time if clock_gettime() is ** called on unsupported OS version. */ #if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1) bool have_clock_gettime = FALSE; if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) have_clock_gettime = TRUE; #endif if( #if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1) have_clock_gettime && #endif (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) { cnow.tv_sec = tsnow.tv_sec; cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); } /* ** Even when the configure process has truly detected monotonic clock ** availability, it might happen that it is not actually available at ** run-time. When this occurs simply fallback to other time source. */ #ifdef HAVE_GETTIMEOFDAY else { (void)gettimeofday(&now, NULL); cnow.tv_sec = now.tv_sec; cnow.tv_usec = (unsigned int)now.tv_usec; } #else else { cnow.tv_sec = time(NULL); cnow.tv_usec = 0; } #endif return cnow; } #elif defined(HAVE_MACH_ABSOLUTE_TIME) #include #include struct curltime Curl_now(void) { /* ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which ** returns time in Mach "absolute time units," which are platform-dependent. ** To convert to nanoseconds, one must use conversion factors specified by ** mach_timebase_info(). */ static mach_timebase_info_data_t timebase; struct curltime cnow; uint64_t usecs; if(0 == timebase.denom) (void) mach_timebase_info(&timebase); usecs = mach_absolute_time(); usecs *= timebase.numer; usecs /= timebase.denom; usecs /= 1000; cnow.tv_sec = usecs / 1000000; cnow.tv_usec = (int)(usecs % 1000000); return cnow; } #elif defined(HAVE_GETTIMEOFDAY) struct curltime Curl_now(void) { /* ** gettimeofday() is not granted to be increased monotonically, due to ** clock drifting and external source time synchronization it can jump ** forward or backward in time. */ struct timeval now; struct curltime ret; (void)gettimeofday(&now, NULL); ret.tv_sec = now.tv_sec; ret.tv_usec = (int)now.tv_usec; return ret; } #else struct curltime Curl_now(void) { /* ** time() returns the value of time in seconds since the Epoch. */ struct curltime now; now.tv_sec = time(NULL); now.tv_usec = 0; return now; } #endif /* * Returns: time difference in number of milliseconds. For too large diffs it * returns max value. * * @unittest: 1323 */ timediff_t Curl_timediff(struct curltime newer, struct curltime older) { timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; if(diff >= (TIMEDIFF_T_MAX/1000)) return TIMEDIFF_T_MAX; else if(diff <= (TIMEDIFF_T_MIN/1000)) return TIMEDIFF_T_MIN; return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000; } /* * Returns: time difference in number of microseconds. For too large diffs it * returns max value. */ timediff_t Curl_timediff_us(struct curltime newer, struct curltime older) { timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; if(diff >= (TIMEDIFF_T_MAX/1000000)) return TIMEDIFF_T_MAX; else if(diff <= (TIMEDIFF_T_MIN/1000000)) return TIMEDIFF_T_MIN; return diff * 1000000 + newer.tv_usec-older.tv_usec; } davix-0.8.0/deps/curl/lib/makefile.amiga0000644000000000000000000000062514121063461016554 0ustar rootroot# # libcurl Makefile for AmigaOS ... # # change the follow to where you have the AmiTCP SDK v4.3 includes: ATCPSDKI= /GG/netinclude CC = m68k-amigaos-gcc CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall include Makefile.inc OBJS = $(CSOURCES:.c=.o) all: $(OBJS) ar cru libcurl.a $(OBJS) ranlib libcurl.a install: $(INSTALL) -c ./libcurl.a /lib/libcurl.a davix-0.8.0/deps/curl/lib/strdup.c0000644000000000000000000000545314121063461015470 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "strdup.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #ifndef HAVE_STRDUP char *curlx_strdup(const char *str) { size_t len; char *newstr; if(!str) return (char *)NULL; len = strlen(str); if(len >= ((size_t)-1) / sizeof(char)) return (char *)NULL; newstr = malloc((len + 1)*sizeof(char)); if(!newstr) return (char *)NULL; memcpy(newstr, str, (len + 1)*sizeof(char)); return newstr; } #endif /*************************************************************************** * * Curl_memdup(source, length) * * Copies the 'source' data to a newly allocated buffer (that is * returned). Copies 'length' bytes. * * Returns the new pointer or NULL on failure. * ***************************************************************************/ void *Curl_memdup(const void *src, size_t length) { void *buffer = malloc(length); if(!buffer) return NULL; /* fail */ memcpy(buffer, src, length); return buffer; } /*************************************************************************** * * Curl_saferealloc(ptr, size) * * Does a normal realloc(), but will free the data pointer if the realloc * fails. If 'size' is non-zero, it will free the data and return a failure. * * This convenience function is provided and used to help us avoid a common * mistake pattern when we could pass in a zero, catch the NULL return and end * up free'ing the memory twice. * * Returns the new pointer or NULL on failure. * ***************************************************************************/ void *Curl_saferealloc(void *ptr, size_t size) { void *datap = realloc(ptr, size); if(size && !datap) /* only free 'ptr' if size was non-zero */ free(ptr); return datap; } davix-0.8.0/deps/curl/lib/rand.h0000644000000000000000000000367014121063461015077 0ustar rootroot#ifndef HEADER_CURL_RAND_H #define HEADER_CURL_RAND_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Curl_rand() stores 'num' number of random unsigned characters in the buffer * 'rnd' points to. * * If libcurl is built without TLS support or with a TLS backend that lacks a * proper random API (Gskit or mbedTLS), this function will use "weak" random. * * When built *with* TLS support and a backend that offers strong random, it * will return error if it cannot provide strong random values. * * NOTE: 'data' may be passed in as NULL when coming from external API without * easy handle! * */ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random * hexadecimal digits PLUS a zero terminating byte. It must be an odd number * size. */ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num); #endif /* HEADER_CURL_RAND_H */ davix-0.8.0/deps/curl/lib/fileinfo.h0000644000000000000000000000250614121063461015743 0ustar rootroot#ifndef HEADER_CURL_FILEINFO_H #define HEADER_CURL_FILEINFO_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #include "llist.h" struct fileinfo { struct curl_fileinfo info; struct curl_llist_element list; }; struct fileinfo *Curl_fileinfo_alloc(void); void Curl_fileinfo_cleanup(struct fileinfo *finfo); #endif /* HEADER_CURL_FILEINFO_H */ davix-0.8.0/deps/curl/lib/curl_path.h0000644000000000000000000000321414121063461016126 0ustar rootroot#ifndef HEADER_CURL_PATH_H #define HEADER_CURL_PATH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #ifdef WIN32 # undef PATH_MAX # define PATH_MAX MAX_PATH # ifndef R_OK # define R_OK 4 # endif #endif #ifndef PATH_MAX #define PATH_MAX 1024 /* just an extra precaution since there are systems that have their definition hidden well */ #endif CURLcode Curl_getworkingpath(struct connectdata *conn, char *homedir, char **path); CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir); #endif /* HEADER_CURL_PATH_H */ davix-0.8.0/deps/curl/lib/if2ip.c0000644000000000000000000001537214121063461015161 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #ifdef HAVE_NET_IF_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_SYS_SOCKIO_H # include #endif #ifdef HAVE_IFADDRS_H # include #endif #ifdef HAVE_STROPTS_H # include #endif #ifdef __VMS # include #endif #include "inet_ntop.h" #include "strcase.h" #include "if2ip.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* ------------------------------------------------------------------ */ /* Return the scope of the given address. */ unsigned int Curl_ipv6_scope(const struct sockaddr *sa) { #ifndef ENABLE_IPV6 (void) sa; #else if(sa->sa_family == AF_INET6) { const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; const unsigned char *b = sa6->sin6_addr.s6_addr; unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */ return IPV6_SCOPE_UNIQUELOCAL; switch(w & 0xFFC0) { case 0xFE80: return IPV6_SCOPE_LINKLOCAL; case 0xFEC0: return IPV6_SCOPE_SITELOCAL; case 0x0000: w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] | b[10] | b[11] | b[12] | b[13] | b[14]; if(w || b[15] != 0x01) break; return IPV6_SCOPE_NODELOCAL; default: break; } } #endif return IPV6_SCOPE_GLOBAL; } #if defined(HAVE_GETIFADDRS) if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int local_scope_id, const char *interf, char *buf, int buf_size) { struct ifaddrs *iface, *head; if2ip_result_t res = IF2IP_NOT_FOUND; #ifndef ENABLE_IPV6 (void) remote_scope; #endif #if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \ !defined(ENABLE_IPV6) (void) local_scope_id; #endif if(getifaddrs(&head) >= 0) { for(iface = head; iface != NULL; iface = iface->ifa_next) { if(iface->ifa_addr != NULL) { if(iface->ifa_addr->sa_family == af) { if(strcasecompare(iface->ifa_name, interf)) { void *addr; char *ip; char scope[12] = ""; char ipstr[64]; #ifdef ENABLE_IPV6 if(af == AF_INET6) { #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID unsigned int scopeid = 0; #endif unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr); if(ifscope != remote_scope) { /* We are interested only in interface addresses whose scope matches the remote address we want to connect to: global for global, link-local for link-local, etc... */ if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; continue; } addr = &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID /* Include the scope of this interface as part of the address */ scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr) ->sin6_scope_id; /* If given, scope id should match. */ if(local_scope_id && scopeid != local_scope_id) { if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED; continue; } if(scopeid) msnprintf(scope, sizeof(scope), "%%%u", scopeid); #endif } else #endif addr = &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; res = IF2IP_FOUND; ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); msnprintf(buf, buf_size, "%s%s", ip, scope); break; } } else if((res == IF2IP_NOT_FOUND) && strcasecompare(iface->ifa_name, interf)) { res = IF2IP_AF_NOT_SUPPORTED; } } } freeifaddrs(head); } return res; } #elif defined(HAVE_IOCTL_SIOCGIFADDR) if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int local_scope_id, const char *interf, char *buf, int buf_size) { struct ifreq req; struct in_addr in; struct sockaddr_in *s; curl_socket_t dummy; size_t len; (void)remote_scope; (void)local_scope_id; if(!interf || (af != AF_INET)) return IF2IP_NOT_FOUND; len = strlen(interf); if(len >= sizeof(req.ifr_name)) return IF2IP_NOT_FOUND; dummy = socket(AF_INET, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == dummy) return IF2IP_NOT_FOUND; memset(&req, 0, sizeof(req)); memcpy(req.ifr_name, interf, len + 1); req.ifr_addr.sa_family = AF_INET; if(ioctl(dummy, SIOCGIFADDR, &req) < 0) { sclose(dummy); /* With SIOCGIFADDR, we cannot tell the difference between an interface that does not exist and an interface that has no address of the correct family. Assume the interface does not exist */ return IF2IP_NOT_FOUND; } s = (struct sockaddr_in *)(void *)&req.ifr_addr; memcpy(&in, &s->sin_addr, sizeof(in)); Curl_inet_ntop(s->sin_family, &in, buf, buf_size); sclose(dummy); return IF2IP_FOUND; } #else if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, unsigned int local_scope_id, const char *interf, char *buf, int buf_size) { (void) af; (void) remote_scope; (void) local_scope_id; (void) interf; (void) buf; (void) buf_size; return IF2IP_NOT_FOUND; } #endif davix-0.8.0/deps/curl/lib/inet_pton.c0000644000000000000000000001376114121063461016147 0ustar rootroot/* This is from the BIND 4.9.4 release, modified to compile by itself */ /* Copyright (c) 1996 - 2019 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include "curl_setup.h" #ifndef HAVE_INET_PTON #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #include "inet_pton.h" #define IN6ADDRSZ 16 #define INADDRSZ 4 #define INT16SZ 2 /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4(const char *src, unsigned char *dst); #ifdef ENABLE_IPV6 static int inet_pton6(const char *src, unsigned char *dst); #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * notice: * On Windows we store the error in the thread errno, not * in the winsock error code. This is to avoid losing the * actual last winsock error. So when this function returns * -1, check errno not SOCKERRNO. * author: * Paul Vixie, 1996. */ int Curl_inet_pton(int af, const char *src, void *dst) { switch(af) { case AF_INET: return (inet_pton4(src, (unsigned char *)dst)); #ifdef ENABLE_IPV6 case AF_INET6: return (inet_pton6(src, (unsigned char *)dst)); #endif default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(const char *src, unsigned char *dst) { static const char digits[] = "0123456789"; int saw_digit, octets, ch; unsigned char tmp[INADDRSZ], *tp; saw_digit = 0; octets = 0; tp = tmp; *tp = 0; while((ch = *src++) != '\0') { const char *pch; pch = strchr(digits, ch); if(pch) { unsigned int val = *tp * 10 + (unsigned int)(pch - digits); if(saw_digit && *tp == 0) return (0); if(val > 255) return (0); *tp = (unsigned char)val; if(! saw_digit) { if(++octets > 4) return (0); saw_digit = 1; } } else if(ch == '.' && saw_digit) { if(octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if(octets < 4) return (0); memcpy(dst, tmp, INADDRSZ); return (1); } #ifdef ENABLE_IPV6 /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ static int inet_pton6(const char *src, unsigned char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; const char *curtok; int ch, saw_xdigit; size_t val; memset((tp = tmp), 0, IN6ADDRSZ); endp = tp + IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if(*src == ':') if(*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while((ch = *src++) != '\0') { const char *xdigits; const char *pch; pch = strchr((xdigits = xdigits_l), ch); if(!pch) pch = strchr((xdigits = xdigits_u), ch); if(pch != NULL) { val <<= 4; val |= (pch - xdigits); if(++saw_xdigit > 4) return (0); continue; } if(ch == ':') { curtok = src; if(!saw_xdigit) { if(colonp) return (0); colonp = tp; continue; } if(tp + INT16SZ > endp) return (0); *tp++ = (unsigned char) ((val >> 8) & 0xff); *tp++ = (unsigned char) (val & 0xff); saw_xdigit = 0; val = 0; continue; } if(ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if(saw_xdigit) { if(tp + INT16SZ > endp) return (0); *tp++ = (unsigned char) ((val >> 8) & 0xff); *tp++ = (unsigned char) (val & 0xff); } if(colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const ssize_t n = tp - colonp; ssize_t i; if(tp == endp) return (0); for(i = 1; i <= n; i++) { *(endp - i) = *(colonp + n - i); *(colonp + n - i) = 0; } tp = endp; } if(tp != endp) return (0); memcpy(dst, tmp, IN6ADDRSZ); return (1); } #endif /* ENABLE_IPV6 */ #endif /* HAVE_INET_PTON */ davix-0.8.0/deps/curl/lib/curl_memory.h0000644000000000000000000001376014121063461016511 0ustar rootroot#ifndef HEADER_CURL_MEMORY_H #define HEADER_CURL_MEMORY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Nasty internal details ahead... * * File curl_memory.h must be included by _all_ *.c source files * that use memory related functions strdup, malloc, calloc, realloc * or free, and given source file is used to build libcurl library. * It should be included immediately before memdebug.h as the last files * included to avoid undesired interaction with other memory function * headers in dependent libraries. * * There is nearly no exception to above rule. All libcurl source * files in 'lib' subdirectory as well as those living deep inside * 'packages' subdirectories and linked together in order to build * libcurl library shall follow it. * * File lib/strdup.c is an exception, given that it provides a strdup * clone implementation while using malloc. Extra care needed inside * this one. * * The need for curl_memory.h inclusion is due to libcurl's feature * of allowing library user to provide memory replacement functions, * memory callbacks, at runtime with curl_global_init_mem() * * Any *.c source file used to build libcurl library that does not * include curl_memory.h and uses any memory function of the five * mentioned above will compile without any indication, but it will * trigger weird memory related issues at runtime. * * OTOH some source files from 'lib' subdirectory may additionally be * used directly as source code when using some curlx_ functions by * third party programs that don't even use libcurl at all. When using * these source files in this way it is necessary these are compiled * with CURLX_NO_MEMORY_CALLBACKS defined, in order to ensure that no * attempt of calling libcurl's memory callbacks is done from code * which can not use this machinery. * * Notice that libcurl's 'memory tracking' system works chaining into * the memory callback machinery. This implies that when compiling * 'lib' source files with CURLX_NO_MEMORY_CALLBACKS defined this file * disengages usage of libcurl's 'memory tracking' system, defining * MEMDEBUG_NODEFINES and overriding CURLDEBUG purpose. * * CURLX_NO_MEMORY_CALLBACKS takes precedence over CURLDEBUG. This is * done in order to allow building a 'memory tracking' enabled libcurl * and at the same time allow building programs which do not use it. * * Programs and libraries in 'tests' subdirectories have specific * purposes and needs, and as such each one will use whatever fits * best, depending additionally whether it links with libcurl or not. * * Caveat emptor. Proper curlx_* separation is a work in progress * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may * still be required. IOW don't use them yet, there are sharp edges. */ #ifdef HEADER_CURL_MEMDEBUG_H #error "Header memdebug.h shall not be included before curl_memory.h" #endif #ifndef CURLX_NO_MEMORY_CALLBACKS #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ /* * The following memory function replacement typedef's are COPIED from * curl/curl.h and MUST match the originals. We copy them to avoid having to * include curl/curl.h here. We avoid that include since it includes stdio.h * and other headers that may get messed up with defines done here. */ typedef void *(*curl_malloc_callback)(size_t size); typedef void (*curl_free_callback)(void *ptr); typedef void *(*curl_realloc_callback)(void *ptr, size_t size); typedef char *(*curl_strdup_callback)(const char *str); typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); #define CURL_DID_MEMORY_FUNC_TYPEDEFS #endif extern curl_malloc_callback Curl_cmalloc; extern curl_free_callback Curl_cfree; extern curl_realloc_callback Curl_crealloc; extern curl_strdup_callback Curl_cstrdup; extern curl_calloc_callback Curl_ccalloc; #if defined(WIN32) && defined(UNICODE) extern curl_wcsdup_callback Curl_cwcsdup; #endif #ifndef CURLDEBUG /* * libcurl's 'memory tracking' system defines strdup, malloc, calloc, * realloc and free, along with others, in memdebug.h in a different * way although still using memory callbacks forward declared above. * When using the 'memory tracking' system (CURLDEBUG defined) we do * not define here the five memory functions given that definitions * from memdebug.h are the ones that shall be used. */ #undef strdup #define strdup(ptr) Curl_cstrdup(ptr) #undef malloc #define malloc(size) Curl_cmalloc(size) #undef calloc #define calloc(nbelem,size) Curl_ccalloc(nbelem, size) #undef realloc #define realloc(ptr,size) Curl_crealloc(ptr, size) #undef free #define free(ptr) Curl_cfree(ptr) #ifdef WIN32 # ifdef UNICODE # undef wcsdup # define wcsdup(ptr) Curl_cwcsdup(ptr) # undef _wcsdup # define _wcsdup(ptr) Curl_cwcsdup(ptr) # undef _tcsdup # define _tcsdup(ptr) Curl_cwcsdup(ptr) # else # undef _tcsdup # define _tcsdup(ptr) Curl_cstrdup(ptr) # endif #endif #endif /* CURLDEBUG */ #else /* CURLX_NO_MEMORY_CALLBACKS */ #ifndef MEMDEBUG_NODEFINES #define MEMDEBUG_NODEFINES #endif #endif /* CURLX_NO_MEMORY_CALLBACKS */ #endif /* HEADER_CURL_MEMORY_H */ davix-0.8.0/deps/curl/lib/timeval.h0000644000000000000000000000411014121063461015602 0ustar rootroot#ifndef HEADER_CURL_TIMEVAL_H #define HEADER_CURL_TIMEVAL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* Use a larger type even for 32 bit time_t systems so that we can keep microsecond accuracy in it */ typedef curl_off_t timediff_t; #define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T #define TIMEDIFF_T_MAX CURL_OFF_T_MAX #define TIMEDIFF_T_MIN CURL_OFF_T_MIN struct curltime { time_t tv_sec; /* seconds */ int tv_usec; /* microseconds */ }; struct curltime Curl_now(void); /* * Make sure that the first argument (t1) is the more recent time and t2 is * the older time, as otherwise you get a weird negative time-diff back... * * Returns: the time difference in number of milliseconds. */ timediff_t Curl_timediff(struct curltime t1, struct curltime t2); /* * Make sure that the first argument (t1) is the more recent time and t2 is * the older time, as otherwise you get a weird negative time-diff back... * * Returns: the time difference in number of microseconds. */ timediff_t Curl_timediff_us(struct curltime newer, struct curltime older); #endif /* HEADER_CURL_TIMEVAL_H */ davix-0.8.0/deps/curl/lib/config-win32.h0000644000000000000000000005524614121063461016366 0ustar rootroot#ifndef HEADER_CURL_CONFIG_WIN32_H #define HEADER_CURL_CONFIG_WIN32_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for Windows */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ /* Define if you have the header file. */ /* #define HAVE_ARPA_INET_H 1 */ /* Define if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define if you have the header file. */ /* #define HAVE_CRYPTO_H 1 */ /* Define if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define if you have the header file. */ /* #define HAVE_ERR_H 1 */ /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ #if defined(__MINGW32__) || defined(__POCC__) #define HAVE_GETOPT_H 1 #endif /* Define to 1 if you have the header file. */ #if defined(_MSC_VER) && (_MSC_VER >= 1800) #define HAVE_INTTYPES_H 1 #endif /* Define if you have the header file. */ #define HAVE_IO_H 1 /* Define if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define if you need header even with header file. */ #if !defined(__SALFORDC__) && !defined(__POCC__) #define NEED_MALLOC_H 1 #endif /* Define if you have the header file. */ /* #define HAVE_NETDB_H 1 */ /* Define if you have the header file. */ /* #define HAVE_NETINET_IN_H 1 */ /* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_PROCESS_H 1 #endif /* Define if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define if you have the header file. */ /* #define HAVE_SGTTY_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SSL_H 1 */ /* Define to 1 if you have the header file. */ #if defined(_MSC_VER) && (_MSC_VER >= 1800) #define HAVE_STDBOOL_H 1 #endif /* Define if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define if you have the header file. */ /* #define HAVE_SYS_PARAM_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SELECT_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SOCKET_H 1 */ /* Define if you have the header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ /* Define if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define if you have the header file. */ /* #define HAVE_SYS_TIME_H 1 */ /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define if you have the header file. */ #ifndef __BORLANDC__ #define HAVE_SYS_UTIME_H 1 #endif /* Define if you have the header file. */ /* #define HAVE_TERMIO_H 1 */ /* Define if you have the header file. */ /* #define HAVE_TERMIOS_H 1 */ /* Define if you have the header file. */ #define HAVE_TIME_H 1 /* Define if you have the header file. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ defined(__POCC__) #define HAVE_UNISTD_H 1 #endif /* Define if you have the header file. */ #define HAVE_WINDOWS_H 1 /* Define if you have the header file. */ #define HAVE_WINSOCK_H 1 /* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_WINSOCK2_H 1 #endif /* Define if you have the header file. */ #ifndef __SALFORDC__ #define HAVE_WS2TCPIP_H 1 #endif /* ---------------------------------------------------------------- */ /* OTHER HEADER INFO */ /* ---------------------------------------------------------------- */ /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ /* #define TIME_WITH_SYS_TIME 1 */ /* Define to 1 if bool is an available type. */ #if defined(_MSC_VER) && (_MSC_VER >= 1800) #define HAVE_BOOL_T 1 #endif /* ---------------------------------------------------------------- */ /* FUNCTIONS */ /* ---------------------------------------------------------------- */ /* Define if you have the closesocket function. */ #define HAVE_CLOSESOCKET 1 /* Define if you don't have vprintf but do have _doprnt. */ /* #define HAVE_DOPRNT 1 */ /* Define if you have the ftruncate function. */ #define HAVE_FTRUNCATE 1 /* Define to 1 if you have the `getpeername' function. */ #define HAVE_GETPEERNAME 1 /* Define to 1 if you have the getsockname function. */ #define HAVE_GETSOCKNAME 1 /* Define if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 /* Define if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 /* Define if you have the getpass function. */ /* #define HAVE_GETPASS 1 */ /* Define if you have the getservbyname function. */ #define HAVE_GETSERVBYNAME 1 /* Define if you have the getprotobyname function. */ #define HAVE_GETPROTOBYNAME /* Define if you have the gettimeofday function. */ /* #define HAVE_GETTIMEOFDAY 1 */ /* Define if you have the inet_addr function. */ #define HAVE_INET_ADDR 1 /* Define if you have the ioctlsocket function. */ #define HAVE_IOCTLSOCKET 1 /* Define if you have a working ioctlsocket FIONBIO function. */ #define HAVE_IOCTLSOCKET_FIONBIO 1 /* Define if you have the perror function. */ #define HAVE_PERROR 1 /* Define if you have the RAND_screen function when using SSL. */ #define HAVE_RAND_SCREEN 1 /* Define if you have the `RAND_status' function when using SSL. */ #define HAVE_RAND_STATUS 1 /* Define if you have the `CRYPTO_cleanup_all_ex_data' function. This is present in OpenSSL versions after 0.9.6b */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 /* Define if you have the select function. */ #define HAVE_SELECT 1 /* Define if you have the setlocale function. */ #define HAVE_SETLOCALE 1 /* Define if you have the setmode function. */ #define HAVE_SETMODE 1 /* Define if you have the setvbuf function. */ #define HAVE_SETVBUF 1 /* Define if you have the socket function. */ #define HAVE_SOCKET 1 /* Define if you have the strcasecmp function. */ /* #define HAVE_STRCASECMP 1 */ /* Define if you have the strdup function. */ #define HAVE_STRDUP 1 /* Define if you have the strftime function. */ #define HAVE_STRFTIME 1 /* Define if you have the stricmp function. */ #define HAVE_STRICMP 1 /* Define if you have the strncasecmp function. */ /* #define HAVE_STRNCASECMP 1 */ /* Define if you have the strnicmp function. */ #define HAVE_STRNICMP 1 /* Define if you have the strstr function. */ #define HAVE_STRSTR 1 /* Define if you have the strtoll function. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) || \ (defined(_MSC_VER) && (_MSC_VER >= 1800)) #define HAVE_STRTOLL 1 #endif /* Define if you have the tcgetattr function. */ /* #define HAVE_TCGETATTR 1 */ /* Define if you have the tcsetattr function. */ /* #define HAVE_TCSETATTR 1 */ /* Define if you have the utime function. */ #ifndef __BORLANDC__ #define HAVE_UTIME 1 #endif /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 DWORD /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 int /* Define if you have the recv function. */ #define HAVE_RECV 1 /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 SOCKET /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 char * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 int /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV int /* Define if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 SOCKET /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 char /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 int /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 int /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV int /* Define if you have the send function. */ #define HAVE_SEND 1 /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 SOCKET /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 const /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 char * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 int /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV int /* ---------------------------------------------------------------- */ /* TYPEDEF REPLACEMENTS */ /* ---------------------------------------------------------------- */ /* Define if in_addr_t is not an available 'typedefed' type. */ #define in_addr_t unsigned long /* Define to the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define if ssize_t is not an available 'typedefed' type. */ #ifndef _SSIZE_T_DEFINED # if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ defined(__POCC__) || \ defined(__MINGW32__) # elif defined(_WIN64) # define _SSIZE_T_DEFINED # define ssize_t __int64 # else # define _SSIZE_T_DEFINED # define ssize_t int # endif #endif /* ---------------------------------------------------------------- */ /* TYPE SIZES */ /* ---------------------------------------------------------------- */ /* Define to the size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* Define to the size of `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 16 /* Define to the size of `long long', as computed by sizeof. */ /* #define SIZEOF_LONG_LONG 8 */ /* Define to the size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* Define to the size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* Define to the size of `size_t', as computed by sizeof. */ #if defined(_WIN64) # define SIZEOF_SIZE_T 8 #else # define SIZEOF_SIZE_T 4 #endif /* Define to the size of `curl_off_t', as computed by sizeof. */ #define SIZEOF_CURL_OFF_T 8 /* ---------------------------------------------------------------- */ /* BSD-style lwIP TCP/IP stack SPECIFIC */ /* ---------------------------------------------------------------- */ /* Define to use BSD-style lwIP TCP/IP stack. */ /* #define USE_LWIPSOCK 1 */ #ifdef USE_LWIPSOCK # undef USE_WINSOCK # undef HAVE_WINSOCK_H # undef HAVE_WINSOCK2_H # undef HAVE_WS2TCPIP_H # undef HAVE_ERRNO_H # undef HAVE_GETHOSTNAME # undef HAVE_GETNAMEINFO # undef LWIP_POSIX_SOCKETS_IO_NAMES # undef RECV_TYPE_ARG1 # undef RECV_TYPE_ARG3 # undef SEND_TYPE_ARG1 # undef SEND_TYPE_ARG3 # define HAVE_FREEADDRINFO # define HAVE_GETADDRINFO # define HAVE_GETHOSTBYNAME # define HAVE_GETHOSTBYNAME_R # define HAVE_GETHOSTBYNAME_R_6 # define LWIP_POSIX_SOCKETS_IO_NAMES 0 # define RECV_TYPE_ARG1 int # define RECV_TYPE_ARG3 size_t # define SEND_TYPE_ARG1 int # define SEND_TYPE_ARG3 size_t #endif /* ---------------------------------------------------------------- */ /* Watt-32 tcp/ip SPECIFIC */ /* ---------------------------------------------------------------- */ #ifdef USE_WATT32 #include #undef byte #undef word #undef USE_WINSOCK #undef HAVE_WINSOCK_H #undef HAVE_WINSOCK2_H #undef HAVE_WS2TCPIP_H #define HAVE_GETADDRINFO #define HAVE_GETNAMEINFO #define HAVE_SYS_IOCTL_H #define HAVE_SYS_SOCKET_H #define HAVE_NETINET_IN_H #define HAVE_NETDB_H #define HAVE_ARPA_INET_H #define HAVE_FREEADDRINFO #define SOCKET int #endif /* ---------------------------------------------------------------- */ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ /* Define to nothing if compiler does not support 'const' qualifier. */ /* #define const */ /* Define to nothing if compiler does not support 'volatile' qualifier. */ /* #define volatile */ /* Windows should not have HAVE_GMTIME_R defined */ /* #undef HAVE_GMTIME_R */ /* Define if the compiler supports C99 variadic macro style. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define HAVE_VARIADIC_MACROS_C99 1 #endif /* Define if the compiler supports the 'long long' data type. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || \ (defined(_MSC_VER) && (_MSC_VER >= 1310)) || \ (defined(__BORLANDC__) && (__BORLANDC__ >= 0x561)) #define HAVE_LONGLONG 1 #endif /* Define to avoid VS2005 complaining about portable C functions. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif /* VS2005 and later default size for time_t is 64-bit, unless _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) # ifndef _USE_32BIT_TIME_T # define SIZEOF_TIME_T 8 # else # define SIZEOF_TIME_T 4 # endif #endif /* Define some minimum and default build targets for Visual Studio */ #if defined(_MSC_VER) /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows 2000 as a supported build target. VS2008 default installations provides an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a valid build target for VS2008. Popular belief is that binaries built with VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target are functional. */ # define VS2008_MIN_TARGET 0x0500 /* The minimum build target for VS2012 is Vista unless Update 1 is installed and the v110_xp toolset is chosen. */ # if defined(_USING_V110_SDK71_) # define VS2012_MIN_TARGET 0x0501 # else # define VS2012_MIN_TARGET 0x0600 # endif /* VS2008 default build target is Windows Vista. We override default target to be Windows XP. */ # define VS2008_DEF_TARGET 0x0501 /* VS2012 default build target is Windows Vista unless Update 1 is installed and the v110_xp toolset is chosen. */ # if defined(_USING_V110_SDK71_) # define VS2012_DEF_TARGET 0x0501 # else # define VS2012_DEF_TARGET 0x0600 # endif #endif /* VS2008 default target settings and minimum build target check. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600) # ifndef _WIN32_WINNT # define _WIN32_WINNT VS2008_DEF_TARGET # endif # ifndef WINVER # define WINVER VS2008_DEF_TARGET # endif # if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) # error VS2008 does not support Windows build targets prior to Windows 2000 # endif #endif /* VS2012 default target settings and minimum build target check. */ #if defined(_MSC_VER) && (_MSC_VER >= 1700) # ifndef _WIN32_WINNT # define _WIN32_WINNT VS2012_DEF_TARGET # endif # ifndef WINVER # define WINVER VS2012_DEF_TARGET # endif # if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) # if defined(_USING_V110_SDK71_) # error VS2012 does not support Windows build targets prior to Windows XP # else # error VS2012 does not support Windows build targets prior to Windows \ Vista # endif # endif #endif /* When no build target is specified Pelles C 5.00 and later default build target is Windows Vista. We override default target to be Windows 2000. */ #if defined(__POCC__) && (__POCC__ >= 500) # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0500 # endif # ifndef WINVER # define WINVER 0x0500 # endif #endif /* Availability of freeaddrinfo, getaddrinfo, getnameinfo and if_nametoindex functions is quite convoluted, compiler dependent and even build target dependent. */ #if defined(HAVE_WS2TCPIP_H) # if defined(__POCC__) # define HAVE_FREEADDRINFO 1 # define HAVE_GETADDRINFO 1 # define HAVE_GETADDRINFO_THREADSAFE 1 # define HAVE_GETNAMEINFO 1 # elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) # define HAVE_FREEADDRINFO 1 # define HAVE_GETADDRINFO 1 # define HAVE_GETADDRINFO_THREADSAFE 1 # define HAVE_GETNAMEINFO 1 # elif defined(_MSC_VER) && (_MSC_VER >= 1200) # define HAVE_FREEADDRINFO 1 # define HAVE_GETADDRINFO 1 # define HAVE_GETADDRINFO_THREADSAFE 1 # define HAVE_GETNAMEINFO 1 # endif #endif #if defined(__POCC__) # ifndef _MSC_VER # error Microsoft extensions /Ze compiler option is required # endif # ifndef __POCC__OLDNAMES # error Compatibility names /Go compiler option is required # endif #endif /* ---------------------------------------------------------------- */ /* STRUCT RELATED */ /* ---------------------------------------------------------------- */ /* Define if you have struct sockaddr_storage. */ #if !defined(__SALFORDC__) && !defined(__BORLANDC__) #define HAVE_STRUCT_SOCKADDR_STORAGE 1 #endif /* Define if you have struct timeval. */ #define HAVE_STRUCT_TIMEVAL 1 /* Define if struct sockaddr_in6 has the sin6_scope_id member. */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 #if defined(HAVE_WINSOCK2_H) && defined(_WIN32_WINNT) && \ (_WIN32_WINNT >= 0x0600) #define HAVE_STRUCT_POLLFD 1 #endif /* ---------------------------------------------------------------- */ /* LARGE FILE SUPPORT */ /* ---------------------------------------------------------------- */ #if defined(_MSC_VER) && !defined(_WIN32_WCE) # if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) # define USE_WIN32_LARGE_FILES # else # define USE_WIN32_SMALL_FILES # endif #endif #if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES) # define USE_WIN32_LARGE_FILES #endif #if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES) # define USE_WIN32_LARGE_FILES #endif #if defined(__POCC__) # undef USE_WIN32_LARGE_FILES #endif #if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) # define USE_WIN32_SMALL_FILES #endif /* ---------------------------------------------------------------- */ /* DNS RESOLVER SPECIALTY */ /* ---------------------------------------------------------------- */ /* * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. */ /* Define to enable c-ares asynchronous DNS lookups. */ /* #define USE_ARES 1 */ /* Default define to enable threaded asynchronous DNS lookups. */ #if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \ !defined(USE_THREADS_WIN32) # define USE_THREADS_WIN32 1 #endif #if defined(USE_ARES) && defined(USE_THREADS_WIN32) # error "Only one DNS lookup specialty may be defined at most" #endif /* ---------------------------------------------------------------- */ /* LDAP SUPPORT */ /* ---------------------------------------------------------------- */ #if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK) #undef USE_WIN32_LDAP #define HAVE_LDAP_SSL_H 1 #define HAVE_LDAP_URL_PARSE 1 #elif defined(CURL_HAS_OPENLDAP_LDAPSDK) #undef USE_WIN32_LDAP #define HAVE_LDAP_URL_PARSE 1 #else #undef HAVE_LDAP_URL_PARSE #define HAVE_LDAP_SSL 1 #define USE_WIN32_LDAP 1 #endif #if defined(__WATCOMC__) && defined(USE_WIN32_LDAP) #if __WATCOMC__ < 1280 #define WINBERAPI __declspec(cdecl) #define WINLDAPAPI __declspec(cdecl) #endif #endif #if defined(__POCC__) && defined(USE_WIN32_LDAP) # define CURL_DISABLE_LDAP 1 #endif /* Define to use the Windows crypto library. */ #if !defined(CURL_WINDOWS_APP) #define USE_WIN32_CRYPTO #endif /* Define to use Unix sockets. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) /* sdkddkver.h first shipped with Platform SDK v6.0A included with VS2008 */ #include #if defined(NTDDI_WIN10_RS4) #define USE_UNIX_SOCKETS #endif #endif /* ---------------------------------------------------------------- */ /* ADDITIONAL DEFINITIONS */ /* ---------------------------------------------------------------- */ /* Define cpu-machine-OS */ #undef OS #if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */ #define OS "i386-pc-win32" #elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */ #define OS "x86_64-pc-win32" #elif defined(_M_IA64) || defined(__ia64__) /* Itanium */ #define OS "ia64-pc-win32" #elif defined(_M_ARM_NT) || defined(__arm__) /* ARMv7-Thumb2 (Windows RT) */ #define OS "thumbv7a-pc-win32" #elif defined(_M_ARM64) || defined(__aarch64__) /* ARM64 (Windows 10) */ #define OS "aarch64-pc-win32" #else #define OS "unknown-pc-win32" #endif /* Name of package */ #define PACKAGE "curl" /* If you want to build curl with the built-in manual */ #define USE_MANUAL 1 #if defined(__POCC__) || defined(USE_IPV6) # define ENABLE_IPV6 1 #endif #endif /* HEADER_CURL_CONFIG_WIN32_H */ davix-0.8.0/deps/curl/lib/strtok.c0000644000000000000000000000420014121063461015462 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef HAVE_STRTOK_R #include #include "strtok.h" char * Curl_strtok_r(char *ptr, const char *sep, char **end) { if(!ptr) /* we got NULL input so then we get our last position instead */ ptr = *end; /* pass all letters that are including in the separator string */ while(*ptr && strchr(sep, *ptr)) ++ptr; if(*ptr) { /* so this is where the next piece of string starts */ char *start = ptr; /* set the end pointer to the first byte after the start */ *end = start + 1; /* scan through the string to find where it ends, it ends on a null byte or a character that exists in the separator string */ while(**end && !strchr(sep, **end)) ++*end; if(**end) { /* the end is not a null byte */ **end = '\0'; /* zero terminate it! */ ++*end; /* advance the last pointer to beyond the null byte */ } return start; /* return the position where the string starts */ } /* we ended up on a null byte, there are no more strings to find! */ return NULL; } #endif /* this was only compiled if strtok_r wasn't present */ davix-0.8.0/deps/curl/lib/curl_des.c0000644000000000000000000000400214121063461015734 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2015 - 2019, Steve Holme, . * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_NTLM) && !defined(USE_OPENSSL) #include "curl_des.h" /* * Curl_des_set_odd_parity() * * This is used to apply odd parity to the given byte array. It is typically * used by when a cryptography engines doesn't have it's own version. * * The function is a port of the Java based oddParity() function over at: * * https://davenport.sourceforge.io/ntlm.html * * Parameters: * * bytes [in/out] - The data whose parity bits are to be adjusted for * odd parity. * len [out] - The length of the data. */ void Curl_des_set_odd_parity(unsigned char *bytes, size_t len) { size_t i; for(i = 0; i < len; i++) { unsigned char b = bytes[i]; bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1)) & 0x01) == 0; if(needs_parity) bytes[i] |= 0x01; else bytes[i] &= 0xfe; } } #endif /* USE_NTLM && !USE_OPENSSL */ davix-0.8.0/deps/curl/lib/vtls/0000755000000000000000000000000014121063461014764 5ustar rootrootdavix-0.8.0/deps/curl/lib/vtls/openssl.h0000644000000000000000000000247714121063461016632 0ustar rootroot#ifndef HEADER_CURL_SSLUSE_H #define HEADER_CURL_SSLUSE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_OPENSSL /* * This header should only be needed to get included by vtls.c and openssl.c */ #include "urldata.h" extern const struct Curl_ssl Curl_ssl_openssl; #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ davix-0.8.0/deps/curl/lib/vtls/mesalink.h0000644000000000000000000000243514121063461016744 0ustar rootroot#ifndef HEADER_CURL_MESALINK_H #define HEADER_CURL_MESALINK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2017-2018, Yiming Jing, * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_MESALINK extern const struct Curl_ssl Curl_ssl_mesalink; #endif /* USE_MESALINK */ #endif /* HEADER_CURL_MESALINK_H */ davix-0.8.0/deps/curl/lib/vtls/gtls.c0000644000000000000000000016165214121063461016114 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. * * Note: don't use the GnuTLS' *_t variable type names in this source code, * since they were not present in 1.0.X. */ #include "curl_setup.h" #ifdef USE_GNUTLS #include #include #include #ifdef USE_GNUTLS_NETTLE #include #include #include #else #include #endif #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "gtls.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "strcase.h" #include "warnless.h" #include "x509asn1.h" #include "multiif.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* Enable GnuTLS debugging by defining GTLSDEBUG */ /*#define GTLSDEBUG */ #ifdef GTLSDEBUG static void tls_log_func(int level, const char *str) { fprintf(stderr, "|<%d>| %s", level, str); } #endif static bool gtls_inited = FALSE; #if defined(GNUTLS_VERSION_NUMBER) # if (GNUTLS_VERSION_NUMBER >= 0x020c00) # undef gnutls_transport_set_lowat # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt # define USE_GNUTLS_PRIORITY_SET_DIRECT 1 # endif # if (GNUTLS_VERSION_NUMBER >= 0x020c03) # define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif # if HAVE_GNUTLS_ALPN_SET_PROTOCOLS # define HAS_ALPN # endif # if HAVE_GNUTLS_OCSP_REQ_INIT # define HAS_OCSP # endif # if (GNUTLS_VERSION_NUMBER >= 0x030306) # define HAS_CAPATH # endif #endif #if (GNUTLS_VERSION_NUMBER >= 0x030603) #define HAS_TLS13 #endif #ifdef HAS_OCSP # include #endif struct ssl_backend_data { gnutls_session_t session; gnutls_certificate_credentials_t cred; #ifdef USE_TLS_SRP gnutls_srp_client_credentials_t srp_client_cred; #endif }; #define BACKEND connssl->backend /* * Custom push and pull callback functions used by GNU TLS to read and write * to the socket. These functions are simple wrappers to send() and recv() * (although here using the sread/swrite macros as defined by * curl_setup_once.h). * We use custom functions rather than the GNU TLS defaults because it allows * us to get specific about the fourth "flags" argument, and to use arbitrary * private data with gnutls_transport_set_ptr if we wish. * * When these custom push and pull callbacks fail, GNU TLS checks its own * session-specific error variable, and when not set also its own global * errno variable, in order to take appropriate action. GNU TLS does not * require that the transport is actually a socket. This implies that for * Windows builds these callbacks should ideally set the session-specific * error variable using function gnutls_transport_set_errno or as a last * resort global errno variable using gnutls_transport_set_global_errno, * with a transport agnostic error value. This implies that some winsock * error translation must take place in these callbacks. * * Paragraph above applies to GNU TLS versions older than 2.12.3, since * this version GNU TLS does its own internal winsock error translation * using system_errno() function. */ #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) # define gtls_EINTR 4 # define gtls_EIO 5 # define gtls_EAGAIN 11 static int gtls_mapped_sockerrno(void) { switch(SOCKERRNO) { case WSAEWOULDBLOCK: return gtls_EAGAIN; case WSAEINTR: return gtls_EINTR; default: break; } return gtls_EIO; } #endif static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = swrite(sock, buf, len); #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif return ret; } static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) { curl_socket_t sock = *(curl_socket_t *)s; ssize_t ret = sread(sock, buf, len); #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) if(ret < 0) gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); #endif return ret; } static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len) { return gnutls_record_send((gnutls_session_t) s, buf, len); } static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) { return gnutls_record_recv((gnutls_session_t) s, buf, len); } /* Curl_gtls_init() * * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that * are not thread-safe and thus this function itself is not thread-safe and * must only be called from within curl_global_init() to keep the thread * situation under control! */ static int Curl_gtls_init(void) { int ret = 1; if(!gtls_inited) { ret = gnutls_global_init()?0:1; #ifdef GTLSDEBUG gnutls_global_set_log_function(tls_log_func); gnutls_global_set_log_level(2); #endif gtls_inited = TRUE; } return ret; } static void Curl_gtls_cleanup(void) { if(gtls_inited) { gnutls_global_deinit(); gtls_inited = FALSE; } } #ifndef CURL_DISABLE_VERBOSE_STRINGS static void showtime(struct Curl_easy *data, const char *text, time_t stamp) { struct tm buffer; const struct tm *tm = &buffer; char str[96]; CURLcode result = Curl_gmtime(stamp, &buffer); if(result) return; msnprintf(str, sizeof(str), "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", text, Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, Curl_month[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); infof(data, "%s\n", str); } #endif static gnutls_datum_t load_file(const char *file) { FILE *f; gnutls_datum_t loaded_file = { NULL, 0 }; long filelen; void *ptr; f = fopen(file, "rb"); if(!f) return loaded_file; if(fseek(f, 0, SEEK_END) != 0 || (filelen = ftell(f)) < 0 || fseek(f, 0, SEEK_SET) != 0 || !(ptr = malloc((size_t)filelen))) goto out; if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { free(ptr); goto out; } loaded_file.data = ptr; loaded_file.size = (unsigned int)filelen; out: fclose(f); return loaded_file; } static void unload_file(gnutls_datum_t data) { free(data.data); } /* this function does a SSL/TLS (re-)handshake */ static CURLcode handshake(struct connectdata *conn, int sockindex, bool duringconnect, bool nonblocking) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gnutls_session_t session = BACKEND->session; curl_socket_t sockfd = conn->sock[sockindex]; for(;;) { timediff_t timeout_ms; int rc; /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, duringconnect); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { int what; curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: timeout_ms?(time_t)timeout_ms:1000); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) return CURLE_OK; else if(timeout_ms) { /* timeout */ failf(data, "SSL connection timeout at %ld", (long)timeout_ms); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } rc = gnutls_handshake(session); if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { connssl->connecting_state = gnutls_record_get_direction(session)? ssl_connect_2_writing:ssl_connect_2_reading; continue; } else if((rc < 0) && !gnutls_error_is_fatal(rc)) { const char *strerr = NULL; if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { int alert = gnutls_alert_get(session); strerr = gnutls_alert_get_name(alert); } if(strerr == NULL) strerr = gnutls_strerror(rc); infof(data, "gnutls_handshake() warning: %s\n", strerr); continue; } else if(rc < 0) { const char *strerr = NULL; if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { int alert = gnutls_alert_get(session); strerr = gnutls_alert_get_name(alert); } if(strerr == NULL) strerr = gnutls_strerror(rc); failf(data, "gnutls_handshake() failed: %s", strerr); return CURLE_SSL_CONNECT_ERROR; } /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } } static gnutls_x509_crt_fmt_t do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; if(strcasecompare(type, "PEM")) return GNUTLS_X509_FMT_PEM; if(strcasecompare(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static CURLcode set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) { struct Curl_easy *data = conn->data; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long i = ssl_version; long protocol_priority_idx = 0; switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: #ifdef HAS_TLS13 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; #endif ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; break; } for(; i <= (ssl_version_max >> 16) && protocol_priority_idx < list_size; ++i) { switch(i) { case CURL_SSLVERSION_TLSv1_0: protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; break; case CURL_SSLVERSION_TLSv1_1: protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; break; case CURL_SSLVERSION_TLSv1_2: protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_TLSv1_3: #ifdef HAS_TLS13 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3; break; #else failf(data, "GnuTLS: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; #endif } } return CURLE_OK; } #else #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" /* If GnuTLS was compiled without support for SRP it will error out if SRP is requested in the priority string, so treat it specially */ #define GNUTLS_SRP "+SRP" static CURLcode set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) { struct Curl_easy *data = conn->data; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; } switch(ssl_version | ssl_version_max) { case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.1:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: #ifdef HAS_TLS13 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.3:" GNUTLS_SRP; return CURLE_OK; #else failf(data, "GnuTLS: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; #endif case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" #ifdef HAS_TLS13 "+VERS-TLS1.3:" #endif GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.1:+VERS-TLS1.2:" #ifdef HAS_TLS13 "+VERS-TLS1.3:" #endif GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" #ifdef HAS_TLS13 "+VERS-TLS1.3:" #endif GNUTLS_SRP; return CURLE_OK; case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" #ifdef HAS_TLS13 "+VERS-TLS1.3:" #endif GNUTLS_SRP; return CURLE_OK; } failf(data, "GnuTLS: cannot set ssl protocol"); return CURLE_SSL_CONNECT_ERROR; } #endif static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned int init_flags; gnutls_session_t session; int rc; bool sni = TRUE; /* default is SNI enabled */ void *transport_ptr = NULL; gnutls_push_func gnutls_transport_push = NULL; gnutls_pull_func gnutls_transport_pull = NULL; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static const int cipher_priority[] = { /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, but this code path is only ever used for ver. < 2.12.0. GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_256_GCM, */ GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_CIPHER_3DES_CBC, }; static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; int protocol_priority[] = { 0, 0, 0, 0 }; #else const char *prioritylist; const char *err = NULL; #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; if(!gtls_inited) Curl_gtls_init(); if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&BACKEND->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #ifdef USE_TLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( &BACKEND->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_OUT_OF_MEMORY; } rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, SSL_SET_OPTION(username), SSL_SET_OPTION(password)); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_BAD_FUNCTION_ARGUMENT; } } #endif if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(BACKEND->cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, SSL_CONN_CONFIG(CAfile)); } #ifdef HAS_CAPATH if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, SSL_CONN_CONFIG(CApath), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, SSL_CONN_CONFIG(CApath)); } #endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ if(SSL_CONN_CONFIG(verifypeer) && !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { gnutls_certificate_set_x509_system_trust(BACKEND->cred); } #endif if(SSL_SET_OPTION(CRLfile)) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)", SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } else infof(data, "found %d CRL in %s\n", rc, SSL_SET_OPTION(CRLfile)); } /* Initialize TLS session as a client */ init_flags = GNUTLS_CLIENT; #if defined(GNUTLS_FORCE_CLIENT_CERT) init_flags |= GNUTLS_FORCE_CLIENT_CERT; #endif #if defined(GNUTLS_NO_TICKETS) /* Disable TLS session tickets */ init_flags |= GNUTLS_NO_TICKETS; #endif rc = gnutls_init(&BACKEND->session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ session = BACKEND->session; if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); /* Use default priorities */ rc = gnutls_set_default_priority(session); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT rc = gnutls_cipher_set_priority(session, cipher_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; if(SSL_CONN_CONFIG(cipher_list) != NULL) { failf(data, "can't pass a custom cipher list to older GnuTLS" " versions"); return CURLE_SSL_CONNECT_ERROR; } switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: protocol_priority[0] = GNUTLS_TLS1_0; protocol_priority[1] = GNUTLS_TLS1_1; protocol_priority[2] = GNUTLS_TLS1_2; #ifdef HAS_TLS13 protocol_priority[3] = GNUTLS_TLS1_3; #endif break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { CURLcode result = set_ssl_version_min_max(protocol_priority, sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); if(result != CURLE_OK) return result; break; } case CURL_SSLVERSION_SSLv2: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } rc = gnutls_protocol_set_priority(session, protocol_priority); if(rc != GNUTLS_E_SUCCESS) { failf(data, "Did you pass a valid GnuTLS cipher list?"); return CURLE_SSL_CONNECT_ERROR; } #else /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" #ifdef HAS_TLS13 "+VERS-TLS1.3:" #endif GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { CURLcode result = set_ssl_version_min_max(&prioritylist, conn); if(result != CURLE_OK) return result; break; } case CURL_SSLVERSION_SSLv2: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } rc = gnutls_priority_set_direct(session, prioritylist, &err); if((rc == GNUTLS_E_INVALID_REQUEST) && err) { if(!strcmp(err, GNUTLS_SRP)) { /* This GnuTLS was probably compiled without support for SRP. * Note that fact and try again without it. */ int validprioritylen = curlx_uztosi(err - prioritylist); char *prioritycopy = strdup(prioritylist); if(!prioritycopy) return CURLE_OUT_OF_MEMORY; infof(data, "This GnuTLS does not support SRP\n"); if(validprioritylen) /* Remove the :+SRP */ prioritycopy[validprioritylen - 1] = 0; rc = gnutls_priority_set_direct(session, prioritycopy, &err); free(prioritycopy); } } if(rc != GNUTLS_E_SUCCESS) { failf(data, "Error %d setting GnuTLS cipher list starting with %s", rc, err); return CURLE_SSL_CONNECT_ERROR; } #endif #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; cur++; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; protocols[cur].size = ALPN_HTTP_1_1_LENGTH; cur++; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); gnutls_alpn_set_protocols(session, protocols, cur, 0); } #endif if(SSL_SET_OPTION(cert)) { if(SSL_SET_OPTION(key_passwd)) { #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( BACKEND->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), do_file_type(SSL_SET_OPTION(cert_type)), SSL_SET_OPTION(key_passwd), supported_key_encryption_algorithms); if(rc != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 potentially-encrypted key file: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #else failf(data, "gnutls lacks support for encrypted key files"); return CURLE_SSL_CONNECT_ERROR; #endif } else { if(gnutls_certificate_set_x509_key_file( BACKEND->cred, SSL_SET_OPTION(cert), SSL_SET_OPTION(key) ? SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), do_file_type(SSL_SET_OPTION(cert_type)) ) != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } } } #ifdef USE_TLS_SRP /* put the credentials to the current session */ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, BACKEND->srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } else #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, BACKEND->cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } if(conn->proxy_ssl[sockindex].use) { transport_ptr = conn->proxy_ssl[sockindex].backend->session; gnutls_transport_push = Curl_gtls_push_ssl; gnutls_transport_pull = Curl_gtls_pull_ssl; } else { /* file descriptor for the socket */ transport_ptr = &conn->sock[sockindex]; gnutls_transport_push = Curl_gtls_push; gnutls_transport_pull = Curl_gtls_pull; } /* set the connection handle */ gnutls_transport_set_ptr(session, transport_ptr); /* register callback functions to send and receive data. */ gnutls_transport_set_push_function(session, gnutls_transport_push); gnutls_transport_set_pull_function(session, gnutls_transport_pull); /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); #ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } } #endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid; size_t ssl_idsize; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { /* we got a session id, use it! */ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); /* Informational message */ infof(data, "SSL re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } return CURLE_OK; } static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, gnutls_x509_crt_t cert, const char *pinnedpubkey) { /* Scratch */ size_t len1 = 0, len2 = 0; unsigned char *buff1 = NULL; gnutls_pubkey_t key = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(NULL == pinnedpubkey) return CURLE_OK; if(NULL == cert) return result; do { int ret; /* Begin Gyrations to get the public key */ gnutls_pubkey_init(&key); ret = gnutls_pubkey_import_x509(key, cert, 0); if(ret < 0) break; /* failed */ ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) break; /* failed */ buff1 = malloc(len1); if(NULL == buff1) break; /* failed */ len2 = len1; ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); if(ret < 0 || len1 != len2) break; /* failed */ /* End Gyrations */ /* The one good exit point */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); if(NULL != key) gnutls_pubkey_deinit(key); Curl_safefree(buff1); return result; } static Curl_recv gtls_recv; static Curl_send gtls_send; static CURLcode gtls_connect_step3(struct connectdata *conn, int sockindex) { unsigned int cert_list_size; const gnutls_datum_t *chainp; unsigned int verify_status = 0; gnutls_x509_crt_t x509_cert, x509_issuer; gnutls_datum_t issuerp; char certbuf[256] = ""; /* big enough? */ size_t size; time_t certclock; const char *ptr; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gnutls_session_t session = BACKEND->session; int rc; #ifdef HAS_ALPN gnutls_datum_t proto; #endif CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS unsigned int algo; unsigned int bits; gnutls_protocol_t version = gnutls_protocol_get_version(session); #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), gnutls_cipher_get(session), gnutls_mac_get(session)); infof(data, "SSL connection using %s / %s\n", gnutls_protocol_get_name(version), ptr); /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for X.509). In case of a X.509 then a certificate list may be present. The first certificate in the list is the peer's certificate, following the issuer's certificate, then the issuer's issuer etc. */ chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { if(SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost) || SSL_SET_OPTION(issuercert)) { #ifdef USE_TLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP && SSL_SET_OPTION(username) != NULL && !SSL_CONN_CONFIG(verifypeer) && gnutls_cipher_get(session)) { /* no peer cert, but auth is ok if we have SRP user and cipher and no peer verify */ } else { #endif failf(data, "failed to get server cert"); return CURLE_PEER_FAILED_VERIFICATION; #ifdef USE_TLS_SRP } #endif } infof(data, "\t common name: WARNING couldn't obtain\n"); } if(data->set.ssl.certinfo && chainp) { unsigned int i; result = Curl_ssl_init_certinfo(data, cert_list_size); if(result) return result; for(i = 0; i < cert_list_size; i++) { const char *beg = (const char *) chainp[i].data; const char *end = beg + chainp[i].size; result = Curl_extract_certinfo(conn, i, beg, end); if(result) return result; } } if(SSL_CONN_CONFIG(verifypeer)) { /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise or'd. To avoid denial of service attacks some default upper limits regarding the certificate key size and chain size are set. To override them use gnutls_certificate_set_verify_limits(). */ rc = gnutls_certificate_verify_peers2(session, &verify_status); if(rc < 0) { failf(data, "server cert verify failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate verification failed. CAfile: %s " "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate verification FAILED\n"); } else infof(data, "\t server certificate verification OK\n"); } else infof(data, "\t server certificate verification SKIPPED\n"); #ifdef HAS_OCSP if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { gnutls_datum_t status_request; gnutls_ocsp_resp_t ocsp_resp; gnutls_ocsp_cert_status_t status; gnutls_x509_crl_reason_t reason; rc = gnutls_ocsp_status_request_get(session, &status_request); infof(data, "\t server certificate status verification FAILED\n"); if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { failf(data, "No OCSP response received"); return CURLE_SSL_INVALIDCERTSTATUS; } if(rc < 0) { failf(data, "Invalid OCSP response received"); return CURLE_SSL_INVALIDCERTSTATUS; } gnutls_ocsp_resp_init(&ocsp_resp); rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); if(rc < 0) { failf(data, "Invalid OCSP response received"); return CURLE_SSL_INVALIDCERTSTATUS; } (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, &status, NULL, NULL, NULL, &reason); switch(status) { case GNUTLS_OCSP_CERT_GOOD: break; case GNUTLS_OCSP_CERT_REVOKED: { const char *crl_reason; switch(reason) { default: case GNUTLS_X509_CRLREASON_UNSPECIFIED: crl_reason = "unspecified reason"; break; case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: crl_reason = "private key compromised"; break; case GNUTLS_X509_CRLREASON_CACOMPROMISE: crl_reason = "CA compromised"; break; case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: crl_reason = "affiliation has changed"; break; case GNUTLS_X509_CRLREASON_SUPERSEDED: crl_reason = "certificate superseded"; break; case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: crl_reason = "operation has ceased"; break; case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: crl_reason = "certificate is on hold"; break; case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: crl_reason = "will be removed from delta CRL"; break; case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: crl_reason = "privilege withdrawn"; break; case GNUTLS_X509_CRLREASON_AACOMPROMISE: crl_reason = "AA compromised"; break; } failf(data, "Server certificate was revoked: %s", crl_reason); break; } default: case GNUTLS_OCSP_CERT_UNKNOWN: failf(data, "Server certificate status is unknown"); break; } gnutls_ocsp_resp_deinit(ocsp_resp); return CURLE_SSL_INVALIDCERTSTATUS; } else infof(data, "\t server certificate status verification OK\n"); } else infof(data, "\t server certificate status verification SKIPPED\n"); #endif /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); if(chainp) /* convert the given DER or PEM encoded Certificate to the native gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); if(SSL_SET_OPTION(issuercert)) { gnutls_x509_crt_init(&x509_issuer); issuerp = load_file(SSL_SET_OPTION(issuercert)); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_ISSUER_ERROR; } infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } size = sizeof(certbuf); rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, 0, /* the first and only one */ FALSE, certbuf, &size); if(rc) { infof(data, "error fetching CN from cert:%s\n", gnutls_strerror(rc)); } /* This function will check if the given certificate's subject matches the given hostname. This is a basic implementation of the matching described in RFC2818 (HTTPS), which takes into account wildcards, and the subject alternative name PKIX extension. Returns non zero on success, and zero on failure. */ rc = gnutls_x509_crt_check_hostname(x509_cert, hostname); #if GNUTLS_VERSION_NUMBER < 0x030306 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP addresses. */ if(!rc) { #ifdef ENABLE_IPV6 #define use_addr in6_addr #else #define use_addr in_addr #endif unsigned char addrbuf[sizeof(struct use_addr)]; size_t addrlen = 0; if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0) addrlen = 4; #ifdef ENABLE_IPV6 else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0) addrlen = 16; #endif if(addrlen) { unsigned char certaddr[sizeof(struct use_addr)]; int i; for(i = 0; ; i++) { size_t certaddrlen = sizeof(certaddr); int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, &certaddrlen, NULL); /* If this happens, it wasn't an IP address. */ if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) continue; if(ret < 0) break; if(ret != GNUTLS_SAN_IPADDRESS) continue; if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) { rc = 1; break; } } } } #endif if(!rc) { const char * const dispname = SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname; if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "SSL: certificate subject name (%s) does not match " "target host name '%s'", certbuf, dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", certbuf, dispname); } else infof(data, "\t common name: %s (matched)\n", certbuf); /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert expiration date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } else infof(data, "\t server certificate expiration date verify FAILED\n"); } else { if(certclock < time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate expiration date has passed."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate expiration date FAILED\n"); } else infof(data, "\t server certificate expiration date OK\n"); } certclock = gnutls_x509_crt_get_activation_time(x509_cert); if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert activation date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } else infof(data, "\t server certificate activation date verify FAILED\n"); } else { if(certclock > time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate not activated yet."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t server certificate activation date FAILED\n"); } else infof(data, "\t server certificate activation date OK\n"); } ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(ptr) { result = pkp_pin_peer_pubkey(data, x509_cert, ptr); if(result != CURLE_OK) { failf(data, "SSL: public key does not match pinned public key!"); gnutls_x509_crt_deinit(x509_cert); return result; } } /* Show: - subject - start date - expire date - common name - issuer */ #ifndef CURL_DISABLE_VERBOSE_STRINGS /* public key algorithm's parameters */ algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); infof(data, "\t certificate public key: %s\n", gnutls_pk_algorithm_get_name(algo)); /* version of the X.509 certificate. */ infof(data, "\t certificate version: #%d\n", gnutls_x509_crt_get_version(x509_cert)); size = sizeof(certbuf); gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); infof(data, "\t subject: %s\n", certbuf); certclock = gnutls_x509_crt_get_activation_time(x509_cert); showtime(data, "start date", certclock); certclock = gnutls_x509_crt_get_expiration_time(x509_cert); showtime(data, "expire date", certclock); size = sizeof(certbuf); gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); infof(data, "\t issuer: %s\n", certbuf); #endif gnutls_x509_crt_deinit(x509_cert); #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { infof(data, "ALPN, server accepted to use %.*s\n", proto.size, proto.data); #ifdef USE_NGHTTP2 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(proto.size == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else infof(data, "ALPN, server did not agree to a protocol\n"); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif conn->ssl[sockindex].state = ssl_connection_complete; conn->recv[sockindex] = gtls_recv; conn->send[sockindex] = gtls_send; if(SSL_SET_OPTION(primary.sessionid)) { /* we always unconditionally get the session id here, as even if we already got it from the cache and asked to use it in the connection, it might've been rejected and then a new one is in use now and we need to detect that. */ void *connect_sessionid; size_t connect_idsize = 0; /* get the session ID data size */ gnutls_session_get_data(session, NULL, &connect_idsize); connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ if(connect_sessionid) { bool incache; void *ssl_sessionid; /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, connect_sessionid, &connect_idsize); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)); if(incache) { /* there was one before in the cache, so instead of risking that the previous one was rejected, we just kill that and store the new */ Curl_ssl_delsessionid(conn, ssl_sessionid); } /* store this session id */ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, sockindex); Curl_ssl_sessionid_unlock(conn); if(result) { free(connect_sessionid); result = CURLE_OUT_OF_MEMORY; } } else result = CURLE_OUT_OF_MEMORY; } return result; } /* * This function is called after the TCP connect has completed. Setup the TLS * layer and do all necessary magic. */ /* We use connssl->connecting_state to keep track of the connection status; there are three states: 'ssl_connect_1' (not started yet or complete), 'ssl_connect_2_reading' (waiting for data from server), and 'ssl_connect_2_writing' (waiting to be able to write). */ static CURLcode gtls_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { int rc; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* Initiate the connection, if not already done */ if(ssl_connect_1 == connssl->connecting_state) { rc = gtls_connect_step1(conn, sockindex); if(rc) return rc; } rc = handshake(conn, sockindex, TRUE, nonblocking); if(rc) /* handshake() sets its own error message with failf() */ return rc; /* Finish connecting once the handshake is done */ if(ssl_connect_1 == connssl->connecting_state) { rc = gtls_connect_step3(conn, sockindex); if(rc) return rc; } *done = ssl_connect_1 == connssl->connecting_state; return CURLE_OK; } static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return gtls_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = gtls_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; bool res = FALSE; if(BACKEND->session && 0 != gnutls_record_check_pending(BACKEND->session)) res = TRUE; connssl = &conn->proxy_ssl[connindex]; if(BACKEND->session && 0 != gnutls_record_check_pending(BACKEND->session)) res = TRUE; return res; } static ssize_t gtls_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) ? CURLE_AGAIN : CURLE_SEND_ERROR; rc = -1; } return rc; } static void close_one(struct ssl_connect_data *connssl) { if(BACKEND->session) { gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); gnutls_deinit(BACKEND->session); BACKEND->session = NULL; } if(BACKEND->cred) { gnutls_certificate_free_credentials(BACKEND->cred); BACKEND->cred = NULL; } #ifdef USE_TLS_SRP if(BACKEND->srp_client_cred) { gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); BACKEND->srp_client_cred = NULL; } #endif } static void Curl_gtls_close(struct connectdata *conn, int sockindex) { close_one(&conn->ssl[sockindex]); close_one(&conn->proxy_ssl[sockindex]); } /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; int retval = 0; struct Curl_easy *data = conn->data; #ifndef CURL_DISABLE_FTP /* This has only been tested on the proftpd server, and the mod_tls code sends a close notify alert without waiting for a close notify alert in response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); #endif if(BACKEND->session) { ssize_t result; bool done = FALSE; char buf[120]; while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ result = gnutls_record_recv(BACKEND->session, buf, sizeof(buf)); switch(result) { case 0: /* This is the expected response. There was no data but only the close notify alert */ done = TRUE; break; case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); break; default: retval = -1; done = TRUE; break; } } else if(0 == what) { /* timeout */ failf(data, "SSL shutdown timeout"); done = TRUE; } else { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); retval = -1; done = TRUE; } } gnutls_deinit(BACKEND->session); } gnutls_certificate_free_credentials(BACKEND->cred); #ifdef USE_TLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP && SSL_SET_OPTION(username) != NULL) gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); #endif BACKEND->cred = NULL; BACKEND->session = NULL; return retval; } static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; ssize_t ret; ret = gnutls_record_recv(BACKEND->session, buf, buffersize); if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { *curlcode = CURLE_AGAIN; return -1; } if(ret == GNUTLS_E_REHANDSHAKE) { /* BLOCKING call, this is bad but a work-around for now. Fixing this "the proper way" takes a whole lot of work. */ CURLcode result = handshake(conn, num, FALSE, FALSE); if(result) /* handshake() writes error message on its own */ *curlcode = result; else *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ return -1; } if(ret < 0) { failf(conn->data, "GnuTLS recv error (%d): %s", (int)ret, gnutls_strerror((int)ret)); *curlcode = CURLE_RECV_ERROR; return -1; } return ret; } static void Curl_gtls_session_free(void *ptr) { free(ptr); } static size_t Curl_gtls_version(char *buffer, size_t size) { return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } #ifndef USE_GNUTLS_NETTLE static int Curl_gtls_seed(struct Curl_easy *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ static bool ssl_seeded = FALSE; /* Quickly add a bit of entropy */ gcry_fast_random_poll(); if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || data->set.str[STRING_SSL_EGDSOCKET]) { ssl_seeded = TRUE; } return 0; } #endif /* data might be NULL! */ static CURLcode Curl_gtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { #if defined(USE_GNUTLS_NETTLE) int rc; (void)data; rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); return rc?CURLE_FAILED_INIT:CURLE_OK; #elif defined(USE_GNUTLS) if(data) Curl_gtls_seed(data); /* Initiate the seed if not already done */ gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); #endif return CURLE_OK; } static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len) { #if defined(USE_GNUTLS_NETTLE) struct md5_ctx MD5pw; md5_init(&MD5pw); md5_update(&MD5pw, (unsigned int)tmplen, tmp); md5_digest(&MD5pw, (unsigned int)md5len, md5sum); #elif defined(USE_GNUTLS) gcry_md_hd_t MD5pw; gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); gcry_md_write(MD5pw, tmp, tmplen); memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len); gcry_md_close(MD5pw); #endif return CURLE_OK; } static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len) { #if defined(USE_GNUTLS_NETTLE) struct sha256_ctx SHA256pw; sha256_init(&SHA256pw); sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); #elif defined(USE_GNUTLS) gcry_md_hd_t SHA256pw; gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); gcry_md_write(SHA256pw, tmp, tmplen); memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len); gcry_md_close(SHA256pw); #endif return CURLE_OK; } static bool Curl_gtls_cert_status_request(void) { #ifdef HAS_OCSP return TRUE; #else return FALSE; #endif } static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->session; } const struct Curl_ssl Curl_ssl_gnutls = { { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */ SSLSUPP_CA_PATH | SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY | SSLSUPP_HTTPS_PROXY, sizeof(struct ssl_backend_data), Curl_gtls_init, /* init */ Curl_gtls_cleanup, /* cleanup */ Curl_gtls_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_gtls_shutdown, /* shutdown */ Curl_gtls_data_pending, /* data_pending */ Curl_gtls_random, /* random */ Curl_gtls_cert_status_request, /* cert_status_request */ Curl_gtls_connect, /* connect */ Curl_gtls_connect_nonblocking, /* connect_nonblocking */ Curl_gtls_get_internals, /* get_internals */ Curl_gtls_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_gtls_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_gtls_md5sum, /* md5sum */ Curl_gtls_sha256sum /* sha256sum */ }; #endif /* USE_GNUTLS */ davix-0.8.0/deps/curl/lib/vtls/gskit.h0000644000000000000000000000246514121063461016265 0ustar rootroot#ifndef HEADER_CURL_GSKIT_H #define HEADER_CURL_GSKIT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* * This header should only be needed to get included by vtls.c and gskit.c */ #include "urldata.h" #ifdef USE_GSKIT extern const struct Curl_ssl Curl_ssl_gskit; #endif /* USE_GSKIT */ #endif /* HEADER_CURL_GSKIT_H */ davix-0.8.0/deps/curl/lib/vtls/bearssl.h0000644000000000000000000000231514121063461016571 0ustar rootroot#ifndef HEADER_CURL_BEARSSL_H #define HEADER_CURL_BEARSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019, Michael Forney, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_BEARSSL extern const struct Curl_ssl Curl_ssl_bearssl; #endif /* USE_BEARSSL */ #endif /* HEADER_CURL_BEARSSL_H */ davix-0.8.0/deps/curl/lib/vtls/schannel_verify.c0000644000000000000000000005517514121063461020324 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for Schannel-specific certificate verification. This code should * only be invoked by code in schannel.c. */ #include "curl_setup.h" #ifdef USE_SCHANNEL #ifndef USE_WINDOWS_SSPI # error "Can't compile SCHANNEL support without SSPI." #endif #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS #include "schannel.h" #ifdef HAS_MANUAL_VERIFY_API #include "vtls.h" #include "sendf.h" #include "strerror.h" #include "curl_multibyte.h" #include "curl_printf.h" #include "hostcheck.h" #include "system_win32.h" /* The last #include file should be: */ #include "curl_memory.h" #include "memdebug.h" #define BACKEND connssl->backend #define MAX_CAFILE_SIZE 1048576 /* 1 MiB */ #define BEGIN_CERT "-----BEGIN CERTIFICATE-----" #define END_CERT "\n-----END CERTIFICATE-----" typedef struct { DWORD cbSize; HCERTSTORE hRestrictedRoot; HCERTSTORE hRestrictedTrust; HCERTSTORE hRestrictedOther; DWORD cAdditionalStore; HCERTSTORE *rghAdditionalStore; DWORD dwFlags; DWORD dwUrlRetrievalTimeout; DWORD MaximumCachedCertificates; DWORD CycleDetectionModulus; HCERTSTORE hExclusiveRoot; HCERTSTORE hExclusiveTrustedPeople; } CERT_CHAIN_ENGINE_CONFIG_WIN7, *PCERT_CHAIN_ENGINE_CONFIG_WIN7; static int is_cr_or_lf(char c) { return c == '\r' || c == '\n'; } static CURLcode add_certs_to_store(HCERTSTORE trust_store, const char *ca_file, struct connectdata *conn) { CURLcode result; struct Curl_easy *data = conn->data; HANDLE ca_file_handle = INVALID_HANDLE_VALUE; LARGE_INTEGER file_size; char *ca_file_buffer = NULL; char *current_ca_file_ptr = NULL; TCHAR *ca_file_tstr = NULL; size_t ca_file_bufsize = 0; DWORD total_bytes_read = 0; bool more_certs = 0; int num_certs = 0; size_t END_CERT_LEN; ca_file_tstr = Curl_convert_UTF8_to_tchar((char *)ca_file); if(!ca_file_tstr) { char buffer[STRERROR_LEN]; failf(data, "schannel: invalid path name for CA file '%s': %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; goto cleanup; } /* * Read the CA file completely into memory before parsing it. This * optimizes for the common case where the CA file will be relatively * small ( < 1 MiB ). */ ca_file_handle = CreateFile(ca_file_tstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(ca_file_handle == INVALID_HANDLE_VALUE) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to open CA file '%s': %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; goto cleanup; } if(!GetFileSizeEx(ca_file_handle, &file_size)) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to determine size of CA file '%s': %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; goto cleanup; } if(file_size.QuadPart > MAX_CAFILE_SIZE) { failf(data, "schannel: CA file exceeds max size of %u bytes", MAX_CAFILE_SIZE); result = CURLE_SSL_CACERT_BADFILE; goto cleanup; } ca_file_bufsize = (size_t)file_size.QuadPart; ca_file_buffer = (char *)malloc(ca_file_bufsize + 1); if(!ca_file_buffer) { result = CURLE_OUT_OF_MEMORY; goto cleanup; } result = CURLE_OK; while(total_bytes_read < ca_file_bufsize) { DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read); DWORD bytes_read = 0; if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read, bytes_to_read, &bytes_read, NULL)) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to read from CA file '%s': %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; goto cleanup; } if(bytes_read == 0) { /* Premature EOF -- adjust the bufsize to the new value */ ca_file_bufsize = total_bytes_read; } else { total_bytes_read += bytes_read; } } /* Null terminate the buffer */ ca_file_buffer[ca_file_bufsize] = '\0'; if(result != CURLE_OK) { goto cleanup; } END_CERT_LEN = strlen(END_CERT); more_certs = 1; current_ca_file_ptr = ca_file_buffer; while(more_certs && *current_ca_file_ptr != '\0') { char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT); if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[strlen(BEGIN_CERT)])) { more_certs = 0; } else { char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT); if(!end_cert_ptr) { failf(data, "schannel: CA file '%s' is not correctly formatted", ca_file); result = CURLE_SSL_CACERT_BADFILE; more_certs = 0; } else { CERT_BLOB cert_blob; CERT_CONTEXT *cert_context = NULL; BOOL add_cert_result = FALSE; DWORD actual_content_type = 0; DWORD cert_size = (DWORD) ((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr); cert_blob.pbData = (BYTE *)begin_cert_ptr; cert_blob.cbData = cert_size; if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &cert_blob, CERT_QUERY_CONTENT_FLAG_CERT, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &actual_content_type, NULL, NULL, NULL, (const void **)&cert_context)) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to extract certificate from CA file " "'%s': %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; more_certs = 0; } else { current_ca_file_ptr = begin_cert_ptr + cert_size; /* Sanity check that the cert_context object is the right type */ if(CERT_QUERY_CONTENT_CERT != actual_content_type) { failf(data, "schannel: unexpected content type '%d' when extracting " "certificate from CA file '%s'", actual_content_type, ca_file); result = CURLE_SSL_CACERT_BADFILE; more_certs = 0; } else { add_cert_result = CertAddCertificateContextToStore(trust_store, cert_context, CERT_STORE_ADD_ALWAYS, NULL); CertFreeCertificateContext(cert_context); if(!add_cert_result) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to add certificate from CA file '%s' " "to certificate store: %s", ca_file, Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; more_certs = 0; } else { num_certs++; } } } } } } if(result == CURLE_OK) { if(!num_certs) { infof(data, "schannel: did not add any certificates from CA file '%s'\n", ca_file); } else { infof(data, "schannel: added %d certificate(s) from CA file '%s'\n", num_certs, ca_file); } } cleanup: if(ca_file_handle != INVALID_HANDLE_VALUE) { CloseHandle(ca_file_handle); } Curl_safefree(ca_file_buffer); Curl_unicodefree(ca_file_tstr); return result; } /* * Returns the number of characters necessary to populate all the host_names. * If host_names is not NULL, populate it with all the host names. Each string * in the host_names is null-terminated and the last string is double * null-terminated. If no DNS names are found, a single null-terminated empty * string is returned. */ static DWORD cert_get_name_string(struct Curl_easy *data, CERT_CONTEXT *cert_context, LPTSTR host_names, DWORD length) { DWORD actual_length = 0; BOOL compute_content = FALSE; CERT_INFO *cert_info = NULL; CERT_EXTENSION *extension = NULL; CRYPT_DECODE_PARA decode_para = {0, 0, 0}; CERT_ALT_NAME_INFO *alt_name_info = NULL; DWORD alt_name_info_size = 0; BOOL ret_val = FALSE; LPTSTR current_pos = NULL; DWORD i; /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ if(Curl_verify_windows_version(6, 2, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG /* CertGetNameString will provide the 8-bit character string without * any decoding */ DWORD name_flags = CERT_NAME_DISABLE_IE4_UTF8_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG; actual_length = CertGetNameString(cert_context, CERT_NAME_DNS_TYPE, name_flags, NULL, host_names, length); return actual_length; #endif } compute_content = host_names != NULL && length != 0; /* Initialize default return values. */ actual_length = 1; if(compute_content) { *host_names = '\0'; } if(!cert_context) { failf(data, "schannel: Null certificate context."); return actual_length; } cert_info = cert_context->pCertInfo; if(!cert_info) { failf(data, "schannel: Null certificate info."); return actual_length; } extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2, cert_info->cExtension, cert_info->rgExtension); if(!extension) { failf(data, "schannel: CertFindExtension() returned no extension."); return actual_length; } decode_para.cbSize = sizeof(CRYPT_DECODE_PARA); ret_val = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME2, extension->Value.pbData, extension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, &decode_para, &alt_name_info, &alt_name_info_size); if(!ret_val) { failf(data, "schannel: CryptDecodeObjectEx() returned no alternate name " "information."); return actual_length; } current_pos = host_names; /* Iterate over the alternate names and populate host_names. */ for(i = 0; i < alt_name_info->cAltEntry; i++) { const CERT_ALT_NAME_ENTRY *entry = &alt_name_info->rgAltEntry[i]; wchar_t *dns_w = NULL; size_t current_length = 0; if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) { continue; } if(entry->pwszDNSName == NULL) { infof(data, "schannel: Empty DNS name."); continue; } current_length = wcslen(entry->pwszDNSName) + 1; if(!compute_content) { actual_length += (DWORD)current_length; continue; } /* Sanity check to prevent buffer overrun. */ if((actual_length + current_length) > length) { failf(data, "schannel: Not enough memory to list all host names."); break; } dns_w = entry->pwszDNSName; /* pwszDNSName is in ia5 string format and hence doesn't contain any * non-ascii characters. */ while(*dns_w != '\0') { *current_pos++ = (char)(*dns_w++); } *current_pos++ = '\0'; actual_length += (DWORD)current_length; } if(compute_content) { /* Last string has double null-terminator. */ *current_pos = '\0'; } return actual_length; } static CURLcode verify_host(struct Curl_easy *data, CERT_CONTEXT *pCertContextServer, const char * const conn_hostname) { CURLcode result = CURLE_PEER_FAILED_VERIFICATION; TCHAR *cert_hostname_buff = NULL; size_t cert_hostname_buff_index = 0; DWORD len = 0; DWORD actual_len = 0; /* Determine the size of the string needed for the cert hostname */ len = cert_get_name_string(data, pCertContextServer, NULL, 0); if(len == 0) { failf(data, "schannel: CertGetNameString() returned no " "certificate name information"); result = CURLE_PEER_FAILED_VERIFICATION; goto cleanup; } /* CertGetNameString guarantees that the returned name will not contain * embedded null bytes. This appears to be undocumented behavior. */ cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR)); if(!cert_hostname_buff) { result = CURLE_OUT_OF_MEMORY; goto cleanup; } actual_len = cert_get_name_string( data, pCertContextServer, (LPTSTR)cert_hostname_buff, len); /* Sanity check */ if(actual_len != len) { failf(data, "schannel: CertGetNameString() returned certificate " "name information of unexpected size"); result = CURLE_PEER_FAILED_VERIFICATION; goto cleanup; } /* If HAVE_CERT_NAME_SEARCH_ALL_NAMES is available, the output * will contain all DNS names, where each name is null-terminated * and the last DNS name is double null-terminated. Due to this * encoding, use the length of the buffer to iterate over all names. */ result = CURLE_PEER_FAILED_VERIFICATION; while(cert_hostname_buff_index < len && cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') && result == CURLE_PEER_FAILED_VERIFICATION) { char *cert_hostname; /* Comparing the cert name and the connection hostname encoded as UTF-8 * is acceptable since both values are assumed to use ASCII * (or some equivalent) encoding */ cert_hostname = Curl_convert_tchar_to_UTF8( &cert_hostname_buff[cert_hostname_buff_index]); if(!cert_hostname) { result = CURLE_OUT_OF_MEMORY; } else { int match_result; match_result = Curl_cert_hostcheck(cert_hostname, conn_hostname); if(match_result == CURL_HOST_MATCH) { infof(data, "schannel: connection hostname (%s) validated " "against certificate name (%s)\n", conn_hostname, cert_hostname); result = CURLE_OK; } else { size_t cert_hostname_len; infof(data, "schannel: connection hostname (%s) did not match " "against certificate name (%s)\n", conn_hostname, cert_hostname); cert_hostname_len = _tcslen( &cert_hostname_buff[cert_hostname_buff_index]); /* Move on to next cert name */ cert_hostname_buff_index += cert_hostname_len + 1; result = CURLE_PEER_FAILED_VERIFICATION; } Curl_unicodefree(cert_hostname); } } if(result == CURLE_PEER_FAILED_VERIFICATION) { failf(data, "schannel: CertGetNameString() failed to match " "connection hostname (%s) against server certificate names", conn_hostname); } else if(result != CURLE_OK) failf(data, "schannel: server certificate name verification failed"); cleanup: Curl_unicodefree(cert_hostname_buff); return result; } CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex) { SECURITY_STATUS sspi_status; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result = CURLE_OK; CERT_CONTEXT *pCertContextServer = NULL; const CERT_CHAIN_CONTEXT *pChainContext = NULL; HCERTCHAINENGINE cert_chain_engine = NULL; HCERTSTORE trust_store = NULL; const char * const conn_hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) { char buffer[STRERROR_LEN]; failf(data, "schannel: Failed to read remote certificate context: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); result = CURLE_PEER_FAILED_VERIFICATION; } if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) && BACKEND->use_manual_cred_validation) { /* * Create a chain engine that uses the certificates in the CA file as * trusted certificates. This is only supported on Windows 7+. */ if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) { failf(data, "schannel: this version of Windows is too old to support " "certificate verification via CA bundle file."); result = CURLE_SSL_CACERT_BADFILE; } else { /* Open the certificate store */ trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, (HCRYPTPROV)NULL, CERT_STORE_CREATE_NEW_FLAG, NULL); if(!trust_store) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to create certificate store: %s", Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; } else { result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile), conn); } } if(result == CURLE_OK) { CERT_CHAIN_ENGINE_CONFIG_WIN7 engine_config; BOOL create_engine_result; memset(&engine_config, 0, sizeof(engine_config)); engine_config.cbSize = sizeof(engine_config); engine_config.hExclusiveRoot = trust_store; /* CertCreateCertificateChainEngine will check the expected size of the * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size * does not match the expected size. When this occurs, it indicates that * CAINFO is not supported on the version of Windows in use. */ create_engine_result = CertCreateCertificateChainEngine( (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine); if(!create_engine_result) { char buffer[STRERROR_LEN]; failf(data, "schannel: failed to create certificate chain engine: %s", Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); result = CURLE_SSL_CACERT_BADFILE; } } } if(result == CURLE_OK) { CERT_CHAIN_PARA ChainPara; memset(&ChainPara, 0, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); if(!CertGetCertificateChain(cert_chain_engine, pCertContextServer, NULL, pCertContextServer->hCertStore, &ChainPara, (data->set.ssl.no_revoke ? 0 : CERT_CHAIN_REVOCATION_CHECK_CHAIN), NULL, &pChainContext)) { char buffer[STRERROR_LEN]; failf(data, "schannel: CertGetCertificateChain failed: %s", Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); pChainContext = NULL; result = CURLE_PEER_FAILED_VERIFICATION; } if(result == CURLE_OK) { CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0]; DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED); dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus; if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_REVOKED"); else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_PARTIAL_CHAIN"); else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_UNTRUSTED_ROOT"); else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_IS_NOT_TIME_VALID"); else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_REVOCATION_STATUS_UNKNOWN"); else failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } } if(result == CURLE_OK) { if(SSL_CONN_CONFIG(verifyhost)) { result = verify_host(conn->data, pCertContextServer, conn_hostname); } } if(cert_chain_engine) { CertFreeCertificateChainEngine(cert_chain_engine); } if(trust_store) { CertCloseStore(trust_store, 0); } if(pChainContext) CertFreeCertificateChain(pChainContext); if(pCertContextServer) CertFreeCertificateContext(pCertContextServer); return result; } #endif /* HAS_MANUAL_VERIFY_API */ #endif /* USE_SCHANNEL */ davix-0.8.0/deps/curl/lib/vtls/mbedtls_threadlock.c0000644000000000000000000001101314121063461020756 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2013 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_MBEDTLS) && \ ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))) #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) # include # define MBEDTLS_MUTEX_T pthread_mutex_t #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) # include # define MBEDTLS_MUTEX_T HANDLE #endif #include "mbedtls_threadlock.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* number of thread locks */ #define NUMT 2 /* This array will store all of the mutexes available to Mbedtls. */ static MBEDTLS_MUTEX_T *mutex_buf = NULL; int Curl_mbedtlsthreadlock_thread_setup(void) { int i; mutex_buf = calloc(NUMT * sizeof(MBEDTLS_MUTEX_T), 1); if(!mutex_buf) return 0; /* error, no number of threads defined */ for(i = 0; i < NUMT; i++) { int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) ret = pthread_mutex_init(&mutex_buf[i], NULL); if(ret) return 0; /* pthread_mutex_init failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) mutex_buf[i] = CreateMutex(0, FALSE, 0); if(mutex_buf[i] == 0) return 0; /* CreateMutex failed */ #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } return 1; /* OK */ } int Curl_mbedtlsthreadlock_thread_cleanup(void) { int i; if(!mutex_buf) return 0; /* error, no threads locks defined */ for(i = 0; i < NUMT; i++) { int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) ret = pthread_mutex_destroy(&mutex_buf[i]); if(ret) return 0; /* pthread_mutex_destroy failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) ret = CloseHandle(mutex_buf[i]); if(!ret) return 0; /* CloseHandle failed */ #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } free(mutex_buf); mutex_buf = NULL; return 1; /* OK */ } int Curl_mbedtlsthreadlock_lock_function(int n) { if(n < NUMT) { int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) ret = pthread_mutex_lock(&mutex_buf[n]); if(ret) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); if(ret) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } return 1; /* OK */ } int Curl_mbedtlsthreadlock_unlock_function(int n) { if(n < NUMT) { int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) ret = pthread_mutex_unlock(&mutex_buf[n]); if(ret) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_unlock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) ret = ReleaseMutex(mutex_buf[n]); if(!ret) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } return 1; /* OK */ } #endif /* USE_MBEDTLS */ davix-0.8.0/deps/curl/lib/vtls/wolfssl.h0000644000000000000000000000232714121063461016632 0ustar rootroot#ifndef HEADER_CURL_WOLFSSL_H #define HEADER_CURL_WOLFSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_WOLFSSL extern const struct Curl_ssl Curl_ssl_wolfssl; #endif /* USE_WOLFSSL */ #endif /* HEADER_CURL_WOLFSSL_H */ davix-0.8.0/deps/curl/lib/vtls/mbedtls.c0000644000000000000000000010043214121063461016562 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2011, Hoi-Ho Chan, * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. * */ #include "curl_setup.h" #ifdef USE_MBEDTLS #include #if MBEDTLS_VERSION_NUMBER >= 0x02040000 #include #else #include #endif #include #include #include #include #include #include #include #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "mbedtls.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "multiif.h" #include "mbedtls_threadlock.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" struct ssl_backend_data { mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_context entropy; mbedtls_ssl_context ssl; int server_fd; mbedtls_x509_crt cacert; mbedtls_x509_crt clicert; mbedtls_x509_crl crl; mbedtls_pk_context pk; mbedtls_ssl_config config; const char *protocols[3]; }; #define BACKEND connssl->backend /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT #endif #if defined(THREADING_SUPPORT) static mbedtls_entropy_context ts_entropy; static int entropy_init_initialized = 0; /* start of entropy_init_mutex() */ static void entropy_init_mutex(mbedtls_entropy_context *ctx) { /* lock 0 = entropy_init_mutex() */ Curl_mbedtlsthreadlock_lock_function(0); if(entropy_init_initialized == 0) { mbedtls_entropy_init(ctx); entropy_init_initialized = 1; } Curl_mbedtlsthreadlock_unlock_function(0); } /* end of entropy_init_mutex() */ /* start of entropy_func_mutex() */ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { int ret; /* lock 1 = entropy_func_mutex() */ Curl_mbedtlsthreadlock_lock_function(1); ret = mbedtls_entropy_func(data, output, len); Curl_mbedtlsthreadlock_unlock_function(1); return ret; } /* end of entropy_func_mutex() */ #endif /* THREADING_SUPPORT */ /* Define this to enable lots of debugging for mbedTLS */ #undef MBEDTLS_DEBUG #ifdef MBEDTLS_DEBUG static void mbed_debug(void *context, int level, const char *f_name, int line_nb, const char *line) { struct Curl_easy *data = NULL; if(!context) return; data = (struct Curl_easy *)context; infof(data, "%s", line); (void) level; } #else #endif /* ALPN for http2? */ #ifdef USE_NGHTTP2 # undef HAS_ALPN # ifdef MBEDTLS_SSL_ALPN # define HAS_ALPN # endif #endif /* * profile */ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = { /* Hashes from SHA-1 and above */ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 0xFFFFFFF, /* Any PK alg */ 0xFFFFFFF, /* Any curve */ 1024, /* RSA min key len */ }; /* See https://tls.mbed.org/discussions/generic/ howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der */ #define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE) #define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) static Curl_recv mbed_recv; static Curl_send mbed_send; static CURLcode mbedtls_version_from_curl(int *mbedver, long version) { switch(version) { case CURL_SSLVERSION_TLSv1_0: *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1: *mbedver = MBEDTLS_SSL_MINOR_VERSION_2; return CURLE_OK; case CURL_SSLVERSION_TLSv1_2: *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; return CURLE_OK; case CURL_SSLVERSION_TLSv1_3: break; } return CURLE_SSL_CONNECT_ERROR; } static CURLcode set_ssl_version_min_max(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); CURLcode result = CURLE_OK; switch(ssl_version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: ssl_version = CURL_SSLVERSION_TLSv1_0; break; } switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; break; } result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version); if(result) { failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); return result; } result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16); if(result) { failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); return result; } mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_min); mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, mbedtls_ver_max); return result; } static CURLcode mbed_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); char * const ssl_cert = SSL_SET_OPTION(cert); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; char errorbuf[128]; errorbuf[0] = 0; /* mbedTLS only supports SSLv3 and TLSv1 */ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "mbedTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } #ifdef THREADING_SUPPORT entropy_init_mutex(&ts_entropy); mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex, &ts_entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", -ret, errorbuf); } #else mbedtls_entropy_init(&BACKEND->entropy); mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg); ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func, &BACKEND->entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", -ret, errorbuf); } #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ mbedtls_x509_crt_init(&BACKEND->cacert); if(ssl_cafile) { ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile); if(ret<0) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", ssl_cafile, -ret, errorbuf); if(verifypeer) return CURLE_SSL_CACERT_BADFILE; } } if(ssl_capath) { ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath); if(ret<0) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", ssl_capath, -ret, errorbuf); if(verifypeer) return CURLE_SSL_CACERT_BADFILE; } } /* Load the client certificate */ mbedtls_x509_crt_init(&BACKEND->clicert); if(ssl_cert) { ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", ssl_cert, -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } } /* Load the client private key */ mbedtls_pk_init(&BACKEND->pk); if(SSL_SET_OPTION(key)) { ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key), SSL_SET_OPTION(key_passwd)); if(ret == 0 && !(mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA) || mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", SSL_SET_OPTION(key), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } } /* Load the CRL */ mbedtls_x509_crl_init(&BACKEND->crl); if(ssl_crlfile) { ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", ssl_crlfile, -ret, errorbuf); return CURLE_SSL_CRL_BADFILE; } } infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port); mbedtls_ssl_config_init(&BACKEND->config); mbedtls_ssl_init(&BACKEND->ssl); if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) { failf(data, "mbedTLS: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } ret = mbedtls_ssl_config_defaults(&BACKEND->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if(ret) { failf(data, "mbedTLS: ssl_config failed"); return CURLE_SSL_CONNECT_ERROR; } /* new profile with RSA min key len = 1024 ... */ mbedtls_ssl_conf_cert_profile(&BACKEND->config, &mbedtls_x509_crt_profile_fr); switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); break; case CURL_SSLVERSION_SSLv3: mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); infof(data, "mbedTLS: Set SSL version to SSLv3\n"); break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { CURLcode result = set_ssl_version_min_max(conn, sockindex); if(result != CURLE_OK) return result; break; } default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random, &BACKEND->ctr_drbg); mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex], mbedtls_net_send, mbedtls_net_recv, NULL /* rev_timeout() */); mbedtls_ssl_conf_ciphersuites(&BACKEND->config, mbedtls_ssl_list_ciphersuites()); #if defined(MBEDTLS_SSL_RENEGOTIATION) mbedtls_ssl_conf_renegotiation(&BACKEND->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) mbedtls_ssl_conf_session_tickets(&BACKEND->config, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); #endif /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *old_session = NULL; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } infof(data, "mbedTLS re-using session\n"); } Curl_ssl_sessionid_unlock(conn); } mbedtls_ssl_conf_ca_chain(&BACKEND->config, &BACKEND->cacert, &BACKEND->crl); if(SSL_SET_OPTION(key)) { mbedtls_ssl_conf_own_cert(&BACKEND->config, &BACKEND->clicert, &BACKEND->pk); } if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) { /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ failf(data, "couldn't set hostname in mbedTLS"); return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { const char **p = &BACKEND->protocols[0]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) *p++ = NGHTTP2_PROTO_VERSION_ID; #endif *p++ = ALPN_HTTP_1_1; *p = NULL; /* this function doesn't clone the protocols array, which is why we need to keep it around */ if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config, &BACKEND->protocols[0])) { failf(data, "Failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } for(p = &BACKEND->protocols[0]; *p; ++p) infof(data, "ALPN, offering %s\n", *p); } #endif #ifdef MBEDTLS_DEBUG /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data); /* - 0 No debug * - 1 Error * - 2 State change * - 3 Informational * - 4 Verbose */ mbedtls_debug_set_threshold(4); #endif /* give application a chance to interfere with mbedTLS set up. */ if(data->set.ssl.fsslctx) { ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config, data->set.ssl.fsslctxp); if(ret) { failf(data, "error signaled by ssl ctx callback"); return ret; } } connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode mbed_connect_step2(struct connectdata *conn, int sockindex) { int ret; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const mbedtls_x509_crt *peercert; const char * const pinnedpubkey = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; ret = mbedtls_ssl_handshake(&BACKEND->ssl); if(ret == MBEDTLS_ERR_SSL_WANT_READ) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } else if(ret) { char errorbuf[128]; errorbuf[0] = 0; #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } infof(data, "mbedTLS: Handshake complete, cipher is %s\n", mbedtls_ssl_get_ciphersuite(&BACKEND->ssl) ); ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl); if(!SSL_CONN_CONFIG(verifyhost)) /* Ignore hostname errors if verifyhost is disabled */ ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); else if(ret & MBEDTLS_X509_BADCERT_REVOKED) failf(data, "Cert verify failed: BADCERT_REVOKED"); else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) failf(data, "Cert verify failed: BADCERT_CN_MISMATCH"); else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED"); else if(ret & MBEDTLS_X509_BADCERT_FUTURE) failf(data, "Cert verify failed: BADCERT_FUTURE"); return CURLE_PEER_FAILED_VERIFICATION; } peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl); if(peercert && data->set.verbose) { const size_t bufsize = 16384; char *buffer = malloc(bufsize); if(!buffer) return CURLE_OUT_OF_MEMORY; if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) infof(data, "Dumping cert info:\n%s\n", buffer); else infof(data, "Unable to dump certificate information.\n"); free(buffer); } if(pinnedpubkey) { int size; CURLcode result; mbedtls_x509_crt *p; unsigned char pubkey[PUB_DER_MAX_BYTES]; if(!peercert || !peercert->raw.p || !peercert->raw.len) { failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } p = calloc(1, sizeof(*p)); if(!p) return CURLE_OUT_OF_MEMORY; mbedtls_x509_crt_init(p); /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { failf(data, "Failed copying peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); mbedtls_x509_crt_free(p); free(p); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, &pubkey[PUB_DER_MAX_BYTES - size], size); if(result) { mbedtls_x509_crt_free(p); free(p); return result; } mbedtls_x509_crt_free(p); free(p); } #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl); if(next_protocol) { infof(data, "ALPN, server accepted to use %s\n", next_protocol); #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN) && !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && !next_protocol[ALPN_HTTP_1_1_LENGTH]) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else { infof(data, "ALPN, server did not agree to a protocol\n"); } Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif connssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); return CURLE_OK; } static CURLcode mbed_connect_step3(struct connectdata *conn, int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); if(SSL_SET_OPTION(primary.sessionid)) { int ret; mbedtls_ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); if(!our_ssl_sessionid) return CURLE_OUT_OF_MEMORY; mbedtls_ssl_session_init(our_ssl_sessionid); ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid); if(ret) { if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) mbedtls_ssl_session_free(our_ssl_sessionid); free(our_ssl_sessionid); failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } /* If there's already a matching session in the cache, delete it */ Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) Curl_ssl_delsessionid(conn, old_ssl_sessionid); retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); Curl_ssl_sessionid_unlock(conn); if(retcode) { mbedtls_ssl_session_free(our_ssl_sessionid); free(our_ssl_sessionid); failf(data, "failed to store ssl session"); return retcode; } } connssl->connecting_state = ssl_connect_done; return CURLE_OK; } static ssize_t mbed_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; int ret = -1; ret = mbedtls_ssl_write(&BACKEND->ssl, (unsigned char *)mem, len); if(ret < 0) { *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? CURLE_AGAIN : CURLE_SEND_ERROR; ret = -1; } return ret; } static void Curl_mbedtls_close_all(struct Curl_easy *data) { (void)data; } static void Curl_mbedtls_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; mbedtls_pk_free(&BACKEND->pk); mbedtls_x509_crt_free(&BACKEND->clicert); mbedtls_x509_crt_free(&BACKEND->cacert); mbedtls_x509_crl_free(&BACKEND->crl); mbedtls_ssl_config_free(&BACKEND->config); mbedtls_ssl_free(&BACKEND->ssl); mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg); #ifndef THREADING_SUPPORT mbedtls_entropy_free(&BACKEND->entropy); #endif /* THREADING_SUPPORT */ } static ssize_t mbed_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; int ret = -1; ssize_t len = -1; memset(buf, 0, buffersize); ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize); if(ret <= 0) { if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) return 0; *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? CURLE_AGAIN : CURLE_RECV_ERROR; return -1; } len = ret; return len; } static void Curl_mbedtls_session_free(void *ptr) { mbedtls_ssl_session_free(ptr); free(ptr); } static size_t Curl_mbedtls_version(char *buffer, size_t size) { #ifdef MBEDTLS_VERSION_C /* if mbedtls_version_get_number() is available it is better */ unsigned int version = mbedtls_version_get_number(); return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24, (version>>16)&0xff, (version>>8)&0xff); #else return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING); #endif } static CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { #if defined(MBEDTLS_CTR_DRBG_C) int ret = -1; char errorbuf[128]; mbedtls_entropy_context ctr_entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_init(&ctr_entropy); mbedtls_ctr_drbg_init(&ctr_drbg); errorbuf[0] = 0; ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &ctr_entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n", -ret, errorbuf); } else { ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", -ret, errorbuf); } } mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&ctr_entropy); return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; #elif defined(MBEDTLS_HAVEGE_C) mbedtls_havege_state hs; mbedtls_havege_init(&hs); mbedtls_havege_random(&hs, entropy, length); mbedtls_havege_free(&hs); return CURLE_OK; #else return CURLE_NOT_BUILT_IN; #endif } static CURLcode mbed_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode retcode; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; timediff_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } retcode = mbed_connect_step1(conn, sockindex); if(retcode) return retcode; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : (time_t)timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if * this connection is part of a multi handle and this loop would * execute again. This permits the owner of a multi handle to * abort a connection attempt before step2 has completed while * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ retcode = mbed_connect_step2(conn, sockindex); if(retcode || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return retcode; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { retcode = mbed_connect_step3(conn, sockindex); if(retcode) return retcode; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = mbed_recv; conn->send[sockindex] = mbed_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return mbed_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex) { CURLcode retcode; bool done = FALSE; retcode = mbed_connect_common(conn, sockindex, FALSE, &done); if(retcode) return retcode; DEBUGASSERT(done); return CURLE_OK; } /* * return 0 error initializing SSL * return 1 SSL initialized successfully */ static int Curl_mbedtls_init(void) { return Curl_mbedtlsthreadlock_thread_setup(); } static void Curl_mbedtls_cleanup(void) { (void)Curl_mbedtlsthreadlock_thread_cleanup(); } static bool Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0; } static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, size_t sha256len UNUSED_PARAM) { (void)sha256len; #if MBEDTLS_VERSION_NUMBER < 0x02070000 mbedtls_sha256(input, inputlen, sha256sum, 0); #else /* returns 0 on success, otherwise failure */ if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) return CURLE_BAD_FUNCTION_ARGUMENT; #endif return CURLE_OK; } static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return &BACKEND->ssl; } const struct Curl_ssl Curl_ssl_mbedtls = { { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */ SSLSUPP_CA_PATH | SSLSUPP_PINNEDPUBKEY | SSLSUPP_SSL_CTX, sizeof(struct ssl_backend_data), Curl_mbedtls_init, /* init */ Curl_mbedtls_cleanup, /* cleanup */ Curl_mbedtls_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_none_shutdown, /* shutdown */ Curl_mbedtls_data_pending, /* data_pending */ Curl_mbedtls_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_mbedtls_connect, /* connect */ Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */ Curl_mbedtls_get_internals, /* get_internals */ Curl_mbedtls_close, /* close_one */ Curl_mbedtls_close_all, /* close_all */ Curl_mbedtls_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_none_md5sum, /* md5sum */ Curl_mbedtls_sha256sum /* sha256sum */ }; #endif /* USE_MBEDTLS */ davix-0.8.0/deps/curl/lib/vtls/vtls.h0000644000000000000000000002710514121063461016132 0ustar rootroot#ifndef HEADER_CURL_VTLS_H #define HEADER_CURL_VTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" struct connectdata; struct ssl_connect_data; #define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */ #define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */ #define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */ #define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */ #define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */ #define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */ struct Curl_ssl { /* * This *must* be the first entry to allow returning the list of available * backends in curl_global_sslset(). */ curl_ssl_backend info; unsigned int supports; /* bitfield, see above */ size_t sizeof_ssl_backend_data; int (*init)(void); void (*cleanup)(void); size_t (*version)(char *buffer, size_t size); int (*check_cxn)(struct connectdata *cxn); int (*shut_down)(struct connectdata *conn, int sockindex); bool (*data_pending)(const struct connectdata *conn, int connindex); /* return 0 if a find random is filled in */ CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy, size_t length); bool (*cert_status_request)(void); CURLcode (*connect_blocking)(struct connectdata *conn, int sockindex); CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex, bool *done); void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info); void (*close_one)(struct connectdata *conn, int sockindex); void (*close_all)(struct Curl_easy *data); void (*session_free)(void *ptr); CURLcode (*set_engine)(struct Curl_easy *data, const char *engine); CURLcode (*set_engine_default)(struct Curl_easy *data); struct curl_slist *(*engines_list)(struct Curl_easy *data); bool (*false_start)(void); CURLcode (*md5sum)(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5sumlen); CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, size_t sha256sumlen); }; #ifdef USE_SSL extern const struct Curl_ssl *Curl_ssl; #endif int Curl_none_init(void); void Curl_none_cleanup(void); int Curl_none_shutdown(struct connectdata *conn, int sockindex); int Curl_none_check_cxn(struct connectdata *conn); CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy, size_t length); void Curl_none_close_all(struct Curl_easy *data); void Curl_none_session_free(void *ptr); bool Curl_none_data_pending(const struct connectdata *conn, int connindex); bool Curl_none_cert_status_request(void); CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine); CURLcode Curl_none_set_engine_default(struct Curl_easy *data); struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); bool Curl_none_false_start(void); bool Curl_ssl_tls13_ciphersuites(void); CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len); #include "openssl.h" /* OpenSSL versions */ #include "gtls.h" /* GnuTLS versions */ #include "nssg.h" /* NSS versions */ #include "gskit.h" /* Global Secure ToolKit versions */ #include "wolfssl.h" /* wolfSSL versions */ #include "schannel.h" /* Schannel SSPI version */ #include "sectransp.h" /* SecureTransport (Darwin) version */ #include "mbedtls.h" /* mbedTLS versions */ #include "mesalink.h" /* MesaLink versions */ #include "bearssl.h" /* BearSSL versions */ #ifndef MAX_PINNED_PUBKEY_SIZE #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */ #endif #ifndef MD5_DIGEST_LENGTH #ifndef LIBWOLFSSL_VERSION_HEX /* because WolfSSL borks this */ #define MD5_DIGEST_LENGTH 16 /* fixed size */ #endif #endif #ifndef CURL_SHA256_DIGEST_LENGTH #define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */ #endif /* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" /* set of helper macros for the backends to access the correct fields. For the proxy or for the remote host - to properly support HTTPS proxy */ #define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) #define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \ data->set.ssl.var) #define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \ conn->proxy_ssl_config.var : conn->ssl_config.var) bool Curl_ssl_config_matches(struct ssl_primary_config* data, struct ssl_primary_config* needle); bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, struct ssl_primary_config *dest); void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc); int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks); int Curl_ssl_backend(void); #ifdef USE_SSL int Curl_ssl_init(void); void Curl_ssl_cleanup(void); CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex); CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); /* tell the SSL stuff to close down all open information regarding connections (and thus session ID caching etc) */ void Curl_ssl_close_all(struct Curl_easy *data); void Curl_ssl_close(struct connectdata *conn, int sockindex); CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); /* Sets engine as default for all SSL operations */ CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); /* init the SSL session ID cache */ CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); size_t Curl_ssl_version(char *buffer, size_t size); bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex); int Curl_ssl_check_cxn(struct connectdata *conn); /* Certificate information list handling. */ void Curl_ssl_free_certinfo(struct Curl_easy *data); CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num); CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, const char *label, const char *value, size_t valuelen); CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, const char *label, const char *value); /* Functions to be used by SSL library adaptation functions */ /* Lock session cache mutex. * Call this before calling other Curl_ssl_*session* functions * Caller should unlock this mutex as soon as possible, as it may block * other SSL connection from making progress. * The purpose of explicitly locking SSL session cache data is to allow * individual SSL engines to manage session lifetime in their specific way. */ void Curl_ssl_sessionid_lock(struct connectdata *conn); /* Unlock session cache mutex */ void Curl_ssl_sessionid_unlock(struct connectdata *conn); /* extract a session ID * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * Caller must make sure that the ownership of returned sessionid object * is properly taken (e.g. its refcount is incremented * under sessionid mutex). */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, size_t *idsize, /* set 0 if unknown */ int sockindex); /* add a new session ID * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * Caller must ensure that it has properly shared ownership of this sessionid * object with cache (e.g. incrementing refcount on success) */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize, int sockindex); /* Kill a single session ID entry in the cache * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * This will call engine-specific curlssl_session_free function, which must * take sessionid object ownership from sessionid cache * (e.g. decrement refcount). */ void Curl_ssl_kill_session(struct curl_ssl_session *session); /* delete a session from the cache * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * This will call engine-specific curlssl_session_free function, which must * take sessionid object ownership from sessionid cache * (e.g. decrement refcount). */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); /* get N random bytes into the buffer */ CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, size_t length); CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); /* Check pinned public key. */ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen); bool Curl_ssl_cert_status_request(void); bool Curl_ssl_false_start(void); #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ #else /* if not USE_SSL */ /* When SSL support is not present, just define away these function calls */ #define Curl_ssl_init() 1 #define Curl_ssl_cleanup() Curl_nop_stmt #define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_close_all(x) Curl_nop_stmt #define Curl_ssl_close(x,y) Curl_nop_stmt #define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN #define Curl_ssl_engines_list(x) NULL #define Curl_ssl_send(a,b,c,d,e) -1 #define Curl_ssl_recv(a,b,c,d,e) -1 #define Curl_ssl_initsessions(x,y) CURLE_OK #define Curl_ssl_version(x,y) 0 #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN #define Curl_ssl_kill_session(x) Curl_nop_stmt #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) #define Curl_ssl_cert_status_request() FALSE #define Curl_ssl_false_start() FALSE #define Curl_ssl_tls13_ciphersuites() FALSE #endif #endif /* HEADER_CURL_VTLS_H */ davix-0.8.0/deps/curl/lib/vtls/mbedtls_threadlock.h0000644000000000000000000000351414121063461020772 0ustar rootroot#ifndef HEADER_CURL_MBEDTLS_THREADLOCK_H #define HEADER_CURL_MBEDTLS_THREADLOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2013 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_MBEDTLS #if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)) int Curl_mbedtlsthreadlock_thread_setup(void); int Curl_mbedtlsthreadlock_thread_cleanup(void); int Curl_mbedtlsthreadlock_lock_function(int n); int Curl_mbedtlsthreadlock_unlock_function(int n); #else #define Curl_mbedtlsthreadlock_thread_setup() 1 #define Curl_mbedtlsthreadlock_thread_cleanup() 1 #define Curl_mbedtlsthreadlock_lock_function(x) 1 #define Curl_mbedtlsthreadlock_unlock_function(x) 1 #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ #endif /* USE_MBEDTLS */ #endif /* HEADER_CURL_MBEDTLS_THREADLOCK_H */ davix-0.8.0/deps/curl/lib/vtls/schannel.c0000644000000000000000000023007514121063461016732 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all Schannel-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. */ /* * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * Thanks for code and inspiration! */ #include "curl_setup.h" #ifdef USE_SCHANNEL #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS #ifndef USE_WINDOWS_SSPI # error "Can't compile SCHANNEL support without SSPI." #endif #include "schannel.h" #include "vtls.h" #include "sendf.h" #include "connect.h" /* for the connect timeout */ #include "strerror.h" #include "select.h" /* for the socket readyness */ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" #include "x509asn1.h" #include "curl_printf.h" #include "multiif.h" #include "system_win32.h" /* The last #include file should be: */ #include "curl_memory.h" #include "memdebug.h" /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800: https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx */ #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) # define HAS_ALPN 1 #endif #ifndef UNISP_NAME_A #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" #endif #ifndef UNISP_NAME_W #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" #endif #ifndef UNISP_NAME #ifdef UNICODE #define UNISP_NAME UNISP_NAME_W #else #define UNISP_NAME UNISP_NAME_A #endif #endif #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) #define HAS_CLIENT_CERT_PATH #endif #ifdef HAS_CLIENT_CERT_PATH #ifdef UNICODE #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W #else #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A #endif #endif #ifndef SP_PROT_SSL2_CLIENT #define SP_PROT_SSL2_CLIENT 0x00000008 #endif #ifndef SP_PROT_SSL3_CLIENT #define SP_PROT_SSL3_CLIENT 0x00000008 #endif #ifndef SP_PROT_TLS1_CLIENT #define SP_PROT_TLS1_CLIENT 0x00000080 #endif #ifndef SP_PROT_TLS1_0_CLIENT #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT #endif #ifndef SP_PROT_TLS1_1_CLIENT #define SP_PROT_TLS1_1_CLIENT 0x00000200 #endif #ifndef SP_PROT_TLS1_2_CLIENT #define SP_PROT_TLS1_2_CLIENT 0x00000800 #endif #ifndef SECBUFFER_ALERT #define SECBUFFER_ALERT 17 #endif /* Both schannel buffer sizes must be > 0 */ #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 #define CERT_THUMBPRINT_STR_LEN 40 #define CERT_THUMBPRINT_DATA_LEN 20 /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) */ #ifndef CALG_SHA_256 # define CALG_SHA_256 0x0000800c #endif #define BACKEND connssl->backend static Curl_recv schannel_recv; static Curl_send schannel_send; static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex, const char *pinnedpubkey); static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType, void *BufDataPtr, unsigned long BufByteSize) { buffer->cbBuffer = BufByteSize; buffer->BufferType = BufType; buffer->pvBuffer = BufDataPtr; } static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, unsigned long NumArrElem) { desc->ulVersion = SECBUFFER_VERSION; desc->pBuffers = BufArr; desc->cBuffers = NumArrElem; } static CURLcode set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) { struct Curl_easy *data = conn->data; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long i = ssl_version; switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; break; } for(; i <= (ssl_version_max >> 16); ++i) { switch(i) { case CURL_SSLVERSION_TLSv1_0: schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; break; case CURL_SSLVERSION_TLSv1_1: schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; break; case CURL_SSLVERSION_TLSv1_2: schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; break; case CURL_SSLVERSION_TLSv1_3: failf(data, "schannel: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; } } return CURLE_OK; } /*longest is 26, buffer is slightly bigger*/ #define LONGEST_ALG_ID 32 #define CIPHEROPTION(X) \ if(strcmp(#X, tmp) == 0) \ return X static int get_alg_id_by_name(char *name) { char tmp[LONGEST_ALG_ID] = { 0 }; char *nameEnd = strchr(name, ':'); size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \ min(strlen(name), LONGEST_ALG_ID - 1); strncpy(tmp, name, n); tmp[n] = 0; CIPHEROPTION(CALG_MD2); CIPHEROPTION(CALG_MD4); CIPHEROPTION(CALG_MD5); CIPHEROPTION(CALG_SHA); CIPHEROPTION(CALG_SHA1); CIPHEROPTION(CALG_MAC); CIPHEROPTION(CALG_RSA_SIGN); CIPHEROPTION(CALG_DSS_SIGN); /*ifdefs for the options that are defined conditionally in wincrypt.h*/ #ifdef CALG_NO_SIGN CIPHEROPTION(CALG_NO_SIGN); #endif CIPHEROPTION(CALG_RSA_KEYX); CIPHEROPTION(CALG_DES); #ifdef CALG_3DES_112 CIPHEROPTION(CALG_3DES_112); #endif CIPHEROPTION(CALG_3DES); CIPHEROPTION(CALG_DESX); CIPHEROPTION(CALG_RC2); CIPHEROPTION(CALG_RC4); CIPHEROPTION(CALG_SEAL); #ifdef CALG_DH_SF CIPHEROPTION(CALG_DH_SF); #endif CIPHEROPTION(CALG_DH_EPHEM); #ifdef CALG_AGREEDKEY_ANY CIPHEROPTION(CALG_AGREEDKEY_ANY); #endif #ifdef CALG_HUGHES_MD5 CIPHEROPTION(CALG_HUGHES_MD5); #endif CIPHEROPTION(CALG_SKIPJACK); #ifdef CALG_TEK CIPHEROPTION(CALG_TEK); #endif CIPHEROPTION(CALG_CYLINK_MEK); CIPHEROPTION(CALG_SSL3_SHAMD5); #ifdef CALG_SSL3_MASTER CIPHEROPTION(CALG_SSL3_MASTER); #endif #ifdef CALG_SCHANNEL_MASTER_HASH CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH); #endif #ifdef CALG_SCHANNEL_MAC_KEY CIPHEROPTION(CALG_SCHANNEL_MAC_KEY); #endif #ifdef CALG_SCHANNEL_ENC_KEY CIPHEROPTION(CALG_SCHANNEL_ENC_KEY); #endif #ifdef CALG_PCT1_MASTER CIPHEROPTION(CALG_PCT1_MASTER); #endif #ifdef CALG_SSL2_MASTER CIPHEROPTION(CALG_SSL2_MASTER); #endif #ifdef CALG_TLS1_MASTER CIPHEROPTION(CALG_TLS1_MASTER); #endif #ifdef CALG_RC5 CIPHEROPTION(CALG_RC5); #endif #ifdef CALG_HMAC CIPHEROPTION(CALG_HMAC); #endif #if !defined(__W32API_MAJOR_VERSION) || \ !defined(__W32API_MINOR_VERSION) || \ defined(__MINGW64_VERSION_MAJOR) || \ (__W32API_MAJOR_VERSION > 5) || \ ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0)) /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0, see https://osdn.net/projects/mingw/ticket/38391 */ CIPHEROPTION(CALG_TLS1PRF); #endif #ifdef CALG_HASH_REPLACE_OWF CIPHEROPTION(CALG_HASH_REPLACE_OWF); #endif #ifdef CALG_AES_128 CIPHEROPTION(CALG_AES_128); #endif #ifdef CALG_AES_192 CIPHEROPTION(CALG_AES_192); #endif #ifdef CALG_AES_256 CIPHEROPTION(CALG_AES_256); #endif #ifdef CALG_AES CIPHEROPTION(CALG_AES); #endif #ifdef CALG_SHA_256 CIPHEROPTION(CALG_SHA_256); #endif #ifdef CALG_SHA_384 CIPHEROPTION(CALG_SHA_384); #endif #ifdef CALG_SHA_512 CIPHEROPTION(CALG_SHA_512); #endif #ifdef CALG_ECDH CIPHEROPTION(CALG_ECDH); #endif #ifdef CALG_ECMQV CIPHEROPTION(CALG_ECMQV); #endif #ifdef CALG_ECDSA CIPHEROPTION(CALG_ECDSA); #endif #ifdef CALG_ECDH_EPHEM CIPHEROPTION(CALG_ECDH_EPHEM); #endif return 0; } static CURLcode set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers) { char *startCur = ciphers; int algCount = 0; static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/ while(startCur && (0 != *startCur) && (algCount < 45)) { long alg = strtol(startCur, 0, 0); if(!alg) alg = get_alg_id_by_name(startCur); if(alg) algIds[algCount++] = alg; else return CURLE_SSL_CIPHER; startCur = strchr(startCur, ':'); if(startCur) startCur++; } schannel_cred->palgSupportedAlgs = algIds; schannel_cred->cSupportedAlgs = algCount; return CURLE_OK; } #ifdef HAS_CLIENT_CERT_PATH static CURLcode get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, TCHAR **thumbprint) { TCHAR *sep; TCHAR *store_path_start; size_t store_name_len; sep = _tcschr(path, TEXT('\\')); if(sep == NULL) return CURLE_SSL_CERTPROBLEM; store_name_len = sep - path; if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_USER; else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE; else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE; else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_SERVICES; else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_USERS; else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY; else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY; else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE; else return CURLE_SSL_CERTPROBLEM; store_path_start = sep + 1; sep = _tcschr(store_path_start, TEXT('\\')); if(sep == NULL) return CURLE_SSL_CERTPROBLEM; *sep = TEXT('\0'); *store_path = _tcsdup(store_path_start); *sep = TEXT('\\'); if(*store_path == NULL) return CURLE_OUT_OF_MEMORY; *thumbprint = sep + 1; if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN) return CURLE_SSL_CERTPROBLEM; return CURLE_OK; } #endif static CURLcode schannel_connect_step1(struct connectdata *conn, int sockindex) { ssize_t written = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; SecBuffer inbuf; SecBufferDesc inbuf_desc; #ifdef HAS_ALPN unsigned char alpn_buffer[128]; #endif SCHANNEL_CRED schannel_cred; PCCERT_CONTEXT client_certs[1] = { NULL }; SECURITY_STATUS sspi_status = SEC_E_OK; struct curl_schannel_cred *old_cred = NULL; struct in_addr addr; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif TCHAR *host_name; CURLcode result; char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", hostname, conn->remote_port)); if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, VERSION_LESS_THAN_EQUAL)) { /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and algorithms that may not be supported by all servers. */ infof(data, "schannel: Windows version is old and may not be able to " "connect to some servers due to lack of SNI, algorithms, etc.\n"); } #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ BACKEND->use_alpn = conn->bits.tls_enable_alpn && !GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version") && Curl_verify_windows_version(6, 3, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL); #else BACKEND->use_alpn = false; #endif #ifdef _WIN32_WCE #ifdef HAS_MANUAL_VERIFY_API /* certificate validation on CE doesn't seem to work right; we'll * do it following a more manual process. */ BACKEND->use_manual_cred_validation = true; #else #error "compiler too old to support requisite manual cert verify for Win CE" #endif #else #ifdef HAS_MANUAL_VERIFY_API if(SSL_CONN_CONFIG(CAfile)) { if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { BACKEND->use_manual_cred_validation = true; } else { failf(data, "schannel: this version of Windows is too old to support " "certificate verification via CA bundle file."); return CURLE_SSL_CACERT_BADFILE; } } else BACKEND->use_manual_cred_validation = false; #else if(SSL_CONN_CONFIG(CAfile)) { failf(data, "schannel: CA cert support not built in"); return CURLE_NOT_BUILT_IN; } #endif #endif BACKEND->cred = NULL; /* check for an existing re-usable credential handle */ if(SSL_SET_OPTION(primary.sessionid)) { Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { BACKEND->cred = old_cred; DEBUGF(infof(data, "schannel: re-using existing credential handle\n")); /* increment the reference counter of the credential/session handle */ BACKEND->cred->refcount++; DEBUGF(infof(data, "schannel: incremented credential handle refcount = %d\n", BACKEND->cred->refcount)); } Curl_ssl_sessionid_unlock(conn); } if(!BACKEND->cred) { /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; if(conn->ssl_config.verifypeer) { #ifdef HAS_MANUAL_VERIFY_API if(BACKEND->use_manual_cred_validation) schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; else #endif schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; if(data->set.ssl.no_revoke) { schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; DEBUGF(infof(data, "schannel: disabled server certificate revocation " "checks\n")); } else { schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; DEBUGF(infof(data, "schannel: checking server certificate revocation\n")); } } else { schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; DEBUGF(infof(data, "schannel: disabled server cert revocation checks\n")); } if(!conn->ssl_config.verifyhost) { schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from " "comparing the supplied target name with the subject " "names in server certificates.\n")); } switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { result = set_ssl_version_min_max(&schannel_cred, conn); if(result != CURLE_OK) return result; break; } case CURL_SSLVERSION_SSLv3: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; break; case CURL_SSLVERSION_SSLv2: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(SSL_CONN_CONFIG(cipher_list)) { result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list)); if(CURLE_OK != result) { failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); return result; } } #ifdef HAS_CLIENT_CERT_PATH /* client certificate */ if(data->set.ssl.cert) { DWORD cert_store_name; TCHAR *cert_store_path; TCHAR *cert_thumbprint_str; CRYPT_HASH_BLOB cert_thumbprint; BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; HCERTSTORE cert_store; TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert); if(!cert_path) return CURLE_OUT_OF_MEMORY; result = get_cert_location(cert_path, &cert_store_name, &cert_store_path, &cert_thumbprint_str); if(result != CURLE_OK) { failf(data, "schannel: Failed to get certificate location for %s", cert_path); Curl_unicodefree(cert_path); return result; } cert_store = CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV)NULL, CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, cert_store_path); if(!cert_store) { failf(data, "schannel: Failed to open cert store %x %s, " "last error is %x", cert_store_name, cert_store_path, GetLastError()); free(cert_store_path); Curl_unicodefree(cert_path); return CURLE_SSL_CERTPROBLEM; } free(cert_store_path); cert_thumbprint.pbData = cert_thumbprint_data; cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN, CRYPT_STRING_HEX, cert_thumbprint_data, &cert_thumbprint.cbData, NULL, NULL)) { Curl_unicodefree(cert_path); return CURLE_SSL_CERTPROBLEM; } client_certs[0] = CertFindCertificateInStore( cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_HASH, &cert_thumbprint, NULL); Curl_unicodefree(cert_path); if(client_certs[0]) { schannel_cred.cCreds = 1; schannel_cred.paCred = client_certs; } else { /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ return CURLE_SSL_CERTPROBLEM; } CertCloseStore(cert_store, 0); } #else if(data->set.ssl.cert) { failf(data, "schannel: client cert support not built in"); return CURLE_NOT_BUILT_IN; } #endif /* allocate memory for the re-usable credential handle */ BACKEND->cred = (struct curl_schannel_cred *) calloc(1, sizeof(struct curl_schannel_cred)); if(!BACKEND->cred) { failf(data, "schannel: unable to allocate memory"); if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); return CURLE_OUT_OF_MEMORY; } BACKEND->cred->refcount = 1; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, &BACKEND->cred->cred_handle, &BACKEND->cred->time_stamp); if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); if(sspi_status != SEC_E_OK) { char buffer[STRERROR_LEN]; failf(data, "schannel: AcquireCredentialsHandle failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); Curl_safefree(BACKEND->cred); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: return CURLE_OUT_OF_MEMORY; case SEC_E_NO_CREDENTIALS: case SEC_E_SECPKG_NOT_FOUND: case SEC_E_NOT_OWNER: case SEC_E_UNKNOWN_CREDENTIALS: case SEC_E_INTERNAL_ERROR: default: return CURLE_SSL_CONNECT_ERROR; } } } /* Warn if SNI is disabled due to use of an IP address */ if(Curl_inet_pton(AF_INET, hostname, &addr) #ifdef ENABLE_IPV6 || Curl_inet_pton(AF_INET6, hostname, &addr6) #endif ) { infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } #ifdef HAS_ALPN if(BACKEND->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int *extension_len = NULL; unsigned short* list_len = NULL; /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the buffer. */ extension_len = (unsigned int *)(&alpn_buffer[cur]); cur += sizeof(unsigned int); /* The next four bytes are an indicator that this buffer will contain ALPN data, as opposed to NPN, for example. */ *(unsigned int *)&alpn_buffer[cur] = SecApplicationProtocolNegotiationExt_ALPN; cur += sizeof(unsigned int); /* The next two bytes will be an unsigned short indicating the number of bytes used to list the preferred protocols. */ list_len = (unsigned short*)(&alpn_buffer[cur]); cur += sizeof(unsigned short); list_start_index = cur; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); cur += NGHTTP2_PROTO_ALPN_LEN; infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); *list_len = curlx_uitous(cur - list_start_index); *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } else { InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); } #else /* HAS_ALPN */ InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); #endif /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); /* setup request flags */ BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* allocate memory for the security context handle */ BACKEND->ctxt = (struct curl_schannel_ctxt *) calloc(1, sizeof(struct curl_schannel_ctxt)); if(!BACKEND->ctxt) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; /* Schannel InitializeSecurityContext: https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx At the moment we don't pass inbuf unless we're using ALPN since we only use it for that, and Wine (for which we currently disable ALPN) is giving us problems with inbuf regardless. https://github.com/curl/curl/issues/983 */ sspi_status = s_pSecFn->InitializeSecurityContext( &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0, (BACKEND->use_alpn ? &inbuf_desc : NULL), 0, &BACKEND->ctxt->ctxt_handle, &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; Curl_safefree(BACKEND->ctxt); switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: failf(data, "schannel: initial InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_OUT_OF_MEMORY; case SEC_E_WRONG_PRINCIPAL: failf(data, "schannel: SNI or certificate check failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_PEER_FAILED_VERIFICATION; /* case SEC_E_INVALID_HANDLE: case SEC_E_INVALID_TOKEN: case SEC_E_LOGON_DENIED: case SEC_E_TARGET_UNKNOWN: case SEC_E_NO_AUTHENTICATING_AUTHORITY: case SEC_E_INTERNAL_ERROR: case SEC_E_NO_CREDENTIALS: case SEC_E_UNSUPPORTED_FUNCTION: case SEC_E_APPLICATION_PROTOCOL_MISMATCH: */ default: failf(data, "schannel: initial InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_SSL_CONNECT_ERROR; } } DEBUGF(infof(data, "schannel: sending initial handshake data: " "sending %lu bytes...\n", outbuf.cbBuffer)); /* send initial handshake data which is now stored in output buffer */ result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, outbuf.cbBuffer, &written); s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { failf(data, "schannel: failed to send initial handshake data: " "sent %zd of %lu bytes", written, outbuf.cbBuffer); return CURLE_SSL_CONNECT_ERROR; } DEBUGF(infof(data, "schannel: sent initial handshake data: " "sent %zd bytes\n", written)); BACKEND->recv_unrecoverable_err = CURLE_OK; BACKEND->recv_sspi_close_notify = false; BACKEND->recv_connection_closed = false; BACKEND->encdata_is_incomplete = false; /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode schannel_connect_step2(struct connectdata *conn, int sockindex) { int i; ssize_t nread = -1, written = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; SecBuffer outbuf[3]; SecBufferDesc outbuf_desc; SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; bool doread; char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char *pubkey_ptr; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", hostname, conn->remote_port)); if(!BACKEND->cred || !BACKEND->ctxt) return CURLE_SSL_CONNECT_ERROR; /* buffer to store previously received and decrypted data */ if(BACKEND->decdata_buffer == NULL) { BACKEND->decdata_offset = 0; BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); if(BACKEND->decdata_buffer == NULL) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* buffer to store previously received and encrypted data */ if(BACKEND->encdata_buffer == NULL) { BACKEND->encdata_is_incomplete = false; BACKEND->encdata_offset = 0; BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); if(BACKEND->encdata_buffer == NULL) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } } /* if we need a bigger buffer to read a full message, increase buffer now */ if(BACKEND->encdata_length - BACKEND->encdata_offset < CURL_SCHANNEL_BUFFER_FREE_SIZE) { /* increase internal encrypted data buffer */ size_t reallocated_length = BACKEND->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { failf(data, "schannel: unable to re-allocate memory"); return CURLE_OUT_OF_MEMORY; } else { BACKEND->encdata_buffer = reallocated_buffer; BACKEND->encdata_length = reallocated_length; } } for(;;) { TCHAR *host_name; if(doread) { /* read encrypted handshake data from socket */ result = Curl_read_plain(conn->sock[sockindex], (char *) (BACKEND->encdata_buffer + BACKEND->encdata_offset), BACKEND->encdata_length - BACKEND->encdata_offset, &nread); if(result == CURLE_AGAIN) { if(connssl->connecting_state != ssl_connect_2_writing) connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, "schannel: failed to receive handshake, " "need more data\n")); return CURLE_OK; } else if((result != CURLE_OK) || (nread == 0)) { failf(data, "schannel: failed to receive handshake, " "SSL/TLS connection failed"); return CURLE_SSL_CONNECT_ERROR; } /* increase encrypted data buffer offset */ BACKEND->encdata_offset += nread; BACKEND->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", BACKEND->encdata_offset, BACKEND->encdata_length)); /* setup input buffers */ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), curlx_uztoul(BACKEND->encdata_offset)); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 2); /* setup output buffers */ InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, outbuf, 3); if(inbuf[0].pvBuffer == NULL) { failf(data, "schannel: unable to allocate memory"); return CURLE_OUT_OF_MEMORY; } /* copy received handshake data into input buffer */ memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, BACKEND->encdata_offset); host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ sspi_status = s_pSecFn->InitializeSecurityContext( &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); /* free buffer for received handshake data */ Curl_safefree(inbuf[0].pvBuffer); /* check if the handshake was incomplete */ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { BACKEND->encdata_is_incomplete = true; connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, "schannel: received incomplete message, need more data\n")); return CURLE_OK; } /* If the server has requested a client certificate, attempt to continue the handshake without one. This will allow connections to servers which request a client certificate but do not require it. */ if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; connssl->connecting_state = ssl_connect_2_writing; DEBUGF(infof(data, "schannel: a client certificate has been requested\n")); return CURLE_OK; } /* check if the handshake needs to be continued */ if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { for(i = 0; i < 3; i++) { /* search for handshake tokens that need to be send */ if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { DEBUGF(infof(data, "schannel: sending next handshake data: " "sending %lu bytes...\n", outbuf[i].cbBuffer)); /* send handshake token to server */ result = Curl_write_plain(conn, conn->sock[sockindex], outbuf[i].pvBuffer, outbuf[i].cbBuffer, &written); if((result != CURLE_OK) || (outbuf[i].cbBuffer != (size_t) written)) { failf(data, "schannel: failed to send next handshake data: " "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); return CURLE_SSL_CONNECT_ERROR; } } /* free obsolete buffer */ if(outbuf[i].pvBuffer != NULL) { s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer); } } } else { char buffer[STRERROR_LEN]; switch(sspi_status) { case SEC_E_INSUFFICIENT_MEMORY: failf(data, "schannel: next InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_OUT_OF_MEMORY; case SEC_E_WRONG_PRINCIPAL: failf(data, "schannel: SNI or certificate check failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_PEER_FAILED_VERIFICATION; /* case SEC_E_INVALID_HANDLE: case SEC_E_INVALID_TOKEN: case SEC_E_LOGON_DENIED: case SEC_E_TARGET_UNKNOWN: case SEC_E_NO_AUTHENTICATING_AUTHORITY: case SEC_E_INTERNAL_ERROR: case SEC_E_NO_CREDENTIALS: case SEC_E_UNSUPPORTED_FUNCTION: case SEC_E_APPLICATION_PROTOCOL_MISMATCH: */ default: failf(data, "schannel: next InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_SSL_CONNECT_ERROR; } } /* check if there was additional remaining encrypted data */ if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { DEBUGF(infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer)); /* There are two cases where we could be getting extra data here: 1) If we're renegotiating a connection and the handshake is already complete (from the server perspective), it can encrypted app data (not handshake data) in an extra buffer at this point. 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a connection and this extra data is part of the handshake. We should process the data immediately; waiting for the socket to be ready may fail since the server is done sending handshake data. */ /* check if the remaining data is less than the total amount and therefore begins after the already processed data */ if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { memmove(BACKEND->encdata_buffer, (BACKEND->encdata_buffer + BACKEND->encdata_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); BACKEND->encdata_offset = inbuf[1].cbBuffer; if(sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; continue; } } } else { BACKEND->encdata_offset = 0; } break; } /* check if the handshake needs to be continued */ if(sspi_status == SEC_I_CONTINUE_NEEDED) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } /* check if the handshake is complete */ if(sspi_status == SEC_E_OK) { connssl->connecting_state = ssl_connect_3; DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n")); } pubkey_ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(pubkey_ptr) { result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } #ifdef HAS_MANUAL_VERIFY_API if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) { return Curl_verify_certificate(conn, sockindex); } #endif return CURLE_OK; } static bool valid_cert_encoding(const CERT_CONTEXT *cert_context) { return (cert_context != NULL) && ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && (cert_context->pbCertEncoded != NULL) && (cert_context->cbCertEncoded > 0); } typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg); static void traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func, void *arg) { const CERT_CONTEXT *current_context = NULL; bool should_continue = true; while(should_continue && (current_context = CertEnumCertificatesInStore( context->hCertStore, current_context)) != NULL) should_continue = func(current_context, arg); if(current_context) CertFreeCertificateContext(current_context); } static bool cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count) { if(valid_cert_encoding(ccert_context)) (*(int *)certs_count)++; return true; } struct Adder_args { struct connectdata *conn; CURLcode result; int idx; int certs_count; }; static bool add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg) { struct Adder_args *args = (struct Adder_args*)raw_arg; args->result = CURLE_OK; if(valid_cert_encoding(ccert_context)) { const char *beg = (const char *) ccert_context->pbCertEncoded; const char *end = beg + ccert_context->cbCertEncoded; int insert_index = (args->certs_count - 1) - args->idx; args->result = Curl_extract_certinfo(args->conn, insert_index, beg, end); args->idx++; } return args->result == CURLE_OK; } static CURLcode schannel_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SECURITY_STATUS sspi_status = SEC_E_OK; CERT_CONTEXT *ccert_context = NULL; #ifdef DEBUGBUILD const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; #endif #ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", hostname, conn->remote_port)); if(!BACKEND->cred) return CURLE_SSL_CONNECT_ERROR; /* check if the required context attributes are met */ if(BACKEND->ret_flags != BACKEND->req_flags) { if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) failf(data, "schannel: failed to setup sequence detection"); if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) failf(data, "schannel: failed to setup replay detection"); if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) failf(data, "schannel: failed to setup confidentiality"); if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) failf(data, "schannel: failed to setup memory allocation"); if(!(BACKEND->ret_flags & ISC_RET_STREAM)) failf(data, "schannel: failed to setup stream orientation"); return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN if(BACKEND->use_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); if(sspi_status != SEC_E_OK) { failf(data, "schannel: failed to retrieve ALPN result"); return CURLE_SSL_CONNECT_ERROR; } if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { infof(data, "schannel: ALPN, server accepted to use %.*s\n", alpn_result.ProtocolIdSize, alpn_result.ProtocolId); #ifdef USE_NGHTTP2 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else infof(data, "ALPN, server did not agree to a protocol\n"); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif /* save the current session data for possible re-use */ if(SSL_SET_OPTION(primary.sessionid)) { bool incache; struct curl_schannel_cred *old_cred = NULL; Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)); if(incache) { if(old_cred != BACKEND->cred) { DEBUGF(infof(data, "schannel: old credential handle is stale, removing\n")); /* we're not taking old_cred ownership here, no refcount++ is needed */ Curl_ssl_delsessionid(conn, (void *)old_cred); incache = FALSE; } } if(!incache) { result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred, sizeof(struct curl_schannel_cred), sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "schannel: failed to store credential handle"); return result; } else { /* this cred session is now also referenced by sessionid cache */ BACKEND->cred->refcount++; DEBUGF(infof(data, "schannel: stored credential handle in session cache\n")); } } Curl_ssl_sessionid_unlock(conn); } if(data->set.ssl.certinfo) { int certs_count = 0; sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { failf(data, "schannel: failed to retrieve remote cert context"); return CURLE_PEER_FAILED_VERIFICATION; } traverse_cert_store(ccert_context, cert_counter_callback, &certs_count); result = Curl_ssl_init_certinfo(data, certs_count); if(!result) { struct Adder_args args; args.conn = conn; args.idx = 0; args.certs_count = certs_count; traverse_cert_store(ccert_context, add_cert_to_certinfo, &args); result = args.result; } CertFreeCertificateContext(ccert_context); if(result) return result; } connssl->connecting_state = ssl_connect_done; return CURLE_OK; } static CURLcode schannel_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; timediff_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* check out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL/TLS connection timeout"); return CURLE_OPERATION_TIMEDOUT; } result = schannel_connect_step1(conn, sockindex); if(result) return result; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL/TLS connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : (time_t)timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL/TLS connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if * this connection is part of a multi handle and this loop would * execute again. This permits the owner of a multi handle to * abort a connection attempt before step2 has completed while * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ result = schannel_connect_step2(conn, sockindex); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { result = schannel_connect_step3(conn, sockindex); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = schannel_recv; conn->send[sockindex] = schannel_send; #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS /* When SSPI is used in combination with Schannel * we need the Schannel context to create the Schannel * binding to pass the IIS extended protection checks. * Available on Windows 7 or later. */ conn->sslContext = &BACKEND->ctxt->ctxt_handle; #endif *done = TRUE; } else *done = FALSE; /* reset our connection state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static ssize_t schannel_send(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err) { ssize_t written = -1; size_t data_len = 0; unsigned char *data = NULL; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; /* check if the maximum stream sizes were queried */ if(BACKEND->stream_sizes.cbMaximumMessage == 0) { sspi_status = s_pSecFn->QueryContextAttributes( &BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &BACKEND->stream_sizes); if(sspi_status != SEC_E_OK) { *err = CURLE_SEND_ERROR; return -1; } } /* check if the buffer is longer than the maximum message length */ if(len > BACKEND->stream_sizes.cbMaximumMessage) { len = BACKEND->stream_sizes.cbMaximumMessage; } /* calculate the complete message length and allocate a buffer for it */ data_len = BACKEND->stream_sizes.cbHeader + len + BACKEND->stream_sizes.cbTrailer; data = (unsigned char *) malloc(data_len); if(data == NULL) { *err = CURLE_OUT_OF_MEMORY; return -1; } /* setup output buffers (header, data, trailer, empty) */ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, data, BACKEND->stream_sizes.cbHeader); InitSecBuffer(&outbuf[1], SECBUFFER_DATA, data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, data + BACKEND->stream_sizes.cbHeader + len, BACKEND->stream_sizes.cbTrailer); InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, outbuf, 4); /* copy data into output buffer */ memcpy(outbuf[1].pvBuffer, buf, len); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, &outbuf_desc, 0); /* check if the message was encrypted */ if(sspi_status == SEC_E_OK) { written = 0; /* send the encrypted message including header, data and trailer */ len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; /* It's important to send the full message which includes the header, encrypted payload, and trailer. Until the client receives all the data a coherent message has not been delivered and the client can't read any of it. If we wanted to buffer the unwritten encrypted bytes, we would tell the client that all data it has requested to be sent has been sent. The unwritten encrypted bytes would be the first bytes to send on the next invocation. Here's the catch with this - if we tell the client that all the bytes have been sent, will the client call this method again to send the buffered data? Looking at who calls this function, it seems the answer is NO. */ /* send entire message or fail */ while(len > (size_t)written) { ssize_t this_write; timediff_t timeleft; int what; this_write = 0; timeleft = Curl_timeleft(conn->data, NULL, FALSE); if(timeleft < 0) { /* we already got the timeout */ failf(conn->data, "schannel: timed out sending data " "(bytes sent: %zd)", written); *err = CURLE_OPERATION_TIMEDOUT; written = -1; break; } what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); *err = CURLE_SEND_ERROR; written = -1; break; } else if(0 == what) { failf(conn->data, "schannel: timed out sending data " "(bytes sent: %zd)", written); *err = CURLE_OPERATION_TIMEDOUT; written = -1; break; } /* socket is writable */ result = Curl_write_plain(conn, conn->sock[sockindex], data + written, len - written, &this_write); if(result == CURLE_AGAIN) continue; else if(result != CURLE_OK) { *err = result; written = -1; break; } written += this_write; } } else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { *err = CURLE_OUT_OF_MEMORY; } else{ *err = CURLE_SEND_ERROR; } Curl_safefree(data); if(len == (size_t)written) /* Encrypted message including header, data and trailer entirely sent. The return value is the number of unencrypted bytes that were sent. */ written = outbuf[1].cbBuffer; return written; } static ssize_t schannel_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { size_t size = 0; ssize_t nread = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; size_t reallocated_length; bool done = FALSE; SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; /* we want the length of the encrypted buffer to be at least large enough that it can hold all the bytes requested and some TLS record overhead. */ size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; /**************************************************************************** * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. * The pattern for return error is set *err, optional infof, goto cleanup. * * Our priority is to always return as much decrypted data to the caller as * possible, even if an error occurs. The state of the decrypted buffer must * always be valid. Transfer of decrypted data to the caller's buffer is * handled in the cleanup. */ DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len)); *err = CURLE_OK; if(len && len <= BACKEND->decdata_offset) { infof(data, "schannel: enough decrypted data is already available\n"); goto cleanup; } else if(BACKEND->recv_unrecoverable_err) { *err = BACKEND->recv_unrecoverable_err; infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); goto cleanup; } else if(BACKEND->recv_sspi_close_notify) { /* once a server has indicated shutdown there is no more encrypted data */ infof(data, "schannel: server indicated shutdown in a prior call\n"); goto cleanup; } else if(!len) { /* It's debatable what to return when !len. Regardless we can't return immediately because there may be data to decrypt (in the case we want to decrypt all encrypted cached data) so handle !len later in cleanup. */ ; /* do nothing */ } else if(!BACKEND->recv_connection_closed) { /* increase enc buffer in order to fit the requested amount of data */ size = BACKEND->encdata_length - BACKEND->encdata_offset; if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || BACKEND->encdata_length < min_encdata_length) { reallocated_length = BACKEND->encdata_offset + CURL_SCHANNEL_BUFFER_FREE_SIZE; if(reallocated_length < min_encdata_length) { reallocated_length = min_encdata_length; } reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { *err = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } BACKEND->encdata_buffer = reallocated_buffer; BACKEND->encdata_length = reallocated_length; size = BACKEND->encdata_length - BACKEND->encdata_offset; DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n", BACKEND->encdata_length)); } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", BACKEND->encdata_offset, BACKEND->encdata_length)); /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], (char *)(BACKEND->encdata_buffer + BACKEND->encdata_offset), size, &nread); if(*err) { nread = -1; if(*err == CURLE_AGAIN) DEBUGF(infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n")); else if(*err == CURLE_RECV_ERROR) infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); else infof(data, "schannel: Curl_read_plain returned error %d\n", *err); } else if(nread == 0) { BACKEND->recv_connection_closed = true; DEBUGF(infof(data, "schannel: server closed the connection\n")); } else if(nread > 0) { BACKEND->encdata_offset += (size_t)nread; BACKEND->encdata_is_incomplete = false; DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread)); } } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", BACKEND->encdata_offset, BACKEND->encdata_length)); /* decrypt loop */ while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && (!len || BACKEND->decdata_offset < len || BACKEND->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, curlx_uztoul(BACKEND->encdata_offset)); /* we need 3 more empty input buffers for possible output */ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 4); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); /* check if everything went fine (server may want to renegotiate or shutdown the connection context) */ if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || sspi_status == SEC_I_CONTEXT_EXPIRED) { /* check for successfully decrypted data, even before actual renegotiation or shutdown of the connection context */ if(inbuf[1].BufferType == SECBUFFER_DATA) { DEBUGF(infof(data, "schannel: decrypted data length: %lu\n", inbuf[1].cbBuffer)); /* increase buffer in order to fit the received amount of data */ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; if(BACKEND->decdata_length - BACKEND->decdata_offset < size || BACKEND->decdata_length < len) { /* increase internal decrypted data buffer */ reallocated_length = BACKEND->decdata_offset + size; /* make sure that the requested amount of data fits */ if(reallocated_length < len) { reallocated_length = len; } reallocated_buffer = realloc(BACKEND->decdata_buffer, reallocated_length); if(reallocated_buffer == NULL) { *err = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } BACKEND->decdata_buffer = reallocated_buffer; BACKEND->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; if(size) { memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, inbuf[1].pvBuffer, size); BACKEND->decdata_offset += size; } DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size)); DEBUGF(infof(data, "schannel: decrypted cached: offset %zu length %zu\n", BACKEND->decdata_offset, BACKEND->decdata_length)); } /* check for remaining encrypted data */ if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { DEBUGF(infof(data, "schannel: encrypted data length: %lu\n", inbuf[3].cbBuffer)); /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { /* move remaining encrypted data forward to the beginning of buffer */ memmove(BACKEND->encdata_buffer, (BACKEND->encdata_buffer + BACKEND->encdata_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer); BACKEND->encdata_offset = inbuf[3].cbBuffer; } DEBUGF(infof(data, "schannel: encrypted cached: offset %zu length %zu\n", BACKEND->encdata_offset, BACKEND->encdata_length)); } else { /* reset encrypted buffer offset, because there is no data remaining */ BACKEND->encdata_offset = 0; } /* check if server wants to renegotiate the connection context */ if(sspi_status == SEC_I_RENEGOTIATE) { infof(data, "schannel: remote party requests renegotiation\n"); if(*err && *err != CURLE_AGAIN) { infof(data, "schannel: can't renogotiate, an error is pending\n"); goto cleanup; } if(BACKEND->encdata_offset) { *err = CURLE_RECV_ERROR; infof(data, "schannel: can't renogotiate, " "encrypted data available\n"); goto cleanup; } /* begin renegotiation */ infof(data, "schannel: renegotiating SSL/TLS connection\n"); connssl->state = ssl_connection_negotiating; connssl->connecting_state = ssl_connect_2_writing; *err = schannel_connect_common(conn, sockindex, FALSE, &done); if(*err) { infof(data, "schannel: renegotiation failed\n"); goto cleanup; } /* now retry receiving data */ sspi_status = SEC_E_OK; infof(data, "schannel: SSL/TLS connection renegotiated\n"); continue; } /* check if the server closed the connection */ else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not returned so we have to work around that in cleanup. */ BACKEND->recv_sspi_close_notify = true; if(!BACKEND->recv_connection_closed) { BACKEND->recv_connection_closed = true; infof(data, "schannel: server closed the connection\n"); } goto cleanup; } } else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { BACKEND->encdata_is_incomplete = true; if(!*err) *err = CURLE_AGAIN; infof(data, "schannel: failed to decrypt data, need more data\n"); goto cleanup; } else { #ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; #endif *err = CURLE_RECV_ERROR; infof(data, "schannel: failed to read data from server: %s\n", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); goto cleanup; } } DEBUGF(infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", BACKEND->encdata_offset, BACKEND->encdata_length)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", BACKEND->decdata_offset, BACKEND->decdata_length)); cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ DEBUGF(infof(data, "schannel: schannel_recv cleanup\n")); /* Error if the connection has closed without a close_notify. Behavior here is a matter of debate. We don't want to be vulnerable to a truncation attack however there's some browser precedent for ignoring the close_notify for compatibility reasons. Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't return close_notify. In that case if the connection was closed we assume it was graceful (close_notify) since there doesn't seem to be a way to tell. */ if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && !BACKEND->recv_sspi_close_notify) { bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT, VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) BACKEND->recv_sspi_close_notify = true; else { *err = CURLE_RECV_ERROR; infof(data, "schannel: server closed abruptly (missing close_notify)\n"); } } /* Any error other than CURLE_AGAIN is an unrecoverable error. */ if(*err && *err != CURLE_AGAIN) BACKEND->recv_unrecoverable_err = *err; size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; if(size) { memcpy(buf, BACKEND->decdata_buffer, size); memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, BACKEND->decdata_offset - size); BACKEND->decdata_offset -= size; DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size)); DEBUGF(infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", BACKEND->decdata_offset, BACKEND->decdata_length)); *err = CURLE_OK; return (ssize_t)size; } if(!*err && !BACKEND->recv_connection_closed) *err = CURLE_AGAIN; /* It's debatable what to return when !len. We could return whatever error we got from decryption but instead we override here so the return is consistent. */ if(!len) *err = CURLE_OK; return *err ? -1 : 0; } static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return schannel_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = schannel_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) { const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->use) /* SSL/TLS is in use */ return (BACKEND->decdata_offset > 0 || (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); else return FALSE; } static void Curl_schannel_close(struct connectdata *conn, int sockindex) { if(conn->ssl[sockindex].use) /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ Curl_ssl_shutdown(conn, sockindex); } static void Curl_schannel_session_free(void *ptr) { /* this is expected to be called under sessionid lock */ struct curl_schannel_cred *cred = ptr; cred->refcount--; if(cred->refcount == 0) { s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); Curl_safefree(cred); } } static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) { /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx * Shutting Down an Schannel Connection */ struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; DEBUGASSERT(data); infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", hostname, conn->remote_port); if(BACKEND->cred && BACKEND->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; SecBuffer outbuf; SecBufferDesc outbuf_desc; CURLcode result; TCHAR *host_name; DWORD dwshut = SCHANNEL_SHUTDOWN; InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); InitSecBufferDesc(&BuffDesc, &Buffer, 1); sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, &BuffDesc); if(sspi_status != SEC_E_OK) { char buffer[STRERROR_LEN]; failf(data, "schannel: ApplyControlToken failure: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); } host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); sspi_status = s_pSecFn->InitializeSecurityContext( &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, host_name, BACKEND->req_flags, 0, 0, NULL, 0, &BACKEND->ctxt->ctxt_handle, &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); Curl_unicodefree(host_name); if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ ssize_t written; result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer, outbuf.cbBuffer, &written); s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { infof(data, "schannel: failed to send close msg: %s" " (bytes written: %zd)\n", curl_easy_strerror(result), written); } } } /* free SSPI Schannel API security context handle */ if(BACKEND->ctxt) { DEBUGF(infof(data, "schannel: clear security context handle\n")); s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); Curl_safefree(BACKEND->ctxt); } /* free SSPI Schannel API credential handle */ if(BACKEND->cred) { /* * When this function is called from Curl_schannel_close() the connection * might not have an associated transfer so the check for conn->data is * necessary. */ Curl_ssl_sessionid_lock(conn); Curl_schannel_session_free(BACKEND->cred); Curl_ssl_sessionid_unlock(conn); BACKEND->cred = NULL; } /* free internal buffer for received encrypted data */ if(BACKEND->encdata_buffer != NULL) { Curl_safefree(BACKEND->encdata_buffer); BACKEND->encdata_length = 0; BACKEND->encdata_offset = 0; BACKEND->encdata_is_incomplete = false; } /* free internal buffer for received decrypted data */ if(BACKEND->decdata_buffer != NULL) { Curl_safefree(BACKEND->decdata_buffer); BACKEND->decdata_length = 0; BACKEND->decdata_offset = 0; } return CURLE_OK; } static int Curl_schannel_init(void) { return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); } static void Curl_schannel_cleanup(void) { Curl_sspi_global_cleanup(); } static size_t Curl_schannel_version(char *buffer, size_t size) { size = msnprintf(buffer, size, "Schannel"); return size; } static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM, unsigned char *entropy, size_t length) { HCRYPTPROV hCryptProv = 0; (void)data; if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return CURLE_FAILED_INIT; if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { CryptReleaseContext(hCryptProv, 0UL); return CURLE_FAILED_INIT; } CryptReleaseContext(hCryptProv, 0UL); return CURLE_OK; } static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex, const char *pinnedpubkey) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CERT_CONTEXT *pCertContextServer = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; do { SECURITY_STATUS sspi_status; const char *x509_der; DWORD x509_der_len; curl_X509certificate x509_parsed; curl_asn1Element *pubkey; sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pCertContextServer); if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) { char buffer[STRERROR_LEN]; failf(data, "schannel: Failed to read remote certificate context: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); break; /* failed */ } if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) && (pCertContextServer->cbCertEncoded > 0))) break; x509_der = (const char *)pCertContextServer->pbCertEncoded; x509_der_len = pCertContextServer->cbCertEncoded; memset(&x509_parsed, 0, sizeof(x509_parsed)); if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) break; pubkey = &x509_parsed.subjectPublicKeyInfo; if(!pubkey->header || pubkey->end <= pubkey->header) { failf(data, "SSL: failed retrieving public key from server certificate"); break; } result = Curl_pin_peer_pubkey(data, pinnedpubkey, (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { failf(data, "SSL: public key does not match pinned public key!"); } } while(0); if(pCertContextServer) CertFreeCertificateContext(pCertContextServer); return result; } static void Curl_schannel_checksum(const unsigned char *input, size_t inputlen, unsigned char *checksum, size_t checksumlen, DWORD provType, const unsigned int algId) { HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; DWORD cbHashSize = 0; DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize); DWORD dwChecksumLen = (DWORD)checksumlen; /* since this can fail in multiple ways, zero memory first so we never * return old data */ memset(checksum, 0, checksumlen); if(!CryptAcquireContext(&hProv, NULL, NULL, provType, CRYPT_VERIFYCONTEXT)) return; /* failed */ do { if(!CryptCreateHash(hProv, algId, 0, 0, &hHash)) break; /* failed */ /* workaround for original MinGW, should be (const BYTE*) */ if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0)) break; /* failed */ /* get hash size */ if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize, &dwHashSizeLen, 0)) break; /* failed */ /* check hash size */ if(checksumlen < cbHashSize) break; /* failed */ if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0)) break; /* failed */ } while(0); if(hHash) CryptDestroyHash(hHash); if(hProv) CryptReleaseContext(hProv, 0); } static CURLcode Curl_schannel_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len) { Curl_schannel_checksum(input, inputlen, md5sum, md5len, PROV_RSA_FULL, CALG_MD5); return CURLE_OK; } static CURLcode Curl_schannel_sha256sum(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, size_t sha256len) { Curl_schannel_checksum(input, inputlen, sha256sum, sha256len, PROV_RSA_AES, CALG_SHA_256); return CURLE_OK; } static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return &BACKEND->ctxt->ctxt_handle; } const struct Curl_ssl Curl_ssl_schannel = { { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */ SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY, sizeof(struct ssl_backend_data), Curl_schannel_init, /* init */ Curl_schannel_cleanup, /* cleanup */ Curl_schannel_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_schannel_shutdown, /* shutdown */ Curl_schannel_data_pending, /* data_pending */ Curl_schannel_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_schannel_connect, /* connect */ Curl_schannel_connect_nonblocking, /* connect_nonblocking */ Curl_schannel_get_internals, /* get_internals */ Curl_schannel_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_schannel_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_schannel_md5sum, /* md5sum */ Curl_schannel_sha256sum /* sha256sum */ }; #endif /* USE_SCHANNEL */ davix-0.8.0/deps/curl/lib/vtls/bearssl.c0000644000000000000000000006127314121063461016574 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2019, Michael Forney, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_BEARSSL #include #include "bearssl.h" #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "vtls.h" #include "connect.h" #include "select.h" #include "multiif.h" #include "curl_printf.h" #include "curl_memory.h" struct x509_context { const br_x509_class *vtable; br_x509_minimal_context minimal; bool verifyhost; bool verifypeer; }; struct ssl_backend_data { br_ssl_client_context ctx; struct x509_context x509; unsigned char buf[BR_SSL_BUFSIZE_BIDI]; br_x509_trust_anchor *anchors; size_t anchors_len; const char *protocols[2]; /* SSL client context is active */ bool active; /* size of pending write, yet to be flushed */ size_t pending_write; }; #define BACKEND connssl->backend struct cafile_parser { CURLcode err; bool in_cert; br_x509_decoder_context xc; /* array of trust anchors loaded from CAfile */ br_x509_trust_anchor *anchors; size_t anchors_len; /* buffer for DN data */ unsigned char dn[1024]; size_t dn_len; }; static void append_dn(void *ctx, const void *buf, size_t len) { struct cafile_parser *ca = ctx; if(ca->err != CURLE_OK || !ca->in_cert) return; if(sizeof(ca->dn) - ca->dn_len < len) { ca->err = CURLE_FAILED_INIT; return; } memcpy(ca->dn + ca->dn_len, buf, len); ca->dn_len += len; } static void x509_push(void *ctx, const void *buf, size_t len) { struct cafile_parser *ca = ctx; if(ca->in_cert) br_x509_decoder_push(&ca->xc, buf, len); } static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, size_t *anchors_len) { struct cafile_parser ca; br_pem_decoder_context pc; br_x509_trust_anchor *ta; size_t ta_size; br_x509_trust_anchor *new_anchors; size_t new_anchors_len; br_x509_pkey *pkey; FILE *fp; unsigned char buf[BUFSIZ], *p; const char *name; size_t n, i, pushed; fp = fopen(path, "rb"); if(!fp) return CURLE_SSL_CACERT_BADFILE; ca.err = CURLE_OK; ca.in_cert = FALSE; ca.anchors = NULL; ca.anchors_len = 0; br_pem_decoder_init(&pc); br_pem_decoder_setdest(&pc, x509_push, &ca); for(;;) { n = fread(buf, 1, sizeof(buf), fp); if(n == 0) break; p = buf; while(n) { pushed = br_pem_decoder_push(&pc, p, n); if(ca.err) goto fail; p += pushed; n -= pushed; switch(br_pem_decoder_event(&pc)) { case 0: break; case BR_PEM_BEGIN_OBJ: name = br_pem_decoder_name(&pc); if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE")) break; br_x509_decoder_init(&ca.xc, append_dn, &ca); if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) { ca.err = CURLE_OUT_OF_MEMORY; goto fail; } new_anchors_len = ca.anchors_len + 1; new_anchors = realloc(ca.anchors, new_anchors_len * sizeof(ca.anchors[0])); if(!new_anchors) { ca.err = CURLE_OUT_OF_MEMORY; goto fail; } ca.anchors = new_anchors; ca.anchors_len = new_anchors_len; ca.in_cert = TRUE; ca.dn_len = 0; ta = &ca.anchors[ca.anchors_len - 1]; ta->dn.data = NULL; break; case BR_PEM_END_OBJ: if(!ca.in_cert) break; ca.in_cert = FALSE; if(br_x509_decoder_last_error(&ca.xc)) { ca.err = CURLE_SSL_CACERT_BADFILE; goto fail; } ta->flags = 0; if(br_x509_decoder_isCA(&ca.xc)) ta->flags |= BR_X509_TA_CA; pkey = br_x509_decoder_get_pkey(&ca.xc); if(!pkey) { ca.err = CURLE_SSL_CACERT_BADFILE; goto fail; } ta->pkey = *pkey; /* calculate space needed for trust anchor data */ ta_size = ca.dn_len; switch(pkey->key_type) { case BR_KEYTYPE_RSA: ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen; break; case BR_KEYTYPE_EC: ta_size += pkey->key.ec.qlen; break; default: ca.err = CURLE_FAILED_INIT; goto fail; } /* fill in trust anchor DN and public key data */ ta->dn.data = malloc(ta_size); if(!ta->dn.data) { ca.err = CURLE_OUT_OF_MEMORY; goto fail; } memcpy(ta->dn.data, ca.dn, ca.dn_len); ta->dn.len = ca.dn_len; switch(pkey->key_type) { case BR_KEYTYPE_RSA: ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len; memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen); ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen; memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen); break; case BR_KEYTYPE_EC: ta->pkey.key.ec.q = ta->dn.data + ta->dn.len; memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen); break; } break; default: ca.err = CURLE_SSL_CACERT_BADFILE; goto fail; } } } if(ferror(fp)) ca.err = CURLE_READ_ERROR; fail: fclose(fp); if(ca.err == CURLE_OK) { *anchors = ca.anchors; *anchors_len = ca.anchors_len; } else { for(i = 0; i < ca.anchors_len; ++i) free(ca.anchors[i].dn.data); free(ca.anchors); } return ca.err; } static void x509_start_chain(const br_x509_class **ctx, const char *server_name) { struct x509_context *x509 = (struct x509_context *)ctx; if(!x509->verifyhost) server_name = NULL; x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name); } static void x509_start_cert(const br_x509_class **ctx, uint32_t length) { struct x509_context *x509 = (struct x509_context *)ctx; x509->minimal.vtable->start_cert(&x509->minimal.vtable, length); } static void x509_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) { struct x509_context *x509 = (struct x509_context *)ctx; x509->minimal.vtable->append(&x509->minimal.vtable, buf, len); } static void x509_end_cert(const br_x509_class **ctx) { struct x509_context *x509 = (struct x509_context *)ctx; x509->minimal.vtable->end_cert(&x509->minimal.vtable); } static unsigned x509_end_chain(const br_x509_class **ctx) { struct x509_context *x509 = (struct x509_context *)ctx; unsigned err; err = x509->minimal.vtable->end_chain(&x509->minimal.vtable); if(err && !x509->verifypeer) { /* ignore any X.509 errors */ err = BR_ERR_OK; } return err; } static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx, unsigned *usages) { struct x509_context *x509 = (struct x509_context *)ctx; return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages); } static const br_x509_class x509_vtable = { sizeof(struct x509_context), x509_start_chain, x509_start_cert, x509_append, x509_end_cert, x509_end_chain, x509_get_pkey }; static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const bool verifyhost = SSL_CONN_CONFIG(verifyhost); CURLcode ret; unsigned version_min, version_max; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv2: failf(data, "BearSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv3: failf(data, "BearSSL does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_TLSv1_0: version_min = BR_TLS10; version_max = BR_TLS10; break; case CURL_SSLVERSION_TLSv1_1: version_min = BR_TLS11; version_max = BR_TLS11; break; case CURL_SSLVERSION_TLSv1_2: version_min = BR_TLS12; version_max = BR_TLS12; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: version_min = BR_TLS10; version_max = BR_TLS12; break; default: failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(ssl_cafile) { ret = load_cafile(ssl_cafile, &BACKEND->anchors, &BACKEND->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n", ssl_cafile); return ret; } infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } } /* initialize SSL context */ br_ssl_client_init_full(&BACKEND->ctx, &BACKEND->x509.minimal, BACKEND->anchors, BACKEND->anchors_len); br_ssl_engine_set_versions(&BACKEND->ctx.eng, version_min, version_max); br_ssl_engine_set_buffer(&BACKEND->ctx.eng, BACKEND->buf, sizeof(BACKEND->buf), 1); /* initialize X.509 context */ BACKEND->x509.vtable = &x509_vtable; BACKEND->x509.verifypeer = verifypeer; BACKEND->x509.verifyhost = verifyhost; br_ssl_engine_set_x509(&BACKEND->ctx.eng, &BACKEND->x509.vtable); if(SSL_SET_OPTION(primary.sessionid)) { void *session; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { br_ssl_engine_set_session_parameters(&BACKEND->ctx.eng, session); infof(data, "BearSSL: re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } if(conn->bits.tls_enable_alpn) { int cur = 0; /* NOTE: when adding more protocols here, increase the size of the * protocols array in `struct ssl_backend_data`. */ #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { BACKEND->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif BACKEND->protocols[cur++] = ALPN_HTTP_1_1; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); br_ssl_engine_set_protocol_names(&BACKEND->ctx.eng, BACKEND->protocols, cur); } if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) #ifdef ENABLE_IPV6 || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) #endif ) { if(verifyhost) { failf(data, "BearSSL: " "host verification of IP address is not supported"); return CURLE_PEER_FAILED_VERIFICATION; } hostname = NULL; } if(!br_ssl_client_reset(&BACKEND->ctx, hostname, 0)) return CURLE_FAILED_INIT; BACKEND->active = TRUE; connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, unsigned target) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; unsigned state; unsigned char *buf; size_t len; ssize_t ret; int err; for(;;) { state = br_ssl_engine_current_state(&BACKEND->ctx.eng); if(state & BR_SSL_CLOSED) { err = br_ssl_engine_last_error(&BACKEND->ctx.eng); switch(err) { case BR_ERR_OK: /* TLS close notify */ if(connssl->state != ssl_connection_complete) { failf(data, "SSL: connection closed during handshake"); return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; case BR_ERR_X509_EXPIRED: failf(data, "SSL: X.509 verification: " "certificate is expired or not yet valid"); return CURLE_PEER_FAILED_VERIFICATION; case BR_ERR_X509_BAD_SERVER_NAME: failf(data, "SSL: X.509 verification: " "expected server name was not found in the chain"); return CURLE_PEER_FAILED_VERIFICATION; case BR_ERR_X509_NOT_TRUSTED: failf(data, "SSL: X.509 verification: " "chain could not be linked to a trust anchor"); return CURLE_PEER_FAILED_VERIFICATION; } /* X.509 errors are documented to have the range 32..63 */ if(err >= 32 && err < 64) return CURLE_PEER_FAILED_VERIFICATION; return CURLE_SSL_CONNECT_ERROR; } if(state & target) return CURLE_OK; if(state & BR_SSL_SENDREC) { buf = br_ssl_engine_sendrec_buf(&BACKEND->ctx.eng, &len); ret = swrite(sockfd, buf, len); if(ret == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { if(connssl->state != ssl_connection_complete) connssl->connecting_state = ssl_connect_2_writing; return CURLE_AGAIN; } return CURLE_WRITE_ERROR; } br_ssl_engine_sendrec_ack(&BACKEND->ctx.eng, ret); } else if(state & BR_SSL_RECVREC) { buf = br_ssl_engine_recvrec_buf(&BACKEND->ctx.eng, &len); ret = sread(sockfd, buf, len); if(ret == 0) { failf(data, "SSL: EOF without close notify"); return CURLE_READ_ERROR; } if(ret == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { if(connssl->state != ssl_connection_complete) connssl->connecting_state = ssl_connect_2_reading; return CURLE_AGAIN; } return CURLE_READ_ERROR; } br_ssl_engine_recvrec_ack(&BACKEND->ctx.eng, ret); } } } static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode ret; ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP); if(ret == CURLE_AGAIN) return CURLE_OK; if(ret == CURLE_OK) { if(br_ssl_engine_current_state(&BACKEND->ctx.eng) == BR_SSL_CLOSED) { failf(data, "SSL: connection closed during handshake"); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_3; } return ret; } static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode ret; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); if(conn->bits.tls_enable_alpn) { const char *protocol; protocol = br_ssl_engine_get_selected_protocol(&BACKEND->ctx.eng); if(protocol) { infof(data, "ALPN, server accepted to use %s\n", protocol); #ifdef USE_NGHTTP2 if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID)) conn->negnpn = CURL_HTTP_VERSION_2; else #endif if(!strcmp(protocol, ALPN_HTTP_1_1)) conn->negnpn = CURL_HTTP_VERSION_1_1; else infof(data, "ALPN, unrecognized protocol %s\n", protocol); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else infof(data, "ALPN, server did not agree to a protocol\n"); } if(SSL_SET_OPTION(primary.sessionid)) { bool incache; void *oldsession; br_ssl_session_parameters *session; session = malloc(sizeof(*session)); if(!session) return CURLE_OUT_OF_MEMORY; br_ssl_engine_get_session_parameters(&BACKEND->ctx.eng, session); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); if(incache) Curl_ssl_delsessionid(conn, oldsession); ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); Curl_ssl_sessionid_unlock(conn); if(ret) { free(session); return CURLE_OUT_OF_MEMORY; } } connssl->connecting_state = ssl_connect_done; return CURLE_OK; } static ssize_t bearssl_send(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *app; size_t applen; for(;;) { *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP); if (*err != CURLE_OK) return -1; app = br_ssl_engine_sendapp_buf(&BACKEND->ctx.eng, &applen); if(!app) { failf(data, "SSL: connection closed during write"); *err = CURLE_SEND_ERROR; return -1; } if(BACKEND->pending_write) { applen = BACKEND->pending_write; BACKEND->pending_write = 0; return applen; } if(applen > len) applen = len; memcpy(app, buf, applen); br_ssl_engine_sendapp_ack(&BACKEND->ctx.eng, applen); br_ssl_engine_flush(&BACKEND->ctx.eng, 0); BACKEND->pending_write = applen; } } static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *app; size_t applen; *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP); if(*err != CURLE_OK) return -1; app = br_ssl_engine_recvapp_buf(&BACKEND->ctx.eng, &applen); if(!app) return 0; if(applen > len) applen = len; memcpy(buf, app, applen); br_ssl_engine_recvapp_ack(&BACKEND->ctx.eng, applen); return applen; } static CURLcode bearssl_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode ret; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; time_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { ret = bearssl_connect_step1(conn, sockindex); if(ret) return ret; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if this * connection is done nonblocking and this loop would execute again. This * permits the owner of a multi handle to abort a connection attempt * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ ret = bearssl_connect_step2(conn, sockindex); if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return ret; } if(ssl_connect_3 == connssl->connecting_state) { ret = bearssl_connect_step3(conn, sockindex); if(ret) return ret; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = bearssl_recv; conn->send[sockindex] = bearssl_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static size_t Curl_bearssl_version(char *buffer, size_t size) { return msnprintf(buffer, size, "BearSSL"); } static bool Curl_bearssl_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; return br_ssl_engine_current_state(&BACKEND->ctx.eng) & BR_SSL_RECVAPP; } static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, unsigned char *entropy, size_t length) { static br_hmac_drbg_context ctx; static bool seeded = FALSE; if(!seeded) { br_prng_seeder seeder; br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); seeder = br_prng_seeder_system(NULL); if(!seeder || !seeder(&ctx.vtable)) return CURLE_FAILED_INIT; seeded = TRUE; } br_hmac_drbg_generate(&ctx, entropy, length); return CURLE_OK; } static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex) { CURLcode ret; bool done = FALSE; ret = bearssl_connect_common(conn, sockindex, FALSE, &done); if(ret) return ret; DEBUGASSERT(done); return CURLE_OK; } static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return bearssl_connect_common(conn, sockindex, TRUE, done); } static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { return &BACKEND->ctx; } static void Curl_bearssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; size_t i; if(BACKEND->active) { br_ssl_engine_close(&BACKEND->ctx.eng); (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED); } for(i = 0; i < BACKEND->anchors_len; ++i) free(BACKEND->anchors[i].dn.data); free(BACKEND->anchors); } static void Curl_bearssl_session_free(void *ptr) { free(ptr); } static CURLcode Curl_bearssl_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len UNUSED_PARAM) { br_md5_context ctx; br_md5_init(&ctx); br_md5_update(&ctx, input, inputlen); br_md5_out(&ctx, md5sum); return CURLE_OK; } static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, size_t sha256len UNUSED_PARAM) { br_sha256_context ctx; br_sha256_init(&ctx); br_sha256_update(&ctx, input, inputlen); br_sha256_out(&ctx, sha256sum); return CURLE_OK; } const struct Curl_ssl Curl_ssl_bearssl = { { CURLSSLBACKEND_BEARSSL, "bearssl" }, 0, sizeof(struct ssl_backend_data), Curl_none_init, Curl_none_cleanup, Curl_bearssl_version, Curl_none_check_cxn, Curl_none_shutdown, Curl_bearssl_data_pending, Curl_bearssl_random, Curl_none_cert_status_request, Curl_bearssl_connect, Curl_bearssl_connect_nonblocking, Curl_bearssl_get_internals, Curl_bearssl_close, Curl_none_close_all, Curl_bearssl_session_free, Curl_none_set_engine, Curl_none_set_engine_default, Curl_none_engines_list, Curl_none_false_start, Curl_bearssl_md5sum, Curl_bearssl_sha256sum }; #endif /* USE_BEARSSL */ davix-0.8.0/deps/curl/lib/vtls/wolfssl.c0000644000000000000000000007460414121063461016634 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all wolfSSL specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. * */ #include "curl_setup.h" #ifdef USE_WOLFSSL #define WOLFSSL_OPTIONS_IGNORE_SYS #include #include /* To determine what functions are available we rely on one or both of: - the user's options.h generated by wolfSSL - the symbols detected by curl's configure Since they are markedly different from one another, and one or the other may not be available, we do some checking below to bring things in sync. */ /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ #ifndef HAVE_ALPN #ifdef HAVE_WOLFSSL_USEALPN #define HAVE_ALPN #endif #endif /* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in options.h, but is only seen in >= 3.6.6 since that's when they started disabling SSLv3 by default. */ #ifndef WOLFSSL_ALLOW_SSLV3 #if (LIBWOLFSSL_VERSION_HEX < 0x03006006) || \ defined(HAVE_WOLFSSLV3_CLIENT_METHOD) #define WOLFSSL_ALLOW_SSLV3 #endif #endif #include #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" #include "multiif.h" #include #include #include #include "wolfssl.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* KEEP_PEER_CERT is a product of the presence of build time symbol OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is in wolfSSL's settings.h, and the latter two are build time symbols in options.h. */ #ifndef KEEP_PEER_CERT #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) #define KEEP_PEER_CERT #endif #endif struct ssl_backend_data { SSL_CTX* ctx; SSL* handle; }; #define BACKEND connssl->backend static Curl_recv wolfssl_recv; static Curl_send wolfssl_send; static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; return -1; } /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ static CURLcode wolfssl_connect_step1(struct connectdata *conn, int sockindex) { char *ciphers; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; #define use_sni(x) sni = (x) #else #define use_sni(x) Curl_nop_stmt #endif if(connssl->state == ssl_connection_complete) return CURLE_OK; if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { failf(data, "wolfSSL does not support to set maximum SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } /* check to see if we've been told to use an explicit SSL/TLS version */ switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ /* minimum protocol version is set later after the CTX object is created */ req_method = SSLv23_client_method(); #else infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " "TLS 1.0 is used exclusively\n"); req_method = TLSv1_client_method(); #endif use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_0: #ifdef WOLFSSL_ALLOW_TLSV10 req_method = TLSv1_client_method(); use_sni(TRUE); #else failf(data, "wolfSSL does not support TLS 1.0"); return CURLE_NOT_BUILT_IN; #endif break; case CURL_SSLVERSION_TLSv1_1: req_method = TLSv1_1_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_2: req_method = TLSv1_2_client_method(); use_sni(TRUE); break; case CURL_SSLVERSION_TLSv1_3: #ifdef WOLFSSL_TLS13 req_method = wolfTLSv1_3_client_method(); use_sni(TRUE); break; #else failf(data, "wolfSSL: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; #endif case CURL_SSLVERSION_SSLv3: #ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); #else failf(data, "wolfSSL does not support SSLv3"); return CURLE_NOT_BUILT_IN; #endif break; case CURL_SSLVERSION_SSLv2: failf(data, "wolfSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(!req_method) { failf(data, "SSL: couldn't create a method!"); return CURLE_OUT_OF_MEMORY; } if(BACKEND->ctx) SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = SSL_CTX_new(req_method); if(!BACKEND->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is * whatever minimum version of TLS was built in and at least TLS 1.0. For * later library versions that could change (eg TLS 1.0 built in but * defaults to TLS 1.1) so we have this short circuit evaluation to find * the minimum supported TLS version. */ if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1) #ifdef WOLFSSL_TLS13 && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1) #endif ) { failf(data, "SSL: couldn't set the minimum protocol version"); return CURLE_SSL_CONNECT_ERROR; } #endif break; } ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } infof(data, "Cipher selection: %s\n", ciphers); } #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", SSL_CONN_CONFIG(CAfile)? SSL_CONN_CONFIG(CAfile): "none", SSL_CONN_CONFIG(CApath)? SSL_CONN_CONFIG(CApath) : "none"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } } else { /* Everything is fine. */ infof(data, "successfully set certificate verify locations:\n"); } infof(data, " CAfile: %s\n" " CApath: %s\n", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none"); } /* Load the client certificate, and private key */ if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } file_type = do_file_type(SSL_SET_OPTION(key_type)); if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } } #endif /* !NO_FILESYSTEM */ /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(BACKEND->ctx, SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI if(sni) { struct in_addr addr4; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; size_t hostname_len = strlen(hostname); if((hostname_len < USHRT_MAX) && (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif (wolfSSL_CTX_UseSNI(BACKEND->ctx, WOLFSSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); } } #endif /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, data->set.ssl.fsslctxp); if(result) { failf(data, "error signaled by ssl ctx callback"); return result; } } #ifdef NO_FILESYSTEM else if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "SSL: Certificates can't be loaded because wolfSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); return CURLE_SSL_CONNECT_ERROR; } #endif /* Let's make an SSL structure */ if(BACKEND->handle) SSL_free(BACKEND->handle); BACKEND->handle = SSL_new(BACKEND->ctx); if(!BACKEND->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } #ifdef HAVE_ALPN if(conn->bits.tls_enable_alpn) { char protocols[128]; *protocols = '\0'; /* wolfSSL's ALPN protocol name list format is a comma separated string of protocols in descending order of preference, eg: "h2,http/1.1" */ #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); if(wolfSSL_UseALPN(BACKEND->handle, protocols, (unsigned)strlen(protocols), WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { failf(data, "SSL: failed setting ALPN protocols"); return CURLE_SSL_CONNECT_ERROR; } } #endif /* HAVE_ALPN */ /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof(data, "SSL re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layer */ if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode wolfssl_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname; const char * const pinnedpubkey = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; conn->recv[sockindex] = wolfssl_recv; conn->send[sockindex] = wolfssl_send; /* Enable RFC2818 checks */ if(SSL_CONN_CONFIG(verifyhost)) { ret = wolfSSL_check_domain_name(BACKEND->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } ret = SSL_connect(BACKEND->handle); if(ret != 1) { char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int detail = SSL_get_error(BACKEND->handle, ret); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else if(SSL_ERROR_WANT_WRITE == detail) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } /* There is no easy way to override only the CN matching. * This will enable the override of both mismatching SubjectAltNames * as also mismatching CN fields */ else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; #else /* When the wolfssl_check_domain_name() is used and you desire to * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA * error. The only way to do this is currently to switch the * Wolfssl_check_domain_name() in and out based on the * 'conn->ssl_config.verifyhost' value. */ if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, "\tsubject alt name(s) and/or common name do not match \"%s\"\n", dispname); return CURLE_OK; } #endif } #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "\tCA signer not available for verification\n"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "CA signer not available for verification, " "continuing anyway\n"); } } #endif else { failf(data, "SSL_connect failed with error %d: %s", detail, ERR_error_string(detail, error_buffer)); return CURLE_SSL_CONNECT_ERROR; } } if(pinnedpubkey) { #ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; int x509_der_len; curl_X509certificate x509_parsed; curl_asn1Element *pubkey; CURLcode result; x509 = SSL_get_peer_certificate(BACKEND->handle); if(!x509) { failf(data, "SSL: failed retrieving server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len); if(!x509_der) { failf(data, "SSL: failed retrieving ASN.1 server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } memset(&x509_parsed, 0, sizeof(x509_parsed)); if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) return CURLE_SSL_PINNEDPUBKEYNOTMATCH; pubkey = &x509_parsed.subjectPublicKeyInfo; if(!pubkey->header || pubkey->end <= pubkey->header) { failf(data, "SSL: failed retrieving public key from server certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } result = Curl_pin_peer_pubkey(data, pinnedpubkey, (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } #else failf(data, "Library lacks pinning support built-in"); return CURLE_NOT_BUILT_IN; #endif } #ifdef HAVE_ALPN if(conn->bits.tls_enable_alpn) { int rc; char *protocol = NULL; unsigned short protocol_len = 0; rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len); if(rc == SSL_SUCCESS) { infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, protocol); if(protocol_len == ALPN_HTTP_1_1_LENGTH && !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) conn->negnpn = CURL_HTTP_VERSION_1_1; #ifdef USE_NGHTTP2 else if(data->set.httpversion >= CURL_HTTP_VERSION_2 && protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) conn->negnpn = CURL_HTTP_VERSION_2; #endif else infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, protocol); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else if(rc == SSL_ALPN_NOT_FOUND) infof(data, "ALPN, server did not agree to a protocol\n"); else { failf(data, "ALPN, failure getting protocol, error %d", rc); return CURLE_SSL_CONNECT_ERROR; } } #endif /* HAVE_ALPN */ connssl->connecting_state = ssl_connect_3; #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) infof(data, "SSL connection using %s / %s\n", wolfSSL_get_version(BACKEND->handle), wolfSSL_get_cipher_name(BACKEND->handle)); #else infof(data, "SSL connected\n"); #endif return CURLE_OK; } static CURLcode wolfssl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); if(SSL_SET_OPTION(primary.sessionid)) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; our_ssl_sessionid = SSL_get_session(BACKEND->handle); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); Curl_ssl_delsessionid(conn, old_ssl_sessionid); incache = FALSE; } } if(!incache) { result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0 /* unknown size */, sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "failed to store ssl session"); return result; } } Curl_ssl_sessionid_unlock(conn); } connssl->connecting_state = ssl_connect_done; return result; } static ssize_t wolfssl_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; int rc = SSL_write(BACKEND->handle, mem, memlen); if(rc < 0) { int err = SSL_get_error(BACKEND->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_write() */ *curlcode = CURLE_AGAIN; return -1; default: failf(conn->data, "SSL write: %s, errno %d", ERR_error_string(err, error_buffer), SOCKERRNO); *curlcode = CURLE_SEND_ERROR; return -1; } } return rc; } static void Curl_wolfssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(BACKEND->handle) { (void)SSL_shutdown(BACKEND->handle); SSL_free(BACKEND->handle); BACKEND->handle = NULL; } if(BACKEND->ctx) { SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = NULL; } } static ssize_t wolfssl_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; int nread = SSL_read(BACKEND->handle, buf, buffsize); if(nread < 0) { int err = SSL_get_error(BACKEND->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_read() */ *curlcode = CURLE_AGAIN; return -1; default: failf(conn->data, "SSL read: %s, errno %d", ERR_error_string(err, error_buffer), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; } } return nread; } static void Curl_wolfssl_session_free(void *ptr) { (void)ptr; /* wolfSSL reuses sessions on own, no free */ } static size_t Curl_wolfssl_version(char *buffer, size_t size) { #if LIBWOLFSSL_VERSION_HEX >= 0x03006000 return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); #elif defined(WOLFSSL_VERSION) return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); #endif } static int Curl_wolfssl_init(void) { return (wolfSSL_Init() == SSL_SUCCESS); } static void Curl_wolfssl_cleanup(void) { wolfSSL_Cleanup(); } static bool Curl_wolfssl_data_pending(const struct connectdata* conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; if(BACKEND->handle) /* SSL is in use */ return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE; else return FALSE; } /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(BACKEND->handle) { SSL_free(BACKEND->handle); BACKEND->handle = NULL; } return retval; } static CURLcode wolfssl_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; time_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } result = wolfssl_connect_step1(conn, sockindex); if(result) return result; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if * this connection is part of a multi handle and this loop would * execute again. This permits the owner of a multi handle to * abort a connection attempt before step2 has completed while * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ result = wolfssl_connect_step2(conn, sockindex); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { result = wolfssl_connect_step3(conn, sockindex); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = wolfssl_recv; conn->send[sockindex] = wolfssl_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_wolfssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return wolfssl_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = wolfssl_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static CURLcode Curl_wolfssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { WC_RNG rng; (void)data; if(wc_InitRng(&rng)) return CURLE_FAILED_INIT; if(length > UINT_MAX) return CURLE_FAILED_INIT; if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length)) return CURLE_FAILED_INIT; if(wc_FreeRng(&rng)) return CURLE_FAILED_INIT; return CURLE_OK; } static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum /* output */, size_t unused) { wc_Sha256 SHA256pw; (void)unused; wc_InitSha256(&SHA256pw); wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen); wc_Sha256Final(&SHA256pw, sha256sum); return CURLE_OK; } static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->handle; } const struct Curl_ssl Curl_ssl_wolfssl = { { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */ #ifdef KEEP_PEER_CERT SSLSUPP_PINNEDPUBKEY | #endif SSLSUPP_SSL_CTX, sizeof(struct ssl_backend_data), Curl_wolfssl_init, /* init */ Curl_wolfssl_cleanup, /* cleanup */ Curl_wolfssl_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_wolfssl_shutdown, /* shutdown */ Curl_wolfssl_data_pending, /* data_pending */ Curl_wolfssl_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_wolfssl_connect, /* connect */ Curl_wolfssl_connect_nonblocking, /* connect_nonblocking */ Curl_wolfssl_get_internals, /* get_internals */ Curl_wolfssl_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_wolfssl_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_none_md5sum, /* md5sum */ Curl_wolfssl_sha256sum /* sha256sum */ }; #endif davix-0.8.0/deps/curl/lib/vtls/vtls.c0000644000000000000000000010741514121063461016130 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* This file is for implementing all "generic" SSL functions that all libcurl internals should use. It is then responsible for calling the proper "backend" function. SSL-functions in libcurl should call functions in this source file, and not to any specific SSL-layer. Curl_ssl_ - prefix for generic ones Note that this source code uses the functions of the configured SSL backend via the global Curl_ssl instance. "SSL/TLS Strong Encryption: An Introduction" https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html */ #include "curl_setup.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #include "urldata.h" #include "vtls.h" /* generic SSL protos etc */ #include "slist.h" #include "sendf.h" #include "strcase.h" #include "url.h" #include "progress.h" #include "share.h" #include "multiif.h" #include "timeval.h" #include "curl_md5.h" #include "warnless.h" #include "curl_base64.h" #include "curl_printf.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* convenience macro to check if this handle is using a shared SSL session */ #define SSLSESSION_SHARED(data) (data->share && \ (data->share->specifier & \ (1<var) { \ dest->var = strdup(source->var); \ if(!dest->var) \ return FALSE; \ } \ else \ dest->var = NULL; bool Curl_ssl_config_matches(struct ssl_primary_config* data, struct ssl_primary_config* needle) { if((data->version == needle->version) && (data->version_max == needle->version_max) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && (data->verifystatus == needle->verifystatus) && Curl_safe_strcasecompare(data->CApath, needle->CApath) && Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && Curl_safe_strcasecompare(data->random_file, needle->random_file) && Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key)) return TRUE; return FALSE; } bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, struct ssl_primary_config *dest) { dest->version = source->version; dest->version_max = source->version_max; dest->verifypeer = source->verifypeer; dest->verifyhost = source->verifyhost; dest->verifystatus = source->verifystatus; dest->sessionid = source->sessionid; CLONE_STRING(CApath); CLONE_STRING(CAfile); CLONE_STRING(clientcert); CLONE_STRING(random_file); CLONE_STRING(egdsocket); CLONE_STRING(cipher_list); CLONE_STRING(cipher_list13); CLONE_STRING(pinned_key); return TRUE; } void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) { Curl_safefree(sslc->CApath); Curl_safefree(sslc->CAfile); Curl_safefree(sslc->clientcert); Curl_safefree(sslc->random_file); Curl_safefree(sslc->egdsocket); Curl_safefree(sslc->cipher_list); Curl_safefree(sslc->cipher_list13); Curl_safefree(sslc->pinned_key); } #ifdef USE_SSL static int multissl_init(const struct Curl_ssl *backend); #endif int Curl_ssl_backend(void) { #ifdef USE_SSL multissl_init(NULL); return Curl_ssl->info.id; #else return (int)CURLSSLBACKEND_NONE; #endif } #ifdef USE_SSL /* "global" init done? */ static bool init_ssl = FALSE; /** * Global SSL init * * @retval 0 error initializing SSL * @retval 1 SSL initialized successfully */ int Curl_ssl_init(void) { /* make sure this is only done once */ if(init_ssl) return 1; init_ssl = TRUE; /* never again */ return Curl_ssl->init(); } /* Global cleanup */ void Curl_ssl_cleanup(void) { if(init_ssl) { /* only cleanup if we did a previous init */ Curl_ssl->cleanup(); init_ssl = FALSE; } } static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ const long sslver = data->set.ssl.primary.version; if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } switch(data->set.ssl.primary.version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: break; default: if((data->set.ssl.primary.version_max >> 16) < sslver) { failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION"); return FALSE; } } return TRUE; } static CURLcode ssl_connect_init_proxy(struct connectdata *conn, int sockindex) { DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); if(ssl_connection_complete == conn->ssl[sockindex].state && !conn->proxy_ssl[sockindex].use) { struct ssl_backend_data *pbdata; if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY)) return CURLE_NOT_BUILT_IN; /* The pointers to the ssl backend data, which is opaque here, are swapped rather than move the contents. */ pbdata = conn->proxy_ssl[sockindex].backend; conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data); conn->ssl[sockindex].backend = pbdata; } return CURLE_OK; } CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; if(conn->bits.proxy_ssl_connected[sockindex]) { result = ssl_connect_init_proxy(conn, sockindex); if(result) return result; } if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; /* mark this is being ssl-enabled from here on. */ conn->ssl[sockindex].use = TRUE; conn->ssl[sockindex].state = ssl_connection_negotiating; result = Curl_ssl->connect_blocking(conn, sockindex); if(!result) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ return result; } CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; if(conn->bits.proxy_ssl_connected[sockindex]) { result = ssl_connect_init_proxy(conn, sockindex); if(result) return result; } if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; /* mark this is being ssl requested from here on. */ conn->ssl[sockindex].use = TRUE; result = Curl_ssl->connect_nonblocking(conn, sockindex, done); if(!result && *done) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ return result; } /* * Lock shared SSL session data */ void Curl_ssl_sessionid_lock(struct connectdata *conn) { if(SSLSESSION_SHARED(conn->data)) Curl_share_lock(conn->data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); } /* * Unlock shared SSL session data */ void Curl_ssl_sessionid_unlock(struct connectdata *conn) { if(SSLSESSION_SHARED(conn->data)) Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); } /* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, size_t *idsize, /* set 0 if unknown */ int sockindex) { struct curl_ssl_session *check; struct Curl_easy *data = conn->data; size_t i; long *general_age; bool no_match = TRUE; const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? &conn->proxy_ssl_config : &conn->ssl_config; const char * const name = isProxy ? conn->http_proxy.host.name : conn->host.name; int port = isProxy ? (int)conn->port : conn->remote_port; *ssl_sessionid = NULL; DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); if(!SSL_SET_OPTION(primary.sessionid)) /* session ID re-use is disabled */ return TRUE; /* Lock if shared */ if(SSLSESSION_SHARED(data)) general_age = &data->share->sessionage; else general_age = &data->state.sessionage; for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { check = &data->state.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; if(strcasecompare(name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || (conn->bits.conn_to_host && check->conn_to_host && strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || (conn->bits.conn_to_port && check->conn_to_port != -1 && conn->conn_to_port == check->conn_to_port)) && (port == check->remote_port) && strcasecompare(conn->handler->scheme, check->scheme) && Curl_ssl_config_matches(ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ *ssl_sessionid = check->sessionid; if(idsize) *idsize = check->idsize; no_match = FALSE; break; } } return no_match; } /* * Kill a single session ID entry in the cache. */ void Curl_ssl_kill_session(struct curl_ssl_session *session) { if(session->sessionid) { /* defensive check */ /* free the ID the SSL-layer specific way */ Curl_ssl->session_free(session->sessionid); session->sessionid = NULL; session->age = 0; /* fresh */ Curl_free_primary_ssl_config(&session->ssl_config); Curl_safefree(session->name); Curl_safefree(session->conn_to_host); } } /* * Delete the given session ID from the cache. */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { size_t i; struct Curl_easy *data = conn->data; for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { Curl_ssl_kill_session(check); break; } } } /* * Store session id in the session cache. The ID passed on to this function * must already have been extracted and allocated the proper way for the SSL * layer. Curl_XXXX_session_free() will be called to free/kill the session ID * later on. */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize, int sockindex) { size_t i; struct Curl_easy *data = conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age = data->state.session[0].age; /* zero if unused */ char *clone_host; char *clone_conn_to_host; int conn_to_port; long *general_age; const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? &conn->proxy_ssl_config : &conn->ssl_config; DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ if(conn->bits.conn_to_host) { clone_conn_to_host = strdup(conn->conn_to_host.name); if(!clone_conn_to_host) { free(clone_host); return CURLE_OUT_OF_MEMORY; /* bail out */ } } else clone_conn_to_host = NULL; if(conn->bits.conn_to_port) conn_to_port = conn->conn_to_port; else conn_to_port = -1; /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { general_age = &data->share->sessionage; } else { general_age = &data->state.sessionage; } /* find an empty slot for us, or find the oldest */ for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } if(i == data->set.general_ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ /* free it if there's one already present */ free(store->name); free(store->conn_to_host); store->name = clone_host; /* clone host name */ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ /* port number */ store->remote_port = isProxy ? (int)conn->port : conn->remote_port; store->scheme = conn->handler->scheme; if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } void Curl_ssl_close_all(struct Curl_easy *data) { /* kill the session ID cache if not shared */ if(data->state.session && !SSLSESSION_SHARED(data)) { size_t i; for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) /* the single-killer function handles empty table slots */ Curl_ssl_kill_session(&data->state.session[i]); /* free the cache data */ Curl_safefree(data->state.session); } Curl_ssl->close_all(data); } #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ defined(USE_SECTRANSP) || defined(USE_NSS) || \ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL) int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; if(connssl->connecting_state == ssl_connect_2_writing) { /* write mode */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_WRITESOCK(0); } if(connssl->connecting_state == ssl_connect_2_reading) { /* read mode */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_READSOCK(0); } return GETSOCK_BLANK; } #else int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks) { (void)conn; (void)socks; return GETSOCK_BLANK; } /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */ #endif void Curl_ssl_close(struct connectdata *conn, int sockindex) { DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); Curl_ssl->close_one(conn, sockindex); } CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) { if(Curl_ssl->shut_down(conn, sockindex)) return CURLE_SSL_SHUTDOWN_FAILED; conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ conn->ssl[sockindex].state = ssl_connection_none; conn->recv[sockindex] = Curl_recv_plain; conn->send[sockindex] = Curl_send_plain; return CURLE_OK; } /* Selects an SSL crypto engine */ CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) { return Curl_ssl->set_engine(data, engine); } /* Selects the default SSL crypto engine */ CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) { return Curl_ssl->set_engine_default(data); } /* Return list of OpenSSL crypto engine names. */ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) { return Curl_ssl->engines_list(data); } /* * This sets up a session ID cache to the specified size. Make sure this code * is agnostic to what underlying SSL technology we use. */ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) { struct curl_ssl_session *session; if(data->state.session) /* this is just a precaution to prevent multiple inits */ return CURLE_OK; session = calloc(amount, sizeof(struct curl_ssl_session)); if(!session) return CURLE_OUT_OF_MEMORY; /* store the info in the SSL section */ data->set.general_ssl.max_ssl_sessions = amount; data->state.session = session; data->state.sessionage = 1; /* this is brand new */ return CURLE_OK; } static size_t Curl_multissl_version(char *buffer, size_t size); size_t Curl_ssl_version(char *buffer, size_t size) { #ifdef CURL_WITH_MULTI_SSL return Curl_multissl_version(buffer, size); #else return Curl_ssl->version(buffer, size); #endif } /* * This function tries to determine connection status. * * Return codes: * 1 means the connection is still in place * 0 means the connection has been closed * -1 means the connection status is unknown */ int Curl_ssl_check_cxn(struct connectdata *conn) { return Curl_ssl->check_cxn(conn); } bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex) { return Curl_ssl->data_pending(conn, connindex); } void Curl_ssl_free_certinfo(struct Curl_easy *data) { struct curl_certinfo *ci = &data->info.certs; if(ci->num_of_certs) { /* free all individual lists used */ int i; for(i = 0; inum_of_certs; i++) { curl_slist_free_all(ci->certinfo[i]); ci->certinfo[i] = NULL; } free(ci->certinfo); /* free the actual array too */ ci->certinfo = NULL; ci->num_of_certs = 0; } } CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) { struct curl_certinfo *ci = &data->info.certs; struct curl_slist **table; /* Free any previous certificate information structures */ Curl_ssl_free_certinfo(data); /* Allocate the required certificate information structures */ table = calloc((size_t) num, sizeof(struct curl_slist *)); if(!table) return CURLE_OUT_OF_MEMORY; ci->num_of_certs = num; ci->certinfo = table; return CURLE_OK; } /* * 'value' is NOT a zero terminated string */ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, const char *label, const char *value, size_t valuelen) { struct curl_certinfo *ci = &data->info.certs; char *output; struct curl_slist *nl; CURLcode result = CURLE_OK; size_t labellen = strlen(label); size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ output = malloc(outlen); if(!output) return CURLE_OUT_OF_MEMORY; /* sprintf the label and colon */ msnprintf(output, outlen, "%s:", label); /* memcpy the value (it might not be zero terminated) */ memcpy(&output[labellen + 1], value, valuelen); /* zero terminate the output */ output[labellen + 1 + valuelen] = 0; nl = Curl_slist_append_nodup(ci->certinfo[certnum], output); if(!nl) { free(output); curl_slist_free_all(ci->certinfo[certnum]); result = CURLE_OUT_OF_MEMORY; } ci->certinfo[certnum] = nl; return result; } /* * This is a convenience function for push_certinfo_len that takes a zero * terminated value. */ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, const char *label, const char *value) { size_t valuelen = strlen(value); return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { return Curl_ssl->random(data, entropy, length); } /* * Public key pem to der conversion */ static CURLcode pubkey_pem_to_der(const char *pem, unsigned char **der, size_t *der_len) { char *stripped_pem, *begin_pos, *end_pos; size_t pem_count, stripped_pem_count = 0, pem_len; CURLcode result; /* if no pem, exit. */ if(!pem) return CURLE_BAD_CONTENT_ENCODING; begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); if(!begin_pos) return CURLE_BAD_CONTENT_ENCODING; pem_count = begin_pos - pem; /* Invalid if not at beginning AND not directly following \n */ if(0 != pem_count && '\n' != pem[pem_count - 1]) return CURLE_BAD_CONTENT_ENCODING; /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ pem_count += 26; /* Invalid if not directly following \n */ end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); if(!end_pos) return CURLE_BAD_CONTENT_ENCODING; pem_len = end_pos - pem; stripped_pem = malloc(pem_len - pem_count + 1); if(!stripped_pem) return CURLE_OUT_OF_MEMORY; /* * Here we loop through the pem array one character at a time between the * correct indices, and place each character that is not '\n' or '\r' * into the stripped_pem array, which should represent the raw base64 string */ while(pem_count < pem_len) { if('\n' != pem[pem_count] && '\r' != pem[pem_count]) stripped_pem[stripped_pem_count++] = pem[pem_count]; ++pem_count; } /* Place the null terminator in the correct place */ stripped_pem[stripped_pem_count] = '\0'; result = Curl_base64_decode(stripped_pem, der, der_len); Curl_safefree(stripped_pem); return result; } /* * Generic pinned public key check. */ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen) { FILE *fp; unsigned char *buf = NULL, *pem_ptr = NULL; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!pubkey || !pubkeylen) return result; /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { CURLcode encode; size_t encodedlen, pinkeylen; char *encoded, *pinkeycopy, *begin_pos, *end_pos; unsigned char *sha256sumdigest; if(!Curl_ssl->sha256sum) { /* without sha256 support, this cannot match */ return result; } /* compute sha256sum of public key */ sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH); if(!sha256sumdigest) return CURLE_OUT_OF_MEMORY; encode = Curl_ssl->sha256sum(pubkey, pubkeylen, sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); if(encode != CURLE_OK) return encode; encode = Curl_base64_encode(data, (char *)sha256sumdigest, CURL_SHA256_DIGEST_LENGTH, &encoded, &encodedlen); Curl_safefree(sha256sumdigest); if(encode) return encode; infof(data, "\t public key hash: sha256//%s\n", encoded); /* it starts with sha256//, copy so we can modify it */ pinkeylen = strlen(pinnedpubkey) + 1; pinkeycopy = malloc(pinkeylen); if(!pinkeycopy) { Curl_safefree(encoded); return CURLE_OUT_OF_MEMORY; } memcpy(pinkeycopy, pinnedpubkey, pinkeylen); /* point begin_pos to the copy, and start extracting keys */ begin_pos = pinkeycopy; do { end_pos = strstr(begin_pos, ";sha256//"); /* * if there is an end_pos, null terminate, * otherwise it'll go to the end of the original string */ if(end_pos) end_pos[0] = '\0'; /* compare base64 sha256 digests, 8 is the length of "sha256//" */ if(encodedlen == strlen(begin_pos + 8) && !memcmp(encoded, begin_pos + 8, encodedlen)) { result = CURLE_OK; break; } /* * change back the null-terminator we changed earlier, * and look for next begin */ if(end_pos) { end_pos[0] = ';'; begin_pos = strstr(end_pos, "sha256//"); } } while(end_pos && begin_pos); Curl_safefree(encoded); Curl_safefree(pinkeycopy); return result; } fp = fopen(pinnedpubkey, "rb"); if(!fp) return result; do { long filesize; size_t size, pem_len; CURLcode pem_read; /* Determine the file's size */ if(fseek(fp, 0, SEEK_END)) break; filesize = ftell(fp); if(fseek(fp, 0, SEEK_SET)) break; if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) break; /* * if the size of our certificate is bigger than the file * size then it can't match */ size = curlx_sotouz((curl_off_t) filesize); if(pubkeylen > size) break; /* * Allocate buffer for the pinned key * With 1 additional byte for null terminator in case of PEM key */ buf = malloc(size + 1); if(!buf) break; /* Returns number of elements read, which should be 1 */ if((int) fread(buf, size, 1, fp) != 1) break; /* If the sizes are the same, it can't be base64 encoded, must be der */ if(pubkeylen == size) { if(!memcmp(pubkey, buf, pubkeylen)) result = CURLE_OK; break; } /* * Otherwise we will assume it's PEM and try to decode it * after placing null terminator */ buf[size] = '\0'; pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); /* if it wasn't read successfully, exit */ if(pem_read) break; /* * if the size of our certificate doesn't match the size of * the decoded file, they can't be the same, otherwise compare */ if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) result = CURLE_OK; } while(0); Curl_safefree(buf); Curl_safefree(pem_ptr); fclose(fp); return result; } #ifndef CURL_DISABLE_CRYPTO_AUTH CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len) { return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len); } #endif /* * Check whether the SSL backend supports the status_request extension. */ bool Curl_ssl_cert_status_request(void) { return Curl_ssl->cert_status_request(); } /* * Check whether the SSL backend supports false start. */ bool Curl_ssl_false_start(void) { return Curl_ssl->false_start(); } /* * Check whether the SSL backend supports setting TLS 1.3 cipher suites */ bool Curl_ssl_tls13_ciphersuites(void) { return Curl_ssl->supports & SSLSUPP_TLS13_CIPHERSUITES; } /* * Default implementations for unsupported functions. */ int Curl_none_init(void) { return 1; } void Curl_none_cleanup(void) { } int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM, int sockindex UNUSED_PARAM) { (void)conn; (void)sockindex; return 0; } int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM) { (void)conn; return -1; } CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM, unsigned char *entropy UNUSED_PARAM, size_t length UNUSED_PARAM) { (void)data; (void)entropy; (void)length; return CURLE_NOT_BUILT_IN; } void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM) { (void)data; } void Curl_none_session_free(void *ptr UNUSED_PARAM) { (void)ptr; } bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM, int connindex UNUSED_PARAM) { (void)conn; (void)connindex; return 0; } bool Curl_none_cert_status_request(void) { return FALSE; } CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM, const char *engine UNUSED_PARAM) { (void)data; (void)engine; return CURLE_NOT_BUILT_IN; } CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM) { (void)data; return CURLE_NOT_BUILT_IN; } struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM) { (void)data; return (struct curl_slist *)NULL; } bool Curl_none_false_start(void) { return FALSE; } #ifndef CURL_DISABLE_CRYPTO_AUTH CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen, unsigned char *md5sum, size_t md5len UNUSED_PARAM) { MD5_context *MD5pw; (void)md5len; MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); if(!MD5pw) return CURLE_OUT_OF_MEMORY; Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen)); Curl_MD5_final(MD5pw, md5sum); return CURLE_OK; } #else CURLcode Curl_none_md5sum(unsigned char *input UNUSED_PARAM, size_t inputlen UNUSED_PARAM, unsigned char *md5sum UNUSED_PARAM, size_t md5len UNUSED_PARAM) { (void)input; (void)inputlen; (void)md5sum; (void)md5len; return CURLE_NOT_BUILT_IN; } #endif static int Curl_multissl_init(void) { if(multissl_init(NULL)) return 1; return Curl_ssl->init(); } static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex) { if(multissl_init(NULL)) return CURLE_FAILED_INIT; return Curl_ssl->connect_blocking(conn, sockindex); } static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { if(multissl_init(NULL)) return CURLE_FAILED_INIT; return Curl_ssl->connect_nonblocking(conn, sockindex, done); } static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl, CURLINFO info) { if(multissl_init(NULL)) return NULL; return Curl_ssl->get_internals(connssl, info); } static void Curl_multissl_close(struct connectdata *conn, int sockindex) { if(multissl_init(NULL)) return; Curl_ssl->close_one(conn, sockindex); } static const struct Curl_ssl Curl_ssl_multi = { { CURLSSLBACKEND_NONE, "multi" }, /* info */ 0, /* supports nothing */ (size_t)-1, /* something insanely large to be on the safe side */ Curl_multissl_init, /* init */ Curl_none_cleanup, /* cleanup */ Curl_multissl_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_none_shutdown, /* shutdown */ Curl_none_data_pending, /* data_pending */ Curl_none_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_multissl_connect, /* connect */ Curl_multissl_connect_nonblocking, /* connect_nonblocking */ Curl_multissl_get_internals, /* get_internals */ Curl_multissl_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_none_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_none_md5sum, /* md5sum */ NULL /* sha256sum */ }; const struct Curl_ssl *Curl_ssl = #if defined(CURL_WITH_MULTI_SSL) &Curl_ssl_multi; #elif defined(USE_WOLFSSL) &Curl_ssl_wolfssl; #elif defined(USE_SECTRANSP) &Curl_ssl_sectransp; #elif defined(USE_GNUTLS) &Curl_ssl_gnutls; #elif defined(USE_GSKIT) &Curl_ssl_gskit; #elif defined(USE_MBEDTLS) &Curl_ssl_mbedtls; #elif defined(USE_NSS) &Curl_ssl_nss; #elif defined(USE_OPENSSL) &Curl_ssl_openssl; #elif defined(USE_SCHANNEL) &Curl_ssl_schannel; #elif defined(USE_MESALINK) &Curl_ssl_mesalink; #elif defined(USE_BEARSSL) &Curl_ssl_bearssl; #else #error "Missing struct Curl_ssl for selected SSL backend" #endif static const struct Curl_ssl *available_backends[] = { #if defined(USE_WOLFSSL) &Curl_ssl_wolfssl, #endif #if defined(USE_SECTRANSP) &Curl_ssl_sectransp, #endif #if defined(USE_GNUTLS) &Curl_ssl_gnutls, #endif #if defined(USE_GSKIT) &Curl_ssl_gskit, #endif #if defined(USE_MBEDTLS) &Curl_ssl_mbedtls, #endif #if defined(USE_NSS) &Curl_ssl_nss, #endif #if defined(USE_OPENSSL) &Curl_ssl_openssl, #endif #if defined(USE_SCHANNEL) &Curl_ssl_schannel, #endif #if defined(USE_MESALINK) &Curl_ssl_mesalink, #endif #if defined(USE_BEARSSL) &Curl_ssl_bearssl, #endif NULL }; static size_t Curl_multissl_version(char *buffer, size_t size) { static const struct Curl_ssl *selected; static char backends[200]; static size_t backends_len; const struct Curl_ssl *current; current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; if(current != selected) { char *p = backends; char *end = backends + sizeof(backends); int i; selected = current; backends[0] = '\0'; for(i = 0; available_backends[i]; ++i) { char vb[200]; bool paren = (selected != available_backends[i]); if(available_backends[i]->version(vb, sizeof(vb))) { p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), (paren ? "(" : ""), vb, (paren ? ")" : "")); } } backends_len = p - backends; } if(!size) return 0; if(size <= backends_len) { strncpy(buffer, backends, size - 1); buffer[size - 1] = '\0'; return size - 1; } strcpy(buffer, backends); return backends_len; } static int multissl_init(const struct Curl_ssl *backend) { const char *env; char *env_tmp; if(Curl_ssl != &Curl_ssl_multi) return 1; if(backend) { Curl_ssl = backend; return 0; } if(!available_backends[0]) return 1; env = env_tmp = curl_getenv("CURL_SSL_BACKEND"); #ifdef CURL_DEFAULT_SSL_BACKEND if(!env) env = CURL_DEFAULT_SSL_BACKEND; #endif if(env) { int i; for(i = 0; available_backends[i]; i++) { if(strcasecompare(env, available_backends[i]->info.name)) { Curl_ssl = available_backends[i]; curl_free(env_tmp); return 0; } } } /* Fall back to first available backend */ Curl_ssl = available_backends[0]; curl_free(env_tmp); return 0; } CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail) { int i; if(avail) *avail = (const curl_ssl_backend **)&available_backends; if(Curl_ssl != &Curl_ssl_multi) return id == Curl_ssl->info.id || (name && strcasecompare(name, Curl_ssl->info.name)) ? CURLSSLSET_OK : #if defined(CURL_WITH_MULTI_SSL) CURLSSLSET_TOO_LATE; #else CURLSSLSET_UNKNOWN_BACKEND; #endif for(i = 0; available_backends[i]; i++) { if(available_backends[i]->info.id == id || (name && strcasecompare(available_backends[i]->info.name, name))) { multissl_init(available_backends[i]); return CURLSSLSET_OK; } } return CURLSSLSET_UNKNOWN_BACKEND; } #else /* USE_SSL */ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail) { (void)id; (void)name; (void)avail; return CURLSSLSET_NO_BACKENDS; } #endif /* !USE_SSL */ davix-0.8.0/deps/curl/lib/vtls/mbedtls.h0000644000000000000000000000242214121063461016567 0ustar rootroot#ifndef HEADER_CURL_MBEDTLS_H #define HEADER_CURL_MBEDTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_MBEDTLS extern const struct Curl_ssl Curl_ssl_mbedtls; #endif /* USE_MBEDTLS */ #endif /* HEADER_CURL_MBEDTLS_H */ davix-0.8.0/deps/curl/lib/vtls/nss.c0000644000000000000000000022064614121063461015745 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all NSS-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. */ #include "curl_setup.h" #ifdef USE_NSS #include "urldata.h" #include "sendf.h" #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "connect.h" #include "strcase.h" #include "select.h" #include "vtls.h" #include "llist.h" #include "multiif.h" #include "curl_printf.h" #include "nssg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for SECKEY_DestroyPublicKey() */ #include /* for PR_ImportTCPSocket */ #define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH) #if NSSVERNUM >= 0x030f00 /* 3.15.0 */ #include #endif #include "strcase.h" #include "warnless.h" #include "x509asn1.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" #define SSL_DIR "/etc/pki/nssdb" /* enough to fit the string "PEM Token #[0|1]" */ #define SLOTSIZE 13 struct ssl_backend_data { PRFileDesc *handle; char *client_nickname; struct Curl_easy *data; struct curl_llist obj_list; PK11GenericObject *obj_clicert; }; #define BACKEND connssl->backend static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; static PRLock *nss_findslot_lock = NULL; static PRLock *nss_trustload_lock = NULL; static struct curl_llist nss_crl_list; static NSSInitContext *nss_context = NULL; static volatile int initialized = 0; /* type used to wrap pointers as list nodes */ struct ptr_list_wrap { void *ptr; struct curl_llist_element node; }; typedef struct { const char *name; int num; } cipher_s; #define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \ CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \ ptr->type = (_type); \ ptr->pValue = (_val); \ ptr->ulValueLen = (_len); \ } while(0) #define CERT_NewTempCertificate __CERT_NewTempCertificate #define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0]) static const cipher_s cipherlist[] = { /* SSL2 cipher suites */ {"rc4", SSL_EN_RC4_128_WITH_MD5}, {"rc4-md5", SSL_EN_RC4_128_WITH_MD5}, {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5}, {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5}, {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5}, {"des", SSL_EN_DES_64_CBC_WITH_MD5}, {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5}, /* SSL3/TLS cipher suites */ {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5}, {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA}, {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA}, {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA}, {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5}, {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5}, {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5}, {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA}, {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA}, {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA}, {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA}, {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA}, {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA}, /* TLS 1.0: Exportable 56-bit Cipher Suites. */ {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA}, {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA}, /* AES ciphers. */ {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA}, {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA}, {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA}, {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA}, {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA}, /* ECC ciphers. */ {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA}, {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA}, {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA}, {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA}, {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA}, {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA}, {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA}, {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA}, {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA}, {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA}, {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA}, {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA}, {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA}, {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA}, #ifdef TLS_RSA_WITH_NULL_SHA256 /* new HMAC-SHA256 cipher suites specified in RFC */ {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256}, {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256}, {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256}, {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256}, {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256}, {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, #endif #ifdef TLS_RSA_WITH_AES_128_GCM_SHA256 /* AES GCM cipher suites in RFC 5288 and RFC 5289 */ {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256}, {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256}, {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256}, {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, #endif #ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 /* cipher suites using SHA384 */ {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384}, {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384}, {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, #endif #ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 /* chacha20-poly1305 cipher suites */ {"ecdhe_rsa_chacha20_poly1305_sha_256", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, {"ecdhe_ecdsa_chacha20_poly1305_sha_256", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, {"dhe_rsa_chacha20_poly1305_sha_256", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, #endif #ifdef TLS_AES_256_GCM_SHA384 {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256}, {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384}, {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256}, #endif }; #if defined(WIN32) static const char *pem_library = "nsspem.dll"; static const char *trust_library = "nssckbi.dll"; #elif defined(__APPLE__) static const char *pem_library = "libnsspem.dylib"; static const char *trust_library = "libnssckbi.dylib"; #else static const char *pem_library = "libnsspem.so"; static const char *trust_library = "libnssckbi.so"; #endif static SECMODModule *pem_module = NULL; static SECMODModule *trust_module = NULL; /* NSPR I/O layer we use to detect blocking direction during SSL handshake */ static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; static PRIOMethods nspr_io_methods; static const char *nss_error_to_name(PRErrorCode code) { const char *name = PR_ErrorToName(code); if(name) return name; return "unknown error"; } static void nss_print_error_message(struct Curl_easy *data, PRUint32 err) { failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); } static char *nss_sslver_to_name(PRUint16 nssver) { switch(nssver) { case SSL_LIBRARY_VERSION_2: return strdup("SSLv2"); case SSL_LIBRARY_VERSION_3_0: return strdup("SSLv3"); case SSL_LIBRARY_VERSION_TLS_1_0: return strdup("TLSv1.0"); #ifdef SSL_LIBRARY_VERSION_TLS_1_1 case SSL_LIBRARY_VERSION_TLS_1_1: return strdup("TLSv1.1"); #endif #ifdef SSL_LIBRARY_VERSION_TLS_1_2 case SSL_LIBRARY_VERSION_TLS_1_2: return strdup("TLSv1.2"); #endif #ifdef SSL_LIBRARY_VERSION_TLS_1_3 case SSL_LIBRARY_VERSION_TLS_1_3: return strdup("TLSv1.3"); #endif default: return curl_maprintf("0x%04x", nssver); } } static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, char *cipher_list) { unsigned int i; PRBool cipher_state[NUM_OF_CIPHERS]; PRBool found; char *cipher; /* use accessors to avoid dynamic linking issues after an update of NSS */ const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers(); const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers(); if(!implemented_ciphers) return SECFailure; /* First disable all ciphers. This uses a different max value in case * NSS adds more ciphers later we don't want them available by * accident */ for(i = 0; i < num_implemented_ciphers; i++) { SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE); } /* Set every entry in our list to false */ for(i = 0; i < NUM_OF_CIPHERS; i++) { cipher_state[i] = PR_FALSE; } cipher = cipher_list; while(cipher_list && (cipher_list[0])) { while((*cipher) && (ISSPACE(*cipher))) ++cipher; cipher_list = strchr(cipher, ','); if(cipher_list) { *cipher_list++ = '\0'; } found = PR_FALSE; for(i = 0; i. */ static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) { PK11SlotInfo *slot; PR_Lock(nss_findslot_lock); slot = PK11_FindSlotByName(slot_name); PR_Unlock(nss_findslot_lock); return slot; } /* wrap 'ptr' as list node and tail-insert into 'list' */ static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr) { struct ptr_list_wrap *wrap = malloc(sizeof(*wrap)); if(!wrap) return CURLE_OUT_OF_MEMORY; wrap->ptr = ptr; Curl_llist_insert_next(list, list->tail, wrap, &wrap->node); return CURLE_OK; } /* Call PK11_CreateGenericObject() with the given obj_class and filename. If * the call succeeds, append the object handle to the list of objects so that * the object can be destroyed in Curl_nss_close(). */ static CURLcode nss_create_object(struct ssl_connect_data *connssl, CK_OBJECT_CLASS obj_class, const char *filename, bool cacert) { PK11SlotInfo *slot; PK11GenericObject *obj; CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; int attr_cnt = 0; CURLcode result = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); if(!slot_name) return CURLE_OUT_OF_MEMORY; slot = nss_find_slot_by_name(slot_name); free(slot_name); if(!slot) return result; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename, (CK_ULONG)strlen(filename) + 1); if(CKO_CERTIFICATE == obj_class) { CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse); PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); } /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because * PK11_DestroyGenericObject() does not release resources allocated by * PK11_CreateGenericObject() early enough. */ obj = #ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT PK11_CreateManagedGenericObject #else PK11_CreateGenericObject #endif (slot, attrs, attr_cnt, PR_FALSE); PK11_FreeSlot(slot); if(!obj) return result; if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } if(!cacert && CKO_CERTIFICATE == obj_class) /* store reference to a client certificate */ BACKEND->obj_clicert = obj; return CURLE_OK; } /* Destroy the NSS object whose handle is given by ptr. This function is * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy * NSS objects in Curl_nss_close() */ static void nss_destroy_object(void *user, void *ptr) { struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr; PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr; (void) user; PK11_DestroyGenericObject(obj); free(wrap); } /* same as nss_destroy_object() but for CRL items */ static void nss_destroy_crl_item(void *user, void *ptr) { struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr; SECItem *crl_der = (SECItem *) wrap->ptr; (void) user; SECITEM_FreeItem(crl_der, PR_TRUE); free(wrap); } static CURLcode nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { CURLcode result = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; /* libnsspem.so leaks memory if the requested file does not exist. For more * details, go to . */ if(is_file(filename)) result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); if(!result && !cacert) { /* we have successfully loaded a client certificate */ CERTCertificate *cert; char *nickname = NULL; char *n = strrchr(filename, '/'); if(n) n++; /* The following undocumented magic helps to avoid a SIGSEGV on call * of PK11_ReadRawAttribute() from SelectClientCert() when using an * immature version of libnsspem.so. For more details, go to * . */ nickname = aprintf("PEM Token #1:%s", n); if(nickname) { cert = PK11_FindCertFromNickname(nickname, NULL); if(cert) CERT_DestroyCertificate(cert); free(nickname); } } return result; } /* add given CRL to cache if it is not already there */ static CURLcode nss_cache_crl(SECItem *crl_der) { CERTCertDBHandle *db = CERT_GetDefaultCertDB(); CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0); if(crl) { /* CRL already cached */ SEC_DestroyCrl(crl); SECITEM_FreeItem(crl_der, PR_TRUE); return CURLE_OK; } /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */ PR_Lock(nss_crllock); if(SECSuccess != CERT_CacheCRL(db, crl_der)) { /* unable to cache CRL */ SECITEM_FreeItem(crl_der, PR_TRUE); PR_Unlock(nss_crllock); return CURLE_SSL_CRL_BADFILE; } /* store the CRL item so that we can free it in Curl_nss_cleanup() */ if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) { if(SECSuccess == CERT_UncacheCRL(db, crl_der)) SECITEM_FreeItem(crl_der, PR_TRUE); PR_Unlock(nss_crllock); return CURLE_OUT_OF_MEMORY; } /* we need to clear session cache, so that the CRL could take effect */ SSL_ClearSessionCache(); PR_Unlock(nss_crllock); return CURLE_OK; } static CURLcode nss_load_crl(const char *crlfilename) { PRFileDesc *infile; PRFileInfo info; SECItem filedata = { 0, NULL, 0 }; SECItem *crl_der = NULL; char *body; infile = PR_Open(crlfilename, PR_RDONLY, 0); if(!infile) return CURLE_SSL_CRL_BADFILE; if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info)) goto fail; if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1)) goto fail; if(info.size != PR_Read(infile, filedata.data, info.size)) goto fail; crl_der = SECITEM_AllocItem(NULL, NULL, 0U); if(!crl_der) goto fail; /* place a trailing zero right after the visible data */ body = (char *)filedata.data; body[--filedata.len] = '\0'; body = strstr(body, "-----BEGIN"); if(body) { /* assume ASCII */ char *trailer; char *begin = PORT_Strchr(body, '\n'); if(!begin) begin = PORT_Strchr(body, '\r'); if(!begin) goto fail; trailer = strstr(++begin, "-----END"); if(!trailer) goto fail; /* retrieve DER from ASCII */ *trailer = '\0'; if(ATOB_ConvertAsciiToItem(crl_der, begin)) goto fail; SECITEM_FreeItem(&filedata, PR_FALSE); } else /* assume DER */ *crl_der = filedata; PR_Close(infile); return nss_cache_crl(crl_der); fail: PR_Close(infile); SECITEM_FreeItem(crl_der, PR_TRUE); SECITEM_FreeItem(&filedata, PR_FALSE); return CURLE_SSL_CRL_BADFILE; } static CURLcode nss_load_key(struct connectdata *conn, int sockindex, char *key_file) { PK11SlotInfo *slot, *tmp; SECStatus status; CURLcode result; struct ssl_connect_data *ssl = conn->ssl; struct Curl_easy *data = conn->data; (void)sockindex; /* unused */ result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); if(result) { PR_SetError(SEC_ERROR_BAD_KEY, 0); return result; } slot = nss_find_slot_by_name("PEM Token #1"); if(!slot) return CURLE_SSL_CERTPROBLEM; /* This will force the token to be seen as re-inserted */ tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0); if(tmp) PK11_FreeSlot(tmp); if(!PK11_IsPresent(slot)) { PK11_FreeSlot(slot); return CURLE_SSL_CERTPROBLEM; } status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd)); PK11_FreeSlot(slot); return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; } static int display_error(struct connectdata *conn, PRInt32 err, const char *filename) { switch(err) { case SEC_ERROR_BAD_PASSWORD: failf(conn->data, "Unable to load client key: Incorrect password"); return 1; case SEC_ERROR_UNKNOWN_CERT: failf(conn->data, "Unable to load certificate %s", filename); return 1; default: break; } return 0; /* The caller will print a generic error */ } static CURLcode cert_stuff(struct connectdata *conn, int sockindex, char *cert_file, char *key_file) { struct Curl_easy *data = conn->data; CURLcode result; if(cert_file) { result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); if(result) { const PRErrorCode err = PR_GetError(); if(!display_error(conn, err, cert_file)) { const char *err_name = nss_error_to_name(err); failf(data, "unable to load client cert: %d (%s)", err, err_name); } return result; } } if(key_file || (is_file(cert_file))) { if(key_file) result = nss_load_key(conn, sockindex, key_file); else /* In case the cert file also has the key */ result = nss_load_key(conn, sockindex, cert_file); if(result) { const PRErrorCode err = PR_GetError(); if(!display_error(conn, err, key_file)) { const char *err_name = nss_error_to_name(err); failf(data, "unable to load client key: %d (%s)", err, err_name); } return result; } } return CURLE_OK; } static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg) { (void)slot; /* unused */ if(retry || NULL == arg) return NULL; else return (char *)PORT_Strdup((char *)arg); } /* bypass the default SSL_AuthCertificate() hook in case we do not want to * verify peer */ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { struct connectdata *conn = (struct connectdata *)arg; #ifdef SSL_ENABLE_OCSP_STAPLING if(SSL_CONN_CONFIG(verifystatus)) { SECStatus cacheResult; const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); if(!csa) { failf(conn->data, "Invalid OCSP response"); return SECFailure; } if(csa->len == 0) { failf(conn->data, "No OCSP response received"); return SECFailure; } cacheResult = CERT_CacheOCSPResponseFromSideChannel( CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd), PR_Now(), &csa->items[0], arg ); if(cacheResult != SECSuccess) { failf(conn->data, "Invalid OCSP response"); return cacheResult; } } #endif if(!SSL_CONN_CONFIG(verifypeer)) { infof(conn->data, "skipping SSL peer certificate verification\n"); return SECSuccess; } return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); } /** * Inform the application that the handshake is complete. */ static void HandshakeCallback(PRFileDesc *sock, void *arg) { struct connectdata *conn = (struct connectdata*) arg; unsigned int buflenmax = 50; unsigned char buf[50]; unsigned int buflen; SSLNextProtoState state; if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) { return; } if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) { switch(state) { #if NSSVERNUM >= 0x031a00 /* 3.26.0 */ /* used by NSS internally to implement 0-RTT */ case SSL_NEXT_PROTO_EARLY_VALUE: /* fall through! */ #endif case SSL_NEXT_PROTO_NO_SUPPORT: case SSL_NEXT_PROTO_NO_OVERLAP: infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); return; #ifdef SSL_ENABLE_ALPN case SSL_NEXT_PROTO_SELECTED: infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf); break; #endif case SSL_NEXT_PROTO_NEGOTIATED: infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf); break; } #ifdef USE_NGHTTP2 if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(buflen == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } } #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, PRBool *canFalseStart) { struct connectdata *conn = client_data; struct Curl_easy *data = conn->data; SSLChannelInfo channelInfo; SSLCipherSuiteInfo cipherInfo; SECStatus rv; PRBool negotiatedExtension; *canFalseStart = PR_FALSE; if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess) return SECFailure; if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo, sizeof(cipherInfo)) != SECSuccess) return SECFailure; /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310 */ if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) goto end; /* Only allow ECDHE key exchange algorithm. * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */ if(cipherInfo.keaType != ssl_kea_ecdh) goto end; /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */ if(cipherInfo.symCipher != ssl_calg_aes_gcm) goto end; /* Enforce ALPN or NPN to do False Start, as an indicator of server * compatibility. */ rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn, &negotiatedExtension); if(rv != SECSuccess || !negotiatedExtension) { rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn, &negotiatedExtension); } if(rv != SECSuccess || !negotiatedExtension) goto end; *canFalseStart = PR_TRUE; infof(data, "Trying TLS False Start\n"); end: return SECSuccess; } #endif static void display_cert_info(struct Curl_easy *data, CERTCertificate *cert) { char *subject, *issuer, *common_name; PRExplodedTime printableTime; char timeString[256]; PRTime notBefore, notAfter; subject = CERT_NameToAscii(&cert->subject); issuer = CERT_NameToAscii(&cert->issuer); common_name = CERT_GetCommonName(&cert->subject); infof(data, "\tsubject: %s\n", subject); CERT_GetCertTimes(cert, ¬Before, ¬After); PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); infof(data, "\tstart date: %s\n", timeString); PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); infof(data, "\texpire date: %s\n", timeString); infof(data, "\tcommon name: %s\n", common_name); infof(data, "\tissuer: %s\n", issuer); PR_Free(subject); PR_Free(issuer); PR_Free(common_name); } static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) { CURLcode result = CURLE_OK; SSLChannelInfo channel; SSLCipherSuiteInfo suite; CERTCertificate *cert; CERTCertificate *cert2; CERTCertificate *cert3; PRTime now; int i; if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) == SECSuccess && channel.length == sizeof(channel) && channel.cipherSuite) { if(SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof(suite)) == SECSuccess) { infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName); } } cert = SSL_PeerCertificate(sock); if(cert) { infof(conn->data, "Server certificate:\n"); if(!conn->data->set.ssl.certinfo) { display_cert_info(conn->data, cert); CERT_DestroyCertificate(cert); } else { /* Count certificates in chain. */ now = PR_Now(); i = 1; if(!cert->isRoot) { cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); while(cert2) { i++; if(cert2->isRoot) { CERT_DestroyCertificate(cert2); break; } cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA); CERT_DestroyCertificate(cert2); cert2 = cert3; } } result = Curl_ssl_init_certinfo(conn->data, i); if(!result) { for(i = 0; cert; cert = cert2) { result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data, (char *)cert->derCert.data + cert->derCert.len); if(result) break; if(cert->isRoot) { CERT_DestroyCertificate(cert); break; } cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA); CERT_DestroyCertificate(cert); } } } } return result; } static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) { struct connectdata *conn = (struct connectdata *)arg; struct Curl_easy *data = conn->data; PRErrorCode err = PR_GetError(); CERTCertificate *cert; /* remember the cert verification result */ if(SSL_IS_PROXY()) data->set.proxy_ssl.certverifyresult = err; else data->set.ssl.certverifyresult = err; if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost)) /* we are asked not to verify the host name */ return SECSuccess; /* print only info about the cert, the error is printed off the callback */ cert = SSL_PeerCertificate(sock); if(cert) { infof(data, "Server certificate:\n"); display_cert_info(data, cert); CERT_DestroyCertificate(cert); } return SECFailure; } /** * * Check that the Peer certificate's issuer certificate matches the one found * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the * issuer check, so we provide comments that mimic the OpenSSL * X509_check_issued function (in x509v3/v3_purp.c) */ static SECStatus check_issuer_cert(PRFileDesc *sock, char *issuer_nickname) { CERTCertificate *cert, *cert_issuer, *issuer; SECStatus res = SECSuccess; void *proto_win = NULL; cert = SSL_PeerCertificate(sock); cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); if((!cert_issuer) || (!issuer)) res = SECFailure; else if(SECITEM_CompareItem(&cert_issuer->derCert, &issuer->derCert) != SECEqual) res = SECFailure; CERT_DestroyCertificate(cert); CERT_DestroyCertificate(issuer); CERT_DestroyCertificate(cert_issuer); return res; } static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; struct Curl_easy *data = BACKEND->data; CERTCertificate *cert; if(!pinnedpubkey) /* no pinned public key specified */ return CURLE_OK; /* get peer certificate */ cert = SSL_PeerCertificate(BACKEND->handle); if(cert) { /* extract public key from peer certificate */ SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert); if(pubkey) { /* encode the public key as DER */ SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); if(cert_der) { /* compare the public key with the pinned public key */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data, cert_der->len); SECITEM_FreeItem(cert_der, PR_TRUE); } SECKEY_DestroyPublicKey(pubkey); } CERT_DestroyCertificate(cert); } /* report the resulting status */ switch(result) { case CURLE_OK: infof(data, "pinned public key verified successfully!\n"); break; case CURLE_SSL_PINNEDPUBKEYNOTMATCH: failf(data, "failed to verify pinned public key"); break; default: /* OOM, etc. */ break; } return result; } /** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct Curl_easy *data = BACKEND->data; const char *nickname = BACKEND->client_nickname; static const char pem_slotname[] = "PEM Token #1"; if(BACKEND->obj_clicert) { /* use the cert/key provided by PEM reader */ SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); struct CERTCertificateStr *cert; struct SECKEYPrivateKeyStr *key; PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); if(NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE, &cert_der) != SECSuccess) { failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); PK11_FreeSlot(slot); return SECFailure; } cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); SECITEM_FreeItem(&cert_der, PR_FALSE); if(NULL == cert) { failf(data, "NSS: client certificate from file not found"); PK11_FreeSlot(slot); return SECFailure; } key = PK11_FindPrivateKeyFromCert(slot, cert, NULL); PK11_FreeSlot(slot); if(NULL == key) { failf(data, "NSS: private key from file not found"); CERT_DestroyCertificate(cert); return SECFailure; } infof(data, "NSS: client certificate from file\n"); display_cert_info(data, cert); *pRetCert = cert; *pRetKey = key; return SECSuccess; } /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, pRetCert, pRetKey) || NULL == *pRetCert) { if(NULL == nickname) failf(data, "NSS: client certificate not found (nickname not " "specified)"); else failf(data, "NSS: client certificate not found: %s", nickname); return SECFailure; } /* get certificate nickname if any */ nickname = (*pRetCert)->nickname; if(NULL == nickname) nickname = "[unknown]"; if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { failf(data, "NSS: refusing previously loaded certificate from file: %s", nickname); return SECFailure; } if(NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } infof(data, "NSS: using client certificate: %s\n", nickname); display_cert_info(data, *pRetCert); return SECSuccess; } /* update blocking direction in case of PR_WOULD_BLOCK_ERROR */ static void nss_update_connecting_state(ssl_connect_state state, void *secret) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret; if(PR_GetError() != PR_WOULD_BLOCK_ERROR) /* an unrelated error is passing by */ return; switch(connssl->connecting_state) { case ssl_connect_2: case ssl_connect_2_reading: case ssl_connect_2_writing: break; default: /* we are not called from an SSL handshake */ return; } /* update the state accordingly */ connssl->connecting_state = state; } /* recv() wrapper we use to detect blocking direction during SSL handshake */ static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { const PRRecvFN recv_fn = fd->lower->methods->recv; const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout); if(rv < 0) /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ nss_update_connecting_state(ssl_connect_2_reading, fd->secret); return rv; } /* send() wrapper we use to detect blocking direction during SSL handshake */ static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { const PRSendFN send_fn = fd->lower->methods->send; const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout); if(rv < 0) /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ nss_update_connecting_state(ssl_connect_2_writing, fd->secret); return rv; } /* close() wrapper to avoid assertion failure due to fd->secret != NULL */ static PRStatus nspr_io_close(PRFileDesc *fd) { const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close; fd->secret = NULL; return close_fn(fd); } /* load a PKCS #11 module */ static CURLcode nss_load_module(SECMODModule **pmod, const char *library, const char *name) { char *config_string; SECMODModule *module = *pmod; if(module) /* already loaded */ return CURLE_OK; config_string = aprintf("library=%s name=%s", library, name); if(!config_string) return CURLE_OUT_OF_MEMORY; module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE); free(config_string); if(module && module->loaded) { /* loaded successfully */ *pmod = module; return CURLE_OK; } if(module) SECMOD_DestroyModule(module); return CURLE_FAILED_INIT; } /* unload a PKCS #11 module */ static void nss_unload_module(SECMODModule **pmod) { SECMODModule *module = *pmod; if(!module) /* not loaded */ return; if(SECMOD_UnloadUserModule(module) != SECSuccess) /* unload failed */ return; SECMOD_DestroyModule(module); *pmod = NULL; } /* data might be NULL */ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) { NSSInitParameters initparams; PRErrorCode err; const char *err_name; if(nss_context != NULL) return CURLE_OK; memset((void *) &initparams, '\0', sizeof(initparams)); initparams.length = sizeof(initparams); if(cert_dir) { char *certpath = aprintf("sql:%s", cert_dir); if(!certpath) return CURLE_OUT_OF_MEMORY; infof(data, "Initializing NSS with certpath: %s\n", certpath); nss_context = NSS_InitContext(certpath, "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); free(certpath); if(nss_context != NULL) return CURLE_OK; err = PR_GetError(); err_name = nss_error_to_name(err); infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name); } infof(data, "Initializing NSS with certpath: none\n"); nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); if(nss_context != NULL) return CURLE_OK; err = PR_GetError(); err_name = nss_error_to_name(err); failf(data, "Unable to initialize NSS: %d (%s)", err, err_name); return CURLE_SSL_CACERT_BADFILE; } /* data might be NULL */ static CURLcode nss_init(struct Curl_easy *data) { char *cert_dir; struct_stat st; CURLcode result; if(initialized) return CURLE_OK; /* list of all CRL items we need to destroy in Curl_nss_cleanup() */ Curl_llist_init(&nss_crl_list, nss_destroy_crl_item); /* First we check if $SSL_DIR points to a valid dir */ cert_dir = getenv("SSL_DIR"); if(cert_dir) { if((stat(cert_dir, &st) != 0) || (!S_ISDIR(st.st_mode))) { cert_dir = NULL; } } /* Now we check if the default location is a valid dir */ if(!cert_dir) { if((stat(SSL_DIR, &st) == 0) && (S_ISDIR(st.st_mode))) { cert_dir = (char *)SSL_DIR; } } if(nspr_io_identity == PR_INVALID_IO_LAYER) { /* allocate an identity for our own NSPR I/O layer */ nspr_io_identity = PR_GetUniqueIdentity("libcurl"); if(nspr_io_identity == PR_INVALID_IO_LAYER) return CURLE_OUT_OF_MEMORY; /* the default methods just call down to the lower I/O layer */ memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof(nspr_io_methods)); /* override certain methods in the table by our wrappers */ nspr_io_methods.recv = nspr_io_recv; nspr_io_methods.send = nspr_io_send; nspr_io_methods.close = nspr_io_close; } result = nss_init_core(data, cert_dir); if(result) return result; if(!any_cipher_enabled()) NSS_SetDomesticPolicy(); initialized = 1; return CURLE_OK; } /** * Global SSL init * * @retval 0 error initializing SSL * @retval 1 SSL initialized successfully */ static int Curl_nss_init(void) { /* curl_global_init() is not thread-safe so this test is ok */ if(nss_initlock == NULL) { PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); nss_initlock = PR_NewLock(); nss_crllock = PR_NewLock(); nss_findslot_lock = PR_NewLock(); nss_trustload_lock = PR_NewLock(); } /* We will actually initialize NSS later */ return 1; } /* data might be NULL */ CURLcode Curl_nss_force_init(struct Curl_easy *data) { CURLcode result; if(!nss_initlock) { if(data) failf(data, "unable to initialize NSS, curl_global_init() should have " "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL"); return CURLE_FAILED_INIT; } PR_Lock(nss_initlock); result = nss_init(data); PR_Unlock(nss_initlock); return result; } /* Global cleanup */ static void Curl_nss_cleanup(void) { /* This function isn't required to be threadsafe and this is only done * as a safety feature. */ PR_Lock(nss_initlock); if(initialized) { /* Free references to client certificates held in the SSL session cache. * Omitting this hampers destruction of the security module owning * the certificates. */ SSL_ClearSessionCache(); nss_unload_module(&pem_module); nss_unload_module(&trust_module); NSS_ShutdownContext(nss_context); nss_context = NULL; } /* destroy all CRL items */ Curl_llist_destroy(&nss_crl_list, NULL); PR_Unlock(nss_initlock); PR_DestroyLock(nss_initlock); PR_DestroyLock(nss_crllock); PR_DestroyLock(nss_findslot_lock); PR_DestroyLock(nss_trustload_lock); nss_initlock = NULL; initialized = 0; } /* * This function uses SSL_peek to determine connection status. * * Return codes: * 1 means the connection is still in place * 0 means the connection has been closed * -1 means the connection status is unknown */ static int Curl_nss_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; int rc; char buf; rc = PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK, PR_SecondsToInterval(1)); if(rc > 0) return 1; /* connection still in place */ if(rc == 0) return 0; /* connection has been closed */ return -1; /* connection status unknown */ } static void nss_close(struct ssl_connect_data *connssl) { /* before the cleanup, check whether we are using a client certificate */ const bool client_cert = (BACKEND->client_nickname != NULL) || (BACKEND->obj_clicert != NULL); free(BACKEND->client_nickname); BACKEND->client_nickname = NULL; /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(&BACKEND->obj_list, NULL); BACKEND->obj_clicert = NULL; if(BACKEND->handle) { if(client_cert) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ SSL_InvalidateSession(BACKEND->handle); PR_Close(BACKEND->handle); BACKEND->handle = NULL; } } /* * This function is called when an SSL connection is closed. */ static void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; if(BACKEND->handle || connssl_proxy->backend->handle) { /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } if(BACKEND->handle) /* nss_close(connssl) will transitively close also connssl_proxy->backend->handle if both are used. Clear it to avoid a double close leading to crash. */ connssl_proxy->backend->handle = NULL; nss_close(connssl); nss_close(connssl_proxy); } /* return true if NSS can provide error code (and possibly msg) for the error */ static bool is_nss_error(CURLcode err) { switch(err) { case CURLE_PEER_FAILED_VERIFICATION: case CURLE_SSL_CERTPROBLEM: case CURLE_SSL_CONNECT_ERROR: case CURLE_SSL_ISSUER_ERROR: return true; default: return false; } } /* return true if the given error code is related to a client certificate */ static bool is_cc_error(PRInt32 err) { switch(err) { case SSL_ERROR_BAD_CERT_ALERT: case SSL_ERROR_EXPIRED_CERT_ALERT: case SSL_ERROR_REVOKED_CERT_ALERT: return true; default: return false; } } static Curl_recv nss_recv; static Curl_send nss_send; static CURLcode nss_load_ca_certificates(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; const char *cafile = SSL_CONN_CONFIG(CAfile); const char *capath = SSL_CONN_CONFIG(CApath); bool use_trust_module; CURLcode result = CURLE_OK; /* treat empty string as unset */ if(cafile && !cafile[0]) cafile = NULL; if(capath && !capath[0]) capath = NULL; infof(data, " CAfile: %s\n CApath: %s\n", cafile ? cafile : "none", capath ? capath : "none"); /* load libnssckbi.so if no other trust roots were specified */ use_trust_module = !cafile && !capath; PR_Lock(nss_trustload_lock); if(use_trust_module && !trust_module) { /* libnssckbi.so needed but not yet loaded --> load it! */ result = nss_load_module(&trust_module, trust_library, "trust"); infof(data, "%s %s\n", (result) ? "failed to load" : "loaded", trust_library); if(result == CURLE_FAILED_INIT) /* If libnssckbi.so is not available (or fails to load), one can still use CA certificates stored in NSS database. Ignore the failure. */ result = CURLE_OK; } else if(!use_trust_module && trust_module) { /* libnssckbi.so not needed but already loaded --> unload it! */ infof(data, "unloading %s\n", trust_library); nss_unload_module(&trust_module); } PR_Unlock(nss_trustload_lock); if(cafile) result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); if(result) return result; if(capath) { struct_stat st; if(stat(capath, &st) == -1) return CURLE_SSL_CACERT_BADFILE; if(S_ISDIR(st.st_mode)) { PRDirEntry *entry; PRDir *dir = PR_OpenDir(capath); if(!dir) return CURLE_SSL_CACERT_BADFILE; while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) { char *fullpath = aprintf("%s/%s", capath, entry->name); if(!fullpath) { PR_CloseDir(dir); return CURLE_OUT_OF_MEMORY; } if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) /* This is purposefully tolerant of errors so non-PEM files can * be in the same directory */ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); free(fullpath); } PR_CloseDir(dir); } else infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath); } return CURLE_OK; } static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version) { switch(version) { case CURL_SSLVERSION_SSLv2: *nssver = SSL_LIBRARY_VERSION_2; return CURLE_OK; case CURL_SSLVERSION_SSLv3: *nssver = SSL_LIBRARY_VERSION_3_0; return CURLE_OK; case CURL_SSLVERSION_TLSv1_0: *nssver = SSL_LIBRARY_VERSION_TLS_1_0; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1: #ifdef SSL_LIBRARY_VERSION_TLS_1_1 *nssver = SSL_LIBRARY_VERSION_TLS_1_1; return CURLE_OK; #else return CURLE_SSL_CONNECT_ERROR; #endif case CURL_SSLVERSION_TLSv1_2: #ifdef SSL_LIBRARY_VERSION_TLS_1_2 *nssver = SSL_LIBRARY_VERSION_TLS_1_2; return CURLE_OK; #else return CURLE_SSL_CONNECT_ERROR; #endif case CURL_SSLVERSION_TLSv1_3: #ifdef SSL_LIBRARY_VERSION_TLS_1_3 *nssver = SSL_LIBRARY_VERSION_TLS_1_3; return CURLE_OK; #else return CURLE_SSL_CONNECT_ERROR; #endif default: return CURLE_SSL_CONNECT_ERROR; } } static CURLcode nss_init_sslver(SSLVersionRange *sslver, struct Curl_easy *data, struct connectdata *conn) { CURLcode result; const long min = SSL_CONN_CONFIG(version); const long max = SSL_CONN_CONFIG(version_max); SSLVersionRange vrange; switch(min) { case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_DEFAULT: /* Bump our minimum TLS version if NSS has stricter requirements. */ if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess) return CURLE_SSL_CONNECT_ERROR; if(sslver->min < vrange.min) sslver->min = vrange.min; break; default: result = nss_sslver_from_curl(&sslver->min, min); if(result) { failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); return result; } } switch(max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: break; default: result = nss_sslver_from_curl(&sslver->max, max >> 16); if(result) { failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); return result; } } return CURLE_OK; } static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, struct Curl_easy *data, CURLcode curlerr) { PRErrorCode err = 0; if(is_nss_error(curlerr)) { /* read NSPR error code */ err = PR_GetError(); if(is_cc_error(err)) curlerr = CURLE_SSL_CERTPROBLEM; /* print the error number and error string */ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); } /* cleanup on connection failure */ Curl_llist_destroy(&BACKEND->obj_list, NULL); return curlerr; } /* Switch the SSL socket into blocking or non-blocking mode. */ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, struct Curl_easy *data, bool blocking) { static PRSocketOptionData sock_opt; sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = !blocking; if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS) return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); return CURLE_OK; } static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) { PRFileDesc *model = NULL; PRFileDesc *nspr_io = NULL; PRFileDesc *nspr_io_stub = NULL; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result; bool second_layer = FALSE; SSLVersionRange sslver_supported; SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, /* min */ #ifdef SSL_LIBRARY_VERSION_TLS_1_3 SSL_LIBRARY_VERSION_TLS_1_3 /* max */ #elif defined SSL_LIBRARY_VERSION_TLS_1_2 SSL_LIBRARY_VERSION_TLS_1_2 #elif defined SSL_LIBRARY_VERSION_TLS_1_1 SSL_LIBRARY_VERSION_TLS_1_1 #else SSL_LIBRARY_VERSION_TLS_1_0 #endif }; BACKEND->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ Curl_llist_init(&BACKEND->obj_list, nss_destroy_object); PR_Lock(nss_initlock); result = nss_init(conn->data); if(result) { PR_Unlock(nss_initlock); goto error; } PK11_SetPasswordFunc(nss_get_password); result = nss_load_module(&pem_module, pem_library, "PEM"); PR_Unlock(nss_initlock); if(result == CURLE_FAILED_INIT) infof(data, "WARNING: failed to load NSS PEM library %s. Using " "OpenSSL PEM certificates will not work.\n", pem_library); else if(result) goto error; result = CURLE_SSL_CONNECT_ERROR; model = PR_NewTCPSocket(); if(!model) goto error; model = SSL_ImportFD(NULL, model); if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) goto error; /* do not use SSL cache if disabled or we are not going to verify peer */ ssl_no_cache = (SSL_SET_OPTION(primary.sessionid) && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; /* enable/disable the requested SSL version(s) */ if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) goto error; if(SSL_VersionRangeGetSupported(ssl_variant_stream, &sslver_supported) != SECSuccess) goto error; if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) { char *sslver_req_str, *sslver_supp_str; sslver_req_str = nss_sslver_to_name(sslver.max); sslver_supp_str = nss_sslver_to_name(sslver_supported.max); if(sslver_req_str && sslver_supp_str) infof(data, "Falling back from %s to max supported SSL version (%s)\n", sslver_req_str, sslver_supp_str); free(sslver_req_str); free(sslver_supp_str); sslver.max = sslver_supported.max; } if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) goto error; ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); #ifdef SSL_CBC_RANDOM_IV /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", ssl_cbc_random_iv); #else if(ssl_cbc_random_iv) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif if(SSL_CONN_CONFIG(cipher_list)) { if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { result = CURLE_SSL_CIPHER; goto error; } } if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) infof(data, "warning: ignoring value of ssl.verifyhost\n"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to * verify peer */ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) goto error; /* not checked yet */ if(SSL_IS_PROXY()) data->set.proxy_ssl.certverifyresult = 0; else data->set.ssl.certverifyresult = 0; if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) goto error; if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) goto error; { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) /* not a fatal error because we are not going to verify the peer */ infof(data, "warning: CA certificates failed to load\n"); else if(rv) { result = rv; goto error; } } if(SSL_SET_OPTION(CRLfile)) { const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); if(rv) { result = rv; goto error; } infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); } if(SSL_SET_OPTION(cert)) { char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ BACKEND->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), SSL_SET_OPTION(key)); if(rv) { /* failf() is already done in cert_stuff() */ result = rv; goto error; } } /* store the nickname for SelectClientCert() called during handshake */ BACKEND->client_nickname = nickname; } else BACKEND->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { result = CURLE_SSL_CERTPROBLEM; goto error; } if(conn->proxy_ssl[sockindex].use) { DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL); nspr_io = conn->proxy_ssl[sockindex].backend->handle; second_layer = TRUE; } else { /* wrap OS file descriptor by NSPR's file descriptor abstraction */ nspr_io = PR_ImportTCPSocket(sockfd); if(!nspr_io) goto error; } /* create our own NSPR I/O layer */ nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); if(!nspr_io_stub) { if(!second_layer) PR_Close(nspr_io); goto error; } /* make the per-connection data accessible from NSPR I/O callbacks */ nspr_io_stub->secret = (void *)connssl; /* push our new layer to the NSPR I/O stack */ if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { if(!second_layer) PR_Close(nspr_io); PR_Close(nspr_io_stub); goto error; } /* import our model socket onto the current I/O stack */ BACKEND->handle = SSL_ImportFD(model, nspr_io); if(!BACKEND->handle) { if(!second_layer) PR_Close(nspr_io); goto error; } PR_Close(model); /* We don't need this any more */ model = NULL; /* This is the password associated with the cert that we're using */ if(SSL_SET_OPTION(key_passwd)) { SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd)); } #ifdef SSL_ENABLE_OCSP_STAPLING if(SSL_CONN_CONFIG(verifystatus)) { if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) goto error; } #endif #ifdef SSL_ENABLE_NPN if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #ifdef SSL_ENABLE_ALPN if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ if(data->set.ssl.falsestart) { if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE) != SECSuccess) goto error; if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback, conn) != SECSuccess) goto error; } #endif #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); cur += NGHTTP2_PROTO_VERSION_ID_LEN; } #endif protocols[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess) goto error; } #endif /* Force handshake on next I/O */ if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE) != SECSuccess) goto error; /* propagate hostname to the TLS layer */ if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; /* prevent NSS from re-using the session for a different hostname */ if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name) != SECSuccess) goto error; return CURLE_OK; error: if(model) PR_Close(model); return nss_fail_connect(connssl, data, result); } static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; const char * const pinnedpubkey = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; /* check timeout situation */ const timediff_t time_left = Curl_timeleft(data, NULL, TRUE); if(time_left < 0) { failf(data, "timed out before SSL handshake"); result = CURLE_OPERATION_TIMEDOUT; goto error; } /* Force the handshake now */ timeout = PR_MillisecondsToInterval((PRUint32) time_left); if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) { if(PR_GetError() == PR_WOULD_BLOCK_ERROR) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) result = CURLE_PEER_FAILED_VERIFICATION; else if(*certverifyresult != 0) result = CURLE_PEER_FAILED_VERIFICATION; goto error; } result = display_conn_info(conn, BACKEND->handle); if(result) goto error; if(SSL_SET_OPTION(issuercert)) { SECStatus ret = SECFailure; char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); if(nickname) { /* we support only nicknames in case of issuercert for now */ ret = check_issuer_cert(BACKEND->handle, nickname); free(nickname); } if(SECFailure == ret) { infof(data, "SSL certificate issuer check failed\n"); result = CURLE_SSL_ISSUER_ERROR; goto error; } else { infof(data, "SSL certificate issuer check ok\n"); } } result = cmp_peer_pubkey(connssl, pinnedpubkey); if(result) /* status already printed */ goto error; return CURLE_OK; error: return nss_fail_connect(connssl, data, result); } static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, bool *done) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; const bool blocking = (done == NULL); CURLcode result; if(connssl->state == ssl_connection_complete) { if(!blocking) *done = TRUE; return CURLE_OK; } if(connssl->connecting_state == ssl_connect_1) { result = nss_setup_connect(conn, sockindex); if(result) /* we do not expect CURLE_AGAIN from nss_setup_connect() */ return result; connssl->connecting_state = ssl_connect_2; } /* enable/disable blocking mode before handshake */ result = nss_set_blocking(connssl, data, blocking); if(result) return result; result = nss_do_connect(conn, sockindex); switch(result) { case CURLE_OK: break; case CURLE_AGAIN: if(!blocking) /* CURLE_AGAIN in non-blocking mode is not an error */ return CURLE_OK; /* FALLTHROUGH */ default: return result; } if(blocking) { /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ result = nss_set_blocking(connssl, data, /* blocking */ FALSE); if(result) return result; } else /* signal completed SSL handshake */ *done = TRUE; connssl->state = ssl_connection_complete; conn->recv[sockindex] = nss_recv; conn->send[sockindex] = nss_send; /* ssl_connect_done is never used outside, go back to the initial state */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) { return nss_connect_common(conn, sockindex, /* blocking */ NULL); } static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return nss_connect_common(conn, sockindex, done); } static ssize_t nss_send(struct connectdata *conn, /* connection data */ int sockindex, /* socketindex */ const void *mem, /* send this data */ size_t len, /* amount to write */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ssize_t rc; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ BACKEND->data = conn->data; rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT); if(rc < 0) { PRInt32 err = PR_GetError(); if(err == PR_WOULD_BLOCK_ERROR) *curlcode = CURLE_AGAIN; else { /* print the error number and error string */ const char *err_name = nss_error_to_name(err); infof(conn->data, "SSL write: error %d (%s)\n", err, err_name); /* print a human-readable message describing the error if available */ nss_print_error_message(conn->data, err); *curlcode = (is_cc_error(err)) ? CURLE_SSL_CERTPROBLEM : CURLE_SEND_ERROR; } return -1; } return rc; /* number of bytes */ } static ssize_t nss_recv(struct connectdata *conn, /* connection data */ int sockindex, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ssize_t nread; /* The SelectClientCert() hook uses this for infof() and failf() but the handle stored in nss_setup_connect() could have already been freed. */ BACKEND->data = conn->data; nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0, PR_INTERVAL_NO_WAIT); if(nread < 0) { /* failed SSL read */ PRInt32 err = PR_GetError(); if(err == PR_WOULD_BLOCK_ERROR) *curlcode = CURLE_AGAIN; else { /* print the error number and error string */ const char *err_name = nss_error_to_name(err); infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name); /* print a human-readable message describing the error if available */ nss_print_error_message(conn->data, err); *curlcode = (is_cc_error(err)) ? CURLE_SSL_CERTPROBLEM : CURLE_RECV_ERROR; } return -1; } return nread; } static size_t Curl_nss_version(char *buffer, size_t size) { return msnprintf(buffer, size, "NSS/%s", NSS_VERSION); } /* data might be NULL */ static int Curl_nss_seed(struct Curl_easy *data) { /* make sure that NSS is initialized */ return !!Curl_nss_force_init(data); } /* data might be NULL */ static CURLcode Curl_nss_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { Curl_nss_seed(data); /* Initiate the seed if not already done */ if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) /* signal a failure */ return CURLE_FAILED_INIT; return CURLE_OK; } static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len) { PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); unsigned int MD5out; PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len)); PK11_DestroyContext(MD5pw, PR_TRUE); return CURLE_OK; } static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len) { PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256); unsigned int SHA256out; PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen)); PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len)); PK11_DestroyContext(SHA256pw, PR_TRUE); return CURLE_OK; } static bool Curl_nss_cert_status_request(void) { #ifdef SSL_ENABLE_OCSP_STAPLING return TRUE; #else return FALSE; #endif } static bool Curl_nss_false_start(void) { #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ return TRUE; #else return FALSE; #endif } static void *Curl_nss_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->handle; } const struct Curl_ssl Curl_ssl_nss = { { CURLSSLBACKEND_NSS, "nss" }, /* info */ SSLSUPP_CA_PATH | SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY | SSLSUPP_HTTPS_PROXY, sizeof(struct ssl_backend_data), Curl_nss_init, /* init */ Curl_nss_cleanup, /* cleanup */ Curl_nss_version, /* version */ Curl_nss_check_cxn, /* check_cxn */ /* NSS has no shutdown function provided and thus always fail */ Curl_none_shutdown, /* shutdown */ Curl_none_data_pending, /* data_pending */ Curl_nss_random, /* random */ Curl_nss_cert_status_request, /* cert_status_request */ Curl_nss_connect, /* connect */ Curl_nss_connect_nonblocking, /* connect_nonblocking */ Curl_nss_get_internals, /* get_internals */ Curl_nss_close, /* close_one */ Curl_none_close_all, /* close_all */ /* NSS has its own session ID cache */ Curl_none_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_nss_false_start, /* false_start */ Curl_nss_md5sum, /* md5sum */ Curl_nss_sha256sum /* sha256sum */ }; #endif /* USE_NSS */ davix-0.8.0/deps/curl/lib/vtls/sectransp.h0000644000000000000000000000244614121063461017145 0ustar rootroot#ifndef HEADER_CURL_SECTRANSP_H #define HEADER_CURL_SECTRANSP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, . * Copyright (C) 2012 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_SECTRANSP extern const struct Curl_ssl Curl_ssl_sectransp; #endif /* USE_SECTRANSP */ #endif /* HEADER_CURL_SECTRANSP_H */ davix-0.8.0/deps/curl/lib/vtls/mesalink.c0000644000000000000000000004602214121063461016737 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2017 - 2018, Yiming Jing, * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all MesaLink-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. * */ /* * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * Thanks for code and inspiration! */ #include "curl_setup.h" #ifdef USE_MESALINK #include #include #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" #include "mesalink.h" #include #include /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" #define MESALINK_MAX_ERROR_SZ 80 struct ssl_backend_data { SSL_CTX *ctx; SSL *handle; }; #define BACKEND connssl->backend static Curl_recv mesalink_recv; static Curl_send mesalink_send; static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; return -1; } /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. */ static CURLcode mesalink_connect_step1(struct connectdata *conn, int sockindex) { char *ciphers; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct in_addr addr4; #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif const char *const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; size_t hostname_len = strlen(hostname); SSL_METHOD *req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; if(connssl->state == ssl_connection_complete) return CURLE_OK; if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { failf(data, "MesaLink does not support to set maximum SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: failf(data, "MesaLink does not support SSL 3.0, TLS 1.0, or TLS 1.1"); return CURLE_NOT_BUILT_IN; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1_2: req_method = TLSv1_2_client_method(); break; case CURL_SSLVERSION_TLSv1_3: req_method = TLSv1_3_client_method(); break; case CURL_SSLVERSION_SSLv2: failf(data, "MesaLink does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(!req_method) { failf(data, "SSL: couldn't create a method!"); return CURLE_OUT_OF_MEMORY; } if(BACKEND->ctx) SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = SSL_CTX_new(req_method); if(!BACKEND->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } SSL_CTX_set_verify( BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) { if(!SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile), SSL_CONN_CONFIG(CApath))) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none", SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none"); return CURLE_SSL_CACERT_BADFILE; } infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } else { infof(data, "successfully set certificate verify locations:\n"); } infof(data, " CAfile: %s\n" " CApath: %s\n", SSL_CONN_CONFIG(CAfile)? SSL_CONN_CONFIG(CAfile): "none", SSL_CONN_CONFIG(CApath)? SSL_CONN_CONFIG(CApath): "none"); } if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { int file_type = do_file_type(SSL_SET_OPTION(cert_type)); if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } file_type = do_file_type(SSL_SET_OPTION(key_type)); if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; } infof(data, "client cert: %s\n", SSL_CONN_CONFIG(clientcert)? SSL_CONN_CONFIG(clientcert): "none"); } ciphers = SSL_CONN_CONFIG(cipher_list); if(ciphers) { #ifdef MESALINK_HAVE_CIPHER if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } #endif infof(data, "Cipher selection: %s\n", ciphers); } if(BACKEND->handle) SSL_free(BACKEND->handle); BACKEND->handle = SSL_new(BACKEND->ctx); if(!BACKEND->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } if((hostname_len < USHRT_MAX) && (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) #ifdef ENABLE_IPV6 && (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) #endif ) { /* hostname is not a valid IP address */ if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) { failf(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); return CURLE_SSL_CONNECT_ERROR; } } else { #ifdef CURLDEBUG /* Check if the hostname is 127.0.0.1 or [::1]; * otherwise reject because MesaLink always wants a valid DNS Name * specified in RFC 5280 Section 7.2 */ if(strncmp(hostname, "127.0.0.1", 9) == 0 #ifdef ENABLE_IPV6 || strncmp(hostname, "[::1]", 5) == 0 #endif ) { SSL_set_tlsext_host_name(BACKEND->handle, "localhost"); } else #endif { failf(data, "ERROR: MesaLink does not accept an IP address as a hostname\n"); return CURLE_SSL_CONNECT_ERROR; } } #ifdef MESALINK_HAVE_SESSION if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); failf( data, "SSL: SSL_set_session failed: %s", ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer)); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof(data, "SSL re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } #endif /* MESALINK_HAVE_SESSION */ if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) { failf(data, "SSL: SSL_set_fd failed"); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode mesalink_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; conn->recv[sockindex] = mesalink_recv; conn->send[sockindex] = mesalink_send; ret = SSL_connect(BACKEND->handle); if(ret != SSL_SUCCESS) { int detail = SSL_get_error(BACKEND->handle, ret); if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } else { char error_buffer[MESALINK_MAX_ERROR_SZ]; failf(data, "SSL_connect failed with error %d: %s", detail, ERR_error_string_n(detail, error_buffer, sizeof(error_buffer))); ERR_print_errors_fp(stderr); if(detail && SSL_CONN_CONFIG(verifypeer)) { detail &= ~0xFF; if(detail == TLS_ERROR_WEBPKI_ERRORS) { failf(data, "Cert verify failed"); return CURLE_PEER_FAILED_VERIFICATION; } } return CURLE_SSL_CONNECT_ERROR; } } connssl->connecting_state = ssl_connect_3; infof(data, "SSL connection using %s / %s\n", SSL_get_version(BACKEND->handle), SSL_get_cipher_name(BACKEND->handle)); return CURLE_OK; } static CURLcode mesalink_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); #ifdef MESALINK_HAVE_SESSION if(SSL_SET_OPTION(primary.sessionid)) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; our_ssl_sessionid = SSL_get_session(BACKEND->handle); Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); Curl_ssl_delsessionid(conn, old_ssl_sessionid); incache = FALSE; } } if(!incache) { result = Curl_ssl_addsessionid( conn, our_ssl_sessionid, 0 /* unknown size */, sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "failed to store ssl session"); return result; } } Curl_ssl_sessionid_unlock(conn); } #endif /* MESALINK_HAVE_SESSION */ connssl->connecting_state = ssl_connect_done; return result; } static ssize_t mesalink_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; char error_buffer[MESALINK_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; int rc = SSL_write(BACKEND->handle, mem, memlen); if(rc < 0) { int err = SSL_get_error(BACKEND->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_write() */ *curlcode = CURLE_AGAIN; return -1; default: failf(conn->data, "SSL write: %s, errno %d", ERR_error_string_n(err, error_buffer, sizeof(error_buffer)), SOCKERRNO); *curlcode = CURLE_SEND_ERROR; return -1; } } return rc; } static void Curl_mesalink_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(BACKEND->handle) { (void)SSL_shutdown(BACKEND->handle); SSL_free(BACKEND->handle); BACKEND->handle = NULL; } if(BACKEND->ctx) { SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = NULL; } } static ssize_t mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; char error_buffer[MESALINK_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; int nread = SSL_read(BACKEND->handle, buf, buffsize); if(nread <= 0) { int err = SSL_get_error(BACKEND->handle, nread); switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ case IO_ERROR_CONNECTION_ABORTED: break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_read() */ *curlcode = CURLE_AGAIN; return -1; default: failf(conn->data, "SSL read: %s, errno %d", ERR_error_string_n(err, error_buffer, sizeof(error_buffer)), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; } } return nread; } static size_t Curl_mesalink_version(char *buffer, size_t size) { return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING); } static int Curl_mesalink_init(void) { return (SSL_library_init() == SSL_SUCCESS); } /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ static int Curl_mesalink_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(BACKEND->handle) { SSL_free(BACKEND->handle); BACKEND->handle = NULL; } return retval; } static CURLcode mesalink_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; timediff_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } result = mesalink_connect_step1(conn, sockindex); if(result) return result; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; what = Curl_socket_check( readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : (time_t)timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if * this connection is part of a multi handle and this loop would * execute again. This permits the owner of a multi handle to * abort a connection attempt before step2 has completed while * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ result = mesalink_connect_step2(conn, sockindex); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) { return result; } } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { result = mesalink_connect_step3(conn, sockindex); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = mesalink_recv; conn->send[sockindex] = mesalink_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return mesalink_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_mesalink_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = mesalink_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static void * Curl_mesalink_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->handle; } const struct Curl_ssl Curl_ssl_mesalink = { { CURLSSLBACKEND_MESALINK, "MesaLink" }, /* info */ SSLSUPP_SSL_CTX, sizeof(struct ssl_backend_data), Curl_mesalink_init, /* init */ Curl_none_cleanup, /* cleanup */ Curl_mesalink_version, /* version */ Curl_none_check_cxn, /* check_cxn */ Curl_mesalink_shutdown, /* shutdown */ Curl_none_data_pending, /* data_pending */ Curl_none_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_mesalink_connect, /* connect */ Curl_mesalink_connect_nonblocking, /* connect_nonblocking */ Curl_mesalink_get_internals, /* get_internals */ Curl_mesalink_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_none_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_none_md5sum, /* md5sum */ NULL /* sha256sum */ }; #endif davix-0.8.0/deps/curl/lib/vtls/gtls.h0000644000000000000000000000234214121063461016107 0ustar rootroot#ifndef HEADER_CURL_GTLS_H #define HEADER_CURL_GTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_GNUTLS #include "urldata.h" extern const struct Curl_ssl Curl_ssl_gnutls; #endif /* USE_GNUTLS */ #endif /* HEADER_CURL_GTLS_H */ davix-0.8.0/deps/curl/lib/vtls/nssg.h0000644000000000000000000000261314121063461016111 0ustar rootroot#ifndef HEADER_CURL_NSSG_H #define HEADER_CURL_NSSG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NSS /* * This header should only be needed to get included by vtls.c and nss.c */ #include "urldata.h" /* initialize NSS library if not already */ CURLcode Curl_nss_force_init(struct Curl_easy *data); extern const struct Curl_ssl Curl_ssl_nss; #endif /* USE_NSS */ #endif /* HEADER_CURL_NSSG_H */ davix-0.8.0/deps/curl/lib/vtls/schannel.h0000644000000000000000000000713314121063461016734 0ustar rootroot#ifndef HEADER_CURL_SCHANNEL_H #define HEADER_CURL_SCHANNEL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Marc Hoersken, , et al. * Copyright (C) 2012 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_SCHANNEL #include #include #include "curl_sspi.h" #include "urldata.h" /* has been included via the above . * Or in case of ldap.c, it was included via . * And since has this: * #define X509_NAME ((LPCSTR) 7) * * And in BoringSSL's there is: * typedef struct X509_name_st X509_NAME; * etc. * * this will cause all kinds of C-preprocessing paste errors in * BoringSSL's : So just undefine those defines here * (and only here). */ #if defined(HAVE_BORINGSSL) || defined(OPENSSL_IS_BORINGSSL) # undef X509_NAME # undef X509_CERT_PAIR # undef X509_EXTENSIONS #endif extern const struct Curl_ssl Curl_ssl_schannel; CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex); /* structs to expose only in schannel.c and schannel_verify.c */ #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS #ifdef __MINGW32__ #include <_mingw.h> #ifdef __MINGW64_VERSION_MAJOR #define HAS_MANUAL_VERIFY_API #endif #else #include #ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN #define HAS_MANUAL_VERIFY_API #endif #endif struct curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; int refcount; }; struct curl_schannel_ctxt { CtxtHandle ctxt_handle; TimeStamp time_stamp; }; struct ssl_backend_data { struct curl_schannel_cred *cred; struct curl_schannel_ctxt *ctxt; SecPkgContext_StreamSizes stream_sizes; size_t encdata_length, decdata_length; size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; /* encdata_is_incomplete: if encdata contains only a partial record that can't be decrypted without another Curl_read_plain (that is, status is SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes more bytes into encdata then set this back to false. */ bool encdata_is_incomplete; unsigned long req_flags, ret_flags; CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ bool use_alpn; /* true if ALPN is used for this connection */ #ifdef HAS_MANUAL_VERIFY_API bool use_manual_cred_validation; /* true if manual cred validation is used */ #endif }; #endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */ #endif /* USE_SCHANNEL */ #endif /* HEADER_CURL_SCHANNEL_H */ davix-0.8.0/deps/curl/lib/vtls/gskit.c0000644000000000000000000011535614121063461016264 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_GSKIT #include #include #undef HAVE_SOCKETPAIR /* because the native one isn't good enough */ #include "socketpair.h" /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */ #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST #define GSK_SSL_EXTN_SERVERNAME_REQUEST 230 #endif #ifndef GSK_TLSV10_CIPHER_SPECS #define GSK_TLSV10_CIPHER_SPECS 236 #endif #ifndef GSK_TLSV11_CIPHER_SPECS #define GSK_TLSV11_CIPHER_SPECS 237 #endif #ifndef GSK_TLSV12_CIPHER_SPECS #define GSK_TLSV12_CIPHER_SPECS 238 #endif #ifndef GSK_PROTOCOL_TLSV11 #define GSK_PROTOCOL_TLSV11 437 #endif #ifndef GSK_PROTOCOL_TLSV12 #define GSK_PROTOCOL_TLSV12 438 #endif #ifndef GSK_FALSE #define GSK_FALSE 0 #endif #ifndef GSK_TRUE #define GSK_TRUE 1 #endif #include #include #include "urldata.h" #include "sendf.h" #include "gskit.h" #include "vtls.h" #include "connect.h" /* for the connect timeout */ #include "select.h" #include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* Directions. */ #define SOS_READ 0x01 #define SOS_WRITE 0x02 /* SSL version flags. */ #define CURL_GSKPROTO_SSLV2 0 #define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2) #define CURL_GSKPROTO_SSLV3 1 #define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3) #define CURL_GSKPROTO_TLSV10 2 #define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10) #define CURL_GSKPROTO_TLSV11 3 #define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11) #define CURL_GSKPROTO_TLSV12 4 #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) #define CURL_GSKPROTO_LAST 5 struct ssl_backend_data { gsk_handle handle; int iocport; int localfd; int remotefd; }; #define BACKEND connssl->backend /* Supported ciphers. */ typedef struct { const char *name; /* Cipher name. */ const char *gsktoken; /* Corresponding token for GSKit String. */ unsigned int versions; /* SSL version flags. */ } gskit_cipher; static const gskit_cipher ciphertable[] = { { "null-md5", "01", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "null-sha", "02", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "exp-rc4-md5", "03", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, { "rc4-md5", "04", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "rc4-sha", "05", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "exp-rc2-cbc-md5", "06", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK }, { "exp-des-cbc-sha", "09", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK }, { "des-cbc3-sha", "0A", CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "aes128-sha", "2F", CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "aes256-sha", "35", CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK }, { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK }, { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK }, { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK }, { "aes128-gcm-sha256", "9C", CURL_GSKPROTO_TLSV12_MASK }, { "aes256-gcm-sha384", "9D", CURL_GSKPROTO_TLSV12_MASK }, { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK }, { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK }, { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK }, { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK }, { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK }, { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK }, { (const char *) NULL, (const char *) NULL, 0 } }; static bool is_separator(char c) { /* Return whether character is a cipher list separator. */ switch(c) { case ' ': case '\t': case ':': case ',': case ';': return true; } return false; } static CURLcode gskit_status(struct Curl_easy *data, int rc, const char *procname, CURLcode defcode) { /* Process GSKit status and map it to a CURLcode. */ switch(rc) { case GSK_OK: case GSK_OS400_ASYNCHRONOUS_SOC_INIT: return CURLE_OK; case GSK_KEYRING_OPEN_ERROR: case GSK_OS400_ERROR_NO_ACCESS: return CURLE_SSL_CACERT_BADFILE; case GSK_INSUFFICIENT_STORAGE: return CURLE_OUT_OF_MEMORY; case GSK_ERROR_BAD_V2_CIPHER: case GSK_ERROR_BAD_V3_CIPHER: case GSK_ERROR_NO_CIPHERS: return CURLE_SSL_CIPHER; case GSK_OS400_ERROR_NOT_TRUSTED_ROOT: case GSK_ERROR_CERT_VALIDATION: return CURLE_PEER_FAILED_VERIFICATION; case GSK_OS400_ERROR_TIMED_OUT: return CURLE_OPERATION_TIMEDOUT; case GSK_WOULD_BLOCK: return CURLE_AGAIN; case GSK_OS400_ERROR_NOT_REGISTERED: break; case GSK_ERROR_IO: switch(errno) { case ENOMEM: return CURLE_OUT_OF_MEMORY; default: failf(data, "%s I/O error: %s", procname, strerror(errno)); break; } break; default: failf(data, "%s: %s", procname, gsk_strerror(rc)); break; } return defcode; } static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) { int rc = gsk_attribute_set_enum(h, id, value); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) return CURLE_UNSUPPORTED_PROTOCOL; default: failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc)); break; } return CURLE_SSL_CONNECT_ERROR; } static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, GSK_BUF_ID id, const char *buffer, bool unsupported_ok) { int rc = gsk_attribute_set_buffer(h, id, buffer, 0); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) return CURLE_UNSUPPORTED_PROTOCOL; default: failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); break; } return CURLE_SSL_CONNECT_ERROR; } static CURLcode set_numeric(struct Curl_easy *data, gsk_handle h, GSK_NUM_ID id, int value) { int rc = gsk_attribute_set_numeric_value(h, id, value); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", strerror(errno)); break; default: failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); break; } return CURLE_SSL_CONNECT_ERROR; } static CURLcode set_callback(struct Curl_easy *data, gsk_handle h, GSK_CALLBACK_ID id, void *info) { int rc = gsk_attribute_set_callback(h, id, info); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); break; default: failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); break; } return CURLE_SSL_CONNECT_ERROR; } static CURLcode set_ciphers(struct connectdata *conn, gsk_handle h, unsigned int *protoflags) { struct Curl_easy *data = conn->data; const char *cipherlist = SSL_CONN_CONFIG(cipher_list); const char *clp; const gskit_cipher *ctp; int i; int l; bool unsupported; CURLcode result; struct { char *buf; char *ptr; } ciphers[CURL_GSKPROTO_LAST]; /* Compile cipher list into GSKit-compatible cipher lists. */ if(!cipherlist) return CURLE_OK; while(is_separator(*cipherlist)) /* Skip initial separators. */ cipherlist++; if(!*cipherlist) return CURLE_OK; /* We allocate GSKit buffers of the same size as the input string: since GSKit tokens are always shorter than their cipher names, allocated buffers will always be large enough to accommodate the result. */ l = strlen(cipherlist) + 1; memset((char *) ciphers, 0, sizeof(ciphers)); for(i = 0; i < CURL_GSKPROTO_LAST; i++) { ciphers[i].buf = malloc(l); if(!ciphers[i].buf) { while(i--) free(ciphers[i].buf); return CURLE_OUT_OF_MEMORY; } ciphers[i].ptr = ciphers[i].buf; *ciphers[i].ptr = '\0'; } /* Process each cipher in input string. */ unsupported = FALSE; result = CURLE_OK; for(;;) { for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) cipherlist++; l = cipherlist - clp; if(!l) break; /* Search the cipher in our table. */ for(ctp = ciphertable; ctp->name; ctp++) if(strncasecompare(ctp->name, clp, l) && !ctp->name[l]) break; if(!ctp->name) { failf(data, "Unknown cipher %.*s", l, clp); result = CURLE_SSL_CIPHER; } else { unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK | CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK)); for(i = 0; i < CURL_GSKPROTO_LAST; i++) { if(ctp->versions & (1 << i)) { strcpy(ciphers[i].ptr, ctp->gsktoken); ciphers[i].ptr += strlen(ctp->gsktoken); } } } /* Advance to next cipher name or end of string. */ while(is_separator(*cipherlist)) cipherlist++; } /* Disable protocols with empty cipher lists. */ for(i = 0; i < CURL_GSKPROTO_LAST; i++) { if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) { *protoflags &= ~(1 << i); ciphers[i].buf[0] = '\0'; } } /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */ if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) { result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS, ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { result = CURLE_OK; if(unsupported) { failf(data, "TLSv1.1-only ciphers are not yet supported"); result = CURLE_SSL_CIPHER; } } } if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) { result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS, ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { result = CURLE_OK; if(unsupported) { failf(data, "TLSv1.2-only ciphers are not yet supported"); result = CURLE_SSL_CIPHER; } } } /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */ if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) { result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS, ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { result = CURLE_OK; strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr, ciphers[CURL_GSKPROTO_TLSV10].ptr); } } /* Set-up other ciphers. */ if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK)) result = set_buffer(data, h, GSK_V3_CIPHER_SPECS, ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE); if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK)) result = set_buffer(data, h, GSK_V2_CIPHER_SPECS, ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE); /* Clean-up. */ for(i = 0; i < CURL_GSKPROTO_LAST; i++) free(ciphers[i].buf); return result; } static int Curl_gskit_init(void) { /* No initialisation needed. */ return 1; } static void Curl_gskit_cleanup(void) { /* Nothing to do. */ } static CURLcode init_environment(struct Curl_easy *data, gsk_handle *envir, const char *appid, const char *file, const char *label, const char *password) { int rc; CURLcode result; gsk_handle h; /* Creates the GSKit environment. */ rc = gsk_environment_open(&h); switch(rc) { case GSK_OK: break; case GSK_INSUFFICIENT_STORAGE: return CURLE_OUT_OF_MEMORY; default: failf(data, "gsk_environment_open(): %s", gsk_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE); if(!result && appid) result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE); if(!result && file) result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE); if(!result && label) result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE); if(!result && password) result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE); if(!result) { /* Locate CAs, Client certificate and key according to our settings. Note: this call may be blocking for some tenths of seconds. */ result = gskit_status(data, gsk_environment_init(h), "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); if(!result) { *envir = h; return result; } } /* Error: rollback. */ gsk_environment_close(&h); return result; } static void cancel_async_handshake(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; Qso_OverlappedIO_t cstat; if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL); } static void close_async_handshake(struct ssl_connect_data *connssl) { QsoDestroyIOCompletionPort(BACKEND->iocport); BACKEND->iocport = -1; } static int pipe_ssloverssl(struct connectdata *conn, int sockindex, int directions) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex]; fd_set fds_read; fd_set fds_write; int n; int m; int i; int ret = 0; struct timeval tv = {0, 0}; char buf[CURL_MAX_WRITE_SIZE]; if(!connssl->use || !connproxyssl->use) return 0; /* No SSL over SSL: OK. */ FD_ZERO(&fds_read); FD_ZERO(&fds_write); n = -1; if(directions & SOS_READ) { FD_SET(BACKEND->remotefd, &fds_write); n = BACKEND->remotefd; } if(directions & SOS_WRITE) { FD_SET(BACKEND->remotefd, &fds_read); n = BACKEND->remotefd; FD_SET(conn->sock[sockindex], &fds_write); if(n < conn->sock[sockindex]) n = conn->sock[sockindex]; } i = select(n + 1, &fds_read, &fds_write, NULL, &tv); if(i < 0) return -1; /* Select error. */ if(FD_ISSET(BACKEND->remotefd, &fds_write)) { /* Try getting data from HTTPS proxy and pipe it upstream. */ n = 0; i = gsk_secure_soc_read(connproxyssl->backend->handle, buf, sizeof(buf), &n); switch(i) { case GSK_OK: if(n) { i = write(BACKEND->remotefd, buf, n); if(i < 0) return -1; ret = 1; } break; case GSK_OS400_ERROR_TIMED_OUT: case GSK_WOULD_BLOCK: break; default: return -1; } } if(FD_ISSET(BACKEND->remotefd, &fds_read) && FD_ISSET(conn->sock[sockindex], &fds_write)) { /* Pipe data to HTTPS proxy. */ n = read(BACKEND->remotefd, buf, sizeof(buf)); if(n < 0) return -1; if(n) { i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m); if(i != GSK_OK || n != m) return -1; ret = 1; } } return ret; /* OK */ } static void close_one(struct ssl_connect_data *connssl, struct connectdata *conn, int sockindex) { if(BACKEND->handle) { gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle), "gsk_secure_soc_close()", 0); /* Last chance to drain output. */ while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) ; BACKEND->handle = (gsk_handle) NULL; if(BACKEND->localfd >= 0) { close(BACKEND->localfd); BACKEND->localfd = -1; } if(BACKEND->remotefd >= 0) { close(BACKEND->remotefd); BACKEND->remotefd = -1; } } if(BACKEND->iocport >= 0) close_async_handshake(connssl); } static ssize_t gskit_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; CURLcode cc = CURLE_SEND_ERROR; int written; if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { cc = gskit_status(data, gsk_secure_soc_write(BACKEND->handle, (char *) mem, (int) len, &written), "gsk_secure_soc_write()", CURLE_SEND_ERROR); if(cc == CURLE_OK) if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0) cc = CURLE_SEND_ERROR; } if(cc != CURLE_OK) { *curlcode = cc; written = -1; } return (ssize_t) written; /* number of bytes */ } static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { struct ssl_connect_data *connssl = &conn->ssl[num]; struct Curl_easy *data = conn->data; int nread; CURLcode cc = CURLE_RECV_ERROR; if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle, buf, buffsize, &nread), "gsk_secure_soc_read()", CURLE_RECV_ERROR); } switch(cc) { case CURLE_OK: break; case CURLE_OPERATION_TIMEDOUT: cc = CURLE_AGAIN; default: *curlcode = cc; nread = -1; break; } return (ssize_t) nread; } static CURLcode set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn) { struct Curl_easy *data = conn->data; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long i = ssl_version; switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: ssl_version_max = CURL_SSLVERSION_TLSv1_2; break; } for(; i <= (ssl_version_max >> 16); ++i) { switch(i) { case CURL_SSLVERSION_TLSv1_0: *protoflags |= CURL_GSKPROTO_TLSV10_MASK; break; case CURL_SSLVERSION_TLSv1_1: *protoflags |= CURL_GSKPROTO_TLSV11_MASK; break; case CURL_SSLVERSION_TLSv1_2: *protoflags |= CURL_GSKPROTO_TLSV11_MASK; break; case CURL_SSLVERSION_TLSv1_3: failf(data, "GSKit: TLS 1.3 is not yet supported"); return CURLE_SSL_CONNECT_ERROR; } } return CURLE_OK; } static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gsk_handle envir; CURLcode result; int rc; const char * const keyringfile = SSL_CONN_CONFIG(CAfile); const char * const keyringpwd = SSL_SET_OPTION(key_passwd); const char * const keyringlabel = SSL_SET_OPTION(cert); const long int ssl_version = SSL_CONN_CONFIG(version); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: conn->host.name; const char *sni; unsigned int protoflags = 0; Qso_OverlappedIO_t commarea; int sockpair[2]; static const int sobufsize = CURL_MAX_WRITE_SIZE; /* Create SSL environment, start (preferably asynchronous) handshake. */ BACKEND->handle = (gsk_handle) NULL; BACKEND->iocport = -1; BACKEND->localfd = -1; BACKEND->remotefd = -1; /* GSKit supports two ways of specifying an SSL context: either by * application identifier (that should have been defined at the system * level) or by keyring file, password and certificate label. * Local certificate name (CURLOPT_SSLCERT) is used to hold either the * application identifier of the certificate label. * Key password (CURLOPT_KEYPASSWD) holds the keyring password. * It is not possible to have different keyrings for the CAs and the * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify * the keyring file. * If no key password is given and the keyring is the system keyring, * application identifier mode is tried first, as recommended in IBM doc. */ envir = (gsk_handle) NULL; if(keyringlabel && *keyringlabel && !keyringpwd && !strcmp(keyringfile, CURL_CA_BUNDLE)) { /* Try application identifier mode. */ init_environment(data, &envir, keyringlabel, (const char *) NULL, (const char *) NULL, (const char *) NULL); } if(!envir) { /* Use keyring mode. */ result = init_environment(data, &envir, (const char *) NULL, keyringfile, keyringlabel, keyringpwd); if(result) return result; } /* Create secure session. */ result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle), "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); gsk_environment_close(&envir); if(result) return result; /* Establish a pipelining socket pair for SSL over SSL. */ if(conn->proxy_ssl[sockindex].use) { if(Curl_socketpair(0, 0, 0, sockpair)) return CURLE_SSL_CONNECT_ERROR; BACKEND->localfd = sockpair[0]; BACKEND->remotefd = sockpair[1]; setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF, (void *) sobufsize, sizeof(sobufsize)); setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF, (void *) sobufsize, sizeof(sobufsize)); setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF, (void *) sobufsize, sizeof(sobufsize)); setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF, (void *) sobufsize, sizeof(sobufsize)); curlx_nonblock(BACKEND->localfd, TRUE); curlx_nonblock(BACKEND->remotefd, TRUE); } /* Determine which SSL/TLS version should be enabled. */ sni = hostname; switch(ssl_version) { case CURL_SSLVERSION_SSLv2: protoflags = CURL_GSKPROTO_SSLV2_MASK; sni = NULL; break; case CURL_SSLVERSION_SSLv3: protoflags = CURL_GSKPROTO_SSLV3_MASK; sni = NULL; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: result = set_ssl_version_min_max(&protoflags, conn); if(result != CURLE_OK) return result; break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ if(sni) { result = set_buffer(data, BACKEND->handle, GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) result = CURLE_OK; } /* Set session parameters. */ if(!result) { /* Compute the handshake timeout. Since GSKit granularity is 1 second, we round up the required value. */ long timeout = Curl_timeleft(data, NULL, TRUE); if(timeout < 0) result = CURLE_OPERATION_TIMEDOUT; else result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT, (timeout + 999) / 1000); } if(!result) result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1); if(!result) result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0? BACKEND->localfd: conn->sock[sockindex]); if(!result) result = set_ciphers(conn, BACKEND->handle, &protoflags); if(!protoflags) { failf(data, "No SSL protocol/cipher combination enabled"); result = CURLE_SSL_CIPHER; } if(!result) result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2, (protoflags & CURL_GSKPROTO_SSLV2_MASK)? GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE); if(!result) result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3, (protoflags & CURL_GSKPROTO_SSLV3_MASK)? GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE); if(!result) result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1, (protoflags & CURL_GSKPROTO_TLSV10_MASK)? GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE); if(!result) { result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11, (protoflags & CURL_GSKPROTO_TLSV11_MASK)? GSK_TRUE: GSK_FALSE, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { result = CURLE_OK; if(protoflags == CURL_GSKPROTO_TLSV11_MASK) { failf(data, "TLS 1.1 not yet supported"); result = CURLE_SSL_CIPHER; } } } if(!result) { result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12, (protoflags & CURL_GSKPROTO_TLSV12_MASK)? GSK_TRUE: GSK_FALSE, TRUE); if(result == CURLE_UNSUPPORTED_PROTOCOL) { result = CURLE_OK; if(protoflags == CURL_GSKPROTO_TLSV12_MASK) { failf(data, "TLS 1.2 not yet supported"); result = CURLE_SSL_CIPHER; } } } if(!result) result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE, verifypeer? GSK_SERVER_AUTH_FULL: GSK_SERVER_AUTH_PASSTHRU, FALSE); if(!result) { /* Start handshake. Try asynchronous first. */ memset(&commarea, 0, sizeof(commarea)); BACKEND->iocport = QsoCreateIOCompletionPort(); if(BACKEND->iocport != -1) { result = gskit_status(data, gsk_secure_soc_startInit(BACKEND->handle, BACKEND->iocport, &commarea), "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR); if(!result) { connssl->connecting_state = ssl_connect_2; return CURLE_OK; } else close_async_handshake(connssl); } else if(errno != ENOBUFS) result = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0); else if(conn->proxy_ssl[sockindex].use) { /* Cannot pipeline while handshaking synchronously. */ result = CURLE_SSL_CONNECT_ERROR; } else { /* No more completion port available. Use synchronous IO. */ result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle), "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); if(!result) { connssl->connecting_state = ssl_connect_3; return CURLE_OK; } } } /* Error: rollback. */ close_one(connssl, conn, sockindex); return result; } static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, bool nonblocking) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; Qso_OverlappedIO_t cstat; struct timeval stmv; CURLcode result; /* Poll or wait for end of SSL asynchronous handshake. */ for(;;) { long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) timeout_ms = 0; stmv.tv_sec = timeout_ms / 1000; stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) { case 1: /* Operation complete. */ break; case -1: /* An error occurred: handshake still in progress. */ if(errno == EINTR) { if(nonblocking) return CURLE_OK; continue; /* Retry. */ } if(errno != ETIME) { failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); cancel_async_handshake(conn, sockindex); close_async_handshake(connssl); return CURLE_SSL_CONNECT_ERROR; } /* FALL INTO... */ case 0: /* Handshake in progress, timeout occurred. */ if(nonblocking) return CURLE_OK; cancel_async_handshake(conn, sockindex); close_async_handshake(connssl); return CURLE_OPERATION_TIMEDOUT; } break; } result = gskit_status(data, cstat.returnValue, "SSL handshake", CURLE_SSL_CONNECT_ERROR); if(!result) connssl->connecting_state = ssl_connect_3; close_async_handshake(connssl); return result; } static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const gsk_cert_data_elem *cdev; int cdec; const gsk_cert_data_elem *p; const char *cert = (const char *) NULL; const char *certend; const char *ptr; CURLcode result; /* SSL handshake done: gather certificate info and verify host. */ if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle, GSK_PARTNER_CERT_INFO, &cdev, &cdec), "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == CURLE_OK) { int i; infof(data, "Server certificate:\n"); p = cdev; for(i = 0; i++ < cdec; p++) switch(p->cert_data_id) { case CERT_BODY_DER: cert = p->cert_data_p; certend = cert + cdev->cert_data_l; break; case CERT_DN_PRINTABLE: infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); break; case CERT_ISSUER_DN_PRINTABLE: infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); break; case CERT_VALID_FROM: infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); break; case CERT_VALID_TO: infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); break; } } /* Verify host. */ result = Curl_verifyhost(conn, cert, certend); if(result) return result; /* The only place GSKit can get the whole CA chain is a validation callback where no user data pointer is available. Therefore it's not possible to copy this chain into our structures for CAINFO. However the server certificate may be available, thus we can return info about it. */ if(data->set.ssl.certinfo) { result = Curl_ssl_init_certinfo(data, 1); if(result) return result; if(cert) { result = Curl_extract_certinfo(conn, 0, cert, certend); if(result) return result; } } /* Check pinned public key. */ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(!result && ptr) { curl_X509certificate x509; curl_asn1Element *p; if(Curl_parseX509(&x509, cert, certend)) return CURLE_SSL_PINNEDPUBKEYNOTMATCH; p = &x509.subjectPublicKeyInfo; result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } connssl->connecting_state = ssl_connect_done; return CURLE_OK; } static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; timediff_t timeout_ms; CURLcode result = CURLE_OK; *done = connssl->state == ssl_connection_complete; if(*done) return CURLE_OK; /* Step 1: create session, start handshake. */ if(connssl->connecting_state == ssl_connect_1) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); result = CURLE_OPERATION_TIMEDOUT; } else result = gskit_connect_step1(conn, sockindex); } /* Handle handshake pipelining. */ if(!result) if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) result = CURLE_SSL_CONNECT_ERROR; /* Step 2: check if handshake is over. */ if(!result && connssl->connecting_state == ssl_connect_2) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); result = CURLE_OPERATION_TIMEDOUT; } else result = gskit_connect_step2(conn, sockindex, nonblocking); } /* Handle handshake pipelining. */ if(!result) if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) result = CURLE_SSL_CONNECT_ERROR; /* Step 3: gather certificate info, verify host. */ if(!result && connssl->connecting_state == ssl_connect_3) result = gskit_connect_step3(conn, sockindex); if(result) close_one(connssl, conn, sockindex); else if(connssl->connecting_state == ssl_connect_done) { connssl->state = ssl_connection_complete; connssl->connecting_state = ssl_connect_1; conn->recv[sockindex] = gskit_recv; conn->send[sockindex] = gskit_send; *done = TRUE; } return result; } static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; result = gskit_connect_common(conn, sockindex, TRUE, done); if(*done || result) conn->ssl[sockindex].connecting_state = ssl_connect_1; return result; } static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done; conn->ssl[sockindex].connecting_state = ssl_connect_1; result = gskit_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static void Curl_gskit_close(struct connectdata *conn, int sockindex) { close_one(&conn->ssl[sockindex], conn, sockindex); close_one(&conn->proxy_ssl[sockindex], conn, sockindex); } static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; int what; int rc; char buf[120]; if(!BACKEND->handle) return 0; #ifndef CURL_DISABLE_FTP if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; #endif close_one(connssl, conn, sockindex); rc = 0; what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); for(;;) { ssize_t nread; if(what < 0) { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); rc = -1; break; } if(!what) { /* timeout */ failf(data, "SSL shutdown timeout"); break; } /* Something to read, let's do it and hope that it is the close notify alert from the server. No way to gsk_secure_soc_read() now, so use read(). */ nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { failf(data, "read: %s", strerror(errno)); rc = -1; } if(nread <= 0) break; what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; } static size_t Curl_gskit_version(char *buffer, size_t size) { return msnprintf(buffer, size, "GSKit"); } static int Curl_gskit_check_cxn(struct connectdata *cxn) { struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET]; int err; int errlen; /* The only thing that can be tested here is at the socket level. */ if(!BACKEND->handle) return 0; /* connection has been closed */ err = 0; errlen = sizeof(err); if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, (unsigned char *) &err, &errlen) || errlen != sizeof(err) || err) return 0; /* connection has been closed */ return -1; /* connection status unknown */ } static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->handle; } const struct Curl_ssl Curl_ssl_gskit = { { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */ SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY, sizeof(struct ssl_backend_data), Curl_gskit_init, /* init */ Curl_gskit_cleanup, /* cleanup */ Curl_gskit_version, /* version */ Curl_gskit_check_cxn, /* check_cxn */ Curl_gskit_shutdown, /* shutdown */ Curl_none_data_pending, /* data_pending */ Curl_none_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_gskit_connect, /* connect */ Curl_gskit_connect_nonblocking, /* connect_nonblocking */ Curl_gskit_get_internals, /* get_internals */ Curl_gskit_close, /* close_one */ Curl_none_close_all, /* close_all */ /* No session handling for GSKit */ Curl_none_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_none_md5sum, /* md5sum */ NULL /* sha256sum */ }; #endif /* USE_GSKIT */ davix-0.8.0/deps/curl/lib/vtls/openssl.c0000644000000000000000000036472414121063461016633 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. */ #include "curl_setup.h" #ifdef USE_OPENSSL #include #include "urldata.h" #include "sendf.h" #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "inet_pton.h" #include "openssl.h" #include "connect.h" #include "slist.h" #include "select.h" #include "vtls.h" #include "strcase.h" #include "hostcheck.h" #include "multiif.h" #include "strerror.h" #include "curl_printf.h" #include #include #include #ifndef OPENSSL_NO_DSA #include #endif #include #include #include #include #include #include #include #include #include #ifdef USE_AMISSL #include "amigaos.h" #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) #include #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \ !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE) #define USE_OPENSSL_ENGINE #include #endif #include "warnless.h" #include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */ /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS renegotiations when built with BoringSSL. Renegotiating is non-compliant with HTTP/2 and "an extremely dangerous protocol feature". Beware. #define ALLOW_RENEG 1 */ #ifndef OPENSSL_VERSION_NUMBER #error "OPENSSL_VERSION_NUMBER not defined" #endif #ifdef USE_OPENSSL_ENGINE #include #endif #if OPENSSL_VERSION_NUMBER >= 0x00909000L #define SSL_METHOD_QUAL const #else #define SSL_METHOD_QUAL #endif #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */ #undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */ #define OPENSSL_NO_SSL2 #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ !(defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER < 0x20700000L) #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ #define CONST_EXTS const #define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 /* funny typecast define due to difference in API */ #ifdef LIBRESSL_VERSION_NUMBER #define ARG2_X509_signature_print (X509_ALGOR *) #else #define ARG2_X509_signature_print #endif #else /* For OpenSSL before 1.1.0 */ #define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) #define X509_get0_notBefore(x) X509_get_notBefore(x) #define X509_get0_notAfter(x) X509_get_notAfter(x) #define CONST_EXTS /* nope */ #ifndef LIBRESSL_VERSION_NUMBER #define OpenSSL_version_num() SSLeay() #endif #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ !(defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER < 0x20700000L) #define HAVE_X509_GET0_SIGNATURE 1 #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */ #define HAVE_SSL_GET_SHUTDOWN 1 #endif #if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ !defined(OPENSSL_NO_COMP) #define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 #endif #if (OPENSSL_VERSION_NUMBER < 0x0090808fL) /* not present in older OpenSSL */ #define OPENSSL_load_builtin_modules(x) #endif /* * Whether SSL_CTX_set_keylog_callback is available. * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 * BoringSSL: supported since d28f59c27bac (committed 2015-11-19) * LibreSSL: unsupported in at least 2.7.2 (explicitly check for it since it * lies and pretends to be OpenSSL 2.0.0). */ #if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ !defined(LIBRESSL_VERSION_NUMBER)) || \ defined(OPENSSL_IS_BORINGSSL) #define HAVE_KEYLOG_CALLBACK #endif /* Whether SSL_CTX_set_ciphersuites is available. * OpenSSL: supported since 1.1.1 (commit a53b5be6a05) * BoringSSL: no * LibreSSL: no */ #if ((OPENSSL_VERSION_NUMBER >= 0x10101000L) && \ !defined(LIBRESSL_VERSION_NUMBER) && \ !defined(OPENSSL_IS_BORINGSSL)) #define HAVE_SSL_CTX_SET_CIPHERSUITES #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH #endif #if defined(LIBRESSL_VERSION_NUMBER) #define OSSL_PACKAGE "LibreSSL" #elif defined(OPENSSL_IS_BORINGSSL) #define OSSL_PACKAGE "BoringSSL" #else #define OSSL_PACKAGE "OpenSSL" #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* up2date versions of OpenSSL maintain the default reasonably secure without * breaking compatibility, so it is better not to override the default by curl */ #define DEFAULT_CIPHER_SELECTION NULL #else /* ... but it is not the case with old versions of OpenSSL */ #define DEFAULT_CIPHER_SELECTION \ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" #endif #define ENABLE_SSLKEYLOGFILE #ifdef ENABLE_SSLKEYLOGFILE typedef struct ssl_tap_state { int master_key_length; unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; unsigned char client_random[SSL3_RANDOM_SIZE]; } ssl_tap_state_t; #endif /* ENABLE_SSLKEYLOGFILE */ struct ssl_backend_data { /* these ones requires specific SSL-types */ SSL_CTX* ctx; SSL* handle; X509* server_cert; #ifdef ENABLE_SSLKEYLOGFILE /* tap_state holds the last seen master key if we're logging them */ ssl_tap_state_t tap_state; #endif }; #define BACKEND connssl->backend /* * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have * an infinite length), but must be large enough to provide enough * entropy to properly seed OpenSSL's PRNG. */ #define RAND_LOAD_LENGTH 1024 #ifdef ENABLE_SSLKEYLOGFILE /* The fp for the open SSLKEYLOGFILE, or NULL if not open */ static FILE *keylog_file_fp; #ifdef HAVE_KEYLOG_CALLBACK static void ossl_keylog_callback(const SSL *ssl, const char *line) { (void)ssl; /* Using fputs here instead of fprintf since libcurl's fprintf replacement may not be thread-safe. */ if(keylog_file_fp && line && *line) { char stackbuf[256]; char *buf; size_t linelen = strlen(line); if(linelen <= sizeof(stackbuf) - 2) buf = stackbuf; else { buf = malloc(linelen + 2); if(!buf) return; } memcpy(buf, line, linelen); buf[linelen] = '\n'; buf[linelen + 1] = '\0'; fputs(buf, keylog_file_fp); if(buf != stackbuf) free(buf); } } #else #define KEYLOG_PREFIX "CLIENT_RANDOM " #define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1) /* * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL * being used doesn't have native support for doing that. */ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) { const char *hex = "0123456789ABCDEF"; int pos, i; char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 + 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1]; const SSL_SESSION *session = SSL_get_session(ssl); unsigned char client_random[SSL3_RANDOM_SIZE]; unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; int master_key_length = 0; if(!session || !keylog_file_fp) return; #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !(defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER < 0x20700000L) /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that * we have a valid SSL context if we have a non-NULL session. */ SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); master_key_length = (int) SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); #else if(ssl->s3 && session->master_key_length > 0) { master_key_length = session->master_key_length; memcpy(master_key, session->master_key, session->master_key_length); memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE); } #endif if(master_key_length <= 0) return; /* Skip writing keys if there is no key or it did not change. */ if(state->master_key_length == master_key_length && !memcmp(state->master_key, master_key, master_key_length) && !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) { return; } state->master_key_length = master_key_length; memcpy(state->master_key, master_key, master_key_length); memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE); memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN); pos = KEYLOG_PREFIX_LEN; /* Client Random for SSLv3/TLS */ for(i = 0; i < SSL3_RANDOM_SIZE; i++) { line[pos++] = hex[client_random[i] >> 4]; line[pos++] = hex[client_random[i] & 0xF]; } line[pos++] = ' '; /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */ for(i = 0; i < master_key_length; i++) { line[pos++] = hex[master_key[i] >> 4]; line[pos++] = hex[master_key[i] & 0xF]; } line[pos++] = '\n'; line[pos] = '\0'; /* Using fputs here instead of fprintf since libcurl's fprintf replacement may not be thread-safe. */ fputs(line, keylog_file_fp); } #endif /* !HAVE_KEYLOG_CALLBACK */ #endif /* ENABLE_SSLKEYLOGFILE */ static const char *SSL_ERROR_to_str(int err) { switch(err) { case SSL_ERROR_NONE: return "SSL_ERROR_NONE"; case SSL_ERROR_SSL: return "SSL_ERROR_SSL"; case SSL_ERROR_WANT_READ: return "SSL_ERROR_WANT_READ"; case SSL_ERROR_WANT_WRITE: return "SSL_ERROR_WANT_WRITE"; case SSL_ERROR_WANT_X509_LOOKUP: return "SSL_ERROR_WANT_X509_LOOKUP"; case SSL_ERROR_SYSCALL: return "SSL_ERROR_SYSCALL"; case SSL_ERROR_ZERO_RETURN: return "SSL_ERROR_ZERO_RETURN"; case SSL_ERROR_WANT_CONNECT: return "SSL_ERROR_WANT_CONNECT"; case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; #if defined(SSL_ERROR_WANT_ASYNC) case SSL_ERROR_WANT_ASYNC: return "SSL_ERROR_WANT_ASYNC"; #endif #if defined(SSL_ERROR_WANT_ASYNC_JOB) case SSL_ERROR_WANT_ASYNC_JOB: return "SSL_ERROR_WANT_ASYNC_JOB"; #endif #if defined(SSL_ERROR_WANT_EARLY) case SSL_ERROR_WANT_EARLY: return "SSL_ERROR_WANT_EARLY"; #endif default: return "SSL_ERROR unknown"; } } /* Return error string for last OpenSSL error */ static char *ossl_strerror(unsigned long error, char *buf, size_t size) { if(size) *buf = '\0'; #ifdef OPENSSL_IS_BORINGSSL ERR_error_string_n((uint32_t)error, buf, size); #else ERR_error_string_n(error, buf, size); #endif if(size > 1 && !*buf) { strncpy(buf, (error ? "Unknown error" : "No error"), size); buf[size - 1] = '\0'; } return buf; } /* Return an extra data index for the connection data. * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). */ static int ossl_get_ssl_conn_index(void) { static int ssl_ex_data_conn_index = -1; if(ssl_ex_data_conn_index < 0) { ssl_ex_data_conn_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); } return ssl_ex_data_conn_index; } /* Return an extra data index for the sockindex. * This index can be used with SSL_get_ex_data() and SSL_set_ex_data(). */ static int ossl_get_ssl_sockindex_index(void) { static int ssl_ex_data_sockindex_index = -1; if(ssl_ex_data_sockindex_index < 0) { ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); } return ssl_ex_data_sockindex_index; } static int passwd_callback(char *buf, int num, int encrypting, void *global_passwd) { DEBUGASSERT(0 == encrypting); if(!encrypting) { int klen = curlx_uztosi(strlen((char *)global_passwd)); if(num > klen) { memcpy(buf, global_passwd, klen + 1); return klen; } } return 0; } /* * rand_enough() returns TRUE if we have seeded the random engine properly. */ static bool rand_enough(void) { return (0 != RAND_status()) ? TRUE : FALSE; } static CURLcode Curl_ossl_seed(struct Curl_easy *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ static bool ssl_seeded = FALSE; char fname[256]; if(ssl_seeded) return CURLE_OK; if(rand_enough()) { /* OpenSSL 1.1.0+ will return here */ ssl_seeded = TRUE; return CURLE_OK; } #ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells us to! */ if(data->set.str[STRING_SSL_RANDOM_FILE]) #define RANDOM_FILE "" /* doesn't matter won't be used */ #endif { /* let the option override the define */ RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? data->set.str[STRING_SSL_RANDOM_FILE]: RANDOM_FILE), RAND_LOAD_LENGTH); if(rand_enough()) return CURLE_OK; } #if defined(HAVE_RAND_EGD) /* only available in OpenSSL 0.9.5 and later */ /* EGD_SOCKET is set at configure time or not at all */ #ifndef EGD_SOCKET /* If we don't have the define set, we only do this if the egd-option is set */ if(data->set.str[STRING_SSL_EGDSOCKET]) #define EGD_SOCKET "" /* doesn't matter won't be used */ #endif { /* If there's an option and a define, the option overrides the define */ int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); if(-1 != ret) { if(rand_enough()) return CURLE_OK; } } #endif /* fallback to a custom seeding of the PRNG using a hash based on a current time */ do { unsigned char randb[64]; size_t len = sizeof(randb); size_t i, i_max; for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { struct curltime tv = Curl_now(); Curl_wait_ms(1); tv.tv_sec *= i + 1; tv.tv_usec *= (unsigned int)i + 2; tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) * (i + 3)) << 8; tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec + Curl_now().tv_usec) * (i + 4)) << 16; memcpy(&randb[i * sizeof(struct curltime)], &tv, sizeof(struct curltime)); } RAND_add(randb, (int)len, (double)len/2); } while(!rand_enough()); /* generates a default path for the random seed file */ fname[0] = 0; /* blank it first */ RAND_file_name(fname, sizeof(fname)); if(fname[0]) { /* we got a file name to try */ RAND_load_file(fname, RAND_LOAD_LENGTH); if(rand_enough()) return CURLE_OK; } infof(data, "libcurl is now using a weak random seed!\n"); return (rand_enough() ? CURLE_OK : CURLE_SSL_CONNECT_ERROR /* confusing error code */); } #ifndef SSL_FILETYPE_ENGINE #define SSL_FILETYPE_ENGINE 42 #endif #ifndef SSL_FILETYPE_PKCS12 #define SSL_FILETYPE_PKCS12 43 #endif static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; if(strcasecompare(type, "ENG")) return SSL_FILETYPE_ENGINE; if(strcasecompare(type, "P12")) return SSL_FILETYPE_PKCS12; return -1; } #ifdef USE_OPENSSL_ENGINE /* * Supply default password to the engine user interface conversation. * The password is passed by OpenSSL engine from ENGINE_load_private_key() * last argument to the ui and can be obtained by UI_get0_user_data(ui) here. */ static int ssl_ui_reader(UI *ui, UI_STRING *uis) { const char *password; switch(UI_get_string_type(uis)) { case UIT_PROMPT: case UIT_VERIFY: password = (const char *)UI_get0_user_data(ui); if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { UI_set_result(ui, uis, password); return 1; } default: break; } return (UI_method_get_reader(UI_OpenSSL()))(ui, uis); } /* * Suppress interactive request for a default password if available. */ static int ssl_ui_writer(UI *ui, UI_STRING *uis) { switch(UI_get_string_type(uis)) { case UIT_PROMPT: case UIT_VERIFY: if(UI_get0_user_data(ui) && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { return 1; } default: break; } return (UI_method_get_writer(UI_OpenSSL()))(ui, uis); } /* * Check if a given string is a PKCS#11 URI */ static bool is_pkcs11_uri(const char *string) { return (string && strncasecompare(string, "pkcs11:", 7)); } #endif static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine); static int cert_stuff(struct connectdata *conn, SSL_CTX* ctx, char *cert_file, const char *cert_type, char *key_file, const char *key_type, char *key_passwd) { struct Curl_easy *data = conn->data; char error_buffer[256]; bool check_privkey = TRUE; int file_type = do_file_type(cert_type); if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) { SSL *ssl; X509 *x509; int cert_done = 0; if(key_passwd) { /* set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { failf(data, "could not load PEM client certificate, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; } break; case SSL_FILETYPE_ASN1: /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but we use the case above for PEM so this can only be performed with ASN1 files. */ if(SSL_CTX_use_certificate_file(ctx, cert_file, file_type) != 1) { failf(data, "could not load ASN1 client certificate, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; } break; case SSL_FILETYPE_ENGINE: #if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) { /* Implicitly use pkcs11 engine if none was provided and the * cert_file is a PKCS#11 URI */ if(!data->state.engine) { if(is_pkcs11_uri(cert_file)) { if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) { return 0; } } } if(data->state.engine) { const char *cmd_name = "LOAD_CERT_CTRL"; struct { const char *cert_id; X509 *cert; } params; params.cert_id = cert_file; params.cert = NULL; /* Does the engine supports LOAD_CERT_CTRL ? */ if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, (void *)cmd_name, NULL)) { failf(data, "ssl engine does not support loading certificates"); return 0; } /* Load the certificate from the engine */ if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, 0, ¶ms, NULL, 1)) { failf(data, "ssl engine cannot load client cert with id" " '%s' [%s]", cert_file, ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); return 0; } if(!params.cert) { failf(data, "ssl engine didn't initialized the certificate " "properly."); return 0; } if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { failf(data, "unable to set client certificate"); X509_free(params.cert); return 0; } X509_free(params.cert); /* we don't need the handle any more... */ } else { failf(data, "crypto engine not set, can't load certificate"); return 0; } } break; #else failf(data, "file type ENG for certificate not implemented"); return 0; #endif case SSL_FILETYPE_PKCS12: { BIO *fp = NULL; PKCS12 *p12 = NULL; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; fp = BIO_new(BIO_s_file()); if(fp == NULL) { failf(data, "BIO_new return NULL, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; } if(BIO_read_filename(fp, cert_file) <= 0) { failf(data, "could not open PKCS12 file '%s'", cert_file); BIO_free(fp); return 0; } p12 = d2i_PKCS12_bio(fp, NULL); BIO_free(fp); if(!p12) { failf(data, "error reading PKCS12 file '%s'", cert_file); return 0; } PKCS12_PBE_add(); if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) { failf(data, "could not parse PKCS12 file, check password, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); PKCS12_free(p12); return 0; } PKCS12_free(p12); if(SSL_CTX_use_certificate(ctx, x509) != 1) { failf(data, "could not load PKCS12 client certificate, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); goto fail; } if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { failf(data, "unable to use private key from PKCS12 file '%s'", cert_file); goto fail; } if(!SSL_CTX_check_private_key (ctx)) { failf(data, "private key from PKCS12 file '%s' " "does not match certificate in same file", cert_file); goto fail; } /* Set Certificate Verification chain */ if(ca) { while(sk_X509_num(ca)) { /* * Note that sk_X509_pop() is used below to make sure the cert is * removed from the stack properly before getting passed to * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously * we used sk_X509_value() instead, but then we'd clean it in the * subsequent sk_X509_pop_free() call. */ X509 *x = sk_X509_pop(ca); if(!SSL_CTX_add_client_CA(ctx, x)) { X509_free(x); failf(data, "cannot add certificate to client CA list"); goto fail; } if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { X509_free(x); failf(data, "cannot add certificate to certificate chain"); goto fail; } } } cert_done = 1; fail: EVP_PKEY_free(pri); X509_free(x509); #ifdef USE_AMISSL sk_X509_pop_free(ca, Curl_amiga_X509_free); #else sk_X509_pop_free(ca, X509_free); #endif if(!cert_done) return 0; /* failure! */ break; } default: failf(data, "not supported file type '%s' for certificate", cert_type); return 0; } if(!key_file) key_file = cert_file; else file_type = do_file_type(key_type); switch(file_type) { case SSL_FILETYPE_PEM: if(cert_done) break; /* FALLTHROUGH */ case SSL_FILETYPE_ASN1: if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { failf(data, "unable to set private key file: '%s' type %s", key_file, key_type?key_type:"PEM"); return 0; } break; case SSL_FILETYPE_ENGINE: #ifdef USE_OPENSSL_ENGINE { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; /* Implicitly use pkcs11 engine if none was provided and the * key_file is a PKCS#11 URI */ if(!data->state.engine) { if(is_pkcs11_uri(key_file)) { if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) { return 0; } } } if(data->state.engine) { UI_METHOD *ui_method = UI_create_method((char *)"curl user interface"); if(!ui_method) { failf(data, "unable do create " OSSL_PACKAGE " user-interface method"); return 0; } UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); UI_method_set_reader(ui_method, ssl_ui_reader); UI_method_set_writer(ui_method, ssl_ui_writer); /* the typecast below was added to please mingw32 */ priv_key = (EVP_PKEY *) ENGINE_load_private_key(data->state.engine, key_file, ui_method, key_passwd); UI_destroy_method(ui_method); if(!priv_key) { failf(data, "failed to load private key from crypto engine"); return 0; } if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { failf(data, "unable to set private key"); EVP_PKEY_free(priv_key); return 0; } EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ } else { failf(data, "crypto engine not set, can't load private key"); return 0; } } break; #else failf(data, "file type ENG for private key not supported"); return 0; #endif case SSL_FILETYPE_PKCS12: if(!cert_done) { failf(data, "file type P12 for private key not supported"); return 0; } break; default: failf(data, "not supported file type for private key"); return 0; } ssl = SSL_new(ctx); if(!ssl) { failf(data, "unable to create an SSL structure"); return 0; } x509 = SSL_get_certificate(ssl); /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ if(x509) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); EVP_PKEY_free(pktmp); } #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) { /* If RSA is used, don't check the private key if its flags indicate * it doesn't support it. */ EVP_PKEY *priv_key = SSL_get_privatekey(ssl); int pktype; #ifdef HAVE_OPAQUE_EVP_PKEY pktype = EVP_PKEY_id(priv_key); #else pktype = priv_key->type; #endif if(pktype == EVP_PKEY_RSA) { RSA *rsa = EVP_PKEY_get1_RSA(priv_key); if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK) check_privkey = FALSE; RSA_free(rsa); /* Decrement reference count */ } } #endif SSL_free(ssl); /* If we are using DSA, we can copy the parameters from * the private key */ if(check_privkey == TRUE) { /* Now we know that a key and cert have been set against * the SSL context */ if(!SSL_CTX_check_private_key(ctx)) { failf(data, "Private key does not match the certificate public key"); return 0; } } } return 1; } /* returns non-zero on failure */ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) { #if 0 return X509_NAME_oneline(a, buf, size); #else BIO *bio_out = BIO_new(BIO_s_mem()); BUF_MEM *biomem; int rc; if(!bio_out) return 1; /* alloc failed! */ rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); BIO_get_mem_ptr(bio_out, &biomem); if((size_t)biomem->length < size) size = biomem->length; else size--; /* don't overwrite the buffer end */ memcpy(buf, biomem->data, size); buf[size] = 0; BIO_free(bio_out); return !rc; #endif } /** * Global SSL init * * @retval 0 error initializing SSL * @retval 1 SSL initialized successfully */ static int Curl_ossl_init(void) { #ifdef ENABLE_SSLKEYLOGFILE char *keylog_file_name; #endif OPENSSL_load_builtin_modules(); #ifdef USE_OPENSSL_ENGINE ENGINE_load_builtin_engines(); #endif /* CONF_MFLAGS_DEFAULT_SECTION was introduced some time between 0.9.8b and 0.9.8e */ #ifndef CONF_MFLAGS_DEFAULT_SECTION #define CONF_MFLAGS_DEFAULT_SECTION 0x0 #endif #ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG CONF_modules_load_file(NULL, NULL, CONF_MFLAGS_DEFAULT_SECTION| CONF_MFLAGS_IGNORE_MISSING_FILE); #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ !defined(LIBRESSL_VERSION_NUMBER) /* OpenSSL 1.1.0+ takes care of initialization itself */ #else /* Lets get nice error messages */ SSL_load_error_strings(); /* Init the global ciphers and digests */ if(!SSLeay_add_ssl_algorithms()) return 0; OpenSSL_add_all_algorithms(); #endif #ifdef ENABLE_SSLKEYLOGFILE if(!keylog_file_fp) { keylog_file_name = curl_getenv("SSLKEYLOGFILE"); if(keylog_file_name) { keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); if(keylog_file_fp) { #ifdef WIN32 if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) #else if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) #endif { fclose(keylog_file_fp); keylog_file_fp = NULL; } } Curl_safefree(keylog_file_name); } } #endif /* Initialize the extra data indexes */ if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0) return 0; return 1; } /* Global cleanup */ static void Curl_ossl_cleanup(void) { #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ !defined(LIBRESSL_VERSION_NUMBER) /* OpenSSL 1.1 deprecates all these cleanup functions and turns them into no-ops in OpenSSL 1.0 compatibility mode */ #else /* Free ciphers and digests lists */ EVP_cleanup(); #ifdef USE_OPENSSL_ENGINE /* Free engine list */ ENGINE_cleanup(); #endif /* Free OpenSSL error strings */ ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ #ifdef HAVE_ERR_REMOVE_THREAD_STATE ERR_remove_thread_state(NULL); #else ERR_remove_state(0); #endif /* Free all memory allocated by all configuration modules */ CONF_modules_free(); #ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS SSL_COMP_free_compression_methods(); #endif #endif #ifdef ENABLE_SSLKEYLOGFILE if(keylog_file_fp) { fclose(keylog_file_fp); keylog_file_fp = NULL; } #endif } /* * This function is used to determine connection status. * * Return codes: * 1 means the connection is still in place * 0 means the connection has been closed * -1 means the connection status is unknown */ static int Curl_ossl_check_cxn(struct connectdata *conn) { /* SSL_peek takes data out of the raw recv buffer without peeking so we use recv MSG_PEEK instead. Bug #795 */ #ifdef MSG_PEEK char buf; ssize_t nread; nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); if(nread == 0) return 0; /* connection has been closed */ if(nread == 1) return 1; /* connection still in place */ else if(nread == -1) { int err = SOCKERRNO; if(err == EINPROGRESS || #if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) err == EAGAIN || #endif err == EWOULDBLOCK) return 1; /* connection still in place */ if(err == ECONNRESET || #ifdef ECONNABORTED err == ECONNABORTED || #endif #ifdef ENETDOWN err == ENETDOWN || #endif #ifdef ENETRESET err == ENETRESET || #endif #ifdef ESHUTDOWN err == ESHUTDOWN || #endif #ifdef ETIMEDOUT err == ETIMEDOUT || #endif err == ENOTCONN) return 0; /* connection has been closed */ } #endif return -1; /* connection status unknown */ } /* Selects an OpenSSL crypto engine */ static CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) { #ifdef USE_OPENSSL_ENGINE ENGINE *e; #if OPENSSL_VERSION_NUMBER >= 0x00909000L e = ENGINE_by_id(engine); #else /* avoid memory leak */ for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { const char *e_id = ENGINE_get_id(e); if(!strcmp(engine, e_id)) break; } #endif if(!e) { failf(data, "SSL Engine '%s' not found", engine); return CURLE_SSL_ENGINE_NOTFOUND; } if(data->state.engine) { ENGINE_finish(data->state.engine); ENGINE_free(data->state.engine); data->state.engine = NULL; } if(!ENGINE_init(e)) { char buf[256]; ENGINE_free(e); failf(data, "Failed to initialise SSL Engine '%s':\n%s", engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); return CURLE_SSL_ENGINE_INITFAILED; } data->state.engine = e; return CURLE_OK; #else (void)engine; failf(data, "SSL Engine not supported"); return CURLE_SSL_ENGINE_NOTFOUND; #endif } /* Sets engine as default for all SSL operations */ static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) { #ifdef USE_OPENSSL_ENGINE if(data->state.engine) { if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) { infof(data, "set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine)); } else { failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine)); return CURLE_SSL_ENGINE_SETFAILED; } } #else (void) data; #endif return CURLE_OK; } /* Return list of OpenSSL crypto engine names. */ static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) { struct curl_slist *list = NULL; #ifdef USE_OPENSSL_ENGINE struct curl_slist *beg; ENGINE *e; for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { beg = curl_slist_append(list, ENGINE_get_id(e)); if(!beg) { curl_slist_free_all(list); return NULL; } list = beg; } #endif (void) data; return list; } static void ossl_close(struct ssl_connect_data *connssl) { if(BACKEND->handle) { (void)SSL_shutdown(BACKEND->handle); SSL_set_connect_state(BACKEND->handle); SSL_free(BACKEND->handle); BACKEND->handle = NULL; } if(BACKEND->ctx) { SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = NULL; } } /* * This function is called when an SSL connection is closed. */ static void Curl_ossl_close(struct connectdata *conn, int sockindex) { ossl_close(&conn->ssl[sockindex]); ossl_close(&conn->proxy_ssl[sockindex]); } /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) */ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; char buf[256]; /* We will use this for the OpenSSL error buffer, so it has to be at least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; int err; bool done = FALSE; #ifndef CURL_DISABLE_FTP /* This has only been tested on the proftpd server, and the mod_tls code sends a close notify alert without waiting for a close notify alert in response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) (void)SSL_shutdown(BACKEND->handle); #endif if(BACKEND->handle) { buffsize = (int)sizeof(buf); while(!done) { int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); /* Something to read, let's do it and hope that it is the close notify alert from the server */ nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); err = SSL_get_error(BACKEND->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ case SSL_ERROR_ZERO_RETURN: /* no more data */ /* This is the expected response. There was no data but only the close notify alert */ done = TRUE; break; case SSL_ERROR_WANT_READ: /* there's data pending, re-invoke SSL_read() */ infof(data, "SSL_ERROR_WANT_READ\n"); break; case SSL_ERROR_WANT_WRITE: /* SSL wants a write. Really odd. Let's bail out. */ infof(data, "SSL_ERROR_WANT_WRITE\n"); done = TRUE; break; default: /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d", (sslerror ? ossl_strerror(sslerror, buf, sizeof(buf)) : SSL_ERROR_to_str(err)), SOCKERRNO); done = TRUE; break; } } else if(0 == what) { /* timeout */ failf(data, "SSL shutdown timeout"); done = TRUE; } else { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); retval = -1; done = TRUE; } } /* while()-loop for the select() */ if(data->set.verbose) { #ifdef HAVE_SSL_GET_SHUTDOWN switch(SSL_get_shutdown(BACKEND->handle)) { case SSL_SENT_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); break; case SSL_RECEIVED_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); break; case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" "SSL_RECEIVED__SHUTDOWN\n"); break; } #endif } SSL_free(BACKEND->handle); BACKEND->handle = NULL; } return retval; } static void Curl_ossl_session_free(void *ptr) { /* free the ID */ SSL_SESSION_free(ptr); } /* * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ static void Curl_ossl_close_all(struct Curl_easy *data) { #ifdef USE_OPENSSL_ENGINE if(data->state.engine) { ENGINE_finish(data->state.engine); ENGINE_free(data->state.engine); data->state.engine = NULL; } #else (void)data; #endif #if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ defined(HAVE_ERR_REMOVE_THREAD_STATE) /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread so we need to clean it here in case the thread will be killed. All OpenSSL code should extract the error in association with the error so clearing this queue here should be harmless at worst. */ ERR_remove_thread_state(NULL); #endif } /* ====================================================== */ /* * Match subjectAltName against the host name. This requires a conversion * in CURL_DOES_CONVERSIONS builds. */ static bool subj_alt_hostcheck(struct Curl_easy *data, const char *match_pattern, const char *hostname, const char *dispname) #ifdef CURL_DOES_CONVERSIONS { bool res = FALSE; /* Curl_cert_hostcheck uses host encoding, but we get ASCII from OpenSSl. */ char *match_pattern2 = strdup(match_pattern); if(match_pattern2) { if(Curl_convert_from_network(data, match_pattern2, strlen(match_pattern2)) == CURLE_OK) { if(Curl_cert_hostcheck(match_pattern2, hostname)) { res = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", dispname, match_pattern2); } } free(match_pattern2); } else { failf(data, "SSL: out of memory when allocating temporary for subjectAltName"); } return res; } #else { #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)dispname; (void)data; #endif if(Curl_cert_hostcheck(match_pattern, hostname)) { infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", dispname, match_pattern); return TRUE; } return FALSE; } #endif /* Quote from RFC2818 section 3.1 "Server Identity" If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. Matching is performed using the matching rules specified by [RFC2459]. If more than one identity of a given type is present in the certificate (e.g., more than one dNSName name, a match in any one of the set is considered acceptable.) Names may contain the wildcard character * which is considered to match any single domain name component or component fragment. E.g., *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com but not bar.com. In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI. */ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) { bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ size_t addrlen = 0; struct Curl_easy *data = conn->data; STACK_OF(GENERAL_NAME) *altnames; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const char * const dispname = SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in6_addr); } else #endif if(Curl_inet_pton(AF_INET, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in_addr); } /* get a "list" of alternative names */ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); if(altnames) { #ifdef OPENSSL_IS_BORINGSSL size_t numalts; size_t i; #else int numalts; int i; #endif bool dnsmatched = FALSE; bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); /* loop through all alternatives - until a dnsmatch */ for(i = 0; (i < numalts) && !dnsmatched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); if(check->type == GEN_DNS) dNSName = TRUE; else if(check->type == GEN_IPADD) iPAddress = TRUE; /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); switch(target) { case GEN_DNS: /* name/pattern comparison */ /* The OpenSSL man page explicitly says: "In general it cannot be assumed that the data returned by ASN1_STRING_data() is null terminated or does not contain embedded nulls." But also that "The actual format of the data will depend on the actual string type itself: for example for an IA5String the data will be ASCII" It has been however verified that in 0.9.6 and 0.9.7, IA5String is always zero-terminated. */ if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ subj_alt_hostcheck(data, altptr, hostname, dispname)) { dnsmatched = TRUE; } break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { ipmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's IP address!\n", dispname); } break; } } } GENERAL_NAMES_free(altnames); if(dnsmatched || ipmatched) matched = TRUE; } if(matched) /* an alternative name matched */ ; else if(dNSName || iPAddress) { infof(data, " subjectAltName does not match %s\n", dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { /* we have to look to the last occurrence of a commonName in the distinguished one to get the most significant one. */ int j, i = -1; /* The following is done because of a bug in 0.9.6b */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; X509_NAME *name = X509_get_subject_name(server_cert); if(name) while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) i = j; /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, UTF8 etc. */ if(i >= 0) { ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input is already UTF-8 encoded. We check for this case and copy the raw string manually to avoid the problem. This code can be made conditional in the future when OpenSSL has been fixed. */ if(tmp) { if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { j = ASN1_STRING_length(tmp); if(j >= 0) { peer_CN = OPENSSL_malloc(j + 1); if(peer_CN) { memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); peer_CN[j] = '\0'; } } } else /* not a UTF8 name */ j = ASN1_STRING_to_UTF8(&peer_CN, tmp); if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) { /* there was a terminating zero before the end of string, this cannot match and we return failure! */ failf(data, "SSL: illegal cert name field"); result = CURLE_PEER_FAILED_VERIFICATION; } } } if(peer_CN == nulstr) peer_CN = NULL; else { /* convert peer_CN from UTF8 */ CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN, strlen((char *)peer_CN)); /* Curl_convert_from_utf8 calls failf if unsuccessful */ if(rc) { OPENSSL_free(peer_CN); return rc; } } if(result) /* error already detected, pass through */ ; else if(!peer_CN) { failf(data, "SSL: unable to obtain common name from peer certificate"); result = CURLE_PEER_FAILED_VERIFICATION; } else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { failf(data, "SSL: certificate subject name '%s' does not match " "target host name '%s'", peer_CN, dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, " common name: %s (matched)\n", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); } return result; } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) static CURLcode verifystatus(struct connectdata *conn, struct ssl_connect_data *connssl) { int i, ocsp_status; unsigned char *status; const unsigned char *p; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status); if(!status) { failf(data, "No OCSP response received"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } p = status; rsp = d2i_OCSP_RESPONSE(NULL, &p, len); if(!rsp) { failf(data, "Invalid OCSP response"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } ocsp_status = OCSP_response_status(rsp); if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { failf(data, "Invalid OCSP response status: %s (%d)", OCSP_response_status_str(ocsp_status), ocsp_status); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } br = OCSP_response_get1_basic(rsp); if(!br) { failf(data, "Invalid OCSP response"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } ch = SSL_get_peer_cert_chain(BACKEND->handle); st = SSL_CTX_get_cert_store(BACKEND->ctx); #if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \ (defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER <= 0x2040200fL)) /* The authorized responder cert in the OCSP response MUST be signed by the peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert, no problem, but if it's an intermediate cert OpenSSL has a bug where it expects this issuer to be present in the chain embedded in the OCSP response. So we add it if necessary. */ /* First make sure the peer cert chain includes both a peer and an issuer, and the OCSP response contains a responder cert. */ if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) { X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1); /* Find issuer of responder cert and add it to the OCSP response chain */ for(i = 0; i < sk_X509_num(ch); i++) { X509 *issuer = sk_X509_value(ch, i); if(X509_check_issued(issuer, responder) == X509_V_OK) { if(!OCSP_basic_add1_cert(br, issuer)) { failf(data, "Could not add issuer cert to OCSP response"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } } } } #endif if(OCSP_basic_verify(br, ch, st, 0) <= 0) { failf(data, "OCSP response verification failed"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } for(i = 0; i < OCSP_resp_count(br); i++) { int cert_status, crl_reason; OCSP_SINGLERESP *single = NULL; ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; single = OCSP_resp_get0(br, i); if(!single) continue; cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, &thisupd, &nextupd); if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { failf(data, "OCSP response has expired"); result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } infof(data, "SSL certificate status: %s (%d)\n", OCSP_cert_status_str(cert_status), cert_status); switch(cert_status) { case V_OCSP_CERTSTATUS_GOOD: break; case V_OCSP_CERTSTATUS_REVOKED: result = CURLE_SSL_INVALIDCERTSTATUS; failf(data, "SSL certificate revocation reason: %s (%d)", OCSP_crl_reason_str(crl_reason), crl_reason); goto end; case V_OCSP_CERTSTATUS_UNKNOWN: result = CURLE_SSL_INVALIDCERTSTATUS; goto end; } } end: if(br) OCSP_BASICRESP_free(br); OCSP_RESPONSE_free(rsp); return result; } #endif #endif /* USE_OPENSSL */ /* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions and thus this cannot be done there. */ #ifdef SSL_CTRL_SET_MSG_CALLBACK static const char *ssl_msg_type(int ssl_ver, int msg) { #ifdef SSL2_VERSION_MAJOR if(ssl_ver == SSL2_VERSION_MAJOR) { switch(msg) { case SSL2_MT_ERROR: return "Error"; case SSL2_MT_CLIENT_HELLO: return "Client hello"; case SSL2_MT_CLIENT_MASTER_KEY: return "Client key"; case SSL2_MT_CLIENT_FINISHED: return "Client finished"; case SSL2_MT_SERVER_HELLO: return "Server hello"; case SSL2_MT_SERVER_VERIFY: return "Server verify"; case SSL2_MT_SERVER_FINISHED: return "Server finished"; case SSL2_MT_REQUEST_CERTIFICATE: return "Request CERT"; case SSL2_MT_CLIENT_CERTIFICATE: return "Client CERT"; } } else #endif if(ssl_ver == SSL3_VERSION_MAJOR) { switch(msg) { case SSL3_MT_HELLO_REQUEST: return "Hello request"; case SSL3_MT_CLIENT_HELLO: return "Client hello"; case SSL3_MT_SERVER_HELLO: return "Server hello"; #ifdef SSL3_MT_NEWSESSION_TICKET case SSL3_MT_NEWSESSION_TICKET: return "Newsession Ticket"; #endif case SSL3_MT_CERTIFICATE: return "Certificate"; case SSL3_MT_SERVER_KEY_EXCHANGE: return "Server key exchange"; case SSL3_MT_CLIENT_KEY_EXCHANGE: return "Client key exchange"; case SSL3_MT_CERTIFICATE_REQUEST: return "Request CERT"; case SSL3_MT_SERVER_DONE: return "Server finished"; case SSL3_MT_CERTIFICATE_VERIFY: return "CERT verify"; case SSL3_MT_FINISHED: return "Finished"; #ifdef SSL3_MT_CERTIFICATE_STATUS case SSL3_MT_CERTIFICATE_STATUS: return "Certificate Status"; #endif #ifdef SSL3_MT_ENCRYPTED_EXTENSIONS case SSL3_MT_ENCRYPTED_EXTENSIONS: return "Encrypted Extensions"; #endif #ifdef SSL3_MT_END_OF_EARLY_DATA case SSL3_MT_END_OF_EARLY_DATA: return "End of early data"; #endif #ifdef SSL3_MT_KEY_UPDATE case SSL3_MT_KEY_UPDATE: return "Key update"; #endif #ifdef SSL3_MT_NEXT_PROTO case SSL3_MT_NEXT_PROTO: return "Next protocol"; #endif #ifdef SSL3_MT_MESSAGE_HASH case SSL3_MT_MESSAGE_HASH: return "Message hash"; #endif } } return "Unknown"; } static const char *tls_rt_type(int type) { switch(type) { #ifdef SSL3_RT_HEADER case SSL3_RT_HEADER: return "TLS header"; #endif case SSL3_RT_CHANGE_CIPHER_SPEC: return "TLS change cipher"; case SSL3_RT_ALERT: return "TLS alert"; case SSL3_RT_HANDSHAKE: return "TLS handshake"; case SSL3_RT_APPLICATION_DATA: return "TLS app data"; default: return "TLS Unknown"; } } /* * Our callback from the SSL/TLS layers. */ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, const void *buf, size_t len, SSL *ssl, void *userp) { struct Curl_easy *data; char unknown[32]; const char *verstr = NULL; struct connectdata *conn = userp; if(!conn || !conn->data || !conn->data->set.fdebug || (direction != 0 && direction != 1)) return; data = conn->data; switch(ssl_ver) { #ifdef SSL2_VERSION /* removed in recent versions */ case SSL2_VERSION: verstr = "SSLv2"; break; #endif #ifdef SSL3_VERSION case SSL3_VERSION: verstr = "SSLv3"; break; #endif case TLS1_VERSION: verstr = "TLSv1.0"; break; #ifdef TLS1_1_VERSION case TLS1_1_VERSION: verstr = "TLSv1.1"; break; #endif #ifdef TLS1_2_VERSION case TLS1_2_VERSION: verstr = "TLSv1.2"; break; #endif #ifdef TLS1_3_VERSION case TLS1_3_VERSION: verstr = "TLSv1.3"; break; #endif case 0: break; default: msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); verstr = unknown; break; } /* Log progress for interesting records only (like Handshake or Alert), skip * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0). * For TLS 1.3, skip notification of the decrypted inner Content Type. */ if(ssl_ver #ifdef SSL3_RT_INNER_CONTENT_TYPE && content_type != SSL3_RT_INNER_CONTENT_TYPE #endif ) { const char *msg_name, *tls_rt_name; char ssl_buf[1024]; int msg_type, txt_len; /* the info given when the version is zero is not that useful for us */ ssl_ver >>= 8; /* check the upper 8 bits only below */ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL * always pass-up content-type as 0. But the interesting message-type * is at 'buf[0]'. */ if(ssl_ver == SSL3_VERSION_MAJOR && content_type) tls_rt_name = tls_rt_type(content_type); else tls_rt_name = ""; if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) { msg_type = *(char *)buf; msg_name = "Change cipher spec"; } else if(content_type == SSL3_RT_ALERT) { msg_type = (((char *)buf)[0] << 8) + ((char *)buf)[1]; msg_name = SSL_alert_desc_string_long(msg_type); } else { msg_type = *(char *)buf; msg_name = ssl_msg_type(ssl_ver, msg_type); } txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", verstr, direction?"OUT":"IN", tls_rt_name, msg_name, msg_type); if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) { Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len); } } Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : CURLINFO_SSL_DATA_IN, (char *)buf, len); (void) ssl; } #endif #ifdef USE_OPENSSL /* ====================================================== */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME # define use_sni(x) sni = (x) #else # define use_sni(x) Curl_nop_stmt #endif /* Check for OpenSSL 1.0.2 which has ALPN support. */ #undef HAS_ALPN #if OPENSSL_VERSION_NUMBER >= 0x10002000L \ && !defined(OPENSSL_NO_TLSEXT) # define HAS_ALPN 1 #endif /* Check for OpenSSL 1.0.1 which has NPN support. */ #undef HAS_NPN #if OPENSSL_VERSION_NUMBER >= 0x10001000L \ && !defined(OPENSSL_NO_TLSEXT) \ && !defined(OPENSSL_NO_NEXTPROTONEG) # define HAS_NPN 1 #endif #ifdef HAS_NPN /* * in is a list of length prefixed strings. this function has to select * the protocol we want to use from the list and write its string into out. */ static int select_next_protocol(unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, const char *key, unsigned int keylen) { unsigned int i; for(i = 0; i + keylen <= inlen; i += in[i] + 1) { if(memcmp(&in[i + 1], key, keylen) == 0) { *out = (unsigned char *) &in[i + 1]; *outlen = in[i]; return 0; } } return -1; } static int select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { struct connectdata *conn = (struct connectdata*) arg; (void)ssl; #ifdef USE_NGHTTP2 if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN)) { infof(conn->data, "NPN, negotiated HTTP2 (%s)\n", NGHTTP2_PROTO_VERSION_ID); conn->negnpn = CURL_HTTP_VERSION_2; return SSL_TLSEXT_ERR_OK; } #endif if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { infof(conn->data, "NPN, negotiated HTTP1.1\n"); conn->negnpn = CURL_HTTP_VERSION_1_1; return SSL_TLSEXT_ERR_OK; } infof(conn->data, "NPN, no overlap, use HTTP1.1\n"); *out = (unsigned char *)ALPN_HTTP_1_1; *outlen = ALPN_HTTP_1_1_LENGTH; conn->negnpn = CURL_HTTP_VERSION_1_1; return SSL_TLSEXT_ERR_OK; } #endif /* HAS_NPN */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static const char * get_ssl_version_txt(SSL *ssl) { if(!ssl) return ""; switch(SSL_version(ssl)) { #ifdef TLS1_3_VERSION case TLS1_3_VERSION: return "TLSv1.3"; #endif #if OPENSSL_VERSION_NUMBER >= 0x1000100FL case TLS1_2_VERSION: return "TLSv1.2"; case TLS1_1_VERSION: return "TLSv1.1"; #endif case TLS1_VERSION: return "TLSv1.0"; case SSL3_VERSION: return "SSLv3"; case SSL2_VERSION: return "SSLv2"; } return "unknown"; } #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ static CURLcode set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) { /* first, TLS min version... */ long curl_ssl_version_min = SSL_CONN_CONFIG(version); long curl_ssl_version_max; /* convert cURL min SSL version option to OpenSSL constant */ #if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER) uint16_t ossl_ssl_version_min = 0; uint16_t ossl_ssl_version_max = 0; #else long ossl_ssl_version_min = 0; long ossl_ssl_version_max = 0; #endif switch(curl_ssl_version_min) { case CURL_SSLVERSION_TLSv1: /* TLS 1.x */ case CURL_SSLVERSION_TLSv1_0: ossl_ssl_version_min = TLS1_VERSION; break; case CURL_SSLVERSION_TLSv1_1: ossl_ssl_version_min = TLS1_1_VERSION; break; case CURL_SSLVERSION_TLSv1_2: ossl_ssl_version_min = TLS1_2_VERSION; break; #ifdef TLS1_3_VERSION case CURL_SSLVERSION_TLSv1_3: ossl_ssl_version_min = TLS1_3_VERSION; break; #endif } /* CURL_SSLVERSION_DEFAULT means that no option was selected. We don't want to pass 0 to SSL_CTX_set_min_proto_version as it would enable all versions down to the lowest supported by the library. So we skip this, and stay with the OS default */ if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) { if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) { return CURLE_SSL_CONNECT_ERROR; } } /* ... then, TLS max version */ curl_ssl_version_max = SSL_CONN_CONFIG(version_max); /* convert cURL max SSL version option to OpenSSL constant */ switch(curl_ssl_version_max) { case CURL_SSLVERSION_MAX_TLSv1_0: ossl_ssl_version_max = TLS1_VERSION; break; case CURL_SSLVERSION_MAX_TLSv1_1: ossl_ssl_version_max = TLS1_1_VERSION; break; case CURL_SSLVERSION_MAX_TLSv1_2: ossl_ssl_version_max = TLS1_2_VERSION; break; #ifdef TLS1_3_VERSION case CURL_SSLVERSION_MAX_TLSv1_3: ossl_ssl_version_max = TLS1_3_VERSION; break; #endif case CURL_SSLVERSION_MAX_NONE: /* none selected */ case CURL_SSLVERSION_MAX_DEFAULT: /* max selected */ default: /* SSL_CTX_set_max_proto_version states that: setting the maximum to 0 will enable protocol versions up to the highest version supported by the library */ ossl_ssl_version_max = 0; break; } if(!SSL_CTX_set_max_proto_version(ctx, ossl_ssl_version_max)) { return CURLE_SSL_CONNECT_ERROR; } return CURLE_OK; } #endif #ifdef OPENSSL_IS_BORINGSSL typedef uint32_t ctx_option_t; #else typedef long ctx_option_t; #endif #if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */ static CURLcode set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, struct connectdata *conn, int sockindex) { #if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION) /* convoluted #if condition just to avoid compiler warnings on unused variable */ struct Curl_easy *data = conn->data; #endif long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); switch(ssl_version) { case CURL_SSLVERSION_TLSv1_3: #ifdef TLS1_3_VERSION { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION); *ctx_options |= SSL_OP_NO_TLSv1_2; } #else (void)sockindex; (void)ctx_options; failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); return CURLE_NOT_BUILT_IN; #endif /* FALLTHROUGH */ case CURL_SSLVERSION_TLSv1_2: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_1; #else failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); return CURLE_NOT_BUILT_IN; #endif /* FALLTHROUGH */ case CURL_SSLVERSION_TLSv1_1: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1; #else failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); return CURLE_NOT_BUILT_IN; #endif /* FALLTHROUGH */ case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1: break; } switch(ssl_version_max) { case CURL_SSLVERSION_MAX_TLSv1_0: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_1; #endif /* FALLTHROUGH */ case CURL_SSLVERSION_MAX_TLSv1_1: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_2; #endif /* FALLTHROUGH */ case CURL_SSLVERSION_MAX_TLSv1_2: #ifdef TLS1_3_VERSION *ctx_options |= SSL_OP_NO_TLSv1_3; #endif break; case CURL_SSLVERSION_MAX_TLSv1_3: #ifdef TLS1_3_VERSION break; #else failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); return CURLE_NOT_BUILT_IN; #endif } return CURLE_OK; } #endif /* The "new session" callback must return zero if the session can be removed * or non-zero if the session has been put into the session cache. */ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) { int res = 0; struct connectdata *conn; struct Curl_easy *data; int sockindex; curl_socket_t *sockindex_ptr; int connectdata_idx = ossl_get_ssl_conn_index(); int sockindex_idx = ossl_get_ssl_sockindex_index(); if(connectdata_idx < 0 || sockindex_idx < 0) return 0; conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx); if(!conn) return 0; data = conn->data; /* The sockindex has been stored as a pointer to an array element */ sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx); sockindex = (int)(sockindex_ptr - conn->sock); if(SSL_SET_OPTION(primary.sessionid)) { bool incache; void *old_ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)); if(incache) { if(old_ssl_sessionid != ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); Curl_ssl_delsessionid(conn, old_ssl_sessionid); incache = FALSE; } } if(!incache) { if(!Curl_ssl_addsessionid(conn, ssl_sessionid, 0 /* unknown size */, sockindex)) { /* the session has been put into the session cache */ res = 1; } else failf(data, "failed to store ssl session"); } Curl_ssl_sessionid_unlock(conn); } return res; } static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; char *ciphers; struct Curl_easy *data = conn->data; SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ctx_option_t ctx_options = 0; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME bool sni; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif #endif long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; const long int ssl_version = SSL_CONN_CONFIG(version); #ifdef USE_TLS_SRP const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); #endif char * const ssl_cert = SSL_SET_OPTION(cert); const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); char error_buffer[256]; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); /* Make funny stuff to get random input */ result = Curl_ossl_seed(data); if(result) return result; *certverifyresult = !X509_V_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ switch(ssl_version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: /* it will be handled later with the context options */ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) req_method = TLS_client_method(); #else req_method = SSLv23_client_method(); #endif use_sni(TRUE); break; case CURL_SSLVERSION_SSLv2: #ifdef OPENSSL_NO_SSL2 failf(data, OSSL_PACKAGE " was built without SSLv2 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv2_client_method(); use_sni(FALSE); break; #endif case CURL_SSLVERSION_SSLv3: #ifdef OPENSSL_NO_SSL3_METHOD failf(data, OSSL_PACKAGE " was built without SSLv3 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv3_client_method(); use_sni(FALSE); break; #endif default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } if(BACKEND->ctx) SSL_CTX_free(BACKEND->ctx); BACKEND->ctx = SSL_CTX_new(req_method); if(!BACKEND->ctx) { failf(data, "SSL: couldn't create a context: %s", ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); return CURLE_OUT_OF_MEMORY; } #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS); #endif #ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { /* the SSL trace callback is only used for verbose logging */ SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace); SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn); } #endif /* OpenSSL contains code to work-around lots of bugs and flaws in various SSL-implementations. SSL_CTX_set_options() is used to enabled those work-arounds. The man page for this option states that SSL_OP_ALL enables all the work-arounds and that "It is usually safe to use SSL_OP_ALL to enable the bug workaround options if compatibility with somewhat broken implementations is desired." The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to disable "rfc4507bis session ticket support". rfc4507bis was later turned into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 The enabled extension concerns the session management. I wonder how often libcurl stops a connection and then resumes a TLS session. also, sending the session data is some overhead. .I suggest that you just use your proposed patch (which explicitly disables TICKET). If someone writes an application with libcurl and openssl who wants to enable the feature, one can do this in the SSL callback. SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper interoperability with web server Netscape Enterprise Server 2.0.1 which was released back in 1996. Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate CVE-2010-4180 when using previous OpenSSL versions we no longer enable this option regardless of OpenSSL version and SSL_OP_ALL definition. OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to SSL_OP_ALL that _disables_ that work-around despite the fact that SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit must not be set. */ ctx_options = SSL_OP_ALL; #ifdef SSL_OP_NO_TICKET ctx_options |= SSL_OP_NO_TICKET; #endif #ifdef SSL_OP_NO_COMPRESSION ctx_options |= SSL_OP_NO_COMPRESSION; #endif #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG /* mitigate CVE-2010-4180 */ ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; #endif #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS /* unless the user explicitly ask to allow the protocol vulnerability we use the work-around */ if(!SSL_SET_OPTION(enable_beast)) ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; #endif switch(ssl_version) { /* "--sslv2" option means SSLv2 only, disable all others */ case CURL_SSLVERSION_SSLv2: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL2_VERSION); SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL2_VERSION); #else ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; # if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_TLSv1_1; ctx_options |= SSL_OP_NO_TLSv1_2; # ifdef TLS1_3_VERSION ctx_options |= SSL_OP_NO_TLSv1_3; # endif # endif #endif break; /* "--sslv3" option means SSLv3 only, disable all others */ case CURL_SSLVERSION_SSLv3: #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ SSL_CTX_set_min_proto_version(BACKEND->ctx, SSL3_VERSION); SSL_CTX_set_max_proto_version(BACKEND->ctx, SSL3_VERSION); #else ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_TLSv1; # if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_TLSv1_1; ctx_options |= SSL_OP_NO_TLSv1_2; # ifdef TLS1_3_VERSION ctx_options |= SSL_OP_NO_TLSv1_3; # endif # endif #endif break; /* "--tlsv" options mean TLS >= version */ case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */ case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */ case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */ case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */ case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */ /* asking for any TLS version as the minimum, means no SSL versions allowed */ ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ result = set_ssl_version_min_max(BACKEND->ctx, conn); #else result = set_ssl_version_min_max_legacy(&ctx_options, conn, sockindex); #endif if(result != CURLE_OK) return result; break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } SSL_CTX_set_options(BACKEND->ctx, ctx_options); #ifdef HAS_NPN if(conn->bits.tls_enable_npn) SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); cur += NGHTTP2_PROTO_VERSION_ID_LEN; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif protocols[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); /* expects length prefixed preference ordered list of protocols in wire * format */ SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur); } #endif if(ssl_cert || ssl_cert_type) { if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type, SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd))) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } ciphers = SSL_CONN_CONFIG(cipher_list); if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; if(ciphers) { if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) { failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } infof(data, "Cipher selection: %s\n", ciphers); } #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES { char *ciphers13 = SSL_CONN_CONFIG(cipher_list13); if(ciphers13) { if(!SSL_CTX_set_ciphersuites(BACKEND->ctx, ciphers13)) { failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); return CURLE_SSL_CIPHER; } infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13); } } #endif #ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH /* OpenSSL 1.1.1 requires clients to opt-in for PHA */ SSL_CTX_set_post_handshake_auth(BACKEND->ctx, 1); #endif #ifdef USE_TLS_SRP if(ssl_authtype == CURL_TLSAUTH_SRP) { char * const ssl_username = SSL_SET_OPTION(username); infof(data, "Using TLS-SRP username: %s\n", ssl_username); if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) { failf(data, "failed setting SRP password"); return CURLE_BAD_FUNCTION_ARGUMENT; } if(!SSL_CONN_CONFIG(cipher_list)) { infof(data, "Setting cipher list SRP\n"); if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) { failf(data, "failed setting SRP cipher list"); return CURLE_SSL_CIPHER; } } } #endif if(ssl_cafile || ssl_capath) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) { if(verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", ssl_cafile ? ssl_cafile : "none", ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," " continuing anyway:\n"); } else { /* Everything is fine. */ infof(data, "successfully set certificate verify locations:\n"); } infof(data, " CAfile: %s\n" " CApath: %s\n", ssl_cafile ? ssl_cafile : "none", ssl_capath ? ssl_capath : "none"); } #ifdef CURL_CA_FALLBACK else if(verifypeer) { /* verifying the peer without any CA certificates won't work so use openssl's built in default as fallback */ SSL_CTX_set_default_verify_paths(BACKEND->ctx); } #endif if(ssl_crlfile) { /* tell SSL where to find CRL file that is used to check certificate * revocation */ lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(BACKEND->ctx), X509_LOOKUP_file()); if(!lookup || (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { failf(data, "error loading CRL file: %s", ssl_crlfile); return CURLE_SSL_CRL_BADFILE; } /* Everything is fine. */ infof(data, "successfully load CRL file:\n"); X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); infof(data, " CRLfile: %s\n", ssl_crlfile); } if(verifypeer) { /* Try building a chain using issuers in the trusted store first to avoid problems with server-sent legacy intermediates. Newer versions of OpenSSL do alternate chain checking by default which gives us the same fix without as much of a performance hit (slight), so we prefer that if available. https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest */ #if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_TRUSTED_FIRST); #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN if(!SSL_SET_OPTION(no_partialchain)) { /* Have intermediate certificates in the trust store be treated as trust-anchors, in the same way as self-signed root CA certificates are. This allows users to verify servers using the intermediate cert only, instead of needing the whole chain. */ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx), X509_V_FLAG_PARTIAL_CHAIN); } #endif } /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(BACKEND->ctx, verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ #if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK) if(keylog_file_fp) { SSL_CTX_set_keylog_callback(BACKEND->ctx, ossl_keylog_callback); } #endif /* Enable the session cache because it's a prerequisite for the "new session" * callback. Use the "external storage" mode to avoid that OpenSSL creates * an internal session cache. */ SSL_CTX_set_session_cache_mode(BACKEND->ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_sess_set_new_cb(BACKEND->ctx, ossl_new_session_cb); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { Curl_set_in_callback(data, true); result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx, data->set.ssl.fsslctxp); Curl_set_in_callback(data, false); if(result) { failf(data, "error signaled by ssl ctx callback"); return result; } } /* Lets make an SSL structure */ if(BACKEND->handle) SSL_free(BACKEND->handle); BACKEND->handle = SSL_new(BACKEND->ctx); if(!BACKEND->handle) { failf(data, "SSL: couldn't create a context (handle)!"); return CURLE_OUT_OF_MEMORY; } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(SSL_CONN_CONFIG(verifystatus)) SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp); #endif #if defined(OPENSSL_IS_BORINGSSL) && defined(ALLOW_RENEG) SSL_set_renegotiate_mode(BACKEND->handle, ssl_renegotiate_freely); #endif SSL_set_connect_state(BACKEND->handle); BACKEND->server_cert = 0x0; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && !SSL_set_tlsext_host_name(BACKEND->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; int connectdata_idx = ossl_get_ssl_conn_index(); int sockindex_idx = ossl_get_ssl_sockindex_index(); if(connectdata_idx >= 0 && sockindex_idx >= 0) { /* Store the data needed for the "new session" callback. * The sockindex is stored as a pointer to an array element. */ SSL_set_ex_data(BACKEND->handle, connectdata_idx, conn); SSL_set_ex_data(BACKEND->handle, sockindex_idx, conn->sock + sockindex); } Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof(data, "SSL re-using session ID\n"); } Curl_ssl_sessionid_unlock(conn); } if(conn->proxy_ssl[sockindex].use) { BIO *const bio = BIO_new(BIO_f_ssl()); SSL *handle = conn->proxy_ssl[sockindex].backend->handle; DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); DEBUGASSERT(handle != NULL); DEBUGASSERT(bio != NULL); BIO_set_ssl(bio, handle, FALSE); SSL_set_bio(BACKEND->handle, bio, bio); } else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) { /* pass the raw socket into the SSL layers */ failf(data, "SSL: SSL_set_fd failed: %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); ERR_clear_error(); err = SSL_connect(BACKEND->handle); /* If keylogging is enabled but the keylog callback is not supported then log secrets here, immediately after SSL_connect by using tap_ssl_key. */ #if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK) tap_ssl_key(BACKEND->handle, &BACKEND->tap_state); #endif /* 1 is fine 0 is "not successful but was shut down controlled" <0 is "handshake was not successful, because a fatal error occurred" */ if(1 != err) { int detail = SSL_get_error(BACKEND->handle, err); if(SSL_ERROR_WANT_READ == detail) { connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } if(SSL_ERROR_WANT_WRITE == detail) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } #ifdef SSL_ERROR_WANT_ASYNC if(SSL_ERROR_WANT_ASYNC == detail) { connssl->connecting_state = ssl_connect_2; return CURLE_OK; } #endif else { /* untreated error */ unsigned long errdetail; char error_buffer[256]=""; CURLcode result; long lerr; int lib; int reason; /* the connection failed, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_2; /* Get the earliest error code from the thread's error queue and removes the entry. */ errdetail = ERR_get_error(); /* Extract which lib and reason */ lib = ERR_GET_LIB(errdetail); reason = ERR_GET_REASON(errdetail); if((lib == ERR_LIB_SSL) && (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_PEER_FAILED_VERIFICATION; lerr = SSL_get_verify_result(BACKEND->handle); if(lerr != X509_V_OK) { *certverifyresult = lerr; msnprintf(error_buffer, sizeof(error_buffer), "SSL certificate problem: %s", X509_verify_cert_error_string(lerr)); } else /* strcpy() is fine here as long as the string fits within error_buffer */ strcpy(error_buffer, "SSL certificate verification failed"); } else { result = CURLE_SSL_CONNECT_ERROR; ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); } /* detail is already set to the SSL error above */ /* If we e.g. use SSLv2 request-method and the server doesn't like us * (RST connection etc.), OpenSSL gives no explanation whatsoever and * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; char extramsg[80]=""; int sockerr = SOCKERRNO; if(sockerr && detail == SSL_ERROR_SYSCALL) Curl_strerror(sockerr, extramsg, sizeof(extramsg)); failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ", extramsg[0] ? extramsg : SSL_ERROR_to_str(detail), hostname, port); return result; } /* Could be a CERT problem */ failf(data, "%s", error_buffer); return result; } } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ infof(data, "SSL connection using %s / %s\n", get_ssl_version_txt(BACKEND->handle), SSL_get_cipher(BACKEND->handle)); #ifdef HAS_ALPN /* Sets data and len to negotiated protocol, len is 0 if no protocol was * negotiated */ if(conn->bits.tls_enable_alpn) { const unsigned char *neg_protocol; unsigned int len; SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len); if(len != 0) { infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); #ifdef USE_NGHTTP2 if(len == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } } else infof(data, "ALPN, server did not agree to a protocol\n"); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif return CURLE_OK; } } static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) { int i, ilen; ilen = (int)len; if(ilen < 0) return 1; /* buffer too big */ i = i2t_ASN1_OBJECT(buf, ilen, a); if(i >= ilen) return 1; /* buffer too small */ return 0; } #define push_certinfo(_label, _num) \ do { \ long info_len = BIO_get_mem_data(mem, &ptr); \ Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ if(1 != BIO_reset(mem)) \ break; \ } while(0) static void pubkey_show(struct Curl_easy *data, BIO *mem, int num, const char *type, const char *name, #ifdef HAVE_OPAQUE_RSA_DSA_DH const #endif BIGNUM *bn) { char *ptr; char namebuf[32]; msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); if(bn) BN_print(mem, bn); push_certinfo(namebuf, num); } #ifdef HAVE_OPAQUE_RSA_DSA_DH #define print_pubkey_BN(_type, _name, _num) \ pubkey_show(data, mem, _num, #_type, #_name, _name) #else #define print_pubkey_BN(_type, _name, _num) \ do { \ if(_type->_name) { \ pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ } \ } while(0) #endif static void X509V3_ext(struct Curl_easy *data, int certnum, CONST_EXTS STACK_OF(X509_EXTENSION) *exts) { int i; if((int)sk_X509_EXTENSION_num(exts) <= 0) /* no extensions, bail out */ return; for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { ASN1_OBJECT *obj; X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); BUF_MEM *biomem; char namebuf[128]; BIO *bio_out = BIO_new(BIO_s_mem()); if(!bio_out) return; obj = X509_EXTENSION_get_object(ext); asn1_object_dump(obj, namebuf, sizeof(namebuf)); if(!X509V3_EXT_print(bio_out, ext, 0, 0)) ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); BIO_get_mem_ptr(bio_out, &biomem); Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, biomem->length); BIO_free(bio_out); } } #ifdef OPENSSL_IS_BORINGSSL typedef size_t numcert_t; #else typedef int numcert_t; #endif static CURLcode get_cert_chain(struct connectdata *conn, struct ssl_connect_data *connssl) { CURLcode result; STACK_OF(X509) *sk; int i; struct Curl_easy *data = conn->data; numcert_t numcerts; BIO *mem; sk = SSL_get_peer_cert_chain(BACKEND->handle); if(!sk) { return CURLE_OUT_OF_MEMORY; } numcerts = sk_X509_num(sk); result = Curl_ssl_init_certinfo(data, (int)numcerts); if(result) { return result; } mem = BIO_new(BIO_s_mem()); for(i = 0; i < (int)numcerts; i++) { ASN1_INTEGER *num; X509 *x = sk_X509_value(sk, i); EVP_PKEY *pubkey = NULL; int j; char *ptr; const ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Issuer", i); BIO_printf(mem, "%lx", X509_get_version(x)); push_certinfo("Version", i); num = X509_get_serialNumber(x); if(num->type == V_ASN1_NEG_INTEGER) BIO_puts(mem, "-"); for(j = 0; j < num->length; j++) BIO_printf(mem, "%02x", num->data[j]); push_certinfo("Serial Number", i); #if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) { const X509_ALGOR *sigalg = NULL; X509_PUBKEY *xpubkey = NULL; ASN1_OBJECT *pubkeyoid = NULL; X509_get0_signature(&psig, &sigalg, x); if(sigalg) { i2a_ASN1_OBJECT(mem, sigalg->algorithm); push_certinfo("Signature Algorithm", i); } xpubkey = X509_get_X509_PUBKEY(x); if(xpubkey) { X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); if(pubkeyoid) { i2a_ASN1_OBJECT(mem, pubkeyoid); push_certinfo("Public Key Algorithm", i); } } X509V3_ext(data, i, X509_get0_extensions(x)); } #else { /* before OpenSSL 1.0.2 */ X509_CINF *cinf = x->cert_info; i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); push_certinfo("Signature Algorithm", i); i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); push_certinfo("Public Key Algorithm", i); X509V3_ext(data, i, cinf->extensions); psig = x->signature; } #endif ASN1_TIME_print(mem, X509_get0_notBefore(x)); push_certinfo("Start date", i); ASN1_TIME_print(mem, X509_get0_notAfter(x)); push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); if(!pubkey) infof(data, " Unable to load public key\n"); else { int pktype; #ifdef HAVE_OPAQUE_EVP_PKEY pktype = EVP_PKEY_id(pubkey); #else pktype = pubkey->type; #endif switch(pktype) { case EVP_PKEY_RSA: { RSA *rsa; #ifdef HAVE_OPAQUE_EVP_PKEY rsa = EVP_PKEY_get0_RSA(pubkey); #else rsa = pubkey->pkey.rsa; #endif #ifdef HAVE_OPAQUE_RSA_DSA_DH { const BIGNUM *n; const BIGNUM *e; RSA_get0_key(rsa, &n, &e, NULL); BIO_printf(mem, "%d", BN_num_bits(n)); push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); } #else BIO_printf(mem, "%d", BN_num_bits(rsa->n)); push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); #endif break; } case EVP_PKEY_DSA: { #ifndef OPENSSL_NO_DSA DSA *dsa; #ifdef HAVE_OPAQUE_EVP_PKEY dsa = EVP_PKEY_get0_DSA(pubkey); #else dsa = pubkey->pkey.dsa; #endif #ifdef HAVE_OPAQUE_RSA_DSA_DH { const BIGNUM *p; const BIGNUM *q; const BIGNUM *g; const BIGNUM *pub_key; DSA_get0_pqg(dsa, &p, &q, &g); DSA_get0_key(dsa, &pub_key, NULL); print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, pub_key, i); } #else print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, pub_key, i); #endif #endif /* !OPENSSL_NO_DSA */ break; } case EVP_PKEY_DH: { DH *dh; #ifdef HAVE_OPAQUE_EVP_PKEY dh = EVP_PKEY_get0_DH(pubkey); #else dh = pubkey->pkey.dh; #endif #ifdef HAVE_OPAQUE_RSA_DSA_DH { const BIGNUM *p; const BIGNUM *q; const BIGNUM *g; const BIGNUM *pub_key; DH_get0_pqg(dh, &p, &q, &g); DH_get0_key(dh, &pub_key, NULL); print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, q, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, pub_key, i); } #else print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, pub_key, i); #endif break; } } EVP_PKEY_free(pubkey); } if(psig) { for(j = 0; j < psig->length; j++) BIO_printf(mem, "%02x:", psig->data[j]); push_certinfo("Signature", i); } PEM_write_bio_X509(mem, x); push_certinfo("Cert", i); } BIO_free(mem); return CURLE_OK; } /* * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL */ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, const char *pinnedpubkey) { /* Scratch */ int len1 = 0, len2 = 0; unsigned char *buff1 = NULL, *temp = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!cert) return result; do { /* Begin Gyrations to get the subjectPublicKeyInfo */ /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ /* https://groups.google.com/group/mailing.openssl.users/browse_thread /thread/d61858dae102c6c7 */ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); if(len1 < 1) break; /* failed */ buff1 = temp = malloc(len1); if(!buff1) break; /* failed */ /* https://www.openssl.org/docs/crypto/d2i_X509.html */ len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp); /* * These checks are verifying we got back the same values as when we * sized the buffer. It's pretty weak since they should always be the * same. But it gives us something to test. */ if((len1 != len2) || !temp || ((temp - buff1) != len1)) break; /* failed */ /* End Gyrations */ /* The one good exit point */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); if(buff1) free(buff1); return result; } /* * Get the server cert, verify it and show it etc, only call failf() if the * 'strict' argument is TRUE as otherwise all this is for informational * purposes only! * * We check certificates to authenticate the server; otherwise we risk * man-in-the-middle attack. */ static CURLcode servercert(struct connectdata *conn, struct ssl_connect_data *connssl, bool strict) { CURLcode result = CURLE_OK; int rc; long lerr; struct Curl_easy *data = conn->data; X509 *issuer; BIO *fp = NULL; char error_buffer[256]=""; char buffer[2048]; const char *ptr; long * const certverifyresult = SSL_IS_PROXY() ? &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); if(!BACKEND->server_cert) { BIO_free(mem); if(!strict) return CURLE_OK; failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert), buffer, sizeof(buffer)); infof(data, " subject: %s\n", rc?"[NONE]":buffer); #ifndef CURL_DISABLE_VERBOSE_STRINGS { long len; ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " start date: %.*s\n", len, ptr); (void)BIO_reset(mem); ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " expire date: %.*s\n", len, ptr); (void)BIO_reset(mem); } #endif BIO_free(mem); if(SSL_CONN_CONFIG(verifyhost)) { result = verifyhost(conn, BACKEND->server_cert); if(result) { X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; } } rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert), buffer, sizeof(buffer)); if(rc) { if(strict) failf(data, "SSL: couldn't get X509-issuer name!"); result = CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, " issuer: %s\n", buffer); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ if(SSL_SET_OPTION(issuercert)) { fp = BIO_new(BIO_s_file()); if(fp == NULL) { failf(data, "BIO_new return NULL, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_OUT_OF_MEMORY; } if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } infof(data, " SSL certificate issuer check ok (%s)\n", SSL_SET_OPTION(issuercert)); BIO_free(fp); X509_free(issuer); } lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle); if(*certverifyresult != X509_V_OK) { if(SSL_CONN_CONFIG(verifypeer)) { /* We probably never reach this, because SSL_connect() will fail and we return earlier if verifypeer is set? */ if(strict) failf(data, "SSL certificate verify result: %s (%ld)", X509_verify_cert_error_string(lerr), lerr); result = CURLE_PEER_FAILED_VERIFICATION; } else infof(data, " SSL certificate verify result: %s (%ld)," " continuing anyway.\n", X509_verify_cert_error_string(lerr), lerr); } else infof(data, " SSL certificate verify ok.\n"); } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; } } #endif if(!strict) /* when not strict, we don't bother about the verify cert problems */ result = CURLE_OK; ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(!result && ptr) { result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key!"); } X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; connssl->connecting_state = ssl_connect_done; return result; } static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); /* * We check certificates to authenticate the server; otherwise we risk * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to * verify the peer ignore faults and failures from the server cert * operations. */ result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost))); if(!result) connssl->connecting_state = ssl_connect_done; return result; } static Curl_recv ossl_recv; static Curl_send ossl_send; static CURLcode ossl_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; timediff_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } result = ossl_connect_step1(conn, sockindex); if(result) return result; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0:(time_t)timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if this * connection is done nonblocking and this loop would execute again. This * permits the owner of a multi handle to abort a connection attempt * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ result = ossl_connect_step2(conn, sockindex); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { result = ossl_connect_step3(conn, sockindex); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = ossl_recv; conn->send[sockindex] = ossl_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return ossl_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = ossl_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; if(connssl->backend->handle && SSL_pending(connssl->backend->handle)) return TRUE; if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle)) return TRUE; return FALSE; } static size_t Curl_ossl_version(char *buffer, size_t size); static ssize_t ossl_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ int err; char error_buffer[256]; unsigned long sslerror; int memlen; int rc; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ERR_clear_error(); memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; rc = SSL_write(BACKEND->handle, mem, memlen); if(rc <= 0) { err = SSL_get_error(BACKEND->handle, rc); switch(err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* The operation did not complete; the same TLS/SSL I/O function should be called again later. This is basically an EWOULDBLOCK equivalent. */ *curlcode = CURLE_AGAIN; return -1; case SSL_ERROR_SYSCALL: { int sockerr = SOCKERRNO; sslerror = ERR_get_error(); if(sslerror) ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr) Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); else { strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer)); error_buffer[sizeof(error_buffer) - 1] = '\0'; } failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d", error_buffer, sockerr); *curlcode = CURLE_SEND_ERROR; return -1; } case SSL_ERROR_SSL: /* A failure in the SSL library occurred, usually a protocol error. The OpenSSL error queue contains more information on the error. */ sslerror = ERR_get_error(); if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && conn->ssl[sockindex].state == ssl_connection_complete && conn->proxy_ssl[sockindex].state == ssl_connection_complete) { char ver[120]; Curl_ossl_version(ver, 120); failf(conn->data, "Error: %s does not support double SSL tunneling.", ver); } else failf(conn->data, "SSL_write() error: %s", ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; return -1; } /* a true error */ failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d", SSL_ERROR_to_str(err), SOCKERRNO); *curlcode = CURLE_SEND_ERROR; return -1; } *curlcode = CURLE_OK; return (ssize_t)rc; /* number of bytes */ } static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ int num, /* socketindex */ char *buf, /* store read data here */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { char error_buffer[256]; unsigned long sslerror; ssize_t nread; int buffsize; struct ssl_connect_data *connssl = &conn->ssl[num]; ERR_clear_error(); buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize); if(nread <= 0) { /* failed SSL_read */ int err = SSL_get_error(BACKEND->handle, (int)nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ break; case SSL_ERROR_ZERO_RETURN: /* no more data */ /* close_notify alert */ if(num == FIRSTSOCKET) /* mark the connection for close if it is indeed the control connection */ connclose(conn, "TLS close_notify"); break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_read() */ *curlcode = CURLE_AGAIN; return -1; default: /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return value/errno" */ /* https://www.openssl.org/docs/crypto/ERR_get_error.html */ sslerror = ERR_get_error(); if((nread < 0) || sslerror) { /* If the return code was negative or there actually is an error in the queue */ int sockerr = SOCKERRNO; if(sslerror) ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr && err == SSL_ERROR_SYSCALL) Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); else { strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer)); error_buffer[sizeof(error_buffer) - 1] = '\0'; } failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); *curlcode = CURLE_RECV_ERROR; return -1; } /* For debug builds be a little stricter and error on any SSL_ERROR_SYSCALL. For example a server may have closed the connection abruptly without a close_notify alert. For compatibility with older peers we don't do this by default. #4624 We can use this to gauge how many users may be affected, and if it goes ok eventually transition to allow in dev and release with the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */ #ifdef DEBUGBUILD if(err == SSL_ERROR_SYSCALL) { int sockerr = SOCKERRNO; if(sockerr) Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); else { msnprintf(error_buffer, sizeof(error_buffer), "Connection closed abruptly"); } failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d" " (Fatal because this is a curl debug build)", error_buffer, sockerr); *curlcode = CURLE_RECV_ERROR; return -1; } #endif } } return nread; } static size_t Curl_ossl_version(char *buffer, size_t size) { #ifdef LIBRESSL_VERSION_NUMBER #if LIBRESSL_VERSION_NUMBER < 0x2070100fL return msnprintf(buffer, size, "%s/%lx.%lx.%lx", OSSL_PACKAGE, (LIBRESSL_VERSION_NUMBER>>28)&0xf, (LIBRESSL_VERSION_NUMBER>>20)&0xff, (LIBRESSL_VERSION_NUMBER>>12)&0xff); #else /* OpenSSL_version() first appeared in LibreSSL 2.7.1 */ char *p; int count; const char *ver = OpenSSL_version(OPENSSL_VERSION); const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */ if(Curl_strncasecompare(ver, expected, sizeof(expected) - 1)) { ver += sizeof(expected) - 1; } count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); for(p = buffer; *p; ++p) { if(ISSPACE(*p)) *p = '_'; } return count; #endif #elif defined(OPENSSL_IS_BORINGSSL) return msnprintf(buffer, size, OSSL_PACKAGE); #elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING) return msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); #else /* not LibreSSL, BoringSSL and not using OpenSSL_version */ char sub[3]; unsigned long ssleay_value; sub[2]='\0'; sub[1]='\0'; ssleay_value = OpenSSL_version_num(); if(ssleay_value < 0x906000) { ssleay_value = SSLEAY_VERSION_NUMBER; sub[0]='\0'; } else { if(ssleay_value&0xff0) { int minor_ver = (ssleay_value >> 4) & 0xff; if(minor_ver > 26) { /* handle extended version introduced for 0.9.8za */ sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); sub[0] = 'z'; } else { sub[0] = (char) (minor_ver + 'a' - 1); } } else sub[0]='\0'; } return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s" #ifdef OPENSSL_FIPS "-fips" #endif , OSSL_PACKAGE, (ssleay_value>>28)&0xf, (ssleay_value>>20)&0xff, (ssleay_value>>12)&0xff, sub); #endif /* OPENSSL_IS_BORINGSSL */ } /* can be called with data == NULL */ static CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { int rc; if(data) { if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */ return CURLE_FAILED_INIT; /* couldn't seed for some reason */ } else { if(!rand_enough()) return CURLE_FAILED_INIT; } /* RAND_bytes() returns 1 on success, 0 otherwise. */ rc = RAND_bytes(entropy, curlx_uztosi(length)); return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); } static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum /* output */, size_t unused) { EVP_MD_CTX *mdctx; unsigned int len = 0; (void) unused; mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, EVP_md5(), NULL); EVP_DigestUpdate(mdctx, tmp, tmplen); EVP_DigestFinal_ex(mdctx, md5sum, &len); EVP_MD_CTX_destroy(mdctx); return CURLE_OK; } #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum /* output */, size_t unused) { EVP_MD_CTX *mdctx; unsigned int len = 0; (void) unused; mdctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, tmp, tmplen); EVP_DigestFinal_ex(mdctx, sha256sum, &len); EVP_MD_CTX_destroy(mdctx); return CURLE_OK; } #endif static bool Curl_ossl_cert_status_request(void) { #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) return TRUE; #else return FALSE; #endif } static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, CURLINFO info) { /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */ return info == CURLINFO_TLS_SESSION ? (void *)BACKEND->ctx : (void *)BACKEND->handle; } const struct Curl_ssl Curl_ssl_openssl = { { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ SSLSUPP_CA_PATH | SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY | SSLSUPP_SSL_CTX | #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES SSLSUPP_TLS13_CIPHERSUITES | #endif SSLSUPP_HTTPS_PROXY, sizeof(struct ssl_backend_data), Curl_ossl_init, /* init */ Curl_ossl_cleanup, /* cleanup */ Curl_ossl_version, /* version */ Curl_ossl_check_cxn, /* check_cxn */ Curl_ossl_shutdown, /* shutdown */ Curl_ossl_data_pending, /* data_pending */ Curl_ossl_random, /* random */ Curl_ossl_cert_status_request, /* cert_status_request */ Curl_ossl_connect, /* connect */ Curl_ossl_connect_nonblocking, /* connect_nonblocking */ Curl_ossl_get_internals, /* get_internals */ Curl_ossl_close, /* close_one */ Curl_ossl_close_all, /* close_all */ Curl_ossl_session_free, /* session_free */ Curl_ossl_set_engine, /* set_engine */ Curl_ossl_set_engine_default, /* set_engine_default */ Curl_ossl_engines_list, /* engines_list */ Curl_none_false_start, /* false_start */ Curl_ossl_md5sum, /* md5sum */ #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) Curl_ossl_sha256sum /* sha256sum */ #else NULL /* sha256sum */ #endif }; #endif /* USE_OPENSSL */ davix-0.8.0/deps/curl/lib/vtls/sectransp.c0000644000000000000000000033121014121063461017132 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2017, Nick Zitzmann, . * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Source file for all iOS and macOS SecureTransport-specific code for the * TLS/SSL layer. No code but vtls.c should ever call or use these functions. */ #include "curl_setup.h" #include "urldata.h" /* for the Curl_easy definition */ #include "curl_base64.h" #include "strtok.h" #include "multiif.h" #ifdef USE_SECTRANSP #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-pointer-compare" #endif /* __clang__ */ #include #include /* For some reason, when building for iOS, the omnibus header above does * not include SecureTransport.h as of iOS SDK 5.1. */ #include #include #include /* The Security framework has changed greatly between iOS and different macOS versions, and we will try to support as many of them as we can (back to Leopard and iOS 5) by using macros and weak-linking. In general, you want to build this using the most recent OS SDK, since some features require curl to be built against the latest SDK. TLS 1.1 and 1.2 support, for instance, require the macOS 10.8 SDK or later. TLS 1.3 requires the macOS 10.13 or iOS 11 SDK or later. */ #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) #if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 #error "The Secure Transport back-end requires Leopard or later." #endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ #define CURL_BUILD_IOS 0 #define CURL_BUILD_IOS_7 0 #define CURL_BUILD_IOS_9 0 #define CURL_BUILD_IOS_11 0 #define CURL_BUILD_MAC 1 /* This is the maximum API level we are allowed to use when building: */ #define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 #define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 #define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 #define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 #define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 #define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 #define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 /* These macros mean "the following code is present to allow runtime backward compatibility with at least this cat or earlier": (You set this at build-time using the compiler command line option "-mmacosx-version-min.") */ #define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 #define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 #define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 #define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 #define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 #elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE #define CURL_BUILD_IOS 1 #define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 #define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 #define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 #define CURL_BUILD_MAC 0 #define CURL_BUILD_MAC_10_5 0 #define CURL_BUILD_MAC_10_6 0 #define CURL_BUILD_MAC_10_7 0 #define CURL_BUILD_MAC_10_8 0 #define CURL_BUILD_MAC_10_9 0 #define CURL_BUILD_MAC_10_11 0 #define CURL_BUILD_MAC_10_13 0 #define CURL_SUPPORT_MAC_10_5 0 #define CURL_SUPPORT_MAC_10_6 0 #define CURL_SUPPORT_MAC_10_7 0 #define CURL_SUPPORT_MAC_10_8 0 #define CURL_SUPPORT_MAC_10_9 0 #else #error "The Secure Transport back-end requires iOS or macOS." #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ #if CURL_BUILD_MAC #include #endif /* CURL_BUILD_MAC */ #include "urldata.h" #include "sendf.h" #include "inet_pton.h" #include "connect.h" #include "select.h" #include "vtls.h" #include "sectransp.h" #include "curl_printf.h" #include "strdup.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /* From MacTypes.h (which we can't include because it isn't present in iOS: */ #define ioErr -36 #define paramErr -50 struct ssl_backend_data { SSLContextRef ssl_ctx; curl_socket_t ssl_sockfd; bool ssl_direction; /* true if writing, false if reading */ size_t ssl_write_buffered_length; }; #define BACKEND connssl->backend /* pinned public key support tests */ /* version 1 supports macOS 10.12+ and iOS 10+ */ #if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) #define SECTRANSP_PINNEDPUBKEY_V1 1 #endif /* version 2 supports MacOSX 10.7+ */ #if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) #define SECTRANSP_PINNEDPUBKEY_V2 1 #endif #if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2) /* this backend supports CURLOPT_PINNEDPUBLICKEY */ #define SECTRANSP_PINNEDPUBKEY 1 #endif /* SECTRANSP_PINNEDPUBKEY */ #ifdef SECTRANSP_PINNEDPUBKEY /* both new and old APIs return rsa keys missing the spki header (not DER) */ static const unsigned char rsa4096SpkiHeader[] = { 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; static const unsigned char rsa2048SpkiHeader[] = { 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; #ifdef SECTRANSP_PINNEDPUBKEY_V1 /* the *new* version doesn't return DER encoded ecdsa certs like the old... */ static const unsigned char ecDsaSecp256r1SpkiHeader[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00}; static const unsigned char ecDsaSecp384r1SpkiHeader[] = { 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00}; #endif /* SECTRANSP_PINNEDPUBKEY_V1 */ #endif /* SECTRANSP_PINNEDPUBKEY */ /* The following two functions were ripped from Apple sample code, * with some modifications: */ static OSStatus SocketRead(SSLConnectionRef connection, void *data, /* owned by * caller, data * RETURNED */ size_t *dataLength) /* IN/OUT */ { size_t bytesToGo = *dataLength; size_t initLen = bytesToGo; UInt8 *currData = (UInt8 *)data; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; int sock = BACKEND->ssl_sockfd; OSStatus rtn = noErr; size_t bytesRead; ssize_t rrtn; int theErr; *dataLength = 0; for(;;) { bytesRead = 0; rrtn = read(sock, currData, bytesToGo); if(rrtn <= 0) { /* this is guesswork... */ theErr = errno; if(rrtn == 0) { /* EOF = server hung up */ /* the framework will turn this into errSSLClosedNoNotify */ rtn = errSSLClosedGraceful; } else /* do the switch */ switch(theErr) { case ENOENT: /* connection closed */ rtn = errSSLClosedGraceful; break; case ECONNRESET: rtn = errSSLClosedAbort; break; case EAGAIN: rtn = errSSLWouldBlock; BACKEND->ssl_direction = false; break; default: rtn = ioErr; break; } break; } else { bytesRead = rrtn; } bytesToGo -= bytesRead; currData += bytesRead; if(bytesToGo == 0) { /* filled buffer with incoming data, done */ break; } } *dataLength = initLen - bytesToGo; return rtn; } static OSStatus SocketWrite(SSLConnectionRef connection, const void *data, size_t *dataLength) /* IN/OUT */ { size_t bytesSent = 0; /*int sock = *(int *)connection;*/ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; int sock = BACKEND->ssl_sockfd; ssize_t length; size_t dataLen = *dataLength; const UInt8 *dataPtr = (UInt8 *)data; OSStatus ortn; int theErr; *dataLength = 0; do { length = write(sock, (char *)dataPtr + bytesSent, dataLen - bytesSent); } while((length > 0) && ( (bytesSent += length) < dataLen) ); if(length <= 0) { theErr = errno; if(theErr == EAGAIN) { ortn = errSSLWouldBlock; BACKEND->ssl_direction = true; } else { ortn = ioErr; } } else { ortn = noErr; } *dataLength = bytesSent; return ortn; } #ifndef CURL_DISABLE_VERBOSE_STRINGS CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { switch(cipher) { /* SSL version 3.0 */ case SSL_RSA_WITH_NULL_MD5: return "SSL_RSA_WITH_NULL_MD5"; break; case SSL_RSA_WITH_NULL_SHA: return "SSL_RSA_WITH_NULL_SHA"; break; case SSL_RSA_EXPORT_WITH_RC4_40_MD5: return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; break; case SSL_RSA_WITH_RC4_128_MD5: return "SSL_RSA_WITH_RC4_128_MD5"; break; case SSL_RSA_WITH_RC4_128_SHA: return "SSL_RSA_WITH_RC4_128_SHA"; break; case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; break; case SSL_RSA_WITH_IDEA_CBC_SHA: return "SSL_RSA_WITH_IDEA_CBC_SHA"; break; case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_RSA_WITH_DES_CBC_SHA: return "SSL_RSA_WITH_DES_CBC_SHA"; break; case SSL_RSA_WITH_3DES_EDE_CBC_SHA: return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_DH_DSS_WITH_DES_CBC_SHA: return "SSL_DH_DSS_WITH_DES_CBC_SHA"; break; case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_DH_RSA_WITH_DES_CBC_SHA: return "SSL_DH_RSA_WITH_DES_CBC_SHA"; break; case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_DHE_DSS_WITH_DES_CBC_SHA: return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; break; case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_DHE_RSA_WITH_DES_CBC_SHA: return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; break; case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; break; case SSL_DH_anon_WITH_RC4_128_MD5: return "SSL_DH_anon_WITH_RC4_128_MD5"; break; case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; break; case SSL_DH_anon_WITH_DES_CBC_SHA: return "SSL_DH_anon_WITH_DES_CBC_SHA"; break; case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; break; case SSL_FORTEZZA_DMS_WITH_NULL_SHA: return "SSL_FORTEZZA_DMS_WITH_NULL_SHA"; break; case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; break; /* TLS 1.0 with AES (RFC 3268) (Apparently these are used in SSLv3 implementations as well.) */ case TLS_RSA_WITH_AES_128_CBC_SHA: return "TLS_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_128_CBC_SHA: return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; break; case TLS_DH_RSA_WITH_AES_128_CBC_SHA: return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; break; case TLS_RSA_WITH_AES_256_CBC_SHA: return "TLS_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_256_CBC_SHA: return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; break; case TLS_DH_RSA_WITH_AES_256_CBC_SHA: return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DH_anon_WITH_AES_256_CBC_SHA: return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; break; /* SSL version 2.0 */ case SSL_RSA_WITH_RC2_CBC_MD5: return "SSL_RSA_WITH_RC2_CBC_MD5"; break; case SSL_RSA_WITH_IDEA_CBC_MD5: return "SSL_RSA_WITH_IDEA_CBC_MD5"; break; case SSL_RSA_WITH_DES_CBC_MD5: return "SSL_RSA_WITH_DES_CBC_MD5"; break; case SSL_RSA_WITH_3DES_EDE_CBC_MD5: return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; break; } return "SSL_NULL_WITH_NULL_NULL"; } CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { switch(cipher) { /* TLS 1.0 with AES (RFC 3268) */ case TLS_RSA_WITH_AES_128_CBC_SHA: return "TLS_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_128_CBC_SHA: return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; break; case TLS_DH_RSA_WITH_AES_128_CBC_SHA: return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; break; case TLS_RSA_WITH_AES_256_CBC_SHA: return "TLS_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_256_CBC_SHA: return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; break; case TLS_DH_RSA_WITH_AES_256_CBC_SHA: return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DH_anon_WITH_AES_256_CBC_SHA: return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; break; #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS /* TLS 1.0 with ECDSA (RFC 4492) */ case TLS_ECDH_ECDSA_WITH_NULL_SHA: return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; break; case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; break; case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; break; case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; break; case TLS_ECDHE_ECDSA_WITH_NULL_SHA: return "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; break; case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; break; case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; break; case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; break; case TLS_ECDH_RSA_WITH_NULL_SHA: return "TLS_ECDH_RSA_WITH_NULL_SHA"; break; case TLS_ECDH_RSA_WITH_RC4_128_SHA: return "TLS_ECDH_RSA_WITH_RC4_128_SHA"; break; case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_ECDHE_RSA_WITH_NULL_SHA: return "TLS_ECDHE_RSA_WITH_NULL_SHA"; break; case TLS_ECDHE_RSA_WITH_RC4_128_SHA: return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; break; case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_ECDH_anon_WITH_NULL_SHA: return "TLS_ECDH_anon_WITH_NULL_SHA"; break; case TLS_ECDH_anon_WITH_RC4_128_SHA: return "TLS_ECDH_anon_WITH_RC4_128_SHA"; break; case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; break; case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; break; case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; break; #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS /* TLS 1.2 (RFC 5246) */ case TLS_RSA_WITH_NULL_MD5: return "TLS_RSA_WITH_NULL_MD5"; break; case TLS_RSA_WITH_NULL_SHA: return "TLS_RSA_WITH_NULL_SHA"; break; case TLS_RSA_WITH_RC4_128_MD5: return "TLS_RSA_WITH_RC4_128_MD5"; break; case TLS_RSA_WITH_RC4_128_SHA: return "TLS_RSA_WITH_RC4_128_SHA"; break; case TLS_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_RSA_WITH_NULL_SHA256: return "TLS_RSA_WITH_NULL_SHA256"; break; case TLS_RSA_WITH_AES_128_CBC_SHA256: return "TLS_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_RSA_WITH_AES_256_CBC_SHA256: return "TLS_RSA_WITH_AES_256_CBC_SHA256"; break; case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; break; case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; break; case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; break; case TLS_DH_anon_WITH_RC4_128_MD5: return "TLS_DH_anon_WITH_RC4_128_MD5"; break; case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA256: return "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; break; case TLS_DH_anon_WITH_AES_256_CBC_SHA256: return "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; break; /* TLS 1.2 with AES GCM (RFC 5288) */ case TLS_RSA_WITH_AES_128_GCM_SHA256: return "TLS_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_RSA_WITH_AES_256_GCM_SHA384: return "TLS_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; break; case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; break; case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; break; case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; break; case TLS_DH_anon_WITH_AES_128_GCM_SHA256: return "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; break; case TLS_DH_anon_WITH_AES_256_GCM_SHA384: return "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; break; /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; break; case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; break; case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; break; case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; break; case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; break; case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; break; case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; break; case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; break; case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; break; case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; break; case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; break; #else case SSL_RSA_WITH_NULL_MD5: return "TLS_RSA_WITH_NULL_MD5"; break; case SSL_RSA_WITH_NULL_SHA: return "TLS_RSA_WITH_NULL_SHA"; break; case SSL_RSA_WITH_RC4_128_MD5: return "TLS_RSA_WITH_RC4_128_MD5"; break; case SSL_RSA_WITH_RC4_128_SHA: return "TLS_RSA_WITH_RC4_128_SHA"; break; case SSL_RSA_WITH_3DES_EDE_CBC_SHA: return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; break; case SSL_DH_anon_WITH_RC4_128_MD5: return "TLS_DH_anon_WITH_RC4_128_MD5"; break; case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; break; #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 /* TLS PSK (RFC 4279): */ case TLS_PSK_WITH_RC4_128_SHA: return "TLS_PSK_WITH_RC4_128_SHA"; break; case TLS_PSK_WITH_3DES_EDE_CBC_SHA: return "TLS_PSK_WITH_3DES_EDE_CBC_SHA"; break; case TLS_PSK_WITH_AES_128_CBC_SHA: return "TLS_PSK_WITH_AES_128_CBC_SHA"; break; case TLS_PSK_WITH_AES_256_CBC_SHA: return "TLS_PSK_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_PSK_WITH_RC4_128_SHA: return "TLS_DHE_PSK_WITH_RC4_128_SHA"; break; case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"; break; case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"; break; case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"; break; case TLS_RSA_PSK_WITH_RC4_128_SHA: return "TLS_RSA_PSK_WITH_RC4_128_SHA"; break; case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"; break; case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"; break; case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"; break; /* More TLS PSK (RFC 4785): */ case TLS_PSK_WITH_NULL_SHA: return "TLS_PSK_WITH_NULL_SHA"; break; case TLS_DHE_PSK_WITH_NULL_SHA: return "TLS_DHE_PSK_WITH_NULL_SHA"; break; case TLS_RSA_PSK_WITH_NULL_SHA: return "TLS_RSA_PSK_WITH_NULL_SHA"; break; /* Even more TLS PSK (RFC 5487): */ case TLS_PSK_WITH_AES_128_GCM_SHA256: return "TLS_PSK_WITH_AES_128_GCM_SHA256"; break; case TLS_PSK_WITH_AES_256_GCM_SHA384: return "TLS_PSK_WITH_AES_256_GCM_SHA384"; break; case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"; break; case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"; break; case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"; break; case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: return "TLS_PSK_WITH_AES_256_GCM_SHA384"; break; case TLS_PSK_WITH_AES_128_CBC_SHA256: return "TLS_PSK_WITH_AES_128_CBC_SHA256"; break; case TLS_PSK_WITH_AES_256_CBC_SHA384: return "TLS_PSK_WITH_AES_256_CBC_SHA384"; break; case TLS_PSK_WITH_NULL_SHA256: return "TLS_PSK_WITH_NULL_SHA256"; break; case TLS_PSK_WITH_NULL_SHA384: return "TLS_PSK_WITH_NULL_SHA384"; break; case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"; break; case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"; break; case TLS_DHE_PSK_WITH_NULL_SHA256: return "TLS_DHE_PSK_WITH_NULL_SHA256"; break; case TLS_DHE_PSK_WITH_NULL_SHA384: return "TLS_RSA_PSK_WITH_NULL_SHA384"; break; case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"; break; case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"; break; case TLS_RSA_PSK_WITH_NULL_SHA256: return "TLS_RSA_PSK_WITH_NULL_SHA256"; break; case TLS_RSA_PSK_WITH_NULL_SHA384: return "TLS_RSA_PSK_WITH_NULL_SHA384"; break; #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 /* New ChaCha20+Poly1305 cipher-suites used by TLS 1.3: */ case TLS_AES_128_GCM_SHA256: return "TLS_AES_128_GCM_SHA256"; break; case TLS_AES_256_GCM_SHA384: return "TLS_AES_256_GCM_SHA384"; break; case TLS_CHACHA20_POLY1305_SHA256: return "TLS_CHACHA20_POLY1305_SHA256"; break; case TLS_AES_128_CCM_SHA256: return "TLS_AES_128_CCM_SHA256"; break; case TLS_AES_128_CCM_8_SHA256: return "TLS_AES_128_CCM_8_SHA256"; break; case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; break; case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"; break; #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ } return "TLS_NULL_WITH_NULL_NULL"; } #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ #if CURL_BUILD_MAC CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) { int mib[2]; char *os_version; size_t os_version_len; char *os_version_major, *os_version_minor; char *tok_buf; /* Get the Darwin kernel version from the kernel using sysctl(): */ mib[0] = CTL_KERN; mib[1] = KERN_OSRELEASE; if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1) return; os_version = malloc(os_version_len*sizeof(char)); if(!os_version) return; if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) { free(os_version); return; } /* Parse the version: */ os_version_major = strtok_r(os_version, ".", &tok_buf); os_version_minor = strtok_r(NULL, ".", &tok_buf); *major = atoi(os_version_major); *minor = atoi(os_version_minor); free(os_version); } #endif /* CURL_BUILD_MAC */ /* Apple provides a myriad of ways of getting information about a certificate into a string. Some aren't available under iOS or newer cats. So here's a unified function for getting a string describing the certificate that ought to work in all cats starting with Leopard. */ CF_INLINE CFStringRef getsubject(SecCertificateRef cert) { CFStringRef server_cert_summary = CFSTR("(null)"); #if CURL_BUILD_IOS /* iOS: There's only one way to do this. */ server_cert_summary = SecCertificateCopySubjectSummary(cert); #else #if CURL_BUILD_MAC_10_7 /* Lion & later: Get the long description if we can. */ if(SecCertificateCopyLongDescription != NULL) server_cert_summary = SecCertificateCopyLongDescription(NULL, cert, NULL); else #endif /* CURL_BUILD_MAC_10_7 */ #if CURL_BUILD_MAC_10_6 /* Snow Leopard: Get the certificate summary. */ if(SecCertificateCopySubjectSummary != NULL) server_cert_summary = SecCertificateCopySubjectSummary(cert); else #endif /* CURL_BUILD_MAC_10_6 */ /* Leopard is as far back as we go... */ (void)SecCertificateCopyCommonName(cert, &server_cert_summary); #endif /* CURL_BUILD_IOS */ return server_cert_summary; } static CURLcode CopyCertSubject(struct Curl_easy *data, SecCertificateRef cert, char **certp) { CFStringRef c = getsubject(cert); CURLcode result = CURLE_OK; const char *direct; char *cbuf = NULL; *certp = NULL; if(!c) { failf(data, "SSL: invalid CA certificate subject"); return CURLE_PEER_FAILED_VERIFICATION; } /* If the subject is already available as UTF-8 encoded (ie 'direct') then use that, else convert it. */ direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8); if(direct) { *certp = strdup(direct); if(!*certp) { failf(data, "SSL: out of memory"); result = CURLE_OUT_OF_MEMORY; } } else { size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1; cbuf = calloc(cbuf_size, 1); if(cbuf) { if(!CFStringGetCString(c, cbuf, cbuf_size, kCFStringEncodingUTF8)) { failf(data, "SSL: invalid CA certificate subject"); result = CURLE_PEER_FAILED_VERIFICATION; } else /* pass back the buffer */ *certp = cbuf; } else { failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size); result = CURLE_OUT_OF_MEMORY; } } if(result) free(cbuf); CFRelease(c); return result; } #if CURL_SUPPORT_MAC_10_6 /* The SecKeychainSearch API was deprecated in Lion, and using it will raise deprecation warnings, so let's not compile this unless it's necessary: */ static OSStatus CopyIdentityWithLabelOldSchool(char *label, SecIdentityRef *out_c_a_k) { OSStatus status = errSecItemNotFound; SecKeychainAttributeList attr_list; SecKeychainAttribute attr; SecKeychainSearchRef search = NULL; SecCertificateRef cert = NULL; /* Set up the attribute list: */ attr_list.count = 1L; attr_list.attr = &attr; /* Set up our lone search criterion: */ attr.tag = kSecLabelItemAttr; attr.data = label; attr.length = (UInt32)strlen(label); /* Start searching: */ status = SecKeychainSearchCreateFromAttributes(NULL, kSecCertificateItemClass, &attr_list, &search); if(status == noErr) { status = SecKeychainSearchCopyNext(search, (SecKeychainItemRef *)&cert); if(status == noErr && cert) { /* If we found a certificate, does it have a private key? */ status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); CFRelease(cert); } } if(search) CFRelease(search); return status; } #endif /* CURL_SUPPORT_MAC_10_6 */ static OSStatus CopyIdentityWithLabel(char *label, SecIdentityRef *out_cert_and_key) { OSStatus status = errSecItemNotFound; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS CFArrayRef keys_list; CFIndex keys_list_count; CFIndex i; CFStringRef common_name; /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { CFTypeRef keys[5]; CFTypeRef values[5]; CFDictionaryRef query_dict; CFStringRef label_cf = CFStringCreateWithCString(NULL, label, kCFStringEncodingUTF8); /* Set up our search criteria and expected results: */ values[0] = kSecClassIdentity; /* we want a certificate and a key */ keys[0] = kSecClass; values[1] = kCFBooleanTrue; /* we want a reference */ keys[1] = kSecReturnRef; values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the * label matching below worked correctly */ keys[2] = kSecMatchLimit; /* identity searches need a SecPolicyRef in order to work */ values[3] = SecPolicyCreateSSL(false, NULL); keys[3] = kSecMatchPolicy; /* match the name of the certificate (doesn't work in macOS 10.12.1) */ values[4] = label_cf; keys[4] = kSecAttrLabel; query_dict = CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 5L, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(values[3]); /* Do we have a match? */ status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity, * we need to find the correct identity ourselves */ if(status == noErr) { keys_list_count = CFArrayGetCount(keys_list); *out_cert_and_key = NULL; status = 1; for(i = 0; idata; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); long max_supported_version_by_os; /* macOS 10.5-10.7 supported TLS 1.0 only. macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2. macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */ #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(__builtin_available(macOS 10.13, iOS 11.0, *)) { max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3; } else { max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2; } #else max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2; #endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 */ switch(ssl_version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: ssl_version = CURL_SSLVERSION_TLSv1_0; break; } switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: ssl_version_max = max_supported_version_by_os; break; } #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { SSLProtocol darwin_ver_min = kTLSProtocol1; SSLProtocol darwin_ver_max = kTLSProtocol1; CURLcode result = sectransp_version_from_curl(&darwin_ver_min, ssl_version); if(result) { failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); return result; } result = sectransp_version_from_curl(&darwin_ver_max, ssl_version_max >> 16); if(result) { failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); return result; } (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, darwin_ver_min); (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, darwin_ver_max); return result; } else { #if CURL_SUPPORT_MAC_10_8 long i = ssl_version; (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); for(; i <= (ssl_version_max >> 16); i++) { switch(i) { case CURL_SSLVERSION_TLSv1_0: (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol11, true); break; case CURL_SSLVERSION_TLSv1_2: (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol12, true); break; case CURL_SSLVERSION_TLSv1_3: failf(data, "Your version of the OS does not support TLSv1.3"); return CURLE_SSL_CONNECT_ERROR; } } return CURLE_OK; #endif /* CURL_SUPPORT_MAC_10_8 */ } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ failf(data, "Secure Transport: cannot set SSL protocol"); return CURLE_SSL_CONNECT_ERROR; } static CURLcode sectransp_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); char * const ssl_cert = SSL_SET_OPTION(cert); const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif /* ENABLE_IPV6 */ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; OSStatus err = noErr; #if CURL_BUILD_MAC int darwinver_maj = 0, darwinver_min = 0; GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); #endif /* CURL_BUILD_MAC */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) { /* use the newer API if available */ if(BACKEND->ssl_ctx) CFRelease(BACKEND->ssl_ctx); BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); if(!BACKEND->ssl_ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } } else { /* The old ST API does not exist under iOS, so don't compile it: */ #if CURL_SUPPORT_MAC_10_8 if(BACKEND->ssl_ctx) (void)SSLDisposeContext(BACKEND->ssl_ctx); err = SSLNewContext(false, &(BACKEND->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } #endif /* CURL_SUPPORT_MAC_10_8 */ } #else if(BACKEND->ssl_ctx) (void)SSLDisposeContext(BACKEND->ssl_ctx); err = SSLNewContext(false, &(BACKEND->ssl_ctx)); if(err != noErr) { failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ BACKEND->ssl_write_buffered_length = 0UL; /* reset buffered write length */ /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { switch(conn->ssl_config.version) { case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1); #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(__builtin_available(macOS 10.13, iOS 11.0, *)) { (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol13); } else { (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); } #else (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12); #endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 */ break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { CURLcode result = set_ssl_version_min_max(conn, sockindex); if(result != CURLE_OK) return result; break; } case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol3); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; } (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3); break; case CURL_SSLVERSION_SSLv2: err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol2); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2); break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } } else { #if CURL_SUPPORT_MAC_10_8 (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol11, true); (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol12, true); break; case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { CURLcode result = set_ssl_version_min_max(conn, sockindex); if(result != CURLE_OK) return result; break; } case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; } break; case CURL_SSLVERSION_SSLv2: err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_SUPPORT_MAC_10_8 */ } #else if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) { failf(data, "Your version of the OS does not support to set maximum" " SSL/TLS version"); return CURLE_SSL_CONNECT_ERROR; } (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: failf(data, "Your version of the OS does not support TLSv1.1"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_TLSv1_2: failf(data, "Your version of the OS does not support TLSv1.2"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_TLSv1_3: failf(data, "Your version of the OS does not support TLSv1.3"); return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv2: err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol2, true); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } break; case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocol3, true); if(err != noErr) { failf(data, "Your version of the OS does not support SSLv3"); return CURLE_SSL_CONNECT_ERROR; } break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(conn->bits.tls_enable_alpn) { if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID)); infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1)); infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); /* expects length prefixed preference ordered list of protocols in wire * format */ err = SSLSetALPNProtocols(BACKEND->ssl_ctx, alpnArr); if(err != noErr) infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n", err); CFRelease(alpnArr); } } #endif if(SSL_SET_OPTION(key)) { infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " "Transport. The private key must be in the Keychain.\n"); } if(ssl_cert) { SecIdentityRef cert_and_key = NULL; bool is_cert_file = is_file(ssl_cert); /* User wants to authenticate with a client cert. Look for it: If we detect that this is a file on disk, then let's load it. Otherwise, assume that the user wants to use an identity loaded from the Keychain. */ if(is_cert_file) { if(!SSL_SET_OPTION(cert_type)) infof(data, "WARNING: SSL: Certificate type not set, assuming " "PKCS#12 format.\n"); else if(strncmp(SSL_SET_OPTION(cert_type), "P12", strlen(SSL_SET_OPTION(cert_type))) != 0) infof(data, "WARNING: SSL: The Security framework only supports " "loading identities that are in PKCS#12 format.\n"); err = CopyIdentityFromPKCS12File(ssl_cert, SSL_SET_OPTION(key_passwd), &cert_and_key); } else err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); if(err == noErr && cert_and_key) { SecCertificateRef cert = NULL; CFTypeRef certs_c[1]; CFArrayRef certs; /* If we found one, print it out: */ err = SecIdentityCopyCertificate(cert_and_key, &cert); if(err == noErr) { char *certp; CURLcode result = CopyCertSubject(data, cert, &certp); if(!result) { infof(data, "Client certificate: %s\n", certp); free(certp); } CFRelease(cert); if(result == CURLE_PEER_FAILED_VERIFICATION) return CURLE_SSL_CERTPROBLEM; if(result) return result; } certs_c[0] = cert_and_key; certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, &kCFTypeArrayCallBacks); err = SSLSetCertificate(BACKEND->ssl_ctx, certs); if(certs) CFRelease(certs); if(err != noErr) { failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); return CURLE_SSL_CERTPROBLEM; } CFRelease(cert_and_key); } else { switch(err) { case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ failf(data, "SSL: Incorrect password for the certificate \"%s\" " "and its private key.", ssl_cert); break; case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ failf(data, "SSL: Couldn't make sense of the data in the " "certificate \"%s\" and its private key.", ssl_cert); break; case -25260: /* errSecPassphraseRequired */ failf(data, "SSL The certificate \"%s\" requires a password.", ssl_cert); break; case errSecItemNotFound: failf(data, "SSL: Can't find the certificate \"%s\" and its private " "key in the Keychain.", ssl_cert); break; default: failf(data, "SSL: Can't load the certificate \"%s\" and its private " "key: OSStatus %d", ssl_cert, err); break; } return CURLE_SSL_CERTPROBLEM; } } /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS /* Snow Leopard introduced the SSLSetSessionOption() function, but due to a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag works, it doesn't work as expected under Snow Leopard, Lion or Mountain Lion. So we need to call SSLSetEnableCertVerify() on those older cats in order to disable certificate validation if the user turned that off. (SecureTransport will always validate the certificate chain by default.) Note: Darwin 11.x.x is Lion (10.7) Darwin 12.x.x is Mountain Lion (10.8) Darwin 13.x.x is Mavericks (10.9) Darwin 14.x.x is Yosemite (10.10) Darwin 15.x.x is El Capitan (10.11) */ #if CURL_BUILD_MAC if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; err = SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, break_on_auth); if(err != noErr) { failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } } else { #if CURL_SUPPORT_MAC_10_8 err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_SUPPORT_MAC_10_8 */ } #else err = SSLSetEnableCertVerify(BACKEND->ssl_ctx, conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ if(ssl_cafile && verifypeer) { bool is_cert_file = is_file(ssl_cafile); if(!is_cert_file) { failf(data, "SSL: can't load CA certificate file %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } } /* Configure hostname check. SNI is used if available. * Both hostname check and SNI require SSLSetPeerDomainName(). * Also: the verifyhost setting influences SNI usage */ if(conn->ssl_config.verifyhost) { err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname, strlen(hostname)); if(err != noErr) { infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", err); } if((Curl_inet_pton(AF_INET, hostname, &addr)) #ifdef ENABLE_IPV6 || (Curl_inet_pton(AF_INET6, hostname, &addr)) #endif ) { infof(data, "WARNING: using IP address, SNI is being disabled by " "the OS.\n"); } } else { infof(data, "WARNING: disabling hostname validation also disables SNI.\n"); } /* Disable cipher suites that ST supports but are not safe. These ciphers are unlikely to be used in any case since ST gives other ciphers a much higher priority, but it's probably better that we not connect at all than to give the user a false sense of security if the server only supports insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */ err = SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count); if(err != noErr) { failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d", err); return CURLE_SSL_CIPHER; } all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); if(!all_ciphers) { failf(data, "SSL: Failed to allocate memory for all ciphers"); return CURLE_OUT_OF_MEMORY; } allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite)); if(!allowed_ciphers) { Curl_safefree(all_ciphers); failf(data, "SSL: Failed to allocate memory for allowed ciphers"); return CURLE_OUT_OF_MEMORY; } err = SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers, &all_ciphers_count); if(err != noErr) { Curl_safefree(all_ciphers); Curl_safefree(allowed_ciphers); return CURLE_SSL_CIPHER; } for(i = 0UL ; i < all_ciphers_count ; i++) { #if CURL_BUILD_MAC /* There's a known bug in early versions of Mountain Lion where ST's ECC ciphers (cipher suite 0xC001 through 0xC032) simply do not work. Work around the problem here by disabling those ciphers if we are running in an affected version of OS X. */ if(darwinver_maj == 12 && darwinver_min <= 3 && all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { continue; } #endif /* CURL_BUILD_MAC */ switch(all_ciphers[i]) { /* Disable NULL ciphersuites: */ case SSL_NULL_WITH_NULL_NULL: case SSL_RSA_WITH_NULL_MD5: case SSL_RSA_WITH_NULL_SHA: case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */ case SSL_FORTEZZA_DMS_WITH_NULL_SHA: case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */ case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */ case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */ case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */ case 0x002C: /* TLS_PSK_WITH_NULL_SHA */ case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */ case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */ case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */ case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */ case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */ case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */ case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */ case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */ /* Disable anonymous ciphersuites: */ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: case SSL_DH_anon_WITH_RC4_128_MD5: case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: case SSL_DH_anon_WITH_DES_CBC_SHA: case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: case TLS_DH_anon_WITH_AES_128_CBC_SHA: case TLS_DH_anon_WITH_AES_256_CBC_SHA: case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */ case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */ case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */ case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */ case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */ case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */ case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */ case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */ /* Disable weak key ciphersuites: */ case SSL_RSA_EXPORT_WITH_RC4_40_MD5: case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: case SSL_RSA_WITH_DES_CBC_SHA: case SSL_DH_DSS_WITH_DES_CBC_SHA: case SSL_DH_RSA_WITH_DES_CBC_SHA: case SSL_DHE_DSS_WITH_DES_CBC_SHA: case SSL_DHE_RSA_WITH_DES_CBC_SHA: /* Disable IDEA: */ case SSL_RSA_WITH_IDEA_CBC_SHA: case SSL_RSA_WITH_IDEA_CBC_MD5: /* Disable RC4: */ case SSL_RSA_WITH_RC4_128_MD5: case SSL_RSA_WITH_RC4_128_SHA: case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/ case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */ case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */ case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */ break; default: /* enable everything else */ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; break; } } err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers, allowed_ciphers_count); Curl_safefree(all_ciphers); Curl_safefree(allowed_ciphers); if(err != noErr) { failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); return CURLE_SSL_CIPHER; } #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord, !data->set.ssl.enable_beast); SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart, data->set.ssl.falsestart); /* false start support */ } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ if(SSL_SET_OPTION(primary.sessionid)) { char *ssl_sessionid; size_t ssl_sessionid_len; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, &ssl_sessionid_len, sockindex)) { /* we got a session id, use it! */ err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); Curl_ssl_sessionid_unlock(conn); if(err != noErr) { failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ infof(data, "SSL re-using session ID\n"); } /* If there isn't one, then let's make one up! This has to be done prior to starting the handshake. */ else { CURLcode result; ssl_sessionid = aprintf("%s:%d:%d:%s:%hu", ssl_cafile, verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); ssl_sessionid_len = strlen(ssl_sessionid); err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len); if(err != noErr) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, sockindex); Curl_ssl_sessionid_unlock(conn); if(result) { failf(data, "failed to store ssl session"); return result; } } } err = SSLSetIOFuncs(BACKEND->ssl_ctx, SocketRead, SocketWrite); if(err != noErr) { failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } /* pass the raw socket into the SSL layers */ /* We need to store the FD in a constant memory address, because * SSLSetConnection() will not copy that address. I've found that * conn->sock[sockindex] may change on its own. */ BACKEND->ssl_sockfd = sockfd; err = SSLSetConnection(BACKEND->ssl_ctx, connssl); if(err != noErr) { failf(data, "SSL: SSLSetConnection() failed: %d", err); return CURLE_SSL_CONNECT_ERROR; } connssl->connecting_state = ssl_connect_2; return CURLE_OK; } static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) { char *sep_start, *sep_end, *cert_start, *cert_end; size_t i, j, err; size_t len; unsigned char *b64; /* Jump through the separators at the beginning of the certificate. */ sep_start = strstr(in, "-----"); if(sep_start == NULL) return 0; cert_start = strstr(sep_start + 1, "-----"); if(cert_start == NULL) return -1; cert_start += 5; /* Find separator after the end of the certificate. */ cert_end = strstr(cert_start, "-----"); if(cert_end == NULL) return -1; sep_end = strstr(cert_end + 1, "-----"); if(sep_end == NULL) return -1; sep_end += 5; len = cert_end - cert_start; b64 = malloc(len + 1); if(!b64) return -1; /* Create base64 string without linefeeds. */ for(i = 0, j = 0; i < len; i++) { if(cert_start[i] != '\r' && cert_start[i] != '\n') b64[j++] = cert_start[i]; } b64[j] = '\0'; err = Curl_base64_decode((const char *)b64, out, outlen); free(b64); if(err) { free(*out); return -1; } return sep_end - in; } static int read_cert(const char *file, unsigned char **out, size_t *outlen) { int fd; ssize_t n, len = 0, cap = 512; unsigned char buf[512], *data; fd = open(file, 0); if(fd < 0) return -1; data = malloc(cap); if(!data) { close(fd); return -1; } for(;;) { n = read(fd, buf, sizeof(buf)); if(n < 0) { close(fd); free(data); return -1; } else if(n == 0) { close(fd); break; } if(len + n >= cap) { cap *= 2; data = Curl_saferealloc(data, cap); if(!data) { close(fd); return -1; } } memcpy(data + len, buf, n); len += n; } data[len] = '\0'; *out = data; *outlen = len; return 0; } static int append_cert_to_array(struct Curl_easy *data, unsigned char *buf, size_t buflen, CFMutableArrayRef array) { CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); char *certp; CURLcode result; if(!certdata) { failf(data, "SSL: failed to allocate array for CA certificate"); return CURLE_OUT_OF_MEMORY; } SecCertificateRef cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata); CFRelease(certdata); if(!cacert) { failf(data, "SSL: failed to create SecCertificate from CA certificate"); return CURLE_SSL_CACERT_BADFILE; } /* Check if cacert is valid. */ result = CopyCertSubject(data, cacert, &certp); switch(result) { case CURLE_OK: break; case CURLE_PEER_FAILED_VERIFICATION: return CURLE_SSL_CACERT_BADFILE; case CURLE_OUT_OF_MEMORY: default: return result; } free(certp); CFArrayAppendValue(array, cacert); CFRelease(cacert); return CURLE_OK; } static CURLcode verify_cert(const char *cafile, struct Curl_easy *data, SSLContextRef ctx) { int n = 0, rc; long res; unsigned char *certbuf, *der; size_t buflen, derlen, offset = 0; if(read_cert(cafile, &certbuf, &buflen) < 0) { failf(data, "SSL: failed to read or invalid CA certificate"); return CURLE_SSL_CACERT_BADFILE; } /* * Certbuf now contains the contents of the certificate file, which can be * - a single DER certificate, * - a single PEM certificate or * - a bunch of PEM certificates (certificate bundle). * * Go through certbuf, and convert any PEM certificate in it into DER * format. */ CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); if(array == NULL) { free(certbuf); failf(data, "SSL: out of memory creating CA certificate array"); return CURLE_OUT_OF_MEMORY; } while(offset < buflen) { n++; /* * Check if the certificate is in PEM format, and convert it to DER. If * this fails, we assume the certificate is in DER format. */ res = pem_to_der((const char *)certbuf + offset, &der, &derlen); if(res < 0) { free(certbuf); CFRelease(array); failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle", n, offset); return CURLE_SSL_CACERT_BADFILE; } offset += res; if(res == 0 && offset == 0) { /* This is not a PEM file, probably a certificate in DER format. */ rc = append_cert_to_array(data, certbuf, buflen, array); free(certbuf); if(rc != CURLE_OK) { CFRelease(array); return rc; } break; } else if(res == 0) { /* No more certificates in the bundle. */ free(certbuf); break; } rc = append_cert_to_array(data, der, derlen, array); free(der); if(rc != CURLE_OK) { free(certbuf); CFRelease(array); return rc; } } SecTrustRef trust; OSStatus ret = SSLCopyPeerTrust(ctx, &trust); if(trust == NULL) { failf(data, "SSL: error getting certificate chain"); CFRelease(array); return CURLE_PEER_FAILED_VERIFICATION; } else if(ret != noErr) { CFRelease(array); failf(data, "SSLCopyPeerTrust() returned error %d", ret); return CURLE_PEER_FAILED_VERIFICATION; } ret = SecTrustSetAnchorCertificates(trust, array); if(ret != noErr) { CFRelease(array); CFRelease(trust); failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret); return CURLE_PEER_FAILED_VERIFICATION; } ret = SecTrustSetAnchorCertificatesOnly(trust, true); if(ret != noErr) { CFRelease(array); CFRelease(trust); failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret); return CURLE_PEER_FAILED_VERIFICATION; } SecTrustResultType trust_eval = 0; ret = SecTrustEvaluate(trust, &trust_eval); CFRelease(array); CFRelease(trust); if(ret != noErr) { failf(data, "SecTrustEvaluate() returned error %d", ret); return CURLE_PEER_FAILED_VERIFICATION; } switch(trust_eval) { case kSecTrustResultUnspecified: case kSecTrustResultProceed: return CURLE_OK; case kSecTrustResultRecoverableTrustFailure: case kSecTrustResultDeny: default: failf(data, "SSL: certificate verification failed (result: %d)", trust_eval); return CURLE_PEER_FAILED_VERIFICATION; } } #ifdef SECTRANSP_PINNEDPUBKEY static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, SSLContextRef ctx, const char *pinnedpubkey) { /* Scratch */ size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; unsigned char *pubkey = NULL, *realpubkey = NULL; const unsigned char *spkiHeader = NULL; CFDataRef publicKeyBits = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!ctx) return result; do { SecTrustRef trust; OSStatus ret = SSLCopyPeerTrust(ctx, &trust); if(ret != noErr || trust == NULL) break; SecKeyRef keyRef = SecTrustCopyPublicKey(trust); CFRelease(trust); if(keyRef == NULL) break; #ifdef SECTRANSP_PINNEDPUBKEY_V1 publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); CFRelease(keyRef); if(publicKeyBits == NULL) break; #elif SECTRANSP_PINNEDPUBKEY_V2 OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, &publicKeyBits); CFRelease(keyRef); if(success != errSecSuccess || publicKeyBits == NULL) break; #endif /* SECTRANSP_PINNEDPUBKEY_V2 */ pubkeylen = CFDataGetLength(publicKeyBits); pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits); switch(pubkeylen) { case 526: /* 4096 bit RSA pubkeylen == 526 */ spkiHeader = rsa4096SpkiHeader; break; case 270: /* 2048 bit RSA pubkeylen == 270 */ spkiHeader = rsa2048SpkiHeader; break; #ifdef SECTRANSP_PINNEDPUBKEY_V1 case 65: /* ecDSA secp256r1 pubkeylen == 65 */ spkiHeader = ecDsaSecp256r1SpkiHeader; spkiHeaderLength = 26; break; case 97: /* ecDSA secp384r1 pubkeylen == 97 */ spkiHeader = ecDsaSecp384r1SpkiHeader; spkiHeaderLength = 23; break; default: infof(data, "SSL: unhandled public key length: %d\n", pubkeylen); #elif SECTRANSP_PINNEDPUBKEY_V2 default: /* ecDSA secp256r1 pubkeylen == 91 header already included? * ecDSA secp384r1 header already included too * we assume rest of algorithms do same, so do nothing */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, pubkeylen); #endif /* SECTRANSP_PINNEDPUBKEY_V2 */ continue; /* break from loop */ } realpubkeylen = pubkeylen + spkiHeaderLength; realpubkey = malloc(realpubkeylen); if(!realpubkey) break; memcpy(realpubkey, spkiHeader, spkiHeaderLength); memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, realpubkeylen); } while(0); Curl_safefree(realpubkey); if(publicKeyBits != NULL) CFRelease(publicKeyBits); return result; } #endif /* SECTRANSP_PINNEDPUBKEY */ static CURLcode sectransp_connect_step2(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(BACKEND->ssl_ctx); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = BACKEND->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; /* The below is errSSLServerAuthCompleted; it's not defined in Leopard's headers */ case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data, BACKEND->ssl_ctx); if(result) return result; } /* the documentation says we need to call SSLHandshake() again */ return sectransp_connect_step2(conn, sockindex); /* Problem with encrypt / decrypt */ case errSSLPeerDecodeError: failf(data, "Decode failed"); break; case errSSLDecryptionFail: case errSSLPeerDecryptionFail: failf(data, "Decryption failed"); break; case errSSLPeerDecryptError: failf(data, "A decryption error occurred"); break; case errSSLBadCipherSuite: failf(data, "A bad SSL cipher suite was encountered"); break; case errSSLCrypto: failf(data, "An underlying cryptographic error was encountered"); break; #if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 case errSSLWeakPeerEphemeralDHKey: failf(data, "Indicates a weak ephemeral Diffie-Hellman key"); break; #endif /* Problem with the message record validation */ case errSSLBadRecordMac: case errSSLPeerBadRecordMac: failf(data, "A record with a bad message authentication code (MAC) " "was encountered"); break; case errSSLRecordOverflow: case errSSLPeerRecordOverflow: failf(data, "A record overflow occurred"); break; /* Problem with zlib decompression */ case errSSLPeerDecompressFail: failf(data, "Decompression failed"); break; /* Problem with access */ case errSSLPeerAccessDenied: failf(data, "Access was denied"); break; case errSSLPeerInsufficientSecurity: failf(data, "There is insufficient security for this operation"); break; /* These are all certificate problems with the server: */ case errSSLXCertChainInvalid: failf(data, "SSL certificate problem: Invalid certificate chain"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLUnknownRootCert: failf(data, "SSL certificate problem: Untrusted root certificate"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLNoRootCert: failf(data, "SSL certificate problem: No root certificate"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLCertNotYetValid: failf(data, "SSL certificate problem: The certificate chain had a " "certificate that is not yet valid"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLCertExpired: case errSSLPeerCertExpired: failf(data, "SSL certificate problem: Certificate chain had an " "expired certificate"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLBadCert: case errSSLPeerBadCert: failf(data, "SSL certificate problem: Couldn't understand the server " "certificate format"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerUnsupportedCert: failf(data, "SSL certificate problem: An unsupported certificate " "format was encountered"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerCertRevoked: failf(data, "SSL certificate problem: The certificate was revoked"); return CURLE_PEER_FAILED_VERIFICATION; case errSSLPeerCertUnknown: failf(data, "SSL certificate problem: The certificate is unknown"); return CURLE_PEER_FAILED_VERIFICATION; /* These are all certificate problems with the client: */ case errSecAuthFailed: failf(data, "SSL authentication failed"); break; case errSSLPeerHandshakeFail: failf(data, "SSL peer handshake failed, the server most likely " "requires a client certificate to connect"); break; case errSSLPeerUnknownCA: failf(data, "SSL server rejected the client certificate due to " "the certificate being signed by an unknown certificate " "authority"); break; /* This error is raised if the server's cert didn't match the server's host name: */ case errSSLHostNameMismatch: failf(data, "SSL certificate peer verification failed, the " "certificate did not match \"%s\"\n", conn->host.dispname); return CURLE_PEER_FAILED_VERIFICATION; /* Problem with SSL / TLS negotiation */ case errSSLNegotiation: failf(data, "Could not negotiate an SSL cipher suite with the server"); break; case errSSLBadConfiguration: failf(data, "A configuration error occurred"); break; case errSSLProtocol: failf(data, "SSL protocol error"); break; case errSSLPeerProtocolVersion: failf(data, "A bad protocol version was encountered"); break; case errSSLPeerNoRenegotiation: failf(data, "No renegotiation is allowed"); break; /* Generic handshake errors: */ case errSSLConnectionRefused: failf(data, "Server dropped the connection during the SSL handshake"); break; case errSSLClosedAbort: failf(data, "Server aborted the SSL handshake"); break; case errSSLClosedGraceful: failf(data, "The connection closed gracefully"); break; case errSSLClosedNoNotify: failf(data, "The server closed the session with no notification"); break; /* Sometimes paramErr happens with buggy ciphers: */ case paramErr: case errSSLInternal: case errSSLPeerInternalError: failf(data, "Internal SSL engine error encountered during the " "SSL handshake"); break; case errSSLFatalAlert: failf(data, "Fatal SSL engine error encountered during the SSL " "handshake"); break; /* Unclassified error */ case errSSLBufferOverflow: failf(data, "An insufficient buffer was provided"); break; case errSSLIllegalParam: failf(data, "An illegal parameter was encountered"); break; case errSSLModuleAttach: failf(data, "Module attach failure"); break; case errSSLSessionNotFound: failf(data, "An attempt to restore an unknown session failed"); break; case errSSLPeerExportRestriction: failf(data, "An export restriction occurred"); break; case errSSLPeerUserCancelled: failf(data, "The user canceled the operation"); break; case errSSLPeerUnexpectedMsg: failf(data, "Peer rejected unexpected message"); break; #if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 /* Treaing non-fatal error as fatal like before */ case errSSLClientHelloReceived: failf(data, "A non-fatal result for providing a server name " "indication"); break; #endif /* Error codes defined in the enum but should never be returned. We list them here just in case. */ #if CURL_BUILD_MAC_10_6 /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */ case errSSLClientCertRequested: failf(data, "The server has requested a client certificate"); break; #endif #if CURL_BUILD_MAC_10_9 /* Alias for errSSLLast, end of error range */ case errSSLUnexpectedRecord: failf(data, "Unexpected (skipped) record in DTLS"); break; #endif default: /* May also return codes listed in Security Framework Result Codes */ failf(data, "Unknown SSL protocol error in connection to %s:%d", hostname, err); break; } return CURLE_SSL_CONNECT_ERROR; } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; #ifdef SECTRANSP_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx, data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } #endif /* SECTRANSP_PINNEDPUBKEY */ /* Informational message */ (void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(BACKEND->ssl_ctx, &protocol); switch(protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kSSLProtocol3: infof(data, "SSL 3.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kTLSProtocol1: infof(data, "TLS 1.0 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS case kTLSProtocol11: infof(data, "TLS 1.1 connection using %s\n", TLSCipherNameForNumber(cipher)); break; case kTLSProtocol12: infof(data, "TLS 1.2 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 case kTLSProtocol13: infof(data, "TLS 1.3 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ default: infof(data, "Unknown protocol connection\n"); break; } #if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 if(conn->bits.tls_enable_alpn) { if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { CFArrayRef alpnArr = NULL; CFStringRef chosenProtocol = NULL; err = SSLCopyALPNProtocols(BACKEND->ssl_ctx, &alpnArr); if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); #ifdef USE_NGHTTP2 if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(NGHTTP2_PROTO_VERSION_ID), 0)) { conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { conn->negnpn = CURL_HTTP_VERSION_1_1; } else infof(data, "ALPN, server did not agree to a protocol\n"); Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); /* chosenProtocol is a reference to the string within alpnArr and doesn't need to be freed separately */ if(alpnArr) CFRelease(alpnArr); } } #endif return CURLE_OK; } } #ifndef CURL_DISABLE_VERBOSE_STRINGS /* This should be called during step3 of the connection at the earliest */ static void show_verbose_server_cert(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CFArrayRef server_certs = NULL; SecCertificateRef server_cert; OSStatus err; CFIndex i, count; SecTrustRef trust = NULL; if(!BACKEND->ssl_ctx) return; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS #pragma unused(server_certs) err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); for(i = 0L ; i < count ; i++) { CURLcode result; char *certp; server_cert = SecTrustGetCertificateAtIndex(trust, i); result = CopyCertSubject(data, server_cert, &certp); if(!result) { infof(data, "Server certificate: %s\n", certp); free(certp); } } CFRelease(trust); } #else /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. The function SecTrustGetCertificateAtIndex() is officially present in Lion, but it is unfortunately also present in Snow Leopard as private API and doesn't work as expected. So we have to look for a different symbol to make sure this code is only executed under Lion or later. */ if(SecTrustEvaluateAsync != NULL) { #pragma unused(server_certs) err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); for(i = 0L ; i < count ; i++) { char *certp; CURLcode result; server_cert = SecTrustGetCertificateAtIndex(trust, i); result = CopyCertSubject(data, server_cert, &certp); if(!result) { infof(data, "Server certificate: %s\n", certp); free(certp); } } CFRelease(trust); } } else { #if CURL_SUPPORT_MAC_10_8 err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); /* Just in case SSLCopyPeerCertificates() returns null too... */ if(err == noErr && server_certs) { count = CFArrayGetCount(server_certs); for(i = 0L ; i < count ; i++) { char *certp; CURLcode result; server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); result = CopyCertSubject(data, server_cert, &certp); if(!result) { infof(data, "Server certificate: %s\n", certp); free(certp); } } CFRelease(server_certs); } #endif /* CURL_SUPPORT_MAC_10_8 */ } #endif /* CURL_BUILD_IOS */ #else #pragma unused(trust) err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); for(i = 0L ; i < count ; i++) { CURLcode result; char *certp; server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); result = CopyCertSubject(data, server_cert, &certp); if(!result) { infof(data, "Server certificate: %s\n", certp); free(certp); } } CFRelease(server_certs); } #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ } #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ static CURLcode sectransp_connect_step3(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* There is no step 3! * Well, okay, if verbose mode is on, let's print the details of the * server certificates. */ #ifndef CURL_DISABLE_VERBOSE_STRINGS if(data->set.verbose) show_verbose_server_cert(conn, sockindex); #endif connssl->connecting_state = ssl_connect_done; return CURLE_OK; } static Curl_recv sectransp_recv; static Curl_send sectransp_send; static CURLcode sectransp_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; timediff_t timeout_ms; int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } if(ssl_connect_1 == connssl->connecting_state) { /* Find out how much more time we're allowed */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } result = sectransp_connect_step1(conn, sockindex); if(result) return result; } while(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* no need to continue if time already is up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } /* if ssl is expecting something, check if it's available. */ if(connssl->connecting_state == ssl_connect_2_reading || connssl->connecting_state == ssl_connect_2_writing) { curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0:(time_t)timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } else if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } else { /* timeout */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } } /* socket is readable or writable */ } /* Run transaction, and return to the caller if it failed or if this * connection is done nonblocking and this loop would execute again. This * permits the owner of a multi handle to abort a connection attempt * before step2 has completed while ensuring that a client using select() * or epoll() will always have a valid fdset to wait on. */ result = sectransp_connect_step2(conn, sockindex); if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state))) return result; } /* repeat step2 until all transactions are done. */ if(ssl_connect_3 == connssl->connecting_state) { result = sectransp_connect_step3(conn, sockindex); if(result) return result; } if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; conn->recv[sockindex] = sectransp_recv; conn->send[sockindex] = sectransp_send; *done = TRUE; } else *done = FALSE; /* Reset our connect state machine */ connssl->connecting_state = ssl_connect_1; return CURLE_OK; } static CURLcode Curl_sectransp_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { return sectransp_connect_common(conn, sockindex, TRUE, done); } static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex) { CURLcode result; bool done = FALSE; result = sectransp_connect_common(conn, sockindex, FALSE, &done); if(result) return result; DEBUGASSERT(done); return CURLE_OK; } static void Curl_sectransp_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(BACKEND->ssl_ctx) { (void)SSLClose(BACKEND->ssl_ctx); #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLCreateContext != NULL) CFRelease(BACKEND->ssl_ctx); #if CURL_SUPPORT_MAC_10_8 else (void)SSLDisposeContext(BACKEND->ssl_ctx); #endif /* CURL_SUPPORT_MAC_10_8 */ #else (void)SSLDisposeContext(BACKEND->ssl_ctx); #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ BACKEND->ssl_ctx = NULL; } BACKEND->ssl_sockfd = 0; } static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; char buf[120]; if(!BACKEND->ssl_ctx) return 0; #ifndef CURL_DISABLE_FTP if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; #endif Curl_sectransp_close(conn, sockindex); rc = 0; what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); rc = -1; break; } if(!what) { /* timeout */ failf(data, "SSL shutdown timeout"); break; } /* Something to read, let's do it and hope that it is the close notify alert from the server. No way to SSL_Read now, so use read(). */ nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { failf(data, "read: %s", strerror(errno)); rc = -1; } if(nread <= 0) break; what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; } static void Curl_sectransp_session_free(void *ptr) { /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a cached session ID inside the Security framework. There is a private function that does this, but I don't want to have to explain to you why I got your application rejected from the App Store due to the use of a private API, so the best we can do is free up our own char array that we created way back in sectransp_connect_step1... */ Curl_safefree(ptr); } static size_t Curl_sectransp_version(char *buffer, size_t size) { return msnprintf(buffer, size, "SecureTransport"); } /* * This function uses SSLGetSessionState to determine connection status. * * Return codes: * 1 means the connection is still in place * 0 means the connection has been closed * -1 means the connection status is unknown */ static int Curl_sectransp_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; OSStatus err; SSLSessionState state; if(BACKEND->ssl_ctx) { err = SSLGetSessionState(BACKEND->ssl_ctx, &state); if(err == noErr) return state == kSSLConnected || state == kSSLHandshake; return -1; } return 0; } static bool Curl_sectransp_data_pending(const struct connectdata *conn, int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; OSStatus err; size_t buffer; if(BACKEND->ssl_ctx) { /* SSL is in use */ err = SSLGetBufferedReadSize(BACKEND->ssl_ctx, &buffer); if(err == noErr) return buffer > 0UL; return false; } else return false; } static CURLcode Curl_sectransp_random(struct Curl_easy *data UNUSED_PARAM, unsigned char *entropy, size_t length) { /* arc4random_buf() isn't available on cats older than Lion, so let's do this manually for the benefit of the older cats. */ size_t i; u_int32_t random_number = 0; (void)data; for(i = 0 ; i < length ; i++) { if(i % sizeof(u_int32_t) == 0) random_number = arc4random(); entropy[i] = random_number & 0xFF; random_number >>= 8; } i = random_number = 0; return CURLE_OK; } static CURLcode Curl_sectransp_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len) { (void)md5len; (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); return CURLE_OK; } static CURLcode Curl_sectransp_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len) { assert(sha256len >= CURL_SHA256_DIGEST_LENGTH); (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); return CURLE_OK; } static bool Curl_sectransp_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 if(SSLSetSessionOption != NULL) return TRUE; #endif return FALSE; } static ssize_t sectransp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; size_t processed = 0UL; OSStatus err; /* The SSLWrite() function works a little differently than expected. The fourth argument (processed) is currently documented in Apple's documentation as: "On return, the length, in bytes, of the data actually written." Now, one could interpret that as "written to the socket," but actually, it returns the amount of data that was written to a buffer internal to the SSLContextRef instead. So it's possible for SSLWrite() to return errSSLWouldBlock and a number of bytes "written" because those bytes were encrypted and written to a buffer, not to the socket. So if this happens, then we need to keep calling SSLWrite() over and over again with no new data until it quits returning errSSLWouldBlock. */ /* Do we have buffered data to write from the last time we were called? */ if(BACKEND->ssl_write_buffered_length) { /* Write the buffered data: */ err = SSLWrite(BACKEND->ssl_ctx, NULL, 0UL, &processed); switch(err) { case noErr: /* processed is always going to be 0 because we didn't write to the buffer, so return how much was written to the socket */ processed = BACKEND->ssl_write_buffered_length; BACKEND->ssl_write_buffered_length = 0UL; break; case errSSLWouldBlock: /* argh, try again */ *curlcode = CURLE_AGAIN; return -1L; default: failf(conn->data, "SSLWrite() returned error %d", err); *curlcode = CURLE_SEND_ERROR; return -1L; } } else { /* We've got new data to write: */ err = SSLWrite(BACKEND->ssl_ctx, mem, len, &processed); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* Data was buffered but not sent, we have to tell the caller to try sending again, and remember how much was buffered */ BACKEND->ssl_write_buffered_length = len; *curlcode = CURLE_AGAIN; return -1L; default: failf(conn->data, "SSLWrite() returned error %d", err); *curlcode = CURLE_SEND_ERROR; return -1L; } } } return (ssize_t)processed; } static ssize_t sectransp_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; size_t processed = 0UL; OSStatus err; again: err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* return how much we read (if anything) */ if(processed) return (ssize_t)processed; *curlcode = CURLE_AGAIN; return -1L; break; /* errSSLClosedGraceful - server gracefully shut down the SSL session errSSLClosedNoNotify - server hung up on us instead of sending a closure alert notice, read() is returning 0 Either way, inform the caller that the server disconnected. */ case errSSLClosedGraceful: case errSSLClosedNoNotify: *curlcode = CURLE_OK; return -1L; break; /* The below is errSSLPeerAuthCompleted; it's not defined in Leopard's headers */ case -9841: if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), conn->data, BACKEND->ssl_ctx); if(result) return result; } goto again; default: failf(conn->data, "SSLRead() return error %d", err); *curlcode = CURLE_RECV_ERROR; return -1L; break; } } return (ssize_t)processed; } static void *Curl_sectransp_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { (void)info; return BACKEND->ssl_ctx; } const struct Curl_ssl Curl_ssl_sectransp = { { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */ #ifdef SECTRANSP_PINNEDPUBKEY SSLSUPP_PINNEDPUBKEY, #else 0, #endif /* SECTRANSP_PINNEDPUBKEY */ sizeof(struct ssl_backend_data), Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ Curl_sectransp_version, /* version */ Curl_sectransp_check_cxn, /* check_cxn */ Curl_sectransp_shutdown, /* shutdown */ Curl_sectransp_data_pending, /* data_pending */ Curl_sectransp_random, /* random */ Curl_none_cert_status_request, /* cert_status_request */ Curl_sectransp_connect, /* connect */ Curl_sectransp_connect_nonblocking, /* connect_nonblocking */ Curl_sectransp_get_internals, /* get_internals */ Curl_sectransp_close, /* close_one */ Curl_none_close_all, /* close_all */ Curl_sectransp_session_free, /* session_free */ Curl_none_set_engine, /* set_engine */ Curl_none_set_engine_default, /* set_engine_default */ Curl_none_engines_list, /* engines_list */ Curl_sectransp_false_start, /* false_start */ Curl_sectransp_md5sum, /* md5sum */ Curl_sectransp_sha256sum /* sha256sum */ }; #ifdef __clang__ #pragma clang diagnostic pop #endif #endif /* USE_SECTRANSP */ davix-0.8.0/deps/curl/lib/hostip6.c0000644000000000000000000001312514121063461015536 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /*********************************************************************** * Only for IPv6-enabled builds **********************************************************************/ #ifdef CURLRES_IPV6 #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_PROCESS_H #include #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" #include "inet_pton.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ bool Curl_ipv6works(struct connectdata *conn) { if(conn) { /* the nature of most system is that IPv6 status doesn't come and go during a program's lifetime so we only probe the first time and then we have the info kept for fast re-use */ DEBUGASSERT(conn); DEBUGASSERT(conn->data); DEBUGASSERT(conn->data->multi); return conn->data->multi->ipv6_works; } else { int ipv6_works = -1; /* probe to see if we have a working IPv6 stack */ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); if(s == CURL_SOCKET_BAD) /* an IPv6 address was requested but we can't get/use one */ ipv6_works = 0; else { ipv6_works = 1; Curl_closesocket(NULL, s); } return (ipv6_works>0)?TRUE:FALSE; } } /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) return Curl_ipv6works(conn); return TRUE; } #if defined(CURLRES_SYNCH) #ifdef DEBUG_ADDRINFO static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) { printf("dump_addrinfo:\n"); for(; ai; ai = ai->ai_next) { char buf[INET6_ADDRSTRLEN]; printf(" fam %2d, CNAME %s, ", ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); if(Curl_printable_address(ai, buf, sizeof(buf))) printf("%s\n", buf); else { char buffer[STRERROR_LEN]; printf("failed; %s\n", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); } } } #else #define dump_addrinfo(x,y) Curl_nop_stmt #endif /* * Curl_getaddrinfo() when built IPv6-enabled (non-threading and * non-ares version). * * Returns name information about the given hostname and port number. If * successful, the 'addrinfo' is returned and the forth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { struct addrinfo hints; Curl_addrinfo *res; int error; char sbuf[12]; char *sbufptr = NULL; #ifndef USE_RESOLVE_ON_IPS char addrbuf[128]; #endif int pf; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) struct Curl_easy *data = conn->data; #endif *waitp = 0; /* synchronous response only */ /* Check if a limited name resolve has been requested */ switch(conn->ip_version) { case CURL_IPRESOLVE_V4: pf = PF_INET; break; case CURL_IPRESOLVE_V6: pf = PF_INET6; break; default: pf = PF_UNSPEC; break; } if((pf != PF_INET) && !Curl_ipv6works(conn)) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; hints.ai_socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; #ifndef USE_RESOLVE_ON_IPS /* * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from * an IPv4 address on iOS and Mac OS X. */ if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { /* the given address is numerical only, prevent a reverse lookup */ hints.ai_flags = AI_NUMERICHOST; } #endif if(port) { msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res); if(error) { infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port); return NULL; } if(port) { Curl_addrinfo_set_port(res, port); } dump_addrinfo(conn, res); return res; } #endif /* CURLRES_SYNCH */ #endif /* CURLRES_IPV6 */ davix-0.8.0/deps/curl/lib/smtp.h0000644000000000000000000000761314121063461015137 0ustar rootroot#ifndef HEADER_CURL_SMTP_H #define HEADER_CURL_SMTP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2009 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "pingpong.h" #include "curl_sasl.h" /**************************************************************************** * SMTP unique setup ***************************************************************************/ typedef enum { SMTP_STOP, /* do nothing state, stops the state machine */ SMTP_SERVERGREET, /* waiting for the initial greeting immediately after a connect */ SMTP_EHLO, SMTP_HELO, SMTP_STARTTLS, SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ SMTP_AUTH, SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */ SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ SMTP_DATA, SMTP_POSTDATA, SMTP_QUIT, SMTP_LAST /* never used */ } smtpstate; /* This SMTP struct is used in the Curl_easy. All SMTP data that is connection-oriented must be in smtp_conn to properly deal with the fact that perhaps the Curl_easy is changed between the times the connection is used. */ struct SMTP { curl_pp_transfer transfer; char *custom; /* Custom Request */ struct curl_slist *rcpt; /* Recipient list */ bool rcpt_had_ok; /* Whether any of RCPT TO commands (depends on total number of recipients) succeeded so far */ int rcpt_last_error; /* The last error received for RCPT TO command */ size_t eob; /* Number of bytes of the EOB (End Of Body) that have been received so far */ bool trailing_crlf; /* Specifies if the tailing CRLF is present */ }; /* smtp_conn is used for struct connection-oriented data in the connectdata struct */ struct smtp_conn { struct pingpong pp; smtpstate state; /* Always use smtp.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ char *domain; /* Client address/name to send in the EHLO */ struct SASL sasl; /* SASL-related storage */ bool tls_supported; /* StartTLS capability supported by server */ bool size_supported; /* If server supports SIZE extension according to RFC 1870 */ bool utf8_supported; /* If server supports SMTPUTF8 extension according to RFC 6531 */ bool auth_supported; /* AUTH capability supported by server */ }; extern const struct Curl_handler Curl_handler_smtp; extern const struct Curl_handler Curl_handler_smtps; /* this is the 5-bytes End-Of-Body marker for SMTP */ #define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a" #define SMTP_EOB_LEN 5 #define SMTP_EOB_FIND_LEN 3 /* if found in data, replace it with this string instead */ #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" #define SMTP_EOB_REPL_LEN 4 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread); #endif /* HEADER_CURL_SMTP_H */ davix-0.8.0/deps/curl/lib/strdup.h0000644000000000000000000000245114121063461015470 0ustar rootroot#ifndef HEADER_CURL_STRDUP_H #define HEADER_CURL_STRDUP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif void *Curl_memdup(const void *src, size_t buffer_length); void *Curl_saferealloc(void *ptr, size_t size); #endif /* HEADER_CURL_STRDUP_H */ davix-0.8.0/deps/curl/lib/hostip4.c0000644000000000000000000002360114121063461015534 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /*********************************************************************** * Only for plain IPv4 builds **********************************************************************/ #ifdef CURLRES_IPV4 /* plain IPv4 code coming up */ #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __VMS #include #include #endif #ifdef HAVE_PROCESS_H #include #endif #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "strerror.h" #include "url.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ bool Curl_ipvalid(struct connectdata *conn) { if(conn->ip_version == CURL_IPRESOLVE_V6) /* An IPv6 address was requested and we can't get/use one */ return FALSE; return TRUE; /* OK, proceed */ } #ifdef CURLRES_SYNCH /* * Curl_getaddrinfo() - the IPv4 synchronous version. * * The original code to this function was from the Dancer source code, written * by Bjorn Reese, it has since been patched and modified considerably. * * gethostbyname_r() is the thread-safe version of the gethostbyname() * function. When we build for plain IPv4, we attempt to use this * function. There are _three_ different gethostbyname_r() versions, and we * detect which one this platform supports in the configure script and set up * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME * has the corresponding rules. This is primarily on *nix. Note that some unix * flavours have thread-safe versions of the plain gethostbyname() etc. * */ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, const char *hostname, int port, int *waitp) { Curl_addrinfo *ai = NULL; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)conn; #endif *waitp = 0; /* synchronous response only */ ai = Curl_ipv4_resolve_r(hostname, port); if(!ai) infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname); return ai; } #endif /* CURLRES_SYNCH */ #endif /* CURLRES_IPV4 */ #if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) /* * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. * * This is used for both synchronous and asynchronous resolver builds, * implying that only threadsafe code and function calls may be used. * */ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port) { #if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3) int res; #endif Curl_addrinfo *ai = NULL; struct hostent *h = NULL; struct hostent *buf = NULL; #if defined(HAVE_GETADDRINFO_THREADSAFE) struct addrinfo hints; char sbuf[12]; char *sbufptr = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; if(port) { msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai); #elif defined(HAVE_GETHOSTBYNAME_R) /* * gethostbyname_r() is the preferred resolve function for many platforms. * Since there are three different versions of it, the following code is * somewhat #ifdef-ridden. */ int h_errnop; buf = calloc(1, CURL_HOSTENT_SIZE); if(!buf) return NULL; /* major failure */ /* * The clearing of the buffer is a workaround for a gethostbyname_r bug in * qnx nto and it is also _required_ for some of these functions on some * platforms. */ #if defined(HAVE_GETHOSTBYNAME_R_5) /* Solaris, IRIX and more */ h = gethostbyname_r(hostname, (struct hostent *)buf, (char *)buf + sizeof(struct hostent), CURL_HOSTENT_SIZE - sizeof(struct hostent), &h_errnop); /* If the buffer is too small, it returns NULL and sets errno to * ERANGE. The errno is thread safe if this is compiled with * -D_REENTRANT as then the 'errno' variable is a macro defined to get * used properly for threads. */ if(h) { ; } else #elif defined(HAVE_GETHOSTBYNAME_R_6) /* Linux */ (void)gethostbyname_r(hostname, (struct hostent *)buf, (char *)buf + sizeof(struct hostent), CURL_HOSTENT_SIZE - sizeof(struct hostent), &h, /* DIFFERENCE */ &h_errnop); /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a * sudden this function returns EAGAIN if the given buffer size is too * small. Previous versions are known to return ERANGE for the same * problem. * * This wouldn't be such a big problem if older versions wouldn't * sometimes return EAGAIN on a common failure case. Alas, we can't * assume that EAGAIN *or* ERANGE means ERANGE for any given version of * glibc. * * For now, we do that and thus we may call the function repeatedly and * fail for older glibc versions that return EAGAIN, until we run out of * buffer size (step_size grows beyond CURL_HOSTENT_SIZE). * * If anyone has a better fix, please tell us! * * ------------------------------------------------------------------- * * On October 23rd 2003, Dan C dug up more details on the mysteries of * gethostbyname_r() in glibc: * * In glibc 2.2.5 the interface is different (this has also been * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32 * (shipped/upgraded by Redhat 7.2) don't show this behavior! * * In this "buggy" version, the return code is -1 on error and 'errno' * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a * thread-safe variable. */ if(!h) /* failure */ #elif defined(HAVE_GETHOSTBYNAME_R_3) /* AIX, Digital Unix/Tru64, HPUX 10, more? */ /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of * the plain fact that it does not return unique full buffers on each * call, but instead several of the pointers in the hostent structs will * point to the same actual data! This have the unfortunate down-side that * our caching system breaks down horribly. Luckily for us though, AIX 4.3 * and more recent versions have a "completely thread-safe"[*] libc where * all the data is stored in thread-specific memory areas making calls to * the plain old gethostbyname() work fine even for multi-threaded * programs. * * This AIX 4.3 or later detection is all made in the configure script. * * Troels Walsted Hansen helped us work this out on March 3rd, 2003. * * [*] = much later we've found out that it isn't at all "completely * thread-safe", but at least the gethostbyname() function is. */ if(CURL_HOSTENT_SIZE >= (sizeof(struct hostent) + sizeof(struct hostent_data))) { /* August 22nd, 2000: Albert Chin-A-Young brought an updated version * that should work! September 20: Richard Prescott worked on the buffer * size dilemma. */ res = gethostbyname_r(hostname, (struct hostent *)buf, (struct hostent_data *)((char *)buf + sizeof(struct hostent))); h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */ } else res = -1; /* failure, too smallish buffer size */ if(!res) { /* success */ h = buf; /* result expected in h */ /* This is the worst kind of the different gethostbyname_r() interfaces. * Since we don't know how big buffer this particular lookup required, * we can't realloc down the huge alloc without doing closer analysis of * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every * name lookup. Fixing this would require an extra malloc() and then * calling Curl_addrinfo_copy() that subsequent realloc()s down the new * memory area to the actually used amount. */ } else #endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */ { h = NULL; /* set return code to NULL */ free(buf); } #else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ /* * Here is code for platforms that don't have a thread safe * getaddrinfo() nor gethostbyname_r() function or for which * gethostbyname() is the preferred one. */ h = gethostbyname((void *)hostname); #endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ if(h) { ai = Curl_he2ai(h, port); if(buf) /* used a *_r() function */ free(buf); } return ai; } #endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */ davix-0.8.0/deps/curl/lib/pop3.h0000644000000000000000000000712114121063461015027 0ustar rootroot#ifndef HEADER_CURL_POP3_H #define HEADER_CURL_POP3_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2009 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "pingpong.h" #include "curl_sasl.h" /**************************************************************************** * POP3 unique setup ***************************************************************************/ typedef enum { POP3_STOP, /* do nothing state, stops the state machine */ POP3_SERVERGREET, /* waiting for the initial greeting immediately after a connect */ POP3_CAPA, POP3_STARTTLS, POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ POP3_AUTH, POP3_APOP, POP3_USER, POP3_PASS, POP3_COMMAND, POP3_QUIT, POP3_LAST /* never used */ } pop3state; /* This POP3 struct is used in the Curl_easy. All POP3 data that is connection-oriented must be in pop3_conn to properly deal with the fact that perhaps the Curl_easy is changed between the times the connection is used. */ struct POP3 { curl_pp_transfer transfer; char *id; /* Message ID */ char *custom; /* Custom Request */ }; /* pop3_conn is used for struct connection-oriented data in the connectdata struct */ struct pop3_conn { struct pingpong pp; pop3state state; /* Always use pop3.c:state() to change state! */ bool ssldone; /* Is connect() over SSL done? */ size_t eob; /* Number of bytes of the EOB (End Of Body) that have been received so far */ size_t strip; /* Number of bytes from the start to ignore as non-body */ struct SASL sasl; /* SASL-related storage */ unsigned int authtypes; /* Accepted authentication types */ unsigned int preftype; /* Preferred authentication type */ char *apoptimestamp; /* APOP timestamp from the server greeting */ bool tls_supported; /* StartTLS capability supported by server */ }; extern const struct Curl_handler Curl_handler_pop3; extern const struct Curl_handler Curl_handler_pop3s; /* Authentication type flags */ #define POP3_TYPE_CLEARTEXT (1 << 0) #define POP3_TYPE_APOP (1 << 1) #define POP3_TYPE_SASL (1 << 2) /* Authentication type values */ #define POP3_TYPE_NONE 0 #define POP3_TYPE_ANY ~0U /* This is the 5-bytes End-Of-Body marker for POP3 */ #define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" #define POP3_EOB_LEN 5 /* This function scans the body after the end-of-body and writes everything * until the end is found */ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread); #endif /* HEADER_CURL_POP3_H */ davix-0.8.0/deps/curl/lib/mime.c0000644000000000000000000014365214121063461015102 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "mime.h" #include "non-ascii.h" #include "urldata.h" #include "sendf.h" #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include #endif #include "rand.h" #include "slist.h" #include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifdef WIN32 # ifndef R_OK # define R_OK 4 # endif #endif #define READ_ERROR ((size_t) -1) /* Encoders. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static curl_off_t encoder_nop_size(curl_mimepart *part); static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static curl_off_t encoder_base64_size(curl_mimepart *part); static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static curl_off_t encoder_qp_size(curl_mimepart *part); static const mime_encoder encoders[] = { {"binary", encoder_nop_read, encoder_nop_size}, {"8bit", encoder_nop_read, encoder_nop_size}, {"7bit", encoder_7bit_read, encoder_nop_size}, {"base64", encoder_base64_read, encoder_base64_size}, {"quoted-printable", encoder_qp_read, encoder_qp_size}, {ZERO_NULL, ZERO_NULL, ZERO_NULL} }; /* Base64 encoding table */ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Quoted-printable character class table. * * We cannot rely on ctype functions since quoted-printable input data * is assumed to be ascii-compatible, even on non-ascii platforms. */ #define QP_OK 1 /* Can be represented by itself. */ #define QP_SP 2 /* Space or tab. */ #define QP_CR 3 /* Carriage return. */ #define QP_LF 4 /* Line-feed. */ static const unsigned char qp_class[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ }; /* Binary --> hexadecimal ASCII table. */ static const char aschex[] = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46"; #ifndef __VMS #define filesize(name, stat_data) (stat_data.st_size) #define fopen_read fopen #else #include /* * get_vms_file_size does what it takes to get the real size of the file * * For fixed files, find out the size of the EOF block and adjust. * * For all others, have to read the entire file in, discarding the contents. * Most posted text files will be small, and binary files like zlib archives * and CD/DVD images should be either a STREAM_LF format or a fixed format. * */ curl_off_t VmsRealFileSize(const char *name, const struct_stat *stat_buf) { char buffer[8192]; curl_off_t count; int ret_stat; FILE * file; file = fopen(name, FOPEN_READTEXT); /* VMS */ if(file == NULL) return 0; count = 0; ret_stat = 1; while(ret_stat > 0) { ret_stat = fread(buffer, 1, sizeof(buffer), file); if(ret_stat != 0) count += ret_stat; } fclose(file); return count; } /* * * VmsSpecialSize checks to see if the stat st_size can be trusted and * if not to call a routine to get the correct size. * */ static curl_off_t VmsSpecialSize(const char *name, const struct_stat *stat_buf) { switch(stat_buf->st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: return VmsRealFileSize(name, stat_buf); break; default: return stat_buf->st_size; } } #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) /* * vmsfopenread * * For upload to work as expected on VMS, different optional * parameters must be added to the fopen command based on * record format of the file. * */ static FILE * vmsfopenread(const char *file, const char *mode) { struct_stat statbuf; int result; result = stat(file, &statbuf); switch(statbuf.st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: return fopen(file, FOPEN_READTEXT); /* VMS */ break; default: return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); } } #define fopen_read vmsfopenread #endif #ifndef HAVE_BASENAME /* (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition) The basename() function shall take the pathname pointed to by path and return a pointer to the final component of the pathname, deleting any trailing '/' characters. If the string pointed to by path consists entirely of the '/' character, basename() shall return a pointer to the string "/". If the string pointed to by path is exactly "//", it is implementation-defined whether '/' or "//" is returned. If path is a null pointer or points to an empty string, basename() shall return a pointer to the string ".". The basename() function may modify the string pointed to by path, and may return a pointer to static storage that may then be overwritten by a subsequent call to basename(). The basename() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe. */ static char *Curl_basename(char *path) { /* Ignore all the details above for now and make a quick and simple implementation here */ char *s1; char *s2; s1 = strrchr(path, '/'); s2 = strrchr(path, '\\'); if(s1 && s2) { path = (s1 > s2? s1 : s2) + 1; } else if(s1) path = s1 + 1; else if(s2) path = s2 + 1; return path; } #define basename(x) Curl_basename((x)) #endif /* Set readback state. */ static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr) { state->state = tok; state->ptr = ptr; state->offset = 0; } /* Escape header string into allocated memory. */ static char *escape_string(const char *src) { size_t bytecount = 0; size_t i; char *dst; for(i = 0; src[i]; i++) if(src[i] == '"' || src[i] == '\\') bytecount++; bytecount += i; dst = malloc(bytecount + 1); if(!dst) return NULL; for(i = 0; *src; src++) { if(*src == '"' || *src == '\\') dst[i++] = '\\'; dst[i++] = *src; } dst[i] = '\0'; return dst; } /* Check if header matches. */ static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len) { char *value = NULL; if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':') for(value = hdr->data + len + 1; *value == ' '; value++) ; return value; } /* Get a header from an slist. */ static char *search_header(struct curl_slist *hdrlist, const char *hdr) { size_t len = strlen(hdr); char *value = NULL; for(; !value && hdrlist; hdrlist = hdrlist->next) value = match_header(hdrlist, hdr, len); return value; } static char *strippath(const char *fullfile) { char *filename; char *base; filename = strdup(fullfile); /* duplicate since basename() may ruin the buffer it works on */ if(!filename) return NULL; base = strdup(basename(filename)); free(filename); /* free temporary buffer */ return base; /* returns an allocated string or NULL ! */ } /* Initialize data encoder state. */ static void cleanup_encoder_state(mime_encoder_state *p) { p->pos = 0; p->bufbeg = 0; p->bufend = 0; } /* Dummy encoder. This is used for 8bit and binary content encodings. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { mime_encoder_state *st = &part->encstate; size_t insize = st->bufend - st->bufbeg; (void) ateof; if(size > insize) size = insize; if(size) memcpy(buffer, st->buf, size); st->bufbeg += size; return size; } static curl_off_t encoder_nop_size(curl_mimepart *part) { return part->datasize; } /* 7bit encoder: the encoder is just a data validity check. */ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { mime_encoder_state *st = &part->encstate; size_t cursize = st->bufend - st->bufbeg; (void) ateof; if(size > cursize) size = cursize; for(cursize = 0; cursize < size; cursize++) { *buffer = st->buf[st->bufbeg]; if(*buffer++ & 0x80) return cursize? cursize: READ_ERROR; st->bufbeg++; } return cursize; } /* Base64 content encoder. */ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { mime_encoder_state *st = &part->encstate; size_t cursize = 0; int i; char *ptr = buffer; while(st->bufbeg < st->bufend) { /* Line full ? */ if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) { /* Yes, we need 2 characters for CRLF. */ if(size < 2) break; *ptr++ = '\r'; *ptr++ = '\n'; st->pos = 0; cursize += 2; size -= 2; } /* Be sure there is enough space and input data for a base64 group. */ if(size < 4 || st->bufend - st->bufbeg < 3) break; /* Encode three bytes as four characters. */ i = st->buf[st->bufbeg++] & 0xFF; i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF); *ptr++ = base64[(i >> 18) & 0x3F]; *ptr++ = base64[(i >> 12) & 0x3F]; *ptr++ = base64[(i >> 6) & 0x3F]; *ptr++ = base64[i & 0x3F]; cursize += 4; st->pos += 4; size -= 4; } /* If at eof, we have to flush the buffered data. */ if(ateof && size >= 4) { /* Buffered data size can only be 0, 1 or 2. */ ptr[2] = ptr[3] = '='; i = 0; switch(st->bufend - st->bufbeg) { case 2: i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; /* FALLTHROUGH */ case 1: i |= (st->buf[st->bufbeg] & 0xFF) << 16; ptr[0] = base64[(i >> 18) & 0x3F]; ptr[1] = base64[(i >> 12) & 0x3F]; if(++st->bufbeg != st->bufend) { ptr[2] = base64[(i >> 6) & 0x3F]; st->bufbeg++; } cursize += 4; st->pos += 4; break; } } #ifdef CURL_DOES_CONVERSIONS /* This is now textual data, Convert character codes. */ if(part->easy && cursize) { CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize); if(result) return READ_ERROR; } #endif return cursize; } static curl_off_t encoder_base64_size(curl_mimepart *part) { curl_off_t size = part->datasize; if(size <= 0) return size; /* Unknown size or no data. */ /* Compute base64 character count. */ size = 4 * (1 + (size - 1) / 3); /* Effective character count must include CRLFs. */ return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH); } /* Quoted-printable lookahead. * * Check if a CRLF or end of data is in input buffer at current position + n. * Return -1 if more data needed, 1 if CRLF or end of data, else 0. */ static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n) { n += st->bufbeg; if(n >= st->bufend && ateof) return 1; if(n + 2 > st->bufend) return ateof? 0: -1; if(qp_class[st->buf[n] & 0xFF] == QP_CR && qp_class[st->buf[n + 1] & 0xFF] == QP_LF) return 1; return 0; } /* Quoted-printable encoder. */ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, curl_mimepart *part) { mime_encoder_state *st = &part->encstate; char *ptr = buffer; size_t cursize = 0; int softlinebreak; char buf[4]; /* On all platforms, input is supposed to be ASCII compatible: for this reason, we use hexadecimal ASCII codes in this function rather than character constants that can be interpreted as non-ascii on some platforms. Preserve ASCII encoding on output too. */ while(st->bufbeg < st->bufend) { size_t len = 1; size_t consumed = 1; int i = st->buf[st->bufbeg]; buf[0] = (char) i; buf[1] = aschex[(i >> 4) & 0xF]; buf[2] = aschex[i & 0xF]; switch(qp_class[st->buf[st->bufbeg] & 0xFF]) { case QP_OK: /* Not a special character. */ break; case QP_SP: /* Space or tab. */ /* Spacing must be escaped if followed by CRLF. */ switch(qp_lookahead_eol(st, ateof, 1)) { case -1: /* More input data needed. */ return cursize; case 0: /* No encoding needed. */ break; default: /* CRLF after space or tab. */ buf[0] = '\x3D'; /* '=' */ len = 3; break; } break; case QP_CR: /* Carriage return. */ /* If followed by a line-feed, output the CRLF pair. Else escape it. */ switch(qp_lookahead_eol(st, ateof, 0)) { case -1: /* Need more data. */ return cursize; case 1: /* CRLF found. */ buf[len++] = '\x0A'; /* Append '\n'. */ consumed = 2; break; default: /* Not followed by LF: escape. */ buf[0] = '\x3D'; /* '=' */ len = 3; break; } break; default: /* Character must be escaped. */ buf[0] = '\x3D'; /* '=' */ len = 3; break; } /* Be sure the encoded character fits within maximum line length. */ if(buf[len - 1] != '\x0A') { /* '\n' */ softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH; if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) { /* We may use the current line only if end of data or followed by a CRLF. */ switch(qp_lookahead_eol(st, ateof, consumed)) { case -1: /* Need more data. */ return cursize; break; case 0: /* Not followed by a CRLF. */ softlinebreak = 1; break; } } if(softlinebreak) { strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */ len = 3; consumed = 0; } } /* If the output buffer would overflow, do not store. */ if(len > size) break; /* Append to output buffer. */ memcpy(ptr, buf, len); cursize += len; ptr += len; size -= len; st->pos += len; if(buf[len - 1] == '\x0A') /* '\n' */ st->pos = 0; st->bufbeg += consumed; } return cursize; } static curl_off_t encoder_qp_size(curl_mimepart *part) { /* Determining the size can only be done by reading the data: unless the data size is 0, we return it as unknown (-1). */ return part->datasize? -1: 0; } /* In-memory data callbacks. */ /* Argument is a pointer to the mime part. */ static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; size_t sz = (size_t) part->datasize - part->state.offset; (void) size; /* Always 1.*/ if(sz > nitems) sz = nitems; if(sz) memcpy(buffer, (char *) &part->data[part->state.offset], sz); part->state.offset += sz; return sz; } static int mime_mem_seek(void *instream, curl_off_t offset, int whence) { curl_mimepart *part = (curl_mimepart *) instream; switch(whence) { case SEEK_CUR: offset += part->state.offset; break; case SEEK_END: offset += part->datasize; break; } if(offset < 0 || offset > part->datasize) return CURL_SEEKFUNC_FAIL; part->state.offset = (size_t) offset; return CURL_SEEKFUNC_OK; } static void mime_mem_free(void *ptr) { Curl_safefree(((curl_mimepart *) ptr)->data); } /* Named file callbacks. */ /* Argument is a pointer to the mime part. */ static int mime_open_file(curl_mimepart * part) { /* Open a MIMEKIND_FILE part. */ if(part->fp) return 0; part->fp = fopen_read(part->data, "rb"); return part->fp? 0: -1; } static size_t mime_file_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; if(mime_open_file(part)) return READ_ERROR; return fread(buffer, size, nitems, part->fp); } static int mime_file_seek(void *instream, curl_off_t offset, int whence) { curl_mimepart *part = (curl_mimepart *) instream; if(whence == SEEK_SET && !offset && !part->fp) return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */ if(mime_open_file(part)) return CURL_SEEKFUNC_FAIL; return fseek(part->fp, (long) offset, whence)? CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK; } static void mime_file_free(void *ptr) { curl_mimepart *part = (curl_mimepart *) ptr; if(part->fp) { fclose(part->fp); part->fp = NULL; } Curl_safefree(part->data); part->data = NULL; } /* Subparts callbacks. */ /* Argument is a pointer to the mime structure. */ /* Readback a byte string segment. */ static size_t readback_bytes(mime_state *state, char *buffer, size_t bufsize, const char *bytes, size_t numbytes, const char *trail) { size_t sz; if(numbytes > state->offset) { sz = numbytes - state->offset; bytes += state->offset; } else { size_t tsz = strlen(trail); sz = state->offset - numbytes; if(sz >= tsz) return 0; bytes = trail + sz; sz = tsz - sz; } if(sz > bufsize) sz = bufsize; memcpy(buffer, bytes, sz); state->offset += sz; return sz; } /* Read a non-encoded part content. */ static size_t read_part_content(curl_mimepart *part, char *buffer, size_t bufsize) { size_t sz = 0; if(part->readfunc) sz = part->readfunc(buffer, 1, bufsize, part->arg); return sz; } /* Read and encode part content. */ static size_t read_encoded_part_content(curl_mimepart *part, char *buffer, size_t bufsize) { mime_encoder_state *st = &part->encstate; size_t cursize = 0; size_t sz; bool ateof = FALSE; while(bufsize) { if(st->bufbeg < st->bufend || ateof) { /* Encode buffered data. */ sz = part->encoder->encodefunc(buffer, bufsize, ateof, part); switch(sz) { case 0: if(ateof) return cursize; break; case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: return cursize? cursize: sz; default: cursize += sz; buffer += sz; bufsize -= sz; continue; } } /* We need more data in input buffer. */ if(st->bufbeg) { size_t len = st->bufend - st->bufbeg; if(len) memmove(st->buf, st->buf + st->bufbeg, len); st->bufbeg = 0; st->bufend = len; } if(st->bufend >= sizeof(st->buf)) return cursize? cursize: READ_ERROR; /* Buffer full. */ sz = read_part_content(part, st->buf + st->bufend, sizeof(st->buf) - st->bufend); switch(sz) { case 0: ateof = TRUE; break; case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: return cursize? cursize: sz; default: st->bufend += sz; break; } } return cursize; } /* Readback a mime part. */ static size_t readback_part(curl_mimepart *part, char *buffer, size_t bufsize) { size_t cursize = 0; #ifdef CURL_DOES_CONVERSIONS char *convbuf = buffer; #endif /* Readback from part. */ while(bufsize) { size_t sz = 0; struct curl_slist *hdr = (struct curl_slist *) part->state.ptr; switch(part->state.state) { case MIMESTATE_BEGIN: mimesetstate(&part->state, (part->flags & MIME_BODY_ONLY)? MIMESTATE_BODY: MIMESTATE_CURLHEADERS, part->curlheaders); break; case MIMESTATE_USERHEADERS: if(!hdr) { mimesetstate(&part->state, MIMESTATE_EOH, NULL); break; } if(match_header(hdr, "Content-Type", 12)) { mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next); break; } /* FALLTHROUGH */ case MIMESTATE_CURLHEADERS: if(!hdr) mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders); else { sz = readback_bytes(&part->state, buffer, bufsize, hdr->data, strlen(hdr->data), "\r\n"); if(!sz) mimesetstate(&part->state, part->state.state, hdr->next); } break; case MIMESTATE_EOH: sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, ""); if(!sz) mimesetstate(&part->state, MIMESTATE_BODY, NULL); break; case MIMESTATE_BODY: #ifdef CURL_DOES_CONVERSIONS if(part->easy && convbuf < buffer) { CURLcode result = Curl_convert_to_network(part->easy, convbuf, buffer - convbuf); if(result) return READ_ERROR; convbuf = buffer; } #endif cleanup_encoder_state(&part->encstate); mimesetstate(&part->state, MIMESTATE_CONTENT, NULL); break; case MIMESTATE_CONTENT: if(part->encoder) sz = read_encoded_part_content(part, buffer, bufsize); else sz = read_part_content(part, buffer, bufsize); switch(sz) { case 0: mimesetstate(&part->state, MIMESTATE_END, NULL); /* Try sparing open file descriptors. */ if(part->kind == MIMEKIND_FILE && part->fp) { fclose(part->fp); part->fp = NULL; } /* FALLTHROUGH */ case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: return cursize? cursize: sz; } break; case MIMESTATE_END: return cursize; default: break; /* Other values not in part state. */ } /* Bump buffer and counters according to read size. */ cursize += sz; buffer += sz; bufsize -= sz; } #ifdef CURL_DOES_CONVERSIONS if(part->easy && convbuf < buffer && part->state.state < MIMESTATE_BODY) { CURLcode result = Curl_convert_to_network(part->easy, convbuf, buffer - convbuf); if(result) return READ_ERROR; } #endif return cursize; } /* Readback from mime. */ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mime *mime = (curl_mime *) instream; size_t cursize = 0; #ifdef CURL_DOES_CONVERSIONS char *convbuf = buffer; #endif (void) size; /* Always 1. */ while(nitems) { size_t sz = 0; curl_mimepart *part = mime->state.ptr; switch(mime->state.state) { case MIMESTATE_BEGIN: case MIMESTATE_BODY: #ifdef CURL_DOES_CONVERSIONS convbuf = buffer; #endif mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart); /* The first boundary always follows the header termination empty line, so is always preceded by a CRLK. We can then spare 2 characters by skipping the leading CRLF in boundary. */ mime->state.offset += 2; break; case MIMESTATE_BOUNDARY1: sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, ""); if(!sz) mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part); break; case MIMESTATE_BOUNDARY2: sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary, strlen(mime->boundary), part? "\r\n": "--\r\n"); if(!sz) { #ifdef CURL_DOES_CONVERSIONS if(mime->easy && convbuf < buffer) { CURLcode result = Curl_convert_to_network(mime->easy, convbuf, buffer - convbuf); if(result) return READ_ERROR; convbuf = buffer; } #endif mimesetstate(&mime->state, MIMESTATE_CONTENT, part); } break; case MIMESTATE_CONTENT: if(!part) { mimesetstate(&mime->state, MIMESTATE_END, NULL); break; } sz = readback_part(part, buffer, nitems); switch(sz) { case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: return cursize? cursize: sz; case 0: #ifdef CURL_DOES_CONVERSIONS convbuf = buffer; #endif mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart); break; } break; case MIMESTATE_END: return cursize; default: break; /* other values not used in mime state. */ } /* Bump buffer and counters according to read size. */ cursize += sz; buffer += sz; nitems -= sz; } #ifdef CURL_DOES_CONVERSIONS if(mime->easy && convbuf < buffer && mime->state.state <= MIMESTATE_CONTENT) { CURLcode result = Curl_convert_to_network(mime->easy, convbuf, buffer - convbuf); if(result) return READ_ERROR; } #endif return cursize; } static int mime_part_rewind(curl_mimepart *part) { int res = CURL_SEEKFUNC_OK; enum mimestate targetstate = MIMESTATE_BEGIN; if(part->flags & MIME_BODY_ONLY) targetstate = MIMESTATE_BODY; cleanup_encoder_state(&part->encstate); if(part->state.state > targetstate) { res = CURL_SEEKFUNC_CANTSEEK; if(part->seekfunc) { res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET); switch(res) { case CURL_SEEKFUNC_OK: case CURL_SEEKFUNC_FAIL: case CURL_SEEKFUNC_CANTSEEK: break; case -1: /* For fseek() error. */ res = CURL_SEEKFUNC_CANTSEEK; break; default: res = CURL_SEEKFUNC_FAIL; break; } } } if(res == CURL_SEEKFUNC_OK) mimesetstate(&part->state, targetstate, NULL); return res; } static int mime_subparts_seek(void *instream, curl_off_t offset, int whence) { curl_mime *mime = (curl_mime *) instream; curl_mimepart *part; int result = CURL_SEEKFUNC_OK; if(whence != SEEK_SET || offset) return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */ if(mime->state.state == MIMESTATE_BEGIN) return CURL_SEEKFUNC_OK; /* Already rewound. */ for(part = mime->firstpart; part; part = part->nextpart) { int res = mime_part_rewind(part); if(res != CURL_SEEKFUNC_OK) result = res; } if(result == CURL_SEEKFUNC_OK) mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); return result; } /* Release part content. */ static void cleanup_part_content(curl_mimepart *part) { if(part->freefunc) part->freefunc(part->arg); part->readfunc = NULL; part->seekfunc = NULL; part->freefunc = NULL; part->arg = (void *) part; /* Defaults to part itself. */ part->data = NULL; part->fp = NULL; part->datasize = (curl_off_t) 0; /* No size yet. */ cleanup_encoder_state(&part->encstate); part->kind = MIMEKIND_NONE; } static void mime_subparts_free(void *ptr) { curl_mime *mime = (curl_mime *) ptr; if(mime && mime->parent) { mime->parent->freefunc = NULL; /* Be sure we won't be called again. */ cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */ } curl_mime_free(mime); } /* Do not free subparts: unbind them. This is used for the top level only. */ static void mime_subparts_unbind(void *ptr) { curl_mime *mime = (curl_mime *) ptr; if(mime && mime->parent) { mime->parent->freefunc = NULL; /* Be sure we won't be called again. */ cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */ mime->parent = NULL; } } void Curl_mime_cleanpart(curl_mimepart *part) { cleanup_part_content(part); curl_slist_free_all(part->curlheaders); if(part->flags & MIME_USERHEADERS_OWNER) curl_slist_free_all(part->userheaders); Curl_safefree(part->mimetype); Curl_safefree(part->name); Curl_safefree(part->filename); Curl_mime_initpart(part, part->easy); } /* Recursively delete a mime handle and its parts. */ void curl_mime_free(curl_mime *mime) { curl_mimepart *part; if(mime) { mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */ while(mime->firstpart) { part = mime->firstpart; mime->firstpart = part->nextpart; Curl_mime_cleanpart(part); free(part); } free(mime); } } CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src) { curl_mime *mime; curl_mimepart *d; const curl_mimepart *s; CURLcode res = CURLE_OK; DEBUGASSERT(dst); /* Duplicate content. */ switch(src->kind) { case MIMEKIND_NONE: break; case MIMEKIND_DATA: res = curl_mime_data(dst, src->data, (size_t) src->datasize); break; case MIMEKIND_FILE: res = curl_mime_filedata(dst, src->data); /* Do not abort duplication if file is not readable. */ if(res == CURLE_READ_ERROR) res = CURLE_OK; break; case MIMEKIND_CALLBACK: res = curl_mime_data_cb(dst, src->datasize, src->readfunc, src->seekfunc, src->freefunc, src->arg); break; case MIMEKIND_MULTIPART: /* No one knows about the cloned subparts, thus always attach ownership to the part. */ mime = curl_mime_init(dst->easy); res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY; /* Duplicate subparts. */ for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) { d = curl_mime_addpart(mime); res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY; } break; default: /* Invalid kind: should not occur. */ res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */ break; } /* Duplicate headers. */ if(!res && src->userheaders) { struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders); if(!hdrs) res = CURLE_OUT_OF_MEMORY; else { /* No one but this procedure knows about the new header list, so always take ownership. */ res = curl_mime_headers(dst, hdrs, TRUE); if(res) curl_slist_free_all(hdrs); } } if(!res) { /* Duplicate other fields. */ dst->encoder = src->encoder; res = curl_mime_type(dst, src->mimetype); } if(!res) res = curl_mime_name(dst, src->name); if(!res) res = curl_mime_filename(dst, src->filename); /* If an error occurred, rollback. */ if(res) Curl_mime_cleanpart(dst); return res; } /* * Mime build functions. */ /* Create a mime handle. */ curl_mime *curl_mime_init(struct Curl_easy *easy) { curl_mime *mime; mime = (curl_mime *) malloc(sizeof(*mime)); if(mime) { mime->easy = easy; mime->parent = NULL; mime->firstpart = NULL; mime->lastpart = NULL; memset(mime->boundary, '-', 24); if(Curl_rand_hex(easy, (unsigned char *) &mime->boundary[24], MIME_RAND_BOUNDARY_CHARS + 1)) { /* failed to get random separator, bail out */ free(mime); return NULL; } mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL); } return mime; } /* Initialize a mime part. */ void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) { memset((char *) part, 0, sizeof(*part)); part->easy = easy; mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); } /* Create a mime part and append it to a mime handle's part list. */ curl_mimepart *curl_mime_addpart(curl_mime *mime) { curl_mimepart *part; if(!mime) return NULL; part = (curl_mimepart *) malloc(sizeof(*part)); if(part) { Curl_mime_initpart(part, mime->easy); part->parent = mime; if(mime->lastpart) mime->lastpart->nextpart = part; else mime->firstpart = part; mime->lastpart = part; } return part; } /* Set mime part name. */ CURLcode curl_mime_name(curl_mimepart *part, const char *name) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; Curl_safefree(part->name); part->name = NULL; if(name) { part->name = strdup(name); if(!part->name) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } /* Set mime part remote file name. */ CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; Curl_safefree(part->filename); part->filename = NULL; if(filename) { part->filename = strdup(filename); if(!part->filename) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } /* Set mime part content from memory data. */ CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; cleanup_part_content(part); if(data) { if(datasize == CURL_ZERO_TERMINATED) datasize = strlen(data); part->data = malloc(datasize + 1); if(!part->data) return CURLE_OUT_OF_MEMORY; part->datasize = datasize; if(datasize) memcpy(part->data, data, datasize); part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */ part->readfunc = mime_mem_read; part->seekfunc = mime_mem_seek; part->freefunc = mime_mem_free; part->kind = MIMEKIND_DATA; } return CURLE_OK; } /* Set mime part content from named local file. */ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) { CURLcode result = CURLE_OK; if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; cleanup_part_content(part); if(filename) { char *base; struct_stat sbuf; if(stat(filename, &sbuf) || access(filename, R_OK)) result = CURLE_READ_ERROR; part->data = strdup(filename); if(!part->data) result = CURLE_OUT_OF_MEMORY; part->datasize = -1; if(!result && S_ISREG(sbuf.st_mode)) { part->datasize = filesize(filename, sbuf); part->seekfunc = mime_file_seek; } part->readfunc = mime_file_read; part->freefunc = mime_file_free; part->kind = MIMEKIND_FILE; /* As a side effect, set the filename to the current file's base name. It is possible to withdraw this by explicitly calling curl_mime_filename() with a NULL filename argument after the current call. */ base = strippath(filename); if(!base) result = CURLE_OUT_OF_MEMORY; else { CURLcode res = curl_mime_filename(part, base); if(res) result = res; free(base); } } return result; } /* Set mime part type. */ CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; Curl_safefree(part->mimetype); part->mimetype = NULL; if(mimetype) { part->mimetype = strdup(mimetype); if(!part->mimetype) return CURLE_OUT_OF_MEMORY; } return CURLE_OK; } /* Set mime data transfer encoder. */ CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; const mime_encoder *mep; if(!part) return result; part->encoder = NULL; if(!encoding) return CURLE_OK; /* Removing current encoder. */ for(mep = encoders; mep->name; mep++) if(strcasecompare(encoding, mep->name)) { part->encoder = mep; result = CURLE_OK; } return result; } /* Set mime part headers. */ CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; if(part->flags & MIME_USERHEADERS_OWNER) { if(part->userheaders != headers) /* Allow setting twice the same list. */ curl_slist_free_all(part->userheaders); part->flags &= ~MIME_USERHEADERS_OWNER; } part->userheaders = headers; if(headers && take_ownership) part->flags |= MIME_USERHEADERS_OWNER; return CURLE_OK; } /* Set mime part content from callback. */ CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, curl_read_callback readfunc, curl_seek_callback seekfunc, curl_free_callback freefunc, void *arg) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; cleanup_part_content(part); if(readfunc) { part->readfunc = readfunc; part->seekfunc = seekfunc; part->freefunc = freefunc; part->arg = arg; part->datasize = datasize; part->kind = MIMEKIND_CALLBACK; } return CURLE_OK; } /* Set mime part content from subparts. */ CURLcode Curl_mime_set_subparts(curl_mimepart *part, curl_mime *subparts, int take_ownership) { curl_mime *root; if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; /* Accept setting twice the same subparts. */ if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts) return CURLE_OK; cleanup_part_content(part); if(subparts) { /* Must belong to the same data handle. */ if(part->easy && subparts->easy && part->easy != subparts->easy) return CURLE_BAD_FUNCTION_ARGUMENT; /* Should not have been attached already. */ if(subparts->parent) return CURLE_BAD_FUNCTION_ARGUMENT; /* Should not be the part's root. */ root = part->parent; if(root) { while(root->parent && root->parent->parent) root = root->parent->parent; if(subparts == root) { if(part->easy) failf(part->easy, "Can't add itself as a subpart!"); return CURLE_BAD_FUNCTION_ARGUMENT; } } subparts->parent = part; part->readfunc = mime_subparts_read; part->seekfunc = mime_subparts_seek; part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind; part->arg = subparts; part->datasize = -1; part->kind = MIMEKIND_MULTIPART; } return CURLE_OK; } CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) { return Curl_mime_set_subparts(part, subparts, TRUE); } /* Readback from top mime. */ /* Argument is the dummy top part. */ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) { curl_mimepart *part = (curl_mimepart *) instream; (void) size; /* Always 1. */ return readback_part(part, buffer, nitems); } /* Rewind mime stream. */ CURLcode Curl_mime_rewind(curl_mimepart *part) { return mime_part_rewind(part) == CURL_SEEKFUNC_OK? CURLE_OK: CURLE_SEND_FAIL_REWIND; } /* Compute header list size. */ static size_t slist_size(struct curl_slist *s, size_t overhead, const char *skip) { size_t size = 0; size_t skiplen = skip? strlen(skip): 0; for(; s; s = s->next) if(!skip || !match_header(s, skip, skiplen)) size += strlen(s->data) + overhead; return size; } /* Get/compute multipart size. */ static curl_off_t multipart_size(curl_mime *mime) { curl_off_t size; size_t boundarysize; curl_mimepart *part; if(!mime) return 0; /* Not present -> empty. */ boundarysize = 4 + strlen(mime->boundary) + 2; size = boundarysize; /* Final boundary - CRLF after headers. */ for(part = mime->firstpart; part; part = part->nextpart) { curl_off_t sz = Curl_mime_size(part); if(sz < 0) size = sz; if(size >= 0) size += boundarysize + sz; } return size; } /* Get/compute mime size. */ curl_off_t Curl_mime_size(curl_mimepart *part) { curl_off_t size; if(part->kind == MIMEKIND_MULTIPART) part->datasize = multipart_size(part->arg); size = part->datasize; if(part->encoder) size = part->encoder->sizefunc(part); if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) { /* Compute total part size. */ size += slist_size(part->curlheaders, 2, NULL); size += slist_size(part->userheaders, 2, "Content-Type"); size += 2; /* CRLF after headers. */ } return size; } /* Add a header. */ /* VARARGS2 */ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) { struct curl_slist *hdr = NULL; char *s = NULL; va_list ap; va_start(ap, fmt); s = curl_mvaprintf(fmt, ap); va_end(ap); if(s) { hdr = Curl_slist_append_nodup(*slp, s); if(hdr) *slp = hdr; else free(s); } return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY; } /* Add a content type header. */ static CURLcode add_content_type(struct curl_slist **slp, const char *type, const char *boundary) { return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type, boundary? "; boundary=": "", boundary? boundary: ""); } const char *Curl_mime_contenttype(const char *filename) { /* * If no content type was specified, we scan through a few well-known * extensions and pick the first we match! */ struct ContentType { const char *extension; const char *type; }; static const struct ContentType ctts[] = { {".gif", "image/gif"}, {".jpg", "image/jpeg"}, {".jpeg", "image/jpeg"}, {".png", "image/png"}, {".svg", "image/svg+xml"}, {".txt", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".pdf", "application/pdf"}, {".xml", "application/xml"} }; if(filename) { size_t len1 = strlen(filename); const char *nameend = filename + len1; unsigned int i; for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) { size_t len2 = strlen(ctts[i].extension); if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension)) return ctts[i].type; } } return NULL; } CURLcode Curl_mime_prepare_headers(curl_mimepart *part, const char *contenttype, const char *disposition, enum mimestrategy strategy) { curl_mime *mime = NULL; const char *boundary = NULL; char *customct; const char *cte = NULL; CURLcode ret = CURLE_OK; /* Get rid of previously prepared headers. */ curl_slist_free_all(part->curlheaders); part->curlheaders = NULL; /* Be sure we won't access old headers later. */ if(part->state.state == MIMESTATE_CURLHEADERS) mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL); /* Check if content type is specified. */ customct = part->mimetype; if(!customct) customct = search_header(part->userheaders, "Content-Type"); if(customct) contenttype = customct; /* If content type is not specified, try to determine it. */ if(!contenttype) { switch(part->kind) { case MIMEKIND_MULTIPART: contenttype = MULTIPART_CONTENTTYPE_DEFAULT; break; case MIMEKIND_FILE: contenttype = Curl_mime_contenttype(part->filename); if(!contenttype) contenttype = Curl_mime_contenttype(part->data); if(!contenttype && part->filename) contenttype = FILE_CONTENTTYPE_DEFAULT; break; default: contenttype = Curl_mime_contenttype(part->filename); break; } } if(part->kind == MIMEKIND_MULTIPART) { mime = (curl_mime *) part->arg; if(mime) boundary = mime->boundary; } else if(contenttype && !customct && strcasecompare(contenttype, "text/plain")) if(strategy == MIMESTRATEGY_MAIL || !part->filename) contenttype = NULL; /* Issue content-disposition header only if not already set by caller. */ if(!search_header(part->userheaders, "Content-Disposition")) { if(!disposition) if(part->filename || part->name || (contenttype && !strncasecompare(contenttype, "multipart/", 10))) disposition = DISPOSITION_DEFAULT; if(disposition && curl_strequal(disposition, "attachment") && !part->name && !part->filename) disposition = NULL; if(disposition) { char *name = NULL; char *filename = NULL; if(part->name) { name = escape_string(part->name); if(!name) ret = CURLE_OUT_OF_MEMORY; } if(!ret && part->filename) { filename = escape_string(part->filename); if(!filename) ret = CURLE_OUT_OF_MEMORY; } if(!ret) ret = Curl_mime_add_header(&part->curlheaders, "Content-Disposition: %s%s%s%s%s%s%s", disposition, name? "; name=\"": "", name? name: "", name? "\"": "", filename? "; filename=\"": "", filename? filename: "", filename? "\"": ""); Curl_safefree(name); Curl_safefree(filename); if(ret) return ret; } } /* Issue Content-Type header. */ if(contenttype) { ret = add_content_type(&part->curlheaders, contenttype, boundary); if(ret) return ret; } /* Content-Transfer-Encoding header. */ if(!search_header(part->userheaders, "Content-Transfer-Encoding")) { if(part->encoder) cte = part->encoder->name; else if(contenttype && strategy == MIMESTRATEGY_MAIL && part->kind != MIMEKIND_MULTIPART) cte = "8bit"; if(cte) { ret = Curl_mime_add_header(&part->curlheaders, "Content-Transfer-Encoding: %s", cte); if(ret) return ret; } } /* If we were reading curl-generated headers, restart with new ones (this should not occur). */ if(part->state.state == MIMESTATE_CURLHEADERS) mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders); /* Process subparts. */ if(part->kind == MIMEKIND_MULTIPART && mime) { curl_mimepart *subpart; disposition = NULL; if(strcasecompare(contenttype, "multipart/form-data")) disposition = "form-data"; for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) { ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy); if(ret) return ret; } } return ret; } #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ /* Mime not compiled in: define stubs for externally-referenced functions. */ curl_mime *curl_mime_init(CURL *easy) { (void) easy; return NULL; } void curl_mime_free(curl_mime *mime) { (void) mime; } curl_mimepart *curl_mime_addpart(curl_mime *mime) { (void) mime; return NULL; } CURLcode curl_mime_name(curl_mimepart *part, const char *name) { (void) part; (void) name; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) { (void) part; (void) filename; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) { (void) part; (void) mimetype; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) { (void) part; (void) encoding; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize) { (void) part; (void) data; (void) datasize; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) { (void) part; (void) filename; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, curl_read_callback readfunc, curl_seek_callback seekfunc, curl_free_callback freefunc, void *arg) { (void) part; (void) datasize; (void) readfunc; (void) seekfunc; (void) freefunc; (void) arg; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) { (void) part; (void) subparts; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership) { (void) part; (void) headers; (void) take_ownership; return CURLE_NOT_BUILT_IN; } CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) { (void)slp; (void)fmt; return CURLE_NOT_BUILT_IN; } #endif /* if disabled */ davix-0.8.0/deps/curl/lib/strtok.h0000644000000000000000000000244014121063461015473 0ustar rootroot#ifndef HEADER_CURL_STRTOK_H #define HEADER_CURL_STRTOK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #ifndef HAVE_STRTOK_R char *Curl_strtok_r(char *s, const char *delim, char **last); #define strtok_r Curl_strtok_r #else #include #endif #endif /* HEADER_CURL_STRTOK_H */ davix-0.8.0/deps/curl/lib/libcurl.plist0000644000000000000000000000141714121063461016510 0ustar rootroot CFBundleInfoDictionaryVersion 6.0 CFBundleDevelopmentRegion English CFBundleExecutable curl CFBundleIdentifier se.haxx.curl.libcurl CFBundleVersion 7.12.3 CFBundleName libcurl CFBundlePackageType FMWK CFBundleSignature ???? CFBundleShortVersionString libcurl 7.12.3 CFBundleGetInfoString libcurl.plist 7.12.3 davix-0.8.0/deps/curl/lib/slist.h0000644000000000000000000000311014121063461015276 0ustar rootroot#ifndef HEADER_CURL_SLIST_H #define HEADER_CURL_SLIST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Curl_slist_duplicate() duplicates a linked list. It always returns the * address of the first record of the cloned list or NULL in case of an * error (or if the input list was NULL). */ struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist); /* * Curl_slist_append_nodup() takes ownership of the given string and appends * it to the list. */ struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data); #endif /* HEADER_CURL_SLIST_H */ davix-0.8.0/deps/curl/lib/curl_gethostname.c0000644000000000000000000000622114121063461017504 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "curl_gethostname.h" /* * Curl_gethostname() is a wrapper around gethostname() which allows * overriding the host name that the function would normally return. * This capability is used by the test suite to verify exact matching * of NTLM authentication, which exercises libcurl's MD4 and DES code * as well as by the SMTP module when a hostname is not provided. * * For libcurl debug enabled builds host name overriding takes place * when environment variable CURL_GETHOSTNAME is set, using the value * held by the variable to override returned host name. * * Note: The function always returns the un-qualified hostname rather * than being provider dependent. * * For libcurl shared library release builds the test suite preloads * another shared library named libhostname using the LD_PRELOAD * mechanism which intercepts, and might override, the gethostname() * function call. In this case a given platform must support the * LD_PRELOAD mechanism and additionally have environment variable * CURL_GETHOSTNAME set in order to override the returned host name. * * For libcurl static library release builds no overriding takes place. */ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { #ifndef HAVE_GETHOSTNAME /* Allow compilation and return failure when unavailable */ (void) name; (void) namelen; return -1; #else int err; char *dot; #ifdef DEBUGBUILD /* Override host name when environment variable CURL_GETHOSTNAME is set */ const char *force_hostname = getenv("CURL_GETHOSTNAME"); if(force_hostname) { strncpy(name, force_hostname, namelen); err = 0; } else { name[0] = '\0'; err = gethostname(name, namelen); } #else /* DEBUGBUILD */ /* The call to system's gethostname() might get intercepted by the libhostname library when libcurl is built as a non-debug shared library when running the test suite. */ name[0] = '\0'; err = gethostname(name, namelen); #endif name[namelen - 1] = '\0'; if(err) return err; /* Truncate domain, leave only machine name */ dot = strchr(name, '.'); if(dot) *dot = '\0'; return 0; #endif } davix-0.8.0/deps/curl/lib/speedcheck.c0000644000000000000000000000470014121063461016237 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "urldata.h" #include "sendf.h" #include "multiif.h" #include "speedcheck.h" void Curl_speedinit(struct Curl_easy *data) { memset(&data->state.keeps_speed, 0, sizeof(struct curltime)); } /* * @unittest: 1606 */ CURLcode Curl_speedcheck(struct Curl_easy *data, struct curltime now) { if((data->progress.current_speed >= 0) && data->set.low_speed_time) { if(data->progress.current_speed < data->set.low_speed_limit) { if(!data->state.keeps_speed.tv_sec) /* under the limit at this very moment */ data->state.keeps_speed = now; else { /* how long has it been under the limit */ timediff_t howlong = Curl_timediff(now, data->state.keeps_speed); if(howlong >= data->set.low_speed_time * 1000) { /* too long */ failf(data, "Operation too slow. " "Less than %ld bytes/sec transferred the last %ld seconds", data->set.low_speed_limit, data->set.low_speed_time); return CURLE_OPERATION_TIMEDOUT; } } } else /* faster right now */ data->state.keeps_speed.tv_sec = 0; } if(data->set.low_speed_limit) /* if low speed limit is enabled, set the expire timer to make this connection's speed get checked again in a second */ Curl_expire(data, 1000, EXPIRE_SPEEDCHECK); return CURLE_OK; } davix-0.8.0/deps/curl/lib/urlapi-int.h0000644000000000000000000000261314121063461016233 0ustar rootroot#ifndef HEADER_CURL_URLAPI_INT_H #define HEADER_CURL_URLAPI_INT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" /* scheme is not URL encoded, the longest libcurl supported ones are... */ #define MAX_SCHEME_LEN 40 bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); #ifdef DEBUGBUILD CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname); #endif #endif /* HEADER_CURL_URLAPI_INT_H */ davix-0.8.0/deps/curl/lib/socks_gssapi.c0000644000000000000000000004735214121063461016643 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2020, Daniel Stenberg, , et al. * Copyright (C) 2009, Markus Moeller, * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY) #include "curl_gssapi.h" #include "urldata.h" #include "sendf.h" #include "connect.h" #include "timeval.h" #include "socks.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; /* * Helper GSS-API error functions. */ static int check_gss_err(struct Curl_easy *data, OM_uint32 major_status, OM_uint32 minor_status, const char *function) { if(GSS_ERROR(major_status)) { OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; char buf[1024]; size_t len; len = 0; msg_ctx = 0; while(!msg_ctx) { /* convert major status code (GSS-API error) to text */ maj_stat = gss_display_status(&min_stat, major_status, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length + 1) { strcpy(buf + len, (char *) status_string.value); len += status_string.length; } gss_release_buffer(&min_stat, &status_string); break; } gss_release_buffer(&min_stat, &status_string); } if(sizeof(buf) > len + 3) { strcpy(buf + len, ".\n"); len += 2; } msg_ctx = 0; while(!msg_ctx) { /* convert minor status code (underlying routine error) to text */ maj_stat = gss_display_status(&min_stat, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length) strcpy(buf + len, (char *) status_string.value); gss_release_buffer(&min_stat, &status_string); break; } gss_release_buffer(&min_stat, &status_string); } failf(data, "GSS-API error: %s failed:\n%s", function, buf); return 1; } return 0; } CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; ssize_t written; int result; OM_uint32 gss_major_status, gss_minor_status, gss_status; OM_uint32 gss_ret_flags; int gss_conf_state, gss_enc; gss_buffer_desc service = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc* gss_token = GSS_C_NO_BUFFER; gss_name_t server = GSS_C_NO_NAME; gss_name_t gss_client_name = GSS_C_NO_NAME; unsigned short us_length; char *user = NULL; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; const size_t serviceptr_length = strlen(serviceptr); /* GSS-API request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ * | 1 | 1 | 2 | up to 2^16 - 1 | * +----+------+-----+----------------+ */ /* prepare service name */ if(strchr(serviceptr, '/')) { service.length = serviceptr_length; service.value = malloc(service.length); if(!service.value) return CURLE_OUT_OF_MEMORY; memcpy(service.value, serviceptr, service.length); gss_major_status = gss_import_name(&gss_minor_status, &service, (gss_OID) GSS_C_NULL_OID, &server); } else { service.value = malloc(serviceptr_length + strlen(conn->socks_proxy.host.name) + 2); if(!service.value) return CURLE_OUT_OF_MEMORY; service.length = serviceptr_length + strlen(conn->socks_proxy.host.name) + 1; msnprintf(service.value, service.length + 1, "%s@%s", serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, GSS_C_NT_HOSTBASED_SERVICE, &server); } gss_release_buffer(&gss_status, &service); /* clear allocated memory */ if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_import_name()")) { failf(data, "Failed to create service name."); gss_release_name(&gss_status, &server); return CURLE_COULDNT_CONNECT; } (void)curlx_nonblock(sock, FALSE); /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { gss_major_status = Curl_gss_init_sec_context(data, &gss_minor_status, &gss_context, server, &Curl_krb5_mech_oid, NULL, gss_token, &gss_send_token, TRUE, &gss_ret_flags); if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_init_sec_context")) { gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to initial GSS-API token."); return CURLE_COULDNT_CONNECT; } if(gss_send_token.length != 0) { socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ us_length = htons((short)gss_send_token.length); memcpy(socksreq + 2, &us_length, sizeof(short)); code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } code = Curl_write_plain(conn, sock, (char *)gss_send_token.value, gss_send_token.length, &written); if(code || ((ssize_t)gss_send_token.length != written)) { failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } } gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_recv_token); if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; /* analyse response */ /* GSS-API response looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | * +----+------+----------------------+ * | 1 | 1 | 2 | up to 2^16 - 1 | * +----+------+-----+----------------+ */ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API authentication response."); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 1) { /* status / messgae type */ failf(data, "Invalid GSS-API authentication response type (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); gss_recv_token.length = us_length; gss_recv_token.value = malloc(us_length); if(!gss_recv_token.value) { failf(data, "Could not allocate memory for GSS-API authentication " "response token."); gss_release_name(&gss_status, &server); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, gss_recv_token.length, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } gss_token = &gss_recv_token; } gss_release_name(&gss_status, &server); /* Everything is good so far, user was authenticated! */ gss_major_status = gss_inquire_context(&gss_minor_status, gss_context, &gss_client_name, NULL, NULL, NULL, NULL, NULL, NULL); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_inquire_context")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } gss_major_status = gss_display_name(&gss_minor_status, gss_client_name, &gss_send_token, NULL); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_display_name")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } user = malloc(gss_send_token.length + 1); if(!user) { gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); return CURLE_OUT_OF_MEMORY; } memcpy(user, gss_send_token.value, gss_send_token.length); user[gss_send_token.length] = '\0'; gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user); free(user); user = NULL; /* Do encryption */ socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 2; /* encryption message type */ gss_enc = 0; /* no data protection */ /* do confidentiality protection if supported */ if(gss_ret_flags & GSS_C_CONF_FLAG) gss_enc = 2; /* else do integrity protection */ else if(gss_ret_flags & GSS_C_INTEG_FLAG) gss_enc = 1; infof(data, "SOCKS5 server supports GSS-API %s data protection.\n", (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality")); /* force for the moment to no data protection */ gss_enc = 0; /* * Sending the encryption type in clear seems wrong. It should be * protected with gss_seal()/gss_wrap(). See RFC1961 extract below * The NEC reference implementations on which this is based is * therefore at fault * * +------+------+------+.......................+ * + ver | mtyp | len | token | * +------+------+------+.......................+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets | * +------+------+------+.......................+ * * Where: * * - "ver" is the protocol version number, here 1 to represent the * first version of the SOCKS/GSS-API protocol * * - "mtyp" is the message type, here 2 to represent a protection * -level negotiation message * * - "len" is the length of the "token" field in octets * * - "token" is the GSS-API encapsulated protection level * * The token is produced by encapsulating an octet containing the * required protection level using gss_seal()/gss_wrap() with conf_req * set to FALSE. The token is verified using gss_unseal()/ * gss_unwrap(). * */ if(data->set.socks5_gssapi_nec) { us_length = htons((short)1); memcpy(socksreq + 2, &us_length, sizeof(short)); } else { gss_send_token.length = 1; gss_send_token.value = malloc(1); if(!gss_send_token.value) { gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } memcpy(gss_send_token.value, &gss_enc, 1); gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0, GSS_C_QOP_DEFAULT, &gss_send_token, &gss_conf_state, &gss_w_token); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to wrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_send_token); us_length = htons((short)gss_w_token.length); memcpy(socksreq + 2, &us_length, sizeof(short)); } code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written); if(code || (4 != written)) { failf(data, "Failed to send GSS-API encryption request."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); code = Curl_write_plain(conn, sock, socksreq, 1, &written); if(code || ( 1 != written)) { failf(data, "Failed to send GSS-API encryption type."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } } else { code = Curl_write_plain(conn, sock, (char *)gss_w_token.value, gss_w_token.length, &written); if(code || ((ssize_t)gss_w_token.length != written)) { failf(data, "Failed to send GSS-API encryption type."); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_w_token); } result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 2) { /* status / messgae type */ failf(data, "Invalid GSS-API encryption response type (%d %d).", socksreq[0], socksreq[1]); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } memcpy(&us_length, socksreq + 2, sizeof(short)); us_length = ntohs(us_length); gss_recv_token.length = us_length; gss_recv_token.value = malloc(gss_recv_token.length); if(!gss_recv_token.value) { gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, gss_recv_token.length, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API encryptrion type."); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(!data->set.socks5_gssapi_nec) { gss_major_status = gss_unwrap(&gss_minor_status, gss_context, &gss_recv_token, &gss_w_token, 0, GSS_C_QOP_DEFAULT); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to unwrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_recv_token); if(gss_w_token.length != 1) { failf(data, "Invalid GSS-API encryption response length (%d).", gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } memcpy(socksreq, gss_w_token.value, gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); } else { if(gss_recv_token.length != 1) { failf(data, "Invalid GSS-API encryption response length (%d).", gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } memcpy(socksreq, gss_recv_token.value, gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); } (void)curlx_nonblock(sock, TRUE); infof(data, "SOCKS5 access with%s protection granted.\n", (socksreq[0] == 0)?"out GSS-API data": ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality")); conn->socks5_gssapi_enctype = socksreq[0]; if(socksreq[0] == 0) gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OK; } #endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */ davix-0.8.0/deps/curl/lib/config-plan9.h0000644000000000000000000001312514121063461016435 0ustar rootroot#ifndef HEADER_CURL_CONFIG_PLAN9_H #define HEADER_CURL_CONFIG_PLAN9_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #define BUILDING_LIBCURL 1 #define CURL_CA_BUNDLE "/sys/lib/tls/ca.pem" #define CURL_CA_PATH "/sys/lib/tls" #define CURL_STATICLIB 1 #define ENABLE_IPV6 1 #define CURL_DISABLE_LDAP 1 #define NEED_REENTRANT 1 #define OS "plan9" #define PACKAGE "curl" #define PACKAGE_NAME "curl" #define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.haxx.se/mail/" #define PACKAGE_STRING "curl -" #define PACKAGE_TARNAME "curl" #define PACKAGE_VERSION "-" #define RANDOM_FILE "/dev/random" #define VERSION "0.0.0" /* TODO */ #define RETSIGTYPE void #define STDC_HEADERS 1 #ifdef _BITS64 #error not implement #else #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG 4 #define SIZEOF_OFF_T 8 #define SIZEOF_CURL_OFF_T 4 /* curl_off_t = timediff_t = int */ #define SIZEOF_SIZE_T 4 #define SIZEOF_TIME_T 4 #endif #define HAVE_GETNAMEINFO 1 #define GETNAMEINFO_QUAL_ARG1 const #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * #define GETNAMEINFO_TYPE_ARG2 int #define GETNAMEINFO_TYPE_ARG46 long #define GETNAMEINFO_TYPE_ARG7 int #define HAVE_RECV 1 #define RECV_TYPE_ARG1 int #define RECV_TYPE_ARG2 void * #define RECV_TYPE_ARG3 int #define RECV_TYPE_ARG4 int #define RECV_TYPE_RETV int #define HAVE_RECVFROM 1 #define RECVFROM_TYPE_ARG1 int #define RECVFROM_TYPE_ARG2 void #define RECVFROM_TYPE_ARG2_IS_VOID 1 #define RECVFROM_TYPE_ARG3 int #define RECVFROM_TYPE_ARG4 int #define RECVFROM_TYPE_ARG5 void #define RECVFROM_TYPE_ARG5_IS_VOID 1 #define RECVFROM_TYPE_ARG6 int #define RECVFROM_TYPE_ARG6_IS_VOID 1 #define RECVFROM_TYPE_RETV int #define HAVE_SELECT 1 #define SELECT_TYPE_ARG1 int #define SELECT_TYPE_ARG234 fd_set * #define SELECT_TYPE_ARG5 struct timeval * #define SELECT_TYPE_RETV int #define HAVE_SEND 1 #define SEND_TYPE_ARG1 int #define SEND_TYPE_ARG2 void * #define SEND_QUAL_ARG2 #define SEND_TYPE_ARG3 int #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV int #define HAVE_ALARM 1 #define HAVE_ARPA_INET_H 1 #define HAVE_ASSERT_H 1 #define HAVE_BASENAME 1 #define HAVE_BOOL_T 1 #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 #define HAVE_ERRNO_H 1 #define HAVE_FCNTL 1 #define HAVE_FCNTL_H 1 #define HAVE_FDOPEN 1 #define HAVE_FORK 1 #define HAVE_FREEADDRINFO 1 #define HAVE_FTRUNCATE 1 #define HAVE_GETADDRINFO 1 #define HAVE_GETEUID 1 #define HAVE_GETHOSTBYADDR 1 #define HAVE_GETHOSTBYNAME 1 #define HAVE_GETHOSTNAME 1 #define HAVE_GETPPID 1 #define HAVE_GETPROTOBYNAME 1 #define HAVE_GETPWUID 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_GMTIME_R 1 #define HAVE_INET_ADDR 1 #define HAVE_INET_NTOP 1 #define HAVE_INET_PTON 1 #define HAVE_INTTYPES_H 1 #define HAVE_IOCTL 1 #define HAVE_LIBGEN_H 1 #define HAVE_LIBZ 1 #define HAVE_LL 1 #define HAVE_LOCALE_H 1 #define HAVE_LOCALTIME_R 1 #define HAVE_LONGLONG 1 #define HAVE_NETDB_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_NETINET_TCP_H 1 #define HAVE_PWD_H 1 #define HAVE_SYS_SELECT_H 1 #define USE_OPENSSL 1 #define HAVE_OPENSSL_CRYPTO_H 1 #define HAVE_OPENSSL_ERR_H 1 #define HAVE_OPENSSL_PEM_H 1 #define HAVE_OPENSSL_PKCS12_H 1 #define HAVE_OPENSSL_RSA_H 1 #define HAVE_OPENSSL_SSL_H 1 #define HAVE_OPENSSL_X509_H 1 #define HAVE_PERROR 1 #define HAVE_PIPE 1 #define HAVE_POLL 1 #define HAVE_POLL_FINE 1 #define HAVE_POLL_H 1 #define HAVE_PTHREAD_H 1 #define HAVE_RAND_STATUS 1 #define HAVE_SETJMP_H 1 #define HAVE_SETLOCALE 1 #define HAVE_SETSOCKOPT 1 #define HAVE_SOCK_OPTS 1 /* for /sys/include/ape/sys/socket.h */ #define HAVE_SIGACTION 1 #define HAVE_SIGNAL 1 #define HAVE_SIGNAL_H 1 #define HAVE_SIGSETJMP 1 #define HAVE_SIG_ATOMIC_T 1 #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 #define HAVE_SOCKET 1 #define HAVE_SSL_GET_SHUTDOWN 1 #define HAVE_STDBOOL_H 1 #define HAVE_STDINT_H 1 #define HAVE_STDIO_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRCASECMP 1 #define HAVE_STRDUP 1 #define HAVE_STRING_H 1 #define HAVE_STRNCASECMP 1 #define HAVE_STRSTR 1 #define HAVE_STRTOK_R 1 #define HAVE_STRTOLL 1 #define HAVE_STRUCT_TIMEVAL 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_RESOURCE_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_UIO_H 1 #define HAVE_SYS_UN_H 1 #define HAVE_TERMIOS_H 1 #define HAVE_TIME_H 1 #define HAVE_UNAME 1 #define HAVE_UNISTD_H 1 #define HAVE_UTIME 1 #define HAVE_UTIME_H 1 #define HAVE_WRITEV 1 #define HAVE_ZLIB_H 1 #define HAVE_POSIX_STRERROR_R 1 #define HAVE_STRERROR_R 1 #define STRERROR_R_TYPE_ARG3 int #define TIME_WITH_SYS_TIME 1 #define USE_BLOCKING_SOCKETS 1 #define USE_MANUAL 1 #define __attribute__(x) #ifndef __cplusplus #undef inline #endif #endif /* HEADER_CURL_CONFIG_PLAN9_H */ davix-0.8.0/deps/curl/lib/pop3.c0000644000000000000000000012505014121063461015024 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC1734 POP3 Authentication * RFC1939 POP3 protocol * RFC2195 CRAM-MD5 authentication * RFC2384 POP URL Scheme * RFC2449 POP3 Extension Mechanism * RFC2595 Using TLS with IMAP, POP3 and ACAP * RFC2831 DIGEST-MD5 authentication * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * RFC5034 POP3 SASL Authentication Mechanism * RFC6749 OAuth 2.0 Authorization Framework * RFC8314 Use of TLS for Email Submission and Access * Draft LOGIN SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_POP3 #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "pop3.h" #include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Local API functions */ static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); static CURLcode pop3_do(struct connectdata *conn, bool *done); static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode pop3_connect(struct connectdata *conn, bool *done); static CURLcode pop3_disconnect(struct connectdata *conn, bool dead); static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done); static CURLcode pop3_setup_connection(struct connectdata *conn); static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct connectdata *conn); static CURLcode pop3_parse_custom_request(struct connectdata *conn); static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); static void pop3_get_message(char *buffer, char **outptr); /* * POP3 protocol handler. */ const struct Curl_handler Curl_handler_pop3 = { "POP3", /* scheme */ pop3_setup_connection, /* setup_connection */ pop3_do, /* do_it */ pop3_done, /* done */ ZERO_NULL, /* do_more */ pop3_connect, /* connect_it */ pop3_multi_statemach, /* connecting */ pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ PROTOPT_URLOPTIONS }; #ifdef USE_SSL /* * POP3S protocol handler. */ const struct Curl_handler Curl_handler_pop3s = { "POP3S", /* scheme */ pop3_setup_connection, /* setup_connection */ pop3_do, /* do_it */ pop3_done, /* done */ ZERO_NULL, /* do_more */ pop3_connect, /* connect_it */ pop3_multi_statemach, /* connecting */ pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_POP3S, /* defport */ CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif /* SASL parameters for the pop3 protocol */ static const struct SASLproto saslpop3 = { "pop", /* The service name */ '*', /* Code received when continuation is expected */ '+', /* Code to receive upon authentication success */ 255 - 8, /* Maximum initial response length (no max) */ pop3_perform_auth, /* Send authentication command */ pop3_continue_auth, /* Send authentication continuation */ pop3_get_message /* Get SASL response message */ }; #ifdef USE_SSL static void pop3_to_pop3s(struct connectdata *conn) { /* Change the connection handler */ conn->handler = &Curl_handler_pop3s; /* Set the connection's upgraded to TLS flag */ conn->tls_upgraded = TRUE; } #else #define pop3_to_pop3s(x) Curl_nop_stmt #endif /*********************************************************************** * * pop3_endofresp() * * Checks for an ending POP3 status code at the start of the given string, but * also detects the APOP timestamp from the server greeting and various * capabilities from the CAPA response including the supported authentication * types and allowed SASL mechanisms. */ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, int *resp) { struct pop3_conn *pop3c = &conn->proto.pop3c; /* Do we have an error response? */ if(len >= 4 && !memcmp("-ERR", line, 4)) { *resp = '-'; return TRUE; } /* Are we processing CAPA command responses? */ if(pop3c->state == POP3_CAPA) { /* Do we have the terminating line? */ if(len >= 1 && line[0] == '.') /* Treat the response as a success */ *resp = '+'; else /* Treat the response as an untagged continuation */ *resp = '*'; return TRUE; } /* Do we have a success response? */ if(len >= 3 && !memcmp("+OK", line, 3)) { *resp = '+'; return TRUE; } /* Do we have a continuation response? */ if(len >= 1 && line[0] == '+') { *resp = '*'; return TRUE; } return FALSE; /* Nothing for us */ } /*********************************************************************** * * pop3_get_message() * * Gets the authentication message from the response buffer. */ static void pop3_get_message(char *buffer, char **outptr) { size_t len = strlen(buffer); char *message = NULL; if(len > 2) { /* Find the start of the message */ len -= 2; for(message = buffer + 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ for(; len--;) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ if(++len) { message[len] = '\0'; } } else /* junk input => zero length output */ message = &buffer[len]; *outptr = message; } /*********************************************************************** * * state() * * This is the ONLY way to change POP3 state! */ static void state(struct connectdata *conn, pop3state newstate) { struct pop3_conn *pop3c = &conn->proto.pop3c; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[] = { "STOP", "SERVERGREET", "CAPA", "STARTTLS", "UPGRADETLS", "AUTH", "APOP", "USER", "PASS", "COMMAND", "QUIT", /* LAST */ }; if(pop3c->state != newstate) infof(conn->data, "POP3 %p state change from %s to %s\n", (void *)pop3c, names[pop3c->state], names[newstate]); #endif pop3c->state = newstate; } /*********************************************************************** * * pop3_perform_capa() * * Sends the CAPA command in order to obtain a list of server side supported * capabilities. */ static CURLcode pop3_perform_capa(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ pop3c->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPA command */ result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); if(!result) state(conn, POP3_CAPA); return result; } /*********************************************************************** * * pop3_perform_starttls() * * Sends the STLS command to start the upgrade to TLS. */ static CURLcode pop3_perform_starttls(struct connectdata *conn) { /* Send the STLS command */ CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS"); if(!result) state(conn, POP3_STARTTLS); return result; } /*********************************************************************** * * pop3_perform_upgrade_tls() * * Performs the upgrade to TLS. */ static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn) { /* Start the SSL connection */ struct pop3_conn *pop3c = &conn->proto.pop3c; CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); if(!result) { if(pop3c->state != POP3_UPGRADETLS) state(conn, POP3_UPGRADETLS); if(pop3c->ssldone) { pop3_to_pop3s(conn); result = pop3_perform_capa(conn); } } return result; } /*********************************************************************** * * pop3_perform_user() * * Sends a clear text USER command to authenticate with. */ static CURLcode pop3_perform_user(struct connectdata *conn) { CURLcode result = CURLE_OK; /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { state(conn, POP3_STOP); return result; } /* Send the USER command */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", conn->user ? conn->user : ""); if(!result) state(conn, POP3_USER); return result; } #ifndef CURL_DISABLE_CRYPTO_AUTH /*********************************************************************** * * pop3_perform_apop() * * Sends an APOP command to authenticate with. */ static CURLcode pop3_perform_apop(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; size_t i; MD5_context *ctxt; unsigned char digest[MD5_DIGEST_LEN]; char secret[2 * MD5_DIGEST_LEN + 1]; /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { state(conn, POP3_STOP); return result; } /* Create the digest */ ctxt = Curl_MD5_init(Curl_DIGEST_MD5); if(!ctxt) return CURLE_OUT_OF_MEMORY; Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, curlx_uztoui(strlen(pop3c->apoptimestamp))); Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, curlx_uztoui(strlen(conn->passwd))); /* Finalise the digest */ Curl_MD5_final(ctxt, digest); /* Convert the calculated 16 octet digest into a 32 byte hex string */ for(i = 0; i < MD5_DIGEST_LEN; i++) msnprintf(&secret[2 * i], 3, "%02x", digest[i]); result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); if(!result) state(conn, POP3_APOP); return result; } #endif /*********************************************************************** * * pop3_perform_auth() * * Sends an AUTH command allowing the client to login with the given SASL * authentication mechanism. */ static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, const char *initresp) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; if(initresp) { /* AUTH ... */ /* Send the AUTH command with the initial response */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); } else { /* Send the AUTH command */ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); } return result; } /*********************************************************************** * * pop3_continue_auth() * * Sends SASL continuation data or cancellation. */ static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp) { struct pop3_conn *pop3c = &conn->proto.pop3c; return Curl_pp_sendf(&pop3c->pp, "%s", resp); } /*********************************************************************** * * pop3_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL * authentication mechanism, falling back to APOP and clear text should a * common mechanism not be available between the client and server. */ static CURLcode pop3_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; saslprogress progress = SASL_IDLE; /* Check we have enough data to authenticate with and end the connect phase if we don't */ if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { state(conn, POP3_STOP); return result; } if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { /* Calculate the SASL login details */ result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); if(!result) if(progress == SASL_INPROGRESS) state(conn, POP3_AUTH); } if(!result && progress == SASL_IDLE) { #ifndef CURL_DISABLE_CRYPTO_AUTH if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); else #endif if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; } } return result; } /*********************************************************************** * * pop3_perform_command() * * Sends a POP3 based command. */ static CURLcode pop3_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *command = NULL; /* Calculate the default command */ if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { command = "LIST"; if(pop3->id[0] != '\0') /* Message specific LIST so skip the BODY transfer */ pop3->transfer = FTPTRANSFER_INFO; } else command = "RETR"; /* Send the command */ if(pop3->id[0] != '\0') result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", (pop3->custom && pop3->custom[0] != '\0' ? pop3->custom : command), pop3->id); else result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", (pop3->custom && pop3->custom[0] != '\0' ? pop3->custom : command)); if(!result) state(conn, POP3_COMMAND); return result; } /*********************************************************************** * * pop3_perform_quit() * * Performs the quit action prior to sclose() be called. */ static CURLcode pop3_perform_quit(struct connectdata *conn) { /* Send the QUIT command */ CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT"); if(!result) state(conn, POP3_QUIT); return result; } /* For the initial server greeting */ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); (void)instate; /* no use for this yet */ if(pop3code != '+') { failf(data, "Got unexpected pop3-server response"); result = CURLE_WEIRD_SERVER_REPLY; } else { /* Does the server support APOP authentication? */ if(len >= 4 && line[len - 2] == '>') { /* Look for the APOP timestamp */ size_t i; for(i = 3; i < len - 2; ++i) { if(line[i] == '<') { /* Calculate the length of the timestamp */ size_t timestamplen = len - 1 - i; char *at; if(!timestamplen) break; /* Allocate some memory for the timestamp */ pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); if(!pop3c->apoptimestamp) break; /* Copy the timestamp */ memcpy(pop3c->apoptimestamp, line + i, timestamplen); pop3c->apoptimestamp[timestamplen] = '\0'; /* If the timestamp does not contain '@' it is not (as required by RFC-1939) conformant to the RFC-822 message id syntax, and we therefore do not use APOP authentication. */ at = strchr(pop3c->apoptimestamp, '@'); if(!at) Curl_safefree(pop3c->apoptimestamp); else /* Store the APOP capability */ pop3c->authtypes |= POP3_TYPE_APOP; break; } } } result = pop3_perform_capa(conn); } return result; } /* For CAPA responses */ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); (void)instate; /* no use for this yet */ /* Do we have a untagged continuation response? */ if(pop3code == '*') { /* Does the server support the STLS capability? */ if(len >= 4 && !memcmp(line, "STLS", 4)) pop3c->tls_supported = TRUE; /* Does the server support clear text authentication? */ else if(len >= 4 && !memcmp(line, "USER", 4)) pop3c->authtypes |= POP3_TYPE_CLEARTEXT; /* Does the server support SASL based authentication? */ else if(len >= 5 && !memcmp(line, "SASL ", 5)) { pop3c->authtypes |= POP3_TYPE_SASL; /* Advance past the SASL keyword */ line += 5; len -= 5; /* Loop through the data line */ for(;;) { size_t llen; size_t wordlen; unsigned int mechbit; while(len && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { line++; len--; } if(!len) break; /* Extract the word */ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && line[wordlen] != '\t' && line[wordlen] != '\r' && line[wordlen] != '\n';) wordlen++; /* Test the word for a matching authentication mechanism */ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); if(mechbit && llen == wordlen) pop3c->sasl.authmechs |= mechbit; line += wordlen; len -= wordlen; } } } else if(pop3code == '+') { if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested */ if(pop3c->tls_supported) /* Switch to TLS connection now */ result = pop3_perform_starttls(conn); else if(data->set.use_ssl == CURLUSESSL_TRY) /* Fallback and carry on with authentication */ result = pop3_perform_authentication(conn); else { failf(data, "STLS not supported."); result = CURLE_USE_SSL_FAILED; } } else result = pop3_perform_authentication(conn); } else { /* Clear text is supported when CAPA isn't recognised */ pop3c->authtypes |= POP3_TYPE_CLEARTEXT; result = pop3_perform_authentication(conn); } return result; } /* For STARTTLS responses */ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else result = pop3_perform_authentication(conn); } else result = pop3_perform_upgrade_tls(conn); return result; } /* For SASL authentication responses */ static CURLcode pop3_state_auth_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; saslprogress progress; (void)instate; /* no use for this yet */ result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); if(!result) switch(progress) { case SASL_DONE: state(conn, POP3_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ #ifndef CURL_DISABLE_CRYPTO_AUTH if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) /* Perform APOP authentication */ result = pop3_perform_apop(conn); else #endif if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) /* Perform clear text authentication */ result = pop3_perform_user(conn); else { failf(data, "Authentication cancelled"); result = CURLE_LOGIN_DENIED; } break; default: break; } return result; } #ifndef CURL_DISABLE_CRYPTO_AUTH /* For APOP responses */ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { failf(data, "Authentication failed: %d", pop3code); result = CURLE_LOGIN_DENIED; } else /* End of connect phase */ state(conn, POP3_STOP); return result; } #endif /* For USER responses */ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } else /* Send the PASS command */ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", conn->passwd ? conn->passwd : ""); if(!result) state(conn, POP3_PASS); return result; } /* For PASS responses */ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); result = CURLE_LOGIN_DENIED; } else /* End of connect phase */ state(conn, POP3_STOP); return result; } /* For command responses */ static CURLcode pop3_state_command_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; (void)instate; /* no use for this yet */ if(pop3code != '+') { state(conn, POP3_STOP); return CURLE_RECV_ERROR; } /* This 'OK' line ends with a CR LF pair which is the two first bytes of the EOB string so count this is two matching bytes. This is necessary to make the code detect the EOB if the only data than comes now is %2e CR LF like when there is no body to return. */ pop3c->eob = 2; /* But since this initial CR LF pair is not part of the actual body, we set the strip counter here so that these bytes won't be delivered. */ pop3c->strip = 2; if(pop3->transfer == FTPTRANSFER_BODY) { /* POP3 download */ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); if(pp->cache) { /* The header "cache" contains a bunch of data that is actually body content so send it as such. Note that there may even be additional "headers" after the body */ if(!data->set.opt_no_body) { result = Curl_pop3_write(conn, pp->cache, pp->cache_size); if(result) return result; } /* Free the cache */ Curl_safefree(pp->cache); /* Reset the cache size */ pp->cache_size = 0; } } /* End of DO phase */ state(conn, POP3_STOP); return result; } static CURLcode pop3_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int pop3code; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; size_t nread = 0; /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ if(pop3c->state == POP3_UPGRADETLS) return pop3_perform_upgrade_tls(conn); /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); do { /* Read the response from the server */ result = Curl_pp_readresp(sock, pp, &pop3code, &nread); if(result) return result; if(!pop3code) break; /* We have now received a full POP3 server response */ switch(pop3c->state) { case POP3_SERVERGREET: result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); break; case POP3_CAPA: result = pop3_state_capa_resp(conn, pop3code, pop3c->state); break; case POP3_STARTTLS: result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); break; case POP3_AUTH: result = pop3_state_auth_resp(conn, pop3code, pop3c->state); break; #ifndef CURL_DISABLE_CRYPTO_AUTH case POP3_APOP: result = pop3_state_apop_resp(conn, pop3code, pop3c->state); break; #endif case POP3_USER: result = pop3_state_user_resp(conn, pop3code, pop3c->state); break; case POP3_PASS: result = pop3_state_pass_resp(conn, pop3code, pop3c->state); break; case POP3_COMMAND: result = pop3_state_command_resp(conn, pop3code, pop3c->state); break; case POP3_QUIT: /* fallthrough, just stop! */ default: /* internal error */ state(conn, POP3_STOP); break; } } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); return result; } /* Called repeatedly until done from multi.c */ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); if(result || !pop3c->ssldone) return result; } result = Curl_pp_statemach(&pop3c->pp, FALSE, FALSE); *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; return result; } static CURLcode pop3_block_statemach(struct connectdata *conn, bool disconnecting) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; while(pop3c->state != POP3_STOP && !result) result = Curl_pp_statemach(&pop3c->pp, TRUE, disconnecting); return result; } /* Allocate and initialize the POP3 struct for the current Curl_easy if required */ static CURLcode pop3_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct POP3 *pop3; pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); if(!pop3) result = CURLE_OUT_OF_MEMORY; return result; } /* For the POP3 "protocol connect" and "doing" phases only */ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks) { return Curl_pp_getsock(&conn->proto.pop3c.pp, socks); } /*********************************************************************** * * pop3_connect() * * This function should do everything that is to be considered a part of the * connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect * phase is done when this function returns, or FALSE if not. */ static CURLcode pop3_connect(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; *done = FALSE; /* default to not done yet */ /* We always support persistent connections in POP3 */ connkeep(conn, "POP3 default"); /* Set the default response time-out */ pp->response_time = RESP_TIMEOUT; pp->statemach_act = pop3_statemach_act; pp->endofresp = pop3_endofresp; pp->conn = conn; /* Set the default preferred authentication type and mechanism */ pop3c->preftype = POP3_TYPE_ANY; Curl_sasl_init(&pop3c->sasl, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_init(pp); /* Parse the URL options */ result = pop3_parse_url_options(conn); if(result) return result; /* Start off waiting for the server greeting response */ state(conn, POP3_SERVERGREET); result = pop3_multi_statemach(conn, done); return result; } /*********************************************************************** * * pop3_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; (void)premature; if(!pop3) return CURLE_OK; if(status) { connclose(conn, "POP3 done with bad status"); result = status; /* use the already set error code */ } /* Cleanup our per-request based variables */ Curl_safefree(pop3->id); Curl_safefree(pop3->custom); /* Clear the transfer mode for the next request */ pop3->transfer = FTPTRANSFER_BODY; return result; } /*********************************************************************** * * pop3_perform() * * This is the actual DO function for POP3. Get a message/listing according to * the options previously setup. */ static CURLcode pop3_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { /* This is POP3 and no proxy */ CURLcode result = CURLE_OK; struct POP3 *pop3 = conn->data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { /* Requested no body means no transfer */ pop3->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* Start the first command in the DO phase */ result = pop3_perform_command(conn); if(result) return result; /* Run the state-machine */ result = pop3_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); return result; } /*********************************************************************** * * pop3_do() * * This function is registered as 'curl_do' function. It decodes the path * parts etc as a wrapper to the actual DO function (pop3_perform). * * The input argument is already checked for validity. */ static CURLcode pop3_do(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ /* Parse the URL path */ result = pop3_parse_url_path(conn); if(result) return result; /* Parse the custom request */ result = pop3_parse_custom_request(conn); if(result) return result; result = pop3_regular_transfer(conn, done); return result; } /*********************************************************************** * * pop3_disconnect() * * Disconnect from an POP3 server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) { struct pop3_conn *pop3c = &conn->proto.pop3c; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ /* The POP3 session may or may not have been allocated/setup at this point! */ if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart) if(!pop3_perform_quit(conn)) (void)pop3_block_statemach(conn, TRUE); /* ignore errors on QUIT */ /* Disconnect from the server */ Curl_pp_disconnect(&pop3c->pp); /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, pop3c->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(pop3c->apoptimestamp); return CURLE_OK; } /* Call this when the DO phase has completed */ static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) { (void)conn; (void)connected; return CURLE_OK; } /* Called from multi.c while DOing */ static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = pop3_multi_statemach(conn, dophase_done); if(result) DEBUGF(infof(conn->data, "DO phase failed\n")); else if(*dophase_done) { result = pop3_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /*********************************************************************** * * pop3_regular_transfer() * * The input argument is already checked for validity. * * Performs all commands done before a regular transfer between a local and a * remote host. */ static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; bool connected = FALSE; struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); /* Carry out the perform */ result = pop3_perform(conn, &connected, dophase_done); /* Perform post DO phase operations if necessary */ if(!result && *dophase_done) result = pop3_dophase_done(conn, connected); return result; } static CURLcode pop3_setup_connection(struct connectdata *conn) { /* Initialise the POP3 layer */ CURLcode result = pop3_init(conn); if(result) return result; /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; return CURLE_OK; } /*********************************************************************** * * pop3_parse_url_options() * * Parse the URL login options. */ static CURLcode pop3_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *ptr = conn->options; pop3c->sasl.resetprefs = TRUE; while(!result && ptr && *ptr) { const char *key = ptr; const char *value; while(*ptr && *ptr != '=') ptr++; value = ptr + 1; while(*ptr && *ptr != ';') ptr++; if(strncasecompare(key, "AUTH=", 5)) { result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, value, ptr - value); if(result && strncasecompare(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; pop3c->sasl.prefmech = SASL_AUTH_NONE; result = CURLE_OK; } } else result = CURLE_URL_MALFORMAT; if(*ptr == ';') ptr++; } if(pop3c->preftype != POP3_TYPE_APOP) switch(pop3c->sasl.prefmech) { case SASL_AUTH_NONE: pop3c->preftype = POP3_TYPE_NONE; break; case SASL_AUTH_DEFAULT: pop3c->preftype = POP3_TYPE_ANY; break; default: pop3c->preftype = POP3_TYPE_SASL; break; } return result; } /*********************************************************************** * * pop3_parse_url_path() * * Parse the URL path into separate path components. */ static CURLcode pop3_parse_url_path(struct connectdata *conn) { /* The POP3 struct is already initialised in pop3_connect() */ struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *path = &data->state.up.path[1]; /* skip leading path */ /* URL decode the path for the message ID */ return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); } /*********************************************************************** * * pop3_parse_custom_request() * * Parse the custom request. */ static CURLcode pop3_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; /* URL decode the custom request */ if(custom) result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); return result; } /*********************************************************************** * * Curl_pop3_write() * * This function scans the body after the end-of-body and writes everything * until the end is found. */ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) { /* This code could be made into a special function in the handler struct */ CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; struct pop3_conn *pop3c = &conn->proto.pop3c; bool strip_dot = FALSE; size_t last = 0; size_t i; /* Search through the buffer looking for the end-of-body marker which is 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches the eob so the server will have prefixed it with an extra dot which we need to strip out. Additionally the marker could of course be spread out over 5 different data chunks. */ for(i = 0; i < nread; i++) { size_t prev = pop3c->eob; switch(str[i]) { case 0x0d: if(pop3c->eob == 0) { pop3c->eob++; if(i) { /* Write out the body part that didn't match */ result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], i - last); if(result) return result; last = i; } } else if(pop3c->eob == 3) pop3c->eob++; else /* If the character match wasn't at position 0 or 3 then restart the pattern matching */ pop3c->eob = 1; break; case 0x0a: if(pop3c->eob == 1 || pop3c->eob == 4) pop3c->eob++; else /* If the character match wasn't at position 1 or 4 then start the search again */ pop3c->eob = 0; break; case 0x2e: if(pop3c->eob == 2) pop3c->eob++; else if(pop3c->eob == 3) { /* We have an extra dot after the CRLF which we need to strip off */ strip_dot = TRUE; pop3c->eob = 0; } else /* If the character match wasn't at position 2 then start the search again */ pop3c->eob = 0; break; default: pop3c->eob = 0; break; } /* Did we have a partial match which has subsequently failed? */ if(prev && prev >= pop3c->eob) { /* Strip can only be non-zero for the very first mismatch after CRLF and then both prev and strip are equal and nothing will be output below */ while(prev && pop3c->strip) { prev--; pop3c->strip--; } if(prev) { /* If the partial match was the CRLF and dot then only write the CRLF as the server would have inserted the dot */ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, strip_dot ? prev - 1 : prev); if(result) return result; last = i; strip_dot = FALSE; } } } if(pop3c->eob == POP3_EOB_LEN) { /* We have a full match so the transfer is done, however we must transfer the CRLF at the start of the EOB as this is considered to be part of the message as per RFC-1939, sect. 3 */ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); k->keepon &= ~KEEP_RECV; pop3c->eob = 0; return result; } if(pop3c->eob) /* While EOB is matching nothing should be output */ return CURLE_OK; if(nread - last) { result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last], nread - last); } return result; } #endif /* CURL_DISABLE_POP3 */ davix-0.8.0/deps/curl/lib/curl_base64.h0000644000000000000000000000310014121063461016250 0ustar rootroot#ifndef HEADER_CURL_BASE64_H #define HEADER_CURL_BASE64_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen); #endif /* HEADER_CURL_BASE64_H */ davix-0.8.0/deps/curl/lib/rand.c0000644000000000000000000001230114121063461015061 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_FCNTL_H #include #endif #include #include "vtls/vtls.h" #include "sendf.h" #include "rand.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) { unsigned int r; CURLcode result = CURLE_OK; static unsigned int randseed; static bool seeded = FALSE; #ifdef CURLDEBUG char *force_entropy = getenv("CURL_ENTROPY"); if(force_entropy) { if(!seeded) { unsigned int seed = 0; size_t elen = strlen(force_entropy); size_t clen = sizeof(seed); size_t min = elen < clen ? elen : clen; memcpy((char *)&seed, force_entropy, min); randseed = ntohl(seed); seeded = TRUE; } else randseed++; *rnd = randseed; return CURLE_OK; } #endif /* data may be NULL! */ result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); if(result != CURLE_NOT_BUILT_IN) /* only if there is no random function in the TLS backend do the non crypto version, otherwise return result */ return result; /* ---- non-cryptographic version following ---- */ #ifdef RANDOM_FILE if(!seeded) { /* if there's a random file to read a seed from, use it */ int fd = open(RANDOM_FILE, O_RDONLY); if(fd > -1) { /* read random data into the randseed variable */ ssize_t nread = read(fd, &randseed, sizeof(randseed)); if(nread == sizeof(randseed)) seeded = TRUE; close(fd); } } #endif if(!seeded) { struct curltime now = Curl_now(); infof(data, "WARNING: Using weak random seed\n"); randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; randseed = randseed * 1103515245 + 12345; randseed = randseed * 1103515245 + 12345; randseed = randseed * 1103515245 + 12345; seeded = TRUE; } /* Return an unsigned 32-bit pseudo-random number. */ r = randseed = randseed * 1103515245 + 12345; *rnd = (r << 16) | ((r >> 16) & 0xFFFF); return CURLE_OK; } /* * Curl_rand() stores 'num' number of random unsigned integers in the buffer * 'rndptr' points to. * * If libcurl is built without TLS support or with a TLS backend that lacks a * proper random API (Gskit or mbedTLS), this function will use "weak" random. * * When built *with* TLS support and a backend that offers strong random, it * will return error if it cannot provide strong random values. * * NOTE: 'data' may be passed in as NULL when coming from external API without * easy handle! * */ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; DEBUGASSERT(num > 0); while(num) { unsigned int r; size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int); result = randit(data, &r); if(result) return result; while(left) { *rnd++ = (unsigned char)(r & 0xFF); r >>= 8; --num; --left; } } return result; } /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random * hexadecimal digits PLUS a zero terminating byte. It must be an odd number * size. */ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; const char *hex = "0123456789abcdef"; unsigned char buffer[128]; unsigned char *bufp = buffer; DEBUGASSERT(num > 1); #ifdef __clang_analyzer__ /* This silences a scan-build warning about accessing this buffer with uninitialized memory. */ memset(buffer, 0, sizeof(buffer)); #endif if((num/2 >= sizeof(buffer)) || !(num&1)) /* make sure it fits in the local buffer and that it is an odd number! */ return CURLE_BAD_FUNCTION_ARGUMENT; num--; /* save one for zero termination */ result = Curl_rand(data, buffer, num/2); if(result) return result; while(num) { /* clang-tidy warns on this line without this comment: */ /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */ *rnd++ = hex[(*bufp & 0xF0)>>4]; *rnd++ = hex[*bufp & 0x0F]; bufp++; num -= 2; } *rnd = 0; return result; } davix-0.8.0/deps/curl/lib/multiif.h0000644000000000000000000000746614121063461015633 0ustar rootroot#ifndef HEADER_CURL_MULTIIF_H #define HEADER_CURL_MULTIIF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Prototypes for library-wide functions provided by multi.c */ void Curl_updatesocket(struct Curl_easy *data); void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id); void Curl_expire_clear(struct Curl_easy *data); void Curl_expire_done(struct Curl_easy *data, expire_id id); void Curl_update_timer(struct Curl_multi *multi); void Curl_attach_connnection(struct Curl_easy *data, struct connectdata *conn); bool Curl_multiplex_wanted(const struct Curl_multi *multi); void Curl_set_in_callback(struct Curl_easy *data, bool value); bool Curl_is_in_callback(struct Curl_easy *easy); /* Internal version of curl_multi_init() accepts size parameters for the socket and connection hashes */ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); /* the write bits start at bit 16 for the *getsock() bitmap */ #define GETSOCK_WRITEBITSTART 16 #define GETSOCK_BLANK 0 /* no bits set */ /* set the bit for the given sock number to make the bitmap for writable */ #define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) /* set the bit for the given sock number to make the bitmap for readable */ #define GETSOCK_READSOCK(x) (1 << (x)) #ifdef DEBUGBUILD /* * Curl_multi_dump is not a stable public function, this is only meant to * allow easier tracking of the internal handle's state and what sockets * they use. Only for research and development DEBUGBUILD enabled builds. */ void Curl_multi_dump(struct Curl_multi *multi); #endif /* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ size_t Curl_multi_max_host_connections(struct Curl_multi *multi); /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ size_t Curl_multi_max_total_connections(struct Curl_multi *multi); void Curl_multiuse_state(struct connectdata *conn, int bundlestate); /* use BUNDLE_* defines */ /* * Curl_multi_closed() * * Used by the connect code to tell the multi_socket code that one of the * sockets we were using is about to be closed. This function will then * remove it from the sockethash for this handle to make the multi_socket API * behave properly, especially for the case when libcurl will create another * socket again and it gets the same file descriptor number. */ void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s); /* * Add a handle and move it into PERFORM state at once. For pushed streams. */ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, struct Curl_easy *data, struct connectdata *conn); /* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */ unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi); #endif /* HEADER_CURL_MULTIIF_H */ davix-0.8.0/deps/curl/lib/dotdot.h0000644000000000000000000000221114121063461015436 0ustar rootroot#ifndef HEADER_CURL_DOTDOT_H #define HEADER_CURL_DOTDOT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ char *Curl_dedotdotify(const char *input); #endif /* HEADER_CURL_DOTDOT_H */ davix-0.8.0/deps/curl/lib/Makefile.vxworks0000644000000000000000000001311614121063461017160 0ustar rootroot#***************************************************************************** # # #Filename : Makefile.vxworks #Description: makefile to be used in order to compile libcurl for VxWoorks 6.3. # #How to use: # 1. Adjust environment variables at the file beginning # 2. Open the Command Prompt window and change directory ('cd') # into the 'lib' folder # 3. Add /bin folder to the PATH environment variable # For example type 'set PATH=C:/embedded/cygwin/bin;%PATH%' # 4. Build the library by typing 'make -f ./Makefile.vxworks' # As a result the libcurl.a should be created in the 'lib' folder. # To clean package use 'make -f ./Makefile.vxworks clean' #Requirements: # 1. WinXP machine # 2. Full CYGWIN installation (open source) with GNU make version # v3.78 or higher # 3. WindRiver Workbench with vxWorks 6.3 (commercial) #***************************************************************************** # ---------------------------------------------------------------------- # Environment # ---------------------------------------------------------------------- export WIND_HOME := C:/embedded/Workbench2.5.0.1 export WIND_BASE := $(WIND_HOME)/vxworks-6.3 export WIND_HOST_TYPE := x86-win32 # BUILD_TYE:= | (build with debugging info or optimized) BUILD_TYPE := debug USER_CFLAGS:= # directories where to seek for includes and libraries OPENSSL_INC := D:/libraries/openssl/openssl-0.9.8zc-vxWorks6.3/include OPENSSL_LIB := D:/libraries/openssl/openssl-0.9.8zc-vxWorks6.3 ZLIB_INC := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/zlib-1.2.8 ZLIB_LIB := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib ARES_INC := ARES_LIB := # ---------------------------------------------------------------------- # Compiler # ---------------------------------------------------------------------- CC := ccppc AR := arppc LINK := ccppc CFLAGS := -D__GNUC__ -D__ppc__ -msoft-float -fno-builtin -mcpu=604 -mlongcall -DCPU=PPC604 -D_GNU_TOOL -Wall -W -Winline $(USER_CFLAGS) LDFLAGS := -nostdlib -Wl,-i -Wl,-X INCLUDE_FLAG := -I C_DEBUGFLAG := -g C_OPTFLAG := -O2 COMPILE_ONLY_FLAG := -c OBJ_EXTENSION := .o CC_OBJ_OUTPUT = -o $@ ARFLAGS := -rc LIBS_FLAG := -l LIBS_DIRFLAG:= -L LD_DEBUGFLAG := $(C_DEBUGFLAG) EXECUTE_EXTENSION := .out TOOL_CHAIN_BIN := $(WIND_HOME)/gnu/3.4.4-vxworks-6.3/$(WIND_HOST_TYPE)/bin/ # ---------------------------------------------------------------------- # Add -DINET6 if the OS kernel image was built with IPv6 support # CFLAGS += -DINET6 # Set up compiler and linker flags for debug or optimization ifeq ($(BUILD_TYPE), debug) CFLAGS += $(C_DEBUGFLAG) LDFLAGS += $(LD_DEBUGFLAG) else CFLAGS += $(C_OPTFLAG) endif # ---------------------------------------------------------------------- # Main Makefile and possible sub-make files MAKEFILES := Makefile.vxworks # List of external include directories #----- # IMPORTANT: include OPENSSL directories before system # in order to prevent WindRiver OpenSSL to be used. #----- INCLUDE_DIRS := ../include $(OPENSSL_INC) $(ZLIB_INC) $(ARES_INC) $(WIND_BASE)/target/h $(WIND_BASE)/target/h/wrn/coreip # List of external libraries and their directories LIBS_LIST := . LIB_DIRS := . ifneq ($(OPENSSL_LIB), ) LIBS_LIST += crypto ssl LIB_DIRS += $(OPENSSL_LIB) endif ifneq ($(ZLIB_LIB), ) LIBS_LIST += z LIB_DIRS += $(ZLIB_LIB) endif ifneq ($(ARES_LIB), ) LIBS_LIST += ares LIB_DIRS += $(ARES_LIB) endif # Add include and library directories and libraries CFLAGS += $(INCLUDE_DIRS:%=$(INCLUDE_FLAG)%) LDFLAGS += $(LIB_DIRS:%=$(LIBS_DIRFLAG)%) # List of targets to make for libs target LIBS_TARGET_LIST := libcurl.a # List of execuatble applications to make in addition to libs for all target EXE_TARGET_LIST := # Support for echoing rules # If ECHORULES variable was set (for example, using 'make' command line) # some shell commands in the rules will be echoed ifneq ($(strip $(findstring $(ECHORULES), yes YES 1 true TRUE)),) _@_ := else _@_ := @ endif # Directory to hold compilation intermediate files TMP_DIR := tmp # Get sources and headers to be compiled include Makefile.inc # List of headers INCLUDE_FILES := $(HHEADERS) INCLUDE_FILES += $(shell find ../include -name \*.h) # List of sources OBJLIST := $(CSOURCES:%.c=$(TMP_DIR)/%$(OBJ_EXTENSION)) # ---------------------------------------------------------------------- #### default rule # It should be first rule in this file .PHONY: default default: libcurl.a #### Compiling C files $(TMP_DIR)/%$(OBJ_EXTENSION): %.c $(MAKEFILES) @echo Compiling C file $< $(ECHO_STDOUT) @[ -d $(@D) ] || mkdir -p $(@D) $(_@_) $(TOOL_CHAIN_BIN)$(CC) $(COMPILE_ONLY_FLAG) $(CFLAGS) $< $(CC_OBJ_OUTPUT) #### Creating library $(LIBS_TARGET_LIST): $(INCLUDE_FILES) $(MAKEFILES) $(OBJLIST) @echo Creating library $@ $(ECHO_STDOUT) $(_@_) [ -d $(@D) ] || mkdir -p $(@D) $(_@_) rm -f $@ $(_@_) $(TOOL_CHAIN_BIN)$(AR) $(ARFLAGS) $@ $(filter %$(OBJ_EXTENSION), $^) #### Creating application $(EXE_TARGET_LIST): $(INCLUDE_FILES) $(MAKEFILES) $(LIBS_TARGET_LIST) @echo Creating application $@ @[ -d $(@D) ] || mkdir -p $(@D) $(_@_) $(TOOL_CHAIN_BIN)$(LINK) $(CC_OBJ_OUTPUT) $($(@)_EXE_OBJ_LIST) $(LDFLAGS) $($(@)_EXE_LIBS_NEEDED:%=$(LIBS_FLAG)%) $(LIBS_LIST:%=$(LIBS_FLAG)%) $(USER_LIBS_LIST) $(USER_LIBS_LIST) #### Master Targets libs: $(LIBS_TARGET_LIST) @echo All libs made. all: $(LIBS_TARGET_LIST) $(EXE_TARGET_LIST) $(INCLUDE_TARGET_LIST) @echo All targets made. # Clean up .PHONY: clean clean: $(_@_) rm -rf $(TMP_DIR) @echo libcurl was cleaned. davix-0.8.0/deps/curl/lib/progress.c0000644000000000000000000005252614121063461016016 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #include "sendf.h" #include "multiif.h" #include "progress.h" #include "timeval.h" #include "curl_printf.h" /* check rate limits within this many recent milliseconds, at minimum. */ #define MIN_RATE_LIMIT_PERIOD 3000 #ifndef CURL_DISABLE_PROGRESS_METER /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ static void time2str(char *r, curl_off_t seconds) { curl_off_t h; if(seconds <= 0) { strcpy(r, "--:--:--"); return; } h = seconds / CURL_OFF_T_C(3600); if(h <= CURL_OFF_T_C(99)) { curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output format to fit within the limits. */ curl_off_t d = seconds / CURL_OFF_T_C(86400); h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); if(d <= CURL_OFF_T_C(999)) msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } /* The point of this function would be to return a string of the input data, but never longer than 5 columns (+ one zero byte). Add suffix k, M, G when suitable... */ static char *max5data(curl_off_t bytes, char *max5) { #define ONE_KILOBYTE CURL_OFF_T_C(1024) #define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) #define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) #define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) if(bytes < CURL_OFF_T_C(100000)) msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) /* 'XX.XM' is good as long as we're less than 100 megs */ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); #if (CURL_SIZEOF_CURL_OFF_T > 4) else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) /* 'XXXXM' is good until we're at 10000MB or above */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) /* 10000 MB - 100 GB, we show it as XX.XG */ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) /* up to 10000GB, display without decimal: XXXXG */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) /* up to 10000TB, display without decimal: XXXXT */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); else /* up to 10000PB, display without decimal: XXXXP */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can hold, but our data type is signed so 8192PB will be the maximum. */ #else else msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); #endif return max5; } #endif /* New proposed interface, 9th of February 2000: pgrsStartNow() - sets start time pgrsSetDownloadSize(x) - known expected download size pgrsSetUploadSize(x) - known expected upload size pgrsSetDownloadCounter() - amount of data currently downloaded pgrsSetUploadCounter() - amount of data currently uploaded pgrsUpdate() - show progress pgrsDone() - transfer complete */ int Curl_pgrsDone(struct connectdata *conn) { int rc; struct Curl_easy *data = conn->data; data->progress.lastshow = 0; rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ if(rc) return rc; if(!(data->progress.flags & PGRS_HIDE) && !data->progress.callback) /* only output if we don't use a progress callback and we're not * hidden */ fprintf(data->set.err, "\n"); data->progress.speeder_c = 0; /* reset the progress meter display */ return 0; } /* reset the known transfer sizes */ void Curl_pgrsResetTransferSizes(struct Curl_easy *data) { Curl_pgrsSetDownloadSize(data, -1); Curl_pgrsSetUploadSize(data, -1); } /* * @unittest: 1399 */ void Curl_pgrsTime(struct Curl_easy *data, timerid timer) { struct curltime now = Curl_now(); timediff_t *delta = NULL; switch(timer) { default: case TIMER_NONE: /* mistake filter */ break; case TIMER_STARTOP: /* This is set at the start of a transfer */ data->progress.t_startop = now; break; case TIMER_STARTSINGLE: /* This is set at the start of each single fetch */ data->progress.t_startsingle = now; data->progress.is_t_startransfer_set = false; break; case TIMER_STARTACCEPT: data->progress.t_acceptdata = now; break; case TIMER_NAMELOOKUP: delta = &data->progress.t_nslookup; break; case TIMER_CONNECT: delta = &data->progress.t_connect; break; case TIMER_APPCONNECT: delta = &data->progress.t_appconnect; break; case TIMER_PRETRANSFER: delta = &data->progress.t_pretransfer; break; case TIMER_STARTTRANSFER: delta = &data->progress.t_starttransfer; /* prevent updating t_starttransfer unless: * 1) this is the first time we're setting t_starttransfer * 2) a redirect has occurred since the last time t_starttransfer was set * This prevents repeated invocations of the function from incorrectly * changing the t_starttransfer time. */ if(data->progress.is_t_startransfer_set) { return; } else { data->progress.is_t_startransfer_set = true; break; } case TIMER_POSTRANSFER: /* this is the normal end-of-transfer thing */ break; case TIMER_REDIRECT: data->progress.t_redirect = Curl_timediff_us(now, data->progress.start); break; } if(delta) { timediff_t us = Curl_timediff_us(now, data->progress.t_startsingle); if(us < 1) us = 1; /* make sure at least one microsecond passed */ *delta += us; } } void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_now(); data->progress.is_t_startransfer_set = false; data->progress.ul_limit_start.tv_sec = 0; data->progress.ul_limit_start.tv_usec = 0; data->progress.dl_limit_start.tv_sec = 0; data->progress.dl_limit_start.tv_usec = 0; data->progress.downloaded = 0; data->progress.uploaded = 0; /* clear all bits except HIDE and HEADERS_OUT */ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; Curl_ratelimit(data, data->progress.start); } /* * This is used to handle speed limits, calculating how many milliseconds to * wait until we're back under the speed limit, if needed. * * The way it works is by having a "starting point" (time & amount of data * transferred by then) used in the speed computation, to be used instead of * the start of the transfer. This starting point is regularly moved as * transfer goes on, to keep getting accurate values (instead of average over * the entire transfer). * * This function takes the current amount of data transferred, the amount at * the starting point, the limit (in bytes/s), the time of the starting point * and the current time. * * Returns 0 if no waiting is needed or when no waiting is needed but the * starting point should be reset (to current); or the number of milliseconds * to wait to get back under the speed limit. */ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, curl_off_t startsize, curl_off_t limit, struct curltime start, struct curltime now) { curl_off_t size = cursize - startsize; timediff_t minimum; timediff_t actual; if(!limit || !size) return 0; /* * 'minimum' is the number of milliseconds 'size' should take to download to * stay below 'limit'. */ if(size < CURL_OFF_T_MAX/1000) minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit); else { minimum = (time_t) (size / limit); if(minimum < TIMEDIFF_T_MAX/1000) minimum *= 1000; else minimum = TIMEDIFF_T_MAX; } /* * 'actual' is the time in milliseconds it took to actually download the * last 'size' bytes. */ actual = Curl_timediff(now, start); if(actual < minimum) { /* if it downloaded the data faster than the limit, make it wait the difference */ return (minimum - actual); } return 0; } /* * Set the number of downloaded bytes so far. */ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { data->progress.downloaded = size; } /* * Update the timestamp and sizestamp to use for rate limit calculations. */ void Curl_ratelimit(struct Curl_easy *data, struct curltime now) { /* don't set a new stamp unless the time since last update is long enough */ if(data->set.max_recv_speed > 0) { if(Curl_timediff(now, data->progress.dl_limit_start) >= MIN_RATE_LIMIT_PERIOD) { data->progress.dl_limit_start = now; data->progress.dl_limit_size = data->progress.downloaded; } } if(data->set.max_send_speed > 0) { if(Curl_timediff(now, data->progress.ul_limit_start) >= MIN_RATE_LIMIT_PERIOD) { data->progress.ul_limit_start = now; data->progress.ul_limit_size = data->progress.uploaded; } } } /* * Set the number of uploaded bytes so far. */ void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { data->progress.uploaded = size; } void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_dl = size; data->progress.flags |= PGRS_DL_SIZE_KNOWN; } else { data->progress.size_dl = 0; data->progress.flags &= ~PGRS_DL_SIZE_KNOWN; } } void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_ul = size; data->progress.flags |= PGRS_UL_SIZE_KNOWN; } else { data->progress.size_ul = 0; data->progress.flags &= ~PGRS_UL_SIZE_KNOWN; } } /* returns TRUE if it's time to show the progress meter */ static bool progress_calc(struct connectdata *conn, struct curltime now) { curl_off_t timespent; curl_off_t timespent_ms; /* milliseconds */ struct Curl_easy *data = conn->data; curl_off_t dl = data->progress.downloaded; curl_off_t ul = data->progress.uploaded; bool timetoshow = FALSE; /* The time spent so far (from the start) */ data->progress.timespent = Curl_timediff_us(now, data->progress.start); timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */ timespent_ms = (curl_off_t)data->progress.timespent/1000; /* ms */ /* The average download speed this far */ if(dl < CURL_OFF_T_MAX/1000) data->progress.dlspeed = (dl * 1000 / (timespent_ms>0?timespent_ms:1)); else data->progress.dlspeed = (dl / (timespent>0?timespent:1)); /* The average upload speed this far */ if(ul < CURL_OFF_T_MAX/1000) data->progress.ulspeed = (ul * 1000 / (timespent_ms>0?timespent_ms:1)); else data->progress.ulspeed = (ul / (timespent>0?timespent:1)); /* Calculations done at most once a second, unless end is reached */ if(data->progress.lastshow != now.tv_sec) { int countindex; /* amount of seconds stored in the speeder array */ int nowindex = data->progress.speeder_c% CURR_TIME; data->progress.lastshow = now.tv_sec; timetoshow = TRUE; /* Let's do the "current speed" thing, with the dl + ul speeds combined. Store the speed at entry 'nowindex'. */ data->progress.speeder[ nowindex ] = data->progress.downloaded + data->progress.uploaded; /* remember the exact time for this moment */ data->progress.speeder_time [ nowindex ] = now; /* advance our speeder_c counter, which is increased every time we get here and we expect it to never wrap as 2^32 is a lot of seconds! */ data->progress.speeder_c++; /* figure out how many index entries of data we have stored in our speeder array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of transfer. Imagine, after one second we have filled in two entries, after two seconds we've filled in three entries etc. */ countindex = ((data->progress.speeder_c >= CURR_TIME)? CURR_TIME:data->progress.speeder_c) - 1; /* first of all, we don't do this if there's no counted seconds yet */ if(countindex) { int checkindex; timediff_t span_ms; /* Get the index position to compare with the 'nowindex' position. Get the oldest entry possible. While we have less than CURR_TIME entries, the first entry will remain the oldest. */ checkindex = (data->progress.speeder_c >= CURR_TIME)? data->progress.speeder_c%CURR_TIME:0; /* Figure out the exact time for the time span */ span_ms = Curl_timediff(now, data->progress.speeder_time[checkindex]); if(0 == span_ms) span_ms = 1; /* at least one millisecond MUST have passed */ /* Calculate the average speed the last 'span_ms' milliseconds */ { curl_off_t amount = data->progress.speeder[nowindex]- data->progress.speeder[checkindex]; if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */) /* the 'amount' value is bigger than would fit in 32 bits if multiplied with 1000, so we use the double math for this */ data->progress.current_speed = (curl_off_t) ((double)amount/((double)span_ms/1000.0)); else /* the 'amount' value is small enough to fit within 32 bits even when multiplied with 1000 */ data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms; } } else /* the first second we use the average */ data->progress.current_speed = data->progress.ulspeed + data->progress.dlspeed; } /* Calculations end */ return timetoshow; } #ifndef CURL_DISABLE_PROGRESS_METER static void progress_meter(struct connectdata *conn) { struct Curl_easy *data = conn->data; char max5[6][10]; curl_off_t dlpercen = 0; curl_off_t ulpercen = 0; curl_off_t total_percen = 0; curl_off_t total_transfer; curl_off_t total_expected_transfer; char time_left[10]; char time_total[10]; char time_spent[10]; curl_off_t ulestimate = 0; curl_off_t dlestimate = 0; curl_off_t total_estimate; curl_off_t timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */ if(!(data->progress.flags & PGRS_HEADERS_OUT)) { if(data->state.resume_from) { fprintf(data->set.err, "** Resuming transfer from byte position %" CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); } fprintf(data->set.err, " %% Total %% Received %% Xferd Average Speed " "Time Time Time Current\n" " Dload Upload " "Total Spent Left Speed\n"); data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */ } /* Figure out the estimated time of arrival for the upload */ if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && (data->progress.ulspeed > CURL_OFF_T_C(0))) { ulestimate = data->progress.size_ul / data->progress.ulspeed; if(data->progress.size_ul > CURL_OFF_T_C(10000)) ulpercen = data->progress.uploaded / (data->progress.size_ul/CURL_OFF_T_C(100)); else if(data->progress.size_ul > CURL_OFF_T_C(0)) ulpercen = (data->progress.uploaded*100) / data->progress.size_ul; } /* ... and the download */ if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && (data->progress.dlspeed > CURL_OFF_T_C(0))) { dlestimate = data->progress.size_dl / data->progress.dlspeed; if(data->progress.size_dl > CURL_OFF_T_C(10000)) dlpercen = data->progress.downloaded / (data->progress.size_dl/CURL_OFF_T_C(100)); else if(data->progress.size_dl > CURL_OFF_T_C(0)) dlpercen = (data->progress.downloaded*100) / data->progress.size_dl; } /* Now figure out which of them is slower and use that one for the total estimate! */ total_estimate = ulestimate>dlestimate?ulestimate:dlestimate; /* create the three time strings */ time2str(time_left, total_estimate > 0?(total_estimate - timespent):0); time2str(time_total, total_estimate); time2str(time_spent, timespent); /* Get the total amount of data expected to get transferred */ total_expected_transfer = ((data->progress.flags & PGRS_UL_SIZE_KNOWN)? data->progress.size_ul:data->progress.uploaded)+ ((data->progress.flags & PGRS_DL_SIZE_KNOWN)? data->progress.size_dl:data->progress.downloaded); /* We have transferred this much so far */ total_transfer = data->progress.downloaded + data->progress.uploaded; /* Get the percentage of data transferred so far */ if(total_expected_transfer > CURL_OFF_T_C(10000)) total_percen = total_transfer / (total_expected_transfer/CURL_OFF_T_C(100)); else if(total_expected_transfer > CURL_OFF_T_C(0)) total_percen = (total_transfer*100) / total_expected_transfer; fprintf(data->set.err, "\r" "%3" CURL_FORMAT_CURL_OFF_T " %s " "%3" CURL_FORMAT_CURL_OFF_T " %s " "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s", total_percen, /* 3 letters */ /* total % */ max5data(total_expected_transfer, max5[2]), /* total size */ dlpercen, /* 3 letters */ /* rcvd % */ max5data(data->progress.downloaded, max5[0]), /* rcvd size */ ulpercen, /* 3 letters */ /* xfer % */ max5data(data->progress.uploaded, max5[1]), /* xfer size */ max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */ max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */ time_total, /* 8 letters */ /* total time */ time_spent, /* 8 letters */ /* time spent */ time_left, /* 8 letters */ /* time left */ max5data(data->progress.current_speed, max5[5]) ); /* we flush the output stream to make it appear as soon as possible */ fflush(data->set.err); } #else /* progress bar disabled */ #define progress_meter(x) Curl_nop_stmt #endif /* * Curl_pgrsUpdate() returns 0 for success or the value returned by the * progress callback! */ int Curl_pgrsUpdate(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct curltime now = Curl_now(); /* what time is it */ bool showprogress = progress_calc(conn, now); if(!(data->progress.flags & PGRS_HIDE)) { if(data->set.fxferinfo) { int result; /* There's a callback set, call that */ Curl_set_in_callback(data, true); result = data->set.fxferinfo(data->set.progress_client, data->progress.size_dl, data->progress.downloaded, data->progress.size_ul, data->progress.uploaded); Curl_set_in_callback(data, false); if(result != CURL_PROGRESSFUNC_CONTINUE) { if(result) failf(data, "Callback aborted"); return result; } } else if(data->set.fprogress) { int result; /* The older deprecated callback is set, call that */ Curl_set_in_callback(data, true); result = data->set.fprogress(data->set.progress_client, (double)data->progress.size_dl, (double)data->progress.downloaded, (double)data->progress.size_ul, (double)data->progress.uploaded); Curl_set_in_callback(data, false); if(result != CURL_PROGRESSFUNC_CONTINUE) { if(result) failf(data, "Callback aborted"); return result; } } if(showprogress) progress_meter(conn); } return 0; } davix-0.8.0/deps/curl/lib/non-ascii.h0000644000000000000000000000466114121063461016034 0ustar rootroot#ifndef HEADER_CURL_NON_ASCII_H #define HEADER_CURL_NON_ASCII_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef CURL_DOES_CONVERSIONS #include "urldata.h" /* * Curl_convert_clone() returns a malloced copy of the source string (if * returning CURLE_OK), with the data converted to network format. * * If no conversion was needed *outbuf may be NULL. */ CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf); void Curl_convert_init(struct Curl_easy *data); void Curl_convert_setup(struct Curl_easy *data); void Curl_convert_close(struct Curl_easy *data); CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length); CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length); CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) #define Curl_convert_init(x) Curl_nop_stmt #define Curl_convert_setup(x) Curl_nop_stmt #define Curl_convert_close(x) Curl_nop_stmt #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) #endif #endif /* HEADER_CURL_NON_ASCII_H */ davix-0.8.0/deps/curl/lib/curl_multibyte.h0000644000000000000000000000702514121063461017214 0ustar rootroot#ifndef HEADER_CURL_MULTIBYTE_H #define HEADER_CURL_MULTIBYTE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \ defined(USE_WIN32_LDAP)) && defined(UNICODE)) /* * MultiByte conversions using Windows kernel32 library. */ wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8); char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w); #endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */ #if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \ defined(USE_WIN32_LDAP) /* * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8() * and Curl_unicodefree() main purpose is to minimize the number of * preprocessor conditional directives needed by code using these * to differentiate UNICODE from non-UNICODE builds. * * When building with UNICODE defined, this two macros * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() * return a pointer to a newly allocated memory area holding result. * When the result is no longer needed, allocated memory is intended * to be free'ed with Curl_unicodefree(). * * When building without UNICODE defined, this macros * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8() * return the pointer received as argument. Curl_unicodefree() does * no actual free'ing of this pointer it is simply set to NULL. */ #ifdef UNICODE #define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr)) #define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr)) #define Curl_unicodefree(ptr) \ do { \ if(ptr) { \ free(ptr); \ (ptr) = NULL; \ } \ } while(0) typedef union { unsigned short *tchar_ptr; const unsigned short *const_tchar_ptr; unsigned short *tbyte_ptr; const unsigned short *const_tbyte_ptr; } xcharp_u; #else #define Curl_convert_UTF8_to_tchar(ptr) (ptr) #define Curl_convert_tchar_to_UTF8(ptr) (ptr) #define Curl_unicodefree(ptr) \ do {(ptr) = NULL;} while(0) typedef union { char *tchar_ptr; const char *const_tchar_ptr; unsigned char *tbyte_ptr; const unsigned char *const_tbyte_ptr; } xcharp_u; #endif /* UNICODE */ #endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */ #endif /* HEADER_CURL_MULTIBYTE_H */ davix-0.8.0/deps/curl/lib/fileinfo.c0000644000000000000000000000263714121063461015743 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #include "strdup.h" #include "fileinfo.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" struct fileinfo *Curl_fileinfo_alloc(void) { return calloc(1, sizeof(struct fileinfo)); } void Curl_fileinfo_cleanup(struct fileinfo *finfo) { if(!finfo) return; Curl_safefree(finfo->info.b_data); free(finfo); } #endif davix-0.8.0/deps/curl/lib/http_chunks.h0000644000000000000000000000664114121063461016506 0ustar rootroot#ifndef HEADER_CURL_HTTP_CHUNKS_H #define HEADER_CURL_HTTP_CHUNKS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ struct connectdata; /* * The longest possible hexadecimal number we support in a chunked transfer. * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul() * to convert it, we "only" support 2^32 bytes chunk data. */ #define MAXNUM_SIZE 16 typedef enum { /* await and buffer all hexadecimal digits until we get one that isn't a hexadecimal digit. When done, we go CHUNK_LF */ CHUNK_HEX, /* wait for LF, ignore all else */ CHUNK_LF, /* We eat the amount of data specified. When done, we move on to the POST_CR state. */ CHUNK_DATA, /* POSTLF should get a CR and then a LF and nothing else, then move back to HEX as the CRLF combination marks the end of a chunk. A missing CR is no big deal. */ CHUNK_POSTLF, /* Used to mark that we're out of the game. NOTE: that there's a 'dataleft' field in the struct that will tell how many bytes that were not passed to the client in the end of the last buffer! */ CHUNK_STOP, /* At this point optional trailer headers can be found, unless the next line is CRLF */ CHUNK_TRAILER, /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. Next char must be a LF */ CHUNK_TRAILER_CR, /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be signalled If this is an empty trailer CHUNKE_STOP will be signalled. Otherwise the trailer will be broadcasted via Curl_client_write() and the next state will be CHUNK_TRAILER */ CHUNK_TRAILER_POSTCR } ChunkyState; typedef enum { CHUNKE_STOP = -1, CHUNKE_OK = 0, CHUNKE_TOO_LONG_HEX = 1, CHUNKE_ILLEGAL_HEX, CHUNKE_BAD_CHUNK, CHUNKE_BAD_ENCODING, CHUNKE_OUT_OF_MEMORY, CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */ CHUNKE_LAST } CHUNKcode; const char *Curl_chunked_strerror(CHUNKcode code); struct Curl_chunker { char hexbuffer[ MAXNUM_SIZE + 1]; int hexindex; ChunkyState state; curl_off_t datasize; size_t dataleft; /* untouched data amount at the end of the last buffer */ }; /* The following functions are defined in http_chunks.c */ void Curl_httpchunk_init(struct connectdata *conn); CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t length, ssize_t *wrote, CURLcode *passthru); #endif /* HEADER_CURL_HTTP_CHUNKS_H */ davix-0.8.0/deps/curl/lib/escape.c0000644000000000000000000001541314121063461015404 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ #include "curl_setup.h" #include #include "urldata.h" #include "warnless.h" #include "non-ascii.h" #include "escape.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Portable character check (remember EBCDIC). Do not use isalnum() because its behavior is altered by the current locale. See https://tools.ietf.org/html/rfc3986#section-2.3 */ bool Curl_isunreserved(unsigned char in) { switch(in) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '-': case '.': case '_': case '~': return TRUE; default: break; } return FALSE; } /* for ABI-compatibility with previous versions */ char *curl_escape(const char *string, int inlength) { return curl_easy_escape(NULL, string, inlength); } /* for ABI-compatibility with previous versions */ char *curl_unescape(const char *string, int length) { return curl_easy_unescape(NULL, string, length, NULL); } char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { size_t alloc; char *ns; char *testing_ptr = NULL; size_t newlen; size_t strindex = 0; size_t length; CURLcode result; if(inlength < 0) return NULL; alloc = (inlength?(size_t)inlength:strlen(string)) + 1; newlen = alloc; ns = malloc(alloc); if(!ns) return NULL; length = alloc-1; while(length--) { unsigned char in = *string; /* we need to treat the characters unsigned */ if(Curl_isunreserved(in)) /* just copy this */ ns[strindex++] = in; else { /* encode it */ newlen += 2; /* the size grows with two, since this'll become a %XX */ if(newlen > alloc) { alloc *= 2; testing_ptr = Curl_saferealloc(ns, alloc); if(!testing_ptr) return NULL; ns = testing_ptr; } result = Curl_convert_to_network(data, (char *)&in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); return NULL; } msnprintf(&ns[strindex], 4, "%%%02X", in); strindex += 3; } string++; } ns[strindex] = 0; /* terminate it */ return ns; } /* * Curl_urldecode() URL decodes the given string. * * Optionally detects control characters (byte codes lower than 32) in the * data and rejects such data. * * Returns a pointer to a malloced string in *ostring with length given in * *olen. If length == 0, the length is assumed to be strlen(string). * * 'data' can be set to NULL but then this function can't convert network * data to host for non-ascii. */ CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_ctrl) { size_t alloc = (length?length:strlen(string)) + 1; char *ns = malloc(alloc); size_t strindex = 0; unsigned long hex; CURLcode result = CURLE_OK; if(!ns) return CURLE_OUT_OF_MEMORY; while(--alloc > 0) { unsigned char in = *string; if(('%' == in) && (alloc > 2) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { /* this is two hexadecimal digits following a '%' */ char hexstr[3]; char *ptr; hexstr[0] = string[1]; hexstr[1] = string[2]; hexstr[2] = 0; hex = strtoul(hexstr, &ptr, 16); in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ if(data) { result = Curl_convert_from_network(data, (char *)&in, 1); if(result) { /* Curl_convert_from_network calls failf if unsuccessful */ free(ns); return result; } } string += 2; alloc -= 2; } if(reject_ctrl && (in < 0x20)) { free(ns); return CURLE_URL_MALFORMAT; } ns[strindex++] = in; string++; } ns[strindex] = 0; /* terminate it */ if(olen) /* store output size */ *olen = strindex; /* store output string */ *ostring = ns; return CURLE_OK; } /* * Unescapes the given URL escaped string of given length. Returns a * pointer to a malloced string with length given in *olen. * If length == 0, the length is assumed to be strlen(string). * If olen == NULL, no output length is stored. */ char *curl_easy_unescape(struct Curl_easy *data, const char *string, int length, int *olen) { char *str = NULL; if(length >= 0) { size_t inputlen = length; size_t outputlen; CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, FALSE); if(res) return NULL; if(olen) { if(outputlen <= (size_t) INT_MAX) *olen = curlx_uztosi(outputlen); else /* too large to return in an int, fail! */ Curl_safefree(str); } } return str; } /* For operating systems/environments that use different malloc/free systems for the app and for this library, we provide a free that uses the library's memory system */ void curl_free(void *p) { free(p); } davix-0.8.0/deps/curl/lib/memdebug.h0000644000000000000000000001542314121063461015737 0ustar rootroot#ifndef HEADER_CURL_MEMDEBUG_H #define HEADER_CURL_MEMDEBUG_H #ifdef CURLDEBUG /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * CAUTION: this header is designed to work when included by the app-side * as well as the library. Do not mix with library internals! */ #define CURL_MT_LOGFNAME_BUFSIZE 512 extern FILE *curl_dbg_logfile; /* memory functions */ CURL_EXTERN void *curl_dbg_malloc(size_t size, int line, const char *source); CURL_EXTERN void *curl_dbg_calloc(size_t elements, size_t size, int line, const char *source); CURL_EXTERN void *curl_dbg_realloc(void *ptr, size_t size, int line, const char *source); CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source); CURL_EXTERN char *curl_dbg_strdup(const char *str, int line, const char *src); #if defined(WIN32) && defined(UNICODE) CURL_EXTERN wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source); #endif CURL_EXTERN void curl_dbg_memdebug(const char *logname); CURL_EXTERN void curl_dbg_memlimit(long limit); CURL_EXTERN void curl_dbg_log(const char *format, ...); /* file descriptor manipulators */ CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol, int line, const char *source); CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source); CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source); CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen, int line, const char *source); #ifdef HAVE_SOCKETPAIR CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], int line, const char *source); #endif /* send/receive sockets */ CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line, const char *source); CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line, const char *source); /* FILE functions */ CURL_EXTERN FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source); CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source); #ifndef MEMDEBUG_NODEFINES /* Set this symbol on the command-line, recompile all lib-sources */ #undef strdup #define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) #define malloc(size) curl_dbg_malloc(size, __LINE__, __FILE__) #define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__) #define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__) #define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__) #define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) #define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef WIN32 # ifdef UNICODE # undef wcsdup # define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) # undef _wcsdup # define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) # undef _tcsdup # define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) # else # undef _tcsdup # define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) # endif #endif #undef socket #define socket(domain,type,protocol)\ curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__) #undef accept /* for those with accept as a macro */ #define accept(sock,addr,len)\ curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) #ifdef HAVE_SOCKETPAIR #define socketpair(domain,type,protocol,socket_vector)\ curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__) #endif #ifdef HAVE_GETADDRINFO #if defined(getaddrinfo) && defined(__osf__) /* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define our macro as for other platforms. Instead, we redefine the new name they define getaddrinfo to become! */ #define ogetaddrinfo(host,serv,hint,res) \ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #else #undef getaddrinfo #define getaddrinfo(host,serv,hint,res) \ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #endif #endif /* HAVE_GETADDRINFO */ #ifdef HAVE_FREEADDRINFO #undef freeaddrinfo #define freeaddrinfo(data) \ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) #endif /* HAVE_FREEADDRINFO */ /* sclose is probably already defined, redefine it! */ #undef sclose #define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__) #define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__) #undef fopen #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #undef fdopen #define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) #define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) #endif /* MEMDEBUG_NODEFINES */ #endif /* CURLDEBUG */ /* ** Following section applies even when CURLDEBUG is not defined. */ #ifndef fake_sclose #define fake_sclose(x) Curl_nop_stmt #endif /* * Curl_safefree defined as a macro to allow MemoryTracking feature * to log free() calls at same location where Curl_safefree is used. * This macro also assigns NULL to given pointer when free'd. */ #define Curl_safefree(ptr) \ do { free((ptr)); (ptr) = NULL;} while(0) #endif /* HEADER_CURL_MEMDEBUG_H */ davix-0.8.0/deps/curl/lib/config-mac.h0000644000000000000000000000764714121063461016166 0ustar rootroot#ifndef HEADER_CURL_CONFIG_MAC_H #define HEADER_CURL_CONFIG_MAC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* =================================================================== */ /* Hand crafted config file for Mac OS 9 */ /* =================================================================== */ /* On Mac OS X you must run configure to generate curl_config.h file */ /* =================================================================== */ #define OS "mac" /* Define if you want the built-in manual */ #define USE_MANUAL 1 #define HAVE_ERRNO_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_SELECT_H 1 #define HAVE_NETDB_H 1 #define HAVE_ARPA_INET_H 1 #define HAVE_UNISTD_H 1 #define HAVE_NET_IF_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_FCNTL_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_ALLOCA_H 1 #define HAVE_STDLIB_H 1 #define HAVE_TIME_H 1 #define HAVE_UTIME_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_UTIME_H 1 #define TIME_WITH_SYS_TIME 1 #define HAVE_ALARM 1 #define HAVE_FTRUNCATE 1 #define HAVE_UTIME 1 #define HAVE_SETVBUF 1 #define HAVE_STRFTIME 1 #define HAVE_INET_ADDR 1 #define HAVE_MEMCPY 1 #define HAVE_SELECT 1 #define HAVE_SOCKET 1 #define HAVE_STRUCT_TIMEVAL 1 #define HAVE_SIGACTION 1 #define HAVE_SIGNAL_H 1 #define HAVE_SIG_ATOMIC_T 1 #ifdef MACOS_SSL_SUPPORT # define USE_OPENSSL 1 #endif #define CURL_DISABLE_LDAP 1 #define HAVE_RAND_STATUS 1 #define HAVE_RAND_EGD 1 #define HAVE_IOCTL 1 #define HAVE_IOCTL_FIONBIO 1 #define RETSIGTYPE void #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_SIZE_T 4 #define HAVE_GETNAMEINFO 1 #define GETNAMEINFO_QUAL_ARG1 const #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * #define GETNAMEINFO_TYPE_ARG2 socklen_t #define GETNAMEINFO_TYPE_ARG46 size_t #define GETNAMEINFO_TYPE_ARG7 int #define HAVE_RECV 1 #define RECV_TYPE_ARG1 int #define RECV_TYPE_ARG2 void * #define RECV_TYPE_ARG3 size_t #define RECV_TYPE_ARG4 int #define RECV_TYPE_RETV ssize_t #define HAVE_RECVFROM 1 #define RECVFROM_TYPE_ARG1 int #define RECVFROM_TYPE_ARG2 void #define RECVFROM_TYPE_ARG3 size_t #define RECVFROM_TYPE_ARG4 int #define RECVFROM_TYPE_ARG5 struct sockaddr #define RECVFROM_TYPE_ARG6 int #define RECVFROM_TYPE_RETV ssize_t #define RECVFROM_TYPE_ARG2_IS_VOID 1 #define HAVE_SEND 1 #define SEND_TYPE_ARG1 int #define SEND_QUAL_ARG2 const #define SEND_TYPE_ARG2 void * #define SEND_TYPE_ARG3 size_T #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV ssize_t #define HAVE_EXTRA_STRICMP_H 1 #define HAVE_EXTRA_STRDUP_H 1 #endif /* HEADER_CURL_CONFIG_MAC_H */ davix-0.8.0/deps/curl/lib/imap.c0000644000000000000000000016501214121063461015073 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * RFC2195 CRAM-MD5 authentication * RFC2595 Using TLS with IMAP, POP3 and ACAP * RFC2831 DIGEST-MD5 authentication * RFC3501 IMAPv4 protocol * RFC4422 Simple Authentication and Security Layer (SASL) * RFC4616 PLAIN authentication * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * RFC4959 IMAP Extension for SASL Initial Client Response * RFC5092 IMAP URL Scheme * RFC6749 OAuth 2.0 Authorization Framework * RFC8314 Use of TLS for Email Submission and Access * Draft LOGIN SASL Mechanism * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_IMAP #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "imap.h" #include "mime.h" #include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "strcase.h" #include "curl_sasl.h" #include "warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Local API functions */ static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done); static CURLcode imap_do(struct connectdata *conn, bool *done); static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode imap_connect(struct connectdata *conn, bool *done); static CURLcode imap_disconnect(struct connectdata *conn, bool dead); static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done); static int imap_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); static CURLcode imap_setup_connection(struct connectdata *conn); static char *imap_atom(const char *str, bool escape_only); static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct connectdata *conn); static CURLcode imap_parse_custom_request(struct connectdata *conn); static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode imap_continue_authenticate(struct connectdata *conn, const char *resp); static void imap_get_message(char *buffer, char **outptr); /* * IMAP protocol handler. */ const struct Curl_handler Curl_handler_imap = { "IMAP", /* scheme */ imap_setup_connection, /* setup_connection */ imap_do, /* do_it */ imap_done, /* done */ ZERO_NULL, /* do_more */ imap_connect, /* connect_it */ imap_multi_statemach, /* connecting */ imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_IMAP, /* defport */ CURLPROTO_IMAP, /* protocol */ PROTOPT_CLOSEACTION| /* flags */ PROTOPT_URLOPTIONS }; #ifdef USE_SSL /* * IMAPS protocol handler. */ const struct Curl_handler Curl_handler_imaps = { "IMAPS", /* scheme */ imap_setup_connection, /* setup_connection */ imap_do, /* do_it */ imap_done, /* done */ ZERO_NULL, /* do_more */ imap_connect, /* connect_it */ imap_multi_statemach, /* connecting */ imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_IMAPS, /* defport */ CURLPROTO_IMAPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */ PROTOPT_URLOPTIONS }; #endif #define IMAP_RESP_OK 1 #define IMAP_RESP_NOT_OK 2 #define IMAP_RESP_PREAUTH 3 /* SASL parameters for the imap protocol */ static const struct SASLproto saslimap = { "imap", /* The service name */ '+', /* Code received when continuation is expected */ IMAP_RESP_OK, /* Code to receive upon authentication success */ 0, /* Maximum initial response length (no max) */ imap_perform_authenticate, /* Send authentication command */ imap_continue_authenticate, /* Send authentication continuation */ imap_get_message /* Get SASL response message */ }; #ifdef USE_SSL static void imap_to_imaps(struct connectdata *conn) { /* Change the connection handler */ conn->handler = &Curl_handler_imaps; /* Set the connection's upgraded to TLS flag */ conn->tls_upgraded = TRUE; } #else #define imap_to_imaps(x) Curl_nop_stmt #endif /*********************************************************************** * * imap_matchresp() * * Determines whether the untagged response is related to the specified * command by checking if it is in format "* ..." or * "* ...". * * The "* " marker is assumed to have already been checked by the caller. */ static bool imap_matchresp(const char *line, size_t len, const char *cmd) { const char *end = line + len; size_t cmd_len = strlen(cmd); /* Skip the untagged response marker */ line += 2; /* Do we have a number after the marker? */ if(line < end && ISDIGIT(*line)) { /* Skip the number */ do line++; while(line < end && ISDIGIT(*line)); /* Do we have the space character? */ if(line == end || *line != ' ') return FALSE; line++; } /* Does the command name match and is it followed by a space character or at the end of line? */ if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) return TRUE; return FALSE; } /*********************************************************************** * * imap_endofresp() * * Checks whether the given string is a valid tagged, untagged or continuation * response which can be processed by the response handler. */ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, int *resp) { struct IMAP *imap = conn->data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; const char *id = imapc->resptag; size_t id_len = strlen(id); /* Do we have a tagged command response? */ if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') { line += id_len + 1; len -= id_len + 1; if(len >= 2 && !memcmp(line, "OK", 2)) *resp = IMAP_RESP_OK; else if(len >= 7 && !memcmp(line, "PREAUTH", 7)) *resp = IMAP_RESP_PREAUTH; else *resp = IMAP_RESP_NOT_OK; return TRUE; } /* Do we have an untagged command response? */ if(len >= 2 && !memcmp("* ", line, 2)) { switch(imapc->state) { /* States which are interested in untagged responses */ case IMAP_CAPABILITY: if(!imap_matchresp(line, len, "CAPABILITY")) return FALSE; break; case IMAP_LIST: if((!imap->custom && !imap_matchresp(line, len, "LIST")) || (imap->custom && !imap_matchresp(line, len, imap->custom) && (!strcasecompare(imap->custom, "STORE") || !imap_matchresp(line, len, "FETCH")) && !strcasecompare(imap->custom, "SELECT") && !strcasecompare(imap->custom, "EXAMINE") && !strcasecompare(imap->custom, "SEARCH") && !strcasecompare(imap->custom, "EXPUNGE") && !strcasecompare(imap->custom, "LSUB") && !strcasecompare(imap->custom, "UID") && !strcasecompare(imap->custom, "NOOP"))) return FALSE; break; case IMAP_SELECT: /* SELECT is special in that its untagged responses do not have a common prefix so accept anything! */ break; case IMAP_FETCH: if(!imap_matchresp(line, len, "FETCH")) return FALSE; break; case IMAP_SEARCH: if(!imap_matchresp(line, len, "SEARCH")) return FALSE; break; /* Ignore other untagged responses */ default: return FALSE; } *resp = '*'; return TRUE; } /* Do we have a continuation response? This should be a + symbol followed by a space and optionally some text as per RFC-3501 for the AUTHENTICATE and APPEND commands and as outlined in Section 4. Examples of RFC-4959 but some e-mail servers ignore this and only send a single + instead. */ if(imap && !imap->custom && ((len == 3 && line[0] == '+') || (len >= 2 && !memcmp("+ ", line, 2)))) { switch(imapc->state) { /* States which are interested in continuation responses */ case IMAP_AUTHENTICATE: case IMAP_APPEND: *resp = '+'; break; default: failf(conn->data, "Unexpected continuation response"); *resp = -1; break; } return TRUE; } return FALSE; /* Nothing for us */ } /*********************************************************************** * * imap_get_message() * * Gets the authentication message from the response buffer. */ static void imap_get_message(char *buffer, char **outptr) { size_t len = strlen(buffer); char *message = NULL; if(len > 2) { /* Find the start of the message */ len -= 2; for(message = buffer + 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ for(; len--;) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ if(++len) { message[len] = '\0'; } } else /* junk input => zero length output */ message = &buffer[len]; *outptr = message; } /*********************************************************************** * * state() * * This is the ONLY way to change IMAP state! */ static void state(struct connectdata *conn, imapstate newstate) { struct imap_conn *imapc = &conn->proto.imapc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const names[]={ "STOP", "SERVERGREET", "CAPABILITY", "STARTTLS", "UPGRADETLS", "AUTHENTICATE", "LOGIN", "LIST", "SELECT", "FETCH", "FETCH_FINAL", "APPEND", "APPEND_FINAL", "SEARCH", "LOGOUT", /* LAST */ }; if(imapc->state != newstate) infof(conn->data, "IMAP %p state change from %s to %s\n", (void *)imapc, names[imapc->state], names[newstate]); #endif imapc->state = newstate; } /*********************************************************************** * * imap_perform_capability() * * Sends the CAPABILITY command in order to obtain a list of server side * supported capabilities. */ static CURLcode imap_perform_capability(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ imapc->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPABILITY command */ result = imap_sendf(conn, "CAPABILITY"); if(!result) state(conn, IMAP_CAPABILITY); return result; } /*********************************************************************** * * imap_perform_starttls() * * Sends the STARTTLS command to start the upgrade to TLS. */ static CURLcode imap_perform_starttls(struct connectdata *conn) { /* Send the STARTTLS command */ CURLcode result = imap_sendf(conn, "STARTTLS"); if(!result) state(conn, IMAP_STARTTLS); return result; } /*********************************************************************** * * imap_perform_upgrade_tls() * * Performs the upgrade to TLS. */ static CURLcode imap_perform_upgrade_tls(struct connectdata *conn) { /* Start the SSL connection */ struct imap_conn *imapc = &conn->proto.imapc; CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); if(!result) { if(imapc->state != IMAP_UPGRADETLS) state(conn, IMAP_UPGRADETLS); if(imapc->ssldone) { imap_to_imaps(conn); result = imap_perform_capability(conn); } } return result; } /*********************************************************************** * * imap_perform_login() * * Sends a clear text LOGIN command to authenticate with. */ static CURLcode imap_perform_login(struct connectdata *conn) { CURLcode result = CURLE_OK; char *user; char *passwd; /* Check we have a username and password to authenticate with and end the connect phase if we don't */ if(!conn->bits.user_passwd) { state(conn, IMAP_STOP); return result; } /* Make sure the username and password are in the correct atom format */ user = imap_atom(conn->user, false); passwd = imap_atom(conn->passwd, false); /* Send the LOGIN command */ result = imap_sendf(conn, "LOGIN %s %s", user ? user : "", passwd ? passwd : ""); free(user); free(passwd); if(!result) state(conn, IMAP_LOGIN); return result; } /*********************************************************************** * * imap_perform_authenticate() * * Sends an AUTHENTICATE command allowing the client to login with the given * SASL authentication mechanism. */ static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *mech, const char *initresp) { CURLcode result = CURLE_OK; if(initresp) { /* Send the AUTHENTICATE command with the initial response */ result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); } else { /* Send the AUTHENTICATE command */ result = imap_sendf(conn, "AUTHENTICATE %s", mech); } return result; } /*********************************************************************** * * imap_continue_authenticate() * * Sends SASL continuation data or cancellation. */ static CURLcode imap_continue_authenticate(struct connectdata *conn, const char *resp) { struct imap_conn *imapc = &conn->proto.imapc; return Curl_pp_sendf(&imapc->pp, "%s", resp); } /*********************************************************************** * * imap_perform_authentication() * * Initiates the authentication sequence, with the appropriate SASL * authentication mechanism, falling back to clear text should a common * mechanism not be available between the client and server. */ static CURLcode imap_perform_authentication(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; saslprogress progress; /* Check if already authenticated OR if there is enough data to authenticate with and end the connect phase if we don't */ if(imapc->preauth || !Curl_sasl_can_authenticate(&imapc->sasl, conn)) { state(conn, IMAP_STOP); return result; } /* Calculate the SASL login details */ result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress); if(!result) { if(progress == SASL_INPROGRESS) state(conn, IMAP_AUTHENTICATE); else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = imap_perform_login(conn); else { /* Other mechanisms not supported */ infof(conn->data, "No known authentication mechanisms supported!\n"); result = CURLE_LOGIN_DENIED; } } return result; } /*********************************************************************** * * imap_perform_list() * * Sends a LIST command or an alternative custom request. */ static CURLcode imap_perform_list(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; if(imap->custom) /* Send the custom request */ result = imap_sendf(conn, "%s%s", imap->custom, imap->custom_params ? imap->custom_params : ""); else { /* Make sure the mailbox is in the correct atom format if necessary */ char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup(""); if(!mailbox) return CURLE_OUT_OF_MEMORY; /* Send the LIST command */ result = imap_sendf(conn, "LIST \"%s\" *", mailbox); free(mailbox); } if(!result) state(conn, IMAP_LIST); return result; } /*********************************************************************** * * imap_perform_select() * * Sends a SELECT command to ask the server to change the selected mailbox. */ static CURLcode imap_perform_select(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; char *mailbox; /* Invalidate old information as we are switching mailboxes */ Curl_safefree(imapc->mailbox); Curl_safefree(imapc->mailbox_uidvalidity); /* Check we have a mailbox */ if(!imap->mailbox) { failf(conn->data, "Cannot SELECT without a mailbox."); return CURLE_URL_MALFORMAT; } /* Make sure the mailbox is in the correct atom format */ mailbox = imap_atom(imap->mailbox, false); if(!mailbox) return CURLE_OUT_OF_MEMORY; /* Send the SELECT command */ result = imap_sendf(conn, "SELECT %s", mailbox); free(mailbox); if(!result) state(conn, IMAP_SELECT); return result; } /*********************************************************************** * * imap_perform_fetch() * * Sends a FETCH command to initiate the download of a message. */ static CURLcode imap_perform_fetch(struct connectdata *conn) { CURLcode result = CURLE_OK; struct IMAP *imap = conn->data->req.protop; /* Check we have a UID */ if(imap->uid) { /* Send the FETCH command */ if(imap->partial) result = imap_sendf(conn, "UID FETCH %s BODY[%s]<%s>", imap->uid, imap->section ? imap->section : "", imap->partial); else result = imap_sendf(conn, "UID FETCH %s BODY[%s]", imap->uid, imap->section ? imap->section : ""); } else if(imap->mindex) { /* Send the FETCH command */ if(imap->partial) result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>", imap->mindex, imap->section ? imap->section : "", imap->partial); else result = imap_sendf(conn, "FETCH %s BODY[%s]", imap->mindex, imap->section ? imap->section : ""); } else { failf(conn->data, "Cannot FETCH without a UID."); return CURLE_URL_MALFORMAT; } if(!result) state(conn, IMAP_FETCH); return result; } /*********************************************************************** * * imap_perform_append() * * Sends an APPEND command to initiate the upload of a message. */ static CURLcode imap_perform_append(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; char *mailbox; /* Check we have a mailbox */ if(!imap->mailbox) { failf(data, "Cannot APPEND without a mailbox."); return CURLE_URL_MALFORMAT; } /* Prepare the mime data if some. */ if(data->set.mimepost.kind != MIMEKIND_NONE) { /* Use the whole structure as data. */ data->set.mimepost.flags &= ~MIME_BODY_ONLY; /* Add external headers and mime version. */ curl_mime_headers(&data->set.mimepost, data->set.headers, 0); result = Curl_mime_prepare_headers(&data->set.mimepost, NULL, NULL, MIMESTRATEGY_MAIL); if(!result) if(!Curl_checkheaders(conn, "Mime-Version")) result = Curl_mime_add_header(&data->set.mimepost.curlheaders, "Mime-Version: 1.0"); /* Make sure we will read the entire mime structure. */ if(!result) result = Curl_mime_rewind(&data->set.mimepost); if(result) return result; data->state.infilesize = Curl_mime_size(&data->set.mimepost); /* Read from mime structure. */ data->state.fread_func = (curl_read_callback) Curl_mime_read; data->state.in = (void *) &data->set.mimepost; } /* Check we know the size of the upload */ if(data->state.infilesize < 0) { failf(data, "Cannot APPEND with unknown input file size\n"); return CURLE_UPLOAD_FAILED; } /* Make sure the mailbox is in the correct atom format */ mailbox = imap_atom(imap->mailbox, false); if(!mailbox) return CURLE_OUT_OF_MEMORY; /* Send the APPEND command */ result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", mailbox, data->state.infilesize); free(mailbox); if(!result) state(conn, IMAP_APPEND); return result; } /*********************************************************************** * * imap_perform_search() * * Sends a SEARCH command. */ static CURLcode imap_perform_search(struct connectdata *conn) { CURLcode result = CURLE_OK; struct IMAP *imap = conn->data->req.protop; /* Check we have a query string */ if(!imap->query) { failf(conn->data, "Cannot SEARCH without a query string."); return CURLE_URL_MALFORMAT; } /* Send the SEARCH command */ result = imap_sendf(conn, "SEARCH %s", imap->query); if(!result) state(conn, IMAP_SEARCH); return result; } /*********************************************************************** * * imap_perform_logout() * * Performs the logout action prior to sclose() being called. */ static CURLcode imap_perform_logout(struct connectdata *conn) { /* Send the LOGOUT command */ CURLcode result = imap_sendf(conn, "LOGOUT"); if(!result) state(conn, IMAP_LOGOUT); return result; } /* For the initial server greeting */ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, int imapcode, imapstate instate) { struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(imapcode == IMAP_RESP_PREAUTH) { /* PREAUTH */ struct imap_conn *imapc = &conn->proto.imapc; imapc->preauth = TRUE; infof(data, "PREAUTH connection, already authenticated!\n"); } else if(imapcode != IMAP_RESP_OK) { failf(data, "Got unexpected imap-server response"); return CURLE_WEIRD_SERVER_REPLY; } return imap_perform_capability(conn); } /* For CAPABILITY responses */ static CURLcode imap_state_capability_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; (void)instate; /* no use for this yet */ /* Do we have a untagged response? */ if(imapcode == '*') { line += 2; /* Loop through the data line */ for(;;) { size_t wordlen; while(*line && (*line == ' ' || *line == '\t' || *line == '\r' || *line == '\n')) { line++; } if(!*line) break; /* Extract the word */ for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' && line[wordlen] != '\t' && line[wordlen] != '\r' && line[wordlen] != '\n';) wordlen++; /* Does the server support the STARTTLS capability? */ if(wordlen == 8 && !memcmp(line, "STARTTLS", 8)) imapc->tls_supported = TRUE; /* Has the server explicitly disabled clear text authentication? */ else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13)) imapc->login_disabled = TRUE; /* Does the server support the SASL-IR capability? */ else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7)) imapc->ir_supported = TRUE; /* Do we have a SASL based authentication mechanism? */ else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) { size_t llen; unsigned int mechbit; line += 5; wordlen -= 5; /* Test the word for a matching authentication mechanism */ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); if(mechbit && llen == wordlen) imapc->sasl.authmechs |= mechbit; } line += wordlen; } } else if(imapcode == IMAP_RESP_OK) { if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { /* We don't have a SSL/TLS connection yet, but SSL is requested */ if(imapc->tls_supported) /* Switch to TLS connection now */ result = imap_perform_starttls(conn); else if(data->set.use_ssl == CURLUSESSL_TRY) /* Fallback and carry on with authentication */ result = imap_perform_authentication(conn); else { failf(data, "STARTTLS not supported."); result = CURLE_USE_SSL_FAILED; } } else result = imap_perform_authentication(conn); } else result = imap_perform_authentication(conn); return result; } /* For STARTTLS responses */ static CURLcode imap_state_starttls_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(imapcode != IMAP_RESP_OK) { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else result = imap_perform_authentication(conn); } else result = imap_perform_upgrade_tls(conn); return result; } /* For SASL authentication responses */ static CURLcode imap_state_auth_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; saslprogress progress; (void)instate; /* no use for this yet */ result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); if(!result) switch(progress) { case SASL_DONE: state(conn, IMAP_STOP); /* Authenticated */ break; case SASL_IDLE: /* No mechanism left after cancellation */ if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) /* Perform clear text authentication */ result = imap_perform_login(conn); else { failf(data, "Authentication cancelled"); result = CURLE_LOGIN_DENIED; } break; default: break; } return result; } /* For LOGIN responses */ static CURLcode imap_state_login_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(imapcode != IMAP_RESP_OK) { failf(data, "Access denied. %c", imapcode); result = CURLE_LOGIN_DENIED; } else /* End of connect phase */ state(conn, IMAP_STOP); return result; } /* For LIST and SEARCH responses */ static CURLcode imap_state_listsearch_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; char *line = conn->data->state.buffer; size_t len = strlen(line); (void)instate; /* No use for this yet */ if(imapcode == '*') { /* Temporarily add the LF character back and send as body to the client */ line[len] = '\n'; result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); line[len] = '\0'; } else if(imapcode != IMAP_RESP_OK) result = CURLE_QUOTE_ERROR; else /* End of DO phase */ state(conn, IMAP_STOP); return result; } /* For SELECT responses */ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = conn->data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; (void)instate; /* no use for this yet */ if(imapcode == '*') { /* See if this is an UIDVALIDITY response */ char tmp[20]; if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) { Curl_safefree(imapc->mailbox_uidvalidity); imapc->mailbox_uidvalidity = strdup(tmp); } } else if(imapcode == IMAP_RESP_OK) { /* Check if the UIDVALIDITY has been specified and matches */ if(imap->uidvalidity && imapc->mailbox_uidvalidity && !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) { failf(conn->data, "Mailbox UIDVALIDITY has changed"); result = CURLE_REMOTE_FILE_NOT_FOUND; } else { /* Note the currently opened mailbox on this connection */ imapc->mailbox = strdup(imap->mailbox); if(imap->custom) result = imap_perform_list(conn); else if(imap->query) result = imap_perform_search(conn); else result = imap_perform_fetch(conn); } } else { failf(data, "Select failed"); result = CURLE_LOGIN_DENIED; } return result; } /* For the (first line of the) FETCH responses */ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; const char *ptr = data->state.buffer; bool parsed = FALSE; curl_off_t size = 0; (void)instate; /* no use for this yet */ if(imapcode != '*') { Curl_pgrsSetDownloadSize(data, -1); state(conn, IMAP_STOP); return CURLE_REMOTE_FILE_NOT_FOUND; } /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse the continuation data contained within the curly brackets */ while(*ptr && (*ptr != '{')) ptr++; if(*ptr == '{') { char *endptr; if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) { if(endptr - ptr > 1 && endptr[0] == '}' && endptr[1] == '\r' && endptr[2] == '\0') parsed = TRUE; } } if(parsed) { infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download\n", size); Curl_pgrsSetDownloadSize(data, size); if(pp->cache) { /* At this point there is a bunch of data in the header "cache" that is actually body content, send it as body and then skip it. Do note that there may even be additional "headers" after the body. */ size_t chunk = pp->cache_size; if(chunk > (size_t)size) /* The conversion from curl_off_t to size_t is always fine here */ chunk = (size_t)size; if(!chunk) { /* no size, we're done with the data */ state(conn, IMAP_STOP); return CURLE_OK; } result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk); if(result) return result; data->req.bytecount += chunk; infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU " bytes are left for transfer\n", chunk, size - chunk); /* Have we used the entire cache or just part of it?*/ if(pp->cache_size > chunk) { /* Only part of it so shrink the cache to fit the trailing data */ memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk); pp->cache_size -= chunk; } else { /* Free the cache */ Curl_safefree(pp->cache); /* Reset the cache size */ pp->cache_size = 0; } } if(data->req.bytecount == size) /* The entire data is already transferred! */ Curl_setup_transfer(data, -1, -1, FALSE, -1); else { /* IMAP download */ data->req.maxdownload = size; Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1); } } else { /* We don't know how to parse this line */ failf(pp->conn->data, "Failed to parse FETCH response."); result = CURLE_WEIRD_SERVER_REPLY; } /* End of DO phase */ state(conn, IMAP_STOP); return result; } /* For final FETCH responses performed after the download */ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; (void)instate; /* No use for this yet */ if(imapcode != IMAP_RESP_OK) result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ state(conn, IMAP_STOP); return result; } /* For APPEND responses */ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; (void)instate; /* No use for this yet */ if(imapcode != '+') { result = CURLE_UPLOAD_FAILED; } else { /* Set the progress upload size */ Curl_pgrsSetUploadSize(data, data->state.infilesize); /* IMAP upload */ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); /* End of DO phase */ state(conn, IMAP_STOP); } return result; } /* For final APPEND responses performed after the upload */ static CURLcode imap_state_append_final_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; (void)instate; /* No use for this yet */ if(imapcode != IMAP_RESP_OK) result = CURLE_UPLOAD_FAILED; else /* End of DONE phase */ state(conn, IMAP_STOP); return result; } static CURLcode imap_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int imapcode; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; size_t nread = 0; /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */ if(imapc->state == IMAP_UPGRADETLS) return imap_perform_upgrade_tls(conn); /* Flush any data that needs to be sent */ if(pp->sendleft) return Curl_pp_flushsend(pp); do { /* Read the response from the server */ result = Curl_pp_readresp(sock, pp, &imapcode, &nread); if(result) return result; /* Was there an error parsing the response line? */ if(imapcode == -1) return CURLE_WEIRD_SERVER_REPLY; if(!imapcode) break; /* We have now received a full IMAP server response */ switch(imapc->state) { case IMAP_SERVERGREET: result = imap_state_servergreet_resp(conn, imapcode, imapc->state); break; case IMAP_CAPABILITY: result = imap_state_capability_resp(conn, imapcode, imapc->state); break; case IMAP_STARTTLS: result = imap_state_starttls_resp(conn, imapcode, imapc->state); break; case IMAP_AUTHENTICATE: result = imap_state_auth_resp(conn, imapcode, imapc->state); break; case IMAP_LOGIN: result = imap_state_login_resp(conn, imapcode, imapc->state); break; case IMAP_LIST: case IMAP_SEARCH: result = imap_state_listsearch_resp(conn, imapcode, imapc->state); break; case IMAP_SELECT: result = imap_state_select_resp(conn, imapcode, imapc->state); break; case IMAP_FETCH: result = imap_state_fetch_resp(conn, imapcode, imapc->state); break; case IMAP_FETCH_FINAL: result = imap_state_fetch_final_resp(conn, imapcode, imapc->state); break; case IMAP_APPEND: result = imap_state_append_resp(conn, imapcode, imapc->state); break; case IMAP_APPEND_FINAL: result = imap_state_append_final_resp(conn, imapcode, imapc->state); break; case IMAP_LOGOUT: /* fallthrough, just stop! */ default: /* internal error */ state(conn, IMAP_STOP); break; } } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp)); return result; } /* Called repeatedly until done from multi.c */ static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) { result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); if(result || !imapc->ssldone) return result; } result = Curl_pp_statemach(&imapc->pp, FALSE, FALSE); *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; return result; } static CURLcode imap_block_statemach(struct connectdata *conn, bool disconnecting) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; while(imapc->state != IMAP_STOP && !result) result = Curl_pp_statemach(&imapc->pp, TRUE, disconnecting); return result; } /* Allocate and initialize the struct IMAP for the current Curl_easy if required */ static CURLcode imap_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap; imap = data->req.protop = calloc(sizeof(struct IMAP), 1); if(!imap) result = CURLE_OUT_OF_MEMORY; return result; } /* For the IMAP "protocol connect" and "doing" phases only */ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks) { return Curl_pp_getsock(&conn->proto.imapc.pp, socks); } /*********************************************************************** * * imap_connect() * * This function should do everything that is to be considered a part of the * connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect * phase is done when this function returns, or FALSE if not. */ static CURLcode imap_connect(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; *done = FALSE; /* default to not done yet */ /* We always support persistent connections in IMAP */ connkeep(conn, "IMAP default"); /* Set the default response time-out */ pp->response_time = RESP_TIMEOUT; pp->statemach_act = imap_statemach_act; pp->endofresp = imap_endofresp; pp->conn = conn; /* Set the default preferred authentication type and mechanism */ imapc->preftype = IMAP_TYPE_ANY; Curl_sasl_init(&imapc->sasl, &saslimap); /* Initialise the pingpong layer */ Curl_pp_init(pp); /* Parse the URL options */ result = imap_parse_url_options(conn); if(result) return result; /* Start off waiting for the server greeting response */ state(conn, IMAP_SERVERGREET); /* Start off with an response id of '*' */ strcpy(imapc->resptag, "*"); result = imap_multi_statemach(conn, done); return result; } /*********************************************************************** * * imap_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; (void)premature; if(!imap) return CURLE_OK; if(status) { connclose(conn, "IMAP done with bad status"); /* marked for closure */ result = status; /* use the already set error code */ } else if(!data->set.connect_only && !imap->custom && (imap->uid || imap->mindex || data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)) { /* Handle responses after FETCH or APPEND transfer has finished */ if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) state(conn, IMAP_FETCH_FINAL); else { /* End the APPEND command first by sending an empty line */ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); if(!result) state(conn, IMAP_APPEND_FINAL); } /* Run the state-machine */ if(!result) result = imap_block_statemach(conn, FALSE); } /* Cleanup our per-request based variables */ Curl_safefree(imap->mailbox); Curl_safefree(imap->uidvalidity); Curl_safefree(imap->uid); Curl_safefree(imap->mindex); Curl_safefree(imap->section); Curl_safefree(imap->partial); Curl_safefree(imap->query); Curl_safefree(imap->custom); Curl_safefree(imap->custom_params); /* Clear the transfer mode for the next request */ imap->transfer = FTPTRANSFER_BODY; return result; } /*********************************************************************** * * imap_perform() * * This is the actual DO function for IMAP. Fetch or append a message, or do * other things according to the options previously setup. */ static CURLcode imap_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { /* This is IMAP and no proxy */ CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; bool selected = FALSE; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { /* Requested no body means no transfer */ imap->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* Determine if the requested mailbox (with the same UIDVALIDITY if set) has already been selected on this connection */ if(imap->mailbox && imapc->mailbox && strcasecompare(imap->mailbox, imapc->mailbox) && (!imap->uidvalidity || !imapc->mailbox_uidvalidity || strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity))) selected = TRUE; /* Start the first command in the DO phase */ if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) /* APPEND can be executed directly */ result = imap_perform_append(conn); else if(imap->custom && (selected || !imap->mailbox)) /* Custom command using the same mailbox or no mailbox */ result = imap_perform_list(conn); else if(!imap->custom && selected && (imap->uid || imap->mindex)) /* FETCH from the same mailbox */ result = imap_perform_fetch(conn); else if(!imap->custom && selected && imap->query) /* SEARCH the current mailbox */ result = imap_perform_search(conn); else if(imap->mailbox && !selected && (imap->custom || imap->uid || imap->mindex || imap->query)) /* SELECT the mailbox */ result = imap_perform_select(conn); else /* LIST */ result = imap_perform_list(conn); if(result) return result; /* Run the state-machine */ result = imap_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); return result; } /*********************************************************************** * * imap_do() * * This function is registered as 'curl_do' function. It decodes the path * parts etc as a wrapper to the actual DO function (imap_perform). * * The input argument is already checked for validity. */ static CURLcode imap_do(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; *done = FALSE; /* default to false */ /* Parse the URL path */ result = imap_parse_url_path(conn); if(result) return result; /* Parse the custom request */ result = imap_parse_custom_request(conn); if(result) return result; result = imap_regular_transfer(conn, done); return result; } /*********************************************************************** * * imap_disconnect() * * Disconnect from an IMAP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection) { struct imap_conn *imapc = &conn->proto.imapc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ /* The IMAP session may or may not have been allocated/setup at this point! */ if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart) if(!imap_perform_logout(conn)) (void)imap_block_statemach(conn, TRUE); /* ignore errors on LOGOUT */ /* Disconnect from the server */ Curl_pp_disconnect(&imapc->pp); /* Cleanup the SASL module */ Curl_sasl_cleanup(conn, imapc->sasl.authused); /* Cleanup our connection based variables */ Curl_safefree(imapc->mailbox); Curl_safefree(imapc->mailbox_uidvalidity); return CURLE_OK; } /* Call this when the DO phase has completed */ static CURLcode imap_dophase_done(struct connectdata *conn, bool connected) { struct IMAP *imap = conn->data->req.protop; (void)connected; if(imap->transfer != FTPTRANSFER_BODY) /* no data to transfer */ Curl_setup_transfer(conn->data, -1, -1, FALSE, -1); return CURLE_OK; } /* Called from multi.c while DOing */ static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = imap_multi_statemach(conn, dophase_done); if(result) DEBUGF(infof(conn->data, "DO phase failed\n")); else if(*dophase_done) { result = imap_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); } return result; } /*********************************************************************** * * imap_regular_transfer() * * The input argument is already checked for validity. * * Performs all commands done before a regular transfer between a local and a * remote host. */ static CURLcode imap_regular_transfer(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; bool connected = FALSE; struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; /* Set the progress data */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); /* Carry out the perform */ result = imap_perform(conn, &connected, dophase_done); /* Perform post DO phase operations if necessary */ if(!result && *dophase_done) result = imap_dophase_done(conn, connected); return result; } static CURLcode imap_setup_connection(struct connectdata *conn) { /* Initialise the IMAP layer */ CURLcode result = imap_init(conn); if(result) return result; /* Clear the TLS upgraded flag */ conn->tls_upgraded = FALSE; return CURLE_OK; } /*********************************************************************** * * imap_sendf() * * Sends the formatted string as an IMAP command to the server. * * Designed to never block. */ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; char *taggedfmt; va_list ap; DEBUGASSERT(fmt); /* Calculate the next command ID wrapping at 3 digits */ imapc->cmdid = (imapc->cmdid + 1) % 1000; /* Calculate the tag based on the connection ID and command ID */ msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); /* Prefix the format with the tag */ taggedfmt = aprintf("%s %s", imapc->resptag, fmt); if(!taggedfmt) return CURLE_OUT_OF_MEMORY; /* Send the data with the tag */ va_start(ap, fmt); result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); va_end(ap); free(taggedfmt); return result; } /*********************************************************************** * * imap_atom() * * Checks the input string for characters that need escaping and returns an * atom ready for sending to the server. * * The returned string needs to be freed. * */ static char *imap_atom(const char *str, bool escape_only) { /* !checksrc! disable PARENBRACE 1 */ const char atom_specials[] = "(){ %*]"; const char *p1; char *p2; size_t backsp_count = 0; size_t quote_count = 0; bool others_exists = FALSE; size_t newlen = 0; char *newstr = NULL; if(!str) return NULL; /* Look for "atom-specials", counting the backslash and quote characters as these will need escaping */ p1 = str; while(*p1) { if(*p1 == '\\') backsp_count++; else if(*p1 == '"') quote_count++; else if(!escape_only) { const char *p3 = atom_specials; while(*p3 && !others_exists) { if(*p1 == *p3) others_exists = TRUE; p3++; } } p1++; } /* Does the input contain any "atom-special" characters? */ if(!backsp_count && !quote_count && !others_exists) return strdup(str); /* Calculate the new string length */ newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2); /* Allocate the new string */ newstr = (char *) malloc((newlen + 1) * sizeof(char)); if(!newstr) return NULL; /* Surround the string in quotes if necessary */ p2 = newstr; if(!escape_only) { newstr[0] = '"'; newstr[newlen - 1] = '"'; p2++; } /* Copy the string, escaping backslash and quote characters along the way */ p1 = str; while(*p1) { if(*p1 == '\\' || *p1 == '"') { *p2 = '\\'; p2++; } *p2 = *p1; p1++; p2++; } /* Terminate the string */ newstr[newlen] = '\0'; return newstr; } /*********************************************************************** * * imap_is_bchar() * * Portable test of whether the specified char is a "bchar" as defined in the * grammar of RFC-5092. */ static bool imap_is_bchar(char ch) { switch(ch) { /* bchar */ case ':': case '@': case '/': /* bchar -> achar */ case '&': case '=': /* bchar -> achar -> uchar -> unreserved */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '-': case '.': case '_': case '~': /* bchar -> achar -> uchar -> sub-delims-sh */ case '!': case '$': case '\'': case '(': case ')': case '*': case '+': case ',': /* bchar -> achar -> uchar -> pct-encoded */ case '%': /* HEXDIG chars are already included above */ return true; default: return false; } } /*********************************************************************** * * imap_parse_url_options() * * Parse the URL login options. */ static CURLcode imap_parse_url_options(struct connectdata *conn) { CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; const char *ptr = conn->options; imapc->sasl.resetprefs = TRUE; while(!result && ptr && *ptr) { const char *key = ptr; const char *value; while(*ptr && *ptr != '=') ptr++; value = ptr + 1; while(*ptr && *ptr != ';') ptr++; if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); else result = CURLE_URL_MALFORMAT; if(*ptr == ';') ptr++; } switch(imapc->sasl.prefmech) { case SASL_AUTH_NONE: imapc->preftype = IMAP_TYPE_NONE; break; case SASL_AUTH_DEFAULT: imapc->preftype = IMAP_TYPE_ANY; break; default: imapc->preftype = IMAP_TYPE_SASL; break; } return result; } /*********************************************************************** * * imap_parse_url_path() * * Parse the URL path into separate path components. * */ static CURLcode imap_parse_url_path(struct connectdata *conn) { /* The imap struct is already initialised in imap_connect() */ CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *begin = &data->state.up.path[1]; /* skip leading slash */ const char *ptr = begin; /* See how much of the URL is a valid path and decode it */ while(imap_is_bchar(*ptr)) ptr++; if(ptr != begin) { /* Remove the trailing slash if present */ const char *end = ptr; if(end > begin && end[-1] == '/') end--; result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL, TRUE); if(result) return result; } else imap->mailbox = NULL; /* There can be any number of parameters in the form ";NAME=VALUE" */ while(*ptr == ';') { char *name; char *value; size_t valuelen; /* Find the length of the name parameter */ begin = ++ptr; while(*ptr && *ptr != '=') ptr++; if(!*ptr) return CURLE_URL_MALFORMAT; /* Decode the name parameter */ result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE); if(result) return result; /* Find the length of the value parameter */ begin = ++ptr; while(imap_is_bchar(*ptr)) ptr++; /* Decode the value parameter */ result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE); if(result) { free(name); return result; } DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value)); /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and PARTIAL) stripping of the trailing slash character if it is present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uidvalidity = value; value = NULL; } else if(strcasecompare(name, "UID") && !imap->uid) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uid = value; value = NULL; } else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->mindex = value; value = NULL; } else if(strcasecompare(name, "SECTION") && !imap->section) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->section = value; value = NULL; } else if(strcasecompare(name, "PARTIAL") && !imap->partial) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->partial = value; value = NULL; } else { free(name); free(value); return CURLE_URL_MALFORMAT; } free(name); free(value); } /* Does the URL contain a query parameter? Only valid when we have a mailbox and no UID as per RFC-5092 */ if(imap->mailbox && !imap->uid && !imap->mindex) { /* Get the query parameter, URL decoded */ (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query, CURLU_URLDECODE); } /* Any extra stuff at the end of the URL is an error */ if(*ptr) return CURLE_URL_MALFORMAT; return CURLE_OK; } /*********************************************************************** * * imap_parse_custom_request() * * Parse the custom request. */ static CURLcode imap_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; if(custom) { /* URL decode the custom request */ result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE); /* Extract the parameters if specified */ if(!result) { const char *params = imap->custom; while(*params && *params != ' ') params++; if(*params) { imap->custom_params = strdup(params); imap->custom[params - imap->custom] = '\0'; if(!imap->custom_params) result = CURLE_OUT_OF_MEMORY; } } } return result; } #endif /* CURL_DISABLE_IMAP */ davix-0.8.0/deps/curl/lib/config-symbian.h0000644000000000000000000005430614121063461017062 0ustar rootroot#ifndef HEADER_CURL_CONFIG_SYMBIAN_H #define HEADER_CURL_CONFIG_SYMBIAN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for Symbian */ /* ================================================================ */ /* Location of default ca bundle */ /* #define CURL_CA_BUNDLE "/etc/pki/tls/certs/ca-bundle.crt"*/ /* Location of default ca path */ /* #undef CURL_CA_PATH */ /* to disable cookies support */ /* #undef CURL_DISABLE_COOKIES */ /* to disable cryptographic authentication */ /* #undef CURL_DISABLE_CRYPTO_AUTH */ /* to disable DICT */ /* #undef CURL_DISABLE_DICT */ /* to disable FILE */ /* #undef CURL_DISABLE_FILE */ /* to disable FTP */ /* #undef CURL_DISABLE_FTP */ /* to disable HTTP */ /* #undef CURL_DISABLE_HTTP */ /* to disable LDAP */ #define CURL_DISABLE_LDAP 1 /* to disable LDAPS */ #define CURL_DISABLE_LDAPS 1 /* to disable TELNET */ /* #undef CURL_DISABLE_TELNET */ /* to disable TFTP */ /* #undef CURL_DISABLE_TFTP */ /* to disable verbose strings */ /* #define CURL_DISABLE_VERBOSE_STRINGS 1*/ /* Definition to make a library symbol externally visible. */ /* #undef CURL_EXTERN_SYMBOL */ /* Use Windows LDAP implementation */ /* #undef USE_WIN32_LDAP */ /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ /* Define if you want to enable IPv6 support */ #define ENABLE_IPV6 1 /* Define if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 size_t /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 int /* Define to 1 if you have the header file. */ /*#define HAVE_ALLOCA_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ /*#define HAVE_ARPA_TFTP_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define to 1 if you have the `basename' function. */ /*#define HAVE_BASENAME 1*/ /* Define to 1 if bool is an available type. */ /*#define HAVE_BOOL_T 1*/ /* Define to 1 if you have the `closesocket' function. */ /* #undef HAVE_CLOSESOCKET */ /* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ /*#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1*/ /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DES_H */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the fcntl function. */ #define HAVE_FCNTL 1 /* Define to 1 if you have a working fcntl O_NONBLOCK function. */ #define HAVE_FCNTL_O_NONBLOCK 1 /* Define to 1 if you have the `fork' function. */ /*#define HAVE_FORK 1*/ /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 /* Define if getaddrinfo exists and works */ #define HAVE_GETADDRINFO 1 /* Define to 1 if you have the `geteuid' function. */ #define HAVE_GETEUID 1 /* Define to 1 if you have the `gethostbyaddr' function. */ #define HAVE_GETHOSTBYADDR 1 /* If you have gethostbyname */ #define HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the `gethostbyname_r' function. */ /* #undef HAVE_GETHOSTBYNAME_R */ /* gethostbyname_r() takes 3 args */ /* #undef HAVE_GETHOSTBYNAME_R_3 */ /* gethostbyname_r() takes 5 args */ /* #undef HAVE_GETHOSTBYNAME_R_5 */ /* gethostbyname_r() takes 6 args */ /* #undef HAVE_GETHOSTBYNAME_R_6 */ /* Define to 1 if you have the getnameinfo function. */ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getpass_r' function. */ /* #undef HAVE_GETPASS_R */ /* Define to 1 if you have the `getppid' function. */ #define HAVE_GETPPID 1 /* Define to 1 if you have the `getprotobyname' function. */ #define HAVE_GETPROTOBYNAME 1 /* Define to 1 if you have the `getpwuid' function. */ #define HAVE_GETPWUID 1 /* Define to 1 if you have the `getrlimit' function. */ /*#define HAVE_GETRLIMIT 1*/ /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* we have a glibc-style strerror_r() */ /* #undef HAVE_GLIBC_STRERROR_R */ /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* if you have the gssapi libraries */ /* #undef HAVE_GSSAPI */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */ /* if you have the GNU gssapi libraries */ /* #undef HAVE_GSSGNU */ /* if you have the Heimdal gssapi libraries */ /* #undef HAVE_GSSHEIMDAL */ /* if you have the MIT gssapi libraries */ /* #undef HAVE_GSSMIT */ /* Define to 1 if you have the `idna_strerror' function. */ /*#define HAVE_IDNA_STRERROR 1*/ /* Define to 1 if you have the `idn_free' function. */ /*#define HAVE_IDN_FREE 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_IDN_FREE_H 1*/ /* Define to 1 if you have the `inet_addr' function. */ /*#define HAVE_INET_ADDR 1*/ /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ /*#define HAVE_INET_NTOP 1*/ /* Define to 1 if you have a IPv6 capable working inet_pton function. */ /*#define HAVE_INET_PTON 1*/ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the ioctl function. */ #define HAVE_IOCTL 1 /* Define to 1 if you have a working ioctl FIONBIO function. */ #define HAVE_IOCTL_FIONBIO 1 /* Define to 1 if you have the ioctlsocket function. */ /* #undef HAVE_IOCTLSOCKET */ /* Define to 1 if you have a working ioctlsocket FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_FIONBIO */ /* Define to 1 if you have the IoctlSocket camel case function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL */ /* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */ /* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */ /* Define to 1 if you have the header file. */ /* #undef HAVE_IO_H */ /* if you have the Kerberos4 libraries (including -ldes) */ /* #undef HAVE_KRB4 */ /* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ /* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KRB_H */ /* Define to 1 if you have the lber.h header file. */ /*#define HAVE_LBER_H 1*/ /* Define to 1 if you have the ldapssl.h header file. */ /* #undef HAVE_LDAPSSL_H */ /* Define to 1 if you have the ldap.h header file. */ /*#define HAVE_LDAP_H 1*/ /* Use LDAPS implementation */ /*#define HAVE_LDAP_SSL 1*/ /* Define to 1 if you have the ldap_ssl.h header file. */ /* #undef HAVE_LDAP_SSL_H */ /* Define to 1 if you have the `ldap_url_parse' function. */ /*#define HAVE_LDAP_URL_PARSE 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_LIBGEN_H 1*/ /* Define to 1 if you have the `idn' library (-lidn). */ /*#define HAVE_LIBIDN 1*/ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `resolve' library (-lresolve). */ /* #undef HAVE_LIBRESOLVE */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Define to 1 if you have the `ssh2' library (-lssh2). */ /*#define HAVE_LIBSSH2 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_LIBSSH2_H 1*/ /* if your compiler supports LL */ #define HAVE_LL 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if the compiler supports the 'long long' data type. */ #define HAVE_LONGLONG 1 /* Define to 1 if you have the malloc.h header file. */ /*#define HAVE_MALLOC_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the MSG_NOSIGNAL flag. */ /*#define HAVE_MSG_NOSIGNAL 1*/ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /*#define HAVE_NETINET_TCP_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 /* Define to 1 if NI_WITHSCOPEID exists and works. */ /*#define HAVE_NI_WITHSCOPEID 1*/ /* we have no strerror_r() proto */ /* #undef HAVE_NO_STRERROR_R_DECL */ /* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ /* #undef HAVE_OLD_GSSMIT */ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_CRYPTO_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_ERR_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_PEM_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_PKCS12_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_RSA_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_SSL_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_OPENSSL_X509_H 1*/ /* Define to 1 if you have the header file. */ /* #undef HAVE_PEM_H */ /* Define to 1 if you have the `perror' function. */ #define HAVE_PERROR 1 /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 /* Define to 1 if you have the `poll' function. */ /*#define HAVE_POLL 1*/ /* If you have a fine poll */ /*#define HAVE_POLL_FINE 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_POLL_H 1*/ /* we have a POSIX-style strerror_r() */ #define HAVE_POSIX_STRERROR_R 1 /* Define to 1 if you have the header file. */ #define HAVE_PWD_H 1 /* Define to 1 if you have the `RAND_egd' function. */ #define HAVE_RAND_EGD 1 /* Define to 1 if you have the `RAND_screen' function. */ /* #undef HAVE_RAND_SCREEN */ /* Define to 1 if you have the `RAND_status' function. */ /*#define HAVE_RAND_STATUS 1*/ /* Define to 1 if you have the recv function. */ #define HAVE_RECV 1 /* Define to 1 if you have the recvfrom function. */ #define HAVE_RECVFROM 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_RSA_H */ /* Define to 1 if you have the select function. */ #define HAVE_SELECT 1 /* Define to 1 if you have the send function. */ #define HAVE_SEND 1 /* Define to 1 if you have the header file. */ #define HAVE_SETJMP_H 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setmode' function. */ /* #undef HAVE_SETMODE */ /* Define to 1 if you have the `setrlimit' function. */ /*#define HAVE_SETRLIMIT 1*/ /* Define to 1 if you have the setsockopt function. */ /* #undef HAVE_SETSOCKOPT */ /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ /* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */ /* Define to 1 if you have the header file. */ /*#define HAVE_SGTTY_H 1*/ /* Define to 1 if you have the `sigaction' function. */ /*#define HAVE_SIGACTION 1*/ /* Define to 1 if you have the `siginterrupt' function. */ /*#define HAVE_SIGINTERRUPT 1*/ /* Define to 1 if you have the `signal' function. */ /*#define HAVE_SIGNAL 1*/ /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 /* If you have sigsetjmp */ /*#define HAVE_SIGSETJMP 1*/ /* Define to 1 if sig_atomic_t is an available typedef. */ /*#define HAVE_SIG_ATOMIC_T 1*/ /* Define to 1 if sig_atomic_t is already defined as volatile. */ /* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SSL_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strcmpi' function. */ /* #undef HAVE_STRCMPI */ /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror_r' function. */ #define HAVE_STRERROR_R 1 /* Define to 1 if you have the `stricmp' function. */ /* #undef HAVE_STRICMP */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if you have the `strtok_r' function. */ #define HAVE_STRTOK_R 1 /* Define to 1 if you have the `strtoll' function. */ #define HAVE_STRTOLL 1 /* if struct sockaddr_storage is defined */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if you have the timeval struct. */ #define HAVE_STRUCT_TIMEVAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ /*#define HAVE_SYS_POLL_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_UTIME_H */ /* Define to 1 if you have the header file. */ /*#define HAVE_TERMIOS_H 1*/ /* Define to 1 if you have the header file. */ /*#define HAVE_TERMIO_H 1*/ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /*#define HAVE_TLD_H 1*/ /* Define to 1 if you have the `tld_strerror' function. */ /*#define HAVE_TLD_STRERROR 1*/ /* Define to 1 if you have the `uname' function. */ #define HAVE_UNAME 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `utime' function. */ #define HAVE_UTIME 1 /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 /* Define to 1 if compiler supports C99 variadic macro style. */ #define HAVE_VARIADIC_MACROS_C99 1 /* Define to 1 if compiler supports old gcc variadic macro style. */ /*#define HAVE_VARIADIC_MACROS_GCC 1*/ /* Define to 1 if you have the winber.h header file. */ /* #undef HAVE_WINBER_H */ /* Define to 1 if you have the windows.h header file. */ /* #undef HAVE_WINDOWS_H */ /* Define to 1 if you have the winldap.h header file. */ /* #undef HAVE_WINLDAP_H */ /* Define to 1 if you have the winsock2.h header file. */ /* #undef HAVE_WINSOCK2_H */ /* Define to 1 if you have the winsock.h header file. */ /* #undef HAVE_WINSOCK_H */ /* Define this symbol if your OS supports changing the contents of argv */ /*#define HAVE_WRITABLE_ARGV 1*/ /* Define to 1 if you have the ws2tcpip.h header file. */ /* #undef HAVE_WS2TCPIP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_X509_H */ /* Define to 1 if you need the lber.h header file even with ldap.h */ /* #undef NEED_LBER_H */ /* Define to 1 if you need the malloc.h header file even with stdlib.h */ /* #undef NEED_MALLOC_H */ /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ /* #undef NEED_REENTRANT */ /* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ /* #undef NEED_THREAD_SAFE */ /* cpu-machine-OS */ #ifdef __WINS__ #define OS "i386-pc-epoc32" #elif __MARM__ #define OS "arm-unknown-epoc32" #else /* This won't happen on any current Symbian version */ #define OS "unknown-unknown-epoc32" #endif /* Name of package */ /*#define PACKAGE "curl"*/ /* Define to the address where bug reports for this package should be sent. */ /*#define PACKAGE_BUGREPORT \ "a suitable curl mailing list => https://curl.haxx.se/mail/"*/ /* Define to the full name of this package. */ /*#define PACKAGE_NAME "curl"*/ /* Define to the full name and version of this package. */ /*#define PACKAGE_STRING "curl -"*/ /* Define to the one symbol short name of this package. */ /*#define PACKAGE_TARNAME "curl"*/ /* Define to the version of this package. */ /*#define PACKAGE_VERSION "-"*/ /* a suitable file to read random data from */ /*#define RANDOM_FILE "/dev/urandom"*/ #define RECV_TYPE_ARG1 int #define RECV_TYPE_ARG2 void * #define RECV_TYPE_ARG3 size_t #define RECV_TYPE_ARG4 int #define RECV_TYPE_RETV ssize_t #define RECVFROM_TYPE_ARG1 int #define RECVFROM_TYPE_ARG2 void #define RECVFROM_TYPE_ARG3 size_t #define RECVFROM_TYPE_ARG4 int #define RECVFROM_TYPE_ARG5 struct sockaddr #define RECVFROM_TYPE_ARG6 size_t #define RECVFROM_TYPE_RETV ssize_t #define RECVFROM_TYPE_ARG2_IS_VOID 1 #define SEND_TYPE_ARG1 int #define SEND_QUAL_ARG2 const #define SEND_TYPE_ARG2 void * #define SEND_TYPE_ARG3 size_t #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV ssize_t /* Define as the return type of signal handlers (`int' or `void'). */ /*#define RETSIGTYPE void*/ /* Define to the type of arg 1 for `select'. */ #define SELECT_TYPE_ARG1 int /* Define to the type of args 2, 3 and 4 for `select'. */ #define SELECT_TYPE_ARG234 (fd_set *) /* Define to the type of arg 5 for `select'. */ #define SELECT_TYPE_ARG5 (struct timeval *) /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 4 /* The size of `time_t', as computed by sizeof. */ #define SIZEOF_TIME_T 4 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you want to enable c-ares support */ /* #undef USE_ARES */ /* Define to disable non-blocking sockets */ /* #undef USE_BLOCKING_SOCKETS */ /* if GnuTLS is enabled */ /* #undef USE_GNUTLS */ /* if libSSH2 is in use */ /*#define USE_LIBSSH2 1*/ /* If you want to build curl with the built-in manual */ /*#define USE_MANUAL 1*/ /* if NSS is enabled */ /* #undef USE_NSS */ /* to enable SSPI support */ /* #undef USE_WINDOWS_SSPI */ /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ /* #undef USE_YASSLEMUL */ /* Version number of package */ /*#define VERSION "7.18.2-CVS"*/ /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Number of bits in a file offset, on hosts where this is settable. */ #define _FILE_OFFSET_BITS 64 /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* type to use in place of in_addr_t if not defined */ /* #undef in_addr_t */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* the signed version of size_t */ /* #undef ssize_t */ /* Enabling curl debug mode when building in Symbian debug mode would work */ /* except that debug mode introduces new exports that must be frozen. */ #ifdef _DEBUG /* #define CURLDEBUG */ #endif /* sys/cdefs.h fails to define this for WINSCW prior to Symbian OS ver. 9.4 */ #ifndef __LONG_LONG_SUPPORTED #define __LONG_LONG_SUPPORTED #endif /* Enable appropriate header only when zlib support is enabled */ #ifdef HAVE_LIBZ #define HAVE_ZLIB_H 1 #endif #endif /* HEADER_CURL_CONFIG_SYMBIAN_H */ davix-0.8.0/deps/curl/lib/curl_fnmatch.c0000644000000000000000000002410414121063461016606 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #include #include "curl_fnmatch.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" #ifndef HAVE_FNMATCH #define CURLFNM_CHARSET_LEN (sizeof(char) * 256) #define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15) #define CURLFNM_NEGATE CURLFNM_CHARSET_LEN #define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1) #define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2) #define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3) #define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4) #define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5) #define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6) #define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7) #define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8) #define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9) #define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10) typedef enum { CURLFNM_SCHS_DEFAULT = 0, CURLFNM_SCHS_RIGHTBR, CURLFNM_SCHS_RIGHTBRLEFTBR } setcharset_state; typedef enum { CURLFNM_PKW_INIT = 0, CURLFNM_PKW_DDOT } parsekey_state; typedef enum { CCLASS_OTHER = 0, CCLASS_DIGIT, CCLASS_UPPER, CCLASS_LOWER } char_class; #define SETCHARSET_OK 1 #define SETCHARSET_FAIL 0 static int parsekeyword(unsigned char **pattern, unsigned char *charset) { parsekey_state state = CURLFNM_PKW_INIT; #define KEYLEN 10 char keyword[KEYLEN] = { 0 }; int found = FALSE; int i; unsigned char *p = *pattern; for(i = 0; !found; i++) { char c = *p++; if(i >= KEYLEN) return SETCHARSET_FAIL; switch(state) { case CURLFNM_PKW_INIT: if(ISLOWER(c)) keyword[i] = c; else if(c == ':') state = CURLFNM_PKW_DDOT; else return SETCHARSET_FAIL; break; case CURLFNM_PKW_DDOT: if(c == ']') found = TRUE; else return SETCHARSET_FAIL; } } #undef KEYLEN *pattern = p; /* move caller's pattern pointer */ if(strcmp(keyword, "digit") == 0) charset[CURLFNM_DIGIT] = 1; else if(strcmp(keyword, "alnum") == 0) charset[CURLFNM_ALNUM] = 1; else if(strcmp(keyword, "alpha") == 0) charset[CURLFNM_ALPHA] = 1; else if(strcmp(keyword, "xdigit") == 0) charset[CURLFNM_XDIGIT] = 1; else if(strcmp(keyword, "print") == 0) charset[CURLFNM_PRINT] = 1; else if(strcmp(keyword, "graph") == 0) charset[CURLFNM_GRAPH] = 1; else if(strcmp(keyword, "space") == 0) charset[CURLFNM_SPACE] = 1; else if(strcmp(keyword, "blank") == 0) charset[CURLFNM_BLANK] = 1; else if(strcmp(keyword, "upper") == 0) charset[CURLFNM_UPPER] = 1; else if(strcmp(keyword, "lower") == 0) charset[CURLFNM_LOWER] = 1; else return SETCHARSET_FAIL; return SETCHARSET_OK; } /* Return the character class. */ static char_class charclass(unsigned char c) { if(ISUPPER(c)) return CCLASS_UPPER; if(ISLOWER(c)) return CCLASS_LOWER; if(ISDIGIT(c)) return CCLASS_DIGIT; return CCLASS_OTHER; } /* Include a character or a range in set. */ static void setcharorrange(unsigned char **pp, unsigned char *charset) { unsigned char *p = (*pp)++; unsigned char c = *p++; charset[c] = 1; if(ISALNUM(c) && *p++ == '-') { char_class cc = charclass(c); unsigned char endrange = *p++; if(endrange == '\\') endrange = *p++; if(endrange >= c && charclass(endrange) == cc) { while(c++ != endrange) if(charclass(c) == cc) /* Chars in class may be not consecutive. */ charset[c] = 1; *pp = p; } } } /* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */ static int setcharset(unsigned char **p, unsigned char *charset) { setcharset_state state = CURLFNM_SCHS_DEFAULT; bool something_found = FALSE; unsigned char c; memset(charset, 0, CURLFNM_CHSET_SIZE); for(;;) { c = **p; if(!c) return SETCHARSET_FAIL; switch(state) { case CURLFNM_SCHS_DEFAULT: if(c == ']') { if(something_found) return SETCHARSET_OK; something_found = TRUE; state = CURLFNM_SCHS_RIGHTBR; charset[c] = 1; (*p)++; } else if(c == '[') { unsigned char *pp = *p + 1; if(*pp++ == ':' && parsekeyword(&pp, charset)) *p = pp; else { charset[c] = 1; (*p)++; } something_found = TRUE; } else if(c == '^' || c == '!') { if(!something_found) { if(charset[CURLFNM_NEGATE]) { charset[c] = 1; something_found = TRUE; } else charset[CURLFNM_NEGATE] = 1; /* negate charset */ } else charset[c] = 1; (*p)++; } else if(c == '\\') { c = *(++(*p)); if(c) setcharorrange(p, charset); else charset['\\'] = 1; something_found = TRUE; } else { setcharorrange(p, charset); something_found = TRUE; } break; case CURLFNM_SCHS_RIGHTBR: if(c == '[') { state = CURLFNM_SCHS_RIGHTBRLEFTBR; charset[c] = 1; (*p)++; } else if(c == ']') { return SETCHARSET_OK; } else if(ISPRINT(c)) { charset[c] = 1; (*p)++; state = CURLFNM_SCHS_DEFAULT; } else /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a * nonsense warning 'statement not reached' at end of the fnc when * compiling on Solaris */ goto fail; break; case CURLFNM_SCHS_RIGHTBRLEFTBR: if(c == ']') return SETCHARSET_OK; state = CURLFNM_SCHS_DEFAULT; charset[c] = 1; (*p)++; break; } } fail: return SETCHARSET_FAIL; } static int loop(const unsigned char *pattern, const unsigned char *string, int maxstars) { unsigned char *p = (unsigned char *)pattern; unsigned char *s = (unsigned char *)string; unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 }; for(;;) { unsigned char *pp; switch(*p) { case '*': if(!maxstars) return CURL_FNMATCH_NOMATCH; /* Regroup consecutive stars and question marks. This can be done because '*?*?*' can be expressed as '??*'. */ for(;;) { if(*++p == '\0') return CURL_FNMATCH_MATCH; if(*p == '?') { if(!*s++) return CURL_FNMATCH_NOMATCH; } else if(*p != '*') break; } /* Skip string characters until we find a match with pattern suffix. */ for(maxstars--; *s; s++) { if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH) return CURL_FNMATCH_MATCH; } return CURL_FNMATCH_NOMATCH; case '?': if(!*s) return CURL_FNMATCH_NOMATCH; s++; p++; break; case '\0': return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH; case '\\': if(p[1]) p++; if(*s++ != *p++) return CURL_FNMATCH_NOMATCH; break; case '[': pp = p + 1; /* Copy in case of syntax error in set. */ if(setcharset(&pp, charset)) { int found = FALSE; if(!*s) return CURL_FNMATCH_NOMATCH; if(charset[(unsigned int)*s]) found = TRUE; else if(charset[CURLFNM_ALNUM]) found = ISALNUM(*s); else if(charset[CURLFNM_ALPHA]) found = ISALPHA(*s); else if(charset[CURLFNM_DIGIT]) found = ISDIGIT(*s); else if(charset[CURLFNM_XDIGIT]) found = ISXDIGIT(*s); else if(charset[CURLFNM_PRINT]) found = ISPRINT(*s); else if(charset[CURLFNM_SPACE]) found = ISSPACE(*s); else if(charset[CURLFNM_UPPER]) found = ISUPPER(*s); else if(charset[CURLFNM_LOWER]) found = ISLOWER(*s); else if(charset[CURLFNM_BLANK]) found = ISBLANK(*s); else if(charset[CURLFNM_GRAPH]) found = ISGRAPH(*s); if(charset[CURLFNM_NEGATE]) found = !found; if(!found) return CURL_FNMATCH_NOMATCH; p = pp + 1; s++; break; } /* Syntax error in set; mismatch! */ return CURL_FNMATCH_NOMATCH; default: if(*p++ != *s++) return CURL_FNMATCH_NOMATCH; break; } } } /* * @unittest: 1307 */ int Curl_fnmatch(void *ptr, const char *pattern, const char *string) { (void)ptr; /* the argument is specified by the curl_fnmatch_callback prototype, but not used by Curl_fnmatch() */ if(!pattern || !string) { return CURL_FNMATCH_FAIL; } return loop((unsigned char *)pattern, (unsigned char *)string, 2); } #else #include /* * @unittest: 1307 */ int Curl_fnmatch(void *ptr, const char *pattern, const char *string) { int rc; (void)ptr; /* the argument is specified by the curl_fnmatch_callback prototype, but not used by Curl_fnmatch() */ if(!pattern || !string) { return CURL_FNMATCH_FAIL; } rc = fnmatch(pattern, string, 0); switch(rc) { case 0: return CURL_FNMATCH_MATCH; case FNM_NOMATCH: return CURL_FNMATCH_NOMATCH; default: return CURL_FNMATCH_FAIL; } /* not reached */ } #endif #endif /* if FTP is disabled */ davix-0.8.0/deps/curl/lib/sigpipe.h0000644000000000000000000000522714121063461015613 0ustar rootroot#ifndef HEADER_CURL_SIGPIPE_H #define HEADER_CURL_SIGPIPE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && \ (defined(USE_OPENSSL) || defined(USE_MBEDTLS)) #include struct sigpipe_ignore { struct sigaction old_pipe_act; bool no_signal; }; #define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x /* * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl * internals, and then sigpipe_restore() will restore the situation when we * return from libcurl again. */ static void sigpipe_ignore(struct Curl_easy *data, struct sigpipe_ignore *ig) { /* get a local copy of no_signal because the Curl_easy might not be around when we restore */ ig->no_signal = data->set.no_signal; if(!data->set.no_signal) { struct sigaction action; /* first, extract the existing situation */ memset(&ig->old_pipe_act, 0, sizeof(struct sigaction)); sigaction(SIGPIPE, NULL, &ig->old_pipe_act); action = ig->old_pipe_act; /* ignore this signal */ action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); } } /* * sigpipe_restore() puts back the outside world's opinion of signal handler * and SIGPIPE handling. It MUST only be called after a corresponding * sigpipe_ignore() was used. */ static void sigpipe_restore(struct sigpipe_ignore *ig) { if(!ig->no_signal) /* restore the outside state */ sigaction(SIGPIPE, &ig->old_pipe_act, NULL); } #else /* for systems without sigaction */ #define sigpipe_ignore(x,y) Curl_nop_stmt #define sigpipe_restore(x) Curl_nop_stmt #define SIGPIPE_VARIABLE(x) #endif #endif /* HEADER_CURL_SIGPIPE_H */ davix-0.8.0/deps/curl/lib/memdebug.c0000644000000000000000000003207614121063461015735 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef CURLDEBUG #include #include "urldata.h" #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* * Until 2011-08-17 libcurl's Memory Tracking feature also performed * automatic malloc and free filling operations using 0xA5 and 0x13 * values. Our own preinitialization of dynamically allocated memory * might be useful when not using third party memory debuggers, but * on the other hand this would fool memory debuggers into thinking * that all dynamically allocated memory is properly initialized. * * As a default setting, libcurl's Memory Tracking feature no longer * performs preinitialization of dynamically allocated memory on its * own. If you know what you are doing, and really want to retain old * behavior, you can achieve this compiling with preprocessor symbols * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate * values. */ #ifdef CURL_MT_MALLOC_FILL # if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff) # error "invalid CURL_MT_MALLOC_FILL or out of range" # endif #endif #ifdef CURL_MT_FREE_FILL # if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff) # error "invalid CURL_MT_FREE_FILL or out of range" # endif #endif #if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL) # if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL) # error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL" # endif #endif #ifdef CURL_MT_MALLOC_FILL # define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len)) #else # define mt_malloc_fill(buf,len) Curl_nop_stmt #endif #ifdef CURL_MT_FREE_FILL # define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len)) #else # define mt_free_fill(buf,len) Curl_nop_stmt #endif struct memdebug { size_t size; union { curl_off_t o; double d; void *p; } mem[1]; /* I'm hoping this is the thing with the strictest alignment * requirements. That also means we waste some space :-( */ }; /* * Note that these debug functions are very simple and they are meant to * remain so. For advanced analysis, record a log file and write perl scripts * to analyze them! * * Don't use these with multithreaded test programs! */ FILE *curl_dbg_logfile = NULL; static bool memlimit = FALSE; /* enable memory limit */ static long memsize = 0; /* set number of mallocs allowed */ /* this sets the log file name */ void curl_dbg_memdebug(const char *logname) { if(!curl_dbg_logfile) { if(logname && *logname) curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT); else curl_dbg_logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC /* Flush the log file after every line so the log isn't lost in a crash */ if(curl_dbg_logfile) setbuf(curl_dbg_logfile, (char *)NULL); #endif } } /* This function sets the number of malloc() calls that should return successfully! */ void curl_dbg_memlimit(long limit) { if(!memlimit) { memlimit = TRUE; memsize = limit; } } /* returns TRUE if this isn't allowed! */ static bool countcheck(const char *func, int line, const char *source) { /* if source is NULL, then the call is made internally and this check should not be made */ if(memlimit && source) { if(!memsize) { if(source) { /* log to file */ curl_dbg_log("LIMIT %s:%d %s reached memlimit\n", source, line, func); /* log to stderr also */ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", source, line, func); fflush(curl_dbg_logfile); /* because it might crash now */ } errno = ENOMEM; return TRUE; /* RETURN ERROR! */ } else memsize--; /* countdown */ } return FALSE; /* allow this */ } void *curl_dbg_malloc(size_t wantedsize, int line, const char *source) { struct memdebug *mem; size_t size; DEBUGASSERT(wantedsize != 0); if(countcheck("malloc", line, source)) return NULL; /* alloc at least 64 bytes */ size = sizeof(struct memdebug) + wantedsize; mem = (Curl_cmalloc)(size); if(mem) { /* fill memory with junk */ mt_malloc_fill(mem->mem, wantedsize); mem->size = wantedsize; } if(source) curl_dbg_log("MEM %s:%d malloc(%zu) = %p\n", source, line, wantedsize, mem ? (void *)mem->mem : (void *)0); return (mem ? mem->mem : NULL); } void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size, int line, const char *source) { struct memdebug *mem; size_t size, user_size; DEBUGASSERT(wanted_elements != 0); DEBUGASSERT(wanted_size != 0); if(countcheck("calloc", line, source)) return NULL; /* alloc at least 64 bytes */ user_size = wanted_size * wanted_elements; size = sizeof(struct memdebug) + user_size; mem = (Curl_ccalloc)(1, size); if(mem) mem->size = user_size; if(source) curl_dbg_log("MEM %s:%d calloc(%zu,%zu) = %p\n", source, line, wanted_elements, wanted_size, mem ? (void *)mem->mem : (void *)0); return (mem ? mem->mem : NULL); } char *curl_dbg_strdup(const char *str, int line, const char *source) { char *mem; size_t len; DEBUGASSERT(str != NULL); if(countcheck("strdup", line, source)) return NULL; len = strlen(str) + 1; mem = curl_dbg_malloc(len, 0, NULL); /* NULL prevents logging */ if(mem) memcpy(mem, str, len); if(source) curl_dbg_log("MEM %s:%d strdup(%p) (%zu) = %p\n", source, line, (const void *)str, len, (const void *)mem); return mem; } #if defined(WIN32) && defined(UNICODE) wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source) { wchar_t *mem; size_t wsiz, bsiz; DEBUGASSERT(str != NULL); if(countcheck("wcsdup", line, source)) return NULL; wsiz = wcslen(str) + 1; bsiz = wsiz * sizeof(wchar_t); mem = curl_dbg_malloc(bsiz, 0, NULL); /* NULL prevents logging */ if(mem) memcpy(mem, str, bsiz); if(source) curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n", source, line, (void *)str, bsiz, (void *)mem); return mem; } #endif /* We provide a realloc() that accepts a NULL as pointer, which then performs a malloc(). In order to work with ares. */ void *curl_dbg_realloc(void *ptr, size_t wantedsize, int line, const char *source) { struct memdebug *mem = NULL; size_t size = sizeof(struct memdebug) + wantedsize; DEBUGASSERT(wantedsize != 0); if(countcheck("realloc", line, source)) return NULL; #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:1684) /* 1684: conversion from pointer to same-sized integral type */ #endif if(ptr) mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif mem = (Curl_crealloc)(mem, size); if(source) curl_dbg_log("MEM %s:%d realloc(%p, %zu) = %p\n", source, line, (void *)ptr, wantedsize, mem ? (void *)mem->mem : (void *)0); if(mem) { mem->size = wantedsize; return mem->mem; } return NULL; } void curl_dbg_free(void *ptr, int line, const char *source) { if(ptr) { struct memdebug *mem; #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:1684) /* 1684: conversion from pointer to same-sized integral type */ #endif mem = (void *)((char *)ptr - offsetof(struct memdebug, mem)); #ifdef __INTEL_COMPILER # pragma warning(pop) #endif /* destroy */ mt_free_fill(mem->mem, mem->size); /* free for real */ (Curl_cfree)(mem); } if(source) curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr); } curl_socket_t curl_dbg_socket(int domain, int type, int protocol, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? "FD %s:%d socket() = %d\n" : (sizeof(curl_socket_t) == sizeof(long)) ? "FD %s:%d socket() = %ld\n" : "FD %s:%d socket() = %zd\n"; curl_socket_t sockfd; if(countcheck("socket", line, source)) return CURL_SOCKET_BAD; sockfd = socket(domain, type, protocol); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log(fmt, source, line, sockfd); return sockfd; } SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line, const char *source) { SEND_TYPE_RETV rc; if(countcheck("send", line, source)) return -1; rc = send(sockfd, buf, len, flags); if(source) curl_dbg_log("SEND %s:%d send(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); return rc; } RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line, const char *source) { RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) return -1; rc = recv(sockfd, buf, len, flags); if(source) curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); return rc; } #ifdef HAVE_SOCKETPAIR int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? "FD %s:%d socketpair() = %d %d\n" : (sizeof(curl_socket_t) == sizeof(long)) ? "FD %s:%d socketpair() = %ld %ld\n" : "FD %s:%d socketpair() = %zd %zd\n"; int res = socketpair(domain, type, protocol, socket_vector); if(source && (0 == res)) curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]); return res; } #endif curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? "FD %s:%d accept() = %d\n" : (sizeof(curl_socket_t) == sizeof(long)) ? "FD %s:%d accept() = %ld\n" : "FD %s:%d accept() = %zd\n"; struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; curl_socket_t sockfd = accept(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log(fmt, source, line, sockfd); return sockfd; } /* separate function to allow libcurl to mark a "faked" close */ void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source) { const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? "FD %s:%d sclose(%d)\n": (sizeof(curl_socket_t) == sizeof(long)) ? "FD %s:%d sclose(%ld)\n": "FD %s:%d sclose(%zd)\n"; if(source) curl_dbg_log(fmt, source, line, sockfd); } /* this is our own defined way to close sockets on *ALL* platforms */ int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source) { int res = sclose(sockfd); curl_dbg_mark_sclose(sockfd, line, source); return res; } FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source) { FILE *res = fopen(file, mode); if(source) curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", source, line, file, mode, (void *)res); return res; } int curl_dbg_fclose(FILE *file, int line, const char *source) { int res; DEBUGASSERT(file != NULL); if(source) curl_dbg_log("FILE %s:%d fclose(%p)\n", source, line, (void *)file); res = fclose(file); return res; } #define LOGLINE_BUFSIZE 1024 /* this does the writing to the memory tracking log file */ void curl_dbg_log(const char *format, ...) { char *buf; int nchars; va_list ap; if(!curl_dbg_logfile) return; buf = (Curl_cmalloc)(LOGLINE_BUFSIZE); if(!buf) return; va_start(ap, format); nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap); va_end(ap); if(nchars > LOGLINE_BUFSIZE - 1) nchars = LOGLINE_BUFSIZE - 1; if(nchars > 0) fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile); (Curl_cfree)(buf); } #endif /* CURLDEBUG */ davix-0.8.0/deps/curl/lib/nonblock.h0000644000000000000000000000242014121063461015750 0ustar rootroot#ifndef HEADER_CURL_NONBLOCK_H #define HEADER_CURL_NONBLOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include /* for curl_socket_t */ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */); #endif /* HEADER_CURL_NONBLOCK_H */ davix-0.8.0/deps/curl/lib/hash.h0000644000000000000000000000656514121063461015104 0ustar rootroot#ifndef HEADER_CURL_HASH_H #define HEADER_CURL_HASH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include #include "llist.h" /* Hash function prototype */ typedef size_t (*hash_function) (void *key, size_t key_length, size_t slots_num); /* Comparator function prototype. Compares two keys. */ typedef size_t (*comp_function) (void *key1, size_t key1_len, void *key2, size_t key2_len); typedef void (*curl_hash_dtor)(void *); struct curl_hash { struct curl_llist *table; /* Hash function to be used for this hash table */ hash_function hash_func; /* Comparator function to compare keys */ comp_function comp_func; curl_hash_dtor dtor; int slots; size_t size; }; struct curl_hash_element { struct curl_llist_element list; void *ptr; size_t key_len; char key[1]; /* allocated memory following the struct */ }; struct curl_hash_iterator { struct curl_hash *hash; int slot_index; struct curl_llist_element *current_element; }; int Curl_hash_init(struct curl_hash *h, int slots, hash_function hfunc, comp_function comparator, curl_hash_dtor dtor); void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p); int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len); void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len); void Curl_hash_apply(struct curl_hash *h, void *user, void (*cb)(void *user, void *ptr)); #define Curl_hash_count(h) ((h)->size) void Curl_hash_destroy(struct curl_hash *h); void Curl_hash_clean(struct curl_hash *h); void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)); size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num); size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, size_t key2_len); void Curl_hash_start_iterate(struct curl_hash *hash, struct curl_hash_iterator *iter); struct curl_hash_element * Curl_hash_next_element(struct curl_hash_iterator *iter); void Curl_hash_print(struct curl_hash *h, void (*func)(void *)); #endif /* HEADER_CURL_HASH_H */ davix-0.8.0/deps/curl/lib/ftp.c0000644000000000000000000040001514121063461014731 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UTSNAME_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef __VMS #include #include #endif #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t #define in_addr_t unsigned long #endif #include #include "urldata.h" #include "sendf.h" #include "if2ip.h" #include "hostip.h" #include "progress.h" #include "transfer.h" #include "escape.h" #include "http.h" /* for HTTP proxy tunnel stuff */ #include "ftp.h" #include "fileinfo.h" #include "ftplistparser.h" #include "curl_range.h" #include "curl_sec.h" #include "strtoofft.h" #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "inet_ntop.h" #include "inet_pton.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" #include "strcase.h" #include "speedcheck.h" #include "warnless.h" #include "http_proxy.h" #include "non-ascii.h" #include "socks.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif #ifdef CURL_DISABLE_VERBOSE_STRINGS #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt #endif /* Local API functions */ #ifndef DEBUGBUILD static void _state(struct connectdata *conn, ftpstate newstate); #define state(x,y) _state(x,y) #else static void _state(struct connectdata *conn, ftpstate newstate, int lineno); #define state(x,y) _state(x,y,__LINE__) #endif static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode ftp_quit(struct connectdata *conn); static CURLcode ftp_parse_url_path(struct connectdata *conn); static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done); #ifndef CURL_DISABLE_VERBOSE_STRINGS static void ftp_pasv_verbose(struct connectdata *conn, Curl_addrinfo *ai, char *newhost, /* ascii version */ int port); #endif static CURLcode ftp_state_prepare_transfer(struct connectdata *conn); static CURLcode ftp_state_mdtm(struct connectdata *conn); static CURLcode ftp_state_quote(struct connectdata *conn, bool init, ftpstate instate); static CURLcode ftp_nb_type(struct connectdata *conn, bool ascii, ftpstate newstate); static int ftp_need_type(struct connectdata *conn, bool ascii); static CURLcode ftp_do(struct connectdata *conn, bool *done); static CURLcode ftp_done(struct connectdata *conn, CURLcode, bool premature); static CURLcode ftp_connect(struct connectdata *conn, bool *done); static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode ftp_do_more(struct connectdata *conn, int *completed); static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks); static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode ftp_setup_connection(struct connectdata * conn); static CURLcode init_wc_data(struct connectdata *conn); static CURLcode wc_statemach(struct connectdata *conn); static void wc_data_dtor(void *ptr); static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize); static CURLcode ftp_readresp(curl_socket_t sockfd, struct pingpong *pp, int *ftpcode, size_t *size); static CURLcode ftp_dophase_done(struct connectdata *conn, bool connected); /* easy-to-use macro: */ #define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \ if(result) \ return result /* * FTP protocol handler. */ const struct Curl_handler Curl_handler_ftp = { "FTP", /* scheme */ ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ ftp_do_more, /* do_more */ ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_FTP, /* defport */ CURLPROTO_FTP, /* protocol */ PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP | PROTOPT_WILDCARD /* flags */ }; #ifdef USE_SSL /* * FTPS protocol handler. */ const struct Curl_handler Curl_handler_ftps = { "FTPS", /* scheme */ ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ ftp_do_more, /* do_more */ ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ZERO_NULL, /* connection_check */ PORT_FTPS, /* defport */ CURLPROTO_FTPS, /* protocol */ PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */ }; #endif static void close_secondarysocket(struct connectdata *conn) { if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; } conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; } /* * NOTE: back in the old days, we added code in the FTP code that made NOBODY * requests on files respond with headers passed to the client/stdout that * looked like HTTP ones. * * This approach is not very elegant, it causes confusion and is error-prone. * It is subject for removal at the next (or at least a future) soname bump. * Until then you can test the effects of the removal by undefining the * following define named CURL_FTP_HTTPSTYLE_HEAD. */ #define CURL_FTP_HTTPSTYLE_HEAD 1 static void freedirs(struct ftp_conn *ftpc) { if(ftpc->dirs) { int i; for(i = 0; i < ftpc->dirdepth; i++) { free(ftpc->dirs[i]); ftpc->dirs[i] = NULL; } free(ftpc->dirs); ftpc->dirs = NULL; ftpc->dirdepth = 0; } Curl_safefree(ftpc->file); /* no longer of any use */ Curl_safefree(ftpc->newhost); } /*********************************************************************** * * AcceptServerConnect() * * After connection request is received from the server this function is * called to accept the connection and close the listening socket * */ static CURLcode AcceptServerConnect(struct connectdata *conn) { struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[SECONDARYSOCKET]; curl_socket_t s = CURL_SOCKET_BAD; #ifdef ENABLE_IPV6 struct Curl_sockaddr_storage add; #else struct sockaddr_in add; #endif curl_socklen_t size = (curl_socklen_t) sizeof(add); if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) { size = sizeof(add); s = accept(sock, (struct sockaddr *) &add, &size); } Curl_closesocket(conn, sock); /* close the first socket */ if(CURL_SOCKET_BAD == s) { failf(data, "Error accept()ing server connect"); return CURLE_FTP_PORT_FAILED; } infof(data, "Connection accepted from server\n"); /* when this happens within the DO state it is important that we mark us as not needing DO_MORE anymore */ conn->bits.do_more = FALSE; conn->sock[SECONDARYSOCKET] = s; (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ conn->sock_accepted = TRUE; if(data->set.fsockopt) { int error = 0; /* activate callback for setting socket options */ Curl_set_in_callback(data, true); error = data->set.fsockopt(data->set.sockopt_client, s, CURLSOCKTYPE_ACCEPT); Curl_set_in_callback(data, false); if(error) { close_secondarysocket(conn); return CURLE_ABORTED_BY_CALLBACK; } } return CURLE_OK; } /* * ftp_timeleft_accept() returns the amount of milliseconds left allowed for * waiting server to connect. If the value is negative, the timeout time has * already elapsed. * * The start time is stored in progress.t_acceptdata - as set with * Curl_pgrsTime(..., TIMER_STARTACCEPT); * */ static timediff_t ftp_timeleft_accept(struct Curl_easy *data) { timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; timediff_t other; struct curltime now; if(data->set.accepttimeout > 0) timeout_ms = data->set.accepttimeout; now = Curl_now(); /* check if the generic timeout possibly is set shorter */ other = Curl_timeleft(data, &now, FALSE); if(other && (other < timeout_ms)) /* note that this also works fine for when other happens to be negative due to it already having elapsed */ timeout_ms = other; else { /* subtract elapsed time */ timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ return -1; } return timeout_ms; } /*********************************************************************** * * ReceivedServerConnect() * * After allowing server to connect to us from data port, this function * checks both data connection for connection establishment and ctrl * connection for a negative response regarding a failure in connecting * */ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) { struct Curl_easy *data = conn->data; curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; int result; timediff_t timeout_ms; ssize_t nread; int ftpcode; *received = FALSE; timeout_ms = ftp_timeleft_accept(data); infof(data, "Checking for server connect\n"); if(timeout_ms < 0) { /* if a timeout was already reached, bail out */ failf(data, "Accept timeout occurred while waiting server connect"); return CURLE_FTP_ACCEPT_TIMEOUT; } /* First check whether there is a cached response from server */ if(pp->cache_size && pp->cache && pp->cache[0] > '3') { /* Data connection could not be established, let's return */ infof(data, "There is negative response in cache while serv connect\n"); Curl_GetFTPResponse(&nread, conn, &ftpcode); return CURLE_FTP_ACCEPT_FAILED; } result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); /* see if the connection request is already here */ switch(result) { case -1: /* error */ /* let's die here */ failf(data, "Error while waiting for server connect"); return CURLE_FTP_ACCEPT_FAILED; case 0: /* Server connect is not received yet */ break; /* loop */ default: if(result & CURL_CSELECT_IN2) { infof(data, "Ready to accept data connection from server\n"); *received = TRUE; } else if(result & CURL_CSELECT_IN) { infof(data, "Ctrl conn has data while waiting for data conn\n"); Curl_GetFTPResponse(&nread, conn, &ftpcode); if(ftpcode/100 > 3) return CURLE_FTP_ACCEPT_FAILED; return CURLE_WEIRD_SERVER_REPLY; } break; } /* switch() */ return CURLE_OK; } /*********************************************************************** * * InitiateTransfer() * * After connection from server is accepted this function is called to * setup transfer parameters and initiate the data transfer. * */ static CURLcode InitiateTransfer(struct connectdata *conn) { struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; if(conn->bits.ftp_use_data_ssl) { /* since we only have a plaintext TCP connection here, we must now * do the TLS stuff */ infof(data, "Doing the SSL/TLS handshake on the data stream\n"); result = Curl_ssl_connect(conn, SECONDARYSOCKET); if(result) return result; } if(conn->proto.ftpc.state_saved == FTP_STOR) { /* When we know we're uploading a specified file, we can get the file size prior to the actual upload. */ Curl_pgrsSetUploadSize(data, data->state.infilesize); /* set the SO_SNDBUF for the secondary socket for those who need it */ Curl_sndbufset(conn->sock[SECONDARYSOCKET]); Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET); } else { /* FTP download: */ Curl_setup_transfer(data, SECONDARYSOCKET, conn->proto.ftpc.retr_size_saved, FALSE, -1); } conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ state(conn, FTP_STOP); return CURLE_OK; } /*********************************************************************** * * AllowServerConnect() * * When we've issue the PORT command, we have told the server to connect to * us. This function checks whether data connection is established if so it is * accepted. * */ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) { struct Curl_easy *data = conn->data; timediff_t timeout_ms; CURLcode result = CURLE_OK; *connected = FALSE; infof(data, "Preparing for accepting server on data port\n"); /* Save the time we start accepting server connect */ Curl_pgrsTime(data, TIMER_STARTACCEPT); timeout_ms = ftp_timeleft_accept(data); if(timeout_ms < 0) { /* if a timeout was already reached, bail out */ failf(data, "Accept timeout occurred while waiting server connect"); return CURLE_FTP_ACCEPT_TIMEOUT; } /* see if the connection request is already here */ result = ReceivedServerConnect(conn, connected); if(result) return result; if(*connected) { result = AcceptServerConnect(conn); if(result) return result; result = InitiateTransfer(conn); if(result) return result; } else { /* Add timeout to multi handle and break out of the loop */ if(*connected == FALSE) { Curl_expire(data, data->set.accepttimeout > 0 ? data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0); } } return result; } /* macro to check for a three-digit ftp status code at the start of the given string */ #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ ISDIGIT(line[2])) /* macro to check for the last line in an FTP server response */ #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len, int *code) { (void)conn; if((len > 3) && LASTLINE(line)) { *code = curlx_sltosi(strtol(line, NULL, 10)); return TRUE; } return FALSE; } static CURLcode ftp_readresp(curl_socket_t sockfd, struct pingpong *pp, int *ftpcode, /* return the ftp-code if done */ size_t *size) /* size of the response */ { struct connectdata *conn = pp->conn; struct Curl_easy *data = conn->data; #ifdef HAVE_GSSAPI char * const buf = data->state.buffer; #endif int code; CURLcode result = Curl_pp_readresp(sockfd, pp, &code, size); #if defined(HAVE_GSSAPI) /* handle the security-oriented responses 6xx ***/ switch(code) { case 631: code = Curl_sec_read_msg(conn, buf, PROT_SAFE); break; case 632: code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE); break; case 633: code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL); break; default: /* normal ftp stuff we pass through! */ break; } #endif /* store the latest code for later retrieval */ data->info.httpcode = code; if(ftpcode) *ftpcode = code; if(421 == code) { /* 421 means "Service not available, closing control connection." and FTP * servers use it to signal that idle session timeout has been exceeded. * If we ignored the response, it could end up hanging in some cases. * * This response code can come at any point so having it treated * generically is a good idea. */ infof(data, "We got a 421 - timeout!\n"); state(conn, FTP_STOP); return CURLE_OPERATION_TIMEDOUT; } return result; } /* --- parse FTP server responses --- */ /* * Curl_GetFTPResponse() is a BLOCKING function to read the full response * from a server after a command. * */ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ struct connectdata *conn, int *ftpcode) /* return the ftp-code */ { /* * We cannot read just one byte per read() and then go back to select() as * the OpenSSL read() doesn't grok that properly. * * Alas, read as much as possible, split up into lines, use the ending * line in a response or continue reading. */ curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; size_t nread; int cache_skip = 0; int value_to_be_ignored = 0; if(ftpcode) *ftpcode = 0; /* 0 for errors */ else /* make the pointer point to something for the rest of this function */ ftpcode = &value_to_be_ignored; *nreadp = 0; while(!*ftpcode && !result) { /* check and reset timeout value every lap */ time_t timeout = Curl_pp_state_timeout(pp, FALSE); time_t interval_ms; if(timeout <= 0) { failf(data, "FTP response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } interval_ms = 1000; /* use 1 second timeout intervals */ if(timeout < interval_ms) interval_ms = timeout; /* * Since this function is blocking, we need to wait here for input on the * connection and only then we call the response reading function. We do * timeout at least every second to make the timeout check run. * * A caution here is that the ftp_readresp() function has a cache that may * contain pieces of a response from the previous invoke and we need to * make sure we don't just wait for input while there is unhandled data in * that cache. But also, if the cache is there, we call ftp_readresp() and * the cache wasn't good enough to continue we must not just busy-loop * around this function. * */ if(pp->cache && (cache_skip < 2)) { /* * There's a cache left since before. We then skipping the wait for * socket action, unless this is the same cache like the previous round * as then the cache was deemed not enough to act on and we then need to * wait for more data anyway. */ } else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) { switch(SOCKET_READABLE(sockfd, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", SOCKERRNO); return CURLE_RECV_ERROR; case 0: /* timeout */ if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; continue; /* just continue in our loop for the timeout duration */ default: /* for clarity */ break; } } result = ftp_readresp(sockfd, pp, ftpcode, &nread); if(result) break; if(!nread && pp->cache) /* bump cache skip counter as on repeated skips we must wait for more data */ cache_skip++; else /* when we got data or there is no cache left, we reset the cache skip counter */ cache_skip = 0; *nreadp += nread; } /* while there's buffer left and loop is requested */ pp->pending_resp = FALSE; return result; } #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ static const char * const ftp_state_names[]={ "STOP", "WAIT220", "AUTH", "USER", "PASS", "ACCT", "PBSZ", "PROT", "CCC", "PWD", "SYST", "NAMEFMT", "QUOTE", "RETR_PREQUOTE", "STOR_PREQUOTE", "POSTQUOTE", "CWD", "MKD", "MDTM", "TYPE", "LIST_TYPE", "RETR_TYPE", "STOR_TYPE", "SIZE", "RETR_SIZE", "STOR_SIZE", "REST", "RETR_REST", "PORT", "PRET", "PASV", "LIST", "RETR", "STOR", "QUIT" }; #endif /* This is the ONLY way to change FTP state! */ static void _state(struct connectdata *conn, ftpstate newstate #ifdef DEBUGBUILD , int lineno #endif ) { struct ftp_conn *ftpc = &conn->proto.ftpc; #if defined(DEBUGBUILD) #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) lineno; #else if(ftpc->state != newstate) infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", (void *)ftpc, lineno, ftp_state_names[ftpc->state], ftp_state_names[newstate]); #endif #endif ftpc->state = newstate; } static CURLcode ftp_state_user(struct connectdata *conn) { CURLcode result; /* send USER */ PPSENDF(&conn->proto.ftpc.pp, "USER %s", conn->user?conn->user:""); state(conn, FTP_USER); conn->data->state.ftp_trying_alternative = FALSE; return CURLE_OK; } static CURLcode ftp_state_pwd(struct connectdata *conn) { CURLcode result; /* send PWD to discover our entry point */ PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD"); state(conn, FTP_PWD); return CURLE_OK; } /* For the FTP "protocol connect" and "doing" phases only */ static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks) { return Curl_pp_getsock(&conn->proto.ftpc.pp, socks); } /* For the FTP "DO_MORE" phase only */ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks) { struct ftp_conn *ftpc = &conn->proto.ftpc; /* When in DO_MORE state, we could be either waiting for us to connect to a * remote site, or we could wait for that site to connect to us. Or just * handle ordinary commands. */ if(SOCKS_STATE(conn->cnnct.state)) return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET); if(FTP_STOP == ftpc->state) { int bits = GETSOCK_READSOCK(0); /* if stopped and still in this state, then we're also waiting for a connect on the secondary connection */ socks[0] = conn->sock[FIRSTSOCKET]; if(!conn->data->set.ftp_use_port) { int s; int i; /* PORT is used to tell the server to connect to us, and during that we don't do happy eyeballs, but we do if we connect to the server */ for(s = 1, i = 0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { socks[s] = conn->tempsock[i]; bits |= GETSOCK_WRITESOCK(s++); } } } else { socks[1] = conn->sock[SECONDARYSOCKET]; bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); } return bits; } return Curl_pp_getsock(&conn->proto.ftpc.pp, socks); } /* This is called after the FTP_QUOTE state is passed. ftp_state_cwd() sends the range of CWD commands to the server to change to the correct directory. It may also need to send MKD commands to create missing ones, if that option is enabled. */ static CURLcode ftp_state_cwd(struct connectdata *conn) { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; if(ftpc->cwddone) /* already done and fine */ result = ftp_state_mdtm(conn); else { /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ DEBUGASSERT((conn->data->set.ftp_filemethod != FTPFILE_NOCWD) || !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); ftpc->count2 = 0; /* count2 counts failed CWDs */ /* count3 is set to allow a MKD to fail once. In the case when first CWD fails and then MKD fails (due to another session raced it to create the dir) this then allows for a second try to CWD to it */ ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0; if(conn->bits.reuse && ftpc->entrypath && /* no need to go to entrypath when we have an absolute path */ !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { /* This is a re-used connection. Since we change directory to where the transfer is taking place, we must first get back to the original dir where we ended up after login: */ ftpc->cwdcount = 0; /* we count this as the first path, then we add one for all upcoming ones in the ftp->dirs[] array */ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath); state(conn, FTP_CWD); } else { if(ftpc->dirdepth) { ftpc->cwdcount = 1; /* issue the first CWD, the rest is sent when the CWD responses are received... */ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]); state(conn, FTP_CWD); } else { /* No CWD necessary */ result = ftp_state_mdtm(conn); } } } return result; } typedef enum { EPRT, PORT, DONE } ftpport; static CURLcode ftp_state_use_port(struct connectdata *conn, ftpport fcmd) /* start with this */ { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; struct Curl_easy *data = conn->data; curl_socket_t portsock = CURL_SOCKET_BAD; char myhost[MAX_IPADR_LEN + 1] = ""; struct Curl_sockaddr_storage ss; Curl_addrinfo *res, *ai; curl_socklen_t sslen; char hbuf[NI_MAXHOST]; struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr_in * const sa4 = (void *)sa; #ifdef ENABLE_IPV6 struct sockaddr_in6 * const sa6 = (void *)sa; #endif static const char mode[][5] = { "EPRT", "PORT" }; enum resolve_t rc; int error; char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; struct Curl_dns_entry *h = NULL; unsigned short port_min = 0; unsigned short port_max = 0; unsigned short port; bool possibly_non_local = TRUE; char buffer[STRERROR_LEN]; char *addr = NULL; /* Step 1, figure out what is requested, * accepted format : * (ipv4|ipv6|domain|interface)?(:port(-range)?)? */ if(data->set.str[STRING_FTPPORT] && (strlen(data->set.str[STRING_FTPPORT]) > 1)) { #ifdef ENABLE_IPV6 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ? INET6_ADDRSTRLEN : strlen(string_ftpport); #else size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ? INET_ADDRSTRLEN : strlen(string_ftpport); #endif char *ip_start = string_ftpport; char *ip_end = NULL; char *port_start = NULL; char *port_sep = NULL; addr = calloc(addrlen + 1, 1); if(!addr) return CURLE_OUT_OF_MEMORY; #ifdef ENABLE_IPV6 if(*string_ftpport == '[') { /* [ipv6]:port(-range) */ ip_start = string_ftpport + 1; ip_end = strchr(string_ftpport, ']'); if(ip_end) strncpy(addr, ip_start, ip_end - ip_start); } else #endif if(*string_ftpport == ':') { /* :port */ ip_end = string_ftpport; } else { ip_end = strchr(string_ftpport, ':'); if(ip_end) { /* either ipv6 or (ipv4|domain|interface):port(-range) */ #ifdef ENABLE_IPV6 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { /* ipv6 */ port_min = port_max = 0; strcpy(addr, string_ftpport); ip_end = NULL; /* this got no port ! */ } else #endif /* (ipv4|domain|interface):port(-range) */ strncpy(addr, string_ftpport, ip_end - ip_start); } else /* ipv4|interface */ strcpy(addr, string_ftpport); } /* parse the port */ if(ip_end != NULL) { port_start = strchr(ip_end, ':'); if(port_start) { port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); port_sep = strchr(port_start, '-'); if(port_sep) { port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); } else port_max = port_min; } } /* correct errors like: * :1234-1230 * :-4711, in this case port_min is (unsigned)-1, * therefore port_min > port_max for all cases * but port_max = (unsigned)-1 */ if(port_min > port_max) port_min = port_max = 0; if(*addr != '\0') { /* attempt to get the address of the given interface name */ switch(Curl_if2ip(conn->ip_addr->ai_family, Curl_ipv6_scope(conn->ip_addr->ai_addr), conn->scope_id, addr, hbuf, sizeof(hbuf))) { case IF2IP_NOT_FOUND: /* not an interface, use the given string as host name instead */ host = addr; break; case IF2IP_AF_NOT_SUPPORTED: return CURLE_FTP_PORT_FAILED; case IF2IP_FOUND: host = hbuf; /* use the hbuf for host name */ } } else /* there was only a port(-range) given, default the host */ host = NULL; } /* data->set.ftpport */ if(!host) { /* not an interface and not a host name, get default by extracting the IP from the control connection */ sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); free(addr); return CURLE_FTP_PORT_FAILED; } switch(sa->sa_family) { #ifdef ENABLE_IPV6 case AF_INET6: Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); break; #endif default: Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); break; } host = hbuf; /* use this host name */ possibly_non_local = FALSE; /* we know it is local now */ } /* resolv ip/host to ip */ rc = Curl_resolv(conn, host, 0, FALSE, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_resolver_wait_resolv(conn, &h); if(h) { res = h->addr; /* when we return from this function, we can forget about this entry to we can unlock it now already */ Curl_resolv_unlock(data, h); } /* (h) */ else res = NULL; /* failure! */ if(res == NULL) { failf(data, "failed to resolve the address provided to PORT: %s", host); free(addr); return CURLE_FTP_PORT_FAILED; } free(addr); host = NULL; /* step 2, create a socket for the requested address */ portsock = CURL_SOCKET_BAD; error = 0; for(ai = res; ai; ai = ai->ai_next) { result = Curl_socket(conn, ai, NULL, &portsock); if(result) { error = SOCKERRNO; continue; } break; } if(!ai) { failf(data, "socket failure: %s", Curl_strerror(error, buffer, sizeof(buffer))); return CURLE_FTP_PORT_FAILED; } /* step 3, bind to a suitable local address */ memcpy(sa, ai->ai_addr, ai->ai_addrlen); sslen = ai->ai_addrlen; for(port = port_min; port <= port_max;) { if(sa->sa_family == AF_INET) sa4->sin_port = htons(port); #ifdef ENABLE_IPV6 else sa6->sin6_port = htons(port); #endif /* Try binding the given address. */ if(bind(portsock, sa, sslen) ) { /* It failed. */ error = SOCKERRNO; if(possibly_non_local && (error == EADDRNOTAVAIL)) { /* The requested bind address is not local. Use the address used for * the control connection instead and restart the port loop */ infof(data, "bind(port=%hu) on non-local address failed: %s\n", port, Curl_strerror(error, buffer, sizeof(buffer))); sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } port = port_min; possibly_non_local = FALSE; /* don't try this again */ continue; } if(error != EADDRINUSE && error != EACCES) { failf(data, "bind(port=%hu) failed: %s", port, Curl_strerror(error, buffer, sizeof(buffer))); Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } } else break; port++; } /* maybe all ports were in use already*/ if(port > port_max) { failf(data, "bind() failed, we ran out of ports!"); Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } /* get the name again after the bind() so that we can extract the port number it uses now */ sslen = sizeof(ss); if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) { failf(data, "getsockname() failed: %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } /* step 4, listen on the socket */ if(listen(portsock, 1)) { failf(data, "socket failure: %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); Curl_closesocket(conn, portsock); return CURLE_FTP_PORT_FAILED; } /* step 5, send the proper FTP command */ /* get a plain printable version of the numerical address to work with below */ Curl_printable_address(ai, myhost, sizeof(myhost)); #ifdef ENABLE_IPV6 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the request and enable EPRT again! */ conn->bits.ftp_use_eprt = TRUE; #endif for(; fcmd != DONE; fcmd++) { if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) /* if disabled, goto next */ continue; if((PORT == fcmd) && sa->sa_family != AF_INET) /* PORT is IPv4 only */ continue; switch(sa->sa_family) { case AF_INET: port = ntohs(sa4->sin_port); break; #ifdef ENABLE_IPV6 case AF_INET6: port = ntohs(sa6->sin6_port); break; #endif default: continue; /* might as well skip this */ } if(EPRT == fcmd) { /* * Two fine examples from RFC2428; * * EPRT |1|132.235.1.2|6275| * * EPRT |2|1080::8:800:200C:417A|5282| */ result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], sa->sa_family == AF_INET?1:2, myhost, port); if(result) { failf(data, "Failure sending EPRT command: %s", curl_easy_strerror(result)); Curl_closesocket(conn, portsock); /* don't retry using PORT */ ftpc->count1 = PORT; /* bail out */ state(conn, FTP_STOP); return result; } break; } if(PORT == fcmd) { /* large enough for [IP address],[num],[num] */ char target[sizeof(myhost) + 20]; char *source = myhost; char *dest = target; /* translate x.x.x.x to x,x,x,x */ while(source && *source) { if(*source == '.') *dest = ','; else *dest = *source; dest++; source++; } *dest = 0; msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], target); if(result) { failf(data, "Failure sending PORT command: %s", curl_easy_strerror(result)); Curl_closesocket(conn, portsock); /* bail out */ state(conn, FTP_STOP); return result; } break; } } /* store which command was sent */ ftpc->count1 = fcmd; close_secondarysocket(conn); /* we set the secondary socket variable to this for now, it is only so that the cleanup function will close it in case we fail before the true secondary stuff is made */ conn->sock[SECONDARYSOCKET] = portsock; /* this tcpconnect assignment below is a hackish work-around to make the multi interface with active FTP work - as it will not wait for a (passive) connect in Curl_is_connected(). The *proper* fix is to make sure that the active connection from the server is done in a non-blocking way. Currently, it is still BLOCKING. */ conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_PORT); return result; } static CURLcode ftp_state_use_pasv(struct connectdata *conn) { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; /* Here's the excecutive summary on what to do: PASV is RFC959, expect: 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) LPSV is RFC1639, expect: 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2) EPSV is RFC2428, expect: 229 Entering Extended Passive Mode (|||port|) */ static const char mode[][5] = { "EPSV", "PASV" }; int modeoff; #ifdef PF_INET6 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the request and enable EPSV again! */ conn->bits.ftp_use_epsv = TRUE; #endif modeoff = conn->bits.ftp_use_epsv?0:1; PPSENDF(&ftpc->pp, "%s", mode[modeoff]); ftpc->count1 = modeoff; state(conn, FTP_PASV); infof(conn->data, "Connect data stream passively\n"); return result; } /* * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. * * REST is the last command in the chain of commands when a "head"-like * request is made. Thus, if an actual transfer is to be made this is where we * take off for real. */ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; struct Curl_easy *data = conn->data; if(ftp->transfer != FTPTRANSFER_BODY) { /* doesn't transfer any data */ /* still possibly do PRE QUOTE jobs */ state(conn, FTP_RETR_PREQUOTE); result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); } else if(data->set.ftp_use_port) { /* We have chosen to use the PORT (or similar) command */ result = ftp_state_use_port(conn, EPRT); } else { /* We have chosen (this is default) to use the PASV (or similar) command */ if(data->set.ftp_use_pret) { /* The user has requested that we send a PRET command to prepare the server for the upcoming PASV */ if(!conn->proto.ftpc.file) { PPSENDF(&conn->proto.ftpc.pp, "PRET %s", data->set.str[STRING_CUSTOMREQUEST]? data->set.str[STRING_CUSTOMREQUEST]: (data->set.ftp_list_only?"NLST":"LIST")); } else if(data->set.upload) { PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file); } else { PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file); } state(conn, FTP_PRET); } else { result = ftp_state_use_pasv(conn); } } return result; } static CURLcode ftp_state_rest(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) { /* if a "head"-like request is being made (on a file) */ /* Determine if server can respond to REST command and therefore whether it supports range */ PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0); state(conn, FTP_REST); } else result = ftp_state_prepare_transfer(conn); return result; } static CURLcode ftp_state_size(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) { /* if a "head"-like request is being made (on a file) */ /* we know ftpc->file is a valid pointer to a file name */ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_SIZE); } else result = ftp_state_rest(conn); return result; } static CURLcode ftp_state_list(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; /* If this output is to be machine-parsed, the NLST command might be better to use, since the LIST command output is not specified or standard in any way. It has turned out that the NLST list output is not the same on all servers either... */ /* if FTPFILE_NOCWD was specified, we should add the path as argument for the LIST / NLST / or custom command. Whether the server will support this, is uncertain. The other ftp_filemethods will CWD into dir/dir/ first and then just do LIST (in that case: nothing to do here) */ char *lstArg = NULL; char *cmd; if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { /* url-decode before evaluation: e.g. paths starting/ending with %2f */ const char *slashPos = NULL; char *rawPath = NULL; result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, TRUE); if(result) return result; slashPos = strrchr(rawPath, '/'); if(slashPos) { /* chop off the file part if format is dir/file otherwise remove the trailing slash for dir/dir/ except for absolute path / */ size_t n = slashPos - rawPath; if(n == 0) ++n; lstArg = rawPath; lstArg[n] = '\0'; } else free(rawPath); } cmd = aprintf("%s%s%s", data->set.str[STRING_CUSTOMREQUEST]? data->set.str[STRING_CUSTOMREQUEST]: (data->set.ftp_list_only?"NLST":"LIST"), lstArg? " ": "", lstArg? lstArg: ""); free(lstArg); if(!cmd) return CURLE_OUT_OF_MEMORY; result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); free(cmd); if(result) return result; state(conn, FTP_LIST); return result; } static CURLcode ftp_state_retr_prequote(struct connectdata *conn) { /* We've sent the TYPE, now we must send the list of prequote strings */ return ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE); } static CURLcode ftp_state_stor_prequote(struct connectdata *conn) { /* We've sent the TYPE, now we must send the list of prequote strings */ return ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE); } static CURLcode ftp_state_type(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* If we have selected NOBODY and HEADER, it means that we only want file information. Which in FTP can't be much more than the file size and date. */ if(data->set.opt_no_body && ftpc->file && ftp_need_type(conn, data->set.prefer_ascii)) { /* The SIZE command is _not_ RFC 959 specified, and therefore many servers may not support it! It is however the only way we have to get a file's size! */ ftp->transfer = FTPTRANSFER_INFO; /* this means no actual transfer will be made */ /* Some servers return different sizes for different modes, and thus we must set the proper type before we check the size */ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE); if(result) return result; } else result = ftp_state_size(conn); return result; } /* This is called after the CWD commands have been done in the beginning of the DO phase */ static CURLcode ftp_state_mdtm(struct connectdata *conn) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* Requested time of file or time-depended transfer? */ if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { /* we have requested to get the modified-time of the file, this is a white spot as the MDTM is not mentioned in RFC959 */ PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file); state(conn, FTP_MDTM); } else result = ftp_state_type(conn); return result; } /* This is called after the TYPE and possible quote commands have been sent */ static CURLcode ftp_state_ul_setup(struct connectdata *conn, bool sizechecked) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; if((data->state.resume_from && !sizechecked) || ((data->state.resume_from > 0) && sizechecked)) { /* we're about to continue the uploading of a file */ /* 1. get already existing file's size. We use the SIZE command for this which may not exist in the server! The SIZE command is not in RFC959. */ /* 2. This used to set REST. But since we can do append, we don't another ftp command. We just skip the source file offset and then we APPEND the rest on the file instead */ /* 3. pass file-size number of bytes in the source file */ /* 4. lower the infilesize counter */ /* => transfer as usual */ int seekerr = CURL_SEEKFUNC_OK; if(data->state.resume_from < 0) { /* Got no given size to start from, figure it out */ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_STOR_SIZE); return result; } /* enable append */ data->set.ftp_append = TRUE; /* Let's read off the proper amount of bytes from the input. */ if(conn->seek_func) { Curl_set_in_callback(data, true); seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, SEEK_SET); Curl_set_in_callback(data, false); } if(seekerr != CURL_SEEKFUNC_OK) { curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { size_t readthisamountnow = (data->state.resume_from - passed > data->set.buffer_size) ? (size_t)data->set.buffer_size : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = data->state.fread_func(data->state.buffer, 1, readthisamountnow, data->state.in); passed += actuallyread; if((actuallyread == 0) || (actuallyread > readthisamountnow)) { /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Failed to read data"); return CURLE_FTP_COULDNT_USE_REST; } } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize>0) { data->state.infilesize -= data->state.resume_from; if(data->state.infilesize <= 0) { infof(data, "File already completely uploaded\n"); /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); /* Set ->transfer so that we won't get any error in * ftp_done() because we didn't transfer anything! */ ftp->transfer = FTPTRANSFER_NONE; state(conn, FTP_STOP); return CURLE_OK; } } /* we've passed, proceed as normal */ } /* resume_from */ PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s", ftpc->file); state(conn, FTP_STOR); return result; } static CURLcode ftp_state_quote(struct connectdata *conn, bool init, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; bool quote = FALSE; struct curl_slist *item; switch(instate) { case FTP_QUOTE: default: item = data->set.quote; break; case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: item = data->set.prequote; break; case FTP_POSTQUOTE: item = data->set.postquote; break; } /* * This state uses: * 'count1' to iterate over the commands to send * 'count2' to store whether to allow commands to fail */ if(init) ftpc->count1 = 0; else ftpc->count1++; if(item) { int i = 0; /* Skip count1 items in the linked list */ while((i< ftpc->count1) && item) { item = item->next; i++; } if(item) { char *cmd = item->data; if(cmd[0] == '*') { cmd++; ftpc->count2 = 1; /* the sent command is allowed to fail */ } else ftpc->count2 = 0; /* failure means cancel operation */ PPSENDF(&ftpc->pp, "%s", cmd); state(conn, instate); quote = TRUE; } } if(!quote) { /* No more quote to send, continue to ... */ switch(instate) { case FTP_QUOTE: default: result = ftp_state_cwd(conn); break; case FTP_RETR_PREQUOTE: if(ftp->transfer != FTPTRANSFER_BODY) state(conn, FTP_STOP); else { if(ftpc->known_filesize != -1) { Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); result = ftp_state_retr(conn, ftpc->known_filesize); } else { if(data->set.ignorecl) { /* This code is to support download of growing files. It prevents the state machine from requesting the file size from the server. With an unknown file size the download continues until the server terminates it, otherwise the client stops if the received byte count exceeds the reported file size. Set option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); state(conn, FTP_RETR); } else { PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_RETR_SIZE); } } } break; case FTP_STOR_PREQUOTE: result = ftp_state_ul_setup(conn, FALSE); break; case FTP_POSTQUOTE: break; } } return result; } /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV problems */ static CURLcode ftp_epsv_disable(struct connectdata *conn) { CURLcode result = CURLE_OK; if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) { /* We can't disable EPSV when doing IPv6, so this is instead a fail */ failf(conn->data, "Failed EPSV attempt, exiting\n"); return CURLE_WEIRD_SERVER_REPLY; } infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); /* disable it for next transfer */ conn->bits.ftp_use_epsv = FALSE; conn->data->state.errorbuf = FALSE; /* allow error message to get rewritten */ PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV"); conn->proto.ftpc.count1++; /* remain in/go to the FTP_PASV state */ state(conn, FTP_PASV); return result; } static char *control_address(struct connectdata *conn) { /* Returns the control connection IP address. If a proxy tunnel is used, returns the original host name instead, because the effective control connection address is the proxy address, not the ftp host. */ if(conn->bits.tunnel_proxy || conn->bits.socksproxy) return conn->host.name; return conn->ip_addr_str; } static CURLcode ftp_state_pasv_resp(struct connectdata *conn, int ftpcode) { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; struct Curl_easy *data = conn->data; struct Curl_dns_entry *addr = NULL; enum resolve_t rc; unsigned short connectport; /* the local port connect() should use! */ char *str = &data->state.buffer[4]; /* start on the first letter */ /* if we come here again, make sure the former name is cleared */ Curl_safefree(ftpc->newhost); if((ftpc->count1 == 0) && (ftpcode == 229)) { /* positive EPSV response */ char *ptr = strchr(str, '('); if(ptr) { unsigned int num; char separator[4]; ptr++; if(5 == sscanf(ptr, "%c%c%c%u%c", &separator[0], &separator[1], &separator[2], &num, &separator[3])) { const char sep1 = separator[0]; int i; /* The four separators should be identical, or else this is an oddly formatted reply and we bail out immediately. */ for(i = 1; i<4; i++) { if(separator[i] != sep1) { ptr = NULL; /* set to NULL to signal error */ break; } } if(num > 0xffff) { failf(data, "Illegal port number in EPSV reply"); return CURLE_FTP_WEIRD_PASV_REPLY; } if(ptr) { ftpc->newport = (unsigned short)(num & 0xffff); ftpc->newhost = strdup(control_address(conn)); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; } } else ptr = NULL; } if(!ptr) { failf(data, "Weirdly formatted EPSV reply"); return CURLE_FTP_WEIRD_PASV_REPLY; } } else if((ftpc->count1 == 1) && (ftpcode == 227)) { /* positive PASV response */ unsigned int ip[4]; unsigned int port[2]; /* * Scan for a sequence of six comma-separated numbers and use them as * IP+port indicators. * * Found reply-strings include: * "227 Entering Passive Mode (127,0,0,1,4,51)" * "227 Data transfer will passively listen to 127,0,0,1,4,51" * "227 Entering passive mode. 127,0,0,1,4,51" */ while(*str) { if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u", &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1])) break; str++; } if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) || (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) { failf(data, "Couldn't interpret the 227-response"); return CURLE_FTP_WEIRD_227_FORMAT; } /* we got OK from server */ if(data->set.ftp_skip_ip) { /* told to ignore the remotely given IP but instead use the host we used for the control connection */ infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n", ip[0], ip[1], ip[2], ip[3], conn->host.name); ftpc->newhost = strdup(control_address(conn)); } else ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); } else if(ftpc->count1 == 0) { /* EPSV failed, move on to PASV */ return ftp_epsv_disable(conn); } else { failf(data, "Bad PASV/EPSV response: %03d", ftpcode); return CURLE_FTP_WEIRD_PASV_REPLY; } if(conn->bits.proxy) { /* * This connection uses a proxy and we need to connect to the proxy again * here. We don't want to rely on a former host lookup that might've * expired now, instead we remake the lookup here and now! */ const char * const host_name = conn->bits.socksproxy ? conn->socks_proxy.host.name : conn->http_proxy.host.name; rc = Curl_resolv(conn, host_name, (int)conn->port, FALSE, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING, ignores the return code but 'addr' will be NULL in case of failure */ (void)Curl_resolver_wait_resolv(conn, &addr); connectport = (unsigned short)conn->port; /* we connect to the proxy's port */ if(!addr) { failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); return CURLE_COULDNT_RESOLVE_PROXY; } } else { /* normal, direct, ftp connection */ rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING */ (void)Curl_resolver_wait_resolv(conn, &addr); connectport = ftpc->newport; /* we connect to the remote port */ if(!addr) { failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); return CURLE_FTP_CANT_GET_HOST; } } conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; result = Curl_connecthost(conn, addr); if(result) { Curl_resolv_unlock(data, addr); /* we're done using this address */ if(ftpc->count1 == 0 && ftpcode == 229) return ftp_epsv_disable(conn); return result; } /* * When this is used from the multi interface, this might've returned with * the 'connected' set to FALSE and thus we are now awaiting a non-blocking * connect to connect. */ if(data->set.verbose) /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); Curl_resolv_unlock(data, addr); /* we're done using this address */ Curl_safefree(conn->secondaryhostname); conn->secondary_port = ftpc->newport; conn->secondaryhostname = strdup(ftpc->newhost); if(!conn->secondaryhostname) return CURLE_OUT_OF_MEMORY; conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ return result; } static CURLcode ftp_state_port_resp(struct connectdata *conn, int ftpcode) { struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; ftpport fcmd = (ftpport)ftpc->count1; CURLcode result = CURLE_OK; /* The FTP spec tells a positive response should have code 200. Be more permissive here to tolerate deviant servers. */ if(ftpcode / 100 != 2) { /* the command failed */ if(EPRT == fcmd) { infof(data, "disabling EPRT usage\n"); conn->bits.ftp_use_eprt = FALSE; } fcmd++; if(fcmd == DONE) { failf(data, "Failed to do PORT"); result = CURLE_FTP_PORT_FAILED; } else /* try next */ result = ftp_state_use_port(conn, fcmd); } else { infof(data, "Connect data stream actively\n"); state(conn, FTP_STOP); /* end of DO phase */ result = ftp_dophase_done(conn, FALSE); } return result; } static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; switch(ftpcode) { case 213: { /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the last .sss part is optional and means fractions of a second */ int year, month, day, hour, minute, second; if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d", &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; msnprintf(timebuf, sizeof(timebuf), "%04d%02d%02d %02d:%02d:%02d GMT", year, month, day, hour, minute, second); /* now, convert this into a time() value: */ data->info.filetime = Curl_getdate_capped(timebuf); } #ifdef CURL_FTP_HTTPSTYLE_HEAD /* If we asked for a time of the file and we actually got one as well, we "emulate" a HTTP-style header in our output. */ if(data->set.opt_no_body && ftpc->file && data->set.get_filetime && (data->info.filetime >= 0) ) { char headerbuf[128]; time_t filetime = data->info.filetime; struct tm buffer; const struct tm *tm = &buffer; result = Curl_gmtime(filetime, &buffer); if(result) return result; /* format: "Tue, 15 Nov 1994 12:45:26" */ msnprintf(headerbuf, sizeof(headerbuf), "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, Curl_month[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0); if(result) return result; } /* end of a ridiculous amount of conditionals */ #endif } break; default: infof(data, "unsupported MDTM reply format\n"); break; case 550: /* "No such file or directory" */ failf(data, "Given file does not exist"); result = CURLE_FTP_COULDNT_RETR_FILE; break; } if(data->set.timecondition) { if((data->info.filetime > 0) && (data->set.timevalue > 0)) { switch(data->set.timecondition) { case CURL_TIMECOND_IFMODSINCE: default: if(data->info.filetime <= data->set.timevalue) { infof(data, "The requested document is not new enough\n"); ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ data->info.timecond = TRUE; state(conn, FTP_STOP); return CURLE_OK; } break; case CURL_TIMECOND_IFUNMODSINCE: if(data->info.filetime > data->set.timevalue) { infof(data, "The requested document is not old enough\n"); ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */ data->info.timecond = TRUE; state(conn, FTP_STOP); return CURLE_OK; } break; } /* switch */ } else { infof(data, "Skipping time comparison\n"); } } if(!result) result = ftp_state_type(conn); return result; } static CURLcode ftp_state_type_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; if(ftpcode/100 != 2) { /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a successful 'TYPE I'. While that is not as RFC959 says, it is still a positive response code and we allow that. */ failf(data, "Couldn't set desired mode"); return CURLE_FTP_COULDNT_SET_TYPE; } if(ftpcode != 200) infof(data, "Got a %03d response code instead of the assumed 200\n", ftpcode); if(instate == FTP_TYPE) result = ftp_state_size(conn); else if(instate == FTP_LIST_TYPE) result = ftp_state_list(conn); else if(instate == FTP_RETR_TYPE) result = ftp_state_retr_prequote(conn); else if(instate == FTP_STOR_TYPE) result = ftp_state_stor_prequote(conn); return result; } static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if(data->set.max_filesize && (filesize > data->set.max_filesize)) { failf(data, "Maximum file size exceeded"); return CURLE_FILESIZE_EXCEEDED; } ftp->downloadsize = filesize; if(data->state.resume_from) { /* We always (attempt to) get the size of downloads, so it is done before this even when not doing resumes. */ if(filesize == -1) { infof(data, "ftp server doesn't support SIZE\n"); /* We couldn't get the size and therefore we can't know if there really is a part of the file left to get, although the server will just close the connection when we start the connection so it won't cause us any harm, just not make us exit as nicely. */ } else { /* We got a file size report, so we check that there actually is a part of the file left to get, or else we go home. */ if(data->state.resume_from< 0) { /* We're supposed to download the last abs(from) bytes */ if(filesize < -data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, filesize); return CURLE_BAD_DOWNLOAD_RESUME; } /* convert to size to download */ ftp->downloadsize = -data->state.resume_from; /* download from where? */ data->state.resume_from = filesize - ftp->downloadsize; } else { if(filesize < data->state.resume_from) { failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")", data->state.resume_from, filesize); return CURLE_BAD_DOWNLOAD_RESUME; } /* Now store the number of bytes we are expected to download */ ftp->downloadsize = filesize-data->state.resume_from; } } if(ftp->downloadsize == 0) { /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); infof(data, "File already completely downloaded\n"); /* Set ->transfer so that we won't get any error in ftp_done() * because we didn't transfer the any file */ ftp->transfer = FTPTRANSFER_NONE; state(conn, FTP_STOP); return CURLE_OK; } /* Set resume file transfer offset */ infof(data, "Instructs server to resume from offset %" CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from); PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, data->state.resume_from); state(conn, FTP_RETR_REST); } else { /* no resume */ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); state(conn, FTP_RETR); } return result; } static CURLcode ftp_state_size_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; curl_off_t filesize = -1; char *buf = data->state.buffer; /* get the size from the ascii string: */ if(ftpcode == 213) { /* To allow servers to prepend "rubbish" in the response string, we scan for all the digits at the end of the response and parse only those as a number. */ char *start = &buf[4]; char *fdigit = strchr(start, '\r'); if(fdigit) { do fdigit--; while(ISDIGIT(*fdigit) && (fdigit > start)); if(!ISDIGIT(*fdigit)) fdigit++; } else fdigit = start; /* ignores parsing errors, which will make the size remain unknown */ (void)curlx_strtoofft(fdigit, NULL, 0, &filesize); } if(instate == FTP_SIZE) { #ifdef CURL_FTP_HTTPSTYLE_HEAD if(-1 != filesize) { char clbuf[128]; msnprintf(clbuf, sizeof(clbuf), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0); if(result) return result; } #endif Curl_pgrsSetDownloadSize(data, filesize); result = ftp_state_rest(conn); } else if(instate == FTP_RETR_SIZE) { Curl_pgrsSetDownloadSize(data, filesize); result = ftp_state_retr(conn, filesize); } else if(instate == FTP_STOR_SIZE) { data->state.resume_from = filesize; result = ftp_state_ul_setup(conn, TRUE); } return result; } static CURLcode ftp_state_rest_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; switch(instate) { case FTP_REST: default: #ifdef CURL_FTP_HTTPSTYLE_HEAD if(ftpcode == 350) { char buffer[24]= { "Accept-ranges: bytes\r\n" }; result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0); if(result) return result; } #endif result = ftp_state_prepare_transfer(conn); break; case FTP_RETR_REST: if(ftpcode != 350) { failf(conn->data, "Couldn't use REST"); result = CURLE_FTP_COULDNT_USE_REST; } else { PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); state(conn, FTP_RETR); } break; } return result; } static CURLcode ftp_state_stor_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; if(ftpcode >= 400) { failf(data, "Failed FTP upload: %0d", ftpcode); state(conn, FTP_STOP); /* oops, we never close the sockets! */ return CURLE_UPLOAD_FAILED; } conn->proto.ftpc.state_saved = instate; /* PORT means we are now awaiting the server to connect to us. */ if(data->set.ftp_use_port) { bool connected; state(conn, FTP_STOP); /* no longer in STOR state */ result = AllowServerConnect(conn, &connected); if(result) return result; if(!connected) { struct ftp_conn *ftpc = &conn->proto.ftpc; infof(data, "Data conn was not available immediately\n"); ftpc->wait_data_conn = TRUE; } return CURLE_OK; } return InitiateTransfer(conn); } /* for LIST and RETR responses */ static CURLcode ftp_state_get_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; if((ftpcode == 150) || (ftpcode == 125)) { /* A; 150 Opening BINARY mode data connection for /etc/passwd (2241 bytes). (ok, the file is being transferred) B: 150 Opening ASCII mode data connection for /bin/ls C: 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes). D: 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes) E: 125 Data connection already open; Transfer starting. */ curl_off_t size = -1; /* default unknown size */ /* * It appears that there are FTP-servers that return size 0 for files when * SIZE is used on the file while being in BINARY mode. To work around * that (stupid) behavior, we attempt to parse the RETR response even if * the SIZE returned size zero. * * Debugging help from Salvatore Sorrentino on February 26, 2003. */ if((instate != FTP_LIST) && !data->set.prefer_ascii && (ftp->downloadsize < 1)) { /* * It seems directory listings either don't show the size or very * often uses size 0 anyway. ASCII transfers may very well turn out * that the transferred amount of data is not the same as this line * tells, why using this number in those cases only confuses us. * * Example D above makes this parsing a little tricky */ char *bytes; char *buf = data->state.buffer; bytes = strstr(buf, " bytes"); if(bytes) { long in = (long)(--bytes-buf); /* this is a hint there is size information in there! ;-) */ while(--in) { /* scan for the left parenthesis and break there */ if('(' == *bytes) break; /* skip only digits */ if(!ISDIGIT(*bytes)) { bytes = NULL; break; } /* one more estep backwards */ bytes--; } /* if we have nothing but digits: */ if(bytes++) { /* get the number! */ (void)curlx_strtoofft(bytes, NULL, 0, &size); } } } else if(ftp->downloadsize > -1) size = ftp->downloadsize; if(size > data->req.maxdownload && data->req.maxdownload > 0) size = data->req.size = data->req.maxdownload; else if((instate != FTP_LIST) && (data->set.prefer_ascii)) size = -1; /* kludge for servers that understate ASCII mode file size */ infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n", data->req.maxdownload); if(instate != FTP_LIST) infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n", size); /* FTP download: */ conn->proto.ftpc.state_saved = instate; conn->proto.ftpc.retr_size_saved = size; if(data->set.ftp_use_port) { bool connected; result = AllowServerConnect(conn, &connected); if(result) return result; if(!connected) { struct ftp_conn *ftpc = &conn->proto.ftpc; infof(data, "Data conn was not available immediately\n"); state(conn, FTP_STOP); ftpc->wait_data_conn = TRUE; } } else return InitiateTransfer(conn); } else { if((instate == FTP_LIST) && (ftpcode == 450)) { /* simply no matching files in the dir listing */ ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */ state(conn, FTP_STOP); /* this phase is over */ } else { failf(data, "RETR response: %03d", ftpcode); return instate == FTP_RETR && ftpcode == 550? CURLE_REMOTE_FILE_NOT_FOUND: CURLE_FTP_COULDNT_RETR_FILE; } } return result; } /* after USER, PASS and ACCT */ static CURLcode ftp_state_loggedin(struct connectdata *conn) { CURLcode result = CURLE_OK; if(conn->ssl[FIRSTSOCKET].use) { /* PBSZ = PROTECTION BUFFER SIZE. The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: Specifically, the PROT command MUST be preceded by a PBSZ command and a PBSZ command MUST be preceded by a successful security data exchange (the TLS negotiation in this case) ... (and on page 8): Thus the PBSZ command must still be issued, but must have a parameter of '0' to indicate that no buffering is taking place and the data connection should not be encapsulated. */ PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0); state(conn, FTP_PBSZ); } else { result = ftp_state_pwd(conn); } return result; } /* for USER and PASS responses */ static CURLcode ftp_state_user_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; (void)instate; /* no use for this yet */ /* some need password anyway, and others just return 2xx ignored */ if((ftpcode == 331) && (ftpc->state == FTP_USER)) { /* 331 Password required for ... (the server requires to send the user's password too) */ PPSENDF(&ftpc->pp, "PASS %s", conn->passwd?conn->passwd:""); state(conn, FTP_PASS); } else if(ftpcode/100 == 2) { /* 230 User ... logged in. (the user logged in with or without password) */ result = ftp_state_loggedin(conn); } else if(ftpcode == 332) { if(data->set.str[STRING_FTP_ACCOUNT]) { PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); state(conn, FTP_ACCT); } else { failf(data, "ACCT requested but none available"); result = CURLE_LOGIN_DENIED; } } else { /* All other response codes, like: 530 User ... access denied (the server denies to log the specified user) */ if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && !conn->data->state.ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ PPSENDF(&conn->proto.ftpc.pp, "%s", conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); conn->data->state.ftp_trying_alternative = TRUE; state(conn, FTP_USER); result = CURLE_OK; } else { failf(data, "Access denied: %03d", ftpcode); result = CURLE_LOGIN_DENIED; } } return result; } /* for ACCT response */ static CURLcode ftp_state_acct_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; if(ftpcode != 230) { failf(data, "ACCT rejected by server: %03d", ftpcode); result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ } else result = ftp_state_loggedin(conn); return result; } static CURLcode ftp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; struct Curl_easy *data = conn->data; int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; static const char ftpauth[][4] = { "SSL", "TLS" }; size_t nread = 0; if(pp->sendleft) return Curl_pp_flushsend(pp); result = ftp_readresp(sock, pp, &ftpcode, &nread); if(result) return result; if(ftpcode) { /* we have now received a full FTP server response */ switch(ftpc->state) { case FTP_WAIT220: if(ftpcode == 230) /* 230 User logged in - already! */ return ftp_state_user_resp(conn, ftpcode, ftpc->state); else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); return CURLE_WEIRD_SERVER_REPLY; } /* We have received a 220 response fine, now we proceed. */ #ifdef HAVE_GSSAPI if(data->set.krb) { /* If not anonymous login, try a secure login. Note that this procedure is still BLOCKING. */ Curl_sec_request_prot(conn, "private"); /* We set private first as default, in case the line below fails to set a valid level */ Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); if(Curl_sec_login(conn)) infof(data, "Logging in with password in cleartext!\n"); else infof(data, "Authentication successful\n"); } #endif if(data->set.use_ssl && (!conn->ssl[FIRSTSOCKET].use || (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && !conn->proxy_ssl[FIRSTSOCKET].use))) { /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ ftpc->count3 = 0; switch(data->set.ftpsslauth) { case CURLFTPAUTH_DEFAULT: case CURLFTPAUTH_SSL: ftpc->count2 = 1; /* add one to get next */ ftpc->count1 = 0; break; case CURLFTPAUTH_TLS: ftpc->count2 = -1; /* subtract one to get next */ ftpc->count1 = 1; break; default: failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", (int)data->set.ftpsslauth); return CURLE_UNKNOWN_OPTION; /* we don't know what to do */ } PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); state(conn, FTP_AUTH); } else { result = ftp_state_user(conn); if(result) return result; } break; case FTP_AUTH: /* we have gotten the response to a previous AUTH command */ /* RFC2228 (page 5) says: * * If the server is willing to accept the named security mechanism, * and does not require any security data, it must respond with * reply code 234/334. */ if((ftpcode == 234) || (ftpcode == 334)) { /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(!result) { conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ result = ftp_state_user(conn); } } else if(ftpc->count3 < 1) { ftpc->count3++; ftpc->count1 += ftpc->count2; /* get next attempt */ result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); /* remain in this same state */ } else { if(data->set.use_ssl > CURLUSESSL_TRY) /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ result = CURLE_USE_SSL_FAILED; else /* ignore the failure and continue */ result = ftp_state_user(conn); } if(result) return result; break; case FTP_USER: case FTP_PASS: result = ftp_state_user_resp(conn, ftpcode, ftpc->state); break; case FTP_ACCT: result = ftp_state_acct_resp(conn, ftpcode); break; case FTP_PBSZ: PPSENDF(&ftpc->pp, "PROT %c", data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); state(conn, FTP_PROT); break; case FTP_PROT: if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ conn->bits.ftp_use_data_ssl = (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ else if(data->set.use_ssl > CURLUSESSL_CONTROL) /* we failed and bails out */ return CURLE_USE_SSL_FAILED; if(data->set.ftp_ccc) { /* CCC - Clear Command Channel */ PPSENDF(&ftpc->pp, "%s", "CCC"); state(conn, FTP_CCC); } else { result = ftp_state_pwd(conn); if(result) return result; } break; case FTP_CCC: if(ftpcode < 500) { /* First shut down the SSL layer (note: this call will block) */ result = Curl_ssl_shutdown(conn, FIRSTSOCKET); if(result) { failf(conn->data, "Failed to clear the command channel (CCC)"); return result; } } /* Then continue as normal */ result = ftp_state_pwd(conn); if(result) return result; break; case FTP_PWD: if(ftpcode == 257) { char *ptr = &data->state.buffer[4]; /* start on the first letter */ const size_t buf_size = data->set.buffer_size; char *dir; bool entry_extracted = FALSE; dir = malloc(nread + 1); if(!dir) return CURLE_OUT_OF_MEMORY; /* Reply format is like 257[rubbish]"" and the RFC959 says The directory name can contain any character; embedded double-quotes should be escaped by double-quotes (the "quote-doubling" convention). */ /* scan for the first double-quote for non-standard responses */ while(ptr < &data->state.buffer[buf_size] && *ptr != '\n' && *ptr != '\0' && *ptr != '"') ptr++; if('\"' == *ptr) { /* it started good */ char *store; ptr++; for(store = dir; *ptr;) { if('\"' == *ptr) { if('\"' == ptr[1]) { /* "quote-doubling" */ *store = ptr[1]; ptr++; } else { /* end of path */ entry_extracted = TRUE; break; /* get out of this loop */ } } else *store = *ptr; store++; ptr++; } *store = '\0'; /* zero terminate */ } if(entry_extracted) { /* If the path name does not look like an absolute path (i.e.: it does not start with a '/'), we probably need some server-dependent adjustments. For example, this is the case when connecting to an OS400 FTP server: this server supports two name syntaxes, the default one being incompatible with standard paths. In addition, this server switches automatically to the regular path syntax when one is encountered in a command: this results in having an entrypath in the wrong syntax when later used in CWD. The method used here is to check the server OS: we do it only if the path name looks strange to minimize overhead on other systems. */ if(!ftpc->server_os && dir[0] != '/') { result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); if(result) { free(dir); return result; } Curl_safefree(ftpc->entrypath); ftpc->entrypath = dir; /* remember this */ infof(data, "Entry path is '%s'\n", ftpc->entrypath); /* also save it where getinfo can access it: */ data->state.most_recent_ftp_entrypath = ftpc->entrypath; state(conn, FTP_SYST); break; } Curl_safefree(ftpc->entrypath); ftpc->entrypath = dir; /* remember this */ infof(data, "Entry path is '%s'\n", ftpc->entrypath); /* also save it where getinfo can access it: */ data->state.most_recent_ftp_entrypath = ftpc->entrypath; } else { /* couldn't get the path */ free(dir); infof(data, "Failed to figure out path\n"); } } state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE\n")); break; case FTP_SYST: if(ftpcode == 215) { char *ptr = &data->state.buffer[4]; /* start on the first letter */ char *os; char *store; os = malloc(nread + 1); if(!os) return CURLE_OUT_OF_MEMORY; /* Reply format is like 215 */ while(*ptr == ' ') ptr++; for(store = os; *ptr && *ptr != ' ';) *store++ = *ptr++; *store = '\0'; /* zero terminate */ /* Check for special servers here. */ if(strcasecompare(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); if(result) { free(os); return result; } /* remember target server OS */ Curl_safefree(ftpc->server_os); ftpc->server_os = os; state(conn, FTP_NAMEFMT); break; } /* Nothing special for the target server. */ /* remember target server OS */ Curl_safefree(ftpc->server_os); ftpc->server_os = os; } else { /* Cannot identify server OS. Continue anyway and cross fingers. */ } state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE\n")); break; case FTP_NAMEFMT: if(ftpcode == 250) { /* Name format change successful: reload initial path. */ ftp_state_pwd(conn); break; } state(conn, FTP_STOP); /* we are done with the CONNECT phase! */ DEBUGF(infof(data, "protocol connect phase DONE\n")); break; case FTP_QUOTE: case FTP_POSTQUOTE: case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: if((ftpcode >= 400) && !ftpc->count2) { /* failure response code, and not allowed to fail */ failf(conn->data, "QUOT command failed with %03d", ftpcode); return CURLE_QUOTE_ERROR; } result = ftp_state_quote(conn, FALSE, ftpc->state); if(result) return result; break; case FTP_CWD: if(ftpcode/100 != 2) { /* failure to CWD there */ if(conn->data->set.ftp_create_missing_dirs && ftpc->cwdcount && !ftpc->count2) { /* try making it */ ftpc->count2++; /* counter to prevent CWD-MKD loops */ PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]); state(conn, FTP_MKD); } else { /* return failure */ failf(data, "Server denied you to change to the given directory"); ftpc->cwdfail = TRUE; /* don't remember this path as we failed to enter it */ return CURLE_REMOTE_ACCESS_DENIED; } } else { /* success */ ftpc->count2 = 0; if(++ftpc->cwdcount <= ftpc->dirdepth) { /* send next CWD */ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); } else { result = ftp_state_mdtm(conn); if(result) return result; } } break; case FTP_MKD: if((ftpcode/100 != 2) && !ftpc->count3--) { /* failure to MKD the dir */ failf(data, "Failed to MKD dir: %03d", ftpcode); return CURLE_REMOTE_ACCESS_DENIED; } state(conn, FTP_CWD); /* send CWD */ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]); break; case FTP_MDTM: result = ftp_state_mdtm_resp(conn, ftpcode); break; case FTP_TYPE: case FTP_LIST_TYPE: case FTP_RETR_TYPE: case FTP_STOR_TYPE: result = ftp_state_type_resp(conn, ftpcode, ftpc->state); break; case FTP_SIZE: case FTP_RETR_SIZE: case FTP_STOR_SIZE: result = ftp_state_size_resp(conn, ftpcode, ftpc->state); break; case FTP_REST: case FTP_RETR_REST: result = ftp_state_rest_resp(conn, ftpcode, ftpc->state); break; case FTP_PRET: if(ftpcode != 200) { /* there only is this one standard OK return code. */ failf(data, "PRET command not accepted: %03d", ftpcode); return CURLE_FTP_PRET_FAILED; } result = ftp_state_use_pasv(conn); break; case FTP_PASV: result = ftp_state_pasv_resp(conn, ftpcode); break; case FTP_PORT: result = ftp_state_port_resp(conn, ftpcode); break; case FTP_LIST: case FTP_RETR: result = ftp_state_get_resp(conn, ftpcode, ftpc->state); break; case FTP_STOR: result = ftp_state_stor_resp(conn, ftpcode, ftpc->state); break; case FTP_QUIT: /* fallthrough, just stop! */ default: /* internal error */ state(conn, FTP_STOP); break; } } /* if(ftpcode) */ return result; } /* called repeatedly until done from multi.c */ static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done) { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE, FALSE); /* Check for the state outside of the Curl_socket_check() return code checks since at times we are in fact already in this state when this function gets called. */ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; return result; } static CURLcode ftp_block_statemach(struct connectdata *conn) { struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; CURLcode result = CURLE_OK; while(ftpc->state != FTP_STOP) { result = Curl_pp_statemach(pp, TRUE, TRUE /* disconnecting */); if(result) break; } return result; } /* * ftp_connect() should do everything that is to be considered a part of * the connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect * phase is done when this function returns, or FALSE if not. * */ static CURLcode ftp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; *done = FALSE; /* default to not done yet */ /* We always support persistent connections on ftp */ connkeep(conn, "FTP default"); pp->response_time = RESP_TIMEOUT; /* set default response time-out */ pp->statemach_act = ftp_statemach_act; pp->endofresp = ftp_endofresp; pp->conn = conn; if(conn->handler->flags & PROTOPT_SSL) { /* BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(result) return result; } Curl_pp_init(pp); /* init the generic pingpong data */ /* When we connect, we start in the state where we await the 220 response */ state(conn, FTP_WAIT220); result = ftp_multi_statemach(conn, done); return result; } /*********************************************************************** * * ftp_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, bool premature) { struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; ssize_t nread; int ftpcode; CURLcode result = CURLE_OK; char *rawPath = NULL; size_t pathLen = 0; if(!ftp) return CURLE_OK; switch(status) { case CURLE_BAD_DOWNLOAD_RESUME: case CURLE_FTP_WEIRD_PASV_REPLY: case CURLE_FTP_PORT_FAILED: case CURLE_FTP_ACCEPT_FAILED: case CURLE_FTP_ACCEPT_TIMEOUT: case CURLE_FTP_COULDNT_SET_TYPE: case CURLE_FTP_COULDNT_RETR_FILE: case CURLE_PARTIAL_FILE: case CURLE_UPLOAD_FAILED: case CURLE_REMOTE_ACCESS_DENIED: case CURLE_FILESIZE_EXCEEDED: case CURLE_REMOTE_FILE_NOT_FOUND: case CURLE_WRITE_ERROR: /* the connection stays alive fine even though this happened */ /* fall-through */ case CURLE_OK: /* doesn't affect the control connection's status */ if(!premature) break; /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ /* FALLTHROUGH */ default: /* by default, an error means the control connection is wedged and should not be used anymore */ ftpc->ctl_valid = FALSE; ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the current path, as this connection is going */ connclose(conn, "FTP ended with bad error code"); result = status; /* use the already set error code */ break; } if(data->state.wildcardmatch) { if(data->set.chunk_end && ftpc->file) { Curl_set_in_callback(data, true); data->set.chunk_end(data->wildcard.customptr); Curl_set_in_callback(data, false); } ftpc->known_filesize = -1; } if(!result) /* get the url-decoded "raw" path */ result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE); if(result) { /* We can limp along anyway (and should try to since we may already be in * the error path) */ ftpc->ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ free(ftpc->prevpath); ftpc->prevpath = NULL; /* no path remembering */ } else { /* remember working directory for connection reuse */ if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ else { free(ftpc->prevpath); if(!ftpc->cwdfail) { if(data->set.ftp_filemethod == FTPFILE_NOCWD) pathLen = 0; /* relative path => working directory is FTP home */ else pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */ rawPath[pathLen] = '\0'; ftpc->prevpath = rawPath; } else { free(rawPath); ftpc->prevpath = NULL; /* no path */ } } if(ftpc->prevpath) infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath); } /* free the dir tree and file parts */ freedirs(ftpc); /* shut down the socket to inform the server we're done */ #ifdef _WIN32_WCE shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ #endif if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { if(!result && ftpc->dont_check && data->req.maxdownload > 0) { /* partial download completed */ result = Curl_pp_sendf(pp, "%s", "ABOR"); if(result) { failf(data, "Failure sending ABOR command: %s", curl_easy_strerror(result)); ftpc->ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "ABOR command failed"); /* connection closure */ } } if(conn->ssl[SECONDARYSOCKET].use) { /* The secondary socket is using SSL so we must close down that part first before we close the socket for real */ Curl_ssl_close(conn, SECONDARYSOCKET); /* Note that we keep "use" set to TRUE since that (next) connection is still requested to use SSL */ } close_secondarysocket(conn); } if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && pp->pending_resp && !premature) { /* * Let's see what the server says about the transfer we just performed, * but lower the timeout as sometimes this connection has died while the * data has been transferred. This happens when doing through NATs etc that * abandon old silent connections. */ long old_time = pp->response_time; pp->response_time = 60*1000; /* give it only a minute for now */ pp->response = Curl_now(); /* timeout relative now */ result = Curl_GetFTPResponse(&nread, conn, &ftpcode); pp->response_time = old_time; /* set this back to previous value */ if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { failf(data, "control connection looks dead"); ftpc->ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */ } if(result) return result; if(ftpc->dont_check && data->req.maxdownload > 0) { /* we have just sent ABOR and there is no reliable way to check if it was * successful or not; we have to close the connection now */ infof(data, "partial download completed, closing connection\n"); connclose(conn, "Partial download with no ability to check"); return result; } if(!ftpc->dont_check) { /* 226 Transfer complete, 250 Requested file action okay, completed. */ if((ftpcode != 226) && (ftpcode != 250)) { failf(data, "server did not report OK, got %d", ftpcode); result = CURLE_PARTIAL_FILE; } } } if(result || premature) /* the response code from the transfer showed an error already so no use checking further */ ; else if(data->set.upload) { if((-1 != data->state.infilesize) && (data->state.infilesize != data->req.writebytecount) && !data->set.crlf && (ftp->transfer == FTPTRANSFER_BODY)) { failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes)", data->req.bytecount, data->state.infilesize); result = CURLE_PARTIAL_FILE; } } else { if((-1 != data->req.size) && (data->req.size != data->req.bytecount) && #ifdef CURL_DO_LINEEND_CONV /* Most FTP servers don't adjust their file SIZE response for CRLFs, so * we'll check to see if the discrepancy can be explained by the number * of CRLFs we've changed to LFs. */ ((data->req.size + data->state.crlf_conversions) != data->req.bytecount) && #endif /* CURL_DO_LINEEND_CONV */ (data->req.maxdownload != data->req.bytecount)) { failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T " bytes", data->req.bytecount); result = CURLE_PARTIAL_FILE; } else if(!ftpc->dont_check && !data->req.bytecount && (data->req.size>0)) { failf(data, "No data was received!"); result = CURLE_FTP_COULDNT_RETR_FILE; } } /* clear these for next connection */ ftp->transfer = FTPTRANSFER_BODY; ftpc->dont_check = FALSE; /* Send any post-transfer QUOTE strings? */ if(!status && !result && !premature && data->set.postquote) result = ftp_sendquote(conn, data->set.postquote); Curl_safefree(ftp->pathalloc); return result; } /*********************************************************************** * * ftp_sendquote() * * Where a 'quote' means a list of custom commands to send to the server. * The quote list is passed as an argument. * * BLOCKING */ static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) { struct curl_slist *item; ssize_t nread; int ftpcode; CURLcode result; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; item = quote; while(item) { if(item->data) { char *cmd = item->data; bool acceptfail = FALSE; /* if a command starts with an asterisk, which a legal FTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command is successful, whatever the server reponds. */ if(cmd[0] == '*') { cmd++; acceptfail = TRUE; } PPSENDF(&conn->proto.ftpc.pp, "%s", cmd); pp->response = Curl_now(); /* timeout relative now */ result = Curl_GetFTPResponse(&nread, conn, &ftpcode); if(result) return result; if(!acceptfail && (ftpcode >= 400)) { failf(conn->data, "QUOT string not accepted: %s", cmd); return CURLE_QUOTE_ERROR; } } item = item->next; } return CURLE_OK; } /*********************************************************************** * * ftp_need_type() * * Returns TRUE if we in the current situation should send TYPE */ static int ftp_need_type(struct connectdata *conn, bool ascii_wanted) { return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); } /*********************************************************************** * * ftp_nb_type() * * Set TYPE. We only deal with ASCII or BINARY so this function * sets one of them. * If the transfer type is not sent, simulate on OK response in newstate */ static CURLcode ftp_nb_type(struct connectdata *conn, bool ascii, ftpstate newstate) { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; char want = (char)(ascii?'A':'I'); if(ftpc->transfertype == want) { state(conn, newstate); return ftp_state_type_resp(conn, 200, newstate); } PPSENDF(&ftpc->pp, "TYPE %c", want); state(conn, newstate); /* keep track of our current transfer type */ ftpc->transfertype = want; return CURLE_OK; } /*************************************************************************** * * ftp_pasv_verbose() * * This function only outputs some informationals about this second connection * when we've issued a PASV command before and thus we have connected to a * possibly new IP address. * */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static void ftp_pasv_verbose(struct connectdata *conn, Curl_addrinfo *ai, char *newhost, /* ascii version */ int port) { char buf[256]; Curl_printable_address(ai, buf, sizeof(buf)); infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port); } #endif /* * ftp_do_more() * * This function shall be called when the second FTP (data) connection is * connected. * * 'complete' can return 0 for incomplete, 1 for done and -1 for go back * (which basically is only for when PASV is being sent to retry a failed * EPSV). */ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) { struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; bool connected = FALSE; bool complete = FALSE; /* the ftp struct is inited in ftp_connect() */ struct FTP *ftp = data->req.protop; /* if the second connection isn't done yet, wait for it */ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { if(Curl_connect_ongoing(conn)) { /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port aren't used so we blank their arguments. */ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0); return result; } result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); /* Ready to do more? */ if(connected) { DEBUGF(infof(data, "DO-MORE connected phase starts\n")); } else { if(result && (ftpc->count1 == 0)) { *completep = -1; /* go back to DOING please */ /* this is a EPSV connect failing, try PASV instead */ return ftp_epsv_disable(conn); } return result; } } result = Curl_proxy_connect(conn, SECONDARYSOCKET); if(result) return result; if(CONNECT_SECONDARYSOCKET_PROXY_SSL()) return result; if(conn->bits.tunnel_proxy && conn->bits.httpproxy && Curl_connect_ongoing(conn)) return result; if(ftpc->state) { /* already in a state so skip the initial commands. They are only done to kickstart the do_more state */ result = ftp_multi_statemach(conn, &complete); *completep = (int)complete; /* if we got an error or if we don't wait for a data connection return immediately */ if(result || !ftpc->wait_data_conn) return result; /* if we reach the end of the FTP state machine here, *complete will be TRUE but so is ftpc->wait_data_conn, which says we need to wait for the data connection and therefore we're not actually complete */ *completep = 0; } if(ftp->transfer <= FTPTRANSFER_INFO) { /* a transfer is about to take place, or if not a file name was given so we'll do a SIZE on it later and then we need the right TYPE first */ if(ftpc->wait_data_conn == TRUE) { bool serv_conned; result = ReceivedServerConnect(conn, &serv_conned); if(result) return result; /* Failed to accept data connection */ if(serv_conned) { /* It looks data connection is established */ result = AcceptServerConnect(conn); ftpc->wait_data_conn = FALSE; if(!result) result = InitiateTransfer(conn); if(result) return result; *completep = 1; /* this state is now complete when the server has connected back to us */ } } else if(data->set.upload) { result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); if(result) return result; result = ftp_multi_statemach(conn, &complete); /* ftpc->wait_data_conn is always false here */ *completep = (int)complete; } else { /* download */ ftp->downloadsize = -1; /* unknown as of yet */ result = Curl_range(conn); if(result == CURLE_OK && data->req.maxdownload >= 0) { /* Don't check for successful transfer */ ftpc->dont_check = TRUE; } if(result) ; else if(data->set.ftp_list_only || !ftpc->file) { /* The specified path ends with a slash, and therefore we think this is a directory that is requested, use LIST. But before that we need to set ASCII transfer mode. */ /* But only if a body transfer was requested. */ if(ftp->transfer == FTPTRANSFER_BODY) { result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE); if(result) return result; } /* otherwise just fall through */ } else { result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE); if(result) return result; } result = ftp_multi_statemach(conn, &complete); *completep = (int)complete; } return result; } /* no data to transfer */ Curl_setup_transfer(data, -1, -1, FALSE, -1); if(!ftpc->wait_data_conn) { /* no waiting for the data connection so this is now complete */ *completep = 1; DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); } return result; } /*********************************************************************** * * ftp_perform() * * This is the actual DO function for FTP. Get a file/directory according to * the options previously setup. */ static CURLcode ftp_perform(struct connectdata *conn, bool *connected, /* connect status after PASV / PORT */ bool *dophase_done) { /* this is FTP and no proxy */ CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { /* requested no body means no transfer... */ struct FTP *ftp = conn->data->req.protop; ftp->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* start the first command in the DO phase */ result = ftp_state_quote(conn, TRUE, FTP_QUOTE); if(result) return result; /* run the state-machine */ result = ftp_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected); if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete1\n")); return result; } static void wc_data_dtor(void *ptr) { struct ftp_wc *ftpwc = ptr; if(ftpwc && ftpwc->parser) Curl_ftp_parselist_data_free(&ftpwc->parser); free(ftpwc); } static CURLcode init_wc_data(struct connectdata *conn) { char *last_slash; struct FTP *ftp = conn->data->req.protop; char *path = ftp->path; struct WildcardData *wildcard = &(conn->data->wildcard); CURLcode result = CURLE_OK; struct ftp_wc *ftpwc = NULL; last_slash = strrchr(ftp->path, '/'); if(last_slash) { last_slash++; if(last_slash[0] == '\0') { wildcard->state = CURLWC_CLEAN; result = ftp_parse_url_path(conn); return result; } wildcard->pattern = strdup(last_slash); if(!wildcard->pattern) return CURLE_OUT_OF_MEMORY; last_slash[0] = '\0'; /* cut file from path */ } else { /* there is only 'wildcard pattern' or nothing */ if(path[0]) { wildcard->pattern = strdup(path); if(!wildcard->pattern) return CURLE_OUT_OF_MEMORY; path[0] = '\0'; } else { /* only list */ wildcard->state = CURLWC_CLEAN; result = ftp_parse_url_path(conn); return result; } } /* program continues only if URL is not ending with slash, allocate needed resources for wildcard transfer */ /* allocate ftp protocol specific wildcard data */ ftpwc = calloc(1, sizeof(struct ftp_wc)); if(!ftpwc) { result = CURLE_OUT_OF_MEMORY; goto fail; } /* INITIALIZE parselist structure */ ftpwc->parser = Curl_ftp_parselist_data_alloc(); if(!ftpwc->parser) { result = CURLE_OUT_OF_MEMORY; goto fail; } wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */ wildcard->dtor = wc_data_dtor; /* wildcard does not support NOCWD option (assert it?) */ if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD) conn->data->set.ftp_filemethod = FTPFILE_MULTICWD; /* try to parse ftp url */ result = ftp_parse_url_path(conn); if(result) { goto fail; } wildcard->path = strdup(ftp->path); if(!wildcard->path) { result = CURLE_OUT_OF_MEMORY; goto fail; } /* backup old write_function */ ftpwc->backup.write_function = conn->data->set.fwrite_func; /* parsing write function */ conn->data->set.fwrite_func = Curl_ftp_parselist; /* backup old file descriptor */ ftpwc->backup.file_descriptor = conn->data->set.out; /* let the writefunc callback know what curl pointer is working with */ conn->data->set.out = conn; infof(conn->data, "Wildcard - Parsing started\n"); return CURLE_OK; fail: if(ftpwc) { Curl_ftp_parselist_data_free(&ftpwc->parser); free(ftpwc); } Curl_safefree(wildcard->pattern); wildcard->dtor = ZERO_NULL; wildcard->protdata = NULL; return result; } /* This is called recursively */ static CURLcode wc_statemach(struct connectdata *conn) { struct WildcardData * const wildcard = &(conn->data->wildcard); CURLcode result = CURLE_OK; switch(wildcard->state) { case CURLWC_INIT: result = init_wc_data(conn); if(wildcard->state == CURLWC_CLEAN) /* only listing! */ break; wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; break; case CURLWC_MATCHING: { /* In this state is LIST response successfully parsed, so lets restore previous WRITEFUNCTION callback and WRITEDATA pointer */ struct ftp_wc *ftpwc = wildcard->protdata; conn->data->set.fwrite_func = ftpwc->backup.write_function; conn->data->set.out = ftpwc->backup.file_descriptor; ftpwc->backup.write_function = ZERO_NULL; ftpwc->backup.file_descriptor = NULL; wildcard->state = CURLWC_DOWNLOADING; if(Curl_ftp_parselist_geterror(ftpwc->parser)) { /* error found in LIST parsing */ wildcard->state = CURLWC_CLEAN; return wc_statemach(conn); } if(wildcard->filelist.size == 0) { /* no corresponding file */ wildcard->state = CURLWC_CLEAN; return CURLE_REMOTE_FILE_NOT_FOUND; } return wc_statemach(conn); } case CURLWC_DOWNLOADING: { /* filelist has at least one file, lets get first one */ struct ftp_conn *ftpc = &conn->proto.ftpc; struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; struct FTP *ftp = conn->data->req.protop; char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); if(!tmp_path) return CURLE_OUT_OF_MEMORY; /* switch default ftp->path and tmp_path */ free(ftp->pathalloc); ftp->pathalloc = ftp->path = tmp_path; infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); if(conn->data->set.chunk_bgn) { long userresponse; Curl_set_in_callback(conn->data, true); userresponse = conn->data->set.chunk_bgn( finfo, wildcard->customptr, (int)wildcard->filelist.size); Curl_set_in_callback(conn->data, false); switch(userresponse) { case CURL_CHUNK_BGN_FUNC_SKIP: infof(conn->data, "Wildcard - \"%s\" skipped by user\n", finfo->filename); wildcard->state = CURLWC_SKIP; return wc_statemach(conn); case CURL_CHUNK_BGN_FUNC_FAIL: return CURLE_CHUNK_FAILED; } } if(finfo->filetype != CURLFILETYPE_FILE) { wildcard->state = CURLWC_SKIP; return wc_statemach(conn); } if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) ftpc->known_filesize = finfo->size; result = ftp_parse_url_path(conn); if(result) return result; /* we don't need the Curl_fileinfo of first file anymore */ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); if(wildcard->filelist.size == 0) { /* remains only one file to down. */ wildcard->state = CURLWC_CLEAN; /* after that will be ftp_do called once again and no transfer will be done because of CURLWC_CLEAN state */ return CURLE_OK; } } break; case CURLWC_SKIP: { if(conn->data->set.chunk_end) { Curl_set_in_callback(conn->data, true); conn->data->set.chunk_end(conn->data->wildcard.customptr); Curl_set_in_callback(conn->data, false); } Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); wildcard->state = (wildcard->filelist.size == 0) ? CURLWC_CLEAN : CURLWC_DOWNLOADING; return wc_statemach(conn); } case CURLWC_CLEAN: { struct ftp_wc *ftpwc = wildcard->protdata; result = CURLE_OK; if(ftpwc) result = Curl_ftp_parselist_geterror(ftpwc->parser); wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; } break; case CURLWC_DONE: case CURLWC_ERROR: case CURLWC_CLEAR: if(wildcard->dtor) wildcard->dtor(wildcard->protdata); break; } return result; } /*********************************************************************** * * ftp_do() * * This function is registered as 'curl_do' function. It decodes the path * parts etc as a wrapper to the actual DO function (ftp_perform). * * The input argument is already checked for validity. */ static CURLcode ftp_do(struct connectdata *conn, bool *done) { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; *done = FALSE; /* default to false */ ftpc->wait_data_conn = FALSE; /* default to no such wait */ if(conn->data->state.wildcardmatch) { result = wc_statemach(conn); if(conn->data->wildcard.state == CURLWC_SKIP || conn->data->wildcard.state == CURLWC_DONE) { /* do not call ftp_regular_transfer */ return CURLE_OK; } if(result) /* error, loop or skipping the file */ return result; } else { /* no wildcard FSM needed */ result = ftp_parse_url_path(conn); if(result) return result; } result = ftp_regular_transfer(conn, done); return result; } CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) { ssize_t bytes_written; #define SBUF_SIZE 1024 char s[SBUF_SIZE]; size_t write_len; char *sptr = s; CURLcode result = CURLE_OK; #ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; #endif if(!cmd) return CURLE_BAD_FUNCTION_ARGUMENT; write_len = strlen(cmd); if(!write_len || write_len > (sizeof(s) -3)) return CURLE_BAD_FUNCTION_ARGUMENT; memcpy(&s, cmd, write_len); strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ write_len += 2; bytes_written = 0; result = Curl_convert_to_network(conn->data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ if(result) return result; for(;;) { #ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, &bytes_written); #ifdef HAVE_GSSAPI DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif if(result) break; if(conn->data->set.verbose) Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written); if(bytes_written != (ssize_t)write_len) { write_len -= bytes_written; sptr += bytes_written; } else break; } return result; } /*********************************************************************** * * ftp_quit() * * This should be called before calling sclose() on an ftp control connection * (not data connections). We should then wait for the response from the * server before returning. The calling code should then try to close the * connection. * */ static CURLcode ftp_quit(struct connectdata *conn) { CURLcode result = CURLE_OK; if(conn->proto.ftpc.ctl_valid) { result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT"); if(result) { failf(conn->data, "Failure sending QUIT command: %s", curl_easy_strerror(result)); conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "QUIT command failed"); /* mark for connection closure */ state(conn, FTP_STOP); return result; } state(conn, FTP_QUIT); result = ftp_block_statemach(conn); } return result; } /*********************************************************************** * * ftp_disconnect() * * Disconnect from an FTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) { struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. ftp_quit() will check the state of ftp->ctl_valid. If it's ok it will try to send the QUIT command, otherwise it will just return. */ if(dead_connection) ftpc->ctl_valid = FALSE; /* The FTP session may or may not have been allocated/setup at this point! */ (void)ftp_quit(conn); /* ignore errors on the QUIT */ if(ftpc->entrypath) { struct Curl_easy *data = conn->data; if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { data->state.most_recent_ftp_entrypath = NULL; } free(ftpc->entrypath); ftpc->entrypath = NULL; } freedirs(ftpc); free(ftpc->prevpath); ftpc->prevpath = NULL; free(ftpc->server_os); ftpc->server_os = NULL; Curl_pp_disconnect(pp); #ifdef HAVE_GSSAPI Curl_sec_end(conn); #endif return CURLE_OK; } /*********************************************************************** * * ftp_parse_url_path() * * Parse the URL path into separate path components. * */ static CURLcode ftp_parse_url_path(struct connectdata *conn) { struct Curl_easy *data = conn->data; /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; const char *slashPos = NULL; const char *fileName = NULL; CURLcode result = CURLE_OK; char *rawPath = NULL; /* url-decoded "raw" path */ size_t pathLen = 0; ftpc->ctl_valid = FALSE; ftpc->cwdfail = FALSE; /* url-decode ftp path before further evaluation */ result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE); if(result) return result; switch(data->set.ftp_filemethod) { case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ if((pathLen > 0) && (rawPath[pathLen - 1] != '/')) fileName = rawPath; /* this is a full file path */ /* else: ftpc->file is not used anywhere other than for operations on a file. In other words, never for directory operations. So we can safely leave filename as NULL here and use it as a argument in dir/file decisions. */ break; case FTPFILE_SINGLECWD: slashPos = strrchr(rawPath, '/'); if(slashPos) { /* get path before last slash, except for / */ size_t dirlen = slashPos - rawPath; if(dirlen == 0) dirlen++; ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); if(!ftpc->dirs) { free(rawPath); return CURLE_OUT_OF_MEMORY; } ftpc->dirs[0] = calloc(1, dirlen + 1); if(!ftpc->dirs[0]) { free(rawPath); return CURLE_OUT_OF_MEMORY; } strncpy(ftpc->dirs[0], rawPath, dirlen); ftpc->dirdepth = 1; /* we consider it to be a single dir */ fileName = slashPos + 1; /* rest is file name */ } else fileName = rawPath; /* file name only (or empty) */ break; default: /* allow pretty much anything */ case FTPFILE_MULTICWD: { /* current position: begin of next path component */ const char *curPos = rawPath; int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */ const char *str = rawPath; for(; *str != 0; ++str) if (*str == '/') ++dirAlloc; if(dirAlloc > 0) { ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); if(!ftpc->dirs) { free(rawPath); return CURLE_OUT_OF_MEMORY; } /* parse the URL path into separate path components */ while((slashPos = strchr(curPos, '/')) != NULL) { size_t compLen = slashPos - curPos; /* path starts with a slash: add that as a directory */ if((compLen == 0) && (ftpc->dirdepth == 0)) ++compLen; /* we skip empty path components, like "x//y" since the FTP command CWD requires a parameter and a non-existent parameter a) doesn't work on many servers and b) has no effect on the others. */ if(compLen > 0) { char *comp = calloc(1, compLen + 1); if(!comp) { free(rawPath); return CURLE_OUT_OF_MEMORY; } strncpy(comp, curPos, compLen); ftpc->dirs[ftpc->dirdepth++] = comp; } curPos = slashPos + 1; } } DEBUGASSERT(ftpc->dirdepth <= dirAlloc); fileName = curPos; /* the rest is the file name (or empty) */ } break; } /* switch */ if(fileName && *fileName) ftpc->file = strdup(fileName); else ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL pointer */ if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { /* We need a file name when uploading. Return error! */ failf(data, "Uploading to a URL without a file name!"); free(rawPath); return CURLE_URL_MALFORMAT; } ftpc->cwddone = FALSE; /* default to not done */ if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) ftpc->cwddone = TRUE; /* skip CWD for absolute paths */ else { /* newly created FTP connections are already in entry path */ const char *oldPath = conn->bits.reuse ? ftpc->prevpath : ""; if(oldPath) { size_t n = pathLen; if(data->set.ftp_filemethod == FTPFILE_NOCWD) n = 0; /* CWD to entry for relative paths */ else n -= ftpc->file?strlen(ftpc->file):0; if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; } } } free(rawPath); return CURLE_OK; } /* call this when the DO phase has completed */ static CURLcode ftp_dophase_done(struct connectdata *conn, bool connected) { struct FTP *ftp = conn->data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; if(connected) { int completed; CURLcode result = ftp_do_more(conn, &completed); if(result) { close_secondarysocket(conn); return result; } } if(ftp->transfer != FTPTRANSFER_BODY) /* no data to transfer */ Curl_setup_transfer(conn->data, -1, -1, FALSE, -1); else if(!connected) /* since we didn't connect now, we want do_more to get called */ conn->bits.do_more = TRUE; ftpc->ctl_valid = TRUE; /* seems good */ return CURLE_OK; } /* called from multi.c while DOing */ static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done) { CURLcode result = ftp_multi_statemach(conn, dophase_done); if(result) DEBUGF(infof(conn->data, "DO phase failed\n")); else if(*dophase_done) { result = ftp_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete2\n")); } return result; } /*********************************************************************** * * ftp_regular_transfer() * * The input argument is already checked for validity. * * Performs all commands done before a regular transfer between a local and a * remote host. * * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the * ftp_done() function without finding any major problem. */ static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *dophase_done) { CURLcode result = CURLE_OK; bool connected = FALSE; struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; data->req.size = -1; /* make sure this is unknown at this point */ Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, -1); Curl_pgrsSetDownloadSize(data, -1); ftpc->ctl_valid = TRUE; /* starts good */ result = ftp_perform(conn, &connected, /* have we connected after PASV/PORT */ dophase_done); /* all commands in the DO-phase done? */ if(!result) { if(!*dophase_done) /* the DO phase has not completed yet */ return CURLE_OK; result = ftp_dophase_done(conn, connected); if(result) return result; } else freedirs(ftpc); return result; } static CURLcode ftp_setup_connection(struct connectdata *conn) { struct Curl_easy *data = conn->data; char *type; struct FTP *ftp; conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1); if(NULL == ftp) return CURLE_OUT_OF_MEMORY; ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ /* FTP URLs support an extension like ";type=" that * we'll try to get now! */ type = strstr(ftp->path, ";type="); if(!type) type = strstr(conn->host.rawalloc, ";type="); if(type) { char command; *type = 0; /* it was in the middle of the hostname */ command = Curl_raw_toupper(type[6]); conn->bits.type_set = TRUE; switch(command) { case 'A': /* ASCII mode */ data->set.prefer_ascii = TRUE; break; case 'D': /* directory mode */ data->set.ftp_list_only = TRUE; break; case 'I': /* binary mode */ default: /* switch off ASCII */ data->set.prefer_ascii = FALSE; break; } } /* get some initial data into the ftp struct */ ftp->transfer = FTPTRANSFER_BODY; ftp->downloadsize = 0; conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ return CURLE_OK; } #endif /* CURL_DISABLE_FTP */ davix-0.8.0/deps/curl/lib/strtoofft.c0000644000000000000000000001324614121063461016200 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #include "curl_setup.h" #include "strtoofft.h" /* * NOTE: * * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we * could use in case strtoll() doesn't exist... See * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html */ #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) # ifdef HAVE_STRTOLL # define strtooff strtoll # else # if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) # if defined(_SAL_VERSION) _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( _In_z_ const char *_String, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); # else _CRTIMP __int64 __cdecl _strtoi64(const char *_String, char **_EndPtr, int _Radix); # endif # define strtooff _strtoi64 # else # define PRIVATE_STRTOOFF 1 # endif # endif #else # define strtooff strtol #endif #ifdef PRIVATE_STRTOOFF /* Range tests can be used for alphanum decoding if characters are consecutive, like in ASCII. Else an array is scanned. Determine this condition now. */ #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 #define NO_RANGE_TEST static const char valchars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; #endif static int get_char(char c, int base); /** * Custom version of the strtooff function. This extracts a curl_off_t * value from the given input string and returns it. */ static curl_off_t strtooff(const char *nptr, char **endptr, int base) { char *end; int is_negative = 0; int overflow; int i; curl_off_t value = 0; curl_off_t newval; /* Skip leading whitespace. */ end = (char *)nptr; while(ISSPACE(end[0])) { end++; } /* Handle the sign, if any. */ if(end[0] == '-') { is_negative = 1; end++; } else if(end[0] == '+') { end++; } else if(end[0] == '\0') { /* We had nothing but perhaps some whitespace -- there was no number. */ if(endptr) { *endptr = end; } return 0; } /* Handle special beginnings, if present and allowed. */ if(end[0] == '0' && end[1] == 'x') { if(base == 16 || base == 0) { end += 2; base = 16; } } else if(end[0] == '0') { if(base == 8 || base == 0) { end++; base = 8; } } /* Matching strtol, if the base is 0 and it doesn't look like * the number is octal or hex, we assume it's base 10. */ if(base == 0) { base = 10; } /* Loop handling digits. */ value = 0; overflow = 0; for(i = get_char(end[0], base); i != -1; end++, i = get_char(end[0], base)) { newval = base * value + i; if(newval < value) { /* We've overflowed. */ overflow = 1; break; } else value = newval; } if(!overflow) { if(is_negative) { /* Fix the sign. */ value *= -1; } } else { if(is_negative) value = CURL_OFF_T_MIN; else value = CURL_OFF_T_MAX; errno = ERANGE; } if(endptr) *endptr = end; return value; } /** * Returns the value of c in the given base, or -1 if c cannot * be interpreted properly in that base (i.e., is out of range, * is a null, etc.). * * @param c the character to interpret according to base * @param base the base in which to interpret c * * @return the value of c in base, or -1 if c isn't in range */ static int get_char(char c, int base) { #ifndef NO_RANGE_TEST int value = -1; if(c <= '9' && c >= '0') { value = c - '0'; } else if(c <= 'Z' && c >= 'A') { value = c - 'A' + 10; } else if(c <= 'z' && c >= 'a') { value = c - 'a' + 10; } #else const char *cp; int value; cp = memchr(valchars, c, 10 + 26 + 26); if(!cp) return -1; value = cp - valchars; if(value >= 10 + 26) value -= 26; /* Lowercase. */ #endif if(value >= base) { value = -1; } return value; } #endif /* Only present if we need strtoll, but don't have it. */ /* * Parse a *positive* up to 64 bit number written in ascii. */ CURLofft curlx_strtoofft(const char *str, char **endp, int base, curl_off_t *num) { char *end; curl_off_t number; errno = 0; *num = 0; /* clear by default */ while(*str && ISSPACE(*str)) str++; if('-' == *str) { if(endp) *endp = (char *)str; /* didn't actually move */ return CURL_OFFT_INVAL; /* nothing parsed */ } number = strtooff(str, &end, base); if(endp) *endp = end; if(errno == ERANGE) /* overflow/underflow */ return CURL_OFFT_FLOW; else if(str == end) /* nothing parsed */ return CURL_OFFT_INVAL; *num = number; return CURL_OFFT_OK; } davix-0.8.0/deps/curl/lib/parsedate.h0000644000000000000000000000270314121063461016117 0ustar rootroot#ifndef HEADER_CURL_PARSEDATE_H #define HEADER_CURL_PARSEDATE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ extern const char * const Curl_wkday[7]; extern const char * const Curl_month[12]; CURLcode Curl_gmtime(time_t intime, struct tm *store); /* Curl_getdate_capped() differs from curl_getdate() in that this will return TIME_T_MAX in case the parsed time value was too big, instead of an error. */ time_t Curl_getdate_capped(const char *p); #endif /* HEADER_CURL_PARSEDATE_H */ davix-0.8.0/deps/curl/lib/pingpong.c0000644000000000000000000003637614121063461016000 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * 'pingpong' is for generic back-and-forth support functions used by FTP, * IMAP, POP3, SMTP and whatever more that likes them. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #include "sendf.h" #include "select.h" #include "progress.h" #include "speedcheck.h" #include "pingpong.h" #include "multiif.h" #include "non-ascii.h" #include "vtls/vtls.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #ifdef USE_PINGPONG /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting) { struct connectdata *conn = pp->conn; struct Curl_easy *data = conn->data; time_t timeout_ms; /* in milliseconds */ long response_time = (data->set.server_response_timeout)? data->set.server_response_timeout: pp->response_time; /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is supposed to govern the response for any given server response, not for the time from connect to the given server response. */ /* Without a requested timeout, we only wait 'response_time' seconds for the full response to arrive before we bail out */ timeout_ms = response_time - (time_t)Curl_timediff(Curl_now(), pp->response); /* spent time */ if(data->set.timeout && !disconnecting) { /* if timeout is requested, find out how much remaining time we have */ time_t timeout2_ms = data->set.timeout - /* timeout time */ (time_t)Curl_timediff(Curl_now(), conn->now); /* spent time */ /* pick the lowest number */ timeout_ms = CURLMIN(timeout_ms, timeout2_ms); } return timeout_ms; } /* * Curl_pp_statemach() */ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block, bool disconnecting) { struct connectdata *conn = pp->conn; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; time_t interval_ms; time_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting); struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; if(timeout_ms <= 0) { failf(data, "server response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } if(block) { interval_ms = 1000; /* use 1 second timeout intervals */ if(timeout_ms < interval_ms) interval_ms = timeout_ms; } else interval_ms = 0; /* immediate */ if(Curl_ssl_data_pending(conn, FIRSTSOCKET)) rc = 1; else if(Curl_pp_moredata(pp)) /* We are receiving and there is data in the cache so just read it */ rc = 1; else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET)) /* We are receiving and there is data ready in the SSL library */ rc = 1; else rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ CURL_SOCKET_BAD, pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ interval_ms); if(block) { /* if we didn't wait, we don't have to spend time on this now */ if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; else result = Curl_speedcheck(data, Curl_now()); if(result) return result; } if(rc == -1) { failf(data, "select/poll error"); result = CURLE_OUT_OF_MEMORY; } else if(rc) result = pp->statemach_act(conn); return result; } /* initialize stuff to prepare for reading a fresh new response */ void Curl_pp_init(struct pingpong *pp) { struct connectdata *conn = pp->conn; pp->nread_resp = 0; pp->linestart_resp = conn->data->state.buffer; pp->pending_resp = TRUE; pp->response = Curl_now(); /* start response time-out now! */ } /*********************************************************************** * * Curl_pp_vsendf() * * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, const char *fmt, va_list args) { ssize_t bytes_written; size_t write_len; char *fmt_crlf; char *s; CURLcode result; struct connectdata *conn = pp->conn; struct Curl_easy *data; #ifdef HAVE_GSSAPI enum protection_level data_sec; #endif DEBUGASSERT(pp->sendleft == 0); DEBUGASSERT(pp->sendsize == 0); DEBUGASSERT(pp->sendthis == NULL); if(!conn) /* can't send without a connection! */ return CURLE_SEND_ERROR; data = conn->data; fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */ if(!fmt_crlf) return CURLE_OUT_OF_MEMORY; s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */ free(fmt_crlf); if(!s) return CURLE_OUT_OF_MEMORY; bytes_written = 0; write_len = strlen(s); Curl_pp_init(pp); result = Curl_convert_to_network(data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ if(result) { free(s); return result; } #ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; #endif result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, &bytes_written); #ifdef HAVE_GSSAPI data_sec = conn->data_prot; DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif if(result) { free(s); return result; } if(conn->data->set.verbose) Curl_debug(conn->data, CURLINFO_HEADER_OUT, s, (size_t)bytes_written); if(bytes_written != (ssize_t)write_len) { /* the whole chunk was not sent, keep it around and adjust sizes */ pp->sendthis = s; pp->sendsize = write_len; pp->sendleft = write_len - bytes_written; } else { free(s); pp->sendthis = NULL; pp->sendleft = pp->sendsize = 0; pp->response = Curl_now(); } return CURLE_OK; } /*********************************************************************** * * Curl_pp_sendf() * * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, const char *fmt, ...) { CURLcode result; va_list ap; va_start(ap, fmt); result = Curl_pp_vsendf(pp, fmt, ap); va_end(ap); return result; } /* * Curl_pp_readresp() * * Reads a piece of a server response. */ CURLcode Curl_pp_readresp(curl_socket_t sockfd, struct pingpong *pp, int *code, /* return the server code if done */ size_t *size) /* size of the response */ { ssize_t perline; /* count bytes per line */ bool keepon = TRUE; ssize_t gotbytes; char *ptr; struct connectdata *conn = pp->conn; struct Curl_easy *data = conn->data; char * const buf = data->state.buffer; CURLcode result = CURLE_OK; *code = 0; /* 0 for errors or not done */ *size = 0; ptr = buf + pp->nread_resp; /* number of bytes in the current line, so far */ perline = (ssize_t)(ptr-pp->linestart_resp); while((pp->nread_resp < (size_t)data->set.buffer_size) && (keepon && !result)) { if(pp->cache) { /* we had data in the "cache", copy that instead of doing an actual * read * * pp->cache_size is cast to ssize_t here. This should be safe, because * it would have been populated with something of size int to begin * with, even though its datatype may be larger than an int. */ if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) { failf(data, "cached response data too big to handle"); return CURLE_RECV_ERROR; } memcpy(ptr, pp->cache, pp->cache_size); gotbytes = (ssize_t)pp->cache_size; free(pp->cache); /* free the cache */ pp->cache = NULL; /* clear the pointer */ pp->cache_size = 0; /* zero the size just in case */ } else { #ifdef HAVE_GSSAPI enum protection_level prot = conn->data_prot; conn->data_prot = PROT_CLEAR; #endif DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <= (buf + data->set.buffer_size + 1)); result = Curl_read(conn, sockfd, ptr, data->set.buffer_size - pp->nread_resp, &gotbytes); #ifdef HAVE_GSSAPI DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); conn->data_prot = prot; #endif if(result == CURLE_AGAIN) return CURLE_OK; /* return */ if(!result && (gotbytes > 0)) /* convert from the network encoding */ result = Curl_convert_from_network(data, ptr, gotbytes); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) /* Set outer result variable to this error. */ keepon = FALSE; } if(!keepon) ; else if(gotbytes <= 0) { keepon = FALSE; result = CURLE_RECV_ERROR; failf(data, "response reading failed"); } else { /* we got a whole chunk of data, which can be anything from one * byte to a set of lines and possible just a piece of the last * line */ ssize_t i; ssize_t clipamount = 0; bool restart = FALSE; data->req.headerbytecount += (long)gotbytes; pp->nread_resp += gotbytes; for(i = 0; i < gotbytes; ptr++, i++) { perline++; if(*ptr == '\n') { /* a newline is CRLF in pp-talk, so the CR is ignored as the line isn't really terminated until the LF comes */ /* output debug output if that is requested */ #ifdef HAVE_GSSAPI if(!conn->sec_complete) #endif if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, pp->linestart_resp, (size_t)perline); /* * We pass all response-lines to the callback function registered * for "headers". The response lines can be seen as a kind of * headers. */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, pp->linestart_resp, perline); if(result) return result; if(pp->endofresp(conn, pp->linestart_resp, perline, code)) { /* This is the end of the last line, copy the last line to the start of the buffer and zero terminate, for old times sake */ size_t n = ptr - pp->linestart_resp; memmove(buf, pp->linestart_resp, n); buf[n] = 0; /* zero terminate */ keepon = FALSE; pp->linestart_resp = ptr + 1; /* advance pointer */ i++; /* skip this before getting out */ *size = pp->nread_resp; /* size of the response */ pp->nread_resp = 0; /* restart */ break; } perline = 0; /* line starts over here */ pp->linestart_resp = ptr + 1; } } if(!keepon && (i != gotbytes)) { /* We found the end of the response lines, but we didn't parse the full chunk of data we have read from the server. We therefore need to store the rest of the data to be checked on the next invoke as it may actually contain another end of response already! */ clipamount = gotbytes - i; restart = TRUE; DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " "server response left\n", (int)clipamount)); } else if(keepon) { if((perline == gotbytes) && (gotbytes > data->set.buffer_size/2)) { /* We got an excessive line without newlines and we need to deal with it. We keep the first bytes of the line then we throw away the rest. */ infof(data, "Excessive server response line length received, " "%zd bytes. Stripping\n", gotbytes); restart = TRUE; /* we keep 40 bytes since all our pingpong protocols are only interested in the first piece */ clipamount = 40; } else if(pp->nread_resp > (size_t)data->set.buffer_size/2) { /* We got a large chunk of data and there's potentially still trailing data to take care of, so we put any such part in the "cache", clear the buffer to make space and restart. */ clipamount = perline; restart = TRUE; } } else if(i == gotbytes) restart = TRUE; if(clipamount) { pp->cache_size = clipamount; pp->cache = malloc(pp->cache_size); if(pp->cache) memcpy(pp->cache, pp->linestart_resp, pp->cache_size); else return CURLE_OUT_OF_MEMORY; } if(restart) { /* now reset a few variables to start over nicely from the start of the big buffer */ pp->nread_resp = 0; /* start over from scratch in the buffer */ ptr = pp->linestart_resp = buf; perline = 0; } } /* there was data */ } /* while there's buffer left and loop is requested */ pp->pending_resp = FALSE; return result; } int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks) { struct connectdata *conn = pp->conn; socks[0] = conn->sock[FIRSTSOCKET]; if(pp->sendleft) { /* write mode */ return GETSOCK_WRITESOCK(0); } /* read mode */ return GETSOCK_READSOCK(0); } CURLcode Curl_pp_flushsend(struct pingpong *pp) { /* we have a piece of a command still left to send */ struct connectdata *conn = pp->conn; ssize_t written; curl_socket_t sock = conn->sock[FIRSTSOCKET]; CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize - pp->sendleft, pp->sendleft, &written); if(result) return result; if(written != (ssize_t)pp->sendleft) { /* only a fraction was sent */ pp->sendleft -= written; } else { free(pp->sendthis); pp->sendthis = NULL; pp->sendleft = pp->sendsize = 0; pp->response = Curl_now(); } return CURLE_OK; } CURLcode Curl_pp_disconnect(struct pingpong *pp) { free(pp->cache); pp->cache = NULL; return CURLE_OK; } bool Curl_pp_moredata(struct pingpong *pp) { return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ? TRUE : FALSE; } #endif davix-0.8.0/deps/curl/lib/escape.h0000644000000000000000000000272714121063461015415 0ustar rootroot#ifndef HEADER_CURL_ESCAPE_H #define HEADER_CURL_ESCAPE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ bool Curl_isunreserved(unsigned char in); CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_crlf); #endif /* HEADER_CURL_ESCAPE_H */ davix-0.8.0/deps/curl/lib/http_digest.c0000644000000000000000000001202514121063461016456 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) #include "urldata.h" #include "strcase.h" #include "vauth/vauth.h" #include "http_digest.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" /* Test example headers: WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" */ CURLcode Curl_input_digest(struct connectdata *conn, bool proxy, const char *header) /* rest of the *-authenticate: header */ { struct Curl_easy *data = conn->data; /* Point to the correct struct with this */ struct digestdata *digest; if(proxy) { digest = &data->state.proxydigest; } else { digest = &data->state.digest; } if(!checkprefix("Digest", header)) return CURLE_BAD_CONTENT_ENCODING; header += strlen("Digest"); while(*header && ISSPACE(*header)) header++; return Curl_auth_decode_digest_http_message(header, digest); } CURLcode Curl_output_digest(struct connectdata *conn, bool proxy, const unsigned char *request, const unsigned char *uripath) { CURLcode result; struct Curl_easy *data = conn->data; unsigned char *path = NULL; char *tmp = NULL; char *response; size_t len; bool have_chlg; /* Point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; /* Point to the name and password for this */ const char *userp; const char *passwdp; /* Point to the correct struct with this */ struct digestdata *digest; struct auth *authp; if(proxy) { digest = &data->state.proxydigest; allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; authp = &data->state.authproxy; } else { digest = &data->state.digest; allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; authp = &data->state.authhost; } Curl_safefree(*allocuserpwd); /* not set means empty */ if(!userp) userp = ""; if(!passwdp) passwdp = ""; #if defined(USE_WINDOWS_SSPI) have_chlg = digest->input_token ? TRUE : FALSE; #else have_chlg = digest->nonce ? TRUE : FALSE; #endif if(!have_chlg) { authp->done = FALSE; return CURLE_OK; } /* So IE browsers < v7 cut off the URI part at the query part when they evaluate the MD5 and some (IIS?) servers work with them so we may need to do the Digest IE-style. Note that the different ways cause different MD5 sums to get sent. Apache servers can be set to do the Digest IE-style automatically using the BrowserMatch feature: https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie Further details on Digest implementation differences: http://www.fngtps.com/2006/09/http-authentication */ if(authp->iestyle) { tmp = strchr((char *)uripath, '?'); if(tmp) { size_t urilen = tmp - (char *)uripath; path = (unsigned char *) aprintf("%.*s", urilen, uripath); } } if(!tmp) path = (unsigned char *) strdup((char *) uripath); if(!path) return CURLE_OUT_OF_MEMORY; result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, path, digest, &response, &len); free(path); if(result) return result; *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", proxy ? "Proxy-" : "", response); free(response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; authp->done = TRUE; return CURLE_OK; } void Curl_http_auth_cleanup_digest(struct Curl_easy *data) { Curl_auth_digest_cleanup(&data->state.digest); Curl_auth_digest_cleanup(&data->state.proxydigest); } #endif davix-0.8.0/deps/curl/lib/setup-vms.h0000644000000000000000000003465714121063461016127 0ustar rootroot#ifndef HEADER_CURL_SETUP_VMS_H #define HEADER_CURL_SETUP_VMS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* */ /* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */ /* getenv(), getpwuid() and provide is_vms_shell() */ /* Also need upper case symbols for system services, and */ /* OpenSSL, and some Kerberos image */ #ifdef __DECC #pragma message save #pragma message disable dollarid #endif /* Hide the stuff we are overriding */ #define getenv decc_getenv #ifdef __DECC # if __INITIAL_POINTER_SIZE != 64 # define getpwuid decc_getpwuid # endif #endif #include char *decc$getenv(const char *__name); #include #include #include #undef getenv #undef getpwuid #define getenv vms_getenv #define getpwuid vms_getpwuid /* VAX needs these in upper case when compiling exact case */ #define sys$assign SYS$ASSIGN #define sys$dassgn SYS$DASSGN #define sys$qiow SYS$QIOW #ifdef __DECC # if __INITIAL_POINTER_SIZE # pragma __pointer_size __save # endif #endif #if __USE_LONG_GID_T # define decc_getpwuid DECC$__LONG_GID_GETPWUID #else # if __INITIAL_POINTER_SIZE # define decc_getpwuid decc$__32_getpwuid # else # define decc_getpwuid decc$getpwuid # endif #endif struct passwd * decc_getpwuid(uid_t uid); #ifdef __DECC # if __INITIAL_POINTER_SIZE == 32 /* Translate the path, but only if the path is a VMS file specification */ /* The translation is usually only needed for older versions of VMS */ static char *vms_translate_path(const char *path) { char *unix_path; char *test_str; /* See if the result is in VMS format, if not, we are done */ /* Assume that this is a PATH, not just some data */ test_str = strpbrk(path, ":[<^"); if(test_str == NULL) { return (char *)path; } unix_path = decc$translate_vms(path); if((int)unix_path <= 0) { /* We can not translate it, so return the original string */ return (char *)path; } } # else /* VMS translate path is actually not needed on the current 64 bit */ /* VMS platforms, so instead of figuring out the pointer settings */ /* Change it to a noop */ # define vms_translate_path(__path) __path # endif #endif #ifdef __DECC # if __INITIAL_POINTER_SIZE # pragma __pointer_size __restore # endif #endif static char *vms_getenv(const char *envvar) { char *result; char *vms_path; /* first use the DECC getenv() function */ result = decc$getenv(envvar); if(result == NULL) { return result; } vms_path = result; result = vms_translate_path(vms_path); /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ /* may do a malloc(2048) for each call to getenv(), so you will need */ /* to add a free(vms_path) */ /* Do not do a free() for DEC C RTL builds, which should be used for */ /* VMS 5.5-2 and later, even if using GCC */ return result; } static struct passwd vms_passwd_cache; static struct passwd * vms_getpwuid(uid_t uid) { struct passwd * my_passwd; /* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ #ifdef __DECC # if __INITIAL_POINTER_SIZE __char_ptr32 unix_path; # else char *unix_path; # endif #else char *unix_path; #endif my_passwd = decc_getpwuid(uid); if(my_passwd == NULL) { return my_passwd; } unix_path = vms_translate_path(my_passwd->pw_dir); if((long)unix_path <= 0) { /* We can not translate it, so return the original string */ return my_passwd; } /* If no changes needed just return it */ if(unix_path == my_passwd->pw_dir) { return my_passwd; } /* Need to copy the structure returned */ /* Since curl is only using pw_dir, no need to fix up */ /* the pw_shell when running under Bash */ vms_passwd_cache.pw_name = my_passwd->pw_name; vms_passwd_cache.pw_uid = my_passwd->pw_uid; vms_passwd_cache.pw_gid = my_passwd->pw_uid; vms_passwd_cache.pw_dir = unix_path; vms_passwd_cache.pw_shell = my_passwd->pw_shell; return &vms_passwd_cache; } #ifdef __DECC #pragma message restore #endif /* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */ /* VMS libraries should have universal symbols in exact and uppercase */ #define ASN1_INTEGER_get ASN1_INTEGER_GET #define ASN1_STRING_data ASN1_STRING_DATA #define ASN1_STRING_length ASN1_STRING_LENGTH #define ASN1_STRING_print ASN1_STRING_PRINT #define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8 #define ASN1_STRING_type ASN1_STRING_TYPE #define BIO_ctrl BIO_CTRL #define BIO_free BIO_FREE #define BIO_new BIO_NEW #define BIO_s_mem BIO_S_MEM #define BN_bn2bin BN_BN2BIN #define BN_num_bits BN_NUM_BITS #define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA #define CRYPTO_free CRYPTO_FREE #define CRYPTO_malloc CRYPTO_MALLOC #define CONF_modules_load_file CONF_MODULES_LOAD_FILE #ifdef __VAX # ifdef VMS_OLD_SSL /* Ancient OpenSSL on VAX/VMS missing this constant */ # define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 # undef CONF_modules_load_file static int CONF_modules_load_file(const char *filename, const char *appname, unsigned long flags) { return 1; } # endif #endif #define DES_ecb_encrypt DES_ECB_ENCRYPT #define DES_set_key DES_SET_KEY #define DES_set_odd_parity DES_SET_ODD_PARITY #define ENGINE_ctrl ENGINE_CTRL #define ENGINE_ctrl_cmd ENGINE_CTRL_CMD #define ENGINE_finish ENGINE_FINISH #define ENGINE_free ENGINE_FREE #define ENGINE_get_first ENGINE_GET_FIRST #define ENGINE_get_id ENGINE_GET_ID #define ENGINE_get_next ENGINE_GET_NEXT #define ENGINE_init ENGINE_INIT #define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES #define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY #define ENGINE_set_default ENGINE_SET_DEFAULT #define ERR_clear_error ERR_CLEAR_ERROR #define ERR_error_string ERR_ERROR_STRING #define ERR_error_string_n ERR_ERROR_STRING_N #define ERR_free_strings ERR_FREE_STRINGS #define ERR_get_error ERR_GET_ERROR #define ERR_peek_error ERR_PEEK_ERROR #define ERR_remove_state ERR_REMOVE_STATE #define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS #define EVP_PKEY_free EVP_PKEY_FREE #define EVP_cleanup EVP_CLEANUP #define GENERAL_NAMES_free GENERAL_NAMES_FREE #define i2d_X509_PUBKEY I2D_X509_PUBKEY #define MD4_Final MD4_FINAL #define MD4_Init MD4_INIT #define MD4_Update MD4_UPDATE #define MD5_Final MD5_FINAL #define MD5_Init MD5_INIT #define MD5_Update MD5_UPDATE #define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF #ifndef __VAX #define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES #endif #define PEM_read_X509 PEM_READ_X509 #define PEM_write_bio_X509 PEM_WRITE_BIO_X509 #define PKCS12_PBE_add PKCS12_PBE_ADD #define PKCS12_free PKCS12_FREE #define PKCS12_parse PKCS12_PARSE #define RAND_add RAND_ADD #define RAND_bytes RAND_BYTES #define RAND_egd RAND_EGD #define RAND_file_name RAND_FILE_NAME #define RAND_load_file RAND_LOAD_FILE #define RAND_status RAND_STATUS #define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME #define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA #define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL #define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY #define SSL_CTX_ctrl SSL_CTX_CTRL #define SSL_CTX_free SSL_CTX_FREE #define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE #define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS #define SSL_CTX_new SSL_CTX_NEW #define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST #define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD #define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB #define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK #define SSL_CTX_set_verify SSL_CTX_SET_VERIFY #define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY #define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE #define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE #define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE #define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE #define SSL_SESSION_free SSL_SESSION_FREE #define SSL_connect SSL_CONNECT #define SSL_free SSL_FREE #define SSL_get1_session SSL_GET1_SESSION #define SSL_get_certificate SSL_GET_CERTIFICATE #define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER #define SSL_get_error SSL_GET_ERROR #define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN #define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE #define SSL_get_privatekey SSL_GET_PRIVATEKEY #define SSL_get_session SSL_GET_SESSION #define SSL_get_shutdown SSL_GET_SHUTDOWN #define SSL_get_verify_result SSL_GET_VERIFY_RESULT #define SSL_library_init SSL_LIBRARY_INIT #define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS #define SSL_new SSL_NEW #define SSL_peek SSL_PEEK #define SSL_pending SSL_PENDING #define SSL_read SSL_READ #define SSL_set_connect_state SSL_SET_CONNECT_STATE #define SSL_set_fd SSL_SET_FD #define SSL_set_session SSL_SET_SESSION #define SSL_shutdown SSL_SHUTDOWN #define SSL_version SSL_VERSION #define SSL_write SSL_WRITE #define SSLeay SSLEAY #define SSLv23_client_method SSLV23_CLIENT_METHOD #define SSLv3_client_method SSLV3_CLIENT_METHOD #define TLSv1_client_method TLSV1_CLIENT_METHOD #define UI_create_method UI_CREATE_METHOD #define UI_destroy_method UI_DESTROY_METHOD #define UI_get0_user_data UI_GET0_USER_DATA #define UI_get_input_flags UI_GET_INPUT_FLAGS #define UI_get_string_type UI_GET_STRING_TYPE #define UI_create_method UI_CREATE_METHOD #define UI_destroy_method UI_DESTROY_METHOD #define UI_method_get_closer UI_METHOD_GET_CLOSER #define UI_method_get_opener UI_METHOD_GET_OPENER #define UI_method_get_reader UI_METHOD_GET_READER #define UI_method_get_writer UI_METHOD_GET_WRITER #define UI_method_set_closer UI_METHOD_SET_CLOSER #define UI_method_set_opener UI_METHOD_SET_OPENER #define UI_method_set_reader UI_METHOD_SET_READER #define UI_method_set_writer UI_METHOD_SET_WRITER #define UI_OpenSSL UI_OPENSSL #define UI_set_result UI_SET_RESULT #define X509V3_EXT_print X509V3_EXT_PRINT #define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL #define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA #define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT #define X509_LOOKUP_file X509_LOOKUP_FILE #define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA #define X509_NAME_get_entry X509_NAME_GET_ENTRY #define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID #define X509_NAME_print_ex X509_NAME_PRINT_EX #define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT #define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP #define X509_STORE_set_flags X509_STORE_SET_FLAGS #define X509_check_issued X509_CHECK_ISSUED #define X509_free X509_FREE #define X509_get_ext_d2i X509_GET_EXT_D2I #define X509_get_issuer_name X509_GET_ISSUER_NAME #define X509_get_pubkey X509_GET_PUBKEY #define X509_get_serialNumber X509_GET_SERIALNUMBER #define X509_get_subject_name X509_GET_SUBJECT_NAME #define X509_load_crl_file X509_LOAD_CRL_FILE #define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING #define d2i_PKCS12_fp D2I_PKCS12_FP #define i2t_ASN1_OBJECT I2T_ASN1_OBJECT #define sk_num SK_NUM #define sk_pop SK_POP #define sk_pop_free SK_POP_FREE #define sk_value SK_VALUE #ifdef __VAX #define OPENSSL_NO_SHA256 #endif #define SHA256_Final SHA256_FINAL #define SHA256_Init SHA256_INIT #define SHA256_Update SHA256_UPDATE #define USE_UPPERCASE_GSSAPI 1 #define gss_seal GSS_SEAL #define gss_unseal GSS_UNSEAL #define USE_UPPERCASE_KRBAPI 1 /* AI_NUMERICHOST needed for IP V6 support in Curl */ #ifdef HAVE_NETDB_H #include #ifndef AI_NUMERICHOST #ifdef ENABLE_IPV6 #undef ENABLE_IPV6 #endif #endif #endif /* VAX symbols are always in uppercase */ #ifdef __VAX #define inflate INFLATE #define inflateEnd INFLATEEND #define inflateInit2_ INFLATEINIT2_ #define inflateInit_ INFLATEINIT_ #define zlibVersion ZLIBVERSION #endif /* Older VAX OpenSSL port defines these as Macros */ /* Need to include the headers first and then redefine */ /* that way a newer port will also work if some one has one */ #ifdef __VAX # if (OPENSSL_VERSION_NUMBER < 0x00907001L) # define des_set_odd_parity DES_SET_ODD_PARITY # define des_set_key DES_SET_KEY # define des_ecb_encrypt DES_ECB_ENCRYPT # endif # include # ifndef OpenSSL_add_all_algorithms # define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS void OPENSSL_ADD_ALL_ALGORITHMS(void); # endif /* Curl defines these to lower case and VAX needs them in upper case */ /* So we need static routines */ # if (OPENSSL_VERSION_NUMBER < 0x00907001L) # undef des_set_odd_parity # undef DES_set_odd_parity # undef des_set_key # undef DES_set_key # undef des_ecb_encrypt # undef DES_ecb_encrypt static void des_set_odd_parity(des_cblock *key) { DES_SET_ODD_PARITY(key); } static int des_set_key(const_des_cblock *key, des_key_schedule schedule) { return DES_SET_KEY(key, schedule); } static void des_ecb_encrypt(const_des_cblock *input, des_cblock *output, des_key_schedule ks, int enc) { DES_ECB_ENCRYPT(input, output, ks, enc); } #endif /* Need this to stop a macro redefinition error */ #if OPENSSL_VERSION_NUMBER < 0x00907000L # ifdef X509_STORE_set_flags # undef X509_STORE_set_flags # define X509_STORE_set_flags(x,y) Curl_nop_stmt # endif #endif #endif #endif /* HEADER_CURL_SETUP_VMS_H */ davix-0.8.0/deps/curl/lib/sockaddr.h0000644000000000000000000000270014121063461015736 0ustar rootroot#ifndef HEADER_CURL_SOCKADDR_H #define HEADER_CURL_SOCKADDR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" struct Curl_sockaddr_storage { union { struct sockaddr sa; struct sockaddr_in sa_in; #ifdef ENABLE_IPV6 struct sockaddr_in6 sa_in6; #endif #ifdef HAVE_STRUCT_SOCKADDR_STORAGE struct sockaddr_storage sa_stor; #else char cbuf[256]; /* this should be big enough to fit a lot */ #endif } buffer; }; #endif /* HEADER_CURL_SOCKADDR_H */ davix-0.8.0/deps/curl/lib/multihandle.h0000644000000000000000000001355414121063461016463 0ustar rootroot#ifndef HEADER_CURL_MULTIHANDLE_H #define HEADER_CURL_MULTIHANDLE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "conncache.h" #include "psl.h" #include "socketpair.h" struct Curl_message { struct curl_llist_element list; /* the 'CURLMsg' is the part that is visible to the external user */ struct CURLMsg extmsg; }; /* NOTE: if you add a state here, add the name to the statename[] array as well! */ typedef enum { CURLM_STATE_INIT, /* 0 - start in this state */ CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */ CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization to complete and/or proxy CONNECT to finalize */ CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect phase */ CURLM_STATE_DO, /* 8 - start send off the request (part 1) */ CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */ CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */ CURLM_STATE_DO_DONE, /* 11 - done sending off request */ CURLM_STATE_PERFORM, /* 12 - transfer data */ CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */ CURLM_STATE_DONE, /* 14 - post data transfer operation */ CURLM_STATE_COMPLETED, /* 15 - operation complete */ CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */ CURLM_STATE_LAST /* 17 - not a true state, never use this */ } CURLMstate; /* we support N sockets per easy handle. Set the corresponding bit to what action we should wait for */ #define MAX_SOCKSPEREASYHANDLE 5 #define GETSOCK_READABLE (0x00ff) #define GETSOCK_WRITABLE (0xff00) #define CURLPIPE_ANY (CURLPIPE_MULTIPLEX) #if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS) #define ENABLE_WAKEUP #endif /* value for MAXIMUM CONCURRENT STREAMS upper limit */ #define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1) /* This is the struct known as CURLM on the outside */ struct Curl_multi { /* First a simple identifier to easier detect if a user mix up this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ long type; /* We have a doubly-linked circular list with easy handles */ struct Curl_easy *easyp; struct Curl_easy *easylp; /* last node */ int num_easy; /* amount of entries in the linked list above. */ int num_alive; /* amount of easy handles that are added but have not yet reached COMPLETE state */ struct curl_llist msglist; /* a list of messages from completed transfers */ struct curl_llist pending; /* Curl_easys that are in the CURLM_STATE_CONNECT_PEND state */ /* callback function and user data pointer for the *socket() API */ curl_socket_callback socket_cb; void *socket_userp; /* callback function and user data pointer for server push */ curl_push_callback push_cb; void *push_userp; /* Hostname cache */ struct curl_hash hostcache; #ifdef USE_LIBPSL /* PSL cache. */ struct PslCache psl; #endif /* timetree points to the splay-tree of time nodes to figure out expire times of all currently set timers */ struct Curl_tree *timetree; /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note the pluralis form, there can be more than one easy handle waiting on the same actual socket) */ struct curl_hash sockhash; /* Shared connection cache (bundles)*/ struct conncache conn_cache; long maxconnects; /* if >0, a fixed limit of the maximum number of entries we're allowed to grow the connection cache to */ long max_host_connections; /* if >0, a fixed limit of the maximum number of connections per host */ long max_total_connections; /* if >0, a fixed limit of the maximum number of connections in total */ /* timer callback and user data pointer for the *socket() API */ curl_multi_timer_callback timer_cb; void *timer_userp; struct curltime timer_lastcall; /* the fixed time for the timeout for the previous callback */ unsigned int max_concurrent_streams; #ifdef ENABLE_WAKEUP curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup 0 is used for read, 1 is used for write */ #endif /* multiplexing wanted */ bool multiplexing; bool recheckstate; /* see Curl_multi_connchanged */ bool in_callback; /* true while executing a callback */ bool ipv6_works; }; #endif /* HEADER_CURL_MULTIHANDLE_H */ davix-0.8.0/deps/curl/lib/nonblock.c0000644000000000000000000000510514121063461015746 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include #endif #ifdef __VMS #include #include #endif #include "nonblock.h" /* * curlx_nonblock() set the given socket to either blocking or non-blocking * mode based on the 'nonblock' boolean argument. This function is highly * portable. */ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */) { #if defined(USE_BLOCKING_SOCKETS) (void)sockfd; (void)nonblock; return 0; /* returns success */ #elif defined(HAVE_FCNTL_O_NONBLOCK) /* most recent unix versions */ int flags; flags = sfcntl(sockfd, F_GETFL, 0); if(nonblock) return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK); return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); #elif defined(HAVE_IOCTL_FIONBIO) /* older unix versions */ int flags = nonblock ? 1 : 0; return ioctl(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_FIONBIO) /* Windows */ unsigned long flags = nonblock ? 1UL : 0UL; return ioctlsocket(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) /* Amiga */ long flags = nonblock ? 1L : 0L; return IoctlSocket(sockfd, FIONBIO, (char *)&flags); #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) /* BeOS */ long b = nonblock ? 1L : 0L; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); #else # error "no non-blocking method was found/used/set" #endif } davix-0.8.0/deps/curl/lib/hostcheck.h0000644000000000000000000000240314121063461016117 0ustar rootroot#ifndef HEADER_CURL_HOSTCHECK_H #define HEADER_CURL_HOSTCHECK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #define CURL_HOST_NOMATCH 0 #define CURL_HOST_MATCH 1 int Curl_cert_hostcheck(const char *match_pattern, const char *hostname); #endif /* HEADER_CURL_HOSTCHECK_H */ davix-0.8.0/deps/curl/lib/sha256.c0000644000000000000000000002767114121063461015165 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 2017, Florin Petriuc, * Copyright (C) 2018 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_CRYPTO_AUTH #include "warnless.h" #include "curl_sha256.h" #if defined(USE_OPENSSL) #include #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) #define USE_OPENSSL_SHA256 #endif #endif /* USE_OPENSSL */ #ifdef USE_MBEDTLS #include #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) #define HAS_RESULT_CODE_BASED_FUNCTIONS #endif #endif /* USE_MBEDTLS */ /* Please keep the SSL backend-specific #if branches in this order: * * 1. USE_OPENSSL * 2. USE_GNUTLS_NETTLE * 3. USE_GNUTLS * 4. USE_MBEDTLS * 5. USE_COMMON_CRYPTO * 6. USE_WIN32_CRYPTO * * This ensures that the same SSL branch gets activated throughout this source * file even if multiple backends are enabled at the same time. */ #if defined(USE_OPENSSL_SHA256) /* When OpenSSL is available we use the SHA256-function from OpenSSL */ #include #elif defined(USE_GNUTLS_NETTLE) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef struct sha256_ctx SHA256_CTX; static void SHA256_Init(SHA256_CTX *ctx) { sha256_init(ctx); } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *data, unsigned int length) { sha256_update(ctx, length, data); } static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) { sha256_digest(ctx, SHA256_DIGEST_SIZE, digest); } #elif defined(USE_GNUTLS) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef gcry_md_hd_t SHA256_CTX; static void SHA256_Init(SHA256_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_SHA256, 0); } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *data, unsigned int length) { gcry_md_write(*ctx, data, length); } static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), SHA256_DIGEST_LENGTH); gcry_md_close(*ctx); } #elif defined(USE_MBEDTLS) #include #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" typedef mbedtls_sha256_context SHA256_CTX; static void SHA256_Init(SHA256_CTX *ctx) { #if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_sha256_starts(ctx, 0); #else (void) mbedtls_sha256_starts_ret(ctx, 0); #endif } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *data, unsigned int length) { #if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_sha256_update(ctx, data, length); #else (void) mbedtls_sha256_update_ret(ctx, data, length); #endif } static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) { #if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_sha256_finish(ctx, digest); #else (void) mbedtls_sha256_finish_ret(ctx, digest); #endif } #else /* When no other crypto library is available we use this code segment */ /* This is based on SHA256 implementation in LibTomCrypt that was released into * public domain by Tom St Denis. */ #define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \ (((unsigned long)(a)[1]) << 16) | \ (((unsigned long)(a)[2]) << 8) | \ ((unsigned long)(a)[3])) #define WPA_PUT_BE32(a, val) \ do { \ (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \ (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \ (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff); \ (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff); \ } while(0) #ifdef HAVE_LONGLONG #define WPA_PUT_BE64(a, val) \ do { \ (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56); \ (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48); \ (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40); \ (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32); \ (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24); \ (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16); \ (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8); \ (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \ } while(0) #else #define WPA_PUT_BE64(a, val) \ do { \ (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56); \ (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48); \ (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40); \ (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32); \ (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24); \ (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16); \ (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8); \ (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \ } while(0) #endif typedef struct sha256_state { #ifdef HAVE_LONGLONG unsigned long long length; #else unsigned __int64 length; #endif unsigned long state[8], curlen; unsigned char buf[64]; } SHA256_CTX; /* The K array */ static const unsigned long K[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Various logical functions */ #define RORc(x, y) \ (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) RORc((x), (n)) #define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) /* Compress 512-bits */ static int sha256_compress(struct sha256_state *md, unsigned char *buf) { unsigned long S[8], W[64]; int i; /* Copy state into S */ for(i = 0; i < 8; i++) { S[i] = md->state[i]; } /* copy the state into 512-bits into W[0..15] */ for(i = 0; i < 16; i++) W[i] = WPA_GET_BE32(buf + (4 * i)); /* fill W[16..63] */ for(i = 16; i < 64; i++) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ unsigned long t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; for(i = 0; i < 64; ++i) { unsigned long t; RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; } /* Feedback */ for(i = 0; i < 8; i++) { md->state[i] = md->state[i] + S[i]; } return 0; } /* Initialize the hash state */ static void SHA256_Init(struct sha256_state *md) { md->curlen = 0; md->length = 0; md->state[0] = 0x6A09E667UL; md->state[1] = 0xBB67AE85UL; md->state[2] = 0x3C6EF372UL; md->state[3] = 0xA54FF53AUL; md->state[4] = 0x510E527FUL; md->state[5] = 0x9B05688CUL; md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; } /* Process a block of memory though the hash @param md The hash state @param in The data to hash @param inlen The length of the data (octets) @return CRYPT_OK if successful */ static int SHA256_Update(struct sha256_state *md, const unsigned char *in, unsigned long inlen) { unsigned long n; #define block_size 64 if(md->curlen > sizeof(md->buf)) return -1; while(inlen > 0) { if(md->curlen == 0 && inlen >= block_size) { if(sha256_compress(md, (unsigned char *)in) < 0) return -1; md->length += block_size * 8; in += block_size; inlen -= block_size; } else { n = CURLMIN(inlen, (block_size - md->curlen)); memcpy(md->buf + md->curlen, in, n); md->curlen += n; in += n; inlen -= n; if(md->curlen == block_size) { if(sha256_compress(md, md->buf) < 0) return -1; md->length += 8 * block_size; md->curlen = 0; } } } return 0; } /* Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) @return CRYPT_OK if successful */ static int SHA256_Final(unsigned char *out, struct sha256_state *md) { int i; if(md->curlen >= sizeof(md->buf)) return -1; /* Increase the length of the message */ md->length += md->curlen * 8; /* Append the '1' bit */ md->buf[md->curlen++] = (unsigned char)0x80; /* If the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if(md->curlen > 56) { while(md->curlen < 64) { md->buf[md->curlen++] = (unsigned char)0; } sha256_compress(md, md->buf); md->curlen = 0; } /* Pad up to 56 bytes of zeroes */ while(md->curlen < 56) { md->buf[md->curlen++] = (unsigned char)0; } /* Store length */ WPA_PUT_BE64(md->buf + 56, md->length); sha256_compress(md, md->buf); /* Copy output */ for(i = 0; i < 8; i++) WPA_PUT_BE32(out + (4 * i), md->state[i]); return 0; } #endif /* CRYPTO LIBS */ /* * Curl_sha256it() * * Generates a SHA256 hash for the given input data. * * Parameters: * * output [in/out] - The output buffer. * input [in] - The input data. * length [in] - The input length. */ void Curl_sha256it(unsigned char *output, const unsigned char *input, const size_t length) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, input, curlx_uztoui(length)); SHA256_Final(output, &ctx); } #endif /* CURL_DISABLE_CRYPTO_AUTH */ davix-0.8.0/deps/curl/lib/checksrc.pl0000755000000000000000000006051214121063461016125 0ustar rootroot#!/usr/bin/env perl #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2011 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### use strict; use warnings; my $max_column = 79; my $indent = 2; my $warnings = 0; my $swarnings = 0; my $errors = 0; my $serrors = 0; my $suppressed; # whitelisted problems my $file; my $dir="."; my $wlist=""; my @alist; my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin'; my $verbose; my %whitelist; my %ignore; my %ignore_set; my %ignore_used; my @ignore_line; my %warnings_extended = ( 'COPYRIGHTYEAR' => 'copyright year incorrect', ); my %warnings = ( 'LONGLINE' => "Line longer than $max_column", 'TABS' => 'TAB characters not allowed', 'TRAILINGSPACE' => 'Trailing white space on the line', 'CPPCOMMENTS' => '// comment detected', 'SPACEBEFOREPAREN' => 'space before an open parenthesis', 'SPACEAFTERPAREN' => 'space after open parenthesis', 'SPACEBEFORECLOSE' => 'space before a close parenthesis', 'SPACEBEFORECOMMA' => 'space before a comma', 'RETURNNOSPACE' => 'return without space', 'COMMANOSPACE' => 'comma without following space', 'BRACEELSE' => '} else on the same line', 'PARENBRACE' => '){ without sufficient space', 'SPACESEMICOLON' => 'space before semicolon', 'BANNEDFUNC' => 'a banned function was used', 'FOPENMODE' => 'fopen needs a macro for the mode string', 'BRACEPOS' => 'wrong position for an open brace', 'INDENTATION' => 'wrong start column for code', 'COPYRIGHT' => 'file missing a copyright statement', 'BADCOMMAND' => 'bad !checksrc! instruction', 'UNUSEDIGNORE' => 'a warning ignore was not used', 'OPENCOMMENT' => 'file ended with a /* comment still "open"', 'ASTERISKSPACE' => 'pointer declared with space after asterisk', 'ASTERISKNOSPACE' => 'pointer declared without space before asterisk', 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression', 'EQUALSNOSPACE' => 'equals sign without following space', 'NOSPACEEQUALS' => 'equals sign without preceding space', 'SEMINOSPACE' => 'semicolon without following space', 'MULTISPACE' => 'multiple spaces used when not suitable', 'SIZEOFNOPAREN' => 'use of sizeof without parentheses', 'SNPRINTF' => 'use of snprintf', ); sub readwhitelist { open(W, "<$dir/checksrc.whitelist") or return; my @all=; for(@all) { $windows_os ? $_ =~ s/\r?\n$// : chomp; $whitelist{$_}=1; } close(W); } # Reads the .checksrc in $dir for any extended warnings to enable locally. # Currently there is no support for disabling warnings from the standard set, # and since that's already handled via !checksrc! commands there is probably # little use to add it. sub readlocalfile { my $i = 0; open(my $rcfile, "<", "$dir/.checksrc") or return; while(<$rcfile>) { $i++; # Lines starting with '#' are considered comments if (/^\s*(#.*)/) { next; } elsif (/^\s*enable ([A-Z]+)$/) { if(!defined($warnings_extended{$1})) { print STDERR "invalid warning specified in .checksrc: \"$1\"\n"; next; } $warnings{$1} = $warnings_extended{$1}; } else { die "Invalid format in $dir/.checksrc on line $i\n"; } } } sub checkwarn { my ($name, $num, $col, $file, $line, $msg, $error) = @_; my $w=$error?"error":"warning"; my $nowarn=0; #if(!$warnings{$name}) { # print STDERR "Dev! there's no description for $name!\n"; #} # checksrc.whitelist if($whitelist{$line}) { $nowarn = 1; } # !checksrc! controlled elsif($ignore{$name}) { $ignore{$name}--; $ignore_used{$name}++; $nowarn = 1; if(!$ignore{$name}) { # reached zero, enable again enable_warn($name, $num, $file, $line); } } if($nowarn) { $suppressed++; if($w) { $swarnings++; } else { $serrors++; } return; } if($w) { $warnings++; } else { $errors++; } $col++; print "$file:$num:$col: $w: $msg ($name)\n"; print " $line\n"; if($col < 80) { my $pref = (' ' x $col); print "${pref}^\n"; } } $file = shift @ARGV; while(defined $file) { if($file =~ /-D(.*)/) { $dir = $1; $file = shift @ARGV; next; } elsif($file =~ /-W(.*)/) { $wlist .= " $1 "; $file = shift @ARGV; next; } elsif($file =~ /-A(.+)/) { push @alist, $1; $file = shift @ARGV; next; } elsif($file =~ /-i([1-9])/) { $indent = $1 + 0; $file = shift @ARGV; next; } elsif($file =~ /-m([0-9]+)/) { $max_column = $1 + 0; $file = shift @ARGV; next; } elsif($file =~ /^(-h|--help)/) { undef $file; last; } last; } if(!$file) { print "checksrc.pl [option] [file2] ...\n"; print " Options:\n"; print " -A[rule] Accept this violation, can be used multiple times\n"; print " -D[DIR] Directory to prepend file names\n"; print " -h Show help output\n"; print " -W[file] Whitelist the given file - ignore all its flaws\n"; print " -i Indent spaces. Default: 2\n"; print " -m Maximum line length. Default: 79\n"; print "\nDetects and warns for these problems:\n"; for(sort keys %warnings) { printf (" %-18s: %s\n", $_, $warnings{$_}); } exit; } readwhitelist(); readlocalfile(); do { if("$wlist" !~ / $file /) { my $fullname = $file; $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/'); scanfile($fullname); } $file = shift @ARGV; } while($file); sub accept_violations { for my $r (@alist) { if(!$warnings{$r}) { print "'$r' is not a warning to accept!\n"; exit; } $ignore{$r}=999999; $ignore_used{$r}=0; } } sub checksrc_clear { undef %ignore; undef %ignore_set; undef @ignore_line; } sub checksrc_endoffile { my ($file) = @_; for(keys %ignore_set) { if($ignore_set{$_} && !$ignore_used{$_}) { checkwarn("UNUSEDIGNORE", $ignore_set{$_}, length($_)+11, $file, $ignore_line[$ignore_set{$_}], "Unused ignore: $_"); } } } sub enable_warn { my ($what, $line, $file, $l) = @_; # switch it back on, but warn if not triggered! if(!$ignore_used{$what}) { checkwarn("UNUSEDIGNORE", $line, length($what) + 11, $file, $l, "No warning was inhibited!"); } $ignore_set{$what}=0; $ignore_used{$what}=0; $ignore{$what}=0; } sub checksrc { my ($cmd, $line, $file, $l) = @_; if($cmd =~ / *([^ ]*) *(.*)/) { my ($enable, $what) = ($1, $2); $what =~ s: *\*/$::; # cut off end of C comment # print "ENABLE $enable WHAT $what\n"; if($enable eq "disable") { my ($warn, $scope)=($1, $2); if($what =~ /([^ ]*) +(.*)/) { ($warn, $scope)=($1, $2); } else { $warn = $what; $scope = 1; } # print "IGNORE $warn for SCOPE $scope\n"; if($scope eq "all") { $scope=999999; } # Comparing for a literal zero rather than the scalar value zero # covers the case where $scope contains the ending '*' from the # comment. If we use a scalar comparison (==) we induce warnings # on non-scalar contents. if($scope eq "0") { checkwarn("BADCOMMAND", $line, 0, $file, $l, "Disable zero not supported, did you mean to enable?"); } elsif($ignore_set{$warn}) { checkwarn("BADCOMMAND", $line, 0, $file, $l, "$warn already disabled from line $ignore_set{$warn}"); } else { $ignore{$warn}=$scope; $ignore_set{$warn}=$line; $ignore_line[$line]=$l; } } elsif($enable eq "enable") { enable_warn($what, $line, $file, $l); } else { checkwarn("BADCOMMAND", $line, 0, $file, $l, "Illegal !checksrc! command"); } } } sub nostrings { my ($str) = @_; $str =~ s/\".*\"//g; return $str; } sub scanfile { my ($file) = @_; my $line = 1; my $prevl=""; my $l; open(R, "<$file") || die "failed to open $file"; my $incomment=0; my @copyright=(); checksrc_clear(); # for file based ignores accept_violations(); while() { $windows_os ? $_ =~ s/\r?\n$// : chomp; my $l = $_; my $ol = $l; # keep the unmodified line for error reporting my $column = 0; # check for !checksrc! commands if($l =~ /\!checksrc\! (.*)/) { my $cmd = $1; checksrc($cmd, $line, $file, $l) } # check for a copyright statement and save the years if($l =~ /\* +copyright .* \d\d\d\d/i) { while($l =~ /([\d]{4})/g) { push @copyright, { year => $1, line => $line, col => index($l, $1), code => $l }; } } # detect long lines if(length($l) > $max_column) { checkwarn("LONGLINE", $line, length($l), $file, $l, "Longer than $max_column columns"); } # detect TAB characters if($l =~ /^(.*)\t/) { checkwarn("TABS", $line, length($1), $file, $l, "Contains TAB character", 1); } # detect trailing white space if($l =~ /^(.*)[ \t]+\z/) { checkwarn("TRAILINGSPACE", $line, length($1), $file, $l, "Trailing whitespace"); } # ------------------------------------------------------------ # Above this marker, the checks were done on lines *including* # comments # ------------------------------------------------------------ # strip off C89 comments comment: if(!$incomment) { if($l =~ s/\/\*.*\*\// /g) { # full /* comments */ were removed! } if($l =~ s/\/\*.*//) { # start of /* comment was removed $incomment = 1; } } else { if($l =~ s/.*\*\///) { # end of comment */ was removed $incomment = 0; goto comment; } else { # still within a comment $l=""; } } # ------------------------------------------------------------ # Below this marker, the checks were done on lines *without* # comments # ------------------------------------------------------------ # crude attempt to detect // comments without too many false # positives if($l =~ /^([^"\*]*)[^:"]\/\//) { checkwarn("CPPCOMMENTS", $line, length($1), $file, $l, "\/\/ comment"); } my $nostr = nostrings($l); # check spaces after for/if/while/function call if($nostr =~ /^(.*)(for|if|while| ([a-zA-Z0-9_]+)) \((.)/) { if($1 =~ / *\#/) { # this is a #if, treat it differently } elsif(defined $3 && $3 eq "return") { # return must have a space } elsif(defined $3 && $3 eq "case") { # case must have a space } elsif($4 eq "*") { # (* beginning makes the space OK! } elsif($1 =~ / *typedef/) { # typedefs can use space-paren } else { checkwarn("SPACEBEFOREPAREN", $line, length($1)+length($2), $file, $l, "$2 with space"); } } if($nostr =~ /^((.*)(if) *\()(.*)\)/) { my $pos = length($1); if($4 =~ / = /) { checkwarn("ASSIGNWITHINCONDITION", $line, $pos+1, $file, $l, "assignment within conditional expression"); } } # check spaces after open parentheses if($l =~ /^(.*[a-z])\( /i) { checkwarn("SPACEAFTERPAREN", $line, length($1)+1, $file, $l, "space after open parenthesis"); } # check spaces before close parentheses, unless it was a space or a # close parenthesis! if($l =~ /(.*[^\) ]) \)/) { checkwarn("SPACEBEFORECLOSE", $line, length($1)+1, $file, $l, "space before close parenthesis"); } # check spaces before comma! if($l =~ /(.*[^ ]) ,/) { checkwarn("SPACEBEFORECOMMA", $line, length($1)+1, $file, $l, "space before comma"); } # check for "return(" without space if($l =~ /^(.*)return\(/) { if($1 =~ / *\#/) { # this is a #if, treat it differently } else { checkwarn("RETURNNOSPACE", $line, length($1)+6, $file, $l, "return without space before paren"); } } # check for "sizeof" without parenthesis if(($l =~ /^(.*)sizeof *([ (])/) && ($2 ne "(")) { if($1 =~ / *\#/) { # this is a #if, treat it differently } else { checkwarn("SIZEOFNOPAREN", $line, length($1)+6, $file, $l, "sizeof without parenthesis"); } } # check for comma without space if($l =~ /^(.*),[^ \n]/) { my $pref=$1; my $ign=0; if($pref =~ / *\#/) { # this is a #if, treat it differently $ign=1; } elsif($pref =~ /\/\*/) { # this is a comment $ign=1; } elsif($pref =~ /[\"\']/) { $ign = 1; # There is a quote here, figure out whether the comma is # within a string or '' or not. if($pref =~ /\"/) { # within a string } elsif($pref =~ /\'$/) { # a single letter } else { $ign = 0; } } if(!$ign) { checkwarn("COMMANOSPACE", $line, length($pref)+1, $file, $l, "comma without following space"); } } # check for "} else" if($l =~ /^(.*)\} *else/) { checkwarn("BRACEELSE", $line, length($1), $file, $l, "else after closing brace on same line"); } # check for "){" if($l =~ /^(.*)\)\{/) { checkwarn("PARENBRACE", $line, length($1)+1, $file, $l, "missing space after close paren"); } # check for space before the semicolon last in a line if($l =~ /^(.*[^ ].*) ;$/) { checkwarn("SPACESEMICOLON", $line, length($1), $file, $ol, "space before last semicolon"); } # scan for use of banned functions if($l =~ /^(.*\W) (gets| strtok| v?sprintf| (str|_mbs|_tcs|_wcs)n?cat| LoadLibrary(Ex)?(A|W)?) \s*\( /x) { checkwarn("BANNEDFUNC", $line, length($1), $file, $ol, "use of $2 is banned"); } # scan for use of snprintf for curl-internals reasons if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) { checkwarn("SNPRINTF", $line, length($1), $file, $ol, "use of $2 is banned"); } # scan for use of non-binary fopen without the macro if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { my $mode = $2; if($mode !~ /b/) { checkwarn("FOPENMODE", $line, length($1), $file, $ol, "use of non-binary fopen without FOPEN_* macro: $mode"); } } # check for open brace first on line but not first column # only alert if previous line ended with a close paren and wasn't a cpp # line if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) { checkwarn("BRACEPOS", $line, length($1), $file, $ol, "badly placed open brace"); } # if the previous line starts with if/while/for AND ends with an open # brace, or an else statement, check that this line is indented $indent # more steps, if not a cpp line if($prevl =~ /^( *)((if|while|for)\(.*\{|else)\z/) { my $first = length($1); # this line has some character besides spaces if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) { my $second = length($1); my $expect = $first+$indent; if($expect != $second) { my $diff = $second - $first; checkwarn("INDENTATION", $line, length($1), $file, $ol, "not indented $indent steps (uses $diff)"); } } } # check for 'char * name' if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost) *(\*+)) (\w+)/) && ($4 ne "const")) { checkwarn("ASTERISKNOSPACE", $line, length($1), $file, $ol, "no space after declarative asterisk"); } # check for 'char*' if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) { checkwarn("ASTERISKNOSPACE", $line, length($1)-1, $file, $ol, "no space before asterisk"); } # check for 'void func() {', but avoid false positives by requiring # both an open and closed parentheses before the open brace if($l =~ /^((\w).*)\{\z/) { my $k = $1; $k =~ s/const *//; $k =~ s/static *//; if($k =~ /\(.*\)/) { checkwarn("BRACEPOS", $line, length($l)-1, $file, $ol, "wrongly placed open brace"); } } # check for equals sign without spaces next to it if($nostr =~ /(.*)\=[a-z0-9]/i) { checkwarn("EQUALSNOSPACE", $line, length($1)+1, $file, $ol, "no space after equals sign"); } # check for equals sign without spaces before it elsif($nostr =~ /(.*)[a-z0-9]\=/i) { checkwarn("NOSPACEEQUALS", $line, length($1)+1, $file, $ol, "no space before equals sign"); } # check for plus signs without spaces next to it if($nostr =~ /(.*)[^+]\+[a-z0-9]/i) { checkwarn("PLUSNOSPACE", $line, length($1)+1, $file, $ol, "no space after plus sign"); } # check for plus sign without spaces before it elsif($nostr =~ /(.*)[a-z0-9]\+[^+]/i) { checkwarn("NOSPACEPLUS", $line, length($1)+1, $file, $ol, "no space before plus sign"); } # check for semicolons without space next to it if($nostr =~ /(.*)\;[a-z0-9]/i) { checkwarn("SEMINOSPACE", $line, length($1)+1, $file, $ol, "no space after semicolon"); } # check for more than one consecutive space before open brace or # question mark. Skip lines containing strings since they make it hard # due to artificially getting multiple spaces if(($l eq $nostr) && $nostr =~ /^(.*(\S)) + [{?]/i) { checkwarn("MULTISPACE", $line, length($1)+1, $file, $ol, "multiple space"); print STDERR "L: $l\n"; print STDERR "nostr: $nostr\n"; } $line++; $prevl = $ol; } if(!scalar(@copyright)) { checkwarn("COPYRIGHT", 1, 0, $file, "", "Missing copyright statement", 1); } # COPYRIGHTYEAR is a extended warning so we must first see if it has been # enabled in .checksrc if(defined($warnings{"COPYRIGHTYEAR"})) { # The check for updated copyrightyear is overly complicated in order to # not punish current hacking for past sins. The copyright years are # right now a bit behind, so enforcing copyright year checking on all # files would cause hundreds of errors. Instead we only look at files # which are tracked in the Git repo and edited in the workdir, or # committed locally on the branch without being in upstream master. # # The simple and naive test is to simply check for the current year, # but updating the year even without an edit is against project policy # (and it would fail every file on January 1st). # # A rather more interesting, and correct, check would be to not test # only locally committed files but inspect all files wrt the year of # their last commit. Removing the `git rev-list origin/master..HEAD` # condition below will enfore copyright year checks against the year # the file was last committed (and thus edited to some degree). my $commityear = undef; @copyright = sort {$$b{year} cmp $$a{year}} @copyright; # if the file is modified, assume commit year this year if(`git status -s -- $file` =~ /^ [MARCU]/) { $commityear = (localtime(time))[5] + 1900; } else { # min-parents=1 to ignore wrong initial commit in truncated repos my $grl = `git rev-list --max-count=1 --min-parents=1 --timestamp HEAD -- $file`; if($grl) { chomp $grl; $commityear = (localtime((split(/ /, $grl))[0]))[5] + 1900; } } if(defined($commityear) && scalar(@copyright) && $copyright[0]{year} != $commityear) { checkwarn("COPYRIGHTYEAR", $copyright[0]{line}, $copyright[0]{col}, $file, $copyright[0]{code}, "Copyright year out of date, should be $commityear, " . "is $copyright[0]{year}", 1); } } if($incomment) { checkwarn("OPENCOMMENT", 1, 0, $file, "", "Missing closing comment", 1); } checksrc_endoffile($file); close(R); } if($errors || $warnings || $verbose) { printf "checksrc: %d errors and %d warnings\n", $errors, $warnings; if($suppressed) { printf "checksrc: %d errors and %d warnings suppressed\n", $serrors, $swarnings; } exit 5; # return failure } davix-0.8.0/deps/curl/lib/Makefile.m320000644000000000000000000002431114121063461016035 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1999 - 2020, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** ########################################################################### # ## Makefile for building libcurl.a with MingW (GCC-3.2 or later or LLVM/Clang) ## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4), ## brotli (1.0.1) ## ## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn ## ## Hint: you can also set environment vars to control the build, f.e.: ## set ZLIB_PATH=c:/zlib-1.2.8 ## set ZLIB=1 # ########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH ZLIB_PATH = ../../zlib-1.2.8 endif # Edit the path below to point to the base of your Brotli sources. ifndef BROTLI_PATH BROTLI_PATH = ../../brotli-1.0.1 endif # Edit the path below to point to the base of your OpenSSL package. ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-1.0.2a endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH LIBSSH2_PATH = ../../libssh2-1.5.0 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.4 endif # Edit the path below to point to the base of your libidn2 package. ifndef LIBIDN2_PATH LIBIDN2_PATH = ../../libidn2-2.0.3 endif # Edit the path below to point to the base of your MS IDN package. # Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 # https://www.microsoft.com/en-us/download/details.aspx?id=734 ifndef WINIDN_PATH WINIDN_PATH = ../../Microsoft IDN Mitigation APIs endif # Edit the path below to point to the base of your Novell LDAP NDK. ifndef LDAP_SDK LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif # Edit the path below to point to the base of your nghttp2 package. ifndef NGHTTP2_PATH NGHTTP2_PATH = ../../nghttp2-1.0.0 endif PROOT = .. # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = $(PROOT)/ares endif ifeq ($(CURL_CC),) CURL_CC := $(CROSSPREFIX)gcc endif ifeq ($(CURL_AR),) CURL_AR := $(CROSSPREFIX)ar endif ifeq ($(CURL_RANLIB),) CURL_RANLIB := $(CROSSPREFIX)ranlib endif CC = $(CURL_CC) CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W CFLAGS += -fno-strict-aliasing # comment LDFLAGS below to keep debug info LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_DLL) -s AR = $(CURL_AR) RANLIB = $(CURL_RANLIB) RC = $(CROSSPREFIX)windres RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF STRIP = $(CROSSPREFIX)strip -g # Set environment var ARCH to your architecture to override autodetection. ifndef ARCH ifeq ($(findstring x86_64,$(shell $(CC) -dumpmachine)),x86_64) ARCH = w64 else ARCH = w32 endif endif ifeq ($(ARCH),w64) CFLAGS += -m64 -D_AMD64_ LDFLAGS += -m64 RCFLAGS += -F pe-x86-64 else CFLAGS += -m32 LDFLAGS += -m32 RCFLAGS += -F pe-i386 endif # Platform-dependent helper tool macros ifeq ($(findstring /sh,$(SHELL)),/sh) DEL = rm -f $1 RMDIR = rm -fr $1 MKDIR = mkdir -p $1 COPY = -cp -afv $1 $2 #COPYR = -cp -afr $1/* $2 COPYR = -rsync -aC $1/* $2 TOUCH = touch $1 CAT = cat ECHONL = echo "" DL = ' else ifeq "$(OS)" "Windows_NT" DEL = -del 2>NUL /q /f $(subst /,\,$1) RMDIR = -rd 2>NUL /q /s $(subst /,\,$1) else DEL = -del 2>NUL $(subst /,\,$1) RMDIR = -deltree 2>NUL /y $(subst /,\,$1) endif MKDIR = -md 2>NUL $(subst /,\,$1) COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2) COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2) TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,, CAT = type ECHONL = $(ComSpec) /c echo. endif ######################################################## ## Nothing more to do below this line! ifeq ($(findstring -dyn,$(CFG)),-dyn) DYN = 1 endif ifeq ($(findstring -ares,$(CFG)),-ares) ARES = 1 endif ifeq ($(findstring -sync,$(CFG)),-sync) SYNC = 1 endif ifeq ($(findstring -rtmp,$(CFG)),-rtmp) RTMP = 1 SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssh2,$(CFG)),-ssh2) SSH2 = 1 SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssl,$(CFG)),-ssl) SSL = 1 endif ifeq ($(findstring -srp,$(CFG)),-srp) SRP = 1 endif ifeq ($(findstring -zlib,$(CFG)),-zlib) ZLIB = 1 endif ifeq ($(findstring -brotli,$(CFG)),-brotli) BROTLI = 1 endif ifeq ($(findstring -idn2,$(CFG)),-idn2) IDN2 = 1 endif ifeq ($(findstring -winidn,$(CFG)),-winidn) WINIDN = 1 endif ifeq ($(findstring -sspi,$(CFG)),-sspi) SSPI = 1 endif ifeq ($(findstring -ldaps,$(CFG)),-ldaps) LDAPS = 1 endif ifeq ($(findstring -ipv6,$(CFG)),-ipv6) IPV6 = 1 endif ifeq ($(findstring -winssl,$(CFG)),-winssl) WINSSL = 1 SSPI = 1 endif ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) NGHTTP2 = 1 endif INCLUDES = -I. -I../include CFLAGS += -DBUILDING_LIBCURL ifdef SSL ifdef WINSSL CFLAGS += -DCURL_WITH_MULTI_SSL endif endif ifdef SYNC CFLAGS += -DUSE_SYNC_DNS else ifdef ARES INCLUDES += -I"$(LIBCARES_PATH)" CFLAGS += -DUSE_ARES -DCARES_STATICLIB DLL_LIBS += -L"$(LIBCARES_PATH)" -lcares libcurl_dll_DEPENDENCIES = $(LIBCARES_PATH)/libcares.a endif endif ifdef RTMP INCLUDES += -I"$(LIBRTMP_PATH)" CFLAGS += -DUSE_LIBRTMP DLL_LIBS += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm endif ifdef NGHTTP2 INCLUDES += -I"$(NGHTTP2_PATH)/include" CFLAGS += -DUSE_NGHTTP2 DLL_LIBS += -L"$(NGHTTP2_PATH)/lib" -lnghttp2 endif ifdef SSH2 INCLUDES += -I"$(LIBSSH2_PATH)/include" -I"$(LIBSSH2_PATH)/win32" CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2 ifdef WINSSL ifndef DYN DLL_LIBS += -lbcrypt -lcrypt32 endif endif endif ifdef SSL ifndef OPENSSL_INCLUDE ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc" OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc endif ifeq "$(wildcard $(OPENSSL_PATH)/include)" "$(OPENSSL_PATH)/include" OPENSSL_INCLUDE = $(OPENSSL_PATH)/include endif endif ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h" $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) endif ifndef OPENSSL_LIBPATH ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out" OPENSSL_LIBPATH = $(OPENSSL_PATH)/out OPENSSL_LIBS = -leay32 -lssl32 endif ifeq "$(wildcard $(OPENSSL_PATH)/lib)" "$(OPENSSL_PATH)/lib" OPENSSL_LIBPATH = $(OPENSSL_PATH)/lib OPENSSL_LIBS = -lcrypto -lssl endif endif ifndef DYN OPENSSL_LIBS += -lgdi32 -lcrypt32 endif INCLUDES += -I"$(OPENSSL_INCLUDE)" CFLAGS += -DUSE_OPENSSL -DHAVE_OPENSSL_PKCS12_H \ -DOPENSSL_NO_KRB5 DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) ifdef SRP ifeq "$(wildcard $(OPENSSL_INCLUDE)/openssl/srp.h)" "$(OPENSSL_INCLUDE)/openssl/srp.h" CFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP endif endif endif ifdef WINSSL CFLAGS += -DUSE_SCHANNEL DLL_LIBS += -lcrypt32 endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H DLL_LIBS += -L"$(ZLIB_PATH)" -lz endif ifdef BROTLI INCLUDES += -I"$(BROTLI_PATH)/include" CFLAGS += -DHAVE_BROTLI DLL_LIBS += -L"$(BROTLI_PATH)/lib" ifdef BROTLI_LIBS DLL_LIBS += $(BROTLI_LIBS) else DLL_LIBS += -lbrotlidec endif endif ifdef IDN2 INCLUDES += -I"$(LIBIDN2_PATH)/include" CFLAGS += -DUSE_LIBIDN2 DLL_LIBS += -L"$(LIBIDN2_PATH)/lib" -lidn2 else ifdef WINIDN CFLAGS += -DUSE_WIN32_IDN CFLAGS += -DWANT_IDN_PROTOTYPES DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif ifdef SPNEGO CFLAGS += -DHAVE_SPNEGO endif ifdef IPV6 CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL endif ifdef USE_LDAP_NOVELL INCLUDES += -I"$(LDAP_SDK)/inc" CFLAGS += -DCURL_HAS_NOVELL_LDAPSDK DLL_LIBS += -L"$(LDAP_SDK)/lib/mscvc" -lldapsdk -lldapssl -lldapx endif ifdef USE_LDAP_OPENLDAP INCLUDES += -I"$(LDAP_SDK)/include" CFLAGS += -DCURL_HAS_OPENLDAP_LDAPSDK DLL_LIBS += -L"$(LDAP_SDK)/lib" -lldap -llber endif ifndef USE_LDAP_NOVELL ifndef USE_LDAP_OPENLDAP DLL_LIBS += -lwldap32 endif endif DLL_LIBS += -lws2_32 # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc ifeq ($(CURL_DLL_A_SUFFIX),) CURL_DLL_A_SUFFIX := dll endif libcurl_dll_LIBRARY = libcurl$(CURL_DLL_SUFFIX).dll libcurl_dll_a_LIBRARY = libcurl$(CURL_DLL_A_SUFFIX).a libcurl_a_LIBRARY = libcurl.a libcurl_a_OBJECTS := $(patsubst %.c,%.o,$(strip $(CSOURCES))) libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS)) RESOURCE = libcurl.res all: $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) $(libcurl_a_LIBRARY): $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES) @$(call DEL, $@) $(AR) cru $@ $(libcurl_a_OBJECTS) $(RANLIB) $@ $(STRIP) $@ # remove the last line above to keep debug info $(libcurl_dll_LIBRARY): $(libcurl_a_OBJECTS) $(RESOURCE) $(libcurl_dll_DEPENDENCIES) @$(call DEL, $@) $(CC) $(LDFLAGS) -shared -o $@ \ -Wl,--output-def,$(@:.dll=.def),--out-implib,$(libcurl_dll_a_LIBRARY) \ $(libcurl_a_OBJECTS) $(RESOURCE) $(DLL_LIBS) %.o: %.c $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ %.res: %.rc $(RC) $(RCFLAGS) -i $< -o $@ clean: @$(call DEL, $(libcurl_a_OBJECTS) $(RESOURCE)) distclean vclean: clean @$(call DEL, $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) $(libcurl_dll_LIBRARY:.dll=.def) $(libcurl_dll_a_LIBRARY)) $(LIBCARES_PATH)/libcares.a: $(MAKE) -C $(LIBCARES_PATH) -f Makefile.m32 davix-0.8.0/deps/curl/lib/cookie.h0000644000000000000000000001114314121063461015416 0ustar rootroot#ifndef HEADER_CURL_COOKIE_H #define HEADER_CURL_COOKIE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include struct Cookie { struct Cookie *next; /* next in the chain */ char *name; /* = value */ char *value; /* name = */ char *path; /* path = which is in Set-Cookie: */ char *spath; /* sanitized cookie path */ char *domain; /* domain = */ curl_off_t expires; /* expires = */ char *expirestr; /* the plain text version */ bool tailmatch; /* whether we do tail-matching of the domain name */ /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ char *version; /* Version = */ char *maxage; /* Max-Age = */ bool secure; /* whether the 'secure' keyword was used */ bool livecookie; /* updated from a server, not a stored file */ bool httponly; /* true if the httponly directive is present */ int creationtime; /* time when the cookie was written */ unsigned char prefix; /* bitmap fields indicating which prefix are set */ }; /* * Available cookie prefixes, as defined in * draft-ietf-httpbis-rfc6265bis-02 */ #define COOKIE_PREFIX__SECURE (1<<0) #define COOKIE_PREFIX__HOST (1<<1) #define COOKIE_HASH_SIZE 256 struct CookieInfo { /* linked list of cookies we know of */ struct Cookie *cookies[COOKIE_HASH_SIZE]; char *filename; /* file we read from/write to */ bool running; /* state info, for cookie adding information */ long numcookies; /* number of cookies in the "jar" */ bool newsession; /* new session, discard session cookies on load */ int lastct; /* last creation-time used in the jar */ }; /* This is the maximum line length we accept for a cookie line. RFC 2109 section 6.3 says: "at least 4096 bytes per cookie (as measured by the size of the characters that comprise the cookie non-terminal in the syntax description of the Set-Cookie header)" We allow max 5000 bytes cookie header. Max 4095 bytes length per cookie name and value. Name + value may not exceed 4096 bytes. */ #define MAX_COOKIE_LINE 5000 /* This is the maximum length of a cookie name or content we deal with: */ #define MAX_NAME 4096 #define MAX_NAME_TXT "4095" struct Curl_easy; /* * Add a cookie to the internal list of cookies. The domain and path arguments * are only used if the header boolean is TRUE. */ struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *, bool header, bool noexpiry, char *lineptr, const char *domain, const char *path, bool secure); struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, const char *, bool); void Curl_cookie_freelist(struct Cookie *cookies); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) #define Curl_cookie_list(x) NULL #define Curl_cookie_loadfiles(x) Curl_nop_stmt #define Curl_cookie_init(x,y,z,w) NULL #define Curl_cookie_cleanup(x) Curl_nop_stmt #define Curl_flush_cookies(x,y) Curl_nop_stmt #else void Curl_flush_cookies(struct Curl_easy *data, bool cleanup); void Curl_cookie_cleanup(struct CookieInfo *); struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *, struct CookieInfo *, bool); struct curl_slist *Curl_cookie_list(struct Curl_easy *data); void Curl_cookie_loadfiles(struct Curl_easy *data); #endif #endif /* HEADER_CURL_COOKIE_H */ davix-0.8.0/deps/curl/lib/config-os400.h0000644000000000000000000003755414121063461016273 0ustar rootroot#ifndef HEADER_CURL_CONFIG_OS400_H #define HEADER_CURL_CONFIG_OS400_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /* Hand crafted config file for OS/400 */ /* ================================================================ */ #pragma enum(int) #undef PACKAGE /* Version number of this archive. */ #undef VERSION /* Define if you have the getpass function. */ #undef HAVE_GETPASS /* Define cpu-machine-OS */ #define OS "OS/400" /* Define if you have the gethostbyaddr_r() function with 5 arguments */ #define HAVE_GETHOSTBYADDR_R_5 /* Define if you have the gethostbyaddr_r() function with 7 arguments */ #undef HAVE_GETHOSTBYADDR_R_7 /* Define if you have the gethostbyaddr_r() function with 8 arguments */ #undef HAVE_GETHOSTBYADDR_R_8 /* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its * prototype is incompatible with the "standard" one (1st argument is not * const). However, getaddrinfo() is supported (ASCII version defined as * a local wrapper in setup-os400.h) in a threadsafe way: we can then * configure getaddrinfo() as such and get rid of gethostbyname_r() without * loss of threadsafeness. */ #undef HAVE_GETHOSTBYNAME_R #undef HAVE_GETHOSTBYNAME_R_3 #undef HAVE_GETHOSTBYNAME_R_5 #undef HAVE_GETHOSTBYNAME_R_6 #define HAVE_GETADDRINFO #define HAVE_GETADDRINFO_THREADSAFE /* Define if you need the _REENTRANT define for some functions */ #undef NEED_REENTRANT /* Define if you have the Kerberos4 libraries (including -ldes) */ #undef HAVE_KRB4 /* Define if you want to enable IPv6 support */ #define ENABLE_IPV6 /* Define if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 /* Define this to 'int' if ssize_t is not an available typedefed type */ #undef ssize_t /* Define this as a suitable file to read random data from */ #undef RANDOM_FILE /* Define this to your Entropy Gathering Daemon socket pathname */ #undef EGD_SOCKET /* Define to 1 if you have the alarm function. */ #define HAVE_ALARM 1 /* Define if you have the header file. */ #undef HAVE_ALLOCA_H /* Define if you have the header file. */ #define HAVE_ARPA_INET_H /* Define if you have the `closesocket' function. */ #undef HAVE_CLOSESOCKET /* Define if you have the header file. */ #undef HAVE_CRYPTO_H /* Define if you have the header file. */ #undef HAVE_DES_H /* Define if you have the header file. */ #define HAVE_ERRNO_H /* Define if you have the header file. */ #undef HAVE_ERR_H /* Define if you have the header file. */ #define HAVE_FCNTL_H /* Define if you have the `geteuid' function. */ #define HAVE_GETEUID /* Define if you have the `gethostbyaddr' function. */ #define HAVE_GETHOSTBYADDR /* Define if you have the `gethostbyaddr_r' function. */ #define HAVE_GETHOSTBYADDR_R /* Define if you have the `gethostname' function. */ #define HAVE_GETHOSTNAME /* Define if you have the header file. */ #undef HAVE_GETOPT_H /* Define if you have the `getpass_r' function. */ #undef HAVE_GETPASS_R /* Define to 1 if you have the getpeername function. */ #define HAVE_GETPEERNAME 1 /* Define if you have the `getpwuid' function. */ #define HAVE_GETPWUID /* Define if you have the `getservbyname' function. */ #define HAVE_GETSERVBYNAME /* Define to 1 if you have the getsockname function. */ #define HAVE_GETSOCKNAME 1 /* Define if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY /* Define if you have the `timeval' struct. */ #define HAVE_STRUCT_TIMEVAL /* Define if you have the `inet_addr' function. */ #define HAVE_INET_ADDR /* Define if you have the header file. */ #define HAVE_INTTYPES_H /* Define if you have the header file. */ #undef HAVE_IO_H /* Define if you have the `krb_get_our_ip_for_realm' function. */ #undef HAVE_KRB_GET_OUR_IP_FOR_REALM /* Define if you have the header file. */ #undef HAVE_KRB_H /* Define if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define if you have the `resolve' library (-lresolve). */ #undef HAVE_LIBRESOLVE /* Define if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define if you have GSS API. */ #define HAVE_GSSAPI /* Define if you have the GNU gssapi libraries */ #undef HAVE_GSSGNU /* Define if you have the Heimdal gssapi libraries */ #define HAVE_GSSHEIMDAL /* Define if you have the MIT gssapi libraries */ #undef HAVE_GSSMIT /* Define if you have the `ucb' library (-lucb). */ #undef HAVE_LIBUCB /* Define if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R /* Define if you have the header file. */ #define HAVE_MALLOC_H /* Define if you need the malloc.h header file even with stdlib.h */ /* #define NEED_MALLOC_H 1 */ /* Define if you have the header file. */ #undef HAVE_MEMORY_H /* Define if you have the header file. */ #define HAVE_NETDB_H /* Define if you have the header file. */ #undef HAVE_NETINET_IF_ETHER_H /* Define if you have the header file. */ #define HAVE_NETINET_IN_H /* Define if you have the header file. */ #define HAVE_NET_IF_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_CRYPTO_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_PEM_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_RSA_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define if you have the header file. */ #undef HAVE_OPENSSL_X509_H /* Define if you have the header file. */ #undef HAVE_PEM_H /* Define if you have the `perror' function. */ #define HAVE_PERROR /* Define if you have the header file. */ #define HAVE_PWD_H /* Define if you have the `RAND_egd' function. */ #undef HAVE_RAND_EGD /* Define if you have the `RAND_screen' function. */ #undef HAVE_RAND_SCREEN /* Define if you have the `RAND_status' function. */ #undef HAVE_RAND_STATUS /* Define if you have the header file. */ #undef HAVE_RSA_H /* Define if you have the `select' function. */ #define HAVE_SELECT /* Define if you have the `setvbuf' function. */ #define HAVE_SETVBUF /* Define if you have the header file. */ #undef HAVE_SGTTY_H /* Define if you have the `sigaction' function. */ #define HAVE_SIGACTION /* Define if you have the `signal' function. */ #undef HAVE_SIGNAL /* Define if you have the header file. */ #define HAVE_SIGNAL_H /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T /* Define if sig_atomic_t is already defined as volatile. */ #undef HAVE_SIG_ATOMIC_T_VOLATILE /* Define if you have the `socket' function. */ #define HAVE_SOCKET /* Define if you have the header file. */ #undef HAVE_SSL_H /* Define if you have the header file. */ #undef HAVE_STDINT_H /* Define if you have the header file. */ #define HAVE_STDLIB_H /* The following define is needed on OS400 to enable strcmpi(), stricmp() and strdup(). */ #define __cplusplus__strings__ /* Define if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define if you have the `strcmpi' function. */ #define HAVE_STRCMPI /* Define if you have the `stricmp' function. */ #define HAVE_STRICMP /* Define if you have the `strdup' function. */ #define HAVE_STRDUP /* Define if you have the `strftime' function. */ #define HAVE_STRFTIME /* Define if you have the header file. */ #define HAVE_STRINGS_H /* Define if you have the header file. */ #define HAVE_STRING_H /* Define if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define if you have the header file. */ #undef HAVE_STROPTS_H /* Define if you have the `strstr' function. */ #define HAVE_STRSTR /* Define if you have the `strtok_r' function. */ #define HAVE_STRTOK_R /* Define if you have the `strtoll' function. */ #undef HAVE_STRTOLL /* Allows ASCII compile on V5R1. */ /* Define if you have the header file. */ #define HAVE_SYS_PARAM_H /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define if you have the header file. */ #define HAVE_SYS_SOCKET_H /* Define if you have the header file. */ #undef HAVE_SYS_SOCKIO_H /* Define if you have the header file. */ #define HAVE_SYS_STAT_H /* Define if you have the header file. */ #define HAVE_SYS_TIME_H /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H /* Define if you have the header file. */ #define HAVE_SYS_UN_H /* Define if you have the header file. */ #define HAVE_SYS_IOCTL_H /* Define if you have the `tcgetattr' function. */ #undef HAVE_TCGETATTR /* Define if you have the `tcsetattr' function. */ #undef HAVE_TCSETATTR /* Define if you have the header file. */ #undef HAVE_TERMIOS_H /* Define if you have the header file. */ #undef HAVE_TERMIO_H /* Define if you have the header file. */ #define HAVE_TIME_H /* Define if you have the `uname' function. */ #undef HAVE_UNAME /* Define if you have the header file. */ #define HAVE_UNISTD_H /* Define if you have the header file. */ #undef HAVE_WINSOCK_H /* Define if you have the header file. */ #undef HAVE_X509_H /* Name of package */ #undef PACKAGE /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of a `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 8 /* Define if the compiler supports the 'long long' data type. */ #define HAVE_LONGLONG /* The size of a `long long', as computed by sizeof. */ #define SIZEOF_LONG_LONG 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 4 /* The size of `curl_off_t', as computed by sizeof. */ #define SIZEOF_CURL_OFF_T 8 /* Whether long long constants must be suffixed by LL. */ #define HAVE_LL /* Define this if you have struct sockaddr_storage */ #define HAVE_STRUCT_SOCKADDR_STORAGE /* Define if you have the ANSI C header files. */ #define STDC_HEADERS /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME /* Define to enable alt-svc support (experimental) */ #undef USE_ALTSVC /* Define to enable HTTP3 support (experimental, requires NGTCP2 or QUICHE) */ #undef ENABLE_QUIC /* Version number of package */ #undef VERSION /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #define _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* type to use in place of in_addr_t if not defined */ #define in_addr_t unsigned long /* Define to `unsigned' if does not define. */ #undef size_t /* Define if you have the ioctl function. */ #define HAVE_IOCTL /* Define if you have a working ioctl FIONBIO function. */ #define HAVE_IOCTL_FIONBIO /* Define if you have a working ioctl SIOCGIFADDR function. */ #define HAVE_IOCTL_SIOCGIFADDR /* To disable LDAP */ #undef CURL_DISABLE_LDAP /* Definition to make a library symbol externally visible. */ #define CURL_EXTERN_SYMBOL /* Define if you have the ldap_url_parse procedure. */ /* #define HAVE_LDAP_URL_PARSE */ /* Disabled because of an IBM bug. */ /* Define if you have the getnameinfo function. */ /* OS400 has no ASCII version of this procedure: wrapped in setup-os400.h. */ #define HAVE_GETNAMEINFO /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const /* Define to the type of arg 1 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG1 struct sockaddr * /* Define to the type of arg 2 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG2 socklen_t /* Define to the type of args 4 and 6 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG46 socklen_t /* Define to the type of arg 7 for getnameinfo. */ #define GETNAMEINFO_TYPE_ARG7 int /* Define if you have the recv function. */ #define HAVE_RECV /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 int /* Define to the type of arg 2 for recv. */ #define RECV_TYPE_ARG2 char * /* Define to the type of arg 3 for recv. */ #define RECV_TYPE_ARG3 int /* Define to the type of arg 4 for recv. */ #define RECV_TYPE_ARG4 int /* Define to the function return type for recv. */ #define RECV_TYPE_RETV int /* Define if you have the recvfrom function. */ #define HAVE_RECVFROM /* Define to the type of arg 1 for recvfrom. */ #define RECVFROM_TYPE_ARG1 int /* Define to the type pointed by arg 2 for recvfrom. */ #define RECVFROM_TYPE_ARG2 char /* Define to the type of arg 3 for recvfrom. */ #define RECVFROM_TYPE_ARG3 int /* Define to the type of arg 4 for recvfrom. */ #define RECVFROM_TYPE_ARG4 int /* Define to the type pointed by arg 5 for recvfrom. */ #define RECVFROM_TYPE_ARG5 struct sockaddr /* Define to the type pointed by arg 6 for recvfrom. */ #define RECVFROM_TYPE_ARG6 int /* Define to the function return type for recvfrom. */ #define RECVFROM_TYPE_RETV int /* Define if you have the send function. */ #define HAVE_SEND /* Define to the type of arg 1 for send. */ #define SEND_TYPE_ARG1 int /* Define to the type qualifier of arg 2 for send. */ #define SEND_QUAL_ARG2 /* Define to the type of arg 2 for send. */ #define SEND_TYPE_ARG2 char * /* Define to the type of arg 3 for send. */ #define SEND_TYPE_ARG3 int /* Define to the type of arg 4 for send. */ #define SEND_TYPE_ARG4 int /* Define to the function return type for send. */ #define SEND_TYPE_RETV int /* Define to use the GSKit package. */ #define USE_GSKIT /* Define to use the OS/400 crypto library. */ #define USE_OS400CRYPTO /* Define to use Unix sockets. */ #define USE_UNIX_SOCKETS /* Use the system keyring as the default CA bundle. */ #define CURL_CA_BUNDLE "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB" /* ---------------------------------------------------------------- */ /* ADDITIONAL DEFINITIONS */ /* ---------------------------------------------------------------- */ /* The following must be defined BEFORE system header files inclusion. */ #define __ptr128 /* No teraspace. */ #define qadrt_use_fputc_inline /* Generate fputc() wrapper inline. */ #define qadrt_use_fread_inline /* Generate fread() wrapper inline. */ #define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */ #endif /* HEADER_CURL_CONFIG_OS400_H */ davix-0.8.0/deps/curl/lib/content_encoding.c0000644000000000000000000006771714121063461017502 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "curl_setup.h" #include "urldata.h" #include #include #ifdef HAVE_ZLIB_H #include #ifdef __SYMBIAN32__ /* zlib pollutes the namespace with this definition */ #undef WIN32 #endif #endif #ifdef HAVE_BROTLI #include #endif #include "sendf.h" #include "http.h" #include "content_encoding.h" #include "strdup.h" #include "strcase.h" #include "curl_memory.h" #include "memdebug.h" #define CONTENT_ENCODING_DEFAULT "identity" #ifndef CURL_DISABLE_HTTP #define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */ #ifdef HAVE_LIBZ /* Comment this out if zlib is always going to be at least ver. 1.2.0.4 (doing so will reduce code size slightly). */ #define OLD_ZLIB_SUPPORT 1 #define GZIP_MAGIC_0 0x1f #define GZIP_MAGIC_1 0x8b /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ typedef enum { ZLIB_UNINIT, /* uninitialized */ ZLIB_INIT, /* initialized */ ZLIB_INFLATING, /* inflating started. */ ZLIB_EXTERNAL_TRAILER, /* reading external trailer */ ZLIB_GZIP_HEADER, /* reading gzip header */ ZLIB_GZIP_INFLATING, /* inflating gzip stream */ ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ } zlibInitState; /* Writer parameters. */ typedef struct { zlibInitState zlib_init; /* zlib init state */ uInt trailerlen; /* Remaining trailer byte count. */ z_stream z; /* State structure for zlib. */ } zlib_params; static voidpf zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) { (void) opaque; /* not a typo, keep it calloc() */ return (voidpf) calloc(items, size); } static void zfree_cb(voidpf opaque, voidpf ptr) { (void) opaque; free(ptr); } static CURLcode process_zlib_error(struct connectdata *conn, z_stream *z) { struct Curl_easy *data = conn->data; if(z->msg) failf(data, "Error while processing content unencoding: %s", z->msg); else failf(data, "Error while processing content unencoding: " "Unknown failure within decompression software."); return CURLE_BAD_CONTENT_ENCODING; } static CURLcode exit_zlib(struct connectdata *conn, z_stream *z, zlibInitState *zlib_init, CURLcode result) { if(*zlib_init == ZLIB_GZIP_HEADER) Curl_safefree(z->next_in); if(*zlib_init != ZLIB_UNINIT) { if(inflateEnd(z) != Z_OK && result == CURLE_OK) result = process_zlib_error(conn, z); *zlib_init = ZLIB_UNINIT; } return result; } static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp) { z_stream *z = &zp->z; CURLcode result = CURLE_OK; uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen; /* Consume expected trailer bytes. Terminate stream if exhausted. Issue an error if unexpected bytes follow. */ zp->trailerlen -= len; z->avail_in -= len; z->next_in += len; if(z->avail_in) result = CURLE_WRITE_ERROR; if(result || !zp->trailerlen) result = exit_zlib(conn, z, &zp->zlib_init, result); else { /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */ zp->zlib_init = ZLIB_EXTERNAL_TRAILER; } return result; } static CURLcode inflate_stream(struct connectdata *conn, contenc_writer *writer, zlibInitState started) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ uInt nread = z->avail_in; Bytef *orig_in = z->next_in; bool done = FALSE; CURLcode result = CURLE_OK; /* Curl_client_write status */ char *decomp; /* Put the decompressed data here. */ /* Check state. */ if(zp->zlib_init != ZLIB_INIT && zp->zlib_init != ZLIB_INFLATING && zp->zlib_init != ZLIB_INIT_GZIP && zp->zlib_init != ZLIB_GZIP_INFLATING) return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR); /* Dynamically allocate a buffer for decompression because it's uncommonly large to hold on the stack */ decomp = malloc(DSIZ); if(decomp == NULL) return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); /* because the buffer size is fixed, iteratively decompress and transfer to the client via downstream_write function. */ while(!done) { int status; /* zlib status */ done = TRUE; /* (re)set buffer for decompressed output for every iteration */ z->next_out = (Bytef *) decomp; z->avail_out = DSIZ; #ifdef Z_BLOCK /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */ status = inflate(z, Z_BLOCK); #else /* fallback for zlib ver. < 1.2.0.5 */ status = inflate(z, Z_SYNC_FLUSH); #endif /* Flush output data if some. */ if(z->avail_out != DSIZ) { if(status == Z_OK || status == Z_STREAM_END) { zp->zlib_init = started; /* Data started. */ result = Curl_unencode_write(conn, writer->downstream, decomp, DSIZ - z->avail_out); if(result) { exit_zlib(conn, z, &zp->zlib_init, result); break; } } } /* Dispatch by inflate() status. */ switch(status) { case Z_OK: /* Always loop: there may be unflushed latched data in zlib state. */ done = FALSE; break; case Z_BUF_ERROR: /* No more data to flush: just exit loop. */ break; case Z_STREAM_END: result = process_trailer(conn, zp); break; case Z_DATA_ERROR: /* some servers seem to not generate zlib headers, so this is an attempt to fix and continue anyway */ if(zp->zlib_init == ZLIB_INIT) { /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */ (void) inflateEnd(z); /* don't care about the return code */ if(inflateInit2(z, -MAX_WBITS) == Z_OK) { z->next_in = orig_in; z->avail_in = nread; zp->zlib_init = ZLIB_INFLATING; zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */ done = FALSE; break; } zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */ } /* FALLTHROUGH */ default: result = exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z)); break; } } free(decomp); /* We're about to leave this call so the `nread' data bytes won't be seen again. If we are in a state that would wrongly allow restart in raw mode at the next call, assume output has already started. */ if(nread && zp->zlib_init == ZLIB_INIT) zp->zlib_init = started; /* Cannot restart anymore. */ return result; } /* Deflate handler. */ static CURLcode deflate_init_writer(struct connectdata *conn, contenc_writer *writer) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) return CURLE_WRITE_ERROR; /* Initialize zlib */ z->zalloc = (alloc_func) zalloc_cb; z->zfree = (free_func) zfree_cb; if(inflateInit(z) != Z_OK) return process_zlib_error(conn, z); zp->zlib_init = ZLIB_INIT; return CURLE_OK; } static CURLcode deflate_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ /* Set the compressed input when this function is called */ z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER) return process_trailer(conn, zp); /* Now uncompress the data */ return inflate_stream(conn, writer, ZLIB_INFLATING); } static void deflate_close_writer(struct connectdata *conn, contenc_writer *writer) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK); } static const content_encoding deflate_encoding = { "deflate", NULL, deflate_init_writer, deflate_unencode_write, deflate_close_writer, sizeof(zlib_params) }; /* Gzip handler. */ static CURLcode gzip_init_writer(struct connectdata *conn, contenc_writer *writer) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) return CURLE_WRITE_ERROR; /* Initialize zlib */ z->zalloc = (alloc_func) zalloc_cb; z->zfree = (free_func) zfree_cb; if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) { return process_zlib_error(conn, z); } zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */ } else { /* we must parse the gzip header and trailer ourselves */ if(inflateInit2(z, -MAX_WBITS) != Z_OK) { return process_zlib_error(conn, z); } zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */ zp->zlib_init = ZLIB_INIT; /* Initial call state */ } return CURLE_OK; } #ifdef OLD_ZLIB_SUPPORT /* Skip over the gzip header */ static enum { GZIP_OK, GZIP_BAD, GZIP_UNDERFLOW } check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen) { int method, flags; const ssize_t totallen = len; /* The shortest header is 10 bytes */ if(len < 10) return GZIP_UNDERFLOW; if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1)) return GZIP_BAD; method = data[2]; flags = data[3]; if(method != Z_DEFLATED || (flags & RESERVED) != 0) { /* Can't handle this compression method or unknown flag */ return GZIP_BAD; } /* Skip over time, xflags, OS code and all previous bytes */ len -= 10; data += 10; if(flags & EXTRA_FIELD) { ssize_t extra_len; if(len < 2) return GZIP_UNDERFLOW; extra_len = (data[1] << 8) | data[0]; if(len < (extra_len + 2)) return GZIP_UNDERFLOW; len -= (extra_len + 2); data += (extra_len + 2); } if(flags & ORIG_NAME) { /* Skip over NUL-terminated file name */ while(len && *data) { --len; ++data; } if(!len || *data) return GZIP_UNDERFLOW; /* Skip over the NUL */ --len; ++data; } if(flags & COMMENT) { /* Skip over NUL-terminated comment */ while(len && *data) { --len; ++data; } if(!len || *data) return GZIP_UNDERFLOW; /* Skip over the NUL */ --len; } if(flags & HEAD_CRC) { if(len < 2) return GZIP_UNDERFLOW; len -= 2; } *headerlen = totallen - len; return GZIP_OK; } #endif static CURLcode gzip_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ if(zp->zlib_init == ZLIB_INIT_GZIP) { /* Let zlib handle the gzip decompression entirely */ z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; /* Now uncompress the data */ return inflate_stream(conn, writer, ZLIB_INIT_GZIP); } #ifndef OLD_ZLIB_SUPPORT /* Support for old zlib versions is compiled away and we are running with an old version, so return an error. */ return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR); #else /* This next mess is to get around the potential case where there isn't * enough data passed in to skip over the gzip header. If that happens, we * malloc a block and copy what we have then wait for the next call. If * there still isn't enough (this is definitely a worst-case scenario), we * make the block bigger, copy the next part in and keep waiting. * * This is only required with zlib versions < 1.2.0.4 as newer versions * can handle the gzip header themselves. */ switch(zp->zlib_init) { /* Skip over gzip header? */ case ZLIB_INIT: { /* Initial call state */ ssize_t hlen; switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) { case GZIP_OK: z->next_in = (Bytef *) buf + hlen; z->avail_in = (uInt) (nbytes - hlen); zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ break; case GZIP_UNDERFLOW: /* We need more data so we can find the end of the gzip header. It's * possible that the memory block we malloc here will never be freed if * the transfer abruptly aborts after this point. Since it's unlikely * that circumstances will be right for this code path to be followed in * the first place, and it's even more unlikely for a transfer to fail * immediately afterwards, it should seldom be a problem. */ z->avail_in = (uInt) nbytes; z->next_in = malloc(z->avail_in); if(z->next_in == NULL) { return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); } memcpy(z->next_in, buf, z->avail_in); zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */ /* We don't have any data to inflate yet */ return CURLE_OK; case GZIP_BAD: default: return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z)); } } break; case ZLIB_GZIP_HEADER: { /* Need more gzip header data state */ ssize_t hlen; z->avail_in += (uInt) nbytes; z->next_in = Curl_saferealloc(z->next_in, z->avail_in); if(z->next_in == NULL) { return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); } /* Append the new block of data to the previous one */ memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes); switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) { case GZIP_OK: /* This is the zlib stream data */ free(z->next_in); /* Don't point into the malloced block since we just freed it */ z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in; z->avail_in = (uInt) (z->avail_in - hlen); zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */ break; case GZIP_UNDERFLOW: /* We still don't have any data to inflate! */ return CURLE_OK; case GZIP_BAD: default: return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z)); } } break; case ZLIB_EXTERNAL_TRAILER: z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; return process_trailer(conn, zp); case ZLIB_GZIP_INFLATING: default: /* Inflating stream state */ z->next_in = (Bytef *) buf; z->avail_in = (uInt) nbytes; break; } if(z->avail_in == 0) { /* We don't have any data to inflate; wait until next time */ return CURLE_OK; } /* We've parsed the header, now uncompress the data */ return inflate_stream(conn, writer, ZLIB_GZIP_INFLATING); #endif } static void gzip_close_writer(struct connectdata *conn, contenc_writer *writer) { zlib_params *zp = (zlib_params *) &writer->params; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK); } static const content_encoding gzip_encoding = { "gzip", "x-gzip", gzip_init_writer, gzip_unencode_write, gzip_close_writer, sizeof(zlib_params) }; #endif /* HAVE_LIBZ */ #ifdef HAVE_BROTLI /* Writer parameters. */ typedef struct { BrotliDecoderState *br; /* State structure for brotli. */ } brotli_params; static CURLcode brotli_map_error(BrotliDecoderErrorCode be) { switch(be) { case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: case BROTLI_DECODER_ERROR_FORMAT_PADDING_1: case BROTLI_DECODER_ERROR_FORMAT_PADDING_2: #ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY: #endif #ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: #endif case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: return CURLE_BAD_CONTENT_ENCODING; case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: return CURLE_OUT_OF_MEMORY; default: break; } return CURLE_WRITE_ERROR; } static CURLcode brotli_init_writer(struct connectdata *conn, contenc_writer *writer) { brotli_params *bp = (brotli_params *) &writer->params; (void) conn; if(!writer->downstream) return CURLE_WRITE_ERROR; bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL); return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY; } static CURLcode brotli_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { brotli_params *bp = (brotli_params *) &writer->params; const uint8_t *src = (const uint8_t *) buf; char *decomp; uint8_t *dst; size_t dstleft; CURLcode result = CURLE_OK; BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; if(!bp->br) return CURLE_WRITE_ERROR; /* Stream already ended. */ decomp = malloc(DSIZ); if(!decomp) return CURLE_OUT_OF_MEMORY; while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) && result == CURLE_OK) { dst = (uint8_t *) decomp; dstleft = DSIZ; r = BrotliDecoderDecompressStream(bp->br, &nbytes, &src, &dstleft, &dst, NULL); result = Curl_unencode_write(conn, writer->downstream, decomp, DSIZ - dstleft); if(result) break; switch(r) { case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: break; case BROTLI_DECODER_RESULT_SUCCESS: BrotliDecoderDestroyInstance(bp->br); bp->br = NULL; if(nbytes) result = CURLE_WRITE_ERROR; break; default: result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br)); break; } } free(decomp); return result; } static void brotli_close_writer(struct connectdata *conn, contenc_writer *writer) { brotli_params *bp = (brotli_params *) &writer->params; (void) conn; if(bp->br) { BrotliDecoderDestroyInstance(bp->br); bp->br = NULL; } } static const content_encoding brotli_encoding = { "br", NULL, brotli_init_writer, brotli_unencode_write, brotli_close_writer, sizeof(brotli_params) }; #endif /* Identity handler. */ static CURLcode identity_init_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; } static CURLcode identity_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { return Curl_unencode_write(conn, writer->downstream, buf, nbytes); } static void identity_close_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; (void) writer; } static const content_encoding identity_encoding = { "identity", "none", identity_init_writer, identity_unencode_write, identity_close_writer, 0 }; /* supported content encodings table. */ static const content_encoding * const encodings[] = { &identity_encoding, #ifdef HAVE_LIBZ &deflate_encoding, &gzip_encoding, #endif #ifdef HAVE_BROTLI &brotli_encoding, #endif NULL }; /* Return a list of comma-separated names of supported encodings. */ char *Curl_all_content_encodings(void) { size_t len = 0; const content_encoding * const *cep; const content_encoding *ce; char *ace; for(cep = encodings; *cep; cep++) { ce = *cep; if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) len += strlen(ce->name) + 2; } if(!len) return strdup(CONTENT_ENCODING_DEFAULT); ace = malloc(len); if(ace) { char *p = ace; for(cep = encodings; *cep; cep++) { ce = *cep; if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) { strcpy(p, ce->name); p += strlen(p); *p++ = ','; *p++ = ' '; } } p[-2] = '\0'; } return ace; } /* Real client writer: no downstream. */ static CURLcode client_init_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK; } static CURLcode client_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; (void) writer; if(!nbytes || k->ignorebody) return CURLE_OK; return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes); } static void client_close_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; (void) writer; } static const content_encoding client_encoding = { NULL, NULL, client_init_writer, client_unencode_write, client_close_writer, 0 }; /* Deferred error dummy writer. */ static CURLcode error_init_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; } static CURLcode error_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { char *all = Curl_all_content_encodings(); (void) writer; (void) buf; (void) nbytes; if(!all) return CURLE_OUT_OF_MEMORY; failf(conn->data, "Unrecognized content encoding type. " "libcurl understands %s content encodings.", all); free(all); return CURLE_BAD_CONTENT_ENCODING; } static void error_close_writer(struct connectdata *conn, contenc_writer *writer) { (void) conn; (void) writer; } static const content_encoding error_encoding = { NULL, NULL, error_init_writer, error_unencode_write, error_close_writer, 0 }; /* Create an unencoding writer stage using the given handler. */ static contenc_writer *new_unencoding_writer(struct connectdata *conn, const content_encoding *handler, contenc_writer *downstream) { size_t sz = offsetof(contenc_writer, params) + handler->paramsize; contenc_writer *writer = (contenc_writer *) calloc(1, sz); if(writer) { writer->handler = handler; writer->downstream = downstream; if(handler->init_writer(conn, writer)) { free(writer); writer = NULL; } } return writer; } /* Write data using an unencoding writer stack. */ CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { if(!nbytes) return CURLE_OK; return writer->handler->unencode_write(conn, writer, buf, nbytes); } /* Close and clean-up the connection's writer stack. */ void Curl_unencode_cleanup(struct connectdata *conn) { struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; contenc_writer *writer = k->writer_stack; while(writer) { k->writer_stack = writer->downstream; writer->handler->close_writer(conn, writer); free(writer); writer = k->writer_stack; } } /* Find the content encoding by name. */ static const content_encoding *find_encoding(const char *name, size_t len) { const content_encoding * const *cep; for(cep = encodings; *cep; cep++) { const content_encoding *ce = *cep; if((strncasecompare(name, ce->name, len) && !ce->name[len]) || (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) return ce; } return NULL; } /* Set-up the unencoding stack from the Content-Encoding header value. * See RFC 7231 section 3.1.2.2. */ CURLcode Curl_build_unencoding_stack(struct connectdata *conn, const char *enclist, int maybechunked) { struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; do { const char *name; size_t namelen; /* Parse a single encoding name. */ while(ISSPACE(*enclist) || *enclist == ',') enclist++; name = enclist; for(namelen = 0; *enclist && *enclist != ','; enclist++) if(!ISSPACE(*enclist)) namelen = enclist - name + 1; /* Special case: chunked encoding is handled at the reader level. */ if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) { k->chunk = TRUE; /* chunks coming our way. */ Curl_httpchunk_init(conn); /* init our chunky engine. */ } else if(namelen) { const content_encoding *encoding = find_encoding(name, namelen); contenc_writer *writer; if(!k->writer_stack) { k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL); if(!k->writer_stack) return CURLE_OUT_OF_MEMORY; } if(!encoding) encoding = &error_encoding; /* Defer error at stack use. */ /* Stack the unencoding stage. */ writer = new_unencoding_writer(conn, encoding, k->writer_stack); if(!writer) return CURLE_OUT_OF_MEMORY; k->writer_stack = writer; } } while(*enclist); return CURLE_OK; } #else /* Stubs for builds without HTTP. */ CURLcode Curl_build_unencoding_stack(struct connectdata *conn, const char *enclist, int maybechunked) { (void) conn; (void) enclist; (void) maybechunked; return CURLE_NOT_BUILT_IN; } CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer, const char *buf, size_t nbytes) { (void) conn; (void) writer; (void) buf; (void) nbytes; return CURLE_NOT_BUILT_IN; } void Curl_unencode_cleanup(struct connectdata *conn) { (void) conn; } char *Curl_all_content_encodings(void) { return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */ } #endif /* CURL_DISABLE_HTTP */ davix-0.8.0/deps/curl/lib/curl_fnmatch.h0000644000000000000000000000336714121063461016623 0ustar rootroot#ifndef HEADER_CURL_FNMATCH_H #define HEADER_CURL_FNMATCH_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #define CURL_FNMATCH_MATCH 0 #define CURL_FNMATCH_NOMATCH 1 #define CURL_FNMATCH_FAIL 2 /* default pattern matching function * ================================= * Implemented with recursive backtracking, if you want to use Curl_fnmatch, * please note that there is not implemented UTF/UNICODE support. * * Implemented features: * '?' notation, does not match UTF characters * '*' can also work with UTF string * [a-zA-Z0-9] enumeration support * * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space * and upper (use as "[[:alnum:]]") */ int Curl_fnmatch(void *ptr, const char *pattern, const char *string); #endif /* HEADER_CURL_FNMATCH_H */ davix-0.8.0/deps/curl/lib/security.c0000644000000000000000000003613014121063461016012 0ustar rootroot/* This source code was modified by Martin Hedenfalk for * use in Curl. His latest changes were done 2000-09-18. * * It has since been patched and modified a lot by Daniel Stenberg * to make it better applied to curl conditions, and to make * it not use globals, pollute name space and more. This source code awaits a * rewrite to work around the paragraph 2 in the BSD licenses as explained * below. * * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * * Copyright (C) 2001 - 2019, Daniel Stenberg, , et al. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP #ifdef HAVE_GSSAPI #ifdef HAVE_NETDB_H #include #endif #include #include "urldata.h" #include "curl_base64.h" #include "curl_memory.h" #include "curl_sec.h" #include "ftp.h" #include "sendf.h" #include "strcase.h" #include "warnless.h" #include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" static const struct { enum protection_level level; const char *name; } level_names[] = { { PROT_CLEAR, "clear" }, { PROT_SAFE, "safe" }, { PROT_CONFIDENTIAL, "confidential" }, { PROT_PRIVATE, "private" } }; static enum protection_level name_to_level(const char *name) { int i; for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) if(checkprefix(name, level_names[i].name)) return level_names[i].level; return PROT_NONE; } /* Convert a protocol |level| to its char representation. We take an int to catch programming mistakes. */ static char level_to_char(int level) { switch(level) { case PROT_CLEAR: return 'C'; case PROT_SAFE: return 'S'; case PROT_CONFIDENTIAL: return 'E'; case PROT_PRIVATE: return 'P'; case PROT_CMD: /* Fall through */ default: /* Those 2 cases should not be reached! */ break; } DEBUGASSERT(0); /* Default to the most secure alternative. */ return 'P'; } /* Send an FTP command defined by |message| and the optional arguments. The function returns the ftp_code. If an error occurs, -1 is returned. */ static int ftp_send_command(struct connectdata *conn, const char *message, ...) { int ftp_code; ssize_t nread = 0; va_list args; char print_buffer[50]; va_start(args, message); mvsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); if(Curl_ftpsend(conn, print_buffer)) { ftp_code = -1; } else { if(Curl_GetFTPResponse(&nread, conn, &ftp_code)) ftp_code = -1; } (void)nread; /* Unused */ return ftp_code; } /* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode saying whether an error occurred or CURLE_OK if |len| was read. */ static CURLcode socket_read(curl_socket_t fd, void *to, size_t len) { char *to_p = to; CURLcode result; ssize_t nread = 0; while(len > 0) { result = Curl_read_plain(fd, to_p, len, &nread); if(!result) { len -= nread; to_p += nread; } else { if(result == CURLE_AGAIN) continue; return result; } } return CURLE_OK; } /* Write |len| bytes from the buffer |to| to the socket |fd|. Return a CURLcode saying whether an error occurred or CURLE_OK if |len| was written. */ static CURLcode socket_write(struct connectdata *conn, curl_socket_t fd, const void *to, size_t len) { const char *to_p = to; CURLcode result; ssize_t written; while(len > 0) { result = Curl_write_plain(conn, fd, to_p, len, &written); if(!result) { len -= written; to_p += written; } else { if(result == CURLE_AGAIN) continue; return result; } } return CURLE_OK; } static CURLcode read_data(struct connectdata *conn, curl_socket_t fd, struct krb5buffer *buf) { int len; CURLcode result; result = socket_read(fd, &len, sizeof(len)); if(result) return result; if(len) { /* only realloc if there was a length */ len = ntohl(len); buf->data = Curl_saferealloc(buf->data, len); } if(!len || !buf->data) return CURLE_OUT_OF_MEMORY; result = socket_read(fd, buf->data, len); if(result) return result; buf->size = conn->mech->decode(conn->app_data, buf->data, len, conn->data_prot, conn); buf->index = 0; return CURLE_OK; } static size_t buffer_read(struct krb5buffer *buf, void *data, size_t len) { if(buf->size - buf->index < len) len = buf->size - buf->index; memcpy(data, (char *)buf->data + buf->index, len); buf->index += len; return len; } /* Matches Curl_recv signature */ static ssize_t sec_recv(struct connectdata *conn, int sockindex, char *buffer, size_t len, CURLcode *err) { size_t bytes_read; size_t total_read = 0; curl_socket_t fd = conn->sock[sockindex]; *err = CURLE_OK; /* Handle clear text response. */ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) return sread(fd, buffer, len); if(conn->in_buffer.eof_flag) { conn->in_buffer.eof_flag = 0; return 0; } bytes_read = buffer_read(&conn->in_buffer, buffer, len); len -= bytes_read; total_read += bytes_read; buffer += bytes_read; while(len > 0) { if(read_data(conn, fd, &conn->in_buffer)) return -1; if(conn->in_buffer.size == 0) { if(bytes_read > 0) conn->in_buffer.eof_flag = 1; return bytes_read; } bytes_read = buffer_read(&conn->in_buffer, buffer, len); len -= bytes_read; total_read += bytes_read; buffer += bytes_read; } return total_read; } /* Send |length| bytes from |from| to the |fd| socket taking care of encoding and negotiating with the server. |from| can be NULL. */ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, const char *from, int length) { int bytes, htonl_bytes; /* 32-bit integers for htonl */ char *buffer = NULL; char *cmd_buffer; size_t cmd_size = 0; CURLcode error; enum protection_level prot_level = conn->data_prot; bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); if(iscmd) { if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5)) prot_level = PROT_PRIVATE; else prot_level = conn->command_prot; } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, (void **)&buffer); if(!buffer || bytes <= 0) return; /* error */ if(iscmd) { error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes), &cmd_buffer, &cmd_size); if(error) { free(buffer); return; /* error */ } if(cmd_size > 0) { static const char *enc = "ENC "; static const char *mic = "MIC "; if(prot_level == PROT_PRIVATE) socket_write(conn, fd, enc, 4); else socket_write(conn, fd, mic, 4); socket_write(conn, fd, cmd_buffer, cmd_size); socket_write(conn, fd, "\r\n", 2); infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, cmd_buffer); free(cmd_buffer); } } else { htonl_bytes = htonl(bytes); socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); socket_write(conn, fd, buffer, curlx_sitouz(bytes)); } free(buffer); } static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd, const char *buffer, size_t length) { ssize_t tx = 0, len = conn->buffer_size; len -= conn->mech->overhead(conn->app_data, conn->data_prot, curlx_sztosi(len)); if(len <= 0) len = length; while(length) { if(length < (size_t)len) len = length; do_sec_send(conn, fd, buffer, curlx_sztosi(len)); length -= len; buffer += len; tx += len; } return tx; } /* Matches Curl_send signature */ static ssize_t sec_send(struct connectdata *conn, int sockindex, const void *buffer, size_t len, CURLcode *err) { curl_socket_t fd = conn->sock[sockindex]; *err = CURLE_OK; return sec_write(conn, fd, buffer, len); } int Curl_sec_read_msg(struct connectdata *conn, char *buffer, enum protection_level level) { /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an int */ int decoded_len; char *buf; int ret_code = 0; size_t decoded_sz = 0; CURLcode error; if(!conn->mech) /* not inititalized, return error */ return -1; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); if(error || decoded_sz == 0) return -1; if(decoded_sz > (size_t)INT_MAX) { free(buf); return -1; } decoded_len = curlx_uztosi(decoded_sz); decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, level, conn); if(decoded_len <= 0) { free(buf); return -1; } if(conn->data->set.verbose) { buf[decoded_len] = '\n'; Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1); } buf[decoded_len] = '\0'; if(decoded_len <= 3) /* suspiciously short */ return 0; if(buf[3] != '-') /* safe to ignore return code */ (void)sscanf(buf, "%d", &ret_code); if(buf[decoded_len - 1] == '\n') buf[decoded_len - 1] = '\0'; strcpy(buffer, buf); free(buf); return ret_code; } static int sec_set_protection_level(struct connectdata *conn) { int code; enum protection_level level = conn->request_data_prot; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); if(!conn->sec_complete) { infof(conn->data, "Trying to change the protection level after the" " completion of the data exchange.\n"); return -1; } /* Bail out if we try to set up the same level */ if(conn->data_prot == level) return 0; if(level) { char *pbsz; static unsigned int buffer_size = 1 << 20; /* 1048576 */ code = ftp_send_command(conn, "PBSZ %u", buffer_size); if(code < 0) return -1; if(code/100 != 2) { failf(conn->data, "Failed to set the protection's buffer size."); return -1; } conn->buffer_size = buffer_size; pbsz = strstr(conn->data->state.buffer, "PBSZ="); if(pbsz) { /* ignore return code, use default value if it fails */ (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; } } /* Now try to negiociate the protection level. */ code = ftp_send_command(conn, "PROT %c", level_to_char(level)); if(code < 0) return -1; if(code/100 != 2) { failf(conn->data, "Failed to set the protection level."); return -1; } conn->data_prot = level; if(level == PROT_PRIVATE) conn->command_prot = level; return 0; } int Curl_sec_request_prot(struct connectdata *conn, const char *level) { enum protection_level l = name_to_level(level); if(l == PROT_NONE) return -1; DEBUGASSERT(l > PROT_NONE && l < PROT_LAST); conn->request_data_prot = l; return 0; } static CURLcode choose_mech(struct connectdata *conn) { int ret; struct Curl_easy *data = conn->data; void *tmp_allocation; const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; tmp_allocation = realloc(conn->app_data, mech->size); if(tmp_allocation == NULL) { failf(data, "Failed realloc of size %zu", mech->size); mech = NULL; return CURLE_OUT_OF_MEMORY; } conn->app_data = tmp_allocation; if(mech->init) { ret = mech->init(conn->app_data); if(ret) { infof(data, "Failed initialization for %s. Skipping it.\n", mech->name); return CURLE_FAILED_INIT; } } infof(data, "Trying mechanism %s...\n", mech->name); ret = ftp_send_command(conn, "AUTH %s", mech->name); if(ret < 0) return CURLE_COULDNT_CONNECT; if(ret/100 != 3) { switch(ret) { case 504: infof(data, "Mechanism %s is not supported by the server (server " "returned ftp code: 504).\n", mech->name); break; case 534: infof(data, "Mechanism %s was rejected by the server (server returned " "ftp code: 534).\n", mech->name); break; default: if(ret/100 == 5) { infof(data, "server does not support the security extensions\n"); return CURLE_USE_SSL_FAILED; } break; } return CURLE_LOGIN_DENIED; } /* Authenticate */ ret = mech->auth(conn->app_data, conn); if(ret != AUTH_CONTINUE) { if(ret != AUTH_OK) { /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } DEBUGASSERT(ret == AUTH_OK); conn->mech = mech; conn->sec_complete = 1; conn->recv[FIRSTSOCKET] = sec_recv; conn->send[FIRSTSOCKET] = sec_send; conn->recv[SECONDARYSOCKET] = sec_recv; conn->send[SECONDARYSOCKET] = sec_send; conn->command_prot = PROT_SAFE; /* Set the requested protection level */ /* BLOCKING */ (void)sec_set_protection_level(conn); } return CURLE_OK; } CURLcode Curl_sec_login(struct connectdata *conn) { return choose_mech(conn); } void Curl_sec_end(struct connectdata *conn) { if(conn->mech != NULL && conn->mech->end) conn->mech->end(conn->app_data); free(conn->app_data); conn->app_data = NULL; if(conn->in_buffer.data) { free(conn->in_buffer.data); conn->in_buffer.data = NULL; conn->in_buffer.size = 0; conn->in_buffer.index = 0; conn->in_buffer.eof_flag = 0; } conn->sec_complete = 0; conn->data_prot = PROT_CLEAR; conn->mech = NULL; } #endif /* HAVE_GSSAPI */ #endif /* CURL_DISABLE_FTP */ davix-0.8.0/deps/curl/lib/.gitattributes0000644000000000000000000000002414121063461016663 0ustar rootrootobjnames.inc eol=lf davix-0.8.0/deps/curl/lib/psl.h0000644000000000000000000000321014121063461014737 0ustar rootroot#ifndef HEADER_PSL_H #define HEADER_PSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #ifdef USE_LIBPSL #include #define PSL_TTL (72 * 3600) /* PSL time to live before a refresh. */ struct PslCache { const psl_ctx_t *psl; /* The PSL. */ time_t expires; /* Time this PSL life expires. */ bool dynamic; /* PSL should be released when no longer needed. */ }; const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy); void Curl_psl_release(struct Curl_easy *easy); void Curl_psl_destroy(struct PslCache *pslcache); #else #define Curl_psl_use(easy) NULL #define Curl_psl_release(easy) #define Curl_psl_destroy(pslcache) #endif /* USE_LIBPSL */ #endif /* HEADER_PSL_H */ davix-0.8.0/deps/curl/src/0000755000000000000000000000000014121063461014015 5ustar rootrootdavix-0.8.0/deps/curl/src/tool_cb_rea.c0000644000000000000000000000447214121063461016440 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_cb_rea.h" #include "tool_operate.h" #include "memdebug.h" /* keep this as LAST include */ /* ** callback for CURLOPT_READFUNCTION */ size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) { ssize_t rc; struct InStruct *in = userdata; rc = read(in->fd, buffer, sz*nmemb); if(rc < 0) { if(errno == EAGAIN) { errno = 0; in->config->readbusy = TRUE; return CURL_READFUNC_PAUSE; } /* since size_t is unsigned we can't return negative values fine */ rc = 0; } in->config->readbusy = FALSE; return (size_t)rc; } /* ** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads */ int tool_readbusy_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { struct per_transfer *per = clientp; struct OperationConfig *config = per->config; (void)dltotal; /* unused */ (void)dlnow; /* unused */ (void)ultotal; /* unused */ (void)ulnow; /* unused */ if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(per->curl, CURLPAUSE_CONT); } return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE; } davix-0.8.0/deps/curl/src/tool_main.h0000644000000000000000000000304114121063461016145 0ustar rootroot#ifndef HEADER_CURL_TOOL_MAIN_H #define HEADER_CURL_TOOL_MAIN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define DEFAULT_MAXREDIRS 50L #define RETRY_SLEEP_DEFAULT 1000L /* ms */ #define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */ #define MAX_PARALLEL 300 /* conservative */ #define PARALLEL_DEFAULT 50 #ifndef STDIN_FILENO # define STDIN_FILENO fileno(stdin) #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO fileno(stdout) #endif #ifndef STDERR_FILENO # define STDERR_FILENO fileno(stderr) #endif #endif /* HEADER_CURL_TOOL_MAIN_H */ davix-0.8.0/deps/curl/src/Makefile.am0000644000000000000000000001271714121063461016061 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### AUTOMAKE_OPTIONS = foreign nostdinc # remove targets if the command fails .DELETE_ON_ERROR: # Specify our include paths here, and do it relative to $(top_srcdir) and # $(top_builddir), to ensure that these paths which belong to the library # being currently built and tested are searched before the library which # might possibly already be installed in the system. # # $(top_srcdir)/include is for libcurl's external include files # $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file # $(top_builddir)/src is for curl's generated src/curl_config.h file # $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files # $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_builddir)/lib \ -I$(top_builddir)/src \ -I$(top_srcdir)/lib \ -I$(top_srcdir)/src bin_PROGRAMS = curl SUBDIRS = ../docs if USE_CPPFLAG_CURL_STATICLIB AM_CPPFLAGS += -DCURL_STATICLIB endif include Makefile.inc # CURL_FILES comes from Makefile.inc curl_SOURCES = $(CURL_FILES) # This might hold -Werror CFLAGS += @CURL_CFLAG_EXTRAS@ # Prevent LIBS from being used for all link targets LIBS = $(BLANK_AT_MAKETIME) if USE_EXPLICIT_LIB_DEPS curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@ else curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @NSS_LIBS@ @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ endif curl_LDFLAGS = @LIBMETALINK_LDFLAGS@ curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBMETALINK_CPPFLAGS) # if unit tests are enabled, build a static library to link them with if BUILD_UNITTESTS noinst_LTLIBRARIES = libcurltool.la libcurltool_la_CPPFLAGS = $(LIBMETALINK_CPPFLAGS) $(AM_CPPFLAGS) \ -DCURL_STATICLIB -DUNITTESTS libcurltool_la_CFLAGS = libcurltool_la_LDFLAGS = -static $(LINKFLAGS) libcurltool_la_SOURCES = $(curl_SOURCES) endif CLEANFILES = tool_hugehelp.c # Use the C locale to ensure that only ASCII characters appear in the # embedded text. NROFF=env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script EXTRA_DIST = mkhelp.pl makefile.dj \ Makefile.m32 macos/curl.mcp.xml.sit.hqx macos/MACINSTALL.TXT \ macos/src/curl_GUSIConfig.cpp macos/src/macos_main.cpp makefile.amiga \ curl.rc Makefile.netware Makefile.inc Makefile.Watcom CMakeLists.txt # Use absolute directory to disable VPATH MANPAGE=$(abs_top_builddir)/docs/curl.1 MKHELP=$(top_srcdir)/src/mkhelp.pl HUGE=tool_hugehelp.c HUGECMD = $(HUGEIT_$(V)) HUGEIT_0 = @echo " HUGE " $@; HUGEIT_1 = HUGEIT_ = $(HUGEIT_0) CHECKSRC = $(CS_$(V)) CS_0 = @echo " RUN " $@; CS_1 = CS_ = $(CS_0) if USE_MANUAL # Here are the stuff to create a built-in manual $(MANPAGE): cd $(top_builddir)/docs && $(MAKE) if HAVE_LIBZ # This generates the tool_hugehelp.c file in both uncompressed and # compressed formats. $(HUGE): $(MANPAGE) $(MKHELP) $(HUGECMD) (echo '#include "tool_setup.h"' > $(HUGE); \ echo '#ifndef HAVE_LIBZ' >> $(HUGE); \ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE); \ echo '#else' >> $(HUGE); \ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c >> $(HUGE); \ echo '#endif /* HAVE_LIBZ */' >> $(HUGE) ) else # HAVE_LIBZ # This generates the tool_hugehelp.c file uncompressed only $(HUGE): $(MANPAGE) $(MKHELP) $(HUGECMD)(echo '#include "tool_setup.h"' > $(HUGE); \ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) >> $(HUGE) ) endif else # USE_MANUAL # built-in manual has been disabled, make a blank file $(HUGE): $(HUGECMD)(echo "/* built-in manual is disabled, blank function */" > $(HUGE); \ echo '#include "tool_hugehelp.h"' >> $(HUGE); \ echo "void hugehelp(void) {}" >>$(HUGE) ) endif # ignore tool_hugehelp.c since it is generated source code and it plays # by slightly different rules! checksrc: $(CHECKSRC)(@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(srcdir) \ -W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch]) if CURLDEBUG # for debug builds, we scan the sources on all regular make invokes all-local: checksrc endif # disable the tests that are mostly causing false positives TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference TIDY:=clang-tidy tidy: $(TIDY) $(CURL_CFILES) $(TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H davix-0.8.0/deps/curl/src/CMakeLists.txt0000644000000000000000000000613514121063461016562 0ustar rootrootset(EXE_NAME curl) if(USE_MANUAL) # Use the C locale to ensure that only ASCII characters appear in the # embedded text. NROFF and MANOPT are set in the parent CMakeLists.txt add_custom_command( OUTPUT tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_setup.h\"" > tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "#ifndef HAVE_LIBZ" >> tool_hugehelp.c COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} "${CURL_BINARY_DIR}/docs/curl.1" | "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" >> tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "#else" >> tool_hugehelp.c COMMAND env LC_ALL=C "${NROFF}" ${NROFF_MANOPT} "${CURL_BINARY_DIR}/docs/curl.1" | "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c >> tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "#endif /* HAVE_LIBZ */" >> tool_hugehelp.c DEPENDS generate-curl.1 "${CURL_BINARY_DIR}/docs/curl.1" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" VERBATIM) else() add_custom_command( OUTPUT tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "/* built-in manual is disabled, blank function */" > tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_hugehelp.h\"" >> tool_hugehelp.c COMMAND ${CMAKE_COMMAND} -E echo "void hugehelp(void) {}" >> tool_hugehelp.c DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h" VERBATIM) endif() transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) if(MSVC) list(APPEND CURL_FILES curl.rc) endif() # CURL_FILES comes from Makefile.inc add_executable( ${EXE_NAME} ${CURL_FILES} ) if(CURL_HAS_LTO) set_target_properties(${EXE_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) endif() source_group("curlX source files" FILES ${CURLX_CFILES}) source_group("curl source files" FILES ${CURL_CFILES}) source_group("curl header files" FILES ${CURL_HFILES}) include_directories( ${CURL_SOURCE_DIR}/lib # To be able to reach "curl_setup_once.h" ${CURL_BINARY_DIR}/lib # To be able to reach "curl_config.h" ${CURL_BINARY_DIR}/include # To be able to reach "curl/curl.h" # This is needed as tool_hugehelp.c is generated in the binary dir ${CURL_SOURCE_DIR}/src # To be able to reach "tool_hugehelp.h" ) #Build curl executable target_link_libraries(${EXE_NAME} libcurl ${CURL_LIBS}) ################################################################################ #SET_TARGET_PROPERTIES(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah") #SET_TARGET_PROPERTIES(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah") #SET_TARGET_PROPERTIES(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah") #INCLUDE(ModuleInstall OPTIONAL) install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) export(TARGETS ${EXE_NAME} APPEND FILE ${PROJECT_BINARY_DIR}/curl-target.cmake NAMESPACE CURL:: ) davix-0.8.0/deps/curl/src/tool_help.h0000644000000000000000000000232314121063461016153 0ustar rootroot#ifndef HEADER_CURL_TOOL_HELP_H #define HEADER_CURL_TOOL_HELP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" void tool_help(void); void tool_list_engines(void); void tool_version_info(void); #endif /* HEADER_CURL_TOOL_HELP_H */ davix-0.8.0/deps/curl/src/tool_formparse.c0000644000000000000000000006176414121063461017232 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_convert.h" #include "tool_msgs.h" #include "tool_binmode.h" #include "tool_getparam.h" #include "tool_paramhlp.h" #include "tool_formparse.h" #include "memdebug.h" /* keep this as LAST include */ /* Macros to free const pointers. */ #define CONST_FREE(x) free((void *) (x)) #define CONST_SAFEFREE(x) Curl_safefree(*((void **) &(x))) /* tool_mime functions. */ static tool_mime *tool_mime_new(tool_mime *parent, toolmimekind kind) { tool_mime *m = (tool_mime *) calloc(1, sizeof(*m)); if(m) { m->kind = kind; m->parent = parent; if(parent) { m->prev = parent->subparts; parent->subparts = m; } } return m; } static tool_mime *tool_mime_new_parts(tool_mime *parent) { return tool_mime_new(parent, TOOLMIME_PARTS); } static tool_mime *tool_mime_new_data(tool_mime *parent, const char *data) { tool_mime *m = NULL; data = strdup(data); if(data) { m = tool_mime_new(parent, TOOLMIME_DATA); if(!m) CONST_FREE(data); else m->data = data; } return m; } static tool_mime *tool_mime_new_filedata(tool_mime *parent, const char *filename, bool isremotefile, CURLcode *errcode) { CURLcode result = CURLE_OK; tool_mime *m = NULL; *errcode = CURLE_OUT_OF_MEMORY; if(strcmp(filename, "-")) { /* This is a normal file. */ filename = strdup(filename); if(filename) { m = tool_mime_new(parent, TOOLMIME_FILE); if(!m) CONST_FREE(filename); else { m->data = filename; if(!isremotefile) m->kind = TOOLMIME_FILEDATA; *errcode = CURLE_OK; } } } else { /* Standard input. */ int fd = fileno(stdin); char *data = NULL; curl_off_t size; curl_off_t origin; struct_stat sbuf; set_binmode(stdin); origin = ftell(stdin); /* If stdin is a regular file, do not buffer data but read it when needed. */ if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) && #ifdef __VMS sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC && #endif S_ISREG(sbuf.st_mode)) { size = sbuf.st_size - origin; if(size < 0) size = 0; } else { /* Not suitable for direct use, buffer stdin data. */ size_t stdinsize = 0; if(file2memory(&data, &stdinsize, stdin) != PARAM_OK) { /* Out of memory. */ return m; } if(ferror(stdin)) { result = CURLE_READ_ERROR; Curl_safefree(data); data = NULL; } else if(!stdinsize) { /* Zero-length data has been freed. Re-create it. */ data = strdup(""); if(!data) return m; } size = curlx_uztoso(stdinsize); origin = 0; } m = tool_mime_new(parent, TOOLMIME_STDIN); if(!m) Curl_safefree(data); else { m->data = data; m->origin = origin; m->size = size; m->curpos = 0; if(!isremotefile) m->kind = TOOLMIME_STDINDATA; *errcode = result; } } return m; } void tool_mime_free(tool_mime *mime) { if(mime) { if(mime->subparts) tool_mime_free(mime->subparts); if(mime->prev) tool_mime_free(mime->prev); CONST_SAFEFREE(mime->name); CONST_SAFEFREE(mime->filename); CONST_SAFEFREE(mime->type); CONST_SAFEFREE(mime->encoder); CONST_SAFEFREE(mime->data); curl_slist_free_all(mime->headers); free(mime); } } /* Mime part callbacks for stdin. */ size_t tool_mime_stdin_read(char *buffer, size_t size, size_t nitems, void *arg) { tool_mime *sip = (tool_mime *) arg; curl_off_t bytesleft; (void) size; /* Always 1: ignored. */ if(sip->size >= 0) { if(sip->curpos >= sip->size) return 0; /* At eof. */ bytesleft = sip->size - sip->curpos; if(curlx_uztoso(nitems) > bytesleft) nitems = curlx_sotouz(bytesleft); } if(nitems) { if(sip->data) { /* Return data from memory. */ memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems); } else { /* Read from stdin. */ nitems = fread(buffer, 1, nitems, stdin); if(ferror(stdin)) { /* Show error only once. */ if(sip->config) { warnf(sip->config, "stdin: %s\n", strerror(errno)); sip->config = NULL; } return CURL_READFUNC_ABORT; } } sip->curpos += curlx_uztoso(nitems); } return nitems; } int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence) { tool_mime *sip = (tool_mime *) instream; switch(whence) { case SEEK_CUR: offset += sip->curpos; break; case SEEK_END: offset += sip->size; break; } if(offset < 0) return CURL_SEEKFUNC_CANTSEEK; if(!sip->data) { if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET)) return CURL_SEEKFUNC_CANTSEEK; } sip->curpos = offset; return CURL_SEEKFUNC_OK; } /* Translate an internal mime tree into a libcurl mime tree. */ static CURLcode tool2curlparts(CURL *curl, tool_mime *m, curl_mime *mime) { CURLcode ret = CURLE_OK; curl_mimepart *part = NULL; curl_mime *submime = NULL; const char *filename = NULL; if(m) { ret = tool2curlparts(curl, m->prev, mime); if(!ret) { part = curl_mime_addpart(mime); if(!part) ret = CURLE_OUT_OF_MEMORY; } if(!ret) { filename = m->filename; switch(m->kind) { case TOOLMIME_PARTS: ret = tool2curlmime(curl, m, &submime); if(!ret) { ret = curl_mime_subparts(part, submime); if(ret) curl_mime_free(submime); } break; case TOOLMIME_DATA: #ifdef CURL_DOES_CONVERSIONS /* Our data is always textual: convert it to ASCII. */ { size_t size = strlen(m->data); char *cp = malloc(size + 1); if(!cp) ret = CURLE_OUT_OF_MEMORY; else { memcpy(cp, m->data, size + 1); ret = convert_to_network(cp, size); if(!ret) ret = curl_mime_data(part, cp, CURL_ZERO_TERMINATED); free(cp); } } #else ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED); #endif break; case TOOLMIME_FILE: case TOOLMIME_FILEDATA: ret = curl_mime_filedata(part, m->data); if(!ret && m->kind == TOOLMIME_FILEDATA && !filename) ret = curl_mime_filename(part, NULL); break; case TOOLMIME_STDIN: if(!filename) filename = "-"; /* FALLTHROUGH */ case TOOLMIME_STDINDATA: ret = curl_mime_data_cb(part, m->size, (curl_read_callback) tool_mime_stdin_read, (curl_seek_callback) tool_mime_stdin_seek, NULL, m); break; default: /* Other cases not possible in this context. */ break; } } if(!ret && filename) ret = curl_mime_filename(part, filename); if(!ret) ret = curl_mime_type(part, m->type); if(!ret) ret = curl_mime_headers(part, m->headers, 0); if(!ret) ret = curl_mime_encoder(part, m->encoder); if(!ret) ret = curl_mime_name(part, m->name); } return ret; } CURLcode tool2curlmime(CURL *curl, tool_mime *m, curl_mime **mime) { CURLcode ret = CURLE_OK; *mime = curl_mime_init(curl); if(!*mime) ret = CURLE_OUT_OF_MEMORY; else ret = tool2curlparts(curl, m->subparts, *mime); if(ret) { curl_mime_free(*mime); *mime = NULL; } return ret; } /* * helper function to get a word from form param * after call get_parm_word, str either point to string end * or point to any of end chars. */ static char *get_param_word(char **str, char **end_pos, char endchar) { char *ptr = *str; /* the first non-space char is here */ char *word_begin = ptr; char *ptr2; char *escape = NULL; if(*ptr == '"') { ++ptr; while(*ptr) { if(*ptr == '\\') { if(ptr[1] == '\\' || ptr[1] == '"') { /* remember the first escape position */ if(!escape) escape = ptr; /* skip escape of back-slash or double-quote */ ptr += 2; continue; } } if(*ptr == '"') { *end_pos = ptr; if(escape) { /* has escape, we restore the unescaped string here */ ptr = ptr2 = escape; do { if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) ++ptr; *ptr2++ = *ptr++; } while(ptr < *end_pos); *end_pos = ptr2; } while(*ptr && *ptr != ';' && *ptr != endchar) ++ptr; *str = ptr; return word_begin + 1; } ++ptr; } /* end quote is missing, treat it as non-quoted. */ ptr = word_begin; } while(*ptr && *ptr != ';' && *ptr != endchar) ++ptr; *str = *end_pos = ptr; return word_begin; } /* Append slist item and return -1 if failed. */ static int slist_append(struct curl_slist **plist, const char *data) { struct curl_slist *s = curl_slist_append(*plist, data); if(!s) return -1; *plist = s; return 0; } /* Read headers from a file and append to list. */ static int read_field_headers(struct OperationConfig *config, const char *filename, FILE *fp, struct curl_slist **pheaders) { size_t hdrlen = 0; size_t pos = 0; bool incomment = FALSE; int lineno = 1; char hdrbuf[999]; /* Max. header length + 1. */ for(;;) { int c = getc(fp); if(c == EOF || (!pos && !ISSPACE(c))) { /* Strip and flush the current header. */ while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) hdrlen--; if(hdrlen) { hdrbuf[hdrlen] = '\0'; if(slist_append(pheaders, hdrbuf)) { fprintf(config->global->errors, "Out of memory for field headers!\n"); return -1; } hdrlen = 0; } } switch(c) { case EOF: if(ferror(fp)) { fprintf(config->global->errors, "Header file %s read error: %s\n", filename, strerror(errno)); return -1; } return 0; /* Done. */ case '\r': continue; /* Ignore. */ case '\n': pos = 0; incomment = FALSE; lineno++; continue; case '#': if(!pos) incomment = TRUE; break; } pos++; if(!incomment) { if(hdrlen == sizeof(hdrbuf) - 1) { warnf(config->global, "File %s line %d: header too long (truncated)\n", filename, lineno); c = ' '; } if(hdrlen <= sizeof(hdrbuf) - 1) hdrbuf[hdrlen++] = (char) c; } } /* NOTREACHED */ } static int get_param_part(struct OperationConfig *config, char endchar, char **str, char **pdata, char **ptype, char **pfilename, char **pencoder, struct curl_slist **pheaders) { char *p = *str; char *type = NULL; char *filename = NULL; char *encoder = NULL; char *endpos; char *tp; char sep; char type_major[128] = ""; char type_minor[128] = ""; char *endct = NULL; struct curl_slist *headers = NULL; if(ptype) *ptype = NULL; if(pfilename) *pfilename = NULL; if(pheaders) *pheaders = NULL; if(pencoder) *pencoder = NULL; while(ISSPACE(*p)) p++; tp = p; *pdata = get_param_word(&p, &endpos, endchar); /* If not quoted, strip trailing spaces. */ if(*pdata == tp) while(endpos > *pdata && ISSPACE(endpos[-1])) endpos--; sep = *p; *endpos = '\0'; while(sep == ';') { while(ISSPACE(*++p)) ; if(!endct && checkprefix("type=", p)) { for(p += 5; ISSPACE(*p); p++) ; /* set type pointer */ type = p; /* verify that this is a fine type specifier */ if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) { warnf(config->global, "Illegally formatted content-type field!\n"); curl_slist_free_all(headers); return -1; /* illegal content-type syntax! */ } /* now point beyond the content-type specifier */ p = type + strlen(type_major) + strlen(type_minor) + 1; for(endct = p; *p && *p != ';' && *p != endchar; p++) if(!ISSPACE(*p)) endct = p + 1; sep = *p; } else if(checkprefix("filename=", p)) { if(endct) { *endct = '\0'; endct = NULL; } for(p += 9; ISSPACE(*p); p++) ; tp = p; filename = get_param_word(&p, &endpos, endchar); /* If not quoted, strip trailing spaces. */ if(filename == tp) while(endpos > filename && ISSPACE(endpos[-1])) endpos--; sep = *p; *endpos = '\0'; } else if(checkprefix("headers=", p)) { if(endct) { *endct = '\0'; endct = NULL; } p += 8; if(*p == '@' || *p == '<') { char *hdrfile; FILE *fp; /* Read headers from a file. */ do { p++; } while(ISSPACE(*p)); tp = p; hdrfile = get_param_word(&p, &endpos, endchar); /* If not quoted, strip trailing spaces. */ if(hdrfile == tp) while(endpos > hdrfile && ISSPACE(endpos[-1])) endpos--; sep = *p; *endpos = '\0'; fp = fopen(hdrfile, FOPEN_READTEXT); if(!fp) warnf(config->global, "Cannot read from %s: %s\n", hdrfile, strerror(errno)); else { int i = read_field_headers(config, hdrfile, fp, &headers); fclose(fp); if(i) { curl_slist_free_all(headers); return -1; } } } else { char *hdr; while(ISSPACE(*p)) p++; tp = p; hdr = get_param_word(&p, &endpos, endchar); /* If not quoted, strip trailing spaces. */ if(hdr == tp) while(endpos > hdr && ISSPACE(endpos[-1])) endpos--; sep = *p; *endpos = '\0'; if(slist_append(&headers, hdr)) { fprintf(config->global->errors, "Out of memory for field header!\n"); curl_slist_free_all(headers); return -1; } } } else if(checkprefix("encoder=", p)) { if(endct) { *endct = '\0'; endct = NULL; } for(p += 8; ISSPACE(*p); p++) ; tp = p; encoder = get_param_word(&p, &endpos, endchar); /* If not quoted, strip trailing spaces. */ if(encoder == tp) while(endpos > encoder && ISSPACE(endpos[-1])) endpos--; sep = *p; *endpos = '\0'; } else if(endct) { /* This is part of content type. */ for(endct = p; *p && *p != ';' && *p != endchar; p++) if(!ISSPACE(*p)) endct = p + 1; sep = *p; } else { /* unknown prefix, skip to next block */ char *unknown = get_param_word(&p, &endpos, endchar); sep = *p; *endpos = '\0'; if(*unknown) warnf(config->global, "skip unknown form field: %s\n", unknown); } } /* Terminate content type. */ if(endct) *endct = '\0'; if(ptype) *ptype = type; else if(type) warnf(config->global, "Field content type not allowed here: %s\n", type); if(pfilename) *pfilename = filename; else if(filename) warnf(config->global, "Field file name not allowed here: %s\n", filename); if(pencoder) *pencoder = encoder; else if(encoder) warnf(config->global, "Field encoder not allowed here: %s\n", encoder); if(pheaders) *pheaders = headers; else if(headers) { warnf(config->global, "Field headers not allowed here: %s\n", headers->data); curl_slist_free_all(headers); } *str = p; return sep & 0xFF; } /*************************************************************************** * * formparse() * * Reads a 'name=value' parameter and builds the appropriate linked list. * * If the value is of the form ''. * * If literal_value is set, any initial '@' or '<' in the value string * loses its special meaning, as does any embedded ';type='. * * You may specify more than one file for a single name (field). Specify * multiple files by writing it like: * * 'name=@filename,filename2,filename3' * * or use double-quotes quote the filename: * * 'name=@"filename","filename2","filename3"' * * If you want content-types specified for each too, write them like: * * 'name=@filename;type=image/gif,filename2,filename3' * * If you want custom headers added for a single part, write them in a separate * file and do like this: * * 'name=foo;headers=@headerfile' or why not * 'name=@filemame;headers=@headerfile' * * To upload a file, but to fake the file name that will be included in the * formpost, do like this: * * 'name=@filename;filename=/dev/null' or quote the faked filename like: * 'name=@filename;filename="play, play, and play.txt"' * * If filename/path contains ',' or ';', it must be quoted by double-quotes, * else curl will fail to figure out the correct filename. if the filename * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash. * ***************************************************************************/ /* Convenience macros for null pointer check. */ #define NULL_CHECK(ptr, init, retcode) { \ (ptr) = (init); \ if(!(ptr)) { \ warnf(config->global, "out of memory!\n"); \ curl_slist_free_all(headers); \ Curl_safefree(contents); \ return retcode; \ } \ } #define SET_TOOL_MIME_PTR(m, field, retcode) { \ if(field) \ NULL_CHECK((m)->field, strdup(field), retcode); \ } int formparse(struct OperationConfig *config, const char *input, tool_mime **mimeroot, tool_mime **mimecurrent, bool literal_value) { /* input MUST be a string in the format 'name=contents' and we'll build a linked list with the info */ char *name = NULL; char *contents = NULL; char *contp; char *data; char *type = NULL; char *filename = NULL; char *encoder = NULL; struct curl_slist *headers = NULL; tool_mime *part = NULL; CURLcode res; /* Allocate the main mime structure if needed. */ if(!*mimecurrent) { NULL_CHECK(*mimeroot, tool_mime_new_parts(NULL), 1); *mimecurrent = *mimeroot; } /* Make a copy we can overwrite. */ NULL_CHECK(contents, strdup(input), 2); /* Scan for the end of the name. */ contp = strchr(contents, '='); if(contp) { int sep = '\0'; if(contp > contents) name = contents; *contp++ = '\0'; if(*contp == '(' && !literal_value) { /* Starting a multipart. */ sep = get_param_part(config, '\0', &contp, &data, &type, NULL, NULL, &headers); if(sep < 0) { Curl_safefree(contents); return 3; } NULL_CHECK(part, tool_mime_new_parts(*mimecurrent), 4); *mimecurrent = part; part->headers = headers; headers = NULL; SET_TOOL_MIME_PTR(part, type, 5); } else if(!name && !strcmp(contp, ")") && !literal_value) { /* Ending a multipart. */ if(*mimecurrent == *mimeroot) { warnf(config->global, "no multipart to terminate!\n"); Curl_safefree(contents); return 6; } *mimecurrent = (*mimecurrent)->parent; } else if('@' == contp[0] && !literal_value) { /* we use the @-letter to indicate file name(s) */ tool_mime *subparts = NULL; do { /* since this was a file, it may have a content-type specifier at the end too, or a filename. Or both. */ ++contp; sep = get_param_part(config, ',', &contp, &data, &type, &filename, &encoder, &headers); if(sep < 0) { Curl_safefree(contents); return 7; } /* now contp point to comma or string end. If more files to come, make sure we have multiparts. */ if(!subparts) { if(sep != ',') /* If there is a single file. */ subparts = *mimecurrent; else NULL_CHECK(subparts, tool_mime_new_parts(*mimecurrent), 8); } /* Store that file in a part. */ NULL_CHECK(part, tool_mime_new_filedata(subparts, data, TRUE, &res), 9); part->headers = headers; headers = NULL; part->config = config->global; if(res == CURLE_READ_ERROR) { /* An error occurred while reading stdin: if read has started, issue the error now. Else, delay it until processed by libcurl. */ if(part->size > 0) { warnf(config->global, "error while reading standard input\n"); Curl_safefree(contents); return 10; } CONST_SAFEFREE(part->data); part->data = NULL; part->size = -1; res = CURLE_OK; } SET_TOOL_MIME_PTR(part, filename, 11); SET_TOOL_MIME_PTR(part, type, 12); SET_TOOL_MIME_PTR(part, encoder, 13); /* *contp could be '\0', so we just check with the delimiter */ } while(sep); /* loop if there's another file name */ part = (*mimecurrent)->subparts; /* Set name on group. */ } else { if(*contp == '<' && !literal_value) { ++contp; sep = get_param_part(config, '\0', &contp, &data, &type, NULL, &encoder, &headers); if(sep < 0) { Curl_safefree(contents); return 14; } NULL_CHECK(part, tool_mime_new_filedata(*mimecurrent, data, FALSE, &res), 15); part->headers = headers; headers = NULL; part->config = config->global; if(res == CURLE_READ_ERROR) { /* An error occurred while reading stdin: if read has started, issue the error now. Else, delay it until processed by libcurl. */ if(part->size > 0) { warnf(config->global, "error while reading standard input\n"); Curl_safefree(contents); return 16; } CONST_SAFEFREE(part->data); part->data = NULL; part->size = -1; res = CURLE_OK; } } else { if(literal_value) data = contp; else { sep = get_param_part(config, '\0', &contp, &data, &type, &filename, &encoder, &headers); if(sep < 0) { Curl_safefree(contents); return 17; } } NULL_CHECK(part, tool_mime_new_data(*mimecurrent, data), 18); part->headers = headers; headers = NULL; } SET_TOOL_MIME_PTR(part, filename, 19); SET_TOOL_MIME_PTR(part, type, 20); SET_TOOL_MIME_PTR(part, encoder, 21); if(sep) { *contp = (char) sep; warnf(config->global, "garbage at end of field specification: %s\n", contp); } } /* Set part name. */ SET_TOOL_MIME_PTR(part, name, 22); } else { warnf(config->global, "Illegally formatted input field!\n"); Curl_safefree(contents); return 23; } Curl_safefree(contents); return 0; } davix-0.8.0/deps/curl/src/tool_binmode.h0000644000000000000000000000240714121063461016643 0ustar rootroot#ifndef HEADER_CURL_TOOL_BINMODE_H #define HEADER_CURL_TOOL_BINMODE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_SETMODE void set_binmode(FILE *stream); #else #define set_binmode(x) Curl_nop_stmt #endif /* HAVE_SETMODE */ #endif /* HEADER_CURL_TOOL_BINMODE_H */ davix-0.8.0/deps/curl/src/tool_cb_see.h0000644000000000000000000000277414121063461016455 0ustar rootroot#ifndef HEADER_CURL_TOOL_CB_SEE_H #define HEADER_CURL_TOOL_CB_SEE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(WIN32) && !defined(__MINGW64__) int tool_ftruncate64(int fd, curl_off_t where); #undef ftruncate #define ftruncate(fd,where) tool_ftruncate64(fd,where) #ifndef HAVE_FTRUNCATE # define HAVE_FTRUNCATE 1 #endif #endif /* WIN32 && ! __MINGW64__ */ /* ** callback for CURLOPT_SEEKFUNCTION */ int tool_seek_cb(void *userdata, curl_off_t offset, int whence); #endif /* HEADER_CURL_TOOL_CB_SEE_H */ davix-0.8.0/deps/curl/src/slist_wc.c0000644000000000000000000000376714121063461016025 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef CURL_DISABLE_LIBCURL_OPTION #include "slist_wc.h" /* The last #include files should be: */ #include "memdebug.h" /* * slist_wc_append() appends a string to the linked list. This function can be * used as an initialization function as well as an append function. */ struct slist_wc *slist_wc_append(struct slist_wc *list, const char *data) { struct curl_slist *new_item = curl_slist_append(NULL, data); if(!new_item) return NULL; if(!list) { list = malloc(sizeof(struct slist_wc)); if(!list) { curl_slist_free_all(new_item); return NULL; } list->first = new_item; list->last = new_item; return list; } list->last->next = new_item; list->last = list->last->next; return list; } /* be nice and clean up resources */ void slist_wc_free_all(struct slist_wc *list) { if(!list) return; curl_slist_free_all(list->first); free(list); } #endif /* CURL_DISABLE_LIBCURL_OPTION */ davix-0.8.0/deps/curl/src/tool_operate.h0000644000000000000000000000463714121063461016674 0ustar rootroot#ifndef HEADER_CURL_TOOL_OPERATE_H #define HEADER_CURL_TOOL_OPERATE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_cb_hdr.h" #include "tool_cb_prg.h" #include "tool_sdecls.h" struct per_transfer { /* double linked */ struct per_transfer *next; struct per_transfer *prev; struct OperationConfig *config; /* for this transfer */ CURL *curl; long retry_numretries; long retry_sleep_default; long retry_sleep; struct timeval retrystart; bool metalink; /* nonzero for metalink download. */ bool metalink_next_res; metalinkfile *mlfile; metalink_resource *mlres; char *this_url; char *outfile; bool infdopen; /* TRUE if infd needs closing */ int infd; bool noprogress; struct ProgressData progressbar; struct OutStruct outs; struct OutStruct heads; struct OutStruct etag_save; struct InStruct input; struct HdrCbData hdrcbdata; char errorbuffer[CURL_ERROR_SIZE]; bool added; /* set TRUE when added to the multi handle */ /* for parallel progress bar */ curl_off_t dltotal; curl_off_t dlnow; curl_off_t ultotal; curl_off_t ulnow; bool dltotal_added; /* if the total has been added from this */ bool ultotal_added; /* NULL or malloced */ char *separator_err; char *separator; char *uploadfile; }; CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[]); extern struct per_transfer *transfers; /* first node */ #endif /* HEADER_CURL_TOOL_OPERATE_H */ davix-0.8.0/deps/curl/src/tool_metalink.c0000644000000000000000000006070614121063461017033 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef USE_METALINK #include #include #ifdef HAVE_FCNTL_H # include #endif #undef HAVE_NSS_CONTEXT #ifdef USE_OPENSSL # include # include #elif defined(USE_GNUTLS_NETTLE) # include # include # define MD5_CTX struct md5_ctx # define SHA_CTX struct sha1_ctx # define SHA256_CTX struct sha256_ctx #elif defined(USE_GNUTLS) # include # define MD5_CTX gcry_md_hd_t # define SHA_CTX gcry_md_hd_t # define SHA256_CTX gcry_md_hd_t #elif defined(USE_NSS) # include # include # define MD5_CTX void * # define SHA_CTX void * # define SHA256_CTX void * # define HAVE_NSS_CONTEXT static NSSInitContext *nss_context; #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) /* For Apple operating systems: CommonCrypto has the functions we need. The library's headers are even backward-compatible with OpenSSL's headers as long as we define COMMON_DIGEST_FOR_OPENSSL first. These functions are available on Tiger and later, as well as iOS 2.0 and later. If you're building for an older cat, well, sorry. */ # define COMMON_DIGEST_FOR_OPENSSL # include #elif defined(USE_WIN32_CRYPTO) /* For Windows: If no other crypto library is provided, we fallback to the hash functions provided within the Microsoft Windows CryptoAPI */ # include /* Custom structure in order to store the required provider and hash handle */ struct win32_crypto_hash { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; }; /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */ # ifndef ALG_SID_SHA_256 # define ALG_SID_SHA_256 12 # endif # ifndef CALG_SHA_256 # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) # endif # define MD5_CTX struct win32_crypto_hash # define SHA_CTX struct win32_crypto_hash # define SHA256_CTX struct win32_crypto_hash #else # error "Can't compile METALINK support without a crypto library." #endif #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_getparam.h" #include "tool_paramhlp.h" #include "tool_cfgable.h" #include "tool_metalink.h" #include "tool_operate.h" #include "tool_msgs.h" #include "memdebug.h" /* keep this as LAST include */ /* Copied from tool_getparam.c */ #define GetStr(str,val) do { \ if(*(str)) { \ free(*(str)); \ *(str) = NULL; \ } \ if((val)) \ *(str) = strdup((val)); \ if(!(val)) \ return PARAM_NO_MEM; \ } while(0) #if defined(USE_OPENSSL) /* Functions are already defined */ #elif defined(USE_GNUTLS_NETTLE) static int MD5_Init(MD5_CTX *ctx) { md5_init(ctx); return 1; } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { md5_update(ctx, inputLen, input); } static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { md5_digest(ctx, 16, digest); } static int SHA1_Init(SHA_CTX *ctx) { sha1_init(ctx); return 1; } static void SHA1_Update(SHA_CTX *ctx, const unsigned char *input, unsigned int inputLen) { sha1_update(ctx, inputLen, input); } static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) { sha1_digest(ctx, 20, digest); } static int SHA256_Init(SHA256_CTX *ctx) { sha256_init(ctx); return 1; } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *input, unsigned int inputLen) { sha256_update(ctx, inputLen, input); } static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) { sha256_digest(ctx, 32, digest); } #elif defined(USE_GNUTLS) static int MD5_Init(MD5_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_MD5, 0); return 1; } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { gcry_md_write(*ctx, input, inputLen); } static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), 16); gcry_md_close(*ctx); } static int SHA1_Init(SHA_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_SHA1, 0); return 1; } static void SHA1_Update(SHA_CTX *ctx, const unsigned char *input, unsigned int inputLen) { gcry_md_write(*ctx, input, inputLen); } static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), 20); gcry_md_close(*ctx); } static int SHA256_Init(SHA256_CTX *ctx) { gcry_md_open(ctx, GCRY_MD_SHA256, 0); return 1; } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *input, unsigned int inputLen) { gcry_md_write(*ctx, input, inputLen); } static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) { memcpy(digest, gcry_md_read(*ctx, 0), 32); gcry_md_close(*ctx); } #elif defined(USE_NSS) static int nss_hash_init(void **pctx, SECOidTag hash_alg) { PK11Context *ctx; /* we have to initialize NSS if not initialized already */ if(!NSS_IsInitialized() && !nss_context) { static NSSInitParameters params; params.length = sizeof(params); nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); } ctx = PK11_CreateDigestContext(hash_alg); if(!ctx) return /* failure */ 0; if(PK11_DigestBegin(ctx) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); return /* failure */ 0; } *pctx = ctx; return /* success */ 1; } static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len) { PK11Context *ctx = *pctx; unsigned int outlen; PK11_DigestFinal(ctx, out, &outlen, len); PK11_DestroyContext(ctx, PR_TRUE); } static int MD5_Init(MD5_CTX *pctx) { return nss_hash_init(pctx, SEC_OID_MD5); } static void MD5_Update(MD5_CTX *pctx, const unsigned char *input, unsigned int input_len) { PK11_DigestOp(*pctx, input, input_len); } static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx) { nss_hash_final(pctx, digest, 16); } static int SHA1_Init(SHA_CTX *pctx) { return nss_hash_init(pctx, SEC_OID_SHA1); } static void SHA1_Update(SHA_CTX *pctx, const unsigned char *input, unsigned int input_len) { PK11_DigestOp(*pctx, input, input_len); } static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx) { nss_hash_final(pctx, digest, 20); } static int SHA256_Init(SHA256_CTX *pctx) { return nss_hash_init(pctx, SEC_OID_SHA256); } static void SHA256_Update(SHA256_CTX *pctx, const unsigned char *input, unsigned int input_len) { PK11_DigestOp(*pctx, input, input_len); } static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx) { nss_hash_final(pctx, digest, 32); } #elif defined(USE_WIN32_CRYPTO) static void win32_crypto_final(struct win32_crypto_hash *ctx, unsigned char *digest, unsigned int digestLen) { unsigned long length; CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); if(length == digestLen) CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); if(ctx->hHash) CryptDestroyHash(ctx->hHash); if(ctx->hCryptProv) CryptReleaseContext(ctx->hCryptProv, 0); } static int MD5_Init(MD5_CTX *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); } return 1; } static void MD5_Update(MD5_CTX *ctx, const unsigned char *input, unsigned int inputLen) { CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { win32_crypto_final(ctx, digest, 16); } static int SHA1_Init(SHA_CTX *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash); } return 1; } static void SHA1_Update(SHA_CTX *ctx, const unsigned char *input, unsigned int inputLen) { CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) { win32_crypto_final(ctx, digest, 20); } static int SHA256_Init(SHA256_CTX *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); } return 1; } static void SHA256_Update(SHA256_CTX *ctx, const unsigned char *input, unsigned int inputLen) { CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); } static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) { win32_crypto_final(ctx, digest, 32); } #endif /* CRYPTO LIBS */ const digest_params MD5_DIGEST_PARAMS[] = { { CURLX_FUNCTION_CAST(Curl_digest_init_func, MD5_Init), CURLX_FUNCTION_CAST(Curl_digest_update_func, MD5_Update), CURLX_FUNCTION_CAST(Curl_digest_final_func, MD5_Final), sizeof(MD5_CTX), 16 } }; const digest_params SHA1_DIGEST_PARAMS[] = { { CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA1_Init), CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA1_Update), CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA1_Final), sizeof(SHA_CTX), 20 } }; const digest_params SHA256_DIGEST_PARAMS[] = { { CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA256_Init), CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA256_Update), CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA256_Final), sizeof(SHA256_CTX), 32 } }; static const metalink_digest_def SHA256_DIGEST_DEF[] = { {"sha-256", SHA256_DIGEST_PARAMS} }; static const metalink_digest_def SHA1_DIGEST_DEF[] = { {"sha-1", SHA1_DIGEST_PARAMS} }; static const metalink_digest_def MD5_DIGEST_DEF[] = { {"md5", MD5_DIGEST_PARAMS} }; /* * The alias of supported hash functions in the order by preference * (basically stronger hash comes first). We included "sha-256" and * "sha256". The former is the name defined in the IANA registry named * "Hash Function Textual Names". The latter is widely (and * historically) used in Metalink version 3. */ static const metalink_digest_alias digest_aliases[] = { {"sha-256", SHA256_DIGEST_DEF}, {"sha256", SHA256_DIGEST_DEF}, {"sha-1", SHA1_DIGEST_DEF}, {"sha1", SHA1_DIGEST_DEF}, {"md5", MD5_DIGEST_DEF}, {NULL, NULL} }; digest_context *Curl_digest_init(const digest_params *dparams) { digest_context *ctxt; /* Create digest context */ ctxt = malloc(sizeof(*ctxt)); if(!ctxt) return ctxt; ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize); if(!ctxt->digest_hashctx) { free(ctxt); return NULL; } ctxt->digest_hash = dparams; if(dparams->digest_init(ctxt->digest_hashctx) != 1) { free(ctxt->digest_hashctx); free(ctxt); return NULL; } return ctxt; } int Curl_digest_update(digest_context *context, const unsigned char *data, unsigned int len) { (*context->digest_hash->digest_update)(context->digest_hashctx, data, len); return 0; } int Curl_digest_final(digest_context *context, unsigned char *result) { if(result) (*context->digest_hash->digest_final)(result, context->digest_hashctx); free(context->digest_hashctx); free(context); return 0; } static unsigned char hex_to_uint(const char *s) { char buf[3]; unsigned long val; buf[0] = s[0]; buf[1] = s[1]; buf[2] = 0; val = strtoul(buf, NULL, 16); return (unsigned char)(val&0xff); } /* * Check checksum of file denoted by filename. The expected hash value * is given in hex_hash which is hex-encoded string. * * This function returns 1 if it succeeds or one of the following * integers: * * 0: * Checksum didn't match. * -1: * Could not open file; or could not read data from file. * -2: * Hash algorithm not available. */ static int check_hash(const char *filename, const metalink_digest_def *digest_def, const unsigned char *digest, FILE *error) { unsigned char *result; digest_context *dctx; int check_ok, flags, fd; flags = O_RDONLY; #ifdef O_BINARY /* O_BINARY is required in order to avoid binary EOF in text mode */ flags |= O_BINARY; #endif fd = open(filename, flags); if(fd == -1) { fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, digest_def->hash_name, strerror(errno)); return -1; } dctx = Curl_digest_init(digest_def->dparams); if(!dctx) { fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, digest_def->hash_name, "failed to initialize hash algorithm"); close(fd); return -2; } result = malloc(digest_def->dparams->digest_resultlen); if(!result) { close(fd); Curl_digest_final(dctx, NULL); return -1; } while(1) { unsigned char buf[4096]; ssize_t len = read(fd, buf, sizeof(buf)); if(len == 0) { break; } else if(len == -1) { fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, digest_def->hash_name, strerror(errno)); Curl_digest_final(dctx, result); close(fd); return -1; } Curl_digest_update(dctx, buf, (unsigned int)len); } Curl_digest_final(dctx, result); check_ok = memcmp(result, digest, digest_def->dparams->digest_resultlen) == 0; /* sha*sum style verdict output */ if(check_ok) fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename, digest_def->hash_name); else fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n", filename, digest_def->hash_name); free(result); close(fd); return check_ok; } int metalink_check_hash(struct GlobalConfig *config, metalinkfile *mlfile, const char *filename) { int rv; fprintf(config->errors, "Metalink: validating (%s)...\n", filename); if(mlfile->checksum == NULL) { fprintf(config->errors, "Metalink: validating (%s) FAILED (digest missing)\n", filename); return -2; } rv = check_hash(filename, mlfile->checksum->digest_def, mlfile->checksum->digest, config->errors); return rv; } static metalink_checksum * checksum_from_hex_digest(const metalink_digest_def *digest_def, const char *hex_digest) { metalink_checksum *chksum; unsigned char *digest; size_t i; size_t len = strlen(hex_digest); digest = malloc(len/2); if(!digest) return 0; for(i = 0; i < len; i += 2) { digest[i/2] = hex_to_uint(hex_digest + i); } chksum = malloc(sizeof(metalink_checksum)); if(chksum) { chksum->digest_def = digest_def; chksum->digest = digest; } else free(digest); return chksum; } static metalink_resource *new_metalink_resource(const char *url) { metalink_resource *res; res = malloc(sizeof(metalink_resource)); if(res) { res->next = NULL; res->url = strdup(url); if(!res->url) { free(res); return NULL; } } return res; } /* Returns nonzero if hex_digest is properly formatted; that is each letter is in [0-9A-Za-z] and the length of the string equals to the result length of digest * 2. */ static int check_hex_digest(const char *hex_digest, const metalink_digest_def *digest_def) { size_t i; for(i = 0; hex_digest[i]; ++i) { char c = hex_digest[i]; if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { return 0; } } return digest_def->dparams->digest_resultlen * 2 == i; } static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo) { metalinkfile *f; f = (metalinkfile*)malloc(sizeof(metalinkfile)); if(!f) return NULL; f->next = NULL; f->filename = strdup(fileinfo->name); if(!f->filename) { free(f); return NULL; } f->checksum = NULL; f->resource = NULL; if(fileinfo->checksums) { const metalink_digest_alias *digest_alias; for(digest_alias = digest_aliases; digest_alias->alias_name; ++digest_alias) { metalink_checksum_t **p; for(p = fileinfo->checksums; *p; ++p) { if(curl_strequal(digest_alias->alias_name, (*p)->type) && check_hex_digest((*p)->hash, digest_alias->digest_def)) { f->checksum = checksum_from_hex_digest(digest_alias->digest_def, (*p)->hash); break; } } if(f->checksum) { break; } } } if(fileinfo->resources) { metalink_resource_t **p; metalink_resource root, *tail; root.next = NULL; tail = &root; for(p = fileinfo->resources; *p; ++p) { metalink_resource *res; /* Filter by type if it is non-NULL. In Metalink v3, type includes the type of the resource. In curl, we are only interested in HTTP, HTTPS and FTP. In addition to them, Metalink v3 file may contain bittorrent type URL, which points to the BitTorrent metainfo file. We ignore it here. In Metalink v4, type was deprecated and all fileinfo->resources point to the target file. BitTorrent metainfo file URL may be appeared in fileinfo->metaurls. */ if((*p)->type == NULL || curl_strequal((*p)->type, "http") || curl_strequal((*p)->type, "https") || curl_strequal((*p)->type, "ftp") || curl_strequal((*p)->type, "ftps")) { res = new_metalink_resource((*p)->url); if(res) { tail->next = res; tail = res; } else { tail = root.next; /* clean up the linked list */ while(tail) { res = tail->next; free(tail->url); free(tail); tail = res; } free(f->filename); free(f); return NULL; } } } f->resource = root.next; } return f; } int parse_metalink(struct OperationConfig *config, struct OutStruct *outs, const char *metalink_url) { metalink_error_t r; metalink_t* metalink; metalink_file_t **files; bool warnings = FALSE; /* metlaink_parse_final deletes outs->metalink_parser */ r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink); outs->metalink_parser = NULL; if(r != 0) { return -1; } if(metalink->files == NULL) { fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " "(missing or invalid file name)\n", metalink_url); metalink_delete(metalink); return -1; } for(files = metalink->files; *files; ++files) { struct getout *url; /* Skip an entry which has no resource. */ if(!(*files)->resources) { fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " "(missing or invalid resource)\n", metalink_url); continue; } if(config->url_get || ((config->url_get = config->url_list) != NULL)) { /* there's a node here, if it already is filled-in continue to find an "empty" node */ while(config->url_get && (config->url_get->flags & GETOUT_URL)) config->url_get = config->url_get->next; } /* now there might or might not be an available node to fill in! */ if(config->url_get) /* existing node */ url = config->url_get; else /* there was no free node, create one! */ url = new_getout(config); if(url) { metalinkfile *mlfile = new_metalinkfile(*files); if(!mlfile) break; if(!mlfile->checksum) { warnings = TRUE; fprintf(config->global->errors, "Metalink: parsing (%s) WARNING (digest missing)\n", metalink_url); } /* Set name as url */ GetStr(&url->url, mlfile->filename); /* set flag metalink here */ url->flags |= GETOUT_URL | GETOUT_METALINK; if(config->metalinkfile_list) { config->metalinkfile_last->next = mlfile; config->metalinkfile_last = mlfile; } else { config->metalinkfile_list = config->metalinkfile_last = mlfile; } } } metalink_delete(metalink); return (warnings) ? -2 : 0; } size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) { struct per_transfer *per = userdata; struct OutStruct *outs = &per->outs; struct OperationConfig *config = per->config; int rv; /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = (sz && nmemb) ? 0 : 1; if(!config) return failure; rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb); if(rv == 0) return sz * nmemb; else { fprintf(config->global->errors, "Metalink: parsing FAILED\n"); return failure; } } /* * Returns nonzero if content_type includes mediatype. */ static int check_content_type(const char *content_type, const char *media_type) { const char *ptr = content_type; size_t media_type_len = strlen(media_type); for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr); if(!*ptr) { return 0; } return curl_strnequal(ptr, media_type, media_type_len) && (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' || *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';'); } int check_metalink_content_type(const char *content_type) { return check_content_type(content_type, "application/metalink+xml"); } int count_next_metalink_resource(metalinkfile *mlfile) { int count = 0; metalink_resource *res; for(res = mlfile->resource; res; res = res->next, ++count); return count; } static void delete_metalink_checksum(metalink_checksum *chksum) { if(chksum == NULL) { return; } Curl_safefree(chksum->digest); Curl_safefree(chksum); } static void delete_metalink_resource(metalink_resource *res) { if(res == NULL) { return; } Curl_safefree(res->url); Curl_safefree(res); } void delete_metalinkfile(metalinkfile *mlfile) { metalink_resource *res; if(mlfile == NULL) { return; } Curl_safefree(mlfile->filename); delete_metalink_checksum(mlfile->checksum); for(res = mlfile->resource; res;) { metalink_resource *next; next = res->next; delete_metalink_resource(res); res = next; } Curl_safefree(mlfile); } void clean_metalink(struct OperationConfig *config) { if(config) { while(config->metalinkfile_list) { metalinkfile *mlfile = config->metalinkfile_list; config->metalinkfile_list = config->metalinkfile_list->next; delete_metalinkfile(mlfile); } config->metalinkfile_last = 0; } } void metalink_cleanup(void) { #ifdef HAVE_NSS_CONTEXT if(nss_context) { NSS_ShutdownContext(nss_context); nss_context = NULL; } #endif } #endif /* USE_METALINK */ davix-0.8.0/deps/curl/src/tool_helpers.c0000644000000000000000000000723314121063461016665 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_msgs.h" #include "tool_getparam.h" #include "tool_helpers.h" #include "memdebug.h" /* keep this as LAST include */ /* ** Helper functions that are used from more than one source file. */ const char *param2text(int res) { ParameterError error = (ParameterError)res; switch(error) { case PARAM_GOT_EXTRA_PARAMETER: return "had unsupported trailing garbage"; case PARAM_OPTION_UNKNOWN: return "is unknown"; case PARAM_OPTION_AMBIGUOUS: return "is ambiguous"; case PARAM_REQUIRES_PARAMETER: return "requires parameter"; case PARAM_BAD_USE: return "is badly used here"; case PARAM_BAD_NUMERIC: return "expected a proper numerical parameter"; case PARAM_NEGATIVE_NUMERIC: return "expected a positive numerical parameter"; case PARAM_LIBCURL_DOESNT_SUPPORT: return "the installed libcurl version doesn't support this"; case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL: return "a specified protocol is unsupported by libcurl"; case PARAM_NO_MEM: return "out of memory"; case PARAM_NO_PREFIX: return "the given option can't be reversed with a --no- prefix"; case PARAM_NUMBER_TOO_LARGE: return "too large number"; case PARAM_NO_NOT_BOOLEAN: return "used '--no-' for option that isn't a boolean"; default: return "unknown error"; } } int SetHTTPrequest(struct OperationConfig *config, HttpReq req, HttpReq *store) { /* this mirrors the HttpReq enum in tool_sdecls.h */ const char *reqname[]= { "", /* unspec */ "GET (-G, --get)", "HEAD (-I, --head)", "multipart formpost (-F, --form)", "POST (-d, --data)" }; if((*store == HTTPREQ_UNSPEC) || (*store == req)) { *store = req; return 0; } warnf(config->global, "You can only select one HTTP request method! " "You asked for both %s and %s.\n", reqname[req], reqname[*store]); return 1; } void customrequest_helper(struct OperationConfig *config, HttpReq req, char *method) { /* this mirrors the HttpReq enum in tool_sdecls.h */ const char *dflt[]= { "GET", "GET", "HEAD", "POST", "POST" }; if(!method) ; else if(curl_strequal(method, dflt[req])) { notef(config->global, "Unnecessary use of -X or --request, %s is already " "inferred.\n", dflt[req]); } else if(curl_strequal(method, "head")) { warnf(config->global, "Setting custom HTTP method to HEAD with -X/--request may not work " "the way you want. Consider using -I/--head instead.\n"); } } davix-0.8.0/deps/curl/src/tool_parsecfg.c0000644000000000000000000002416714121063461017022 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_getparam.h" #include "tool_helpers.h" #include "tool_homedir.h" #include "tool_msgs.h" #include "tool_parsecfg.h" #include "memdebug.h" /* keep this as LAST include */ /* only acknowledge colon or equals as separators if the option was not specified with an initial dash! */ #define ISSEP(x,dash) (!dash && (((x) == '=') || ((x) == ':'))) static const char *unslashquote(const char *line, char *param); static char *my_get_line(FILE *fp); #ifdef WIN32 static FILE *execpath(const char *filename) { char filebuffer[512]; /* Get the filename of our executable. GetModuleFileName is already declared * via inclusions done in setup header file. We assume that we are using * the ASCII version here. */ unsigned long len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer)); if(len > 0 && len < sizeof(filebuffer)) { /* We got a valid filename - get the directory part */ char *lastdirchar = strrchr(filebuffer, '\\'); if(lastdirchar) { size_t remaining; *lastdirchar = 0; /* If we have enough space, build the RC filename */ remaining = sizeof(filebuffer) - strlen(filebuffer); if(strlen(filename) < remaining - 1) { msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename); return fopen(filebuffer, FOPEN_READTEXT); } } } return NULL; } #endif /* return 0 on everything-is-fine, and non-zero otherwise */ int parseconfig(const char *filename, struct GlobalConfig *global) { FILE *file = NULL; bool usedarg = FALSE; int rc = 0; struct OperationConfig *operation = global->first; char *pathalloc = NULL; if(!filename || !*filename) { /* NULL or no file name attempts to load .curlrc from the homedir! */ char *home = homedir(); /* portable homedir finder */ #ifndef WIN32 if(home) { pathalloc = curl_maprintf("%s%s.curlrc", home, DIR_CHAR); if(!pathalloc) { free(home); return 1; /* out of memory */ } filename = pathalloc; } #else /* Windows */ if(home) { int i = 0; char prefix = '.'; do { /* if it was allocated in a previous attempt */ curl_free(pathalloc); /* check for .curlrc then _curlrc in the home dir */ pathalloc = curl_maprintf("%s%s%ccurlrc", home, DIR_CHAR, prefix); if(!pathalloc) { free(home); return 1; /* out of memory */ } /* Check if the file exists - if not, try _curlrc */ file = fopen(pathalloc, FOPEN_READTEXT); if(file) { filename = pathalloc; break; } prefix = '_'; } while(++i < 2); } if(!filename) { /* check for .curlrc then _curlrc in the dir of the executable */ file = execpath(".curlrc"); if(!file) file = execpath("_curlrc"); } #endif Curl_safefree(home); /* we've used it, now free it */ } if(!file && filename) { /* no need to fopen() again */ if(strcmp(filename, "-")) file = fopen(filename, FOPEN_READTEXT); else file = stdin; } if(file) { char *line; char *aline; char *option; char *param; int lineno = 0; bool dashed_option; while(NULL != (aline = my_get_line(file))) { int res; bool alloced_param = FALSE; lineno++; line = aline; /* line with # in the first non-blank column is a comment! */ while(*line && ISSPACE(*line)) line++; switch(*line) { case '#': case '/': case '\r': case '\n': case '*': case '\0': Curl_safefree(aline); continue; } /* the option keywords starts here */ option = line; /* the option starts with a dash? */ dashed_option = option[0]=='-'?TRUE:FALSE; while(*line && !ISSPACE(*line) && !ISSEP(*line, dashed_option)) line++; /* ... and has ended here */ if(*line) *line++ = '\0'; /* zero terminate, we have a local copy of the data */ #ifdef DEBUG_CONFIG fprintf(stderr, "GOT: %s\n", option); #endif /* pass spaces and separator(s) */ while(*line && (ISSPACE(*line) || ISSEP(*line, dashed_option))) line++; /* the parameter starts here (unless quoted) */ if(*line == '\"') { /* quoted parameter, do the quote dance */ line++; param = malloc(strlen(line) + 1); /* parameter */ if(!param) { /* out of memory */ Curl_safefree(aline); rc = 1; break; } alloced_param = TRUE; (void)unslashquote(line, param); } else { param = line; /* parameter starts here */ while(*line && !ISSPACE(*line)) line++; if(*line) { *line = '\0'; /* zero terminate */ /* to detect mistakes better, see if there's data following */ line++; /* pass all spaces */ while(*line && ISSPACE(*line)) line++; switch(*line) { case '\0': case '\r': case '\n': case '#': /* comment */ break; default: warnf(operation->global, "%s:%d: warning: '%s' uses unquoted " "white space in the line that may cause side-effects!\n", filename, lineno, option); } } if(!*param) /* do this so getparameter can check for required parameters. Otherwise it always thinks there's a parameter. */ param = NULL; } #ifdef DEBUG_CONFIG fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); #endif res = getparameter(option, param, &usedarg, global, operation); if(!res && param && *param && !usedarg) /* we passed in a parameter that wasn't used! */ res = PARAM_GOT_EXTRA_PARAMETER; if(res == PARAM_NEXT_OPERATION) { if(operation->url_list && operation->url_list->url) { /* Allocate the next config */ operation->next = malloc(sizeof(struct OperationConfig)); if(operation->next) { /* Initialise the newly created config */ config_init(operation->next); /* Set the global config pointer */ operation->next->global = global; /* Update the last operation pointer */ global->last = operation->next; /* Move onto the new config */ operation->next->prev = operation; operation = operation->next; } else res = PARAM_NO_MEM; } } if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) { /* the help request isn't really an error */ if(!strcmp(filename, "-")) { filename = ""; } if(res != PARAM_HELP_REQUESTED && res != PARAM_MANUAL_REQUESTED && res != PARAM_VERSION_INFO_REQUESTED && res != PARAM_ENGINES_REQUESTED) { const char *reason = param2text(res); warnf(operation->global, "%s:%d: warning: '%s' %s\n", filename, lineno, option, reason); } } if(alloced_param) Curl_safefree(param); Curl_safefree(aline); } if(file != stdin) fclose(file); } else rc = 1; /* couldn't open the file */ curl_free(pathalloc); return rc; } /* * Copies the string from line to the buffer at param, unquoting * backslash-quoted characters and NUL-terminating the output string. * Stops at the first non-backslash-quoted double quote character or the * end of the input string. param must be at least as long as the input * string. Returns the pointer after the last handled input character. */ static const char *unslashquote(const char *line, char *param) { while(*line && (*line != '\"')) { if(*line == '\\') { char out; line++; /* default is to output the letter after the backslash */ switch(out = *line) { case '\0': continue; /* this'll break out of the loop */ case 't': out = '\t'; break; case 'n': out = '\n'; break; case 'r': out = '\r'; break; case 'v': out = '\v'; break; } *param++ = out; line++; } else *param++ = *line++; } *param = '\0'; /* always zero terminate */ return line; } /* * Reads a line from the given file, ensuring is NUL terminated. * The pointer must be freed by the caller. * NULL is returned on an out of memory condition. */ static char *my_get_line(FILE *fp) { char buf[4096]; char *nl = NULL; char *line = NULL; do { if(NULL == fgets(buf, sizeof(buf), fp)) break; if(!line) { line = strdup(buf); if(!line) return NULL; } else { char *ptr; size_t linelen = strlen(line); ptr = realloc(line, linelen + strlen(buf) + 1); if(!ptr) { Curl_safefree(line); return NULL; } line = ptr; strcpy(&line[linelen], buf); } nl = strchr(line, '\n'); } while(!nl); if(nl) *nl = '\0'; return line; } davix-0.8.0/deps/curl/src/tool_setup.h0000644000000000000000000000446414121063461016373 0ustar rootroot#ifndef HEADER_CURL_TOOL_SETUP_H #define HEADER_CURL_TOOL_SETUP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #define CURL_NO_OLDIES /* * curl_setup.h may define preprocessor macros such as _FILE_OFFSET_BITS and * _LARGE_FILES in order to support files larger than 2 GB. On platforms * where this happens it is mandatory that these macros are defined before * any system header file is included, otherwise file handling function * prototypes will be misdeclared and curl tool may not build properly; * therefore we must include curl_setup.h before curl.h when building curl. */ #include "curl_setup.h" /* from the lib directory */ /* * curl tool certainly uses libcurl's external interface. */ #include /* external interface */ /* * Platform specific stuff. */ #if defined(macintosh) && defined(__MRC__) # define main(x,y) curl_main(x,y) #endif #ifdef TPF # undef select /* change which select is used for the curl command line tool */ # define select(a,b,c,d,e) tpf_select_bsd(a,b,c,d,e) /* and turn off the progress meter */ # define CONF_DEFAULT (0|CONF_NOPROGRESS) #endif #ifndef OS # define OS "unknown" #endif #ifndef UNPRINTABLE_CHAR /* define what to use for unprintable characters */ # define UNPRINTABLE_CHAR '.' #endif #ifndef HAVE_STRDUP # include "tool_strdup.h" #endif #endif /* HEADER_CURL_TOOL_SETUP_H */ davix-0.8.0/deps/curl/src/tool_version.h0000644000000000000000000000267614121063461016723 0ustar rootroot#ifndef HEADER_CURL_TOOL_VERSION_H #define HEADER_CURL_TOOL_VERSION_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #define CURL_NAME "curl" #define CURL_COPYRIGHT LIBCURL_COPYRIGHT #define CURL_VERSION LIBCURL_VERSION #define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR #define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR #define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " #endif /* HEADER_CURL_TOOL_VERSION_H */ davix-0.8.0/deps/curl/src/tool_convert.h0000644000000000000000000000306214121063461016704 0ustar rootroot#ifndef HEADER_CURL_TOOL_CONVERT_H #define HEADER_CURL_TOOL_CONVERT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef CURL_DOES_CONVERSIONS #ifdef HAVE_ICONV CURLcode convert_to_network(char *buffer, size_t length); CURLcode convert_from_network(char *buffer, size_t length); void convert_cleanup(void); #endif /* HAVE_ICONV */ char convert_char(curl_infotype infotype, char this_char); #endif /* CURL_DOES_CONVERSIONS */ #if !defined(CURL_DOES_CONVERSIONS) || !defined(HAVE_ICONV) #define convert_cleanup() Curl_nop_stmt #endif #endif /* HEADER_CURL_TOOL_CONVERT_H */ davix-0.8.0/deps/curl/src/tool_metalink.h0000644000000000000000000001274214121063461017035 0ustar rootroot#ifndef HEADER_CURL_TOOL_METALINK_H #define HEADER_CURL_TOOL_METALINK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2014, 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_sdecls.h" struct GlobalConfig; struct OperationConfig; /* returns 1 for success, 0 otherwise (we use OpenSSL *_Init fncs directly) */ typedef int (* Curl_digest_init_func)(void *context); typedef void (* Curl_digest_update_func)(void *context, const unsigned char *data, unsigned int len); typedef void (* Curl_digest_final_func)(unsigned char *result, void *context); typedef struct { Curl_digest_init_func digest_init; /* Initialize context procedure */ Curl_digest_update_func digest_update; /* Update context with data */ Curl_digest_final_func digest_final; /* Get final result procedure */ unsigned int digest_ctxtsize; /* Context structure size */ unsigned int digest_resultlen; /* Result length (bytes) */ } digest_params; typedef struct { const digest_params *digest_hash; /* Hash function definition */ void *digest_hashctx; /* Hash function context */ } digest_context; digest_context * Curl_digest_init(const digest_params *dparams); int Curl_digest_update(digest_context *context, const unsigned char *data, unsigned int len); int Curl_digest_final(digest_context *context, unsigned char *result); typedef struct { const char *hash_name; const digest_params *dparams; } metalink_digest_def; typedef struct { const char *alias_name; const metalink_digest_def *digest_def; } metalink_digest_alias; typedef struct metalink_checksum { const metalink_digest_def *digest_def; /* raw digest value, not ascii hex digest */ unsigned char *digest; } metalink_checksum; typedef struct metalink_resource { struct metalink_resource *next; char *url; } metalink_resource; typedef struct metalinkfile { struct metalinkfile *next; char *filename; metalink_checksum *checksum; metalink_resource *resource; } metalinkfile; #ifdef USE_METALINK /* * curl requires libmetalink 0.1.0 or newer */ #define CURL_REQ_LIBMETALINK_MAJOR 0 #define CURL_REQ_LIBMETALINK_MINOR 1 #define CURL_REQ_LIBMETALINK_PATCH 0 #define CURL_REQ_LIBMETALINK_VERS ((CURL_REQ_LIBMETALINK_MAJOR * 10000) + \ (CURL_REQ_LIBMETALINK_MINOR * 100) + \ CURL_REQ_LIBMETALINK_PATCH) extern const digest_params MD5_DIGEST_PARAMS[1]; extern const digest_params SHA1_DIGEST_PARAMS[1]; extern const digest_params SHA256_DIGEST_PARAMS[1]; #include /* * Counts the resource in the metalinkfile. */ int count_next_metalink_resource(metalinkfile *mlfile); void delete_metalinkfile(metalinkfile *mlfile); void clean_metalink(struct OperationConfig *config); /* * Performs final parse operation and extracts information from * Metalink and creates metalinkfile structs. * * This function returns 0 if it succeeds without warnings, or one of * the following negative error codes: * * -1: Parsing failed; or no file is found * -2: Parsing succeeded with some warnings. */ int parse_metalink(struct OperationConfig *config, struct OutStruct *outs, const char *metalink_url); /* * Callback function for CURLOPT_WRITEFUNCTION */ size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); /* * Returns nonzero if content_type includes "application/metalink+xml" * media-type. The check is done in case-insensitive manner. */ int check_metalink_content_type(const char *content_type); /* * Check checksum of file denoted by filename. * * This function returns 1 if the checksum matches or one of the * following integers: * * 0: * Checksum didn't match. * -1: * Could not open file; or could not read data from file. * -2: * No checksum in Metalink supported, hash algorithm not available, or * Metalink does not contain checksum. */ int metalink_check_hash(struct GlobalConfig *config, metalinkfile *mlfile, const char *filename); /* * Release resources allocated at global scope. */ void metalink_cleanup(void); #else /* USE_METALINK */ #define count_next_metalink_resource(x) 0 #define delete_metalinkfile(x) (void)x #define clean_metalink(x) (void)x /* metalink_cleanup() takes no arguments */ #define metalink_cleanup() Curl_nop_stmt #endif /* USE_METALINK */ #endif /* HEADER_CURL_TOOL_METALINK_H */ davix-0.8.0/deps/curl/src/tool_cb_prg.c0000644000000000000000000002065714121063461016464 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_SYS_IOCTL_H #include #endif #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_cb_prg.h" #include "tool_util.h" #include "tool_operate.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef HAVE_TERMIOS_H # include #elif defined(HAVE_TERMIO_H) # include #endif /* 200 values generated by this perl code: my $pi = 3.1415; foreach my $i (1 .. 200) { printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000; } */ static const unsigned int sinus[] = { 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491, 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906, 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047, 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406, 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840, 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060, 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888, 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277, 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072, 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548, 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751, 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703, 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525, 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555, 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613, 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225, 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448, 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445, 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480, 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856, 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854, 468513, 484202, 499907 }; static void fly(struct ProgressData *bar, bool moved) { char buf[256]; int pos; int check = bar->width - 2; msnprintf(buf, sizeof(buf), "%*s\r", bar->width-1, " "); memcpy(&buf[bar->bar], "-=O=-", 5); pos = sinus[bar->tick%200] / (1000000 / check); buf[pos] = '#'; pos = sinus[(bar->tick + 5)%200] / (1000000 / check); buf[pos] = '#'; pos = sinus[(bar->tick + 10)%200] / (1000000 / check); buf[pos] = '#'; pos = sinus[(bar->tick + 15)%200] / (1000000 / check); buf[pos] = '#'; fputs(buf, bar->out); bar->tick += 2; if(bar->tick >= 200) bar->tick -= 200; bar->bar += (moved?bar->barmove:0); if(bar->bar >= (bar->width - 6)) { bar->barmove = -1; bar->bar = bar->width - 6; } else if(bar->bar < 0) { bar->barmove = 1; bar->bar = 0; } } /* ** callback for CURLOPT_XFERINFOFUNCTION */ #define MAX_BARLENGTH 256 #if (SIZEOF_CURL_OFF_T == 4) # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) #else /* assume CURL_SIZEOF_CURL_OFF_T == 8 */ # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) #endif int tool_progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { /* The original progress-bar source code was written for curl by Lars Aas, and this new edition inherits some of his concepts. */ struct timeval now = tvnow(); struct per_transfer *per = clientp; struct OperationConfig *config = per->config; struct ProgressData *bar = &per->progressbar; curl_off_t total; curl_off_t point; /* Calculate expected transfer size. initial_size can be less than zero when indicating that we are expecting to get the filesize from the remote */ if(bar->initial_size < 0 || ((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal))) total = CURL_OFF_T_MAX; else total = dltotal + ultotal + bar->initial_size; /* Calculate the current progress. initial_size can be less than zero when indicating that we are expecting to get the filesize from the remote */ if(bar->initial_size < 0 || ((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow))) point = CURL_OFF_T_MAX; else point = dlnow + ulnow + bar->initial_size; if(bar->calls) { /* after first call... */ if(total) { /* we know the total data to get... */ if(bar->prev == point) /* progress didn't change since last invoke */ return 0; else if((tvdiff(now, bar->prevtime) < 100L) && point < total) /* limit progress-bar updating to 10 Hz except when we're at 100% */ return 0; } else { /* total is unknown */ if(tvdiff(now, bar->prevtime) < 100L) /* limit progress-bar updating to 10 Hz */ return 0; fly(bar, point != bar->prev); } } /* simply count invokes */ bar->calls++; if((total > 0) && (point != bar->prev)) { char line[MAX_BARLENGTH + 1]; char format[40]; double frac; double percent; int barwidth; int num; if(point > total) /* we have got more than the expected total! */ total = point; frac = (double)point / (double)total; percent = frac * 100.0; barwidth = bar->width - 7; num = (int) (((double)barwidth) * frac); if(num > MAX_BARLENGTH) num = MAX_BARLENGTH; memset(line, '#', num); line[num] = '\0'; msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); fprintf(bar->out, format, line, percent); } fflush(bar->out); bar->prev = point; bar->prevtime = now; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(per->curl, CURLPAUSE_CONT); } return 0; } void progressbarinit(struct ProgressData *bar, struct OperationConfig *config) { char *colp; memset(bar, 0, sizeof(struct ProgressData)); /* pass this through to progress function so * it can display progress towards total file * not just the part that's left. (21-may-03, dbyron) */ if(config->use_resume) bar->initial_size = config->resume_from; colp = curlx_getenv("COLUMNS"); if(colp) { char *endptr; long num = strtol(colp, &endptr, 10); if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) && (num < 10000)) bar->width = (int)num; curl_free(colp); } if(!bar->width) { int cols = 0; #ifdef TIOCGSIZE struct ttysize ts; if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts)) cols = ts.ts_cols; #elif defined(TIOCGWINSZ) struct winsize ts; if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts)) cols = ts.ws_col; #elif defined(WIN32) { HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); CONSOLE_SCREEN_BUFFER_INFO console_info; if((stderr_hnd != INVALID_HANDLE_VALUE) && GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) { /* * Do not use +1 to get the true screen-width since writing a * character at the right edge will cause a line wrap. */ cols = (int) (console_info.srWindow.Right - console_info.srWindow.Left); } } #endif /* TIOCGSIZE */ if(cols > 20) bar->width = cols; } if(!bar->width) bar->width = 79; else if(bar->width > MAX_BARLENGTH) bar->width = MAX_BARLENGTH; bar->out = config->global->errors; bar->tick = 150; bar->barmove = 1; } davix-0.8.0/deps/curl/src/tool_getpass.c0000644000000000000000000001464314121063461016674 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(__AMIGA__) && !defined(__amigaos4__) # undef HAVE_TERMIOS_H #endif #ifndef HAVE_GETPASS_R /* this file is only for systems without getpass_r() */ #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_TERMIOS_H # include #elif defined(HAVE_TERMIO_H) # include #endif #ifdef __VMS # include descrip # include starlet # include iodef #endif #ifdef WIN32 # include #endif #ifdef NETWARE # ifdef __NOVELL_LIBC__ # include # else # include # endif #endif #ifdef HAVE_UNISTD_H #include #endif #include "tool_getpass.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef __VMS /* VMS implementation */ char *getpass_r(const char *prompt, char *buffer, size_t buflen) { long sts; short chan; /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */ /* distribution so I created this. May revert back later to */ /* struct _iosb iosb; */ struct _iosb { short int iosb$w_status; /* status */ short int iosb$w_bcnt; /* byte count */ int unused; /* unused */ } iosb; $DESCRIPTOR(ttdesc, "TT"); buffer[0] = '\0'; sts = sys$assign(&ttdesc, &chan, 0, 0); if(sts & 1) { sts = sys$qiow(0, chan, IO$_READPROMPT | IO$M_NOECHO, &iosb, 0, 0, buffer, buflen, 0, 0, prompt, strlen(prompt)); if((sts & 1) && (iosb.iosb$w_status & 1)) buffer[iosb.iosb$w_bcnt] = '\0'; sys$dassgn(chan); } return buffer; /* we always return success */ } #define DONE #endif /* __VMS */ #ifdef __SYMBIAN32__ # define getch() getchar() #endif #if defined(WIN32) || defined(__SYMBIAN32__) char *getpass_r(const char *prompt, char *buffer, size_t buflen) { size_t i; fputs(prompt, stderr); for(i = 0; i < buflen; i++) { buffer[i] = (char)getch(); if(buffer[i] == '\r' || buffer[i] == '\n') { buffer[i] = '\0'; break; } else if(buffer[i] == '\b') /* remove this letter and if this is not the first key, remove the previous one as well */ i = i - (i >= 1 ? 2 : 1); } #ifndef __SYMBIAN32__ /* since echo is disabled, print a newline */ fputs("\n", stderr); #endif /* if user didn't hit ENTER, terminate buffer */ if(i == buflen) buffer[buflen-1] = '\0'; return buffer; /* we always return success */ } #define DONE #endif /* WIN32 || __SYMBIAN32__ */ #ifdef NETWARE /* NetWare implementation */ #ifdef __NOVELL_LIBC__ char *getpass_r(const char *prompt, char *buffer, size_t buflen) { return getpassword(prompt, buffer, buflen); } #else char *getpass_r(const char *prompt, char *buffer, size_t buflen) { size_t i = 0; printf("%s", prompt); do { buffer[i++] = getch(); if(buffer[i-1] == '\b') { /* remove this letter and if this is not the first key, remove the previous one as well */ if(i > 1) { printf("\b \b"); i = i - 2; } else { RingTheBell(); i = i - 1; } } else if(buffer[i-1] != 13) putchar('*'); } while((buffer[i-1] != 13) && (i < buflen)); buffer[i-1] = '\0'; printf("\r\n"); return buffer; } #endif /* __NOVELL_LIBC__ */ #define DONE #endif /* NETWARE */ #ifndef DONE /* not previously provided */ #ifdef HAVE_TERMIOS_H # define struct_term struct termios #elif defined(HAVE_TERMIO_H) # define struct_term struct termio #else # undef struct_term #endif static bool ttyecho(bool enable, int fd) { #ifdef struct_term static struct_term withecho; static struct_term noecho; #endif if(!enable) { /* disable echo by extracting the current 'withecho' mode and remove the ECHO bit and set back the struct */ #ifdef HAVE_TERMIOS_H tcgetattr(fd, &withecho); noecho = withecho; noecho.c_lflag &= ~ECHO; tcsetattr(fd, TCSANOW, &noecho); #elif defined(HAVE_TERMIO_H) ioctl(fd, TCGETA, &withecho); noecho = withecho; noecho.c_lflag &= ~ECHO; ioctl(fd, TCSETA, &noecho); #else /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ (void)fd; return FALSE; /* not disabled */ #endif return TRUE; /* disabled */ } /* re-enable echo, assumes we disabled it before (and set the structs we now use to reset the terminal status) */ #ifdef HAVE_TERMIOS_H tcsetattr(fd, TCSAFLUSH, &withecho); #elif defined(HAVE_TERMIO_H) ioctl(fd, TCSETA, &withecho); #else return FALSE; /* not enabled */ #endif return TRUE; /* enabled */ } char *getpass_r(const char *prompt, /* prompt to display */ char *password, /* buffer to store password in */ size_t buflen) /* size of buffer to store password in */ { ssize_t nread; bool disabled; int fd = open("/dev/tty", O_RDONLY); if(-1 == fd) fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ disabled = ttyecho(FALSE, fd); /* disable terminal echo */ fputs(prompt, stderr); nread = read(fd, password, buflen); if(nread > 0) password[--nread] = '\0'; /* zero terminate where enter is stored */ else password[0] = '\0'; /* got nothing */ if(disabled) { /* if echo actually was disabled, add a newline */ fputs("\n", stderr); (void)ttyecho(TRUE, fd); /* enable echo */ } if(STDIN_FILENO != fd) close(fd); return password; /* return pointer to buffer */ } #endif /* DONE */ #endif /* HAVE_GETPASS_R */ davix-0.8.0/deps/curl/src/tool_hugehelp.c.cvs0000644000000000000000000000221314121063461017607 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_hugehelp.h" void hugehelp(void) { puts("This is a silly replacement for the actual file."); } davix-0.8.0/deps/curl/src/tool_operhlp.h0000644000000000000000000000267714121063461016710 0ustar rootroot#ifndef HEADER_CURL_TOOL_OPERHLP_H #define HEADER_CURL_TOOL_OPERHLP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" struct OperationConfig; void clean_getout(struct OperationConfig *config); bool output_expected(const char *url, const char *uploadfile); bool stdin_upload(const char *uploadfile); char *add_file_name_to_url(char *url, const char *filename); CURLcode get_url_file_name(char **filename, const char *url); #endif /* HEADER_CURL_TOOL_OPERHLP_H */ davix-0.8.0/deps/curl/src/tool_setopt.h0000644000000000000000000001362714121063461016552 0ustar rootroot#ifndef HEADER_CURL_TOOL_SETOPT_H #define HEADER_CURL_TOOL_SETOPT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_formparse.h" /* * Macros used in operate() */ #define SETOPT_CHECK(v,opt) do { \ if(!tool_setopt_skip(opt)) { \ result = (v); \ if(result) \ break; \ } \ } while(0) /* allow removed features to simulate success: */ bool tool_setopt_skip(CURLoption tag); #ifndef CURL_DISABLE_LIBCURL_OPTION /* Associate symbolic names with option values */ typedef struct { const char *name; long value; } NameValue; typedef struct { const char *name; unsigned long value; } NameValueUnsigned; extern const NameValue setopt_nv_CURLPROXY[]; extern const NameValue setopt_nv_CURL_SOCKS_PROXY[]; extern const NameValue setopt_nv_CURL_HTTP_VERSION[]; extern const NameValue setopt_nv_CURL_SSLVERSION[]; extern const NameValue setopt_nv_CURL_TIMECOND[]; extern const NameValue setopt_nv_CURLFTPSSL_CCC[]; extern const NameValue setopt_nv_CURLUSESSL[]; extern const NameValueUnsigned setopt_nv_CURLSSLOPT[]; extern const NameValue setopt_nv_CURL_NETRC[]; extern const NameValue setopt_nv_CURLPROTO[]; extern const NameValueUnsigned setopt_nv_CURLAUTH[]; /* Map options to NameValue sets */ #define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION #define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION #define setopt_nv_CURLOPT_PROXY_SSLVERSION setopt_nv_CURL_SSLVERSION #define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND #define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC #define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL #define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT #define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC #define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY #define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH /* Intercept setopt calls for --libcurl */ CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValue *nv, long lval); CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValue *nv, long lval); CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValueUnsigned *nv, long lval); CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, curl_mime *mimepost); CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, struct curl_slist *list); CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config, const char *name, CURLoption tag, ...); #define my_setopt(x,y,z) \ SETOPT_CHECK(tool_setopt(x, FALSE, global, #y, y, z), y) #define my_setopt_str(x,y,z) \ SETOPT_CHECK(tool_setopt(x, TRUE, global, #y, y, z), y) #define my_setopt_enum(x,y,z) \ SETOPT_CHECK(tool_setopt_enum(x, global, #y, y, setopt_nv_ ## y, z), y) #define my_setopt_flags(x,y,z) \ SETOPT_CHECK(tool_setopt_flags(x, global, #y, y, setopt_nv_ ## y, z), y) #define my_setopt_bitmask(x,y,z) \ SETOPT_CHECK(tool_setopt_bitmask(x, global, #y, y, setopt_nv_ ## y, z), y) #define my_setopt_mimepost(x,y,z) \ SETOPT_CHECK(tool_setopt_mimepost(x, global, #y, y, z), y) #define my_setopt_slist(x,y,z) \ SETOPT_CHECK(tool_setopt_slist(x, global, #y, y, z), y) #define res_setopt(x,y,z) tool_setopt(x, FALSE, global, #y, y, z) #define res_setopt_str(x,y,z) tool_setopt(x, TRUE, global, #y, y, z) #else /* CURL_DISABLE_LIBCURL_OPTION */ /* No --libcurl, so pass options directly to library */ #define my_setopt(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_str(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_enum(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_flags(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_bitmask(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_mimepost(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define my_setopt_slist(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z), y) #define res_setopt(x,y,z) curl_easy_setopt(x,y,z) #define res_setopt_str(x,y,z) curl_easy_setopt(x,y,z) #endif /* CURL_DISABLE_LIBCURL_OPTION */ #endif /* HEADER_CURL_TOOL_SETOPT_H */ davix-0.8.0/deps/curl/src/tool_xattr.h0000644000000000000000000000225214121063461016366 0ustar rootroot#ifndef HEADER_CURL_TOOL_XATTR_H #define HEADER_CURL_TOOL_XATTR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" int fwrite_xattr(CURL *curl, int fd); #endif /* HEADER_CURL_TOOL_XATTR_H */ davix-0.8.0/deps/curl/src/tool_bname.c0000644000000000000000000000264214121063461016304 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_bname.h" #include "memdebug.h" /* keep this as LAST include */ #ifndef HAVE_BASENAME char *tool_basename(char *path) { char *s1; char *s2; s1 = strrchr(path, '/'); s2 = strrchr(path, '\\'); if(s1 && s2) { path = (s1 > s2) ? s1 + 1 : s2 + 1; } else if(s1) path = s1 + 1; else if(s2) path = s2 + 1; return path; } #endif /* HAVE_BASENAME */ davix-0.8.0/deps/curl/src/tool_strdup.h0000644000000000000000000000227114121063461016546 0ustar rootroot#ifndef HEADER_TOOL_STRDUP_H #define HEADER_TOOL_STRDUP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef HAVE_STRDUP extern char *strdup(const char *str); #endif #endif /* HEADER_TOOL_STRDUP_H */ davix-0.8.0/deps/curl/src/tool_vms.c0000644000000000000000000001440114121063461016023 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef __VMS #if defined(__DECC) && !defined(__VAX) && \ defined(__CRTL_VER) && (__CRTL_VER >= 70301000) #include #endif #define ENABLE_CURLX_PRINTF #include "curlx.h" #include "curlmsg_vms.h" #include "tool_vms.h" #include "memdebug.h" /* keep this as LAST include */ void decc$__posix_exit(int __status); void decc$exit(int __status); static int vms_shell = -1; /* VMS has a DCL shell and and also has Unix shells ported to it. * When curl is running under a Unix shell, we want it to be as much * like Unix as possible. */ int is_vms_shell(void) { char *shell; /* Have we checked the shell yet? */ if(vms_shell >= 0) return vms_shell; shell = getenv("SHELL"); /* No shell, means DCL */ if(shell == NULL) { vms_shell = 1; return 1; } /* Have to make sure some one did not set shell to DCL */ if(strcmp(shell, "DCL") == 0) { vms_shell = 1; return 1; } vms_shell = 0; return 0; } /* * VMS has two exit() routines. When running under a Unix style shell, then * Unix style and the __posix_exit() routine is used. * * When running under the DCL shell, then the VMS encoded codes and decc$exit() * is used. * * We can not use exit() or return a code from main() because the actual * routine called depends on both the compiler version, compile options, and * feature macro settings, and one of the exit routines is hidden at compile * time. * * Since we want Curl to work properly under the VMS DCL shell and Unix * shells under VMS, this routine should compile correctly regardless of * the settings. */ void vms_special_exit(int code, int vms_show) { int vms_code; /* The Posix exit mode is only available after VMS 7.0 */ #if __CRTL_VER >= 70000000 if(is_vms_shell() == 0) { decc$__posix_exit(code); } #endif if(code > CURL_LAST) { /* If CURL_LAST exceeded then */ vms_code = CURL_LAST; /* curlmsg.h is out of sync. */ } else { vms_code = vms_cond[code] | vms_show; } decc$exit(vms_code); } #if defined(__DECC) && !defined(__VAX) && \ defined(__CRTL_VER) && (__CRTL_VER >= 70301000) /* * 2004-09-19 SMS. * * decc_init() * * On non-VAX systems, use LIB$INITIALIZE to set a collection of C * RTL features without using the DECC$* logical name method, nor * requiring the user to define the corresponding logical names. */ /* Structure to hold a DECC$* feature name and its desired value. */ typedef struct { char *name; int value; } decc_feat_t; /* Array of DECC$* feature names and their desired values. */ static decc_feat_t decc_feat_array[] = { /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */ { "DECC$ARGV_PARSE_STYLE", 1 }, /* Preserve case for file names on ODS5 disks. */ { "DECC$EFS_CASE_PRESERVE", 1 }, /* Enable multiple dots (and most characters) in ODS5 file names, while preserving VMS-ness of ";version". */ { "DECC$EFS_CHARSET", 1 }, /* List terminator. */ { (char *)NULL, 0 } }; /* Flag to sense if decc_init() was called. */ static int decc_init_done = -1; /* LIB$INITIALIZE initialization function. */ static void decc_init(void) { int feat_index; int feat_value; int feat_value_max; int feat_value_min; int i; int sts; /* Set the global flag to indicate that LIB$INITIALIZE worked. */ decc_init_done = 1; /* Loop through all items in the decc_feat_array[]. */ for(i = 0; decc_feat_array[i].name != NULL; i++) { /* Get the feature index. */ feat_index = decc$feature_get_index(decc_feat_array[i].name); if(feat_index >= 0) { /* Valid item. Collect its properties. */ feat_value = decc$feature_get_value(feat_index, 1); feat_value_min = decc$feature_get_value(feat_index, 2); feat_value_max = decc$feature_get_value(feat_index, 3); if((decc_feat_array[i].value >= feat_value_min) && (decc_feat_array[i].value <= feat_value_max)) { /* Valid value. Set it if necessary. */ if(feat_value != decc_feat_array[i].value) { sts = decc$feature_set_value(feat_index, 1, decc_feat_array[i].value); } } else { /* Invalid DECC feature value. */ printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", feat_value, feat_value_min, decc_feat_array[i].name, feat_value_max); } } else { /* Invalid DECC feature name. */ printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name); } } } /* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */ #pragma nostandard /* Establish the LIB$INITIALIZE PSECTs, with proper alignment and other attributes. Note that "nopic" is significant only on VAX. */ #pragma extern_model save #pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt const int spare[8] = {0}; #pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt void (*const x_decc_init)() = decc_init; #pragma extern_model restore /* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */ #pragma extern_model save int LIB$INITIALIZE(void); #pragma extern_model strict_refdef int dmy_lib$initialize = (int) LIB$INITIALIZE; #pragma extern_model restore #pragma standard #endif /* __DECC && !__VAX && __CRTL_VER && __CRTL_VER >= 70301000 */ #endif /* __VMS */ davix-0.8.0/deps/curl/src/tool_util.c0000644000000000000000000000752714121063461016206 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_util.h" #include "memdebug.h" /* keep this as LAST include */ #if defined(WIN32) && !defined(MSDOS) /* set in win32_init() */ extern LARGE_INTEGER Curl_freq; extern bool Curl_isVistaOrGreater; /* In case of bug fix this function has a counterpart in timeval.c */ struct timeval tvnow(void) { struct timeval now; if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ LARGE_INTEGER count; QueryPerformanceCounter(&count); now.tv_sec = (long)(count.QuadPart / Curl_freq.QuadPart); now.tv_usec = (long)((count.QuadPart % Curl_freq.QuadPart) * 1000000 / Curl_freq.QuadPart); } else { /* Disable /analyze warning that GetTickCount64 is preferred */ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:28159) #endif DWORD milliseconds = GetTickCount(); #if defined(_MSC_VER) #pragma warning(pop) #endif now.tv_sec = (long)(milliseconds / 1000); now.tv_usec = (long)((milliseconds % 1000) * 1000); } return now; } #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) struct timeval tvnow(void) { /* ** clock_gettime() is granted to be increased monotonically when the ** monotonic clock is queried. Time starting point is unspecified, it ** could be the system start-up time, the Epoch, or something else, ** in any case the time starting point does not change once that the ** system has started up. */ struct timeval now; struct timespec tsnow; if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { now.tv_sec = tsnow.tv_sec; now.tv_usec = tsnow.tv_nsec / 1000; } /* ** Even when the configure process has truly detected monotonic clock ** availability, it might happen that it is not actually available at ** run-time. When this occurs simply fallback to other time source. */ #ifdef HAVE_GETTIMEOFDAY else (void)gettimeofday(&now, NULL); #else else { now.tv_sec = (long)time(NULL); now.tv_usec = 0; } #endif return now; } #elif defined(HAVE_GETTIMEOFDAY) struct timeval tvnow(void) { /* ** gettimeofday() is not granted to be increased monotonically, due to ** clock drifting and external source time synchronization it can jump ** forward or backward in time. */ struct timeval now; (void)gettimeofday(&now, NULL); return now; } #else struct timeval tvnow(void) { /* ** time() returns the value of time in seconds since the Epoch. */ struct timeval now; now.tv_sec = (long)time(NULL); now.tv_usec = 0; return now; } #endif /* * Make sure that the first argument is the more recent time, as otherwise * we'll get a weird negative time-diff back... * * Returns: the time difference in number of milliseconds. */ long tvdiff(struct timeval newer, struct timeval older) { return (long)(newer.tv_sec-older.tv_sec)*1000+ (long)(newer.tv_usec-older.tv_usec)/1000; } davix-0.8.0/deps/curl/src/tool_msgs.h0000644000000000000000000000255714121063461016205 0ustar rootroot#ifndef HEADER_CURL_TOOL_MSGS_H #define HEADER_CURL_TOOL_MSGS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" void warnf(struct GlobalConfig *config, const char *fmt, ...); void notef(struct GlobalConfig *config, const char *fmt, ...); void helpf(FILE *errors, const char *fmt, ...); void errorf(struct GlobalConfig *config, const char *fmt, ...); #endif /* HEADER_CURL_TOOL_MSGS_H */ davix-0.8.0/deps/curl/src/tool_vms.h0000644000000000000000000000315514121063461016034 0ustar rootroot#ifndef HEADER_CURL_TOOL_VMS_H #define HEADER_CURL_TOOL_VMS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef __VMS /* * Forward-declaration of global variable vms_show defined * in tool_main.c, used in main() as parameter for function * vms_special_exit() to allow proper curl tool exiting. */ extern int vms_show; int is_vms_shell(void); void vms_special_exit(int code, int vms_show); #undef exit #define exit(__code) vms_special_exit((__code), (0)) #define VMS_STS(c,f,e,s) (((c&0xF)<<28)|((f&0xFFF)<<16)|((e&0x1FFF)<3)|(s&7)) #define VMSSTS_HIDE VMS_STS(1,0,0,0) #endif /* __VMS */ #endif /* HEADER_CURL_TOOL_VMS_H */ davix-0.8.0/deps/curl/src/tool_cb_wrt.c0000644000000000000000000001414014121063461016476 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_msgs.h" #include "tool_cb_wrt.h" #include "tool_operate.h" #include "memdebug.h" /* keep this as LAST include */ /* create a local file for writing, return TRUE on success */ bool tool_create_output_file(struct OutStruct *outs, struct OperationConfig *config) { struct GlobalConfig *global; FILE *file; DEBUGASSERT(outs); DEBUGASSERT(config); global = config->global; if(!outs->filename || !*outs->filename) { warnf(global, "Remote filename has no length!\n"); return FALSE; } if(outs->is_cd_filename) { /* don't overwrite existing files */ file = fopen(outs->filename, "rb"); if(file) { fclose(file); warnf(global, "Refusing to overwrite %s: %s\n", outs->filename, strerror(EEXIST)); return FALSE; } } /* open file for writing */ file = fopen(outs->filename, "wb"); if(!file) { warnf(global, "Failed to create the file %s: %s\n", outs->filename, strerror(errno)); return FALSE; } outs->s_isreg = TRUE; outs->fopened = TRUE; outs->stream = file; outs->bytes = 0; outs->init = 0; return TRUE; } /* ** callback for CURLOPT_WRITEFUNCTION */ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) { size_t rc; struct per_transfer *per = userdata; struct OutStruct *outs = &per->outs; struct OperationConfig *config = per->config; size_t bytes = sz * nmemb; bool is_tty = config->global->isatty; #ifdef WIN32 CONSOLE_SCREEN_BUFFER_INFO console_info; intptr_t fhnd; #endif /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = bytes ? 0 : 1; #ifdef DEBUGBUILD { char *tty = curlx_getenv("CURL_ISATTY"); if(tty) { is_tty = TRUE; curl_free(tty); } } if(config->show_headers) { if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { warnf(config->global, "Header data size exceeds single call write " "limit!\n"); return failure; } } else { if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { warnf(config->global, "Data size exceeds single call write limit!\n"); return failure; } } { /* Some internal congruency checks on received OutStruct */ bool check_fails = FALSE; if(outs->filename) { /* regular file */ if(!*outs->filename) check_fails = TRUE; if(!outs->s_isreg) check_fails = TRUE; if(outs->fopened && !outs->stream) check_fails = TRUE; if(!outs->fopened && outs->stream) check_fails = TRUE; if(!outs->fopened && outs->bytes) check_fails = TRUE; } else { /* standard stream */ if(!outs->stream || outs->s_isreg || outs->fopened) check_fails = TRUE; if(outs->alloc_filename || outs->is_cd_filename || outs->init) check_fails = TRUE; } if(check_fails) { warnf(config->global, "Invalid output struct data for write callback\n"); return failure; } } #endif if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { /* binary output to terminal? */ if(memchr(buffer, 0, bytes)) { warnf(config->global, "Binary output can mess up your terminal. " "Use \"--output -\" to tell curl to output it to your terminal " "anyway, or consider \"--output \" to save to a file.\n"); config->synthetic_error = ERR_BINARY_TERMINAL; return failure; } } #ifdef WIN32 fhnd = _get_osfhandle(fileno(outs->stream)); if(isatty(fileno(outs->stream)) && GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) { DWORD in_len = (DWORD)(sz * nmemb); wchar_t* wc_buf; DWORD wc_len; /* calculate buffer size for wide characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, NULL, 0); wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); if(!wc_buf) return failure; /* calculate buffer size for multi-byte characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len); if(!wc_len) { free(wc_buf); return failure; } if(!WriteConsoleW( (HANDLE) fhnd, wc_buf, wc_len, &wc_len, NULL)) { free(wc_buf); return failure; } free(wc_buf); rc = bytes; } else #endif rc = fwrite(buffer, sz, nmemb, outs->stream); if(bytes == rc) /* we added this amount of data to the output */ outs->bytes += bytes; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(per->curl, CURLPAUSE_CONT); } if(config->nobuffer) { /* output buffering disabled */ int res = fflush(outs->stream); if(res) return failure; } return rc; } davix-0.8.0/deps/curl/src/Makefile.netware0000644000000000000000000003236114121063461017126 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2004 - 2014, Guenter Knauf # Copyright (C) 2001 - 2018, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** ################################################################# # ## Makefile for building curl.nlm (NetWare version - gnu make) ## ## Use: make -f Makefile.netware # ################################################################# # Edit the path below to point to the base of your Novell NDK. ifndef NDKBASE NDKBASE = c:/novell endif # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH ZLIB_PATH = ../../zlib-1.2.8 endif # Edit the path below to point to the base of your OpenSSL package. ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-1.0.2a endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH LIBSSH2_PATH = ../../libssh2-1.5.0 endif # Edit the path below to point to the base of your libidn package. ifndef LIBIDN_PATH LIBIDN_PATH = ../../libidn-1.18 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.3 endif # Edit the path below to point to the base of your nghttp2 package. ifndef NGHTTP2_PATH NGHTTP2_PATH = ../../nghttp2-0.6.7 endif # Edit the path below to point to the base of your fbopenssl package. ifndef FBOPENSSL_PATH FBOPENSSL_PATH = ../../fbopenssl-0.4 endif # Edit the path below to point to the base of your libmetalink package. ifndef LIBMETALINK_PATH LIBMETALINK_PATH = ../../libmetalink-0.1.2 endif # Edit the path below to point to the base of your libexpat package. ifndef LIBEXPAT_PATH LIBEXPAT_PATH = ../../expat-2.1.0 endif # Edit the path below to point to the base of your libXML2 package. ifndef LIBXML2_PATH LIBXML2_PATH = ../../libxml2-2.8.0 endif # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = ../ares endif ifndef INSTDIR INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw endif # Edit the vars below to change NLM target settings. TARGET = curl VERSION = $(LIBCURL_VERSION) COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) DESCR = curl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se MTSAFE = YES STACK = 64000 SCREEN = $(TARGET) commandline utility # Comment the line below if you don't want to load protected automatically. # LDRING = 3 # Uncomment the next line to enable linking with POSIX semantics. # POSIXFL = 1 # Edit the var below to point to your lib architecture. ifndef LIBARCH LIBARCH = LIBC endif # must be equal to NDEBUG or DEBUG, CURLDEBUG ifndef DB DB = NDEBUG endif # Optimization: -O or debugging: -g ifeq ($(DB),NDEBUG) OPT = -O2 OBJDIR = release else OPT = -g OBJDIR = debug endif # The following lines defines your compiler. ifdef CWFolder METROWERKS = $(CWFolder) endif ifdef METROWERKS # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support CC = mwccnlm else CC = gcc endif PERL = perl # Here you can find a native Win32 binary of the original awk: # http://www.gknw.net/development/prgtools/awk-20100523.zip AWK = awk CP = cp -afv MKDIR = mkdir # RM = rm -f # If you want to mark the target as MTSAFE you will need a tool for # generating the xdc data for the linker; here's a minimal tool: # http://www.gknw.net/development/prgtools/mkxdc.zip MPKXDC = mkxdc # LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH)) LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH)) # Include the version info retrieved from curlver.h -include $(OBJDIR)/version.inc # Global flags for all compilers CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc ifeq ($(CC),mwccnlm) LD = mwldnlm LDFLAGS = -nostdlib $(OBJS) $(PRELUDE) $(LDLIBS) -o $@ -commandfile LIBEXT = lib CFLAGS += -gccinc -inline off -opt nointrinsics -proc 586 CFLAGS += -relax_pointers #CFLAGS += -w on ifeq ($(LIBARCH),LIBC) ifeq ($(POSIXFL),1) PRELUDE = $(NDK_LIBC)/imports/posixpre.o else PRELUDE = $(NDK_LIBC)/imports/libcpre.o endif CFLAGS += -align 4 else # PRELUDE = $(NDK_CLIB)/imports/clibpre.o # to avoid the __init_* / __deinit_* woes don't use prelude from NDK PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj" # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h" CFLAGS += -align 1 endif else LD = nlmconv LDFLAGS = -T LIBEXT = a CFLAGS += -m32 CFLAGS += -fno-builtin -fno-strict-aliasing ifeq ($(findstring gcc,$(CC)),gcc) CFLAGS += -fpcc-struct-return endif CFLAGS += -Wall # -pedantic ifeq ($(LIBARCH),LIBC) ifeq ($(POSIXFL),1) PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o else PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o endif else # PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o # to avoid the __init_* / __deinit_* woes don't use prelude from NDK # http://www.gknw.net/development/mk_nlm/gcc_pre.zip PRELUDE = $(NDK_ROOT)/pre/prelude.o CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h endif endif NDK_ROOT = $(NDKBASE)/ndk ifndef NDK_CLIB NDK_CLIB = $(NDK_ROOT)/nwsdk endif ifndef NDK_LIBC NDK_LIBC = $(NDK_ROOT)/libc endif ifndef NDK_LDAP NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware endif CURL_INC = ../include CURL_LIB = ../lib INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) ifeq ($(findstring -static,$(CFG)),-static) LINK_STATIC = 1 endif ifeq ($(findstring -ares,$(CFG)),-ares) WITH_ARES = 1 endif ifeq ($(findstring -rtmp,$(CFG)),-rtmp) WITH_RTMP = 1 WITH_SSL = 1 WITH_ZLIB = 1 endif ifeq ($(findstring -ssh2,$(CFG)),-ssh2) WITH_SSH2 = 1 WITH_SSL = 1 WITH_ZLIB = 1 endif ifeq ($(findstring -ssl,$(CFG)),-ssl) WITH_SSL = 1 endif ifeq ($(findstring -zlib,$(CFG)),-zlib) WITH_ZLIB = 1 endif ifeq ($(findstring -idn,$(CFG)),-idn) WITH_IDN = 1 endif ifeq ($(findstring -metalink,$(CFG)),-metalink) WITH_METALINK = 1 WITH_SSL = 1 endif ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) WITH_NGHTTP2 = 1 endif ifeq ($(findstring -ipv6,$(CFG)),-ipv6) ENABLE_IPV6 = 1 endif ifdef LINK_STATIC LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT) ifdef WITH_ARES LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) endif else MODULES = libcurl.nlm IMPORTS = @$(CURL_LIB)/libcurl.imp endif ifdef WITH_SSH2 # INCLUDES += -I$(LIBSSH2_PATH)/include ifdef LINK_STATIC LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) else MODULES += libssh2.nlm IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp endif endif ifdef WITH_RTMP # INCLUDES += -I$(LIBRTMP_PATH) ifdef LINK_STATIC LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT) endif endif ifdef WITH_SSL # INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) IMPORTS += GetProcessSwitchCount RunningProcess endif ifdef WITH_ZLIB INCLUDES += -I$(ZLIB_PATH) ifdef LINK_STATIC LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT) else MODULES += libz.nlm IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp endif endif ifdef WITH_IDN # INCLUDES += -I$(LIBIDN_PATH)/include LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT) endif ifdef WITH_NGHTTP2 INCLUDES += -I$(NGHTTP2_PATH)/include LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT) endif ifdef WITH_METALINK CFLAGS += -DUSE_METALINK INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) INCLUDES += -I$(LIBMETALINK_PATH)/include LDLIBS += $(LIBMETALINK_PATH)/lib/libmetalink.$(LIBEXT) ifdef WITH_LIBEXPAT ifeq ($(LIBARCH),LIBC) IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlbc.imp MODULES += expatlbc else IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlib.imp MODULES += expatlib endif else ifdef WITH_LIBXML2 IMPORTS += @$(LIBXML2_PATH)/lib/libxml2.imp MODULES += libxml2 endif endif endif ifeq ($(LIBARCH),LIBC) INCLUDES += -I$(NDK_LIBC)/include # INCLUDES += -I$(NDK_LIBC)/include/nks # INCLUDES += -I$(NDK_LIBC)/include/winsock CFLAGS += -D_POSIX_SOURCE else INCLUDES += -I$(NDK_CLIB)/include/nlm # INCLUDES += -I$(NDK_CLIB)/include endif ifndef DISABLE_LDAP # INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc endif CFLAGS += $(INCLUDES) ifeq ($(MTSAFE),YES) XDCOPT = -n endif ifeq ($(MTSAFE),NO) XDCOPT = -u endif ifdef XDCOPT XDCDATA = $(OBJDIR)/$(TARGET).xdc endif ifeq ($(findstring /sh,$(SHELL)),/sh) DL = ' DS = / PCT = % #-include $(NDKBASE)/nlmconv/ncpfs.inc else DS = \\ PCT = %% endif # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc OBJX := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(strip $(CURLX_CFILES)))) OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(CURL_CFILES))) ifndef LINK_STATIC OBJS += $(OBJX) endif vpath %.c $(CURL_LIB) all: prebuild $(TARGET).nlm prebuild: $(OBJDIR) $(OBJDIR)/version.inc $(OBJDIR)/%.o: %.c # @echo Compiling $< $(CC) $(CFLAGS) -c $< -o $@ $(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR) @echo Creating $@ @$(AWK) -f ../packages/NetWare/get_ver.awk $< > $@ install: $(INSTDIR) all @-$(CP) ../docs/$(TARGET).pdf $(INSTDIR) @-$(CP) ../docs/$(TARGET).html $(INSTDIR) @$(CP) $(TARGET).nlm $(INSTDIR) clean: ifeq "$(wildcard tool_hugehelp.c.cvs)" "tool_hugehelp.c.cvs" -$(RM) tool_hugehelp.c endif -$(RM) -r $(OBJDIR) distclean vclean: clean -$(RM) $(TARGET).nlm $(OBJDIR) $(INSTDIR): @$(MKDIR) $@ $(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA) @echo Linking $@ @-$(RM) $@ @$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def $(OBJDIR)/%.xdc: Makefile.netware @echo Creating $@ @$(MPKXDC) $(XDCOPT) $@ $(OBJDIR)/%.def: Makefile.netware @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@ @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@ @echo $(DL)# All your changes will be lost!!$(DL) >> $@ @echo $(DL)#$(DL) >> $@ @echo $(DL)copyright "$(COPYR)"$(DL) >> $@ @echo $(DL)description "$(DESCR)"$(DL) >> $@ @echo $(DL)version $(VERSION)$(DL) >> $@ ifdef NLMTYPE @echo $(DL)type $(NLMTYPE)$(DL) >> $@ endif ifdef STACK @echo $(DL)stack $(STACK)$(DL) >> $@ endif ifdef SCREEN @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@ else @echo $(DL)screenname "DEFAULT"$(DL) >> $@ endif ifneq ($(DB),NDEBUG) @echo $(DL)debug$(DL) >> $@ endif @echo $(DL)threadname "$(TARGET)"$(DL) >> $@ ifdef XDCDATA @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@ endif ifeq ($(LDRING),0) @echo $(DL)flag_on 16$(DL) >> $@ endif ifeq ($(LDRING),3) @echo $(DL)flag_on 512$(DL) >> $@ endif ifeq ($(LIBARCH),CLIB) @echo $(DL)start _Prelude$(DL) >> $@ @echo $(DL)exit _Stop$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@ @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@ @echo $(DL)module clib$(DL) >> $@ ifndef DISABLE_LDAP @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@ # @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@ @echo $(DL)module ldapsdk ldapssl$(DL) >> $@ endif else ifeq ($(POSIXFL),1) @echo $(DL)flag_on 4194304$(DL) >> $@ endif @echo $(DL)flag_on 64$(DL) >> $@ @echo $(DL)pseudopreemption$(DL) >> $@ ifeq ($(findstring posixpre,$(PRELUDE)),posixpre) @echo $(DL)start POSIX_Start$(DL) >> $@ @echo $(DL)exit POSIX_Stop$(DL) >> $@ @echo $(DL)check POSIX_CheckUnload$(DL) >> $@ else @echo $(DL)start _LibCPrelude$(DL) >> $@ @echo $(DL)exit _LibCPostlude$(DL) >> $@ @echo $(DL)check _LibCCheckUnload$(DL) >> $@ endif @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@ @echo $(DL)module libc$(DL) >> $@ ifndef DISABLE_LDAP @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@ @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@ # @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@ @echo $(DL)module lldapsdk lldapssl$(DL) >> $@ endif endif ifdef MODULES @echo $(DL)module $(MODULES)$(DL) >> $@ endif ifdef EXPORTS @echo $(DL)export $(EXPORTS)$(DL) >> $@ endif ifdef IMPORTS @echo $(DL)import $(IMPORTS)$(DL) >> $@ endif ifeq ($(findstring nlmconv,$(LD)),nlmconv) @echo $(DL)input $(PRELUDE)$(DL) >> $@ @echo $(DL)input $(OBJS)$(DL) >> $@ ifdef LDLIBS @echo $(DL)input $(LDLIBS)$(DL) >> $@ endif @echo $(DL)output $(TARGET).nlm$(DL) >> $@ endif tool_hugehelp.c: @echo Creating $@ @$(CP) tool_hugehelp.c.cvs $@ $(LIBCARES_PATH)/libcares.$(LIBEXT): $(MAKE) -C $(LIBCARES_PATH) -f Makefile.netware lib davix-0.8.0/deps/curl/src/tool_panykey.c0000644000000000000000000000265514121063461016706 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(__SYMBIAN32__) || defined(NETWARE) #ifdef NETWARE # ifdef __NOVELL_LIBC__ # include # else # include # endif #endif #include "tool_panykey.h" #include "memdebug.h" /* keep this as LAST include */ void tool_pressanykey(void) { #if defined(__SYMBIAN32__) getchar(); #elif defined(NETWARE) pressanykey(); #endif } #endif /* __SYMBIAN32__ || NETWARE */ davix-0.8.0/deps/curl/src/tool_filetime.h0000644000000000000000000000305714121063461017026 0ustar rootroot#ifndef HEADER_CURL_TOOL_FILETIME_H #define HEADER_CURL_TOOL_FILETIME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" curl_off_t getfiletime(const char *filename, FILE *error_stream); #if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) void setfiletime(curl_off_t filetime, const char *filename, FILE *error_stream); #else #define setfiletime(a,b,c) Curl_nop_stmt #endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */ #endif /* HEADER_CURL_TOOL_FILETIME_H */ davix-0.8.0/deps/curl/src/Makefile.Watcom0000644000000000000000000001277514121063461016722 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2005 - 2008, Gisle Vanem . # Copyright (C) 2005 - 2015, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # # Watcom / OpenWatcom / Win32 makefile for curl. # .ERASE !if $(__VERSION__) < 1280 !message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !message ! This Open Watcom version is too old and is no longer supported ! !message ! Please download latest version from www.openwatcom.org ! !message !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !error Unsupported version of Open Watcom !endif !ifndef %watcom !error WATCOM environment variable not set! !endif # In order to process Makefile.inc wmake must be called with -u switch! !ifndef %MAKEFLAGS !error You MUST call wmake with the -u switch! !endif !ifdef %libname LIBNAME = $(%libname) !else LIBNAME = libcurl !endif TARGETS = curl.exe CC = wcc386 LD = wlink AR = wlib RC = wrc !ifdef __LOADDLL__ ! loaddll wcc386 wccd386 ! loaddll wpp386 wppd386 ! loaddll wlib wlibd ! loaddll wlink wlinkd !endif !ifdef __UNIX__ CP = cp MD = mkdir -p !else CP = copy 2>NUL MD = mkdir !endif !if $(__VERSION__) > 1290 RD = rm -rf !else ifdef __UNIX__ RD = rm -rf !else RD = rmdir /q /s 2>NUL !endif SYS_INCL = -I"$(%watcom)/h/nt" -I"$(%watcom)/h" CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -s -fr=con -w2 -fpi -oilrtfm & -wcd=201 -bt=nt -bc -d+ -dWIN32 -dHAVE_STRTOLL & -I"../include" -I"../lib" $(SYS_INCL) !ifdef %debug DEBUG = -dDEBUG=1 -dDEBUGBUILD CFLAGS += -d3 $(DEBUG) !else CFLAGS += -d0 !endif !ifdef %use_ipv6 CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6 !endif !ifdef %use_ssl CFLAGS += -wcd=138 -dUSE_OPENSSL -dUSE_OPENSSL -I"$(OPENSSL_ROOT)/inc32" !endif !ifdef %curl_static CFLAGS += -DCURL_STATICLIB !else CFLAGS += -br !endif # # Change to suite. # !ifdef %zlib_root ZLIB_ROOT = $(%zlib_root) !else ZLIB_ROOT = ../../zlib-1.2.8 !endif !ifdef %libssh2_root LIBSSH2_ROOT = $(%libssh2_root) !else LIBSSH2_ROOT = ../../libssh2-1.5.0 !endif !ifdef %librtmp_root LIBRTMP_ROOT = $(%librtmp_root) !else LIBRTMP_ROOT = ../../rtmpdump-2.3 !endif !ifdef %openssl_root OPENSSL_ROOT = $(%openssl_root) !else OPENSSL_ROOT = ../../openssl-1.0.2a !endif !ifdef %ares_root ARES_ROOT = $(%ares_root) !else ARES_ROOT = ../ares !endif OBJ_DIR = WC_Win32.obj LINK_ARG = $(OBJ_DIR)/wlink.arg !include Makefile.inc OBJS1 = $(OBJ_DIR)/$(CURL_CFILES) !ifndef %curl_static OBJS1 += $(CURLX_CFILES:../lib/=) !endif OBJS2 = $(OBJS1: = $(OBJ_DIR)/) OBJS = $(OBJS2:.c=.obj) RESOURCE = $(OBJ_DIR)/curl.res DIRS = $(OBJ_DIR) all: tool_hugehelp.c $(DIRS) $(TARGETS) .SYMBOLIC @echo Welcome to curl clean: .SYMBOLIC -rm -f $(OBJS) -rm -f $(RESOURCE) $(LINK_ARG) vclean distclean: clean .SYMBOLIC -$(RD) $(OBJ_DIR) -rm -f curl.exe curl.sym tool_hugehelp.c tool_hugehelp.c: tool_hugehelp.c.cvs $(CP) $[@ $^@ tool_hugehelp.c.cvs: .EXISTSONLY $(CP) tool_hugehelp.c $^@ $(DIRS): -$(MD) $^@ curl.exe: $(OBJS) $(RESOURCE) %create $(LINK_ARG) @%append $(LINK_ARG) system nt !ifdef %debug @%append $(LINK_ARG) debug all @%append $(LINK_ARG) option symfile !endif @%append $(LINK_ARG) option quiet, caseexact, eliminate @%append $(LINK_ARG) option map=$(OBJ_DIR)/$^&.map @%append $(LINK_ARG) option res=$(RESOURCE) @%append $(LINK_ARG) file { $(OBJS) } !ifndef %curl_static @%append $(LINK_ARG) library ../lib/$(LIBNAME)_imp.lib !else @%append $(LINK_ARG) library ../lib/$(LIBNAME).lib @%append $(LINK_ARG) library wldap32.lib ! ifdef %use_zlib @%append $(LINK_ARG) library '$(ZLIB_ROOT)/zlib.lib' ! endif ! ifdef %use_rtmp @%append $(LINK_ARG) library '$(LIBRTMP_ROOT)/librtmp/librtmp.lib' @%append $(LINK_ARG) library winmm.lib ! endif ! ifdef %use_ssh2 @%append $(LINK_ARG) library '$(LIBSSH2_ROOT)/win32/libssh2.lib' ! endif ! ifdef %use_ssl @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/libeay32.lib' @%append $(LINK_ARG) library '$(OPENSSL_ROOT)/out32/ssleay32.lib' ! endif ! ifdef %use_ares @%append $(LINK_ARG) library '$(ARES_ROOT)/cares.lib' ! endif ! ifdef %use_winidn ! if $(__VERSION__) > 1290 @%append $(LINK_ARG) library normaliz.lib ! else @%append $(LINK_ARG) import '_IdnToAscii@20' 'NORMALIZ.DLL'.'IdnToAscii' @%append $(LINK_ARG) import '_IdnToUnicode@20' 'NORMALIZ.DLL'.'IdnToUnicode' ! endif ! endif !endif !ifeq USE_WATT32 1 @%append $(LINK_ARG) library '$(%watt_root)/lib/wattcpw_imp.lib' !else @%append $(LINK_ARG) library ws2_32.lib !endif $(LD) name $^@ @$(LINK_ARG) $(RESOURCE): curl.rc $(RC) $(DEBUG) -q -r -zm -bt=nt -I"../include" $(SYS_INCL) $[@ -fo=$^@ # suffix search path - vpath-like hack .c: ../lib .c{$(OBJ_DIR)}.obj: $(CC) $(CFLAGS) $[@ -fo=$^@ davix-0.8.0/deps/curl/src/Makefile.inc0000644000000000000000000000465714121063461016241 0ustar rootroot# ./src/Makefile.inc # Using the backslash as line continuation character might be problematic # with some make flavours, as Watcom's wmake showed us already. If we # ever want to change this in a portable manner then we should consider # this idea (posted to the libcurl list by Adam Kellas): # CSRC1 = file1.c file2.c file3.c # CSRC2 = file4.c file5.c file6.c # CSOURCES = $(CSRC1) $(CSRC2) # libcurl has sources that provide functions named curlx_* that aren't part of # the official API, but we re-use the code here to avoid duplication. CURLX_CFILES = \ ../lib/strtoofft.c \ ../lib/nonblock.c \ ../lib/warnless.c \ ../lib/curl_ctype.c CURLX_HFILES = \ ../lib/curl_setup.h \ ../lib/strtoofft.h \ ../lib/nonblock.h \ ../lib/warnless.h \ ../lib/curl_ctype.h CURL_CFILES = \ slist_wc.c \ tool_binmode.c \ tool_bname.c \ tool_cb_dbg.c \ tool_cb_hdr.c \ tool_cb_prg.c \ tool_cb_rea.c \ tool_cb_see.c \ tool_cb_wrt.c \ tool_cfgable.c \ tool_convert.c \ tool_dirhie.c \ tool_doswin.c \ tool_easysrc.c \ tool_filetime.c \ tool_formparse.c \ tool_getparam.c \ tool_getpass.c \ tool_help.c \ tool_helpers.c \ tool_homedir.c \ tool_hugehelp.c \ tool_libinfo.c \ tool_main.c \ tool_metalink.c \ tool_msgs.c \ tool_operate.c \ tool_operhlp.c \ tool_panykey.c \ tool_paramhlp.c \ tool_parsecfg.c \ tool_progress.c \ tool_strdup.c \ tool_setopt.c \ tool_sleep.c \ tool_urlglob.c \ tool_util.c \ tool_vms.c \ tool_writeout.c \ tool_xattr.c CURL_HFILES = \ slist_wc.h \ tool_binmode.h \ tool_bname.h \ tool_cb_dbg.h \ tool_cb_hdr.h \ tool_cb_prg.h \ tool_cb_rea.h \ tool_cb_see.h \ tool_cb_wrt.h \ tool_cfgable.h \ tool_convert.h \ tool_dirhie.h \ tool_doswin.h \ tool_easysrc.h \ tool_filetime.h \ tool_formparse.h \ tool_getparam.h \ tool_getpass.h \ tool_help.h \ tool_helpers.h \ tool_homedir.h \ tool_hugehelp.h \ tool_libinfo.h \ tool_main.h \ tool_metalink.h \ tool_msgs.h \ tool_operate.h \ tool_operhlp.h \ tool_panykey.h \ tool_paramhlp.h \ tool_parsecfg.h \ tool_progress.h \ tool_sdecls.h \ tool_setopt.h \ tool_setup.h \ tool_sleep.h \ tool_strdup.h \ tool_urlglob.h \ tool_util.h \ tool_version.h \ tool_vms.h \ tool_writeout.h \ tool_xattr.h CURL_RCFILES = curl.rc # curl_SOURCES is special and gets assigned in src/Makefile.am CURL_FILES = $(CURL_CFILES) $(CURLX_CFILES) $(CURL_HFILES) davix-0.8.0/deps/curl/src/tool_easysrc.c0000644000000000000000000001441114121063461016670 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "slist_wc.h" #ifndef CURL_DISABLE_LIBCURL_OPTION #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_easysrc.h" #include "tool_msgs.h" #include "memdebug.h" /* keep this as LAST include */ /* global variable definitions, for easy-interface source code generation */ struct slist_wc *easysrc_decl = NULL; /* Variable declarations */ struct slist_wc *easysrc_data = NULL; /* Build slists, forms etc. */ struct slist_wc *easysrc_code = NULL; /* Setopt calls */ struct slist_wc *easysrc_toohard = NULL; /* Unconvertible setopt */ struct slist_wc *easysrc_clean = NULL; /* Clean up allocated data */ int easysrc_mime_count = 0; int easysrc_slist_count = 0; static const char *const srchead[]={ "/********* Sample code generated by the curl command line tool **********", " * All curl_easy_setopt() options are documented at:", " * https://curl.haxx.se/libcurl/c/curl_easy_setopt.html", " ************************************************************************/", "#include ", "", "int main(int argc, char *argv[])", "{", " CURLcode ret;", " CURL *hnd;", NULL }; /* easysrc_decl declarations come here */ /* easysrc_data initialisations come here */ /* easysrc_code statements come here */ static const char *const srchard[]={ "/* Here is a list of options the curl code used that cannot get generated", " as source easily. You may select to either not use them or implement", " them yourself.", "", NULL }; static const char *const srcend[]={ "", " return (int)ret;", "}", "/**** End of sample code ****/", NULL }; /* Clean up all source code if we run out of memory */ static void easysrc_free(void) { slist_wc_free_all(easysrc_decl); easysrc_decl = NULL; slist_wc_free_all(easysrc_data); easysrc_data = NULL; slist_wc_free_all(easysrc_code); easysrc_code = NULL; slist_wc_free_all(easysrc_toohard); easysrc_toohard = NULL; slist_wc_free_all(easysrc_clean); easysrc_clean = NULL; } /* Add a source line to the main code or remarks */ CURLcode easysrc_add(struct slist_wc **plist, const char *line) { CURLcode ret = CURLE_OK; struct slist_wc *list = slist_wc_append(*plist, line); if(!list) { easysrc_free(); ret = CURLE_OUT_OF_MEMORY; } else *plist = list; return ret; } CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...) { CURLcode ret; char *bufp; va_list ap; va_start(ap, fmt); bufp = curlx_mvaprintf(fmt, ap); va_end(ap); if(! bufp) { ret = CURLE_OUT_OF_MEMORY; } else { ret = easysrc_add(plist, bufp); curl_free(bufp); } return ret; } #define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} while(0) CURLcode easysrc_init(void) { CHKRET(easysrc_add(&easysrc_code, "hnd = curl_easy_init();")); return CURLE_OK; } CURLcode easysrc_perform(void) { /* Note any setopt calls which we could not convert */ if(easysrc_toohard) { int i; struct curl_slist *ptr; const char *c; CHKRET(easysrc_add(&easysrc_code, "")); /* Preamble comment */ for(i = 0; ((c = srchard[i]) != NULL); i++) CHKRET(easysrc_add(&easysrc_code, c)); /* Each unconverted option */ if(easysrc_toohard) { for(ptr = easysrc_toohard->first; ptr; ptr = ptr->next) CHKRET(easysrc_add(&easysrc_code, ptr->data)); } CHKRET(easysrc_add(&easysrc_code, "")); CHKRET(easysrc_add(&easysrc_code, "*/")); slist_wc_free_all(easysrc_toohard); easysrc_toohard = NULL; } CHKRET(easysrc_add(&easysrc_code, "")); CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);")); CHKRET(easysrc_add(&easysrc_code, "")); return CURLE_OK; } CURLcode easysrc_cleanup(void) { CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);")); CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;")); return CURLE_OK; } void dumpeasysrc(struct GlobalConfig *config) { struct curl_slist *ptr; char *o = config->libcurl; FILE *out; bool fopened = FALSE; if(strcmp(o, "-")) { out = fopen(o, FOPEN_WRITETEXT); fopened = TRUE; } else out = stdout; if(!out) warnf(config, "Failed to open %s to write libcurl code!\n", o); else { int i; const char *c; for(i = 0; ((c = srchead[i]) != NULL); i++) fprintf(out, "%s\n", c); /* Declare variables used for complex setopt values */ if(easysrc_decl) { for(ptr = easysrc_decl->first; ptr; ptr = ptr->next) fprintf(out, " %s\n", ptr->data); } /* Set up complex values for setopt calls */ if(easysrc_data) { fprintf(out, "\n"); for(ptr = easysrc_data->first; ptr; ptr = ptr->next) fprintf(out, " %s\n", ptr->data); } fprintf(out, "\n"); if(easysrc_code) { for(ptr = easysrc_code->first; ptr; ptr = ptr->next) { if(ptr->data[0]) { fprintf(out, " %s\n", ptr->data); } else { fprintf(out, "\n"); } } } if(easysrc_clean) { for(ptr = easysrc_clean->first; ptr; ptr = ptr->next) fprintf(out, " %s\n", ptr->data); } for(i = 0; ((c = srcend[i]) != NULL); i++) fprintf(out, "%s\n", c); if(fopened) fclose(out); } easysrc_free(); } #endif /* CURL_DISABLE_LIBCURL_OPTION */ davix-0.8.0/deps/curl/src/tool_homedir.h0000644000000000000000000000223714121063461016656 0ustar rootroot#ifndef HEADER_CURL_TOOL_HOMEDIR_H #define HEADER_CURL_TOOL_HOMEDIR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" char *homedir(void); #endif /* HEADER_CURL_TOOL_HOMEDIR_H */ davix-0.8.0/deps/curl/src/tool_msgs.c0000644000000000000000000000717414121063461016200 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_msgs.h" #include "memdebug.h" /* keep this as LAST include */ #define WARN_PREFIX "Warning: " #define NOTE_PREFIX "Note: " #define ERROR_PREFIX "curl: " static void voutf(struct GlobalConfig *config, const char *prefix, const char *fmt, va_list ap) { size_t width = (79 - strlen(prefix)); if(!config->mute) { size_t len; char *ptr; char *print_buffer; print_buffer = curlx_mvaprintf(fmt, ap); if(!print_buffer) return; len = strlen(print_buffer); ptr = print_buffer; while(len > 0) { fputs(prefix, config->errors); if(len > width) { size_t cut = width-1; while(!ISSPACE(ptr[cut]) && cut) { cut--; } if(0 == cut) /* not a single cutting position was found, just cut it at the max text width then! */ cut = width-1; (void)fwrite(ptr, cut + 1, 1, config->errors); fputs("\n", config->errors); ptr += cut + 1; /* skip the space too */ len -= cut + 1; } else { fputs(ptr, config->errors); len = 0; } } curl_free(print_buffer); } } /* * Emit 'note' formatted message on configured 'errors' stream, if verbose was * selected. */ void notef(struct GlobalConfig *config, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if(config->tracetype) voutf(config, NOTE_PREFIX, fmt, ap); va_end(ap); } /* * Emit warning formatted message on configured 'errors' stream unless * mute (--silent) was selected. */ void warnf(struct GlobalConfig *config, const char *fmt, ...) { va_list ap; va_start(ap, fmt); voutf(config, WARN_PREFIX, fmt, ap); va_end(ap); } /* * Emit help formatted message on given stream. This is for errors with or * related to command line arguments. */ void helpf(FILE *errors, const char *fmt, ...) { if(fmt) { va_list ap; va_start(ap, fmt); fputs("curl: ", errors); /* prefix it */ vfprintf(errors, fmt, ap); va_end(ap); } fprintf(errors, "curl: try 'curl --help' " #ifdef USE_MANUAL "or 'curl --manual' " #endif "for more information\n"); } /* * Emit error message on error stream if not muted. When errors are not tied * to command line arguments, use helpf() for such errors. */ void errorf(struct GlobalConfig *config, const char *fmt, ...) { if(!config->mute) { va_list ap; va_start(ap, fmt); voutf(config, ERROR_PREFIX, fmt, ap); va_end(ap); } } davix-0.8.0/deps/curl/src/tool_main.c0000644000000000000000000002267014121063461016151 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include #ifdef HAVE_SIGNAL_H #include #endif #ifdef USE_NSS #include #include #endif #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_convert.h" #include "tool_doswin.h" #include "tool_msgs.h" #include "tool_operate.h" #include "tool_panykey.h" #include "tool_vms.h" #include "tool_main.h" #include "tool_libinfo.h" /* * This is low-level hard-hacking memory leak tracking and similar. Using * the library level code from this client-side is ugly, but we do this * anyway for convenience. */ #include "memdebug.h" /* keep this as LAST include */ #ifdef __VMS /* * vms_show is a global variable, used in main() as parameter for * function vms_special_exit() to allow proper curl tool exiting. * Its value may be set in other tool_*.c source files thanks to * forward declaration present in tool_vms.h */ int vms_show = 0; #endif #ifdef __MINGW32__ /* * There seems to be no way to escape "*" in command-line arguments with MinGW * when command-line argument globbing is enabled under the MSYS shell, so turn * it off. */ int _CRT_glob = 0; #endif /* __MINGW32__ */ /* if we build a static library for unit tests, there is no main() function */ #ifndef UNITTESTS /* * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are * open before starting to run. Otherwise, the first three network * sockets opened by curl could be used for input sources, downloaded data * or error logs as they will effectively be stdin, stdout and/or stderr. */ static void main_checkfds(void) { #ifdef HAVE_PIPE int fd[2] = { STDIN_FILENO, STDIN_FILENO }; while(fd[0] == STDIN_FILENO || fd[0] == STDOUT_FILENO || fd[0] == STDERR_FILENO || fd[1] == STDIN_FILENO || fd[1] == STDOUT_FILENO || fd[1] == STDERR_FILENO) if(pipe(fd) < 0) return; /* Out of handles. This isn't really a big problem now, but will be when we try to create a socket later. */ close(fd[0]); close(fd[1]); #endif } #ifdef CURLDEBUG static void memory_tracking_init(void) { char *env; /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ env = curlx_getenv("CURL_MEMDEBUG"); if(env) { /* use the value as file name */ char fname[CURL_MT_LOGFNAME_BUFSIZE]; if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; strcpy(fname, env); curl_free(env); curl_dbg_memdebug(fname); /* this weird stuff here is to make curl_free() get called before curl_gdb_memdebug() as otherwise memory tracking will log a free() without an alloc! */ } /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ env = curlx_getenv("CURL_MEMLIMIT"); if(env) { char *endptr; long num = strtol(env, &endptr, 10); if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) curl_dbg_memlimit(num); curl_free(env); } } #else # define memory_tracking_init() Curl_nop_stmt #endif /* * This is the main global constructor for the app. Call this before * _any_ libcurl usage. If this fails, *NO* libcurl functions may be * used, or havoc may be the result. */ static CURLcode main_init(struct GlobalConfig *config) { CURLcode result = CURLE_OK; #if defined(__DJGPP__) || defined(__GO32__) /* stop stat() wasting time */ _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; #endif /* Initialise the global config */ config->showerror = -1; /* Will show errors */ config->errors = stderr; /* Default errors to stderr */ config->styled_output = TRUE; /* enable detection */ config->parallel_max = PARALLEL_DEFAULT; /* Allocate the initial operate config */ config->first = config->last = malloc(sizeof(struct OperationConfig)); if(config->first) { /* Perform the libcurl initialization */ result = curl_global_init(CURL_GLOBAL_DEFAULT); if(!result) { /* Get information about libcurl */ result = get_libcurl_info(); if(!result) { /* Initialise the config */ config_init(config->first); config->first->global = config; } else { errorf(config, "error retrieving curl library information\n"); free(config->first); } } else { errorf(config, "error initializing curl library\n"); free(config->first); } } else { errorf(config, "error initializing curl\n"); result = CURLE_FAILED_INIT; } return result; } static void free_globalconfig(struct GlobalConfig *config) { Curl_safefree(config->trace_dump); if(config->errors_fopened && config->errors) fclose(config->errors); config->errors = NULL; if(config->trace_fopened && config->trace_stream) fclose(config->trace_stream); config->trace_stream = NULL; Curl_safefree(config->libcurl); } /* * This is the main global destructor for the app. Call this after * _all_ libcurl usage is done. */ static void main_free(struct GlobalConfig *config) { /* Cleanup the easy handle */ /* Main cleanup */ curl_global_cleanup(); convert_cleanup(); metalink_cleanup(); #ifdef USE_NSS if(PR_Initialized()) { /* prevent valgrind from reporting still reachable mem from NSRP arenas */ PL_ArenaFinish(); /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */ PR_Cleanup(); } #endif free_globalconfig(config); /* Free the config structures */ config_free(config->last); config->first = NULL; config->last = NULL; } #ifdef WIN32 /* TerminalSettings for Windows */ static struct TerminalSettings { HANDLE hStdOut; DWORD dwOutputMode; } TerminalSettings; static void configure_terminal(void) { /* * If we're running Windows, enable VT output. * Note: VT mode flag can be set on any version of Windows, but VT * processing only performed on Win10 >= Creators Update) */ /* Define the VT flags in case we're building with an older SDK */ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif memset(&TerminalSettings, 0, sizeof(TerminalSettings)); /* Enable VT output */ TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if((TerminalSettings.hStdOut != INVALID_HANDLE_VALUE) && (GetConsoleMode(TerminalSettings.hStdOut, &TerminalSettings.dwOutputMode))) { SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } } #else #define configure_terminal() #endif static void restore_terminal(void) { #ifdef WIN32 /* Restore Console output mode and codepage to whatever they were * when Curl started */ SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode); #endif } /* ** curl tool main function. */ int main(int argc, char *argv[]) { CURLcode result = CURLE_OK; struct GlobalConfig global; memset(&global, 0, sizeof(global)); #ifdef WIN32 /* Undocumented diagnostic option to list the full paths of all loaded modules. This is purposely pre-init. */ if(argc == 2 && !strcmp(argv[1], "--dump-module-paths")) { struct curl_slist *item, *head = GetLoadedModulePaths(); for(item = head; item; item = item->next) printf("%s\n", item->data); curl_slist_free_all(head); return head ? 0 : 1; } /* win32_init must be called before other init routines. */ result = win32_init(); if(result) { fprintf(stderr, "curl: (%d) Windows-specific init failed.\n", result); return result; } #endif /* Perform any platform-specific terminal configuration */ configure_terminal(); main_checkfds(); #if defined(HAVE_SIGNAL) && defined(SIGPIPE) (void)signal(SIGPIPE, SIG_IGN); #endif /* Initialize memory tracking */ memory_tracking_init(); /* Initialize the curl library - do not call any libcurl functions before this point */ result = main_init(&global); if(!result) { /* Start our curl operation */ result = operate(&global, argc, argv); #ifdef __SYMBIAN32__ if(global.showerror) tool_pressanykey(); #endif /* Perform the main cleanup */ main_free(&global); } /* Return the terminal to its original state */ restore_terminal(); #ifdef __NOVELL_LIBC__ if(getenv("_IN_NETWARE_BASH_") == NULL) tool_pressanykey(); #endif #ifdef __VMS vms_special_exit(result, vms_show); #else return (int)result; #endif } #endif /* ndef UNITTESTS */ davix-0.8.0/deps/curl/src/tool_doswin.c0000644000000000000000000005131014121063461016521 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(MSDOS) || defined(WIN32) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) # include #endif #ifdef WIN32 # include # include "tool_cfgable.h" # include "tool_libinfo.h" #endif #include "tool_bname.h" #include "tool_doswin.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef WIN32 # undef PATH_MAX # define PATH_MAX MAX_PATH #endif #ifndef S_ISCHR # ifdef S_IFCHR # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) # else # define S_ISCHR(m) (0) /* cannot tell if file is a device */ # endif #endif #ifdef WIN32 # define _use_lfn(f) (1) /* long file names always available */ #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ # define _use_lfn(f) (0) /* long file names never available */ #elif defined(__DJGPP__) # include /* _use_lfn(f) prototype */ #endif #ifndef UNITTESTS static SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos); #ifdef MSDOS static SANITIZEcode msdosify(char **const sanitized, const char *file_name, int flags); #endif static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, const char *file_name, int flags); #endif /* !UNITTESTS (static declarations used if no unit tests) */ /* Sanitize a file or path name. All banned characters are replaced by underscores, for example: f?*foo => f__foo f:foo::$DATA => f_foo__$DATA f:\foo:bar => f__foo_bar f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) This function was implemented according to the guidelines in 'Naming Files, Paths, and Namespaces' section 'Naming Conventions'. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx Flags ----- SANITIZE_ALLOW_COLONS: Allow colons. Without this flag colons are sanitized. SANITIZE_ALLOW_PATH: Allow path separators and colons. Without this flag path separators and colons are sanitized. SANITIZE_ALLOW_RESERVED: Allow reserved device names. Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's in a UNC prefixed path. SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename. Without this flag if the sanitized filename or path will be too long an error occurs. With this flag the filename --and not any other parts of the path-- may be truncated to at least a single character. A filename followed by an alternate data stream (ADS) cannot be truncated in any case. Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. */ SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, int flags) { char *p, *target; size_t len; SANITIZEcode sc; size_t max_sanitized_len; if(!sanitized) return SANITIZE_ERR_BAD_ARGUMENT; *sanitized = NULL; if(!file_name) return SANITIZE_ERR_BAD_ARGUMENT; if((flags & SANITIZE_ALLOW_PATH)) { #ifndef MSDOS if(file_name[0] == '\\' && file_name[1] == '\\') /* UNC prefixed path \\ (eg \\?\C:\foo) */ max_sanitized_len = 32767-1; else #endif max_sanitized_len = PATH_MAX-1; } else /* The maximum length of a filename. FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and does not discount the path information therefore we shouldn't use it. */ max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1; len = strlen(file_name); if(len > max_sanitized_len) { if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(file_name, max_sanitized_len)) return SANITIZE_ERR_INVALID_PATH; len = max_sanitized_len; } target = malloc(len + 1); if(!target) return SANITIZE_ERR_OUT_OF_MEMORY; strncpy(target, file_name, len); target[len] = '\0'; #ifndef MSDOS if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4)) /* Skip the literal path prefix \\?\ */ p = target + 4; else #endif p = target; /* replace control characters and other banned characters */ for(; *p; ++p) { const char *banned; if((1 <= *p && *p <= 31) || (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') || (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) { *p = '_'; continue; } for(banned = "|<>\"?*"; *banned; ++banned) { if(*p == *banned) { *p = '_'; break; } } } /* remove trailing spaces and periods if not allowing paths */ if(!(flags & SANITIZE_ALLOW_PATH) && len) { char *clip = NULL; p = &target[len]; do { --p; if(*p != ' ' && *p != '.') break; clip = p; } while(p != target); if(clip) { *clip = '\0'; len = clip - target; } } #ifdef MSDOS sc = msdosify(&p, target, flags); free(target); if(sc) return sc; target = p; len = strlen(target); if(len > max_sanitized_len) { free(target); return SANITIZE_ERR_INVALID_PATH; } #endif if(!(flags & SANITIZE_ALLOW_RESERVED)) { sc = rename_if_reserved_dos_device_name(&p, target, flags); free(target); if(sc) return sc; target = p; len = strlen(target); if(len > max_sanitized_len) { free(target); return SANITIZE_ERR_INVALID_PATH; } } *sanitized = target; return SANITIZE_ERR_OK; } /* Test if truncating a path to a file will leave at least a single character in the filename. Filenames suffixed by an alternate data stream can't be truncated. This performs a dry run, nothing is modified. Good truncate_pos 9: C:\foo\bar => C:\foo\ba Good truncate_pos 6: C:\foo => C:\foo Good truncate_pos 5: C:\foo => C:\fo Bad* truncate_pos 5: C:foo => C:foo Bad truncate_pos 5: C:\foo:ads => C:\fo Bad truncate_pos 9: C:\foo:ads => C:\foo:ad Bad truncate_pos 5: C:\foo\bar => C:\fo Bad truncate_pos 5: C:\foo\ => C:\fo Bad truncate_pos 7: C:\foo\ => C:\foo\ Error truncate_pos 7: C:\foo => (pos out of range) Bad truncate_pos 1: C:\foo\ => C * C:foo is ambiguous, C could end up being a drive or file therefore something like C:superlongfilename can't be truncated. Returns SANITIZE_ERR_OK: Good -- 'path' can be truncated SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated != SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error */ SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos) { size_t len; if(!path) return SANITIZE_ERR_BAD_ARGUMENT; len = strlen(path); if(truncate_pos > len) return SANITIZE_ERR_BAD_ARGUMENT; if(!len || !truncate_pos) return SANITIZE_ERR_INVALID_PATH; if(strpbrk(&path[truncate_pos - 1], "\\/:")) return SANITIZE_ERR_INVALID_PATH; /* C:\foo can be truncated but C:\foo:ads can't */ if(truncate_pos > 1) { const char *p = &path[truncate_pos - 1]; do { --p; if(*p == ':') return SANITIZE_ERR_INVALID_PATH; } while(p != path && *p != '\\' && *p != '/'); } return SANITIZE_ERR_OK; } /* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function * were taken with modification from the DJGPP port of tar 1.12. They use * algorithms originally from DJTAR. */ /* Extra sanitization MSDOS for file_name. This is a supporting function for sanitize_file_name. Warning: This is an MSDOS legacy function and was purposely written in a way that some path information may pass through. For example drive letter names (C:, D:, etc) are allowed to pass through. For sanitizing a filename use sanitize_file_name. Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. */ #if defined(MSDOS) || defined(UNITTESTS) SANITIZEcode msdosify(char **const sanitized, const char *file_name, int flags) { char dos_name[PATH_MAX]; static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ "|<>/\\\":?*"; /* illegal in DOS & W95 */ static const char *illegal_chars_w95 = &illegal_chars_dos[8]; int idx, dot_idx; const char *s = file_name; char *d = dos_name; const char *const dlimit = dos_name + sizeof(dos_name) - 1; const char *illegal_aliens = illegal_chars_dos; size_t len = sizeof(illegal_chars_dos) - 1; if(!sanitized) return SANITIZE_ERR_BAD_ARGUMENT; *sanitized = NULL; if(!file_name) return SANITIZE_ERR_BAD_ARGUMENT; if(strlen(file_name) > PATH_MAX-1 && (!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(file_name, PATH_MAX-1))) return SANITIZE_ERR_INVALID_PATH; /* Support for Windows 9X VFAT systems, when available. */ if(_use_lfn(file_name)) { illegal_aliens = illegal_chars_w95; len -= (illegal_chars_w95 - illegal_chars_dos); } /* Get past the drive letter, if any. */ if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') { *d++ = *s++; *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_'; ++d, ++s; } for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { if(memchr(illegal_aliens, *s, len)) { if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':') *d = ':'; else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\')) *d = *s; /* Dots are special: DOS doesn't allow them as the leading character, and a file name cannot have more than a single dot. We leave the first non-leading dot alone, unless it comes too close to the beginning of the name: we want sh.lex.c to become sh_lex.c, not sh.lex-c. */ else if(*s == '.') { if((flags & SANITIZE_ALLOW_PATH) && idx == 0 && (s[1] == '/' || s[1] == '\\' || (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) { /* Copy "./" and "../" verbatim. */ *d++ = *s++; if(d == dlimit) break; if(*s == '.') { *d++ = *s++; if(d == dlimit) break; } *d = *s; } else if(idx == 0) *d = '_'; else if(dot_idx >= 0) { if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */ d[dot_idx - idx] = '_'; /* replace previous dot */ *d = '.'; } else *d = '-'; } else *d = '.'; if(*s == '.') dot_idx = idx; } else if(*s == '+' && s[1] == '+') { if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */ *d++ = 'x'; if(d == dlimit) break; *d = 'x'; } else { /* libg++ etc. */ if(dlimit - d < 4) { *d++ = 'x'; if(d == dlimit) break; *d = 'x'; } else { memcpy(d, "plus", 4); d += 3; } } s++; idx++; } else *d = '_'; } else *d = *s; if(*s == '/' || *s == '\\') { idx = 0; dot_idx = -1; } else idx++; } *d = '\0'; if(*s) { /* dos_name is truncated, check that truncation requirements are met, specifically truncating a filename suffixed by an alternate data stream or truncating the entire filename is not allowed. */ if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") || truncate_dryrun(dos_name, d - dos_name)) return SANITIZE_ERR_INVALID_PATH; } *sanitized = strdup(dos_name); return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); } #endif /* MSDOS || UNITTESTS */ /* Rename file_name if it's a reserved dos device name. This is a supporting function for sanitize_file_name. Warning: This is an MSDOS legacy function and was purposely written in a way that some path information may pass through. For example drive letter names (C:, D:, etc) are allowed to pass through. For sanitizing a filename use sanitize_file_name. Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. */ SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, const char *file_name, int flags) { /* We could have a file whose name is a device on MS-DOS. Trying to * retrieve such a file would fail at best and wedge us at worst. We need * to rename such files. */ char *p, *base; char fname[PATH_MAX]; #ifdef MSDOS struct_stat st_buf; #endif if(!sanitized) return SANITIZE_ERR_BAD_ARGUMENT; *sanitized = NULL; if(!file_name) return SANITIZE_ERR_BAD_ARGUMENT; /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */ #ifndef MSDOS if((flags & SANITIZE_ALLOW_PATH) && file_name[0] == '\\' && file_name[1] == '\\') { size_t len = strlen(file_name); *sanitized = malloc(len + 1); if(!*sanitized) return SANITIZE_ERR_OUT_OF_MEMORY; strncpy(*sanitized, file_name, len + 1); return SANITIZE_ERR_OK; } #endif if(strlen(file_name) > PATH_MAX-1 && (!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(file_name, PATH_MAX-1))) return SANITIZE_ERR_INVALID_PATH; strncpy(fname, file_name, PATH_MAX-1); fname[PATH_MAX-1] = '\0'; base = basename(fname); /* Rename reserved device names that are known to be accessible without \\.\ Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS https://support.microsoft.com/en-us/kb/74496 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx */ for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { size_t p_len; int x = (curl_strnequal(p, "CON", 3) || curl_strnequal(p, "PRN", 3) || curl_strnequal(p, "AUX", 3) || curl_strnequal(p, "NUL", 3)) ? 3 : (curl_strnequal(p, "CLOCK$", 6)) ? 6 : (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ? (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0; if(!x) continue; /* the devices may be accessible with an extension or ADS, for example CON.AIR and 'CON . AIR' and CON:AIR access console */ for(; p[x] == ' '; ++x) ; if(p[x] == '.') { p[x] = '_'; continue; } else if(p[x] == ':') { if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) { p[x] = '_'; continue; } ++x; } else if(p[x]) /* no match */ continue; /* p points to 'CON' or 'CON ' or 'CON:', etc */ p_len = strlen(p); /* Prepend a '_' */ if(strlen(fname) == PATH_MAX-1) { --p_len; if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len)) return SANITIZE_ERR_INVALID_PATH; p[p_len] = '\0'; } memmove(p + 1, p, p_len + 1); p[0] = '_'; ++p_len; /* if fname was just modified then the basename pointer must be updated */ if(p == fname) base = basename(fname); } /* This is the legacy portion from rename_if_dos_device_name that checks for reserved device names. It only works on MSDOS. On Windows XP the stat check errors with EINVAL if the device name is reserved. On Windows Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN stat doc the latter behavior is correct, but that doesn't help us identify whether it's a reserved device name and not a regular file name. */ #ifdef MSDOS if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { /* Prepend a '_' */ size_t blen = strlen(base); if(blen) { if(strlen(fname) == PATH_MAX-1) { --blen; if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen)) return SANITIZE_ERR_INVALID_PATH; base[blen] = '\0'; } memmove(base + 1, base, blen + 1); base[0] = '_'; } } #endif *sanitized = strdup(fname); return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); } #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) /* * Disable program default argument globbing. We do it on our own. */ char **__crt0_glob_function(char *arg) { (void)arg; return (char **)0; } #endif /* MSDOS && (__DJGPP__ || __GO32__) */ #ifdef WIN32 /* * Function to find CACert bundle on a Win32 platform using SearchPath. * (SearchPath is already declared via inclusions done in setup header file) * (Use the ASCII version instead of the unicode one!) * The order of the directories it searches is: * 1. application's directory * 2. current working directory * 3. Windows System directory (e.g. C:\windows\system32) * 4. Windows Directory (e.g. C:\windows) * 5. all directories along %PATH% * * For WinXP and later search order actually depends on registry value: * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode */ CURLcode FindWin32CACert(struct OperationConfig *config, curl_sslbackend backend, const char *bundle_file) { CURLcode result = CURLE_OK; /* Search and set cert file only if libcurl supports SSL. * * If Schannel is the selected SSL backend then these locations are * ignored. We allow setting CA location for schannel only when explicitly * specified by the user via CURLOPT_CAINFO / --cacert. */ if((curlinfo->features & CURL_VERSION_SSL) && backend != CURLSSLBACKEND_SCHANNEL) { DWORD res_len; char buf[PATH_MAX]; char *ptr = NULL; buf[0] = '\0'; res_len = SearchPathA(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr); if(res_len > 0) { Curl_safefree(config->cacert); config->cacert = strdup(buf); if(!config->cacert) result = CURLE_OUT_OF_MEMORY; } } return result; } /* Get a list of all loaded modules with full paths. * Returns slist on success or NULL on error. */ struct curl_slist *GetLoadedModulePaths(void) { HANDLE hnd = INVALID_HANDLE_VALUE; MODULEENTRY32 mod = {0}; struct curl_slist *slist = NULL; mod.dwSize = sizeof(MODULEENTRY32); do { hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH); if(hnd == INVALID_HANDLE_VALUE) goto error; if(!Module32First(hnd, &mod)) goto error; do { char *path; /* points to stack allocated buffer */ struct curl_slist *temp; #ifdef UNICODE /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total bytes of multibyte chars won't be more than twice that. */ char buffer[sizeof(mod.szExePath) * 2]; if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1, buffer, sizeof(buffer), NULL, NULL)) goto error; path = buffer; #else path = mod.szExePath; #endif temp = curl_slist_append(slist, path); if(!temp) goto error; slist = temp; } while(Module32Next(hnd, &mod)); goto cleanup; error: curl_slist_free_all(slist); slist = NULL; cleanup: if(hnd != INVALID_HANDLE_VALUE) CloseHandle(hnd); return slist; } LARGE_INTEGER Curl_freq; bool Curl_isVistaOrGreater; CURLcode win32_init(void) { OSVERSIONINFOEXA osvi; unsigned __int64 mask = 0; unsigned char op = VER_GREATER_EQUAL; memset(&osvi, 0, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); osvi.dwMajorVersion = 6; VER_SET_CONDITION(mask, VER_MAJORVERSION, op); VER_SET_CONDITION(mask, VER_MINORVERSION, op); if(VerifyVersionInfoA(&osvi, (VER_MAJORVERSION | VER_MINORVERSION), mask)) Curl_isVistaOrGreater = true; else if(GetLastError() == ERROR_OLD_WIN_VERSION) Curl_isVistaOrGreater = false; else return CURLE_FAILED_INIT; QueryPerformanceFrequency(&Curl_freq); return CURLE_OK; } #endif /* WIN32 */ #endif /* MSDOS || WIN32 */ davix-0.8.0/deps/curl/src/tool_parsecfg.h0000644000000000000000000000232114121063461017013 0ustar rootroot#ifndef HEADER_CURL_TOOL_PARSECFG_H #define HEADER_CURL_TOOL_PARSECFG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" int parseconfig(const char *filename, struct GlobalConfig *config); #endif /* HEADER_CURL_TOOL_PARSECFG_H */ davix-0.8.0/deps/curl/src/tool_libinfo.c0000644000000000000000000000640114121063461016641 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_libinfo.h" #include "memdebug.h" /* keep this as LAST include */ /* global variable definitions, for libcurl run-time info */ curl_version_info_data *curlinfo = NULL; long built_in_protos = 0; /* * libcurl_info_init: retrieves run-time information about libcurl, * setting a global pointer 'curlinfo' to libcurl's run-time info * struct, and a global bit pattern 'built_in_protos' composed of * CURLPROTO_* bits indicating which protocols are actually built * into library being used. */ CURLcode get_libcurl_info(void) { static struct proto_name_pattern { const char *proto_name; long proto_pattern; } const possibly_built_in[] = { { "dict", CURLPROTO_DICT }, { "file", CURLPROTO_FILE }, { "ftp", CURLPROTO_FTP }, { "ftps", CURLPROTO_FTPS }, { "gopher", CURLPROTO_GOPHER }, { "http", CURLPROTO_HTTP }, { "https", CURLPROTO_HTTPS }, { "imap", CURLPROTO_IMAP }, { "imaps", CURLPROTO_IMAPS }, { "ldap", CURLPROTO_LDAP }, { "ldaps", CURLPROTO_LDAPS }, { "pop3", CURLPROTO_POP3 }, { "pop3s", CURLPROTO_POP3S }, { "rtmp", CURLPROTO_RTMP }, { "rtsp", CURLPROTO_RTSP }, { "scp", CURLPROTO_SCP }, { "sftp", CURLPROTO_SFTP }, { "smb", CURLPROTO_SMB }, { "smbs", CURLPROTO_SMBS }, { "smtp", CURLPROTO_SMTP }, { "smtps", CURLPROTO_SMTPS }, { "telnet", CURLPROTO_TELNET }, { "tftp", CURLPROTO_TFTP }, { NULL, 0 } }; const char *const *proto; /* Pointer to libcurl's run-time version information */ curlinfo = curl_version_info(CURLVERSION_NOW); if(!curlinfo) return CURLE_FAILED_INIT; /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */ built_in_protos = 0; if(curlinfo->protocols) { for(proto = curlinfo->protocols; *proto; proto++) { struct proto_name_pattern const *p; for(p = possibly_built_in; p->proto_name; p++) { if(curl_strequal(*proto, p->proto_name)) { built_in_protos |= p->proto_pattern; break; } } } } return CURLE_OK; } davix-0.8.0/deps/curl/src/tool_urlglob.h0000644000000000000000000000433614121063461016677 0ustar rootroot#ifndef HEADER_CURL_TOOL_URLGLOB_H #define HEADER_CURL_TOOL_URLGLOB_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" typedef enum { UPTSet = 1, UPTCharRange, UPTNumRange } URLPatternType; typedef struct { URLPatternType type; int globindex; /* the number of this particular glob or -1 if not used within {} or [] */ union { struct { char **elements; int size; int ptr_s; } Set; struct { char min_c; char max_c; char ptr_c; int step; } CharRange; struct { unsigned long min_n; unsigned long max_n; int padlength; unsigned long ptr_n; unsigned long step; } NumRange; } content; } URLPattern; /* the total number of globs supported */ #define GLOB_PATTERN_NUM 100 typedef struct { URLPattern pattern[GLOB_PATTERN_NUM]; size_t size; size_t urllen; char *glob_buffer; char beenhere; const char *error; /* error message */ size_t pos; /* column position of error or 0 */ } URLGlob; CURLcode glob_url(URLGlob**, char *, unsigned long *, FILE *); CURLcode glob_next_url(char **, URLGlob *); CURLcode glob_match_url(char **, char *, URLGlob *); void glob_cleanup(URLGlob* glob); #endif /* HEADER_CURL_TOOL_URLGLOB_H */ davix-0.8.0/deps/curl/src/tool_getpass.h0000644000000000000000000000264214121063461016675 0ustar rootroot#ifndef HEADER_CURL_TOOL_GETPASS_H #define HEADER_CURL_TOOL_GETPASS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef HAVE_GETPASS_R /* If there's a system-provided function named like this, we trust it is also found in one of the standard headers. */ /* * Returning NULL will abort the continued operation! */ char *getpass_r(const char *prompt, char *buffer, size_t buflen); #endif #endif /* HEADER_CURL_TOOL_GETPASS_H */ davix-0.8.0/deps/curl/src/tool_operhlp.c0000644000000000000000000001226514121063461016675 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_convert.h" #include "tool_doswin.h" #include "tool_operhlp.h" #include "tool_metalink.h" #include "memdebug.h" /* keep this as LAST include */ void clean_getout(struct OperationConfig *config) { if(config) { struct getout *next; struct getout *node = config->url_list; while(node) { next = node->next; Curl_safefree(node->url); Curl_safefree(node->outfile); Curl_safefree(node->infile); Curl_safefree(node); node = next; } config->url_list = NULL; } } bool output_expected(const char *url, const char *uploadfile) { if(!uploadfile) return TRUE; /* download */ if(checkprefix("http://", url) || checkprefix("https://", url)) return TRUE; /* HTTP(S) upload */ return FALSE; /* non-HTTP upload, probably no output should be expected */ } bool stdin_upload(const char *uploadfile) { return (!strcmp(uploadfile, "-") || !strcmp(uploadfile, ".")) ? TRUE : FALSE; } /* * Adds the file name to the URL if it doesn't already have one. * url will be freed before return if the returned pointer is different */ char *add_file_name_to_url(char *url, const char *filename) { /* If no file name part is given in the URL, we add this file name */ char *ptr = strstr(url, "://"); CURL *curl = curl_easy_init(); /* for url escaping */ if(!curl) return NULL; /* error! */ if(ptr) ptr += 3; else ptr = url; ptr = strrchr(ptr, '/'); if(!ptr || !*++ptr) { /* The URL has no file name part, add the local file name. In order to be able to do so, we have to create a new URL in another buffer.*/ /* We only want the part of the local path that is on the right side of the rightmost slash and backslash. */ const char *filep = strrchr(filename, '/'); char *file2 = strrchr(filep?filep:filename, '\\'); char *encfile; if(file2) filep = file2 + 1; else if(filep) filep++; else filep = filename; /* URL encode the file name */ encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); if(encfile) { char *urlbuffer; if(ptr) /* there is a trailing slash on the URL */ urlbuffer = aprintf("%s%s", url, encfile); else /* there is no trailing slash on the URL */ urlbuffer = aprintf("%s/%s", url, encfile); curl_free(encfile); if(!urlbuffer) { url = NULL; goto end; } Curl_safefree(url); url = urlbuffer; /* use our new URL instead! */ } } end: curl_easy_cleanup(curl); return url; } /* Extracts the name portion of the URL. * Returns a pointer to a heap-allocated string or NULL if * no name part, at location indicated by first argument. */ CURLcode get_url_file_name(char **filename, const char *url) { const char *pc, *pc2; *filename = NULL; /* Find and get the remote file name */ pc = strstr(url, "://"); if(pc) pc += 3; else pc = url; pc2 = strrchr(pc, '\\'); pc = strrchr(pc, '/'); if(pc2 && (!pc || pc < pc2)) pc = pc2; if(pc) /* duplicate the string beyond the slash */ pc++; else /* no slash => empty string */ pc = ""; *filename = strdup(pc); if(!*filename) return CURLE_OUT_OF_MEMORY; #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0); Curl_safefree(*filename); if(sc) return CURLE_URL_MALFORMAT; *filename = sanitized; } #endif /* MSDOS || WIN32 */ /* in case we built debug enabled, we allow an environment variable * named CURL_TESTDIR to prefix the given file name to put it into a * specific directory */ #ifdef DEBUGBUILD { char *tdir = curlx_getenv("CURL_TESTDIR"); if(tdir) { char buffer[512]; /* suitably large */ msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename); Curl_safefree(*filename); *filename = strdup(buffer); /* clone the buffer */ curl_free(tdir); if(!*filename) return CURLE_OUT_OF_MEMORY; } } #endif return CURLE_OK; } davix-0.8.0/deps/curl/src/tool_cfgable.h0000644000000000000000000002643614121063461016621 0ustar rootroot#ifndef HEADER_CURL_TOOL_CFGABLE_H #define HEADER_CURL_TOOL_CFGABLE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_sdecls.h" #include "tool_metalink.h" #include "tool_urlglob.h" #include "tool_formparse.h" typedef enum { ERR_NONE, ERR_BINARY_TERMINAL = 1, /* binary to terminal detected */ ERR_LAST } curl_error; struct GlobalConfig; struct State { struct getout *urlnode; URLGlob *inglob; URLGlob *urls; char *outfiles; char *httpgetfields; char *uploadfile; unsigned long infilenum; /* number of files to upload */ unsigned long up; /* upload file counter within a single upload glob */ unsigned long urlnum; /* how many iterations this single URL has with ranges etc */ unsigned long li; }; struct OperationConfig { bool remote_time; char *random_file; char *egd_file; char *useragent; char *cookie; /* single line with specified cookies */ char *cookiejar; /* write to this file */ char *cookiefile; /* read from this file */ char *altsvc; /* alt-svc cache file name */ bool cookiesession; /* new session? */ bool encoding; /* Accept-Encoding please */ bool tr_encoding; /* Transfer-Encoding please */ unsigned long authtype; /* auth bitmask */ bool use_resume; bool resume_from_current; bool disable_epsv; bool disable_eprt; bool ftp_pret; long proto; bool proto_present; long proto_redir; bool proto_redir_present; char *proto_default; curl_off_t resume_from; char *postfields; curl_off_t postfieldsize; char *referer; double timeout; double connecttimeout; long maxredirs; curl_off_t max_filesize; char *headerfile; char *ftpport; char *iface; long localport; long localportrange; unsigned short porttouse; char *range; long low_speed_limit; long low_speed_time; char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */ char *dns_interface; /* interface name */ char *dns_ipv4_addr; /* dot notation */ char *dns_ipv6_addr; /* dot notation */ char *userpwd; char *login_options; char *tls_username; char *tls_password; char *tls_authtype; char *proxy_tls_username; char *proxy_tls_password; char *proxy_tls_authtype; char *proxyuserpwd; char *proxy; int proxyver; /* set to CURLPROXY_HTTP* define */ char *noproxy; char *mail_from; struct curl_slist *mail_rcpt; char *mail_auth; bool mail_rcpt_allowfails; /* --mail-rcpt-allowfails */ char *sasl_authzid; /* Authorisation identity (identity to use) */ bool sasl_ir; /* Enable/disable SASL initial response */ bool proxytunnel; bool ftp_append; /* APPE on ftp */ bool use_ascii; /* select ascii or text transfer */ bool autoreferer; /* automatically set referer */ bool failonerror; /* fail on (HTTP) errors */ bool show_headers; /* show headers to data output */ bool no_body; /* don't get the body */ bool dirlistonly; /* only get the FTP dir list */ bool followlocation; /* follow http redirects */ bool unrestricted_auth; /* Continue to send authentication (user+password) when following ocations, even when hostname changed */ bool netrc_opt; bool netrc; char *netrc_file; struct getout *url_list; /* point to the first node */ struct getout *url_last; /* point to the last/current node */ struct getout *url_get; /* point to the node to fill in URL */ struct getout *url_out; /* point to the node to fill in outfile */ struct getout *url_ul; /* point to the node to fill in upload */ char *doh_url; char *cipher_list; char *proxy_cipher_list; char *cipher13_list; char *proxy_cipher13_list; char *cert; char *proxy_cert; char *cert_type; char *proxy_cert_type; char *cacert; char *proxy_cacert; char *capath; char *proxy_capath; char *crlfile; char *proxy_crlfile; char *pinnedpubkey; char *proxy_pinnedpubkey; char *key; char *proxy_key; char *key_type; char *proxy_key_type; char *key_passwd; char *proxy_key_passwd; char *pubkey; char *hostpubmd5; char *engine; char *etag_save_file; char *etag_compare_file; bool crlf; char *customrequest; char *krblevel; char *request_target; long httpversion; bool http09_allowed; bool nobuffer; bool readbusy; /* set when reading input returns EAGAIN */ bool globoff; bool use_httpget; bool insecure_ok; /* set TRUE to allow insecure SSL connects */ bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects for proxy */ bool terminal_binary_ok; bool verifystatus; bool create_dirs; bool ftp_create_dirs; bool ftp_skip_ip; bool proxynegotiate; bool proxyntlm; bool proxydigest; bool proxybasic; bool proxyanyauth; char *writeout; /* %-styled format string to output */ struct curl_slist *quote; struct curl_slist *postquote; struct curl_slist *prequote; long ssl_version; long ssl_version_max; long proxy_ssl_version; long ip_version; curl_TimeCond timecond; curl_off_t condtime; struct curl_slist *headers; struct curl_slist *proxyheaders; tool_mime *mimeroot; tool_mime *mimecurrent; curl_mime *mimepost; struct curl_slist *telnet_options; struct curl_slist *resolve; struct curl_slist *connect_to; HttpReq httpreq; /* for bandwidth limiting features: */ curl_off_t sendpersecond; /* send to peer */ curl_off_t recvpersecond; /* receive from peer */ bool ftp_ssl; bool ftp_ssl_reqd; bool ftp_ssl_control; bool ftp_ssl_ccc; int ftp_ssl_ccc_mode; char *preproxy; int socks5_gssapi_nec; /* The NEC reference server does not protect the encryption type exchange */ unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ char *proxy_service_name; /* set authentication service name for HTTP and SOCKS5 proxies */ char *service_name; /* set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ bool tcp_nodelay; bool tcp_fastopen; long req_retry; /* number of retries */ bool retry_connrefused; /* set connection refused as a transient error */ long retry_delay; /* delay between retries (in seconds) */ long retry_maxtime; /* maximum time to keep retrying */ char *ftp_account; /* for ACCT */ char *ftp_alternative_to_user; /* send command if USER/PASS fails */ int ftp_filemethod; long tftp_blksize; /* TFTP BLKSIZE option */ bool tftp_no_options; /* do not send TFTP options requests */ bool ignorecl; /* --ignore-content-length */ bool disable_sessionid; bool raw; bool post301; bool post302; bool post303; bool nokeepalive; /* for keepalive needs */ long alivetime; bool content_disposition; /* use Content-disposition filename */ int default_node_flags; /* default flags to search for each 'node', which is basically each given URL to transfer */ bool xattr; /* store metadata in extended attributes */ long gssapi_delegation; bool ssl_allow_beast; /* allow this SSL vulnerability */ bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy*/ bool ssl_no_revoke; /* disable SSL certificate revocation checks */ /*bool proxy_ssl_no_revoke; */ bool use_metalink; /* process given URLs as metalink XML file */ metalinkfile *metalinkfile_list; /* point to the first node */ metalinkfile *metalinkfile_last; /* point to the last/current node */ char *oauth_bearer; /* OAuth 2.0 bearer token */ bool nonpn; /* enable/disable TLS NPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */ char *unix_socket_path; /* path to Unix domain socket */ bool abstract_unix_socket; /* path to an abstract Unix domain socket */ bool falsestart; bool path_as_is; double expect100timeout; bool suppress_connect_headers; /* suppress proxy CONNECT response headers from user callbacks */ curl_error synthetic_error; /* if non-zero, it overrides any libcurl error */ bool ssh_compression; /* enable/disable SSH compression */ long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds. 0 is valid. default: CURL_HET_DEFAULT. */ bool haproxy_protocol; /* whether to send HAProxy protocol v1 */ bool disallow_username_in_url; /* disallow usernames in URLs */ struct GlobalConfig *global; struct OperationConfig *prev; struct OperationConfig *next; /* Always last in the struct */ struct State state; /* for create_transfer() */ }; struct GlobalConfig { int showerror; /* -1 == unset, default => show errors 0 => -s is used to NOT show errors 1 => -S has been used to show errors */ bool mute; /* don't show messages, --silent given */ bool noprogress; /* don't show progress bar --silent given */ bool isatty; /* Updated internally if output is a tty */ FILE *errors; /* Error stream, defaults to stderr */ bool errors_fopened; /* Whether error stream isn't stderr */ char *trace_dump; /* file to dump the network trace to */ FILE *trace_stream; bool trace_fopened; trace tracetype; bool tracetime; /* include timestamp? */ int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */ char *libcurl; /* Output libcurl code to this file name */ bool fail_early; /* exit on first transfer error */ bool styled_output; /* enable fancy output style detection */ #ifdef CURLDEBUG bool test_event_based; #endif bool parallel; long parallel_max; bool parallel_connect; struct OperationConfig *first; struct OperationConfig *current; struct OperationConfig *last; /* Always last in the struct */ }; void config_init(struct OperationConfig *config); void config_free(struct OperationConfig *config); #endif /* HEADER_CURL_TOOL_CFGABLE_H */ davix-0.8.0/deps/curl/src/tool_panykey.h0000644000000000000000000000242014121063461016701 0ustar rootroot#ifndef HEADER_CURL_TOOL_PANYKEY_H #define HEADER_CURL_TOOL_PANYKEY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(__SYMBIAN32__) || defined(NETWARE) void tool_pressanykey(void); #else #define tool_pressanykey() Curl_nop_stmt #endif #endif /* HEADER_CURL_TOOL_PANYKEY_H */ davix-0.8.0/deps/curl/src/tool_cb_dbg.h0000644000000000000000000000246614121063461016433 0ustar rootroot#ifndef HEADER_CURL_TOOL_CB_DBG_H #define HEADER_CURL_TOOL_CB_DBG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" /* ** callback for CURLOPT_DEBUGFUNCTION */ int tool_debug_cb(CURL *handle, curl_infotype type, char *data, size_t size, void *userdata); #endif /* HEADER_CURL_TOOL_CB_DBG_H */ davix-0.8.0/deps/curl/src/tool_sdecls.h0000644000000000000000000001163214121063461016503 0ustar rootroot#ifndef HEADER_CURL_TOOL_SDECLS_H #define HEADER_CURL_TOOL_SDECLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef USE_METALINK # include #endif /* USE_METALINK */ /* * OutStruct variables keep track of information relative to curl's * output writing, which may take place to a standard stream or a file. * * 'filename' member is either a pointer to a file name string or NULL * when dealing with a standard stream. * * 'alloc_filename' member is TRUE when string pointed by 'filename' has been * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE. * * 'is_cd_filename' member is TRUE when string pointed by 'filename' has been * set using a server-specified Content-Disposition filename, otherwise FALSE. * * 's_isreg' member is TRUE when output goes to a regular file, this also * implies that output is 'seekable' and 'appendable' and also that member * 'filename' points to file name's string. For any standard stream member * 's_isreg' will be FALSE. * * 'fopened' member is TRUE when output goes to a regular file and it * has been fopen'ed, requiring it to be closed later on. In any other * case this is FALSE. * * 'stream' member is a pointer to a stream controlling object as returned * from a 'fopen' call or a standard stream. * * 'config' member is a pointer to associated 'OperationConfig' struct. * * 'bytes' member represents amount written so far. * * 'init' member holds original file size or offset at which truncation is * taking place. Always zero unless appending to a non-empty regular file. * * 'metalink_parser' member is a pointer to Metalink XML parser * context. */ struct OutStruct { char *filename; bool alloc_filename; bool is_cd_filename; bool s_isreg; bool fopened; FILE *stream; curl_off_t bytes; curl_off_t init; #ifdef USE_METALINK metalink_parser_context_t *metalink_parser; #endif /* USE_METALINK */ }; /* * InStruct variables keep track of information relative to curl's * input reading, which may take place from stdin or from some file. * * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO * or a file descriptor as returned from an 'open' call for some file. * * 'config' member is a pointer to associated 'OperationConfig' struct. */ struct InStruct { int fd; struct OperationConfig *config; }; /* * A linked list of these 'getout' nodes contain URL's to fetch, * as well as information relative to where URL contents should * be stored or which file should be uploaded. */ struct getout { struct getout *next; /* next one */ char *url; /* the URL we deal with */ char *outfile; /* where to store the output */ char *infile; /* file to upload, if GETOUT_UPLOAD is set */ int flags; /* options - composed of GETOUT_* bits */ }; #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */ #define GETOUT_URL (1<<1) /* set when URL is deemed done */ #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */ #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */ #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */ #define GETOUT_METALINK (1<<5) /* set when Metalink download */ /* * 'trace' enumeration represents curl's output look'n feel possibilities. */ typedef enum { TRACE_NONE, /* no trace/verbose output at all */ TRACE_BIN, /* tcpdump inspired look */ TRACE_ASCII, /* like *BIN but without the hex output */ TRACE_PLAIN /* -v/--verbose type */ } trace; /* * 'HttpReq' enumeration represents HTTP request types. */ typedef enum { HTTPREQ_UNSPEC, /* first in list */ HTTPREQ_GET, HTTPREQ_HEAD, HTTPREQ_MIMEPOST, HTTPREQ_SIMPLEPOST } HttpReq; /* * Complete struct declarations which have OperationConfig struct members, * just in case this header is directly included in some source file. */ #include "tool_cfgable.h" #endif /* HEADER_CURL_TOOL_SDECLS_H */ davix-0.8.0/deps/curl/src/tool_cb_hdr.c0000644000000000000000000002273414121063461016447 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_doswin.h" #include "tool_msgs.h" #include "tool_cb_hdr.h" #include "tool_cb_wrt.h" #include "tool_operate.h" #include "memdebug.h" /* keep this as LAST include */ static char *parse_filename(const char *ptr, size_t len); #ifdef WIN32 #define BOLD #define BOLDOFF #else #define BOLD "\x1b[1m" /* Switch off bold by setting "all attributes off" since the explicit bold-off code (21) isn't supported everywhere - like in the mac Terminal. */ #define BOLDOFF "\x1b[0m" #endif /* ** callback for CURLOPT_HEADERFUNCTION */ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) { struct per_transfer *per = userdata; struct HdrCbData *hdrcbdata = &per->hdrcbdata; struct OutStruct *outs = &per->outs; struct OutStruct *heads = &per->heads; struct OutStruct *etag_save = &per->etag_save; const char *str = ptr; const size_t cb = size * nmemb; const char *end = (char *)ptr + cb; long protocol = 0; /* * Once that libcurl has called back tool_header_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ size_t failure = (size && nmemb) ? 0 : 1; if(!per->config) return failure; #ifdef DEBUGBUILD if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { warnf(per->config->global, "Header data exceeds single call write " "limit!\n"); return failure; } #endif /* * Write header data when curl option --dump-header (-D) is given. */ if(per->config->headerfile && heads->stream) { size_t rc = fwrite(ptr, size, nmemb, heads->stream); if(rc != cb) return rc; /* flush the stream to send off what we got earlier */ (void)fflush(heads->stream); } /* * Write etag to file when --etag-save option is given. * etag string that we want is enveloped in double quotes */ if(per->config->etag_save_file && etag_save->stream) { /* match only header that start with etag (case insensitive) */ if(curl_strnequal(str, "etag:", 5)) { char *etag_h = NULL; char *first = NULL; char *last = NULL; size_t etag_length = 0; etag_h = ptr; /* point to first occurrence of double quote */ first = memchr(etag_h, '\"', cb); /* * if server side messed with the etag header and doesn't include * double quotes around the etag, kindly exit with a warning */ if(!first) { warnf(per->config->global, "\nReceived header etag is missing double quote/s\n"); return 1; } else { /* discard first double quote */ first++; } /* point to last occurrence of double quote */ last = memchr(first, '\"', cb); if(!last) { warnf(per->config->global, "\nReceived header etag is missing double quote/s\n"); return 1; } /* get length of desired etag */ etag_length = (size_t)last - (size_t)first; fwrite(first, size, etag_length, etag_save->stream); /* terminate with new line */ fputc('\n', etag_save->stream); } (void)fflush(etag_save->stream); } /* * This callback sets the filename where output shall be written when * curl options --remote-name (-O) and --remote-header-name (-J) have * been simultaneously given and additionally server returns an HTTP * Content-Disposition header specifying a filename property. */ curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol); if(hdrcbdata->honor_cd_filename && (cb > 20) && checkprefix("Content-disposition:", str) && (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { const char *p = str + 20; /* look for the 'filename=' parameter (encoded filenames (*=) are not supported) */ for(;;) { char *filename; size_t len; while(*p && (p < end) && !ISALPHA(*p)) p++; if(p > end - 9) break; if(memcmp(p, "filename=", 9)) { /* no match, find next parameter */ while((p < end) && (*p != ';')) p++; continue; } p += 9; /* this expression below typecasts 'cb' only to avoid warning: signed and unsigned type in conditional expression */ len = (ssize_t)cb - (p - str); filename = parse_filename(p, len); if(filename) { if(outs->stream) { int rc; /* already opened and possibly written to */ if(outs->fopened) fclose(outs->stream); outs->stream = NULL; /* rename the initial file name to the new file name */ rc = rename(outs->filename, filename); if(rc != 0) { warnf(per->config->global, "Failed to rename %s -> %s: %s\n", outs->filename, filename, strerror(errno)); } if(outs->alloc_filename) Curl_safefree(outs->filename); if(rc != 0) { free(filename); return failure; } } outs->is_cd_filename = TRUE; outs->s_isreg = TRUE; outs->fopened = FALSE; outs->filename = filename; outs->alloc_filename = TRUE; hdrcbdata->honor_cd_filename = FALSE; /* done now! */ if(!tool_create_output_file(outs, per->config)) return failure; } break; } if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; } if(hdrcbdata->config->show_headers && (protocol & (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { /* bold headers only for selected protocols */ char *value = NULL; if(!outs->stream && !tool_create_output_file(outs, per->config)) return failure; if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) value = memchr(ptr, ':', cb); if(value) { size_t namelen = value - ptr; fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr); fwrite(&value[1], cb - namelen - 1, 1, outs->stream); } else /* not "handled", just show it */ fwrite(ptr, cb, 1, outs->stream); } return cb; } /* * Copies a file name part and returns an ALLOCATED data buffer. */ static char *parse_filename(const char *ptr, size_t len) { char *copy; char *p; char *q; char stop = '\0'; /* simple implementation of strndup() */ copy = malloc(len + 1); if(!copy) return NULL; memcpy(copy, ptr, len); copy[len] = '\0'; p = copy; if(*p == '\'' || *p == '"') { /* store the starting quote */ stop = *p; p++; } else stop = ';'; /* scan for the end letter and stop there */ q = strchr(p, stop); if(q) *q = '\0'; /* if the filename contains a path, only use filename portion */ q = strrchr(p, '/'); if(q) { p = q + 1; if(!*p) { Curl_safefree(copy); return NULL; } } /* If the filename contains a backslash, only use filename portion. The idea is that even systems that don't handle backslashes as path separators probably want the path removed for convenience. */ q = strrchr(p, '\\'); if(q) { p = q + 1; if(!*p) { Curl_safefree(copy); return NULL; } } /* make sure the file name doesn't end in \r or \n */ q = strchr(p, '\r'); if(q) *q = '\0'; q = strchr(p, '\n'); if(q) *q = '\0'; if(copy != p) memmove(copy, p, strlen(p) + 1); #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0); Curl_safefree(copy); if(sc) return NULL; copy = sanitized; } #endif /* MSDOS || WIN32 */ /* in case we built debug enabled, we allow an environment variable * named CURL_TESTDIR to prefix the given file name to put it into a * specific directory */ #ifdef DEBUGBUILD { char *tdir = curlx_getenv("CURL_TESTDIR"); if(tdir) { char buffer[512]; /* suitably large */ msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy); Curl_safefree(copy); copy = strdup(buffer); /* clone the buffer, we don't use the libcurl aprintf() or similar since we want to use the same memory code as the "real" parse_filename function */ curl_free(tdir); } } #endif return copy; } davix-0.8.0/deps/curl/src/tool_setopt.c0000644000000000000000000005377314121063461016553 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef CURL_DISABLE_LIBCURL_OPTION #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_easysrc.h" #include "tool_setopt.h" #include "tool_convert.h" #include "memdebug.h" /* keep this as LAST include */ /* Lookup tables for converting setopt values back to symbols */ /* For enums, values may be in any order. */ /* For bit masks, put combinations first, then single bits, */ /* and finally any "NONE" value. */ #define NV(e) {#e, e} #define NV1(e, v) {#e, (v)} #define NVEND {NULL, 0} /* sentinel to mark end of list */ const NameValue setopt_nv_CURLPROXY[] = { NV(CURLPROXY_HTTP), NV(CURLPROXY_HTTP_1_0), NV(CURLPROXY_HTTPS), NV(CURLPROXY_SOCKS4), NV(CURLPROXY_SOCKS5), NV(CURLPROXY_SOCKS4A), NV(CURLPROXY_SOCKS5_HOSTNAME), NVEND, }; const NameValue setopt_nv_CURL_SOCKS_PROXY[] = { NV(CURLPROXY_SOCKS4), NV(CURLPROXY_SOCKS5), NV(CURLPROXY_SOCKS4A), NV(CURLPROXY_SOCKS5_HOSTNAME), NVEND, }; const NameValueUnsigned setopt_nv_CURLAUTH[] = { NV(CURLAUTH_ANY), /* combination */ NV(CURLAUTH_ANYSAFE), /* combination */ NV(CURLAUTH_BASIC), NV(CURLAUTH_DIGEST), NV(CURLAUTH_GSSNEGOTIATE), NV(CURLAUTH_NTLM), NV(CURLAUTH_DIGEST_IE), NV(CURLAUTH_NTLM_WB), NV(CURLAUTH_ONLY), NV(CURLAUTH_NONE), NVEND, }; const NameValue setopt_nv_CURL_HTTP_VERSION[] = { NV(CURL_HTTP_VERSION_NONE), NV(CURL_HTTP_VERSION_1_0), NV(CURL_HTTP_VERSION_1_1), NV(CURL_HTTP_VERSION_2_0), NV(CURL_HTTP_VERSION_2TLS), NV(CURL_HTTP_VERSION_3), NVEND, }; const NameValue setopt_nv_CURL_SSLVERSION[] = { NV(CURL_SSLVERSION_DEFAULT), NV(CURL_SSLVERSION_TLSv1), NV(CURL_SSLVERSION_SSLv2), NV(CURL_SSLVERSION_SSLv3), NV(CURL_SSLVERSION_TLSv1_0), NV(CURL_SSLVERSION_TLSv1_1), NV(CURL_SSLVERSION_TLSv1_2), NV(CURL_SSLVERSION_TLSv1_3), NVEND, }; const NameValue setopt_nv_CURL_TIMECOND[] = { NV(CURL_TIMECOND_IFMODSINCE), NV(CURL_TIMECOND_IFUNMODSINCE), NV(CURL_TIMECOND_LASTMOD), NV(CURL_TIMECOND_NONE), NVEND, }; const NameValue setopt_nv_CURLFTPSSL_CCC[] = { NV(CURLFTPSSL_CCC_NONE), NV(CURLFTPSSL_CCC_PASSIVE), NV(CURLFTPSSL_CCC_ACTIVE), NVEND, }; const NameValue setopt_nv_CURLUSESSL[] = { NV(CURLUSESSL_NONE), NV(CURLUSESSL_TRY), NV(CURLUSESSL_CONTROL), NV(CURLUSESSL_ALL), NVEND, }; const NameValueUnsigned setopt_nv_CURLSSLOPT[] = { NV(CURLSSLOPT_ALLOW_BEAST), NV(CURLSSLOPT_NO_REVOKE), NV(CURLSSLOPT_NO_PARTIALCHAIN), NVEND, }; const NameValue setopt_nv_CURL_NETRC[] = { NV(CURL_NETRC_IGNORED), NV(CURL_NETRC_OPTIONAL), NV(CURL_NETRC_REQUIRED), NVEND, }; /* These mappings essentially triplicated - see * tool_libinfo.c and tool_paramhlp.c */ const NameValue setopt_nv_CURLPROTO[] = { NV(CURLPROTO_ALL), /* combination */ NV(CURLPROTO_DICT), NV(CURLPROTO_FILE), NV(CURLPROTO_FTP), NV(CURLPROTO_FTPS), NV(CURLPROTO_GOPHER), NV(CURLPROTO_HTTP), NV(CURLPROTO_HTTPS), NV(CURLPROTO_IMAP), NV(CURLPROTO_IMAPS), NV(CURLPROTO_LDAP), NV(CURLPROTO_LDAPS), NV(CURLPROTO_POP3), NV(CURLPROTO_POP3S), NV(CURLPROTO_RTSP), NV(CURLPROTO_SCP), NV(CURLPROTO_SFTP), NV(CURLPROTO_SMB), NV(CURLPROTO_SMBS), NV(CURLPROTO_SMTP), NV(CURLPROTO_SMTPS), NV(CURLPROTO_TELNET), NV(CURLPROTO_TFTP), NVEND, }; /* These options have non-zero default values. */ static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = { NV1(CURLOPT_SSL_VERIFYPEER, 1), NV1(CURLOPT_SSL_VERIFYHOST, 1), NV1(CURLOPT_SSL_ENABLE_NPN, 1), NV1(CURLOPT_SSL_ENABLE_ALPN, 1), NV1(CURLOPT_TCP_NODELAY, 1), NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), NV1(CURLOPT_SOCKS5_AUTH, 1), NVEND }; /* Format and add code; jump to nomem on malloc error */ #define ADD(args) do { \ ret = easysrc_add args; \ if(ret) \ goto nomem; \ } while(0) #define ADDF(args) do { \ ret = easysrc_addf args; \ if(ret) \ goto nomem; \ } while(0) #define NULL_CHECK(p) do { \ if(!p) { \ ret = CURLE_OUT_OF_MEMORY; \ goto nomem; \ } \ } while(0) #define DECL0(s) ADD((&easysrc_decl, s)) #define DECL1(f,a) ADDF((&easysrc_decl, f,a)) #define DATA0(s) ADD((&easysrc_data, s)) #define DATA1(f,a) ADDF((&easysrc_data, f,a)) #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) #define CODE0(s) ADD((&easysrc_code, s)) #define CODE1(f,a) ADDF((&easysrc_code, f,a)) #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) #define CLEAN0(s) ADD((&easysrc_clean, s)) #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) #define REM0(s) ADD((&easysrc_toohard, s)) #define REM1(f,a) ADDF((&easysrc_toohard, f,a)) #define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) /* Escape string to C string syntax. Return NULL if out of memory. * Is this correct for those wacky EBCDIC guys? */ static char *c_escape(const char *str, size_t len) { const char *s; unsigned char c; char *escaped, *e; if(len == CURL_ZERO_TERMINATED) len = strlen(str); /* Check for possible overflow. */ if(len > (~(size_t) 0) / 4) return NULL; /* Allocate space based on worst-case */ escaped = malloc(4 * len + 1); if(!escaped) return NULL; e = escaped; for(s = str; (c = *s) != '\0'; s++) { if(c == '\n') { strcpy(e, "\\n"); e += 2; } else if(c == '\r') { strcpy(e, "\\r"); e += 2; } else if(c == '\t') { strcpy(e, "\\t"); e += 2; } else if(c == '\\') { strcpy(e, "\\\\"); e += 2; } else if(c == '"') { strcpy(e, "\\\""); e += 2; } else if(! isprint(c)) { msnprintf(e, 5, "\\%03o", (unsigned)c); e += 4; } else *e++ = c; } *e = '\0'; return escaped; } /* setopt wrapper for enum types */ CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValue *nvlist, long lval) { CURLcode ret = CURLE_OK; bool skip = FALSE; ret = curl_easy_setopt(curl, tag, lval); if(!lval) skip = TRUE; if(config->libcurl && !skip && !ret) { /* we only use this for real if --libcurl was used */ const NameValue *nv = NULL; for(nv = nvlist; nv->name; nv++) { if(nv->value == lval) break; /* found it */ } if(! nv->name) { /* If no definition was found, output an explicit value. * This could happen if new values are defined and used * but the NameValue list is not updated. */ CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); } else { CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); } } nomem: return ret; } /* setopt wrapper for flags */ CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValue *nvlist, long lval) { CURLcode ret = CURLE_OK; bool skip = FALSE; ret = curl_easy_setopt(curl, tag, lval); if(!lval) skip = TRUE; if(config->libcurl && !skip && !ret) { /* we only use this for real if --libcurl was used */ char preamble[80]; /* should accommodate any symbol name */ long rest = lval; /* bits not handled yet */ const NameValue *nv = NULL; msnprintf(preamble, sizeof(preamble), "curl_easy_setopt(hnd, %s, ", name); for(nv = nvlist; nv->name; nv++) { if((nv->value & ~ rest) == 0) { /* all value flags contained in rest */ rest &= ~ nv->value; /* remove bits handled here */ CODE3("%s(long)%s%s", preamble, nv->name, rest ? " |" : ");"); if(!rest) break; /* handled them all */ /* replace with all spaces for continuation line */ msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); } } /* If any bits have no definition, output an explicit value. * This could happen if new bits are defined and used * but the NameValue list is not updated. */ if(rest) CODE2("%s%ldL);", preamble, rest); } nomem: return ret; } /* setopt wrapper for bitmasks */ CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, const NameValueUnsigned *nvlist, long lval) { CURLcode ret = CURLE_OK; bool skip = FALSE; ret = curl_easy_setopt(curl, tag, lval); if(!lval) skip = TRUE; if(config->libcurl && !skip && !ret) { /* we only use this for real if --libcurl was used */ char preamble[80]; unsigned long rest = (unsigned long)lval; const NameValueUnsigned *nv = NULL; msnprintf(preamble, sizeof(preamble), "curl_easy_setopt(hnd, %s, ", name); for(nv = nvlist; nv->name; nv++) { if((nv->value & ~ rest) == 0) { /* all value flags contained in rest */ rest &= ~ nv->value; /* remove bits handled here */ CODE3("%s(long)%s%s", preamble, nv->name, rest ? " |" : ");"); if(!rest) break; /* handled them all */ /* replace with all spaces for continuation line */ msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); } } /* If any bits have no definition, output an explicit value. * This could happen if new bits are defined and used * but the NameValue list is not updated. */ if(rest) CODE2("%s%luUL);", preamble, rest); } nomem: return ret; } /* Generate code for a struct curl_slist. */ static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno) { CURLcode ret = CURLE_OK; char *escaped = NULL; /* May need several slist variables, so invent name */ *slistno = ++easysrc_slist_count; DECL1("struct curl_slist *slist%d;", *slistno); DATA1("slist%d = NULL;", *slistno); CLEAN1("curl_slist_free_all(slist%d);", *slistno); CLEAN1("slist%d = NULL;", *slistno); for(; slist; slist = slist->next) { Curl_safefree(escaped); escaped = c_escape(slist->data, CURL_ZERO_TERMINATED); if(!escaped) return CURLE_OUT_OF_MEMORY; DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", *slistno, *slistno, escaped); } nomem: Curl_safefree(escaped); return ret; } static CURLcode libcurl_generate_mime(CURL *curl, struct GlobalConfig *config, tool_mime *toolmime, int *mimeno); /* Forward. */ /* Wrapper to generate source code for a mime part. */ static CURLcode libcurl_generate_mime_part(CURL *curl, struct GlobalConfig *config, tool_mime *part, int mimeno) { CURLcode ret = CURLE_OK; int submimeno = 0; char *escaped = NULL; const char *data = NULL; const char *filename = part->filename; /* Parts are linked in reverse order. */ if(part->prev) { ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno); if(ret) return ret; } /* Create the part. */ CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno); switch(part->kind) { case TOOLMIME_PARTS: ret = libcurl_generate_mime(curl, config, part, &submimeno); if(!ret) { CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno); CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */ } break; case TOOLMIME_DATA: #ifdef CURL_DOES_CONVERSIONS /* Data will be set in ASCII, thus issue a comment with clear text. */ escaped = c_escape(part->data, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE1("/* \"%s\" */", escaped); /* Our data is always textual: convert it to ASCII. */ { size_t size = strlen(part->data); char *cp = malloc(size + 1); NULL_CHECK(cp); memcpy(cp, part->data, size + 1); ret = convert_to_network(cp, size); data = cp; } #else data = part->data; #endif if(!ret) { Curl_safefree(escaped); escaped = c_escape(data, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);", mimeno, escaped); } break; case TOOLMIME_FILE: case TOOLMIME_FILEDATA: escaped = c_escape(part->data, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped); if(part->kind == TOOLMIME_FILEDATA && !filename) { CODE1("curl_mime_filename(part%d, NULL);", mimeno); } break; case TOOLMIME_STDIN: if(!filename) filename = "-"; /* FALLTHROUGH */ case TOOLMIME_STDINDATA: /* Can only be reading stdin in the current context. */ CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\", mimeno); CODE0(" (curl_seek_callback) fseek, NULL, stdin);"); break; default: /* Other cases not possible in this context. */ break; } if(!ret && part->encoder) { Curl_safefree(escaped); escaped = c_escape(part->encoder, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped); } if(!ret && filename) { Curl_safefree(escaped); escaped = c_escape(filename, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->name) { Curl_safefree(escaped); escaped = c_escape(part->name, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->type) { Curl_safefree(escaped); escaped = c_escape(part->type, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped); } if(!ret && part->headers) { int slistno; ret = libcurl_generate_slist(part->headers, &slistno); if(!ret) { CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno); CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */ } } nomem: #ifdef CURL_DOES_CONVERSIONS if(data) free((char *) data); #endif Curl_safefree(escaped); return ret; } /* Wrapper to generate source code for a mime structure. */ static CURLcode libcurl_generate_mime(CURL *curl, struct GlobalConfig *config, tool_mime *toolmime, int *mimeno) { CURLcode ret = CURLE_OK; /* May need several mime variables, so invent name. */ *mimeno = ++easysrc_mime_count; DECL1("curl_mime *mime%d;", *mimeno); DATA1("mime%d = NULL;", *mimeno); CODE1("mime%d = curl_mime_init(hnd);", *mimeno); CLEAN1("curl_mime_free(mime%d);", *mimeno); CLEAN1("mime%d = NULL;", *mimeno); if(toolmime->subparts) { DECL1("curl_mimepart *part%d;", *mimeno); ret = libcurl_generate_mime_part(curl, config, toolmime->subparts, *mimeno); } nomem: return ret; } /* setopt wrapper for CURLOPT_MIMEPOST */ CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, curl_mime *mimepost) { CURLcode ret = curl_easy_setopt(curl, tag, mimepost); int mimeno = 0; if(!ret && config->libcurl) { ret = libcurl_generate_mime(curl, config, config->current->mimeroot, &mimeno); if(!ret) CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno); } nomem: return ret; } /* setopt wrapper for curl_slist options */ CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, const char *name, CURLoption tag, struct curl_slist *list) { CURLcode ret = CURLE_OK; ret = curl_easy_setopt(curl, tag, list); if(config->libcurl && list && !ret) { int i; ret = libcurl_generate_slist(list, &i); if(!ret) CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); } nomem: return ret; } /* generic setopt wrapper for all other options. * Some type information is encoded in the tag value. */ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config, const char *name, CURLoption tag, ...) { va_list arg; char buf[256]; const char *value = NULL; bool remark = FALSE; bool skip = FALSE; bool escape = FALSE; char *escaped = NULL; CURLcode ret = CURLE_OK; va_start(arg, tag); if(tag < CURLOPTTYPE_OBJECTPOINT) { /* Value is expected to be a long */ long lval = va_arg(arg, long); long defval = 0L; const NameValue *nv = NULL; for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) { if(!strcmp(name, nv->name)) { defval = nv->value; break; /* found it */ } } msnprintf(buf, sizeof(buf), "%ldL", lval); value = buf; ret = curl_easy_setopt(curl, tag, lval); if(lval == defval) skip = TRUE; } else if(tag < CURLOPTTYPE_OFF_T) { /* Value is some sort of object pointer */ void *pval = va_arg(arg, void *); /* function pointers are never printable */ if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { if(pval) { value = "functionpointer"; remark = TRUE; } else skip = TRUE; } else if(pval && str) { value = (char *)pval; escape = TRUE; } else if(pval) { value = "objectpointer"; remark = TRUE; } else skip = TRUE; ret = curl_easy_setopt(curl, tag, pval); } else { /* Value is expected to be curl_off_t */ curl_off_t oval = va_arg(arg, curl_off_t); msnprintf(buf, sizeof(buf), "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); value = buf; ret = curl_easy_setopt(curl, tag, oval); if(!oval) skip = TRUE; } va_end(arg); if(config->libcurl && !skip && !ret) { /* we only use this for real if --libcurl was used */ if(remark) REM2("%s set to a %s", name, value); else { if(escape) { escaped = c_escape(value, CURL_ZERO_TERMINATED); NULL_CHECK(escaped); CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); } else CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); } } nomem: Curl_safefree(escaped); return ret; } #else /* CURL_DISABLE_LIBCURL_OPTION */ #include "tool_cfgable.h" #include "tool_setopt.h" #endif /* CURL_DISABLE_LIBCURL_OPTION */ /* * tool_setopt_skip() allows the curl tool code to avoid setopt options that * are explicitly disabled in the build. */ bool tool_setopt_skip(CURLoption tag) { #ifdef CURL_DISABLE_PROXY #define USED_TAG switch(tag) { case CURLOPT_HAPROXYPROTOCOL: case CURLOPT_HTTPPROXYTUNNEL: case CURLOPT_NOPROXY: case CURLOPT_PRE_PROXY: case CURLOPT_PROXY: case CURLOPT_PROXYAUTH: case CURLOPT_PROXY_CAINFO: case CURLOPT_PROXY_CAPATH: case CURLOPT_PROXY_CRLFILE: case CURLOPT_PROXYHEADER: case CURLOPT_PROXY_KEYPASSWD: case CURLOPT_PROXYPASSWORD: case CURLOPT_PROXY_PINNEDPUBLICKEY: case CURLOPT_PROXYPORT: case CURLOPT_PROXY_SERVICE_NAME: case CURLOPT_PROXY_SSLCERT: case CURLOPT_PROXY_SSLCERTTYPE: case CURLOPT_PROXY_SSL_CIPHER_LIST: case CURLOPT_PROXY_SSLKEY: case CURLOPT_PROXY_SSLKEYTYPE: case CURLOPT_PROXY_SSL_OPTIONS: case CURLOPT_PROXY_SSL_VERIFYHOST: case CURLOPT_PROXY_SSL_VERIFYPEER: case CURLOPT_PROXY_SSLVERSION: case CURLOPT_PROXY_TLS13_CIPHERS: case CURLOPT_PROXY_TLSAUTH_PASSWORD: case CURLOPT_PROXY_TLSAUTH_TYPE: case CURLOPT_PROXY_TLSAUTH_USERNAME: case CURLOPT_PROXY_TRANSFER_MODE: case CURLOPT_PROXYTYPE: case CURLOPT_PROXYUSERNAME: case CURLOPT_PROXYUSERPWD: return TRUE; default: break; } #endif #ifdef CURL_DISABLE_FTP #define USED_TAG switch(tag) { case CURLOPT_FTPPORT: case CURLOPT_FTP_ACCOUNT: case CURLOPT_FTP_ALTERNATIVE_TO_USER: case CURLOPT_FTP_FILEMETHOD: case CURLOPT_FTP_SKIP_PASV_IP: case CURLOPT_FTP_USE_EPRT: case CURLOPT_FTP_USE_EPSV: case CURLOPT_FTP_USE_PRET: case CURLOPT_KRBLEVEL: return TRUE; default: break; } #endif #ifdef CURL_DISABLE_RTSP #define USED_TAG switch(tag) { case CURLOPT_INTERLEAVEDATA: return TRUE; default: break; } #endif #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) #define USED_TAG switch(tag) { case CURLOPT_COOKIE: case CURLOPT_COOKIEFILE: case CURLOPT_COOKIEJAR: case CURLOPT_COOKIESESSION: return TRUE; default: break; } #endif #if defined(CURL_DISABLE_TELNET) #define USED_TAG switch(tag) { case CURLOPT_TELNETOPTIONS: return TRUE; default: break; } #endif #ifdef CURL_DISABLE_TFTP #define USED_TAG switch(tag) { case CURLOPT_TFTP_BLKSIZE: case CURLOPT_TFTP_NO_OPTIONS: return TRUE; default: break; } #endif #ifdef CURL_DISABLE_NETRC #define USED_TAG switch(tag) { case CURLOPT_NETRC: case CURLOPT_NETRC_FILE: return TRUE; default: break; } #endif #ifndef USED_TAG (void)tag; #endif return FALSE; } davix-0.8.0/deps/curl/src/slist_wc.h0000644000000000000000000000334214121063461016017 0ustar rootroot#ifndef HEADER_CURL_SLIST_WC_H #define HEADER_CURL_SLIST_WC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef CURL_DISABLE_LIBCURL_OPTION /* linked-list structure with last node cache for easysrc */ struct slist_wc { struct curl_slist *first; struct curl_slist *last; }; /* * NAME curl_slist_wc_append() * * DESCRIPTION * * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ struct slist_wc *slist_wc_append(struct slist_wc *, const char *); /* * NAME curl_slist_free_all() * * DESCRIPTION * * free a previously built curl_slist_wc. */ void slist_wc_free_all(struct slist_wc *); #endif /* CURL_DISABLE_LIBCURL_OPTION */ #endif /* HEADER_CURL_SLIST_WC_H */ davix-0.8.0/deps/curl/src/tool_doswin.h0000644000000000000000000000534314121063461016533 0ustar rootroot#ifndef HEADER_CURL_TOOL_DOSWIN_H #define HEADER_CURL_TOOL_DOSWIN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(MSDOS) || defined(WIN32) #define SANITIZE_ALLOW_COLONS (1<<0) /* Allow colons */ #define SANITIZE_ALLOW_PATH (1<<1) /* Allow path separators and colons */ #define SANITIZE_ALLOW_RESERVED (1<<2) /* Allow reserved device names */ #define SANITIZE_ALLOW_TRUNCATE (1<<3) /* Allow truncating a long filename */ typedef enum { SANITIZE_ERR_OK = 0, /* 0 - OK */ SANITIZE_ERR_INVALID_PATH, /* 1 - the path is invalid */ SANITIZE_ERR_BAD_ARGUMENT, /* 2 - bad function parameter */ SANITIZE_ERR_OUT_OF_MEMORY, /* 3 - out of memory */ SANITIZE_ERR_LAST /* never use! */ } SANITIZEcode; SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, int flags); #ifdef UNITTESTS SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos); SANITIZEcode msdosify(char **const sanitized, const char *file_name, int flags); SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, const char *file_name, int flags); #endif /* UNITTESTS */ #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) char **__crt0_glob_function(char *arg); #endif /* MSDOS && (__DJGPP__ || __GO32__) */ #ifdef WIN32 CURLcode FindWin32CACert(struct OperationConfig *config, curl_sslbackend backend, const char *bundle_file); struct curl_slist *GetLoadedModulePaths(void); CURLcode win32_init(void); #endif /* WIN32 */ #endif /* MSDOS || WIN32 */ #endif /* HEADER_CURL_TOOL_DOSWIN_H */ davix-0.8.0/deps/curl/src/tool_sleep.h0000644000000000000000000000224114121063461016332 0ustar rootroot#ifndef HEADER_CURL_TOOL_SLEEP_H #define HEADER_CURL_TOOL_SLEEP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" void tool_go_sleep(long ms); #endif /* HEADER_CURL_TOOL_SLEEP_H */ davix-0.8.0/deps/curl/src/tool_dirhie.c0000644000000000000000000001147114121063461016466 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include #ifdef WIN32 # include #endif #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_dirhie.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef NETWARE # ifndef __NOVELL_LIBC__ # define mkdir mkdir_510 # endif #endif #if defined(WIN32) || (defined(MSDOS) && !defined(__DJGPP__)) # define mkdir(x,y) (mkdir)((x)) # ifndef F_OK # define F_OK 0 # endif #endif static void show_dir_errno(FILE *errors, const char *name) { switch(errno) { #ifdef EACCES case EACCES: fprintf(errors, "You don't have permission to create %s.\n", name); break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: fprintf(errors, "The directory name %s is too long.\n", name); break; #endif #ifdef EROFS case EROFS: fprintf(errors, "%s resides on a read-only file system.\n", name); break; #endif #ifdef ENOSPC case ENOSPC: fprintf(errors, "No space left on the file system that will " "contain the directory %s.\n", name); break; #endif #ifdef EDQUOT case EDQUOT: fprintf(errors, "Cannot create directory %s because you " "exceeded your quota.\n", name); break; #endif default : fprintf(errors, "Error creating directory %s.\n", name); break; } } /* * Create the needed directory hierarchy recursively in order to save * multi-GETs in file output, ie: * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" * should create all the dir* automagically */ #if defined(WIN32) || defined(__DJGPP__) /* systems that may use either or when specifying a path */ #define PATH_DELIMITERS "\\/" #else #define PATH_DELIMITERS DIR_CHAR #endif CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) { char *tempdir; char *tempdir2; char *outdup; char *dirbuildup; CURLcode result = CURLE_OK; size_t outlen; outlen = strlen(outfile); outdup = strdup(outfile); if(!outdup) return CURLE_OUT_OF_MEMORY; dirbuildup = malloc(outlen + 1); if(!dirbuildup) { Curl_safefree(outdup); return CURLE_OUT_OF_MEMORY; } dirbuildup[0] = '\0'; /* Allow strtok() here since this isn't used threaded */ /* !checksrc! disable BANNEDFUNC 2 */ tempdir = strtok(outdup, PATH_DELIMITERS); while(tempdir != NULL) { bool skip = false; tempdir2 = strtok(NULL, PATH_DELIMITERS); /* since strtok returns a token for the last word even if not ending with DIR_CHAR, we need to prune it */ if(tempdir2 != NULL) { size_t dlen = strlen(dirbuildup); if(dlen) msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir); else { if(outdup == tempdir) { #if defined(MSDOS) || defined(WIN32) /* Skip creating a drive's current directory. It may seem as though that would harmlessly fail but it could be a corner case if X: did not exist, since we would be creating it erroneously. eg if outfile is X:\foo\bar\filename then don't mkdir X: This logic takes into account unsupported drives !:, 1:, etc. */ char *p = strchr(tempdir, ':'); if(p && !p[1]) skip = true; #endif /* the output string doesn't start with a separator */ strcpy(dirbuildup, tempdir); } else msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir); } /* Create directory. Ignore access denied error to allow traversal. */ if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) && (errno != EACCES) && (errno != EEXIST)) { show_dir_errno(errors, dirbuildup); result = CURLE_WRITE_ERROR; break; /* get out of loop */ } } tempdir = tempdir2; } Curl_safefree(dirbuildup); Curl_safefree(outdup); return result; } davix-0.8.0/deps/curl/src/tool_homedir.c0000644000000000000000000000420014121063461016641 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_PWD_H # include #endif #include #include "tool_homedir.h" #include "memdebug.h" /* keep this as LAST include */ static char *GetEnv(const char *variable) { char *dupe, *env; env = curl_getenv(variable); if(!env) return NULL; dupe = strdup(env); curl_free(env); return dupe; } /* return the home directory of the current user as an allocated string */ char *homedir(void) { char *home; home = GetEnv("CURL_HOME"); if(home) return home; home = GetEnv("HOME"); if(home) return home; #if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) { struct passwd *pw = getpwuid(geteuid()); if(pw) { home = pw->pw_dir; if(home && home[0]) home = strdup(home); else home = NULL; } } #endif /* PWD-stuff */ #ifdef WIN32 home = GetEnv("APPDATA"); if(!home) { char *env = GetEnv("USERPROFILE"); if(env) { char *path = curl_maprintf("%s\\Application Data", env); if(path) { home = strdup(path); curl_free(path); } free(env); } } #endif /* WIN32 */ return home; } davix-0.8.0/deps/curl/src/tool_cb_see.c0000644000000000000000000001012614121063461016436 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_cb_see.h" #include "memdebug.h" /* keep this as LAST include */ /* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t, both represent the same value. Maximum offset used here when we lseek using a 'long' data type offset */ #define OUR_MAX_SEEK_L 2147483647L - 1L #define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1) /* ** callback for CURLOPT_SEEKFUNCTION ** ** Notice that this is not supposed to return the resulting offset. This ** shall only return CURL_SEEKFUNC_* return codes. */ int tool_seek_cb(void *userdata, curl_off_t offset, int whence) { struct InStruct *in = userdata; #if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES) /* The offset check following here is only interesting if curl_off_t is larger than off_t and we are not using the WIN32 large file support macros that provide the support to do 64bit seeks correctly */ if(offset > OUR_MAX_SEEK_O) { /* Some precaution code to work around problems with different data sizes to allow seeking >32bit even if off_t is 32bit. Should be very rare and is really valid on weirdo-systems. */ curl_off_t left = offset; if(whence != SEEK_SET) /* this code path doesn't support other types */ return CURL_SEEKFUNC_FAIL; if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET)) /* couldn't rewind to beginning */ return CURL_SEEKFUNC_FAIL; while(left) { long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left; if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR)) /* couldn't seek forwards the desired amount */ return CURL_SEEKFUNC_FAIL; left -= step; } return CURL_SEEKFUNC_OK; } #endif if(LSEEK_ERROR == lseek(in->fd, offset, whence)) /* couldn't rewind, the reason is in errno but errno is just not portable enough and we don't actually care that much why we failed. We'll let libcurl know that it may try other means if it wants to. */ return CURL_SEEKFUNC_CANTSEEK; return CURL_SEEKFUNC_OK; } #if defined(WIN32) && !defined(__MINGW64__) #ifdef __BORLANDC__ /* 64-bit lseek-like function unavailable */ # define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) #endif #ifdef __POCC__ # if(__POCC__ < 450) /* 64-bit lseek-like function unavailable */ # define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence) # else # define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence) # endif #endif #ifdef _WIN32_WCE /* 64-bit lseek-like function unavailable */ # undef _lseeki64 # define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) # undef _get_osfhandle # define _get_osfhandle(fd) (fd) #endif /* * Truncate a file handle at a 64-bit position 'where'. */ int tool_ftruncate64(int fd, curl_off_t where) { intptr_t handle = _get_osfhandle(fd); if(_lseeki64(fd, where, SEEK_SET) < 0) return -1; if(!SetEndOfFile((HANDLE)handle)) return -1; return 0; } #endif /* WIN32 && ! __MINGW64__ */ davix-0.8.0/deps/curl/src/tool_bname.h0000644000000000000000000000240014121063461016301 0ustar rootroot#ifndef HEADER_CURL_TOOL_BNAME_H #define HEADER_CURL_TOOL_BNAME_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef HAVE_BASENAME char *tool_basename(char *path); #define basename(x) tool_basename((x)) #endif /* HAVE_BASENAME */ #endif /* HEADER_CURL_TOOL_BNAME_H */ davix-0.8.0/deps/curl/src/tool_xattr.c0000644000000000000000000000742414121063461016367 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_FSETXATTR # include /* header from libc, not from libattr */ # define USE_XATTR #elif defined(__FreeBSD_version) && (__FreeBSD_version > 500000) # include # include # define USE_XATTR #endif #include "tool_xattr.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef USE_XATTR /* mapping table of curl metadata to extended attribute names */ static const struct xattr_mapping { const char *attr; /* name of the xattr */ CURLINFO info; } mappings[] = { /* mappings proposed by * https://freedesktop.org/wiki/CommonExtendedAttributes/ */ { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL }, { "user.mime_type", CURLINFO_CONTENT_TYPE }, { NULL, CURLINFO_NONE } /* last element, abort loop here */ }; /* returns TRUE if a new URL is returned, that then needs to be freed */ /* @unittest: 1621 */ #ifdef UNITTESTS bool stripcredentials(char **url); #else static #endif bool stripcredentials(char **url) { CURLU *u; CURLUcode uc; char *nurl; u = curl_url(); if(u) { uc = curl_url_set(u, CURLUPART_URL, *url, 0); if(uc) goto error; uc = curl_url_set(u, CURLUPART_USER, NULL, 0); if(uc) goto error; uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); if(uc) goto error; uc = curl_url_get(u, CURLUPART_URL, &nurl, 0); if(uc) goto error; curl_url_cleanup(u); *url = nurl; return TRUE; } error: curl_url_cleanup(u); return FALSE; } /* store metadata from the curl request alongside the downloaded * file using extended attributes */ int fwrite_xattr(CURL *curl, int fd) { int i = 0; int err = 0; /* loop through all xattr-curlinfo pairs and abort on a set error */ while(err == 0 && mappings[i].attr != NULL) { char *value = NULL; CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value); if(!result && value) { bool freeptr = FALSE; if(CURLINFO_EFFECTIVE_URL == mappings[i].info) freeptr = stripcredentials(&value); if(value) { #ifdef HAVE_FSETXATTR_6 err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0); #elif defined(HAVE_FSETXATTR_5) err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0); #elif defined(__FreeBSD_version) { ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, mappings[i].attr, value, strlen(value)); /* FreeBSD's extattr_set_fd returns the length of the extended attribute */ err = (rc < 0 ? -1 : 0); } #endif if(freeptr) curl_free(value); } } i++; } return err; } #else int fwrite_xattr(CURL *curl, int fd) { (void)curl; (void)fd; return 0; } #endif davix-0.8.0/deps/curl/src/tool_urlglob.c0000644000000000000000000004741214121063461016674 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_doswin.h" #include "tool_urlglob.h" #include "tool_vms.h" #include "memdebug.h" /* keep this as LAST include */ #define GLOBERROR(string, column, code) \ glob->error = string, glob->pos = column, code static CURLcode glob_fixed(URLGlob *glob, char *fixed, size_t len) { URLPattern *pat = &glob->pattern[glob->size]; pat->type = UPTSet; pat->content.Set.size = 1; pat->content.Set.ptr_s = 0; pat->globindex = -1; pat->content.Set.elements = malloc(sizeof(char *)); if(!pat->content.Set.elements) return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); pat->content.Set.elements[0] = malloc(len + 1); if(!pat->content.Set.elements[0]) return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); memcpy(pat->content.Set.elements[0], fixed, len); pat->content.Set.elements[0][len] = 0; return CURLE_OK; } /* multiply * * Multiplies and checks for overflow. */ static int multiply(unsigned long *amount, long with) { unsigned long sum = *amount * with; if(!with) { *amount = 0; return 0; } if(sum/with != *amount) return 1; /* didn't fit, bail out */ *amount = sum; return 0; } static CURLcode glob_set(URLGlob *glob, char **patternp, size_t *posp, unsigned long *amount, int globindex) { /* processes a set expression with the point behind the opening '{' ','-separated elements are collected until the next closing '}' */ URLPattern *pat; bool done = FALSE; char *buf = glob->glob_buffer; char *pattern = *patternp; char *opattern = pattern; size_t opos = *posp-1; pat = &glob->pattern[glob->size]; /* patterns 0,1,2,... correspond to size=1,3,5,... */ pat->type = UPTSet; pat->content.Set.size = 0; pat->content.Set.ptr_s = 0; pat->content.Set.elements = NULL; pat->globindex = globindex; while(!done) { switch (*pattern) { case '\0': /* URL ended while set was still open */ return GLOBERROR("unmatched brace", opos, CURLE_URL_MALFORMAT); case '{': case '[': /* no nested expressions at this time */ return GLOBERROR("nested brace", *posp, CURLE_URL_MALFORMAT); case '}': /* set element completed */ if(opattern == pattern) return GLOBERROR("empty string within braces", *posp, CURLE_URL_MALFORMAT); /* add 1 to size since it'll be incremented below */ if(multiply(amount, pat->content.Set.size + 1)) return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT); /* FALLTHROUGH */ case ',': *buf = '\0'; if(pat->content.Set.elements) { char **new_arr = realloc(pat->content.Set.elements, (pat->content.Set.size + 1) * sizeof(char *)); if(!new_arr) return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); pat->content.Set.elements = new_arr; } else pat->content.Set.elements = malloc(sizeof(char *)); if(!pat->content.Set.elements) return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); pat->content.Set.elements[pat->content.Set.size] = strdup(glob->glob_buffer); if(!pat->content.Set.elements[pat->content.Set.size]) return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); ++pat->content.Set.size; if(*pattern == '}') { pattern++; /* pass the closing brace */ done = TRUE; continue; } buf = glob->glob_buffer; ++pattern; ++(*posp); break; case ']': /* illegal closing bracket */ return GLOBERROR("unexpected close bracket", *posp, CURLE_URL_MALFORMAT); case '\\': /* escaped character, skip '\' */ if(pattern[1]) { ++pattern; ++(*posp); } /* FALLTHROUGH */ default: *buf++ = *pattern++; /* copy character to set element */ ++(*posp); } } *patternp = pattern; /* return with the new position */ return CURLE_OK; } static CURLcode glob_range(URLGlob *glob, char **patternp, size_t *posp, unsigned long *amount, int globindex) { /* processes a range expression with the point behind the opening '[' - char range: e.g. "a-z]", "B-Q]" - num range: e.g. "0-9]", "17-2000]" - num range with leading zeros: e.g. "001-999]" expression is checked for well-formedness and collected until the next ']' */ URLPattern *pat; int rc; char *pattern = *patternp; char *c; pat = &glob->pattern[glob->size]; pat->globindex = globindex; if(ISALPHA(*pattern)) { /* character range detected */ char min_c; char max_c; char end_c; unsigned long step = 1; pat->type = UPTCharRange; rc = sscanf(pattern, "%c-%c%c", &min_c, &max_c, &end_c); if(rc == 3) { if(end_c == ':') { char *endp; errno = 0; step = strtoul(&pattern[4], &endp, 10); if(errno || &pattern[4] == endp || *endp != ']') step = 0; else pattern = endp + 1; } else if(end_c != ']') /* then this is wrong */ rc = 0; else /* end_c == ']' */ pattern += 4; } *posp += (pattern - *patternp); if(rc != 3 || !step || step > (unsigned)INT_MAX || (min_c == max_c && step != 1) || (min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) || (max_c - min_c) > ('z' - 'a')))) /* the pattern is not well-formed */ return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT); /* if there was a ":[num]" thing, use that as step or else use 1 */ pat->content.CharRange.step = (int)step; pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c; pat->content.CharRange.max_c = max_c; if(multiply(amount, ((pat->content.CharRange.max_c - pat->content.CharRange.min_c) / pat->content.CharRange.step + 1))) return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT); } else if(ISDIGIT(*pattern)) { /* numeric range detected */ unsigned long min_n; unsigned long max_n = 0; unsigned long step_n = 0; char *endp; pat->type = UPTNumRange; pat->content.NumRange.padlength = 0; if(*pattern == '0') { /* leading zero specified, count them! */ c = pattern; while(ISDIGIT(*c)) { c++; ++pat->content.NumRange.padlength; /* padding length is set for all instances of this pattern */ } } errno = 0; min_n = strtoul(pattern, &endp, 10); if(errno || (endp == pattern)) endp = NULL; else { if(*endp != '-') endp = NULL; else { pattern = endp + 1; while(*pattern && ISBLANK(*pattern)) pattern++; if(!ISDIGIT(*pattern)) { endp = NULL; goto fail; } errno = 0; max_n = strtoul(pattern, &endp, 10); if(errno) /* overflow */ endp = NULL; else if(*endp == ':') { pattern = endp + 1; errno = 0; step_n = strtoul(pattern, &endp, 10); if(errno) /* over/underflow situation */ endp = NULL; } else step_n = 1; if(endp && (*endp == ']')) { pattern = endp + 1; } else endp = NULL; } } fail: *posp += (pattern - *patternp); if(!endp || !step_n || (min_n == max_n && step_n != 1) || (min_n != max_n && (min_n > max_n || step_n > (max_n - min_n)))) /* the pattern is not well-formed */ return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT); /* typecasting to ints are fine here since we make sure above that we are within 31 bits */ pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n; pat->content.NumRange.max_n = max_n; pat->content.NumRange.step = step_n; if(multiply(amount, ((pat->content.NumRange.max_n - pat->content.NumRange.min_n) / pat->content.NumRange.step + 1))) return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT); } else return GLOBERROR("bad range specification", *posp, CURLE_URL_MALFORMAT); *patternp = pattern; return CURLE_OK; } static bool peek_ipv6(const char *str, size_t *skip) { /* * Scan for a potential IPv6 literal. * - Valid globs contain a hyphen and <= 1 colon. * - IPv6 literals contain no hyphens and >= 2 colons. */ size_t i = 0; size_t colons = 0; if(str[i++] != '[') { return FALSE; } for(;;) { const char c = str[i++]; if(ISALNUM(c) || c == '.' || c == '%') { /* ok */ } else if(c == ':') { colons++; } else if(c == ']') { *skip = i; return colons >= 2 ? TRUE : FALSE; } else { return FALSE; } } } static CURLcode glob_parse(URLGlob *glob, char *pattern, size_t pos, unsigned long *amount) { /* processes a literal string component of a URL special characters '{' and '[' branch to set/range processing functions */ CURLcode res = CURLE_OK; int globindex = 0; /* count "actual" globs */ *amount = 1; while(*pattern && !res) { char *buf = glob->glob_buffer; size_t sublen = 0; while(*pattern && *pattern != '{') { if(*pattern == '[') { /* skip over IPv6 literals and [] */ size_t skip = 0; if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']')) skip = 2; if(skip) { memcpy(buf, pattern, skip); buf += skip; pattern += skip; sublen += skip; continue; } break; } if(*pattern == '}' || *pattern == ']') return GLOBERROR("unmatched close brace/bracket", pos, CURLE_URL_MALFORMAT); /* only allow \ to escape known "special letters" */ if(*pattern == '\\' && (*(pattern + 1) == '{' || *(pattern + 1) == '[' || *(pattern + 1) == '}' || *(pattern + 1) == ']') ) { /* escape character, skip '\' */ ++pattern; ++pos; } *buf++ = *pattern++; /* copy character to literal */ ++pos; sublen++; } if(sublen) { /* we got a literal string, add it as a single-item list */ *buf = '\0'; res = glob_fixed(glob, glob->glob_buffer, sublen); } else { switch (*pattern) { case '\0': /* done */ break; case '{': /* process set pattern */ pattern++; pos++; res = glob_set(glob, &pattern, &pos, amount, globindex++); break; case '[': /* process range pattern */ pattern++; pos++; res = glob_range(glob, &pattern, &pos, amount, globindex++); break; } } if(++glob->size >= GLOB_PATTERN_NUM) return GLOBERROR("too many globs", pos, CURLE_URL_MALFORMAT); } return res; } CURLcode glob_url(URLGlob **glob, char *url, unsigned long *urlnum, FILE *error) { /* * We can deal with any-size, just make a buffer with the same length * as the specified URL! */ URLGlob *glob_expand; unsigned long amount = 0; char *glob_buffer; CURLcode res; *glob = NULL; glob_buffer = malloc(strlen(url) + 1); if(!glob_buffer) return CURLE_OUT_OF_MEMORY; glob_buffer[0] = 0; glob_expand = calloc(1, sizeof(URLGlob)); if(!glob_expand) { Curl_safefree(glob_buffer); return CURLE_OUT_OF_MEMORY; } glob_expand->urllen = strlen(url); glob_expand->glob_buffer = glob_buffer; res = glob_parse(glob_expand, url, 1, &amount); if(!res) *urlnum = amount; else { if(error && glob_expand->error) { char text[512]; const char *t; if(glob_expand->pos) { msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^", glob_expand->error, glob_expand->pos, url, glob_expand->pos - 1, " "); t = text; } else t = glob_expand->error; /* send error description to the error-stream */ fprintf(error, "curl: (%d) %s\n", res, t); } /* it failed, we cleanup */ glob_cleanup(glob_expand); *urlnum = 1; return res; } *glob = glob_expand; return CURLE_OK; } void glob_cleanup(URLGlob* glob) { size_t i; int elem; if(!glob) return; for(i = 0; i < glob->size; i++) { if((glob->pattern[i].type == UPTSet) && (glob->pattern[i].content.Set.elements)) { for(elem = glob->pattern[i].content.Set.size - 1; elem >= 0; --elem) { Curl_safefree(glob->pattern[i].content.Set.elements[elem]); } Curl_safefree(glob->pattern[i].content.Set.elements); } } Curl_safefree(glob->glob_buffer); Curl_safefree(glob); } CURLcode glob_next_url(char **globbed, URLGlob *glob) { URLPattern *pat; size_t i; size_t len; size_t buflen = glob->urllen + 1; char *buf = glob->glob_buffer; *globbed = NULL; if(!glob->beenhere) glob->beenhere = 1; else { bool carry = TRUE; /* implement a counter over the index ranges of all patterns, starting with the rightmost pattern */ for(i = 0; carry && (i < glob->size); i++) { carry = FALSE; pat = &glob->pattern[glob->size - 1 - i]; switch(pat->type) { case UPTSet: if((pat->content.Set.elements) && (++pat->content.Set.ptr_s == pat->content.Set.size)) { pat->content.Set.ptr_s = 0; carry = TRUE; } break; case UPTCharRange: pat->content.CharRange.ptr_c = (char)(pat->content.CharRange.step + (int)((unsigned char)pat->content.CharRange.ptr_c)); if(pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) { pat->content.CharRange.ptr_c = pat->content.CharRange.min_c; carry = TRUE; } break; case UPTNumRange: pat->content.NumRange.ptr_n += pat->content.NumRange.step; if(pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) { pat->content.NumRange.ptr_n = pat->content.NumRange.min_n; carry = TRUE; } break; default: printf("internal error: invalid pattern type (%d)\n", (int)pat->type); return CURLE_FAILED_INIT; } } if(carry) { /* first pattern ptr has run into overflow, done! */ return CURLE_OK; } } for(i = 0; i < glob->size; ++i) { pat = &glob->pattern[i]; switch(pat->type) { case UPTSet: if(pat->content.Set.elements) { msnprintf(buf, buflen, "%s", pat->content.Set.elements[pat->content.Set.ptr_s]); len = strlen(buf); buf += len; buflen -= len; } break; case UPTCharRange: if(buflen) { *buf++ = pat->content.CharRange.ptr_c; *buf = '\0'; buflen--; } break; case UPTNumRange: msnprintf(buf, buflen, "%0*lu", pat->content.NumRange.padlength, pat->content.NumRange.ptr_n); len = strlen(buf); buf += len; buflen -= len; break; default: printf("internal error: invalid pattern type (%d)\n", (int)pat->type); return CURLE_FAILED_INIT; } } *globbed = strdup(glob->glob_buffer); if(!*globbed) return CURLE_OUT_OF_MEMORY; return CURLE_OK; } CURLcode glob_match_url(char **result, char *filename, URLGlob *glob) { char *target; size_t allocsize; char numbuf[18]; char *appendthis = (char *)""; size_t appendlen = 0; size_t stringlen = 0; *result = NULL; /* We cannot use the glob_buffer for storage here since the filename may * be longer than the URL we use. We allocate a good start size, then * we need to realloc in case of need. */ allocsize = strlen(filename) + 1; /* make it at least one byte to store the trailing zero */ target = malloc(allocsize); if(!target) return CURLE_OUT_OF_MEMORY; while(*filename) { if(*filename == '#' && ISDIGIT(filename[1])) { char *ptr = filename; unsigned long num = strtoul(&filename[1], &filename, 10); URLPattern *pat = NULL; if(num && (num < glob->size)) { unsigned long i; num--; /* make it zero based */ /* find the correct glob entry */ for(i = 0; isize; i++) { if(glob->pattern[i].globindex == (int)num) { pat = &glob->pattern[i]; break; } } } if(pat) { switch(pat->type) { case UPTSet: if(pat->content.Set.elements) { appendthis = pat->content.Set.elements[pat->content.Set.ptr_s]; appendlen = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]); } break; case UPTCharRange: numbuf[0] = pat->content.CharRange.ptr_c; numbuf[1] = 0; appendthis = numbuf; appendlen = 1; break; case UPTNumRange: msnprintf(numbuf, sizeof(numbuf), "%0*lu", pat->content.NumRange.padlength, pat->content.NumRange.ptr_n); appendthis = numbuf; appendlen = strlen(numbuf); break; default: fprintf(stderr, "internal error: invalid pattern type (%d)\n", (int)pat->type); Curl_safefree(target); return CURLE_FAILED_INIT; } } else { /* #[num] out of range, use the #[num] in the output */ filename = ptr; appendthis = filename++; appendlen = 1; } } else { appendthis = filename++; appendlen = 1; } if(appendlen + stringlen >= allocsize) { char *newstr; /* we append a single byte to allow for the trailing byte to be appended at the end of this function outside the while() loop */ allocsize = (appendlen + stringlen) * 2; newstr = realloc(target, allocsize + 1); if(!newstr) { Curl_safefree(target); return CURLE_OUT_OF_MEMORY; } target = newstr; } memcpy(&target[stringlen], appendthis, appendlen); stringlen += appendlen; } target[stringlen]= '\0'; #if defined(MSDOS) || defined(WIN32) { char *sanitized; SANITIZEcode sc = sanitize_file_name(&sanitized, target, (SANITIZE_ALLOW_PATH | SANITIZE_ALLOW_RESERVED)); Curl_safefree(target); if(sc) return CURLE_URL_MALFORMAT; target = sanitized; } #endif /* MSDOS || WIN32 */ *result = target; return CURLE_OK; } davix-0.8.0/deps/curl/src/makefile.dj0000644000000000000000000000444414121063461016117 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 2003 - 2007, Gisle Vanem . # Copyright (C) 2003 - 2015, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** # # Adapted for djgpp2 / Watt-32 / DOS # DEPEND_PREREQ = # tool_hugehelp.c TOPDIR = .. include ../packages/DOS/common.dj include Makefile.inc CSOURCES = $(CURL_CFILES) ifeq ($(USE_SSL),1) EX_LIBS += $(OPENSSL_ROOT)/lib/libssl.a $(OPENSSL_ROOT)/lib/libcrypt.a endif ifeq ($(USE_ARES),1) EX_LIBS += $(ARES_ROOT)/libcares.a endif ifeq ($(USE_ZLIB),1) EX_LIBS += $(ZLIB_ROOT)/libz.a CFLAGS += -DUSE_MANUAL endif ifeq ($(USE_IDNA),1) EX_LIBS += $(LIBIDN_ROOT)/lib/dj_obj/libidn.a -liconv endif EX_LIBS += $(WATT32_ROOT)/lib/libwatt.a PROGRAM = curl.exe OBJECTS += $(addprefix $(OBJ_DIR)/, $(CSOURCES:.c=.o)) all: $(OBJ_DIR) $(PROGRAM) @echo Welcome to curl $(PROGRAM): $(OBJECTS) ../lib/libcurl.a $(CC) -o $@ $^ $(LDFLAGS) $(EX_LIBS) # # groff 1.18+ requires "-P -c" # tool_hugehelp.c: ../docs/MANUAL ../docs/curl.1 mkhelp.pl groff -Tascii -man ../docs/curl.1 | \ perl -w mkhelp.pl ../docs/MANUAL > $@ # clean generated files # genclean: - $(DELETE) tool_hugehelp.c # clean object files and subdir # objclean: genclean - $(DELETE) $(OBJ_DIR)$(DS)*.o - $(RMDIR) $(OBJ_DIR) # clean without removing built program # clean: objclean - $(DELETE) depend.dj # clean everything # realclean vclean: clean - $(DELETE) $(PROGRAM) -include depend.dj davix-0.8.0/deps/curl/src/tool_writeout.h0000644000000000000000000000233214121063461017105 0ustar rootroot#ifndef HEADER_CURL_TOOL_WRITEOUT_H #define HEADER_CURL_TOOL_WRITEOUT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo); #endif /* HEADER_CURL_TOOL_WRITEOUT_H */ davix-0.8.0/deps/curl/src/mkhelp.pl0000755000000000000000000001345614121063461015646 0ustar rootroot#!/usr/bin/env perl #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # ########################################################################### # Yeah, I know, probably 1000 other persons already wrote a script like # this, but I'll tell ya: # THEY DON'T FIT ME :-) # Get readme file as parameter: if($ARGV[0] eq "-c") { $c=1; shift @ARGV; } push @out, " _ _ ____ _\n"; push @out, " Project ___| | | | _ \\| |\n"; push @out, " / __| | | | |_) | |\n"; push @out, " | (__| |_| | _ <| |___\n"; push @out, " \\___|\\___/|_| \\_\\_____|\n"; my $olen=0; while () { my $line = $_; # this should be removed: $line =~ s/(.|_)//g; # remove trailing CR from line. msysgit checks out files as line+CRLF $line =~ s/\r$//; if($line =~ /^([ \t]*\n|curl)/i) { # cut off headers and empty lines $wline++; # count number of cut off lines next; } my $text = $line; $text =~ s/^\s+//g; # cut off preceding... $text =~ s/\s+$//g; # and trailing whitespaces $tlen = length($text); if($wline && ($olen == $tlen)) { # if the previous line with contents was exactly as long as # this line, then we ignore the newlines! # We do this magic because a header may abort a paragraph at # any line, but we don't want that to be noticed in the output # here $wline=0; } $olen = $tlen; if($wline) { # we only make one empty line max $wline = 0; push @out, "\n"; } push @out, $line; } push @out, "\n"; # just an extra newline print <import(); 1; }; print STDERR "Warning: compression requested but Gzip is not available\n" if (!$c) } if($c) { my $content = join("", @out); my $gzippedContent; IO::Compress::Gzip::gzip( \$content, \$gzippedContent, Level => 9, TextFlag => 1, Time=>0) or die "gzip failed:"; $gzip = length($content); $gzipped = length($gzippedContent); print < #include "memdebug.h" /* keep this as LAST include */ static const unsigned char hugehelpgz[] = { /* This mumbo-jumbo is the huge help text compressed with gzip. Thanks to this operation, the size of this data shrank from $gzip to $gzipped bytes. You can disable the use of compressed help texts by NOT passing -c to the mkhelp.pl tool. */ HEAD ; my $c=0; print " "; for(split(//, $gzippedContent)) { my $num=ord($_); printf(" 0x%02x,", 0+$num); if(!(++$c % 12)) { print "\n "; } } print "\n};\n"; print < 500) { # terminate and make another fputs() call here print ", stdout);\n fputs(\n"; $outsize=length($new)+1; } printf("\"%s\\n\"\n", $new); } print ", stdout) ;\n}\n"; foot(); sub foot { print <, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" struct timeval tvnow(void); /* * Make sure that the first argument (t1) is the more recent time and t2 is * the older time, as otherwise you get a weird negative time-diff back... * * Returns: the time difference in number of milliseconds. */ long tvdiff(struct timeval t1, struct timeval t2); #endif /* HEADER_CURL_TOOL_UTIL_H */ davix-0.8.0/deps/curl/src/makefile.amiga0000644000000000000000000000134014121063461016570 0ustar rootroot# # $VER: curl Makefile for AmigaOS ... # # change the follow to where you have the AmiTCP SDK v4.3 includes: ATCPSDKI= /GG/netinclude CC = m68k-amigaos-gcc CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall LIBS = ../lib/libcurl.a -lssl -lcrypto -lz MANPAGE = ../docs/curl.1 README = ../docs/MANUAL MKHELP = ../src/mkhelp.pl include Makefile.inc OBJS = $(CURL_CFILES:.c=.o) $(CURLX_CFILES:.c=.o) all: tool_hugehelp.c $(OBJS) $(CC) $(CFLAGS) -o curl $(OBJS) $(LIBS) -Wl,-Map,curl.map,--cref tool_hugehelp.c: $(README) $(MANPAGE) mkhelp.pl rm -f tool_hugehelp.c /bin/nroff -man $(MANPAGE) | /bin/perl $(MKHELP) -c $(README) > tool_hugehelp.c install: $(INSTALL) -c curl /c/curl davix-0.8.0/deps/curl/src/curl.rc0000644000000000000000000000752714121063461015323 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include #include "tool_version.h" LANGUAGE 0, 0 #define RC_VERSION CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0 VS_VERSION_INFO VERSIONINFO FILEVERSION RC_VERSION PRODUCTVERSION RC_VERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #if defined(DEBUGBUILD) || defined(_DEBUG) FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "curl, https://curl.haxx.se/\0" VALUE "FileDescription", "The curl executable\0" VALUE "FileVersion", CURL_VERSION "\0" VALUE "InternalName", "curl\0" VALUE "OriginalFilename", "curl.exe\0" VALUE "ProductName", "The curl executable\0" VALUE "ProductVersion", CURL_VERSION "\0" VALUE "LegalCopyright", "\xa9 " CURL_COPYRIGHT "\0" /* a9: Copyright symbol */ VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END /* Manifest */ #if defined(CURL_EMBED_MANIFEST) /* String escaping rules: https://msdn.microsoft.com/library/aa381050 Application Manifest doc, including the list of 'supportedOS Id's: https://msdn.microsoft.com/library/aa374191 */ #ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 #endif #ifndef RT_MANIFEST #define RT_MANIFEST 24 #endif #define _STR(macro) _STR_(macro) #define _STR_(macro) #macro CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST BEGIN "" "" "" "" "" "" /* Vista / Server 2008 */ "" /* 7 / Server 2008 R2 */ "" /* 8 / Server 2012 */ "" /* 8.1 / Server 2012 R2 */ "" /* 10 / Server 2016 */ "" "" "" "" "" "" "" "" "" "" END #endif davix-0.8.0/deps/curl/src/tool_paramhlp.c0000644000000000000000000004223014121063461017023 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_getparam.h" #include "tool_getpass.h" #include "tool_homedir.h" #include "tool_msgs.h" #include "tool_paramhlp.h" #include "tool_version.h" #include "memdebug.h" /* keep this as LAST include */ struct getout *new_getout(struct OperationConfig *config) { struct getout *node = calloc(1, sizeof(struct getout)); struct getout *last = config->url_last; if(node) { /* append this new node last in the list */ if(last) last->next = node; else config->url_list = node; /* first node */ /* move the last pointer */ config->url_last = node; node->flags = config->default_node_flags; } return node; } ParameterError file2string(char **bufp, FILE *file) { char *string = NULL; if(file) { char *ptr; size_t alloc = 512; size_t alloc_needed; char buffer[256]; size_t stringlen = 0; string = calloc(1, alloc); if(!string) return PARAM_NO_MEM; while(fgets(buffer, sizeof(buffer), file)) { size_t buflen; ptr = strchr(buffer, '\r'); if(ptr) *ptr = '\0'; ptr = strchr(buffer, '\n'); if(ptr) *ptr = '\0'; buflen = strlen(buffer); alloc_needed = stringlen + buflen + 1; if(alloc < alloc_needed) { #if SIZEOF_SIZE_T < 8 if(alloc >= (size_t)SIZE_T_MAX/2) { Curl_safefree(string); return PARAM_NO_MEM; } #endif /* doubling is enough since the string to add is always max 256 bytes and the alloc size start at 512 */ alloc *= 2; ptr = realloc(string, alloc); if(!ptr) { Curl_safefree(string); return PARAM_NO_MEM; } string = ptr; } strcpy(string + stringlen, buffer); stringlen += buflen; } } *bufp = string; return PARAM_OK; } ParameterError file2memory(char **bufp, size_t *size, FILE *file) { char *newbuf; char *buffer = NULL; size_t nused = 0; if(file) { size_t nread; size_t alloc = 512; do { if(!buffer || (alloc == nused)) { /* size_t overflow detection for huge files */ if(alloc + 1 > ((size_t)-1)/2) { Curl_safefree(buffer); return PARAM_NO_MEM; } alloc *= 2; /* allocate an extra char, reserved space, for null termination */ newbuf = realloc(buffer, alloc + 1); if(!newbuf) { Curl_safefree(buffer); return PARAM_NO_MEM; } buffer = newbuf; } nread = fread(buffer + nused, 1, alloc-nused, file); nused += nread; } while(nread); /* null terminate the buffer in case it's used as a string later */ buffer[nused] = '\0'; /* free trailing slack space, if possible */ if(alloc != nused) { newbuf = realloc(buffer, nused + 1); if(!newbuf) { Curl_safefree(buffer); return PARAM_NO_MEM; } buffer = newbuf; } /* discard buffer if nothing was read */ if(!nused) { Curl_safefree(buffer); /* no string */ } } *size = nused; *bufp = buffer; return PARAM_OK; } void cleanarg(char *str) { #ifdef HAVE_WRITABLE_ARGV /* now that GetStr has copied the contents of nextarg, wipe the next * argument out so that the username:password isn't displayed in the * system process list */ if(str) { size_t len = strlen(str); memset(str, ' ', len); } #else (void)str; #endif } /* * Parse the string and write the long in the given address. Return PARAM_OK * on success, otherwise a parameter specific error enum. * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ ParameterError str2num(long *val, const char *str) { if(str) { char *endptr; long num; errno = 0; num = strtol(str, &endptr, 10); if(errno == ERANGE) return PARAM_NUMBER_TOO_LARGE; if((endptr != str) && (endptr == str + strlen(str))) { *val = num; return PARAM_OK; /* Ok */ } } return PARAM_BAD_NUMERIC; /* badness */ } /* * Parse the string and write the long in the given address. Return PARAM_OK * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ ParameterError str2unum(long *val, const char *str) { ParameterError result = str2num(val, str); if(result != PARAM_OK) return result; if(*val < 0) return PARAM_NEGATIVE_NUMERIC; return PARAM_OK; } /* * Parse the string and write the long in the given address if it is below the * maximum allowed value. Return PARAM_OK on success, otherwise a parameter * error enum. ONLY ACCEPTS POSITIVE NUMBERS! * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ ParameterError str2unummax(long *val, const char *str, long max) { ParameterError result = str2unum(val, str); if(result != PARAM_OK) return result; if(*val > max) return PARAM_NUMBER_TOO_LARGE; return PARAM_OK; } /* * Parse the string and write the double in the given address. Return PARAM_OK * on success, otherwise a parameter specific error enum. * * The 'max' argument is the maximum value allowed, as the numbers are often * multiplied when later used. * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ static ParameterError str2double(double *val, const char *str, long max) { if(str) { char *endptr; double num; errno = 0; num = strtod(str, &endptr); if(errno == ERANGE) return PARAM_NUMBER_TOO_LARGE; if(num > max) { /* too large */ return PARAM_NUMBER_TOO_LARGE; } if((endptr != str) && (endptr == str + strlen(str))) { *val = num; return PARAM_OK; /* Ok */ } } return PARAM_BAD_NUMERIC; /* badness */ } /* * Parse the string and write the double in the given address. Return PARAM_OK * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! * * The 'max' argument is the maximum value allowed, as the numbers are often * multiplied when later used. * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ ParameterError str2udouble(double *valp, const char *str, long max) { double value; ParameterError result = str2double(&value, str, max); if(result != PARAM_OK) return result; if(value < 0) return PARAM_NEGATIVE_NUMERIC; *valp = value; return PARAM_OK; } /* * Parse the string and modify the long in the given address. Return * non-zero on failure, zero on success. * * The string is a list of protocols * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ long proto2num(struct OperationConfig *config, long *val, const char *str) { char *buffer; const char *sep = ","; char *token; static struct sprotos { const char *name; long bit; } const protos[] = { { "all", CURLPROTO_ALL }, { "http", CURLPROTO_HTTP }, { "https", CURLPROTO_HTTPS }, { "ftp", CURLPROTO_FTP }, { "ftps", CURLPROTO_FTPS }, { "scp", CURLPROTO_SCP }, { "sftp", CURLPROTO_SFTP }, { "telnet", CURLPROTO_TELNET }, { "ldap", CURLPROTO_LDAP }, { "ldaps", CURLPROTO_LDAPS }, { "dict", CURLPROTO_DICT }, { "file", CURLPROTO_FILE }, { "tftp", CURLPROTO_TFTP }, { "imap", CURLPROTO_IMAP }, { "imaps", CURLPROTO_IMAPS }, { "pop3", CURLPROTO_POP3 }, { "pop3s", CURLPROTO_POP3S }, { "smtp", CURLPROTO_SMTP }, { "smtps", CURLPROTO_SMTPS }, { "rtsp", CURLPROTO_RTSP }, { "gopher", CURLPROTO_GOPHER }, { "smb", CURLPROTO_SMB }, { "smbs", CURLPROTO_SMBS }, { NULL, 0 } }; if(!str) return 1; buffer = strdup(str); /* because strtok corrupts it */ if(!buffer) return 1; /* Allow strtok() here since this isn't used threaded */ /* !checksrc! disable BANNEDFUNC 2 */ for(token = strtok(buffer, sep); token; token = strtok(NULL, sep)) { enum e_action { allow, deny, set } action = allow; struct sprotos const *pp; /* Process token modifiers */ while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ switch (*token++) { case '=': action = set; break; case '-': action = deny; break; case '+': action = allow; break; default: /* Includes case of terminating NULL */ Curl_safefree(buffer); return 1; } } for(pp = protos; pp->name; pp++) { if(curl_strequal(token, pp->name)) { switch(action) { case deny: *val &= ~(pp->bit); break; case allow: *val |= pp->bit; break; case set: *val = pp->bit; break; } break; } } if(!(pp->name)) { /* unknown protocol */ /* If they have specified only this protocol, we say treat it as if no protocols are allowed */ if(action == set) *val = 0; warnf(config->global, "unrecognized protocol '%s'\n", token); } } Curl_safefree(buffer); return 0; } /** * Check if the given string is a protocol supported by libcurl * * @param str the protocol name * @return PARAM_OK protocol supported * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported * @return PARAM_REQUIRES_PARAMETER missing parameter */ int check_protocol(const char *str) { const char * const *pp; const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW); if(!str) return PARAM_REQUIRES_PARAMETER; for(pp = curlinfo->protocols; *pp; pp++) { if(curl_strequal(*pp, str)) return PARAM_OK; } return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL; } /** * Parses the given string looking for an offset (which may be a * larger-than-integer value). The offset CANNOT be negative! * * @param val the offset to populate * @param str the buffer containing the offset * @return PARAM_OK if successful, a parameter specific error enum if failure. */ ParameterError str2offset(curl_off_t *val, const char *str) { char *endptr; if(str[0] == '-') /* offsets aren't negative, this indicates weird input */ return PARAM_NEGATIVE_NUMERIC; #if(SIZEOF_CURL_OFF_T > SIZEOF_LONG) { CURLofft offt = curlx_strtoofft(str, &endptr, 0, val); if(CURL_OFFT_FLOW == offt) return PARAM_NUMBER_TOO_LARGE; else if(CURL_OFFT_INVAL == offt) return PARAM_BAD_NUMERIC; } #else errno = 0; *val = strtol(str, &endptr, 0); if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE) return PARAM_NUMBER_TOO_LARGE; #endif if((endptr != str) && (endptr == str + strlen(str))) return PARAM_OK; return PARAM_BAD_NUMERIC; } static CURLcode checkpasswd(const char *kind, /* for what purpose */ const size_t i, /* operation index */ const bool last, /* TRUE if last operation */ char **userpwd) /* pointer to allocated string */ { char *psep; char *osep; if(!*userpwd) return CURLE_OK; /* Attempt to find the password separator */ psep = strchr(*userpwd, ':'); /* Attempt to find the options separator */ osep = strchr(*userpwd, ';'); if(!psep && **userpwd != ';') { /* no password present, prompt for one */ char passwd[256] = ""; char prompt[256]; size_t passwdlen; size_t userlen = strlen(*userpwd); char *passptr; if(osep) *osep = '\0'; /* build a nice-looking prompt */ if(!i && last) curlx_msnprintf(prompt, sizeof(prompt), "Enter %s password for user '%s':", kind, *userpwd); else curlx_msnprintf(prompt, sizeof(prompt), "Enter %s password for user '%s' on URL #%zu:", kind, *userpwd, i + 1); /* get password */ getpass_r(prompt, passwd, sizeof(passwd)); passwdlen = strlen(passwd); if(osep) *osep = ';'; /* extend the allocated memory area to fit the password too */ passptr = realloc(*userpwd, passwdlen + 1 + /* an extra for the colon */ userlen + 1); /* an extra for the zero */ if(!passptr) return CURLE_OUT_OF_MEMORY; /* append the password separated with a colon */ passptr[userlen] = ':'; memcpy(&passptr[userlen + 1], passwd, passwdlen + 1); *userpwd = passptr; } return CURLE_OK; } ParameterError add2list(struct curl_slist **list, const char *ptr) { struct curl_slist *newlist = curl_slist_append(*list, ptr); if(newlist) *list = newlist; else return PARAM_NO_MEM; return PARAM_OK; } int ftpfilemethod(struct OperationConfig *config, const char *str) { if(curl_strequal("singlecwd", str)) return CURLFTPMETHOD_SINGLECWD; if(curl_strequal("nocwd", str)) return CURLFTPMETHOD_NOCWD; if(curl_strequal("multicwd", str)) return CURLFTPMETHOD_MULTICWD; warnf(config->global, "unrecognized ftp file method '%s', using default\n", str); return CURLFTPMETHOD_MULTICWD; } int ftpcccmethod(struct OperationConfig *config, const char *str) { if(curl_strequal("passive", str)) return CURLFTPSSL_CCC_PASSIVE; if(curl_strequal("active", str)) return CURLFTPSSL_CCC_ACTIVE; warnf(config->global, "unrecognized ftp CCC method '%s', using default\n", str); return CURLFTPSSL_CCC_PASSIVE; } long delegation(struct OperationConfig *config, const char *str) { if(curl_strequal("none", str)) return CURLGSSAPI_DELEGATION_NONE; if(curl_strequal("policy", str)) return CURLGSSAPI_DELEGATION_POLICY_FLAG; if(curl_strequal("always", str)) return CURLGSSAPI_DELEGATION_FLAG; warnf(config->global, "unrecognized delegation method '%s', using none\n", str); return CURLGSSAPI_DELEGATION_NONE; } /* * my_useragent: returns allocated string with default user agent */ static char *my_useragent(void) { return strdup(CURL_NAME "/" CURL_VERSION); } CURLcode get_args(struct OperationConfig *config, const size_t i) { CURLcode result = CURLE_OK; bool last = (config->next ? FALSE : TRUE); /* Check we have a password for the given host user */ if(config->userpwd && !config->oauth_bearer) { result = checkpasswd("host", i, last, &config->userpwd); if(result) return result; } /* Check we have a password for the given proxy user */ if(config->proxyuserpwd) { result = checkpasswd("proxy", i, last, &config->proxyuserpwd); if(result) return result; } /* Check we have a user agent */ if(!config->useragent) { config->useragent = my_useragent(); if(!config->useragent) { errorf(config->global, "out of memory\n"); result = CURLE_OUT_OF_MEMORY; } } return result; } /* * Parse the string and modify ssl_version in the val argument. Return PARAM_OK * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! * * Since this function gets called with the 'nextarg' pointer from within the * getparameter a lot, we must check it for NULL before accessing the str * data. */ ParameterError str2tls_max(long *val, const char *str) { static struct s_tls_max { const char *tls_max_str; long tls_max; } const tls_max_array[] = { { "default", CURL_SSLVERSION_MAX_DEFAULT }, { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 }, { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 }, { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 }, { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 } }; size_t i = 0; if(!str) return PARAM_REQUIRES_PARAMETER; for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) { if(!strcmp(str, tls_max_array[i].tls_max_str)) { *val = tls_max_array[i].tls_max; return PARAM_OK; } } return PARAM_BAD_USE; } davix-0.8.0/deps/curl/src/tool_cb_prg.h0000644000000000000000000000341114121063461016456 0ustar rootroot#ifndef HEADER_CURL_TOOL_CB_PRG_H #define HEADER_CURL_TOOL_CB_PRG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define CURL_PROGRESS_STATS 0 /* default progress display */ #define CURL_PROGRESS_BAR 1 struct ProgressData { int calls; curl_off_t prev; struct timeval prevtime; int width; FILE *out; /* where to write everything to */ curl_off_t initial_size; unsigned int tick; int bar; int barmove; }; void progressbarinit(struct ProgressData *bar, struct OperationConfig *config); /* ** callback for CURLOPT_PROGRESSFUNCTION */ int tool_progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); #endif /* HEADER_CURL_TOOL_CB_PRG_H */ davix-0.8.0/deps/curl/src/tool_libinfo.h0000644000000000000000000000246114121063461016650 0ustar rootroot#ifndef HEADER_CURL_TOOL_LIBINFO_H #define HEADER_CURL_TOOL_LIBINFO_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" /* global variable declarations, for libcurl run-time info */ extern curl_version_info_data *curlinfo; extern long built_in_protos; CURLcode get_libcurl_info(void); #endif /* HEADER_CURL_TOOL_LIBINFO_H */ davix-0.8.0/deps/curl/src/tool_writeout.c0000644000000000000000000003215414121063461017105 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_writeout.h" #include "memdebug.h" /* keep this as LAST include */ typedef enum { VAR_NONE, /* must be the first */ VAR_TOTAL_TIME, VAR_NAMELOOKUP_TIME, VAR_CONNECT_TIME, VAR_APPCONNECT_TIME, VAR_PRETRANSFER_TIME, VAR_STARTTRANSFER_TIME, VAR_SIZE_DOWNLOAD, VAR_SIZE_UPLOAD, VAR_SPEED_DOWNLOAD, VAR_SPEED_UPLOAD, VAR_HTTP_CODE, VAR_HTTP_CODE_PROXY, VAR_HEADER_SIZE, VAR_REQUEST_SIZE, VAR_EFFECTIVE_URL, VAR_CONTENT_TYPE, VAR_NUM_CONNECTS, VAR_REDIRECT_TIME, VAR_REDIRECT_COUNT, VAR_FTP_ENTRY_PATH, VAR_REDIRECT_URL, VAR_SSL_VERIFY_RESULT, VAR_PROXY_SSL_VERIFY_RESULT, VAR_EFFECTIVE_FILENAME, VAR_PRIMARY_IP, VAR_PRIMARY_PORT, VAR_LOCAL_IP, VAR_LOCAL_PORT, VAR_HTTP_VERSION, VAR_SCHEME, VAR_STDOUT, VAR_STDERR, VAR_NUM_OF_VARS /* must be the last */ } replaceid; struct variable { const char *name; replaceid id; }; static const struct variable replacements[]={ {"url_effective", VAR_EFFECTIVE_URL}, {"http_code", VAR_HTTP_CODE}, {"response_code", VAR_HTTP_CODE}, {"http_connect", VAR_HTTP_CODE_PROXY}, {"time_total", VAR_TOTAL_TIME}, {"time_namelookup", VAR_NAMELOOKUP_TIME}, {"time_connect", VAR_CONNECT_TIME}, {"time_appconnect", VAR_APPCONNECT_TIME}, {"time_pretransfer", VAR_PRETRANSFER_TIME}, {"time_starttransfer", VAR_STARTTRANSFER_TIME}, {"size_header", VAR_HEADER_SIZE}, {"size_request", VAR_REQUEST_SIZE}, {"size_download", VAR_SIZE_DOWNLOAD}, {"size_upload", VAR_SIZE_UPLOAD}, {"speed_download", VAR_SPEED_DOWNLOAD}, {"speed_upload", VAR_SPEED_UPLOAD}, {"content_type", VAR_CONTENT_TYPE}, {"num_connects", VAR_NUM_CONNECTS}, {"time_redirect", VAR_REDIRECT_TIME}, {"num_redirects", VAR_REDIRECT_COUNT}, {"ftp_entry_path", VAR_FTP_ENTRY_PATH}, {"redirect_url", VAR_REDIRECT_URL}, {"ssl_verify_result", VAR_SSL_VERIFY_RESULT}, {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT}, {"filename_effective", VAR_EFFECTIVE_FILENAME}, {"remote_ip", VAR_PRIMARY_IP}, {"remote_port", VAR_PRIMARY_PORT}, {"local_ip", VAR_LOCAL_IP}, {"local_port", VAR_LOCAL_PORT}, {"http_version", VAR_HTTP_VERSION}, {"scheme", VAR_SCHEME}, {"stdout", VAR_STDOUT}, {"stderr", VAR_STDERR}, {NULL, VAR_NONE} }; void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo) { FILE *stream = stdout; const char *ptr = writeinfo; char *stringp = NULL; long longinfo; double doubleinfo; while(ptr && *ptr) { if('%' == *ptr && ptr[1]) { if('%' == ptr[1]) { /* an escaped %-letter */ fputc('%', stream); ptr += 2; } else { /* this is meant as a variable to output */ char *end; if('{' == ptr[1]) { char keepit; int i; bool match = FALSE; end = strchr(ptr, '}'); ptr += 2; /* pass the % and the { */ if(!end) { fputs("%{", stream); continue; } keepit = *end; *end = 0; /* zero terminate */ for(i = 0; replacements[i].name; i++) { if(curl_strequal(ptr, replacements[i].name)) { match = TRUE; switch(replacements[i].id) { case VAR_EFFECTIVE_URL: if((CURLE_OK == curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp)) && stringp) fputs(stringp, stream); break; case VAR_HTTP_CODE: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo)) fprintf(stream, "%03ld", longinfo); break; case VAR_HTTP_CODE_PROXY: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, &longinfo)) fprintf(stream, "%03ld", longinfo); break; case VAR_HEADER_SIZE: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_REQUEST_SIZE: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_NUM_CONNECTS: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_REDIRECT_COUNT: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_REDIRECT_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_TOTAL_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_NAMELOOKUP_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_CONNECT_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_APPCONNECT_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_PRETRANSFER_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_STARTTRANSFER_TIME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &doubleinfo)) fprintf(stream, "%.6f", doubleinfo); break; case VAR_SIZE_UPLOAD: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo)) fprintf(stream, "%.0f", doubleinfo); break; case VAR_SIZE_DOWNLOAD: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &doubleinfo)) fprintf(stream, "%.0f", doubleinfo); break; case VAR_SPEED_DOWNLOAD: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, &doubleinfo)) fprintf(stream, "%.3f", doubleinfo); break; case VAR_SPEED_UPLOAD: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo)) fprintf(stream, "%.3f", doubleinfo); break; case VAR_CONTENT_TYPE: if((CURLE_OK == curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp)) && stringp) fputs(stringp, stream); break; case VAR_FTP_ENTRY_PATH: if((CURLE_OK == curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp)) && stringp) fputs(stringp, stream); break; case VAR_REDIRECT_URL: if((CURLE_OK == curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp)) && stringp) fputs(stringp, stream); break; case VAR_SSL_VERIFY_RESULT: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_PROXY_SSL_VERIFY_RESULT: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_EFFECTIVE_FILENAME: if(outs->filename) fprintf(stream, "%s", outs->filename); break; case VAR_PRIMARY_IP: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &stringp)) fprintf(stream, "%s", stringp); break; case VAR_PRIMARY_PORT: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_PRIMARY_PORT, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_LOCAL_IP: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_LOCAL_IP, &stringp)) fprintf(stream, "%s", stringp); break; case VAR_LOCAL_PORT: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_LOCAL_PORT, &longinfo)) fprintf(stream, "%ld", longinfo); break; case VAR_HTTP_VERSION: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, &longinfo)) { const char *version = "0"; switch(longinfo) { case CURL_HTTP_VERSION_1_0: version = "1.0"; break; case CURL_HTTP_VERSION_1_1: version = "1.1"; break; case CURL_HTTP_VERSION_2_0: version = "2"; break; case CURL_HTTP_VERSION_3: version = "3"; break; } fprintf(stream, version); } break; case VAR_SCHEME: if(CURLE_OK == curl_easy_getinfo(curl, CURLINFO_SCHEME, &stringp)) fprintf(stream, "%s", stringp); break; case VAR_STDOUT: stream = stdout; break; case VAR_STDERR: stream = stderr; break; default: break; } break; } } if(!match) { fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr); } ptr = end + 1; /* pass the end */ *end = keepit; } else { /* illegal syntax, then just output the characters that are used */ fputc('%', stream); fputc(ptr[1], stream); ptr += 2; } } } else if('\\' == *ptr && ptr[1]) { switch(ptr[1]) { case 'r': fputc('\r', stream); break; case 'n': fputc('\n', stream); break; case 't': fputc('\t', stream); break; default: /* unknown, just output this */ fputc(*ptr, stream); fputc(ptr[1], stream); break; } ptr += 2; } else { fputc(*ptr, stream); ptr++; } } } davix-0.8.0/deps/curl/src/tool_dirhie.h0000644000000000000000000000231114121063461016464 0ustar rootroot#ifndef HEADER_CURL_TOOL_DIRHIE_H #define HEADER_CURL_TOOL_DIRHIE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" CURLcode create_dir_hierarchy(const char *outfile, FILE *errors); #endif /* HEADER_CURL_TOOL_DIRHIE_H */ davix-0.8.0/deps/curl/src/tool_cfgable.c0000644000000000000000000001312614121063461016604 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_cfgable.h" #include "tool_main.h" #include "memdebug.h" /* keep this as LAST include */ void config_init(struct OperationConfig* config) { memset(config, 0, sizeof(struct OperationConfig)); config->postfieldsize = -1; config->use_httpget = FALSE; config->create_dirs = FALSE; config->maxredirs = DEFAULT_MAXREDIRS; config->proto = CURLPROTO_ALL; config->proto_present = FALSE; config->proto_redir = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | CURLPROTO_SMBS); config->proto_redir_present = FALSE; config->proto_default = NULL; config->tcp_nodelay = TRUE; /* enabled by default */ config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; config->http09_allowed = FALSE; } static void free_config_fields(struct OperationConfig *config) { struct getout *urlnode; Curl_safefree(config->random_file); Curl_safefree(config->egd_file); Curl_safefree(config->useragent); Curl_safefree(config->altsvc); Curl_safefree(config->cookie); Curl_safefree(config->cookiejar); Curl_safefree(config->cookiefile); Curl_safefree(config->postfields); Curl_safefree(config->referer); Curl_safefree(config->headerfile); Curl_safefree(config->ftpport); Curl_safefree(config->iface); Curl_safefree(config->range); Curl_safefree(config->userpwd); Curl_safefree(config->tls_username); Curl_safefree(config->tls_password); Curl_safefree(config->tls_authtype); Curl_safefree(config->proxy_tls_username); Curl_safefree(config->proxy_tls_password); Curl_safefree(config->proxy_tls_authtype); Curl_safefree(config->proxyuserpwd); Curl_safefree(config->proxy); Curl_safefree(config->dns_ipv6_addr); Curl_safefree(config->dns_ipv4_addr); Curl_safefree(config->dns_interface); Curl_safefree(config->dns_servers); Curl_safefree(config->noproxy); Curl_safefree(config->mail_from); curl_slist_free_all(config->mail_rcpt); Curl_safefree(config->mail_auth); Curl_safefree(config->netrc_file); urlnode = config->url_list; while(urlnode) { struct getout *next = urlnode->next; Curl_safefree(urlnode->url); Curl_safefree(urlnode->outfile); Curl_safefree(urlnode->infile); Curl_safefree(urlnode); urlnode = next; } config->url_list = NULL; config->url_last = NULL; config->url_get = NULL; config->url_out = NULL; Curl_safefree(config->doh_url); Curl_safefree(config->cipher_list); Curl_safefree(config->proxy_cipher_list); Curl_safefree(config->cert); Curl_safefree(config->proxy_cert); Curl_safefree(config->cert_type); Curl_safefree(config->proxy_cert_type); Curl_safefree(config->cacert); Curl_safefree(config->proxy_cacert); Curl_safefree(config->capath); Curl_safefree(config->proxy_capath); Curl_safefree(config->crlfile); Curl_safefree(config->pinnedpubkey); Curl_safefree(config->proxy_pinnedpubkey); Curl_safefree(config->proxy_crlfile); Curl_safefree(config->key); Curl_safefree(config->proxy_key); Curl_safefree(config->key_type); Curl_safefree(config->proxy_key_type); Curl_safefree(config->key_passwd); Curl_safefree(config->proxy_key_passwd); Curl_safefree(config->pubkey); Curl_safefree(config->hostpubmd5); Curl_safefree(config->engine); Curl_safefree(config->etag_save_file); Curl_safefree(config->etag_compare_file); Curl_safefree(config->request_target); Curl_safefree(config->customrequest); Curl_safefree(config->krblevel); Curl_safefree(config->oauth_bearer); Curl_safefree(config->sasl_authzid); Curl_safefree(config->unix_socket_path); Curl_safefree(config->writeout); Curl_safefree(config->proto_default); curl_slist_free_all(config->quote); curl_slist_free_all(config->postquote); curl_slist_free_all(config->prequote); curl_slist_free_all(config->headers); curl_slist_free_all(config->proxyheaders); curl_mime_free(config->mimepost); config->mimepost = NULL; tool_mime_free(config->mimeroot); config->mimeroot = NULL; config->mimecurrent = NULL; curl_slist_free_all(config->telnet_options); curl_slist_free_all(config->resolve); curl_slist_free_all(config->connect_to); Curl_safefree(config->preproxy); Curl_safefree(config->proxy_service_name); Curl_safefree(config->service_name); Curl_safefree(config->ftp_account); Curl_safefree(config->ftp_alternative_to_user); } void config_free(struct OperationConfig *config) { struct OperationConfig *last = config; /* Free each of the structures in reverse order */ while(last) { struct OperationConfig *prev = last->prev; free_config_fields(last); free(last); last = prev; } } davix-0.8.0/deps/curl/src/tool_binmode.c0000644000000000000000000000266614121063461016645 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_SETMODE #ifdef HAVE_IO_H # include #endif #ifdef HAVE_FCNTL_H # include #endif #include "tool_binmode.h" #include "memdebug.h" /* keep this as LAST include */ void set_binmode(FILE *stream) { #ifdef O_BINARY # ifdef __HIGHC__ _setmode(stream, O_BINARY); # else (void)setmode(fileno(stream), O_BINARY); # endif #else (void)stream; #endif } #endif /* HAVE_SETMODE */ davix-0.8.0/deps/curl/src/tool_easysrc.h0000644000000000000000000000412614121063461016677 0ustar rootroot#ifndef HEADER_CURL_TOOL_EASYSRC_H #define HEADER_CURL_TOOL_EASYSRC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifndef CURL_DISABLE_LIBCURL_OPTION /* global variable declarations, for easy-interface source code generation */ extern struct slist_wc *easysrc_decl; /* Variable declarations */ extern struct slist_wc *easysrc_data; /* Build slists, forms etc. */ extern struct slist_wc *easysrc_code; /* Setopt calls etc. */ extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */ extern struct slist_wc *easysrc_clean; /* Clean up (reverse order) */ extern int easysrc_mime_count; /* Number of curl_mime variables */ extern int easysrc_slist_count; /* Number of curl_slist variables */ extern CURLcode easysrc_init(void); extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf); extern CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...); extern CURLcode easysrc_perform(void); extern CURLcode easysrc_cleanup(void); void dumpeasysrc(struct GlobalConfig *config); #endif /* CURL_DISABLE_LIBCURL_OPTION */ #endif /* HEADER_CURL_TOOL_EASYSRC_H */ davix-0.8.0/deps/curl/src/tool_progress.c0000644000000000000000000002360414121063461017067 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "tool_operate.h" #include "tool_progress.h" #include "tool_util.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" /* The point of this function would be to return a string of the input data, but never longer than 5 columns (+ one zero byte). Add suffix k, M, G when suitable... */ static char *max5data(curl_off_t bytes, char *max5) { #define ONE_KILOBYTE CURL_OFF_T_C(1024) #define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) #define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) #define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) if(bytes < CURL_OFF_T_C(100000)) msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) /* 'XX.XM' is good as long as we're less than 100 megs */ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); #if (CURL_SIZEOF_CURL_OFF_T > 4) else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) /* 'XXXXM' is good until we're at 10000MB or above */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) /* 10000 MB - 100 GB, we show it as XX.XG */ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) /* up to 10000GB, display without decimal: XXXXG */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) /* up to 10000TB, display without decimal: XXXXT */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); else /* up to 10000PB, display without decimal: XXXXP */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can hold, but our data type is signed so 8192PB will be the maximum. */ #else else msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); #endif return max5; } int xferinfo_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { struct per_transfer *per = clientp; struct OperationConfig *config = per->config; per->dltotal = dltotal; per->dlnow = dlnow; per->ultotal = ultotal; per->ulnow = ulnow; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(per->curl, CURLPAUSE_CONT); } return 0; } /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero byte) */ static void time2str(char *r, curl_off_t seconds) { curl_off_t h; if(seconds <= 0) { strcpy(r, "--:--:--"); return; } h = seconds / CURL_OFF_T_C(3600); if(h <= CURL_OFF_T_C(99)) { curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output format to fit within the limits. */ curl_off_t d = seconds / CURL_OFF_T_C(86400); h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); if(d <= CURL_OFF_T_C(999)) msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } static curl_off_t all_dltotal = 0; static curl_off_t all_ultotal = 0; static curl_off_t all_dlalready = 0; static curl_off_t all_ulalready = 0; curl_off_t all_xfers = 0; /* current total */ struct speedcount { curl_off_t dl; curl_off_t ul; struct timeval stamp; }; #define SPEEDCNT 10 static unsigned int speedindex; static bool indexwrapped; static struct speedcount speedstore[SPEEDCNT]; /* |DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed | 6 -- 9.9G 0 2 2 0 0:00:40 0:00:02 0:00:37 4087M */ bool progress_meter(struct GlobalConfig *global, struct timeval *start, bool final) { static struct timeval stamp; static bool header = FALSE; struct timeval now; long diff; if(global->noprogress) return FALSE; now = tvnow(); diff = tvdiff(now, stamp); if(!header) { header = TRUE; fputs("DL% UL% Dled Uled Xfers Live Qd " "Total Current Left Speed\n", global->errors); } if(final || (diff > 500)) { char time_left[10]; char time_total[10]; char time_spent[10]; char buffer[3][6]; curl_off_t spent = tvdiff(now, *start)/1000; char dlpercen[4]="--"; char ulpercen[4]="--"; struct per_transfer *per; curl_off_t all_dlnow = 0; curl_off_t all_ulnow = 0; bool dlknown = TRUE; bool ulknown = TRUE; curl_off_t all_running = 0; /* in progress */ curl_off_t all_queued = 0; /* pending */ curl_off_t speed = 0; unsigned int i; stamp = now; /* first add the amounts of the already completed transfers */ all_dlnow += all_dlalready; all_ulnow += all_ulalready; for(per = transfers; per; per = per->next) { all_dlnow += per->dlnow; all_ulnow += per->ulnow; if(!per->dltotal) dlknown = FALSE; else if(!per->dltotal_added) { /* only add this amount once */ all_dltotal += per->dltotal; per->dltotal_added = TRUE; } if(!per->ultotal) ulknown = FALSE; else if(!per->ultotal_added) { /* only add this amount once */ all_ultotal += per->ultotal; per->ultotal_added = TRUE; } if(!per->added) all_queued++; else all_running++; } if(dlknown && all_dltotal) /* TODO: handle integer overflow */ msnprintf(dlpercen, sizeof(dlpercen), "%3d", all_dlnow * 100 / all_dltotal); if(ulknown && all_ultotal) /* TODO: handle integer overflow */ msnprintf(ulpercen, sizeof(ulpercen), "%3d", all_ulnow * 100 / all_ultotal); /* get the transfer speed, the higher of the two */ i = speedindex; speedstore[i].dl = all_dlnow; speedstore[i].ul = all_ulnow; speedstore[i].stamp = now; if(++speedindex >= SPEEDCNT) { indexwrapped = TRUE; speedindex = 0; } { long deltams; curl_off_t dl; curl_off_t ul; curl_off_t dls; curl_off_t uls; if(indexwrapped) { /* 'speedindex' is the oldest stored data */ deltams = tvdiff(now, speedstore[speedindex].stamp); dl = all_dlnow - speedstore[speedindex].dl; ul = all_ulnow - speedstore[speedindex].ul; } else { /* since the beginning */ deltams = tvdiff(now, *start); dl = all_dlnow; ul = all_ulnow; } dls = (curl_off_t)((double)dl / ((double)deltams/1000.0)); uls = (curl_off_t)((double)ul / ((double)deltams/1000.0)); speed = dls > uls ? dls : uls; } if(dlknown && speed) { curl_off_t est = all_dltotal / speed; curl_off_t left = (all_dltotal - all_dlnow) / speed; time2str(time_left, left); time2str(time_total, est); } else { time2str(time_left, 0); time2str(time_total, 0); } time2str(time_spent, spent); fprintf(global->errors, "\r" "%-3s " /* percent downloaded */ "%-3s " /* percent uploaded */ "%s " /* Dled */ "%s " /* Uled */ "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ "%5" CURL_FORMAT_CURL_OFF_T " " /* Queued */ "%s " /* Total time */ "%s " /* Current time */ "%s " /* Time left */ "%s " /* Speed */ "%5s" /* final newline */, dlpercen, /* 3 letters */ ulpercen, /* 3 letters */ max5data(all_dlnow, buffer[0]), max5data(all_ulnow, buffer[1]), all_xfers, all_running, all_queued, time_total, time_spent, time_left, max5data(speed, buffer[2]), /* speed */ final ? "\n" :""); return TRUE; } return FALSE; } void progress_finalize(struct per_transfer *per) { /* get the numbers before this transfer goes away */ all_dlalready += per->dlnow; all_ulalready += per->ulnow; } davix-0.8.0/deps/curl/src/tool_convert.c0000644000000000000000000001055214121063461016701 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef CURL_DOES_CONVERSIONS #ifdef HAVE_ICONV # include #endif #include "tool_convert.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef HAVE_ICONV /* curl tool iconv conversion descriptors */ static iconv_t inbound_cd = (iconv_t)-1; static iconv_t outbound_cd = (iconv_t)-1; /* set default codesets for iconv */ #ifndef CURL_ICONV_CODESET_OF_NETWORK # define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" #endif /* * convert_to_network() is a curl tool function to convert * from the host encoding to ASCII on non-ASCII platforms. */ CURLcode convert_to_network(char *buffer, size_t length) { /* translate from the host encoding to the network encoding */ char *input_ptr, *output_ptr; size_t res, in_bytes, out_bytes; /* open an iconv conversion descriptor if necessary */ if(outbound_cd == (iconv_t)-1) { outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST); if(outbound_cd == (iconv_t)-1) { return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; res = iconv(outbound_cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if((res == (size_t)-1) || (in_bytes != 0)) { return CURLE_CONV_FAILED; } return CURLE_OK; } /* * convert_from_network() is a curl tool function * for performing ASCII conversions on non-ASCII platforms. */ CURLcode convert_from_network(char *buffer, size_t length) { /* translate from the network encoding to the host encoding */ char *input_ptr, *output_ptr; size_t res, in_bytes, out_bytes; /* open an iconv conversion descriptor if necessary */ if(inbound_cd == (iconv_t)-1) { inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); if(inbound_cd == (iconv_t)-1) { return CURLE_CONV_FAILED; } } /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; res = iconv(inbound_cd, &input_ptr, &in_bytes, &output_ptr, &out_bytes); if((res == (size_t)-1) || (in_bytes != 0)) { return CURLE_CONV_FAILED; } return CURLE_OK; } void convert_cleanup(void) { /* close iconv conversion descriptors */ if(inbound_cd != (iconv_t)-1) (void)iconv_close(inbound_cd); if(outbound_cd != (iconv_t)-1) (void)iconv_close(outbound_cd); } #endif /* HAVE_ICONV */ char convert_char(curl_infotype infotype, char this_char) { /* determine how this specific character should be displayed */ switch(infotype) { case CURLINFO_DATA_IN: case CURLINFO_DATA_OUT: case CURLINFO_SSL_DATA_IN: case CURLINFO_SSL_DATA_OUT: /* data, treat as ASCII */ if(this_char < 0x20 || this_char >= 0x7f) { /* non-printable ASCII, use a replacement character */ return UNPRINTABLE_CHAR; } /* printable ASCII hex value: convert to host encoding */ (void)convert_from_network(&this_char, 1); /* FALLTHROUGH */ default: /* treat as host encoding */ if(ISPRINT(this_char) && (this_char != '\t') && (this_char != '\r') && (this_char != '\n')) { /* printable characters excluding tabs and line end characters */ return this_char; } break; } /* non-printable, use a replacement character */ return UNPRINTABLE_CHAR; } #endif /* CURL_DOES_CONVERSIONS */ davix-0.8.0/deps/curl/src/tool_progress.h0000644000000000000000000000303414121063461017067 0ustar rootroot#ifndef HEADER_CURL_TOOL_PROGRESS_H #define HEADER_CURL_TOOL_PROGRESS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" int xferinfo_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); bool progress_meter(struct GlobalConfig *global, struct timeval *start, bool final); void progress_finalize(struct per_transfer *per); extern curl_off_t all_xfers; /* total number */ #endif /* HEADER_CURL_TOOL_PROGRESS_H */ davix-0.8.0/deps/curl/src/tool_operate.c0000644000000000000000000024205114121063461016661 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_LOCALE_H # include #endif #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef __VMS # include #endif #ifdef __AMIGA__ # include #endif #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_binmode.h" #include "tool_cfgable.h" #include "tool_cb_dbg.h" #include "tool_cb_hdr.h" #include "tool_cb_prg.h" #include "tool_cb_rea.h" #include "tool_cb_see.h" #include "tool_cb_wrt.h" #include "tool_dirhie.h" #include "tool_doswin.h" #include "tool_easysrc.h" #include "tool_filetime.h" #include "tool_getparam.h" #include "tool_helpers.h" #include "tool_homedir.h" #include "tool_libinfo.h" #include "tool_main.h" #include "tool_metalink.h" #include "tool_msgs.h" #include "tool_operate.h" #include "tool_operhlp.h" #include "tool_paramhlp.h" #include "tool_parsecfg.h" #include "tool_setopt.h" #include "tool_sleep.h" #include "tool_urlglob.h" #include "tool_util.h" #include "tool_writeout.h" #include "tool_xattr.h" #include "tool_vms.h" #include "tool_help.h" #include "tool_hugehelp.h" #include "tool_progress.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef CURLDEBUG /* libcurl's debug builds provide an extra function */ CURLcode curl_easy_perform_ev(CURL *easy); #endif #define CURLseparator "--_curl_--" #ifndef O_BINARY /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in source code but yet it doesn't ruin anything */ # define O_BINARY 0 #endif #define CURL_CA_CERT_ERRORMSG \ "More details here: https://curl.haxx.se/docs/sslcerts.html\n\n" \ "curl failed to verify the legitimacy of the server and therefore " \ "could not\nestablish a secure connection to it. To learn more about " \ "this situation and\nhow to fix it, please visit the web page mentioned " \ "above.\n" static CURLcode single_transfer(struct GlobalConfig *global, struct OperationConfig *config, CURLSH *share, bool capath_from_env, bool *added); static CURLcode create_transfer(struct GlobalConfig *global, CURLSH *share, bool *added); static bool is_fatal_error(CURLcode code) { switch(code) { case CURLE_FAILED_INIT: case CURLE_OUT_OF_MEMORY: case CURLE_UNKNOWN_OPTION: case CURLE_FUNCTION_NOT_FOUND: case CURLE_BAD_FUNCTION_ARGUMENT: /* critical error */ return TRUE; default: break; } /* no error or not critical */ return FALSE; } /* * Check if a given string is a PKCS#11 URI */ static bool is_pkcs11_uri(const char *string) { if(curl_strnequal(string, "pkcs11:", 7)) { return TRUE; } else { return FALSE; } } #ifdef __VMS /* * get_vms_file_size does what it takes to get the real size of the file * * For fixed files, find out the size of the EOF block and adjust. * * For all others, have to read the entire file in, discarding the contents. * Most posted text files will be small, and binary files like zlib archives * and CD/DVD images should be either a STREAM_LF format or a fixed format. * */ static curl_off_t vms_realfilesize(const char *name, const struct_stat *stat_buf) { char buffer[8192]; curl_off_t count; int ret_stat; FILE * file; /* !checksrc! disable FOPENMODE 1 */ file = fopen(name, "r"); /* VMS */ if(file == NULL) { return 0; } count = 0; ret_stat = 1; while(ret_stat > 0) { ret_stat = fread(buffer, 1, sizeof(buffer), file); if(ret_stat != 0) count += ret_stat; } fclose(file); return count; } /* * * VmsSpecialSize checks to see if the stat st_size can be trusted and * if not to call a routine to get the correct size. * */ static curl_off_t VmsSpecialSize(const char *name, const struct_stat *stat_buf) { switch(stat_buf->st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: return vms_realfilesize(name, stat_buf); break; default: return stat_buf->st_size; } } #endif /* __VMS */ #define BUFFER_SIZE (100*1024) struct per_transfer *transfers; /* first node */ static struct per_transfer *transfersl; /* last node */ /* add_per_transfer creates a new 'per_transfer' node in the linked list of transfers */ static CURLcode add_per_transfer(struct per_transfer **per) { struct per_transfer *p; p = calloc(sizeof(struct per_transfer), 1); if(!p) return CURLE_OUT_OF_MEMORY; if(!transfers) /* first entry */ transfersl = transfers = p; else { /* make the last node point to the new node */ transfersl->next = p; /* make the new node point back to the formerly last node */ p->prev = transfersl; /* move the last node pointer to the new entry */ transfersl = p; } *per = p; all_xfers++; /* count total number of transfers added */ return CURLE_OK; } /* Remove the specified transfer from the list (and free it), return the next in line */ static struct per_transfer *del_per_transfer(struct per_transfer *per) { struct per_transfer *n; struct per_transfer *p; DEBUGASSERT(transfers); DEBUGASSERT(transfersl); DEBUGASSERT(per); n = per->next; p = per->prev; if(p) p->next = n; else transfers = n; if(n) n->prev = p; else transfersl = p; free(per); return n; } static CURLcode pre_transfer(struct GlobalConfig *global, struct per_transfer *per) { curl_off_t uploadfilesize = -1; struct_stat fileinfo; CURLcode result = CURLE_OK; if(per->separator_err) fprintf(global->errors, "%s\n", per->separator_err); if(per->separator) printf("%s\n", per->separator); if(per->uploadfile && !stdin_upload(per->uploadfile)) { /* VMS Note: * * Reading binary from files can be a problem... Only FIXED, VAR * etc WITHOUT implied CC will work Others need a \n appended to a * line * * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a * fixed file with implied CC needs to have a byte added for every * record processed, this can by derived from Filesize & recordsize * for VARiable record files the records need to be counted! for * every record add 1 for linefeed and subtract 2 for the record * header for VARIABLE header files only the bare record data needs * to be considered with one appended if implied CC */ #ifdef __VMS /* Calculate the real upload size for VMS */ per->infd = -1; if(stat(per->uploadfile, &fileinfo) == 0) { fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo); switch(fileinfo.st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: per->infd = open(per->uploadfile, O_RDONLY | O_BINARY); break; default: per->infd = open(per->uploadfile, O_RDONLY | O_BINARY, "rfm=stmlf", "ctx=stm"); } } if(per->infd == -1) #else per->infd = open(per->uploadfile, O_RDONLY | O_BINARY); if((per->infd == -1) || fstat(per->infd, &fileinfo)) #endif { helpf(global->errors, "Can't open '%s'!\n", per->uploadfile); if(per->infd != -1) { close(per->infd); per->infd = STDIN_FILENO; } return CURLE_READ_ERROR; } per->infdopen = TRUE; /* we ignore file size for char/block devices, sockets, etc. */ if(S_ISREG(fileinfo.st_mode)) uploadfilesize = fileinfo.st_size; if(uploadfilesize != -1) my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); per->input.fd = per->infd; } return result; } /* * Call this after a transfer has completed. */ static CURLcode post_per_transfer(struct GlobalConfig *global, struct per_transfer *per, CURLcode result, bool *retryp) { struct OutStruct *outs = &per->outs; CURL *curl = per->curl; struct OperationConfig *config = per->config; if(!curl || !config) return result; *retryp = FALSE; if(per->infdopen) close(per->infd); #ifdef __VMS if(is_vms_shell()) { /* VMS DCL shell behavior */ if(!global->showerror) vms_show = VMSSTS_HIDE; } else #endif if(config->synthetic_error) { ; } else if(result && global->showerror) { fprintf(global->errors, "curl: (%d) %s\n", result, (per->errorbuffer[0]) ? per->errorbuffer : curl_easy_strerror(result)); if(result == CURLE_PEER_FAILED_VERIFICATION) fputs(CURL_CA_CERT_ERRORMSG, global->errors); } /* Set file extended attributes */ if(!result && config->xattr && outs->fopened && outs->stream) { int rc = fwrite_xattr(curl, fileno(outs->stream)); if(rc) warnf(config->global, "Error setting extended attributes: %s\n", strerror(errno)); } if(!result && !outs->stream && !outs->bytes) { /* we have received no data despite the transfer was successful ==> force cration of an empty output file (if an output file was specified) */ long cond_unmet = 0L; /* do not create (or even overwrite) the file in case we get no data because of unmet condition */ curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); if(!cond_unmet && !tool_create_output_file(outs, config)) result = CURLE_WRITE_ERROR; } if(!outs->s_isreg && outs->stream) { /* Dump standard stream buffered data */ int rc = fflush(outs->stream); if(!result && rc) { /* something went wrong in the writing process */ result = CURLE_WRITE_ERROR; fprintf(global->errors, "(%d) Failed writing body\n", result); } } #ifdef USE_METALINK if(per->metalink && !per->metalink_next_res) fprintf(global->errors, "Metalink: fetching (%s) from (%s) OK\n", per->mlfile->filename, per->this_url); if(!per->metalink && config->use_metalink && result == CURLE_OK) { int rv = parse_metalink(config, outs, per->this_url); if(!rv) { fprintf(config->global->errors, "Metalink: parsing (%s) OK\n", per->this_url); } else if(rv == -1) fprintf(config->global->errors, "Metalink: parsing (%s) FAILED\n", per->this_url); } else if(per->metalink && result == CURLE_OK && !per->metalink_next_res) { int rv; (void)fflush(outs->stream); rv = metalink_check_hash(global, per->mlfile, outs->filename); if(!rv) per->metalink_next_res = 1; } #endif /* USE_METALINK */ #ifdef USE_METALINK if(outs->metalink_parser) metalink_parser_context_delete(outs->metalink_parser); #endif /* USE_METALINK */ if(outs->is_cd_filename && outs->stream && !global->mute && outs->filename) printf("curl: Saved to filename '%s'\n", outs->filename); /* if retry-max-time is non-zero, make sure we haven't exceeded the time */ if(per->retry_numretries && (!config->retry_maxtime || (tvdiff(tvnow(), per->retrystart) < config->retry_maxtime*1000L)) ) { enum { RETRY_NO, RETRY_TIMEOUT, RETRY_CONNREFUSED, RETRY_HTTP, RETRY_FTP, RETRY_LAST /* not used */ } retry = RETRY_NO; long response; if((CURLE_OPERATION_TIMEDOUT == result) || (CURLE_COULDNT_RESOLVE_HOST == result) || (CURLE_COULDNT_RESOLVE_PROXY == result) || (CURLE_FTP_ACCEPT_TIMEOUT == result)) /* retry timeout always */ retry = RETRY_TIMEOUT; else if(config->retry_connrefused && (CURLE_COULDNT_CONNECT == result)) { long oserrno; curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno); if(ECONNREFUSED == oserrno) retry = RETRY_CONNREFUSED; } else if((CURLE_OK == result) || (config->failonerror && (CURLE_HTTP_RETURNED_ERROR == result))) { /* If it returned OK. _or_ failonerror was enabled and it returned due to such an error, check for HTTP transient errors to retry on. */ long protocol; curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { /* This was HTTP(S) */ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); switch(response) { case 429: /* Too Many Requests (RFC6585) */ case 500: /* Internal Server Error */ case 502: /* Bad Gateway */ case 503: /* Service Unavailable */ case 504: /* Gateway Timeout */ retry = RETRY_HTTP; /* * At this point, we have already written data to the output * file (or terminal). If we write to a file, we must rewind * or close/re-open the file so that the next attempt starts * over from the beginning. * * TODO: similar action for the upload case. We might need * to start over reading from a previous point if we have * uploaded something when this was returned. */ break; } } } /* if CURLE_OK */ else if(result) { long protocol; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) && response / 100 == 4) /* * This is typically when the FTP server only allows a certain * amount of users and we are not one of them. All 4xx codes * are transient. */ retry = RETRY_FTP; } if(retry) { long sleeptime = 0; curl_off_t retry_after = 0; static const char * const m[]={ NULL, "timeout", "connection refused", "HTTP error", "FTP error" }; sleeptime = per->retry_sleep; if(RETRY_HTTP == retry) { curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); if(retry_after) { /* store in a 'long', make sure it doesn't overflow */ if(retry_after > LONG_MAX/1000) sleeptime = LONG_MAX; else sleeptime = (long)retry_after * 1000; /* milliseconds */ } } warnf(config->global, "Transient problem: %s " "Will retry in %ld seconds. " "%ld retries left.\n", m[retry], sleeptime/1000L, per->retry_numretries); per->retry_numretries--; tool_go_sleep(sleeptime); if(!config->retry_delay) { per->retry_sleep *= 2; if(per->retry_sleep > RETRY_SLEEP_MAX) per->retry_sleep = RETRY_SLEEP_MAX; } if(outs->bytes && outs->filename && outs->stream) { int rc; /* We have written data to a output file, we truncate file */ if(!global->mute) fprintf(global->errors, "Throwing away %" CURL_FORMAT_CURL_OFF_T " bytes\n", outs->bytes); fflush(outs->stream); /* truncate file at the position where we started appending */ #ifdef HAVE_FTRUNCATE if(ftruncate(fileno(outs->stream), outs->init)) { /* when truncate fails, we can't just append as then we'll create something strange, bail out */ if(!global->mute) fprintf(global->errors, "failed to truncate, exiting\n"); return CURLE_WRITE_ERROR; } /* now seek to the end of the file, the position where we just truncated the file in a large file-safe way */ rc = fseek(outs->stream, 0, SEEK_END); #else /* ftruncate is not available, so just reposition the file to the location we would have truncated it. This won't work properly with large files on 32-bit systems, but most of those will have ftruncate. */ rc = fseek(outs->stream, (long)outs->init, SEEK_SET); #endif if(rc) { if(!global->mute) fprintf(global->errors, "failed seeking to end of file, exiting\n"); return CURLE_WRITE_ERROR; } outs->bytes = 0; /* clear for next round */ } *retryp = TRUE; /* curl_easy_perform loop */ return CURLE_OK; } } /* if retry_numretries */ else if(per->metalink) { /* Metalink: Decide to try the next resource or not. Try the next resource if download was not successful. */ long response; if(CURLE_OK == result) { /* TODO We want to try next resource when download was not successful. How to know that? */ char *effective_url = NULL; curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url); if(effective_url && curl_strnequal(effective_url, "http", 4)) { /* This was HTTP(S) */ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); if(response != 200 && response != 206) { per->metalink_next_res = 1; fprintf(global->errors, "Metalink: fetching (%s) from (%s) FAILED " "(HTTP status code %ld)\n", per->mlfile->filename, per->this_url, response); } } } else { per->metalink_next_res = 1; fprintf(global->errors, "Metalink: fetching (%s) from (%s) FAILED (%s)\n", per->mlfile->filename, per->this_url, curl_easy_strerror(result)); } } if((global->progressmode == CURL_PROGRESS_BAR) && per->progressbar.calls) /* if the custom progress bar has been displayed, we output a newline here */ fputs("\n", per->progressbar.out); if(config->writeout) ourWriteOut(per->curl, &per->outs, config->writeout); /* Close the outs file */ if(outs->fopened && outs->stream) { int rc = fclose(outs->stream); if(!result && rc) { /* something went wrong in the writing process */ result = CURLE_WRITE_ERROR; fprintf(global->errors, "(%d) Failed writing body\n", result); } } /* File time can only be set _after_ the file has been closed */ if(!result && config->remote_time && outs->s_isreg && outs->filename) { /* Ask libcurl if we got a remote file time */ curl_off_t filetime = -1; curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime); setfiletime(filetime, outs->filename, config->global->errors); } /* Close function-local opened file descriptors */ if(per->heads.fopened && per->heads.stream) fclose(per->heads.stream); if(per->heads.alloc_filename) Curl_safefree(per->heads.filename); if(per->etag_save.fopened && per->etag_save.stream) fclose(per->etag_save.stream); if(per->etag_save.alloc_filename) Curl_safefree(per->etag_save.filename); curl_easy_cleanup(per->curl); if(outs->alloc_filename) free(outs->filename); free(per->this_url); free(per->separator_err); free(per->separator); free(per->outfile); free(per->uploadfile); return CURLE_OK; } static void single_transfer_cleanup(struct OperationConfig *config) { if(config) { struct State *state = &config->state; if(state->urls) { /* Free list of remaining URLs */ glob_cleanup(state->urls); state->urls = NULL; } Curl_safefree(state->outfiles); Curl_safefree(state->httpgetfields); Curl_safefree(state->uploadfile); if(state->inglob) { /* Free list of globbed upload files */ glob_cleanup(state->inglob); state->inglob = NULL; } } } /* create the next (singular) transfer */ static CURLcode single_transfer(struct GlobalConfig *global, struct OperationConfig *config, CURLSH *share, bool capath_from_env, bool *added) { CURLcode result = CURLE_OK; struct getout *urlnode; metalinkfile *mlfile_last = NULL; bool orig_noprogress = global->noprogress; bool orig_isatty = global->isatty; struct State *state = &config->state; char *httpgetfields = state->httpgetfields; *added = FALSE; /* not yet */ if(config->postfields) { if(config->use_httpget) { if(!httpgetfields) { /* Use the postfields data for a http get */ httpgetfields = state->httpgetfields = strdup(config->postfields); Curl_safefree(config->postfields); if(!httpgetfields) { errorf(global, "out of memory\n"); result = CURLE_OUT_OF_MEMORY; } else if(SetHTTPrequest(config, (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), &config->httpreq)) { result = CURLE_FAILED_INIT; } } } else { if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) result = CURLE_FAILED_INIT; } if(result) { single_transfer_cleanup(config); return result; } } if(!state->urlnode) { /* first time caller, setup things */ state->urlnode = config->url_list; state->infilenum = 1; } while(config->state.urlnode) { char *infiles; /* might be a glob pattern */ URLGlob *inglob = state->inglob; bool metalink = FALSE; /* metalink download? */ metalinkfile *mlfile; metalink_resource *mlres; urlnode = config->state.urlnode; if(urlnode->flags & GETOUT_METALINK) { metalink = 1; if(mlfile_last == NULL) { mlfile_last = config->metalinkfile_list; } mlfile = mlfile_last; mlfile_last = mlfile_last->next; mlres = mlfile->resource; } else { mlfile = NULL; mlres = NULL; } /* urlnode->url is the full URL (it might be NULL) */ if(!urlnode->url) { /* This node has no URL. Free node data without destroying the node itself nor modifying next pointer and continue to next */ Curl_safefree(urlnode->outfile); Curl_safefree(urlnode->infile); urlnode->flags = 0; config->state.urlnode = urlnode->next; state->up = 0; continue; /* next URL please */ } /* save outfile pattern before expansion */ if(urlnode->outfile && !state->outfiles) { state->outfiles = strdup(urlnode->outfile); if(!state->outfiles) { errorf(global, "out of memory\n"); result = CURLE_OUT_OF_MEMORY; break; } } infiles = urlnode->infile; if(!config->globoff && infiles && !inglob) { /* Unless explicitly shut off */ result = glob_url(&inglob, infiles, &state->infilenum, global->showerror?global->errors:NULL); if(result) break; config->state.inglob = inglob; } { int separator; unsigned long urlnum; if(!state->up && !infiles) Curl_nop_stmt; else { if(!state->uploadfile) { if(inglob) { result = glob_next_url(&state->uploadfile, inglob); if(result == CURLE_OUT_OF_MEMORY) errorf(global, "out of memory\n"); } else if(!state->up) { state->uploadfile = strdup(infiles); if(!state->uploadfile) { errorf(global, "out of memory\n"); result = CURLE_OUT_OF_MEMORY; } } } if(result) break; } if(!state->urlnum) { if(metalink) { /* For Metalink download, we don't use glob. Instead we use the number of resources as urlnum. */ urlnum = count_next_metalink_resource(mlfile); } else if(!config->globoff) { /* Unless explicitly shut off, we expand '{...}' and '[...]' expressions and return total number of URLs in pattern set */ result = glob_url(&state->urls, urlnode->url, &state->urlnum, global->showerror?global->errors:NULL); if(result) break; urlnum = state->urlnum; } else urlnum = 1; /* without globbing, this is a single URL */ } else urlnum = state->urlnum; /* if multiple files extracted to stdout, insert separators! */ separator = ((!state->outfiles || !strcmp(state->outfiles, "-")) && urlnum > 1); if(state->up < state->infilenum) { struct per_transfer *per; struct OutStruct *outs; struct InStruct *input; struct OutStruct *heads; struct OutStruct *etag_save; struct HdrCbData *hdrcbdata = NULL; CURL *curl = curl_easy_init(); result = add_per_transfer(&per); if(result || !curl) { curl_easy_cleanup(curl); result = CURLE_OUT_OF_MEMORY; break; } if(state->uploadfile) { per->uploadfile = strdup(state->uploadfile); if(!per->uploadfile) { curl_easy_cleanup(curl); result = CURLE_OUT_OF_MEMORY; break; } } *added = TRUE; per->config = config; per->curl = curl; /* default headers output stream is stdout */ heads = &per->heads; heads->stream = stdout; /* Single header file for all URLs */ if(config->headerfile) { /* open file for output: */ if(strcmp(config->headerfile, "-")) { FILE *newfile; newfile = fopen(config->headerfile, per->prev == NULL?"wb":"ab"); if(!newfile) { warnf(config->global, "Failed to open %s\n", config->headerfile); result = CURLE_WRITE_ERROR; break; } else { heads->filename = config->headerfile; heads->s_isreg = TRUE; heads->fopened = TRUE; heads->stream = newfile; } } else { /* always use binary mode for protocol header output */ set_binmode(heads->stream); } } hdrcbdata = &per->hdrcbdata; outs = &per->outs; input = &per->input; per->outfile = NULL; per->infdopen = FALSE; per->infd = STDIN_FILENO; /* default output stream is stdout */ outs->stream = stdout; /* --etag-save */ etag_save = &per->etag_save; etag_save->stream = stdout; if(config->etag_save_file) { /* open file for output: */ if(strcmp(config->etag_save_file, "-")) { FILE *newfile = fopen(config->etag_save_file, "wb"); if(!newfile) { warnf( config->global, "Failed to open %s\n", config->etag_save_file); result = CURLE_WRITE_ERROR; break; } else { etag_save->filename = config->etag_save_file; etag_save->s_isreg = TRUE; etag_save->fopened = TRUE; etag_save->stream = newfile; } } else { /* always use binary mode for protocol header output */ set_binmode(etag_save->stream); } } /* --etag-compare */ if(config->etag_compare_file) { char *etag_from_file = NULL; char *header = NULL; /* open file for reading: */ FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); if(!file) { errorf(config->global, "Failed to open %s\n", config->etag_compare_file); result = CURLE_READ_ERROR; break; } if((PARAM_OK == file2string(&etag_from_file, file)) && etag_from_file) { header = aprintf("If-None-Match: \"%s\"", etag_from_file); Curl_safefree(etag_from_file); } else header = aprintf("If-None-Match: \"\""); if(!header) { if(file) fclose(file); errorf(config->global, "Failed to allocate memory for custom etag header\n"); result = CURLE_OUT_OF_MEMORY; break; } /* add Etag from file to list of custom headers */ add2list(&config->headers, header); Curl_safefree(header); if(file) { fclose(file); } } if(metalink) { /* For Metalink download, use name in Metalink file as filename. */ per->outfile = strdup(mlfile->filename); if(!per->outfile) { result = CURLE_OUT_OF_MEMORY; break; } per->this_url = strdup(mlres->url); if(!per->this_url) { result = CURLE_OUT_OF_MEMORY; break; } per->mlfile = mlfile; } else { if(state->urls) { result = glob_next_url(&per->this_url, state->urls); if(result) break; } else if(!state->li) { per->this_url = strdup(urlnode->url); if(!per->this_url) { result = CURLE_OUT_OF_MEMORY; break; } } else per->this_url = NULL; if(!per->this_url) break; if(state->outfiles) { per->outfile = strdup(state->outfiles); if(!per->outfile) { result = CURLE_OUT_OF_MEMORY; break; } } } if(((urlnode->flags&GETOUT_USEREMOTE) || (per->outfile && strcmp("-", per->outfile))) && (metalink || !config->use_metalink)) { /* * We have specified a file name to store the result in, or we have * decided we want to use the remote file name. */ if(!per->outfile) { /* extract the file name from the URL */ result = get_url_file_name(&per->outfile, per->this_url); if(result) break; if(!*per->outfile && !config->content_disposition) { errorf(global, "Remote file name has no length!\n"); result = CURLE_WRITE_ERROR; break; } } else if(state->urls) { /* fill '#1' ... '#9' terms from URL pattern */ char *storefile = per->outfile; result = glob_match_url(&per->outfile, storefile, state->urls); Curl_safefree(storefile); if(result) { /* bad globbing */ warnf(config->global, "bad output glob!\n"); break; } } /* Create the directory hierarchy, if not pre-existent to a multiple file output call */ if(config->create_dirs || metalink) { result = create_dir_hierarchy(per->outfile, global->errors); /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ if(result) break; } if((urlnode->flags & GETOUT_USEREMOTE) && config->content_disposition) { /* Our header callback MIGHT set the filename */ DEBUGASSERT(!outs->filename); } if(config->resume_from_current) { /* We're told to continue from where we are now. Get the size of the file as it is now and open it for append instead */ struct_stat fileinfo; /* VMS -- Danger, the filesize is only valid for stream files */ if(0 == stat(per->outfile, &fileinfo)) /* set offset to current file size: */ config->resume_from = fileinfo.st_size; else /* let offset be 0 */ config->resume_from = 0; } if(config->resume_from) { #ifdef __VMS /* open file for output, forcing VMS output format into stream mode which is needed for stat() call above to always work. */ FILE *file = fopen(outfile, "ab", "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); #else /* open file for output: */ FILE *file = fopen(per->outfile, "ab"); #endif if(!file) { errorf(global, "Can't open '%s'!\n", per->outfile); result = CURLE_WRITE_ERROR; break; } outs->fopened = TRUE; outs->stream = file; outs->init = config->resume_from; } else { outs->stream = NULL; /* open when needed */ } outs->filename = per->outfile; outs->s_isreg = TRUE; } if(per->uploadfile && !stdin_upload(per->uploadfile)) { /* * We have specified a file to upload and it isn't "-". */ char *nurl = add_file_name_to_url(per->this_url, per->uploadfile); if(!nurl) { result = CURLE_OUT_OF_MEMORY; break; } per->this_url = nurl; } else if(per->uploadfile && stdin_upload(per->uploadfile)) { /* count to see if there are more than one auth bit set in the authtype field */ int authbits = 0; int bitcheck = 0; while(bitcheck < 32) { if(config->authtype & (1UL << bitcheck++)) { authbits++; if(authbits > 1) { /* more than one, we're done! */ break; } } } /* * If the user has also selected --anyauth or --proxy-anyauth * we should warn him/her. */ if(config->proxyanyauth || (authbits>1)) { warnf(config->global, "Using --anyauth or --proxy-anyauth with upload from stdin" " involves a big risk of it not working. Use a temporary" " file or a fixed auth type instead!\n"); } DEBUGASSERT(per->infdopen == FALSE); DEBUGASSERT(per->infd == STDIN_FILENO); set_binmode(stdin); if(!strcmp(per->uploadfile, ".")) { if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0) warnf(config->global, "fcntl failed on fd=%d: %s\n", per->infd, strerror(errno)); } } if(per->uploadfile && config->resume_from_current) config->resume_from = -1; /* -1 will then force get-it-yourself */ if(output_expected(per->this_url, per->uploadfile) && outs->stream && isatty(fileno(outs->stream))) /* we send the output to a tty, therefore we switch off the progress meter */ per->noprogress = global->noprogress = global->isatty = TRUE; else { /* progress meter is per download, so restore config values */ per->noprogress = global->noprogress = orig_noprogress; global->isatty = orig_isatty; } if(urlnum > 1 && !global->mute) { per->separator_err = aprintf("\n[%lu/%lu]: %s --> %s", state->li + 1, urlnum, per->this_url, per->outfile ? per->outfile : ""); if(separator) per->separator = aprintf("%s%s", CURLseparator, per->this_url); } if(httpgetfields) { char *urlbuffer; /* Find out whether the url contains a file name */ const char *pc = strstr(per->this_url, "://"); char sep = '?'; if(pc) pc += 3; else pc = per->this_url; pc = strrchr(pc, '/'); /* check for a slash */ if(pc) { /* there is a slash present in the URL */ if(strchr(pc, '?')) /* Ouch, there's already a question mark in the URL string, we then append the data with an ampersand separator instead! */ sep = '&'; } /* * Then append ? followed by the get fields to the url. */ if(pc) urlbuffer = aprintf("%s%c%s", per->this_url, sep, httpgetfields); else /* Append / before the ? to create a well-formed url if the url contains a hostname only */ urlbuffer = aprintf("%s/?%s", per->this_url, httpgetfields); if(!urlbuffer) { result = CURLE_OUT_OF_MEMORY; break; } Curl_safefree(per->this_url); /* free previous URL */ per->this_url = urlbuffer; /* use our new URL instead! */ } if(!global->errors) global->errors = stderr; if((!per->outfile || !strcmp(per->outfile, "-")) && !config->use_ascii) { /* We get the output to stdout and we have not got the ASCII/text flag, then set stdout to be binary */ set_binmode(stdout); } /* explicitly passed to stdout means okaying binary gunk */ config->terminal_binary_ok = (per->outfile && !strcmp(per->outfile, "-")); /* Avoid having this setopt added to the --libcurl source output. */ result = curl_easy_setopt(curl, CURLOPT_SHARE, share); if(result) break; if(!config->tcp_nodelay) my_setopt(curl, CURLOPT_TCP_NODELAY, 0L); if(config->tcp_fastopen) my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L); /* where to store */ my_setopt(curl, CURLOPT_WRITEDATA, per); my_setopt(curl, CURLOPT_INTERLEAVEDATA, per); if(metalink || !config->use_metalink) /* what call to write */ my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); #ifdef USE_METALINK else /* Set Metalink specific write callback function to parse XML data progressively. */ my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb); #endif /* USE_METALINK */ /* for uploads */ input->config = config; /* Note that if CURLOPT_READFUNCTION is fread (the default), then * lib/telnet.c will Curl_poll() on the input file descriptor * rather then calling the READFUNCTION at regular intervals. * The circumstances in which it is preferable to enable this * behaviour, by omitting to set the READFUNCTION & READDATA options, * have not been determined. */ my_setopt(curl, CURLOPT_READDATA, input); /* what call to read */ my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb); /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ my_setopt(curl, CURLOPT_SEEKDATA, input); my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb); if(config->recvpersecond && (config->recvpersecond < BUFFER_SIZE)) /* use a smaller sized buffer for better sleeps */ my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond); else my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE); my_setopt_str(curl, CURLOPT_URL, per->this_url); my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L); if(config->no_body) my_setopt(curl, CURLOPT_NOBODY, 1L); if(config->oauth_bearer) my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer); { my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* new in libcurl 7.5 */ if(config->proxy) my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver); my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); /* new in libcurl 7.3 */ my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L); /* new in libcurl 7.52.0 */ if(config->preproxy) my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy); /* new in libcurl 7.10.6 */ if(config->proxyanyauth) my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); else if(config->proxynegotiate) my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_GSSNEGOTIATE); else if(config->proxyntlm) my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_NTLM); else if(config->proxydigest) my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_DIGEST); else if(config->proxybasic) my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_BASIC); /* new in libcurl 7.19.4 */ my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy); my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS, config->suppress_connect_headers?1L:0L); } my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L); my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target); my_setopt(curl, CURLOPT_UPLOAD, per->uploadfile?1L:0L); my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L); my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L); if(config->netrc_opt) my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL); else if(config->netrc || config->netrc_file) my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED); else my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED); if(config->netrc_file) my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file); my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L); if(config->login_options) my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options); my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); my_setopt_str(curl, CURLOPT_RANGE, config->range); my_setopt(curl, CURLOPT_ERRORBUFFER, per->errorbuffer); my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000)); switch(config->httpreq) { case HTTPREQ_SIMPLEPOST: my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields); my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize); break; case HTTPREQ_MIMEPOST: /* free previous remainders */ curl_mime_free(config->mimepost); config->mimepost = NULL; result = tool2curlmime(curl, config->mimeroot, &config->mimepost); if(result) break; my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost); break; default: break; } if(result) break; /* new in libcurl 7.10.6 (default is Basic) */ if(config->authtype) my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype); my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) { my_setopt_str(curl, CURLOPT_REFERER, config->referer); my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); } if(built_in_protos & CURLPROTO_HTTP) { long postRedir = 0; my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation?1L:0L); my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth?1L:0L); my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L); /* new in libcurl 7.36.0 */ if(config->proxyheaders) { my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders); my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE); } /* new in libcurl 7.5 */ my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); if(config->httpversion) my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion); else if(curlinfo->features & CURL_VERSION_HTTP2) { my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); } /* curl 7.19.1 (the 301 version existed in 7.18.2), 303 was added in 7.26.0 */ if(config->post301) postRedir |= CURL_REDIR_POST_301; if(config->post302) postRedir |= CURL_REDIR_POST_302; if(config->post303) postRedir |= CURL_REDIR_POST_303; my_setopt(curl, CURLOPT_POSTREDIR, postRedir); /* new in libcurl 7.21.6 */ if(config->encoding) my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); /* new in libcurl 7.21.6 */ if(config->tr_encoding) my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L); /* new in libcurl 7.64.0 */ my_setopt(curl, CURLOPT_HTTP09_ALLOWED, config->http09_allowed ? 1L : 0L); } /* (built_in_protos & CURLPROTO_HTTP) */ my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit); my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, config->sendpersecond); my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, config->recvpersecond); if(config->use_resume) my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from); else my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0)); my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd); if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { /* SSH and SSL private key uses same command-line option */ /* new in libcurl 7.16.1 */ my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); /* new in libcurl 7.16.1 */ my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); /* new in libcurl 7.17.1: SSH host key md5 checking allows us to fail if we are not talking to who we think we should */ my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, config->hostpubmd5); /* new in libcurl 7.56.0 */ if(config->ssh_compression) my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L); } if(config->cacert) my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); if(config->proxy_cacert) my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert); if(config->capath) { result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath); if(result == CURLE_NOT_BUILT_IN) { warnf(config->global, "ignoring %s, not supported by libcurl\n", capath_from_env? "SSL_CERT_DIR environment variable":"--capath"); } else if(result) break; } /* For the time being if --proxy-capath is not set then we use the --capath value for it, if any. See #1257 */ if((config->proxy_capath || config->capath) && !tool_setopt_skip(CURLOPT_PROXY_CAPATH)) { result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH, (config->proxy_capath ? config->proxy_capath : config->capath)); if(result == CURLE_NOT_BUILT_IN) { if(config->proxy_capath) { warnf(config->global, "ignoring --proxy-capath, not supported by libcurl\n"); } } else if(result) break; } if(config->crlfile) my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); if(config->proxy_crlfile) my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile); else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */ my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile); if(config->pinnedpubkey) my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey); if(curlinfo->features & CURL_VERSION_SSL) { /* Check if config->cert is a PKCS#11 URI and set the * config->cert_type if necessary */ if(config->cert) { if(!config->cert_type) { if(is_pkcs11_uri(config->cert)) { config->cert_type = strdup("ENG"); } } } /* Check if config->key is a PKCS#11 URI and set the * config->key_type if necessary */ if(config->key) { if(!config->key_type) { if(is_pkcs11_uri(config->key)) { config->key_type = strdup("ENG"); } } } /* Check if config->proxy_cert is a PKCS#11 URI and set the * config->proxy_type if necessary */ if(config->proxy_cert) { if(!config->proxy_cert_type) { if(is_pkcs11_uri(config->proxy_cert)) { config->proxy_cert_type = strdup("ENG"); } } } /* Check if config->proxy_key is a PKCS#11 URI and set the * config->proxy_key_type if necessary */ if(config->proxy_key) { if(!config->proxy_key_type) { if(is_pkcs11_uri(config->proxy_key)) { config->proxy_key_type = strdup("ENG"); } } } my_setopt_str(curl, CURLOPT_SSLCERT, config->cert); my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert); my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE, config->proxy_cert_type); my_setopt_str(curl, CURLOPT_SSLKEY, config->key); my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key); my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE, config->proxy_key_type); if(config->insecure_ok) { my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } else { my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); /* libcurl default is strict verifyhost -> 2L */ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ } if(config->proxy_insecure_ok) { my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L); my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L); } else { my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L); } if(config->verifystatus) my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); if(config->falsestart) my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version | config->ssl_version_max); my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION, config->proxy_ssl_version); } if(config->path_as_is) my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { if(!config->insecure_ok) { char *home; char *file; result = CURLE_FAILED_INIT; home = homedir(); if(home) { file = aprintf("%s/.ssh/known_hosts", home); if(file) { /* new in curl 7.19.6 */ result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file); curl_free(file); if(result == CURLE_UNKNOWN_OPTION) /* libssh2 version older than 1.1.1 */ result = CURLE_OK; } Curl_safefree(home); } else { errorf(global, "Failed to figure out user's home dir!"); } if(result) break; } } if(config->no_body || config->remote_time) { /* no body or use remote time */ my_setopt(curl, CURLOPT_FILETIME, 1L); } my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L); my_setopt_slist(curl, CURLOPT_QUOTE, config->quote); my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote); my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote); if(config->cookie) my_setopt_str(curl, CURLOPT_COOKIE, config->cookie); if(config->cookiefile) my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile); /* new in libcurl 7.9 */ if(config->cookiejar) my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); /* new in libcurl 7.9.7 */ my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L); my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond); my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime); my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); customrequest_helper(config, config->httpreq, config->customrequest); my_setopt(curl, CURLOPT_STDERR, global->errors); /* three new ones in libcurl 7.3: */ my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); progressbarinit(&per->progressbar, config); if((global->progressmode == CURL_PROGRESS_BAR) && !global->noprogress && !global->mute) { /* we want the alternative style, then we have to implement it ourselves! */ my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb); my_setopt(curl, CURLOPT_XFERINFODATA, per); } else if(per->uploadfile && !strcmp(per->uploadfile, ".")) { /* when reading from stdin in non-blocking mode, we use the progress function to unpause a busy read */ my_setopt(curl, CURLOPT_NOPROGRESS, 0L); my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb); my_setopt(curl, CURLOPT_XFERINFODATA, per); } /* new in libcurl 7.24.0: */ if(config->dns_servers) my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers); /* new in libcurl 7.33.0: */ if(config->dns_interface) my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface); if(config->dns_ipv4_addr) my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr); if(config->dns_ipv6_addr) my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr); /* new in libcurl 7.6.2: */ my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); /* new in libcurl 7.7: */ my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file); my_setopt_str(curl, CURLOPT_EGDSOCKET, config->egd_file); my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, (long)(config->connecttimeout * 1000)); if(config->doh_url) my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url); if(config->cipher_list) my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); if(config->proxy_cipher_list) my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, config->proxy_cipher_list); if(config->cipher13_list) my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list); if(config->proxy_cipher13_list) my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, config->proxy_cipher13_list); /* new in libcurl 7.9.2: */ if(config->disable_epsv) /* disable it */ my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); /* new in libcurl 7.10.5 */ if(config->disable_eprt) /* disable it */ my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L); if(global->tracetype != TRACE_NONE) { my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb); my_setopt(curl, CURLOPT_DEBUGDATA, config); my_setopt(curl, CURLOPT_VERBOSE, 1L); } /* new in curl 7.9.3 */ if(config->engine) { result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); if(result) break; } /* new in curl 7.10.7, extended in 7.19.4. Modified to use CREATE_DIR_RETRY in 7.49.0 */ my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, (long)(config->ftp_create_dirs? CURLFTP_CREATE_DIR_RETRY: CURLFTP_CREATE_DIR_NONE)); /* new in curl 7.10.8 */ if(config->max_filesize) my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, config->max_filesize); if(4 == config->ip_version) my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); else if(6 == config->ip_version) my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); else my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); /* new in curl 7.15.5 */ if(config->ftp_ssl_reqd) my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); /* new in curl 7.11.0 */ else if(config->ftp_ssl) my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); /* new in curl 7.16.0 */ else if(config->ftp_ssl_control) my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL); /* new in curl 7.16.1 */ if(config->ftp_ssl_ccc) my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, (long)config->ftp_ssl_ccc_mode); /* new in curl 7.19.4 */ if(config->socks5_gssapi_nec) my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, config->socks5_gssapi_nec); /* new in curl 7.55.0 */ if(config->socks5_auth) my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH, (long)config->socks5_auth); /* new in curl 7.43.0 */ if(config->proxy_service_name) my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME, config->proxy_service_name); /* new in curl 7.43.0 */ if(config->service_name) my_setopt_str(curl, CURLOPT_SERVICE_NAME, config->service_name); /* curl 7.13.0 */ my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L); /* curl 7.14.2 */ my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L); /* curl 7.15.1 */ my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod); /* curl 7.15.2 */ if(config->localport) { my_setopt(curl, CURLOPT_LOCALPORT, config->localport); my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, config->localportrange); } /* curl 7.15.5 */ my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, config->ftp_alternative_to_user); /* curl 7.16.0 */ if(config->disable_sessionid) /* disable it */ my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); /* curl 7.16.2 */ if(config->raw) { my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L); my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L); } /* curl 7.17.1 */ if(!config->nokeepalive) { my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); if(config->alivetime != 0) { my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime); my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime); } } else my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L); /* curl 7.20.0 */ if(config->tftp_blksize) my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); if(config->mail_from) my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); if(config->mail_rcpt) my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); /* curl 7.69.x */ my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS, config->mail_rcpt_allowfails ? 1L : 0L); /* curl 7.20.x */ if(config->ftp_pret) my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L); if(config->proto_present) my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto); if(config->proto_redir_present) my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); if(config->content_disposition && (urlnode->flags & GETOUT_USEREMOTE)) hdrcbdata->honor_cd_filename = TRUE; else hdrcbdata->honor_cd_filename = FALSE; hdrcbdata->outs = outs; hdrcbdata->heads = heads; hdrcbdata->etag_save = etag_save; hdrcbdata->global = global; hdrcbdata->config = config; my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb); my_setopt(curl, CURLOPT_HEADERDATA, per); if(config->resolve) /* new in 7.21.3 */ my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve); if(config->connect_to) /* new in 7.49.0 */ my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to); /* new in 7.21.4 */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { if(config->tls_username) my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username); if(config->tls_password) my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password); if(config->tls_authtype) my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, config->tls_authtype); if(config->proxy_tls_username) my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, config->proxy_tls_username); if(config->proxy_tls_password) my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, config->proxy_tls_password); if(config->proxy_tls_authtype) my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE, config->proxy_tls_authtype); } /* new in 7.22.0 */ if(config->gssapi_delegation) my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION, config->gssapi_delegation); /* new in 7.25.0 and 7.44.0 */ { long mask = (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) | (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0); if(mask) my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask); } if(config->proxy_ssl_allow_beast) my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST); if(config->mail_auth) my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); /* new in 7.66.0 */ if(config->sasl_authzid) my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid); /* new in 7.31.0 */ if(config->sasl_ir) my_setopt(curl, CURLOPT_SASL_IR, 1L); if(config->nonpn) { my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L); } if(config->noalpn) { my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } /* new in 7.40.0, abstract support added in 7.53.0 */ if(config->unix_socket_path) { if(config->abstract_unix_socket) { my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, config->unix_socket_path); } else { my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH, config->unix_socket_path); } } /* new in 7.45.0 */ if(config->proto_default) my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default); /* new in 7.47.0 */ if(config->expect100timeout > 0) my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, (long)(config->expect100timeout*1000)); /* new in 7.48.0 */ if(config->tftp_no_options) my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L); /* new in 7.59.0 */ if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT) my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, config->happy_eyeballs_timeout_ms); /* new in 7.60.0 */ if(config->haproxy_protocol) my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L); if(config->disallow_username_in_url) my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); if(config->altsvc) my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc); #ifdef USE_METALINK if(!metalink && config->use_metalink) { outs->metalink_parser = metalink_parser_context_new(); if(outs->metalink_parser == NULL) { result = CURLE_OUT_OF_MEMORY; break; } fprintf(config->global->errors, "Metalink: parsing (%s) metalink/XML...\n", per->this_url); } else if(metalink) fprintf(config->global->errors, "Metalink: fetching (%s) from (%s)...\n", mlfile->filename, per->this_url); #endif /* USE_METALINK */ per->metalink = metalink; /* initialize retry vars for loop below */ per->retry_sleep_default = (config->retry_delay) ? config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ per->retry_numretries = config->req_retry; per->retry_sleep = per->retry_sleep_default; /* ms */ per->retrystart = tvnow(); state->li++; /* Here's looping around each globbed URL */ if(state->li >= urlnum) { state->li = 0; state->urlnum = 0; /* forced reglob of URLs */ glob_cleanup(state->urls); state->urls = NULL; state->up++; Curl_safefree(state->uploadfile); /* clear it to get the next */ } } else { /* Free this URL node data without destroying the the node itself nor modifying next pointer. */ Curl_safefree(urlnode->outfile); Curl_safefree(urlnode->infile); urlnode->flags = 0; glob_cleanup(state->urls); state->urls = NULL; state->urlnum = 0; Curl_safefree(state->outfiles); Curl_safefree(state->uploadfile); if(state->inglob) { /* Free list of globbed upload files */ glob_cleanup(state->inglob); state->inglob = NULL; } config->state.urlnode = urlnode->next; state->up = 0; continue; } } break; } if(!*added || result) { *added = FALSE; single_transfer_cleanup(config); } return result; } static long all_added; /* number of easy handles currently added */ /* * add_parallel_transfers() sets 'morep' to TRUE if there are more transfers * to add even after this call returns. sets 'addedp' to TRUE if one or more * transfers were added. */ static CURLcode add_parallel_transfers(struct GlobalConfig *global, CURLM *multi, CURLSH *share, bool *morep, bool *addedp) { struct per_transfer *per; CURLcode result = CURLE_OK; CURLMcode mcode; *addedp = FALSE; *morep = FALSE; result = create_transfer(global, share, addedp); if(result || !*addedp) return result; for(per = transfers; per && (all_added < global->parallel_max); per = per->next) { bool getadded = FALSE; if(per->added) /* already added */ continue; result = pre_transfer(global, per); if(result) break; /* parallel connect means that we don't set PIPEWAIT since pipewait will make libcurl prefer multiplexing */ (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT, global->parallel_connect ? 0L : 1L); (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per); (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb); (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per); mcode = curl_multi_add_handle(multi, per->curl); if(mcode) return CURLE_OUT_OF_MEMORY; result = create_transfer(global, share, &getadded); if(result) return result; per->added = TRUE; all_added++; *addedp = TRUE; } *morep = per ? TRUE : FALSE; return CURLE_OK; } static CURLcode parallel_transfers(struct GlobalConfig *global, CURLSH *share) { CURLM *multi; CURLMcode mcode = CURLM_OK; CURLcode result = CURLE_OK; int still_running = 1; struct timeval start = tvnow(); bool more_transfers; bool added_transfers; multi = curl_multi_init(); if(!multi) return CURLE_OUT_OF_MEMORY; result = add_parallel_transfers(global, multi, share, &more_transfers, &added_transfers); if(result) { curl_multi_cleanup(multi); return result; } while(!mcode && (still_running || more_transfers)) { mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL); if(!mcode) mcode = curl_multi_perform(multi, &still_running); progress_meter(global, &start, FALSE); if(!mcode) { int rc; CURLMsg *msg; bool removed = FALSE; do { msg = curl_multi_info_read(multi, &rc); if(msg) { bool retry; struct per_transfer *ended; CURL *easy = msg->easy_handle; result = msg->data.result; curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended); curl_multi_remove_handle(multi, easy); result = post_per_transfer(global, ended, result, &retry); if(retry) continue; progress_finalize(ended); /* before it goes away */ all_added--; /* one fewer added */ removed = TRUE; (void)del_per_transfer(ended); } } while(msg); if(removed) { /* one or more transfers completed, add more! */ (void)add_parallel_transfers(global, multi, share, &more_transfers, &added_transfers); if(added_transfers) /* we added new ones, make sure the loop doesn't exit yet */ still_running = 1; } } } (void)progress_meter(global, &start, TRUE); /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : /* The other multi errors should never happen, so return something suitably generic */ CURLE_BAD_FUNCTION_ARGUMENT; } curl_multi_cleanup(multi); return result; } static CURLcode serial_transfers(struct GlobalConfig *global, CURLSH *share) { CURLcode returncode = CURLE_OK; CURLcode result = CURLE_OK; struct per_transfer *per; bool added = FALSE; result = create_transfer(global, share, &added); if(result || !added) return result; for(per = transfers; per;) { bool retry; bool bailout = FALSE; result = pre_transfer(global, per); if(result) break; #ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { result = easysrc_perform(); if(result) break; } #endif #ifdef CURLDEBUG if(global->test_event_based) result = curl_easy_perform_ev(per->curl); else #endif result = curl_easy_perform(per->curl); /* store the result of the actual transfer */ returncode = result; result = post_per_transfer(global, per, result, &retry); if(retry) continue; /* Bail out upon critical errors or --fail-early */ if(result || is_fatal_error(returncode) || (returncode && global->fail_early)) bailout = TRUE; else { /* setup the next one just before we delete this */ result = create_transfer(global, share, &added); if(result) bailout = TRUE; } /* Release metalink related resources here */ delete_metalinkfile(per->mlfile); per = del_per_transfer(per); if(bailout) break; } if(returncode) /* returncode errors have priority */ result = returncode; if(result) single_transfer_cleanup(global->current); return result; } /* setup a transfer for the given config */ static CURLcode transfer_per_config(struct GlobalConfig *global, struct OperationConfig *config, CURLSH *share, bool *added) { CURLcode result = CURLE_OK; bool capath_from_env; *added = FALSE; /* Check we have a url */ if(!config->url_list || !config->url_list->url) { helpf(global->errors, "no URL specified!\n"); return CURLE_FAILED_INIT; } /* On WIN32 we can't set the path to curl-ca-bundle.crt * at compile time. So we look here for the file in two ways: * 1: look at the environment variable CURL_CA_BUNDLE for a path * 2: if #1 isn't found, use the windows API function SearchPath() * to find it along the app's path (includes app's dir and CWD) * * We support the environment variable thing for non-Windows platforms * too. Just for the sake of it. */ capath_from_env = false; if(!config->cacert && !config->capath && !config->insecure_ok) { CURL *curltls = curl_easy_init(); struct curl_tlssessioninfo *tls_backend_info = NULL; /* With the addition of CAINFO support for Schannel, this search could find * a certificate bundle that was previously ignored. To maintain backward * compatibility, only perform this search if not using Schannel. */ result = curl_easy_getinfo(curltls, CURLINFO_TLS_SSL_PTR, &tls_backend_info); if(result) return result; /* Set the CA cert locations specified in the environment. For Windows if * no environment-specified filename is found then check for CA bundle * default filename curl-ca-bundle.crt in the user's PATH. * * If Schannel is the selected SSL backend then these locations are * ignored. We allow setting CA location for schannel only when explicitly * specified by the user via CURLOPT_CAINFO / --cacert. */ if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) { char *env; env = curlx_getenv("CURL_CA_BUNDLE"); if(env) { config->cacert = strdup(env); if(!config->cacert) { curl_free(env); errorf(global, "out of memory\n"); return CURLE_OUT_OF_MEMORY; } } else { env = curlx_getenv("SSL_CERT_DIR"); if(env) { config->capath = strdup(env); if(!config->capath) { curl_free(env); helpf(global->errors, "out of memory\n"); return CURLE_OUT_OF_MEMORY; } capath_from_env = true; } else { env = curlx_getenv("SSL_CERT_FILE"); if(env) { config->cacert = strdup(env); if(!config->cacert) { curl_free(env); errorf(global, "out of memory\n"); return CURLE_OUT_OF_MEMORY; } } } } if(env) curl_free(env); #ifdef WIN32 else { result = FindWin32CACert(config, tls_backend_info->backend, "curl-ca-bundle.crt"); } #endif } curl_easy_cleanup(curltls); } if(!result) result = single_transfer(global, config, share, capath_from_env, added); return result; } /* * 'create_transfer' gets the details and sets up a new transfer if 'added' * returns TRUE. */ static CURLcode create_transfer(struct GlobalConfig *global, CURLSH *share, bool *added) { CURLcode result = CURLE_OK; *added = FALSE; while(global->current) { result = transfer_per_config(global, global->current, share, added); if(!result && !*added) { /* when one set is drained, continue to next */ global->current = global->current->next; continue; } break; } return result; } static CURLcode run_all_transfers(struct GlobalConfig *global, CURLSH *share, CURLcode result) { /* Save the values of noprogress and isatty to restore them later on */ bool orig_noprogress = global->noprogress; bool orig_isatty = global->isatty; struct per_transfer *per; /* Time to actually do the transfers */ if(!result) { if(global->parallel) result = parallel_transfers(global, share); else result = serial_transfers(global, share); } /* cleanup if there are any left */ for(per = transfers; per;) { bool retry; CURLcode result2 = post_per_transfer(global, per, result, &retry); if(!result) /* don't overwrite the original error */ result = result2; /* Free list of given URLs */ clean_getout(per->config); /* Release metalink related resources here */ clean_metalink(per->config); per = del_per_transfer(per); } /* Reset the global config variables */ global->noprogress = orig_noprogress; global->isatty = orig_isatty; return result; } CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) { CURLcode result = CURLE_OK; /* Setup proper locale from environment */ #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); #endif /* Parse .curlrc if necessary */ if((argc == 1) || (!curl_strequal(argv[1], "-q") && !curl_strequal(argv[1], "--disable"))) { parseconfig(NULL, global); /* ignore possible failure */ /* If we had no arguments then make sure a url was specified in .curlrc */ if((argc < 2) && (!global->first->url_list)) { helpf(global->errors, NULL); result = CURLE_FAILED_INIT; } } if(!result) { /* Parse the command line arguments */ ParameterError res = parse_args(global, argc, argv); if(res) { result = CURLE_OK; /* Check if we were asked for the help */ if(res == PARAM_HELP_REQUESTED) tool_help(); /* Check if we were asked for the manual */ else if(res == PARAM_MANUAL_REQUESTED) hugehelp(); /* Check if we were asked for the version information */ else if(res == PARAM_VERSION_INFO_REQUESTED) tool_version_info(); /* Check if we were asked to list the SSL engines */ else if(res == PARAM_ENGINES_REQUESTED) tool_list_engines(); else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL) result = CURLE_UNSUPPORTED_PROTOCOL; else result = CURLE_FAILED_INIT; } else { #ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Initialise the libcurl source output */ result = easysrc_init(); } #endif /* Perform the main operations */ if(!result) { size_t count = 0; struct OperationConfig *operation = global->first; CURLSH *share = curl_share_init(); if(!share) { #ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Cleanup the libcurl source output */ easysrc_cleanup(); } #endif return CURLE_OUT_OF_MEMORY; } curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL); /* Get the required arguments for each operation */ do { result = get_args(operation, count++); operation = operation->next; } while(!result && operation); /* Set the current operation pointer */ global->current = global->first; /* now run! */ result = run_all_transfers(global, share, result); curl_share_cleanup(share); #ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Cleanup the libcurl source output */ easysrc_cleanup(); /* Dump the libcurl code if previously enabled */ dumpeasysrc(global); } #endif } else errorf(global, "out of memory\n"); } } return result; } davix-0.8.0/deps/curl/src/tool_getparam.c0000644000000000000000000022447214121063461017031 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #include "strcase.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_binmode.h" #include "tool_cfgable.h" #include "tool_cb_prg.h" #include "tool_convert.h" #include "tool_filetime.h" #include "tool_formparse.h" #include "tool_getparam.h" #include "tool_helpers.h" #include "tool_libinfo.h" #include "tool_metalink.h" #include "tool_msgs.h" #include "tool_paramhlp.h" #include "tool_parsecfg.h" #include "tool_main.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef MSDOS # define USE_WATT32 #endif #define GetStr(str,val) do { \ if(*(str)) { \ free(*(str)); \ *(str) = NULL; \ } \ if((val)) { \ *(str) = strdup((val)); \ if(!(*(str))) \ return PARAM_NO_MEM; \ } \ } while(0) struct LongShort { const char *letter; /* short name option */ const char *lname; /* long name option */ enum { ARG_NONE, /* stand-alone but not a boolean */ ARG_BOOL, /* accepts a --no-[name] prefix */ ARG_STRING, /* requires an argument */ ARG_FILENAME /* requires an argument, usually a file name */ } desc; }; static const struct LongShort aliases[]= { /* 'letter' strings with more than one character have *no* short option to mention. */ {"*@", "url", ARG_STRING}, {"*4", "dns-ipv4-addr", ARG_STRING}, {"*6", "dns-ipv6-addr", ARG_STRING}, {"*a", "random-file", ARG_FILENAME}, {"*b", "egd-file", ARG_STRING}, {"*B", "oauth2-bearer", ARG_STRING}, {"*c", "connect-timeout", ARG_STRING}, {"*C", "doh-url" , ARG_STRING}, {"*d", "ciphers", ARG_STRING}, {"*D", "dns-interface", ARG_STRING}, {"*e", "disable-epsv", ARG_BOOL}, {"*f", "disallow-username-in-url", ARG_BOOL}, {"*E", "epsv", ARG_BOOL}, /* 'epsv' made like this to make --no-epsv and --epsv to work although --disable-epsv is the documented option */ {"*F", "dns-servers", ARG_STRING}, {"*g", "trace", ARG_FILENAME}, {"*G", "npn", ARG_BOOL}, {"*h", "trace-ascii", ARG_FILENAME}, {"*H", "alpn", ARG_BOOL}, {"*i", "limit-rate", ARG_STRING}, {"*j", "compressed", ARG_BOOL}, {"*J", "tr-encoding", ARG_BOOL}, {"*k", "digest", ARG_BOOL}, {"*l", "negotiate", ARG_BOOL}, {"*m", "ntlm", ARG_BOOL}, {"*M", "ntlm-wb", ARG_BOOL}, {"*n", "basic", ARG_BOOL}, {"*o", "anyauth", ARG_BOOL}, #ifdef USE_WATT32 {"*p", "wdebug", ARG_BOOL}, #endif {"*q", "ftp-create-dirs", ARG_BOOL}, {"*r", "create-dirs", ARG_BOOL}, {"*s", "max-redirs", ARG_STRING}, {"*t", "proxy-ntlm", ARG_BOOL}, {"*u", "crlf", ARG_BOOL}, {"*v", "stderr", ARG_FILENAME}, {"*w", "interface", ARG_STRING}, {"*x", "krb", ARG_STRING}, {"*x", "krb4", ARG_STRING}, /* 'krb4' is the previous name */ {"*X", "haproxy-protocol", ARG_BOOL}, {"*y", "max-filesize", ARG_STRING}, {"*z", "disable-eprt", ARG_BOOL}, {"*Z", "eprt", ARG_BOOL}, /* 'eprt' made like this to make --no-eprt and --eprt to work although --disable-eprt is the documented option */ {"*~", "xattr", ARG_BOOL}, {"$a", "ftp-ssl", ARG_BOOL}, /* 'ftp-ssl' deprecated name since 7.20.0 */ {"$a", "ssl", ARG_BOOL}, /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */ {"$b", "ftp-pasv", ARG_BOOL}, {"$c", "socks5", ARG_STRING}, {"$d", "tcp-nodelay", ARG_BOOL}, {"$e", "proxy-digest", ARG_BOOL}, {"$f", "proxy-basic", ARG_BOOL}, {"$g", "retry", ARG_STRING}, {"$V", "retry-connrefused", ARG_BOOL}, {"$h", "retry-delay", ARG_STRING}, {"$i", "retry-max-time", ARG_STRING}, {"$k", "proxy-negotiate", ARG_BOOL}, {"$m", "ftp-account", ARG_STRING}, {"$n", "proxy-anyauth", ARG_BOOL}, {"$o", "trace-time", ARG_BOOL}, {"$p", "ignore-content-length", ARG_BOOL}, {"$q", "ftp-skip-pasv-ip", ARG_BOOL}, {"$r", "ftp-method", ARG_STRING}, {"$s", "local-port", ARG_STRING}, {"$t", "socks4", ARG_STRING}, {"$T", "socks4a", ARG_STRING}, {"$u", "ftp-alternative-to-user", ARG_STRING}, {"$v", "ftp-ssl-reqd", ARG_BOOL}, /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */ {"$v", "ssl-reqd", ARG_BOOL}, /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */ {"$w", "sessionid", ARG_BOOL}, /* 'sessionid' listed as --no-sessionid in the help */ {"$x", "ftp-ssl-control", ARG_BOOL}, {"$y", "ftp-ssl-ccc", ARG_BOOL}, {"$j", "ftp-ssl-ccc-mode", ARG_STRING}, {"$z", "libcurl", ARG_STRING}, {"$#", "raw", ARG_BOOL}, {"$0", "post301", ARG_BOOL}, {"$1", "keepalive", ARG_BOOL}, /* 'keepalive' listed as --no-keepalive in the help */ {"$2", "socks5-hostname", ARG_STRING}, {"$3", "keepalive-time", ARG_STRING}, {"$4", "post302", ARG_BOOL}, {"$5", "noproxy", ARG_STRING}, {"$7", "socks5-gssapi-nec", ARG_BOOL}, {"$8", "proxy1.0", ARG_STRING}, {"$9", "tftp-blksize", ARG_STRING}, {"$A", "mail-from", ARG_STRING}, {"$B", "mail-rcpt", ARG_STRING}, {"$C", "ftp-pret", ARG_BOOL}, {"$D", "proto", ARG_STRING}, {"$E", "proto-redir", ARG_STRING}, {"$F", "resolve", ARG_STRING}, {"$G", "delegation", ARG_STRING}, {"$H", "mail-auth", ARG_STRING}, {"$I", "post303", ARG_BOOL}, {"$J", "metalink", ARG_BOOL}, {"$6", "sasl-authzid", ARG_STRING}, {"$K", "sasl-ir", ARG_BOOL }, {"$L", "test-event", ARG_BOOL}, {"$M", "unix-socket", ARG_FILENAME}, {"$N", "path-as-is", ARG_BOOL}, {"$O", "socks5-gssapi-service", ARG_STRING}, /* 'socks5-gssapi-service' merged with'proxy-service-name' and deprecated since 7.49.0 */ {"$O", "proxy-service-name", ARG_STRING}, {"$P", "service-name", ARG_STRING}, {"$Q", "proto-default", ARG_STRING}, {"$R", "expect100-timeout", ARG_STRING}, {"$S", "tftp-no-options", ARG_BOOL}, {"$U", "connect-to", ARG_STRING}, {"$W", "abstract-unix-socket", ARG_FILENAME}, {"$X", "tls-max", ARG_STRING}, {"$Y", "suppress-connect-headers", ARG_BOOL}, {"$Z", "compressed-ssh", ARG_BOOL}, {"$~", "happy-eyeballs-timeout-ms", ARG_STRING}, {"0", "http1.0", ARG_NONE}, {"01", "http1.1", ARG_NONE}, {"02", "http2", ARG_NONE}, {"03", "http2-prior-knowledge", ARG_NONE}, {"04", "http3", ARG_NONE}, {"09", "http0.9", ARG_BOOL}, {"1", "tlsv1", ARG_NONE}, {"10", "tlsv1.0", ARG_NONE}, {"11", "tlsv1.1", ARG_NONE}, {"12", "tlsv1.2", ARG_NONE}, {"13", "tlsv1.3", ARG_NONE}, {"1A", "tls13-ciphers", ARG_STRING}, {"1B", "proxy-tls13-ciphers", ARG_STRING}, {"2", "sslv2", ARG_NONE}, {"3", "sslv3", ARG_NONE}, {"4", "ipv4", ARG_NONE}, {"6", "ipv6", ARG_NONE}, {"a", "append", ARG_BOOL}, {"A", "user-agent", ARG_STRING}, {"b", "cookie", ARG_STRING}, {"ba", "alt-svc", ARG_STRING}, {"B", "use-ascii", ARG_BOOL}, {"c", "cookie-jar", ARG_STRING}, {"C", "continue-at", ARG_STRING}, {"d", "data", ARG_STRING}, {"dr", "data-raw", ARG_STRING}, {"da", "data-ascii", ARG_STRING}, {"db", "data-binary", ARG_STRING}, {"de", "data-urlencode", ARG_STRING}, {"D", "dump-header", ARG_FILENAME}, {"e", "referer", ARG_STRING}, {"E", "cert", ARG_FILENAME}, {"Ea", "cacert", ARG_FILENAME}, {"Eb", "cert-type", ARG_STRING}, {"Ec", "key", ARG_FILENAME}, {"Ed", "key-type", ARG_STRING}, {"Ee", "pass", ARG_STRING}, {"Ef", "engine", ARG_STRING}, {"Eg", "capath", ARG_FILENAME}, {"Eh", "pubkey", ARG_STRING}, {"Ei", "hostpubmd5", ARG_STRING}, {"Ej", "crlfile", ARG_FILENAME}, {"Ek", "tlsuser", ARG_STRING}, {"El", "tlspassword", ARG_STRING}, {"Em", "tlsauthtype", ARG_STRING}, {"En", "ssl-allow-beast", ARG_BOOL}, /* Eo */ {"Ep", "pinnedpubkey", ARG_STRING}, {"EP", "proxy-pinnedpubkey", ARG_STRING}, {"Eq", "cert-status", ARG_BOOL}, {"Er", "false-start", ARG_BOOL}, {"Es", "ssl-no-revoke", ARG_BOOL}, {"Et", "tcp-fastopen", ARG_BOOL}, {"Eu", "proxy-tlsuser", ARG_STRING}, {"Ev", "proxy-tlspassword", ARG_STRING}, {"Ew", "proxy-tlsauthtype", ARG_STRING}, {"Ex", "proxy-cert", ARG_FILENAME}, {"Ey", "proxy-cert-type", ARG_STRING}, {"Ez", "proxy-key", ARG_FILENAME}, {"E0", "proxy-key-type", ARG_STRING}, {"E1", "proxy-pass", ARG_STRING}, {"E2", "proxy-ciphers", ARG_STRING}, {"E3", "proxy-crlfile", ARG_FILENAME}, {"E4", "proxy-ssl-allow-beast", ARG_BOOL}, {"E5", "login-options", ARG_STRING}, {"E6", "proxy-cacert", ARG_FILENAME}, {"E7", "proxy-capath", ARG_FILENAME}, {"E8", "proxy-insecure", ARG_BOOL}, {"E9", "proxy-tlsv1", ARG_NONE}, {"EA", "socks5-basic", ARG_BOOL}, {"EB", "socks5-gssapi", ARG_BOOL}, {"EC", "etag-save", ARG_FILENAME}, {"ED", "etag-compare", ARG_FILENAME}, {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, {"fc", "mail-rcpt-allowfails", ARG_BOOL}, {"F", "form", ARG_STRING}, {"Fs", "form-string", ARG_STRING}, {"g", "globoff", ARG_BOOL}, {"G", "get", ARG_NONE}, {"Ga", "request-target", ARG_STRING}, {"h", "help", ARG_BOOL}, {"H", "header", ARG_STRING}, {"Hp", "proxy-header", ARG_STRING}, {"i", "include", ARG_BOOL}, {"I", "head", ARG_BOOL}, {"j", "junk-session-cookies", ARG_BOOL}, {"J", "remote-header-name", ARG_BOOL}, {"k", "insecure", ARG_BOOL}, {"K", "config", ARG_FILENAME}, {"l", "list-only", ARG_BOOL}, {"L", "location", ARG_BOOL}, {"Lt", "location-trusted", ARG_BOOL}, {"m", "max-time", ARG_STRING}, {"M", "manual", ARG_BOOL}, {"n", "netrc", ARG_BOOL}, {"no", "netrc-optional", ARG_BOOL}, {"ne", "netrc-file", ARG_FILENAME}, {"N", "buffer", ARG_BOOL}, /* 'buffer' listed as --no-buffer in the help */ {"o", "output", ARG_FILENAME}, {"O", "remote-name", ARG_NONE}, {"Oa", "remote-name-all", ARG_BOOL}, {"p", "proxytunnel", ARG_BOOL}, {"P", "ftp-port", ARG_STRING}, {"q", "disable", ARG_BOOL}, {"Q", "quote", ARG_STRING}, {"r", "range", ARG_STRING}, {"R", "remote-time", ARG_BOOL}, {"s", "silent", ARG_BOOL}, {"S", "show-error", ARG_BOOL}, {"t", "telnet-option", ARG_STRING}, {"T", "upload-file", ARG_FILENAME}, {"u", "user", ARG_STRING}, {"U", "proxy-user", ARG_STRING}, {"v", "verbose", ARG_BOOL}, {"V", "version", ARG_BOOL}, {"w", "write-out", ARG_STRING}, {"x", "proxy", ARG_STRING}, {"xa", "preproxy", ARG_STRING}, {"X", "request", ARG_STRING}, {"Y", "speed-limit", ARG_STRING}, {"y", "speed-time", ARG_STRING}, {"z", "time-cond", ARG_STRING}, {"Z", "parallel", ARG_BOOL}, {"Zb", "parallel-max", ARG_STRING}, {"Zc", "parallel-immediate", ARG_BOOL}, {"#", "progress-bar", ARG_BOOL}, {"#m", "progress-meter", ARG_BOOL}, {":", "next", ARG_NONE}, }; /* Split the argument of -E to 'certname' and 'passphrase' separated by colon. * We allow ':' and '\' to be escaped by '\' so that we can use certificate * nicknames containing ':'. See * for details. */ #ifndef UNITTESTS static #endif void parse_cert_parameter(const char *cert_parameter, char **certname, char **passphrase) { size_t param_length = strlen(cert_parameter); size_t span; const char *param_place = NULL; char *certname_place = NULL; *certname = NULL; *passphrase = NULL; /* most trivial assumption: cert_parameter is empty */ if(param_length == 0) return; /* next less trivial: cert_parameter starts 'pkcs11:' and thus * looks like a RFC7512 PKCS#11 URI which can be used as-is. * Also if cert_parameter contains no colon nor backslash, this * means no passphrase was given and no characters escaped */ if(curl_strnequal(cert_parameter, "pkcs11:", 7) || !strpbrk(cert_parameter, ":\\")) { *certname = strdup(cert_parameter); return; } /* deal with escaped chars; find unescaped colon if it exists */ certname_place = malloc(param_length + 1); if(!certname_place) return; *certname = certname_place; param_place = cert_parameter; while(*param_place) { span = strcspn(param_place, ":\\"); strncpy(certname_place, param_place, span); param_place += span; certname_place += span; /* we just ate all the non-special chars. now we're on either a special * char or the end of the string. */ switch(*param_place) { case '\0': break; case '\\': param_place++; switch(*param_place) { case '\0': *certname_place++ = '\\'; break; case '\\': *certname_place++ = '\\'; param_place++; break; case ':': *certname_place++ = ':'; param_place++; break; default: *certname_place++ = '\\'; *certname_place++ = *param_place; param_place++; break; } break; case ':': /* Since we live in a world of weirdness and confusion, the win32 dudes can use : when using drive letters and thus c:\file:password needs to work. In order not to break compatibility, we still use : as separator, but we try to detect when it is used for a file name! On windows. */ #ifdef WIN32 if(param_place && (param_place == &cert_parameter[1]) && (cert_parameter[2] == '\\' || cert_parameter[2] == '/') && (ISALPHA(cert_parameter[0])) ) { /* colon in the second column, followed by a backslash, and the first character is an alphabetic letter: this is a drive letter colon */ *certname_place++ = ':'; param_place++; break; } #endif /* escaped colons and Windows drive letter colons were handled * above; if we're still here, this is a separating colon */ param_place++; if(*param_place) { *passphrase = strdup(param_place); } goto done; } } done: *certname_place = '\0'; } static void GetFileAndPassword(char *nextarg, char **file, char **password) { char *certname, *passphrase; parse_cert_parameter(nextarg, &certname, &passphrase); Curl_safefree(*file); *file = certname; if(passphrase) { Curl_safefree(*password); *password = passphrase; } cleanarg(nextarg); } /* Get a size parameter for '--limit-rate' or '--max-filesize'. * We support a 'G', 'M' or 'K' suffix too. */ static ParameterError GetSizeParameter(struct GlobalConfig *global, const char *arg, const char *which, curl_off_t *value_out) { char *unit; curl_off_t value; if(curlx_strtoofft(arg, &unit, 0, &value)) { warnf(global, "invalid number specified for %s\n", which); return PARAM_BAD_USE; } if(!*unit) unit = (char *)"b"; else if(strlen(unit) > 1) unit = (char *)"w"; /* unsupported */ switch(*unit) { case 'G': case 'g': if(value > (CURL_OFF_T_MAX / (1024*1024*1024))) return PARAM_NUMBER_TOO_LARGE; value *= 1024*1024*1024; break; case 'M': case 'm': if(value > (CURL_OFF_T_MAX / (1024*1024))) return PARAM_NUMBER_TOO_LARGE; value *= 1024*1024; break; case 'K': case 'k': if(value > (CURL_OFF_T_MAX / 1024)) return PARAM_NUMBER_TOO_LARGE; value *= 1024; break; case 'b': case 'B': /* for plain bytes, leave as-is */ break; default: warnf(global, "unsupported %s unit. Use G, M, K or B!\n", which); return PARAM_BAD_USE; } *value_out = value; return PARAM_OK; } ParameterError getparameter(const char *flag, /* f or -long-flag */ char *nextarg, /* NULL if unset */ bool *usedarg, /* set to TRUE if the arg has been used */ struct GlobalConfig *global, struct OperationConfig *config) { char letter; char subletter = '\0'; /* subletters can only occur on long options */ int rc; const char *parse = NULL; unsigned int j; time_t now; int hit = -1; bool longopt = FALSE; bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ ParameterError err; bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled by using --OPTION or --no-OPTION */ *usedarg = FALSE; /* default is that we don't use the arg */ if(('-' != flag[0]) || ('-' == flag[1])) { /* this should be a long name */ const char *word = ('-' == flag[0]) ? flag + 2 : flag; size_t fnam = strlen(word); int numhits = 0; bool noflagged = FALSE; if(!strncmp(word, "no-", 3)) { /* disable this option but ignore the "no-" part when looking for it */ word += 3; toggle = FALSE; noflagged = TRUE; } for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { if(curl_strnequal(aliases[j].lname, word, fnam)) { longopt = TRUE; numhits++; if(curl_strequal(aliases[j].lname, word)) { parse = aliases[j].letter; hit = j; numhits = 1; /* a single unique hit */ break; } parse = aliases[j].letter; hit = j; } } if(numhits > 1) { /* this is at least the second match! */ return PARAM_OPTION_AMBIGUOUS; } if(hit < 0) { return PARAM_OPTION_UNKNOWN; } if(noflagged && (aliases[hit].desc != ARG_BOOL)) /* --no- prefixed an option that isn't boolean! */ return PARAM_NO_NOT_BOOLEAN; } else { flag++; /* prefixed with one dash, pass it */ hit = -1; parse = flag; } do { /* we can loop here if we have multiple single-letters */ if(!longopt) { letter = (char)*parse; subletter = '\0'; } else { letter = parse[0]; subletter = parse[1]; } if(hit < 0) { for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { if(letter == aliases[j].letter[0]) { hit = j; break; } } if(hit < 0) { return PARAM_OPTION_UNKNOWN; } } if(aliases[hit].desc >= ARG_STRING) { /* this option requires an extra parameter */ if(!longopt && parse[1]) { nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ singleopt = TRUE; /* don't loop anymore after this */ } else if(!nextarg) return PARAM_REQUIRES_PARAMETER; else *usedarg = TRUE; /* mark it as used */ if((aliases[hit].desc == ARG_FILENAME) && (nextarg[0] == '-') && nextarg[1]) { /* if the file name looks like a command line option */ warnf(global, "The file name argument '%s' looks like a flag.\n", nextarg); } } else if((aliases[hit].desc == ARG_NONE) && !toggle) return PARAM_NO_PREFIX; switch(letter) { case '*': /* options without a short option */ switch(subletter) { case '4': /* --dns-ipv4-addr */ /* addr in dot notation */ GetStr(&config->dns_ipv4_addr, nextarg); break; case '6': /* --dns-ipv6-addr */ /* addr in dot notation */ GetStr(&config->dns_ipv6_addr, nextarg); break; case 'a': /* random-file */ GetStr(&config->random_file, nextarg); break; case 'b': /* egd-file */ GetStr(&config->egd_file, nextarg); break; case 'B': /* OAuth 2.0 bearer token */ GetStr(&config->oauth_bearer, nextarg); config->authtype |= CURLAUTH_BEARER; break; case 'c': /* connect-timeout */ err = str2udouble(&config->connecttimeout, nextarg, LONG_MAX/1000); if(err) return err; break; case 'C': /* doh-url */ GetStr(&config->doh_url, nextarg); break; case 'd': /* ciphers */ GetStr(&config->cipher_list, nextarg); break; case 'D': /* --dns-interface */ /* interface name */ GetStr(&config->dns_interface, nextarg); break; case 'e': /* --disable-epsv */ config->disable_epsv = toggle; break; case 'f': /* --disallow-username-in-url */ config->disallow_username_in_url = toggle; break; case 'E': /* --epsv */ config->disable_epsv = (!toggle)?TRUE:FALSE; break; case 'F': /* --dns-servers */ /* IP addrs of DNS servers */ GetStr(&config->dns_servers, nextarg); break; case 'g': /* --trace */ GetStr(&global->trace_dump, nextarg); if(global->tracetype && (global->tracetype != TRACE_BIN)) warnf(global, "--trace overrides an earlier trace/verbose option\n"); global->tracetype = TRACE_BIN; break; case 'G': /* --npn */ config->nonpn = (!toggle)?TRUE:FALSE; break; case 'h': /* --trace-ascii */ GetStr(&global->trace_dump, nextarg); if(global->tracetype && (global->tracetype != TRACE_ASCII)) warnf(global, "--trace-ascii overrides an earlier trace/verbose option\n"); global->tracetype = TRACE_ASCII; break; case 'H': /* --alpn */ config->noalpn = (!toggle)?TRUE:FALSE; break; case 'i': /* --limit-rate */ { curl_off_t value; ParameterError pe = GetSizeParameter(global, nextarg, "rate", &value); if(pe != PARAM_OK) return pe; config->recvpersecond = value; config->sendpersecond = value; } break; case 'j': /* --compressed */ if(toggle && !(curlinfo->features & (CURL_VERSION_LIBZ | CURL_VERSION_BROTLI))) return PARAM_LIBCURL_DOESNT_SUPPORT; config->encoding = toggle; break; case 'J': /* --tr-encoding */ config->tr_encoding = toggle; break; case 'k': /* --digest */ if(toggle) config->authtype |= CURLAUTH_DIGEST; else config->authtype &= ~CURLAUTH_DIGEST; break; case 'l': /* --negotiate */ if(toggle) { if(curlinfo->features & CURL_VERSION_SPNEGO) config->authtype |= CURLAUTH_NEGOTIATE; else return PARAM_LIBCURL_DOESNT_SUPPORT; } else config->authtype &= ~CURLAUTH_NEGOTIATE; break; case 'm': /* --ntlm */ if(toggle) { if(curlinfo->features & CURL_VERSION_NTLM) config->authtype |= CURLAUTH_NTLM; else return PARAM_LIBCURL_DOESNT_SUPPORT; } else config->authtype &= ~CURLAUTH_NTLM; break; case 'M': /* --ntlm-wb */ if(toggle) { if(curlinfo->features & CURL_VERSION_NTLM_WB) config->authtype |= CURLAUTH_NTLM_WB; else return PARAM_LIBCURL_DOESNT_SUPPORT; } else config->authtype &= ~CURLAUTH_NTLM_WB; break; case 'n': /* --basic for completeness */ if(toggle) config->authtype |= CURLAUTH_BASIC; else config->authtype &= ~CURLAUTH_BASIC; break; case 'o': /* --anyauth, let libcurl pick it */ if(toggle) config->authtype = CURLAUTH_ANY; /* --no-anyauth simply doesn't touch it */ break; #ifdef USE_WATT32 case 'p': /* --wdebug */ dbug_init(); break; #endif case 'q': /* --ftp-create-dirs */ config->ftp_create_dirs = toggle; break; case 'r': /* --create-dirs */ config->create_dirs = toggle; break; case 's': /* --max-redirs */ /* specified max no of redirects (http(s)), this accepts -1 as a special condition */ err = str2num(&config->maxredirs, nextarg); if(err) return err; if(config->maxredirs < -1) return PARAM_BAD_NUMERIC; break; case 't': /* --proxy-ntlm */ if(curlinfo->features & CURL_VERSION_NTLM) config->proxyntlm = toggle; else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'u': /* --crlf */ /* LF -> CRLF conversion? */ config->crlf = toggle; break; case 'v': /* --stderr */ if(strcmp(nextarg, "-")) { FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT); if(!newfile) warnf(global, "Failed to open %s!\n", nextarg); else { if(global->errors_fopened) fclose(global->errors); global->errors = newfile; global->errors_fopened = TRUE; } } else global->errors = stdout; break; case 'w': /* --interface */ /* interface */ GetStr(&config->iface, nextarg); break; case 'x': /* --krb */ /* kerberos level string */ if(curlinfo->features & CURL_VERSION_KERBEROS4) GetStr(&config->krblevel, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'X': /* --haproxy-protocol */ config->haproxy_protocol = toggle; break; case 'y': /* --max-filesize */ { curl_off_t value; ParameterError pe = GetSizeParameter(global, nextarg, "max-filesize", &value); if(pe != PARAM_OK) return pe; config->max_filesize = value; } break; case 'z': /* --disable-eprt */ config->disable_eprt = toggle; break; case 'Z': /* --eprt */ config->disable_eprt = (!toggle)?TRUE:FALSE; break; case '~': /* --xattr */ config->xattr = toggle; break; case '@': /* the URL! */ { struct getout *url; if(!config->url_get) config->url_get = config->url_list; if(config->url_get) { /* there's a node here, if it already is filled-in continue to find an "empty" node */ while(config->url_get && (config->url_get->flags & GETOUT_URL)) config->url_get = config->url_get->next; } /* now there might or might not be an available node to fill in! */ if(config->url_get) /* existing node */ url = config->url_get; else /* there was no free node, create one! */ config->url_get = url = new_getout(config); if(!url) return PARAM_NO_MEM; /* fill in the URL */ GetStr(&url->url, nextarg); url->flags |= GETOUT_URL; } } break; case '$': /* more options without a short option */ switch(subletter) { case 'a': /* --ssl */ if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) return PARAM_LIBCURL_DOESNT_SUPPORT; config->ftp_ssl = toggle; break; case 'b': /* --ftp-pasv */ Curl_safefree(config->ftpport); break; case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves the name locally and passes on the resolved address */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_SOCKS5; break; case 't': /* --socks4 specifies a socks4 proxy to use */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_SOCKS4; break; case 'T': /* --socks4a specifies a socks4a proxy to use */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_SOCKS4A; break; case '2': /* --socks5-hostname specifies a socks5 proxy and enables name resolving with the proxy */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_SOCKS5_HOSTNAME; break; case 'd': /* --tcp-nodelay option */ config->tcp_nodelay = toggle; break; case 'e': /* --proxy-digest */ config->proxydigest = toggle; break; case 'f': /* --proxy-basic */ config->proxybasic = toggle; break; case 'g': /* --retry */ err = str2unum(&config->req_retry, nextarg); if(err) return err; break; case 'V': /* --retry-connrefused */ config->retry_connrefused = toggle; break; case 'h': /* --retry-delay */ err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000); if(err) return err; break; case 'i': /* --retry-max-time */ err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000); if(err) return err; break; case 'k': /* --proxy-negotiate */ if(curlinfo->features & CURL_VERSION_SPNEGO) config->proxynegotiate = toggle; else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'm': /* --ftp-account */ GetStr(&config->ftp_account, nextarg); break; case 'n': /* --proxy-anyauth */ config->proxyanyauth = toggle; break; case 'o': /* --trace-time */ global->tracetime = toggle; break; case 'p': /* --ignore-content-length */ config->ignorecl = toggle; break; case 'q': /* --ftp-skip-pasv-ip */ config->ftp_skip_ip = toggle; break; case 'r': /* --ftp-method (undocumented at this point) */ config->ftp_filemethod = ftpfilemethod(config, nextarg); break; case 's': { /* --local-port */ char lrange[7]; /* 16bit base 10 is 5 digits, but we allow 6 so that this catches overflows, not just truncates */ char *p = nextarg; while(ISDIGIT(*p)) p++; if(*p) { /* if there's anything more than a plain decimal number */ rc = sscanf(p, " - %6s", lrange); *p = 0; /* zero terminate to make str2unum() work below */ } else rc = 0; err = str2unum(&config->localport, nextarg); if(err || (config->localport > 65535)) return PARAM_BAD_USE; if(!rc) config->localportrange = 1; /* default number of ports to try */ else { err = str2unum(&config->localportrange, lrange); if(err || (config->localportrange > 65535)) return PARAM_BAD_USE; config->localportrange -= (config->localport-1); if(config->localportrange < 1) return PARAM_BAD_USE; } break; } case 'u': /* --ftp-alternative-to-user */ GetStr(&config->ftp_alternative_to_user, nextarg); break; case 'v': /* --ssl-reqd */ if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) return PARAM_LIBCURL_DOESNT_SUPPORT; config->ftp_ssl_reqd = toggle; break; case 'w': /* --no-sessionid */ config->disable_sessionid = (!toggle)?TRUE:FALSE; break; case 'x': /* --ftp-ssl-control */ if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) return PARAM_LIBCURL_DOESNT_SUPPORT; config->ftp_ssl_control = toggle; break; case 'y': /* --ftp-ssl-ccc */ config->ftp_ssl_ccc = toggle; if(!config->ftp_ssl_ccc_mode) config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; break; case 'j': /* --ftp-ssl-ccc-mode */ config->ftp_ssl_ccc = TRUE; config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); break; case 'z': /* --libcurl */ #ifdef CURL_DISABLE_LIBCURL_OPTION warnf(global, "--libcurl option was disabled at build-time!\n"); return PARAM_OPTION_UNKNOWN; #else GetStr(&global->libcurl, nextarg); break; #endif case '#': /* --raw */ config->raw = toggle; break; case '0': /* --post301 */ config->post301 = toggle; break; case '1': /* --no-keepalive */ config->nokeepalive = (!toggle)?TRUE:FALSE; break; case '3': /* --keepalive-time */ err = str2unum(&config->alivetime, nextarg); if(err) return err; break; case '4': /* --post302 */ config->post302 = toggle; break; case 'I': /* --post303 */ config->post303 = toggle; break; case '5': /* --noproxy */ /* This specifies the noproxy list */ GetStr(&config->noproxy, nextarg); break; case '7': /* --socks5-gssapi-nec*/ config->socks5_gssapi_nec = toggle; break; case '8': /* --proxy1.0 */ /* http 1.0 proxy */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_HTTP_1_0; break; case '9': /* --tftp-blksize */ err = str2unum(&config->tftp_blksize, nextarg); if(err) return err; break; case 'A': /* --mail-from */ GetStr(&config->mail_from, nextarg); break; case 'B': /* --mail-rcpt */ /* append receiver to a list */ err = add2list(&config->mail_rcpt, nextarg); if(err) return err; break; case 'C': /* --ftp-pret */ config->ftp_pret = toggle; break; case 'D': /* --proto */ config->proto_present = TRUE; if(proto2num(config, &config->proto, nextarg)) return PARAM_BAD_USE; break; case 'E': /* --proto-redir */ config->proto_redir_present = TRUE; if(proto2num(config, &config->proto_redir, nextarg)) return PARAM_BAD_USE; break; case 'F': /* --resolve */ err = add2list(&config->resolve, nextarg); if(err) return err; break; case 'G': /* --delegation LEVEL */ config->gssapi_delegation = delegation(config, nextarg); break; case 'H': /* --mail-auth */ GetStr(&config->mail_auth, nextarg); break; case 'J': /* --metalink */ { #ifdef USE_METALINK int mlmaj, mlmin, mlpatch; metalink_get_version(&mlmaj, &mlmin, &mlpatch); if((mlmaj*10000)+(mlmin*100) + mlpatch < CURL_REQ_LIBMETALINK_VERS) { warnf(global, "--metalink option cannot be used because the version of " "the linked libmetalink library is too old. " "Required: %d.%d.%d, found %d.%d.%d\n", CURL_REQ_LIBMETALINK_MAJOR, CURL_REQ_LIBMETALINK_MINOR, CURL_REQ_LIBMETALINK_PATCH, mlmaj, mlmin, mlpatch); return PARAM_BAD_USE; } else config->use_metalink = toggle; #else warnf(global, "--metalink option is ignored because the binary is " "built without the Metalink support.\n"); #endif break; } case '6': /* --sasl-authzid */ GetStr(&config->sasl_authzid, nextarg); break; case 'K': /* --sasl-ir */ config->sasl_ir = toggle; break; case 'L': /* --test-event */ #ifdef CURLDEBUG global->test_event_based = toggle; #else warnf(global, "--test-event is ignored unless a debug build!\n"); #endif break; case 'M': /* --unix-socket */ config->abstract_unix_socket = FALSE; GetStr(&config->unix_socket_path, nextarg); break; case 'N': /* --path-as-is */ config->path_as_is = toggle; break; case 'O': /* --proxy-service-name */ GetStr(&config->proxy_service_name, nextarg); break; case 'P': /* --service-name */ GetStr(&config->service_name, nextarg); break; case 'Q': /* --proto-default */ GetStr(&config->proto_default, nextarg); err = check_protocol(config->proto_default); if(err) return err; break; case 'R': /* --expect100-timeout */ err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000); if(err) return err; break; case 'S': /* --tftp-no-options */ config->tftp_no_options = toggle; break; case 'U': /* --connect-to */ err = add2list(&config->connect_to, nextarg); if(err) return err; break; case 'W': /* --abstract-unix-socket */ config->abstract_unix_socket = TRUE; GetStr(&config->unix_socket_path, nextarg); break; case 'X': /* --tls-max */ err = str2tls_max(&config->ssl_version_max, nextarg); if(err) return err; break; case 'Y': /* --suppress-connect-headers */ config->suppress_connect_headers = toggle; break; case 'Z': /* --compressed-ssh */ config->ssh_compression = toggle; break; case '~': /* --happy-eyeballs-timeout-ms */ err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); if(err) return err; /* 0 is a valid value for this timeout */ break; } break; case '#': switch(subletter) { case 'm': /* --progress-meter */ global->noprogress = !toggle; break; default: /* --progress-bar */ global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS; break; } break; case ':': /* --next */ return PARAM_NEXT_OPERATION; case '0': /* --http* options */ switch(subletter) { case '\0': /* HTTP version 1.0 */ config->httpversion = CURL_HTTP_VERSION_1_0; break; case '1': /* HTTP version 1.1 */ config->httpversion = CURL_HTTP_VERSION_1_1; break; case '2': /* HTTP version 2.0 */ config->httpversion = CURL_HTTP_VERSION_2_0; break; case '3': /* --http2-prior-knowledge */ /* HTTP version 2.0 over clean TCP*/ config->httpversion = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE; break; case '4': /* --http3 */ /* HTTP version 3 go over QUIC - at once */ if(curlinfo->features & CURL_VERSION_HTTP3) config->httpversion = CURL_HTTP_VERSION_3; else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case '9': /* Allow HTTP/0.9 responses! */ config->http09_allowed = toggle; break; } break; case '1': /* --tlsv1* options */ switch(subletter) { case '\0': /* TLS version 1.x */ config->ssl_version = CURL_SSLVERSION_TLSv1; break; case '0': /* TLS version 1.0 */ config->ssl_version = CURL_SSLVERSION_TLSv1_0; break; case '1': /* TLS version 1.1 */ config->ssl_version = CURL_SSLVERSION_TLSv1_1; break; case '2': /* TLS version 1.2 */ config->ssl_version = CURL_SSLVERSION_TLSv1_2; break; case '3': /* TLS version 1.3 */ config->ssl_version = CURL_SSLVERSION_TLSv1_3; break; case 'A': /* --tls13-ciphers */ GetStr(&config->cipher13_list, nextarg); break; case 'B': /* --proxy-tls13-ciphers */ GetStr(&config->proxy_cipher13_list, nextarg); break; } break; case '2': /* SSL version 2 */ config->ssl_version = CURL_SSLVERSION_SSLv2; break; case '3': /* SSL version 3 */ config->ssl_version = CURL_SSLVERSION_SSLv3; break; case '4': /* IPv4 */ config->ip_version = 4; break; case '6': /* IPv6 */ config->ip_version = 6; break; case 'a': /* This makes the FTP sessions use APPE instead of STOR */ config->ftp_append = toggle; break; case 'A': /* This specifies the User-Agent name */ GetStr(&config->useragent, nextarg); break; case 'b': switch(subletter) { case 'a': /* --alt-svc */ if(curlinfo->features & CURL_VERSION_ALTSVC) GetStr(&config->altsvc, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; default: /* --cookie string coming up: */ if(nextarg[0] == '@') { nextarg++; } else if(strchr(nextarg, '=')) { /* A cookie string must have a =-letter */ GetStr(&config->cookie, nextarg); break; } /* We have a cookie file to read from! */ GetStr(&config->cookiefile, nextarg); } break; case 'B': /* use ASCII/text when transferring */ config->use_ascii = toggle; break; case 'c': /* get the file name to dump all cookies in */ GetStr(&config->cookiejar, nextarg); break; case 'C': /* This makes us continue an ftp transfer at given position */ if(strcmp(nextarg, "-")) { err = str2offset(&config->resume_from, nextarg); if(err) return err; config->resume_from_current = FALSE; } else { config->resume_from_current = TRUE; config->resume_from = 0; } config->use_resume = TRUE; break; case 'd': /* postfield data */ { char *postdata = NULL; FILE *file; size_t size = 0; bool raw_mode = (subletter == 'r'); if(subletter == 'e') { /* --data-urlencode*/ /* [name]=[content], we encode the content part only * [name]@[file name] * * Case 2: we first load the file using that name and then encode * the content. */ const char *p = strchr(nextarg, '='); size_t nlen; char is_file; if(!p) /* there was no '=' letter, check for a '@' instead */ p = strchr(nextarg, '@'); if(p) { nlen = p - nextarg; /* length of the name part */ is_file = *p++; /* pass the separator */ } else { /* neither @ nor =, so no name and it isn't a file */ nlen = is_file = 0; p = nextarg; } if('@' == is_file) { /* a '@' letter, it means that a file name or - (stdin) follows */ if(!strcmp("-", p)) { file = stdin; set_binmode(stdin); } else { file = fopen(p, "rb"); if(!file) warnf(global, "Couldn't read data from file \"%s\", this makes " "an empty POST.\n", nextarg); } err = file2memory(&postdata, &size, file); if(file && (file != stdin)) fclose(file); if(err) return err; } else { GetStr(&postdata, p); if(postdata) size = strlen(postdata); } if(!postdata) { /* no data from the file, point to a zero byte string to make this get sent as a POST anyway */ postdata = strdup(""); if(!postdata) return PARAM_NO_MEM; size = 0; } else { char *enc = curl_easy_escape(NULL, postdata, (int)size); Curl_safefree(postdata); /* no matter if it worked or not */ if(enc) { /* now make a string with the name from above and append the encoded string */ size_t outlen = nlen + strlen(enc) + 2; char *n = malloc(outlen); if(!n) { curl_free(enc); return PARAM_NO_MEM; } if(nlen > 0) { /* only append '=' if we have a name */ msnprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); size = outlen-1; } else { strcpy(n, enc); size = outlen-2; /* since no '=' was inserted */ } curl_free(enc); postdata = n; } else return PARAM_NO_MEM; } } else if('@' == *nextarg && !raw_mode) { /* the data begins with a '@' letter, it means that a file name or - (stdin) follows */ nextarg++; /* pass the @ */ if(!strcmp("-", nextarg)) { file = stdin; if(subletter == 'b') /* forced data-binary */ set_binmode(stdin); } else { file = fopen(nextarg, "rb"); if(!file) warnf(global, "Couldn't read data from file \"%s\", this makes " "an empty POST.\n", nextarg); } if(subletter == 'b') /* forced binary */ err = file2memory(&postdata, &size, file); else { err = file2string(&postdata, file); if(postdata) size = strlen(postdata); } if(file && (file != stdin)) fclose(file); if(err) return err; if(!postdata) { /* no data from the file, point to a zero byte string to make this get sent as a POST anyway */ postdata = strdup(""); if(!postdata) return PARAM_NO_MEM; } } else { GetStr(&postdata, nextarg); if(postdata) size = strlen(postdata); } #ifdef CURL_DOES_CONVERSIONS if(subletter != 'b') { /* NOT forced binary, convert to ASCII */ if(convert_to_network(postdata, strlen(postdata))) { Curl_safefree(postdata); return PARAM_NO_MEM; } } #endif if(config->postfields) { /* we already have a string, we append this one with a separating &-letter */ char *oldpost = config->postfields; curl_off_t oldlen = config->postfieldsize; curl_off_t newlen = oldlen + curlx_uztoso(size) + 2; config->postfields = malloc((size_t)newlen); if(!config->postfields) { Curl_safefree(oldpost); Curl_safefree(postdata); return PARAM_NO_MEM; } memcpy(config->postfields, oldpost, (size_t)oldlen); /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */ config->postfields[oldlen] = '\x26'; memcpy(&config->postfields[oldlen + 1], postdata, size); config->postfields[oldlen + 1 + size] = '\0'; Curl_safefree(oldpost); Curl_safefree(postdata); config->postfieldsize += size + 1; } else { config->postfields = postdata; config->postfieldsize = curlx_uztoso(size); } } /* We can't set the request type here, as this data might be used in a simple GET if -G is used. Already or soon. if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) { Curl_safefree(postdata); return PARAM_BAD_USE; } */ break; case 'D': /* dump-header to given file name */ GetStr(&config->headerfile, nextarg); break; case 'e': { char *ptr = strstr(nextarg, ";auto"); if(ptr) { /* Automatic referer requested, this may be combined with a set initial one */ config->autoreferer = TRUE; *ptr = 0; /* zero terminate here */ } else config->autoreferer = FALSE; GetStr(&config->referer, nextarg); } break; case 'E': switch(subletter) { case '\0': /* certificate file */ GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); break; case 'a': /* CA info PEM file */ GetStr(&config->cacert, nextarg); break; case 'b': /* cert file type */ GetStr(&config->cert_type, nextarg); break; case 'c': /* private key file */ GetStr(&config->key, nextarg); break; case 'd': /* private key file type */ GetStr(&config->key_type, nextarg); break; case 'e': /* private key passphrase */ GetStr(&config->key_passwd, nextarg); cleanarg(nextarg); break; case 'f': /* crypto engine */ GetStr(&config->engine, nextarg); if(config->engine && curl_strequal(config->engine, "list")) return PARAM_ENGINES_REQUESTED; break; case 'g': /* CA cert directory */ GetStr(&config->capath, nextarg); break; case 'h': /* --pubkey public key file */ GetStr(&config->pubkey, nextarg); break; case 'i': /* --hostpubmd5 md5 of the host public key */ GetStr(&config->hostpubmd5, nextarg); if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) return PARAM_BAD_USE; break; case 'j': /* CRL file */ GetStr(&config->crlfile, nextarg); break; case 'k': /* TLS username */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) GetStr(&config->tls_username, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'l': /* TLS password */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) GetStr(&config->tls_password, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'm': /* TLS authentication type */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { GetStr(&config->tls_authtype, nextarg); if(!curl_strequal(config->tls_authtype, "SRP")) return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ } else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'n': /* no empty SSL fragments, --ssl-allow-beast */ if(curlinfo->features & CURL_VERSION_SSL) config->ssl_allow_beast = toggle; break; case 'p': /* Pinned public key DER file */ GetStr(&config->pinnedpubkey, nextarg); break; case 'P': /* proxy pinned public key */ GetStr(&config->proxy_pinnedpubkey, nextarg); break; case 'q': /* --cert-status */ config->verifystatus = TRUE; break; case 'r': /* --false-start */ config->falsestart = TRUE; break; case 's': /* --ssl-no-revoke */ if(curlinfo->features & CURL_VERSION_SSL) config->ssl_no_revoke = TRUE; break; case 't': /* --tcp-fastopen */ config->tcp_fastopen = TRUE; break; case 'u': /* TLS username for proxy */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) GetStr(&config->proxy_tls_username, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'v': /* TLS password for proxy */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) GetStr(&config->proxy_tls_password, nextarg); else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'w': /* TLS authentication type for proxy */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { GetStr(&config->proxy_tls_authtype, nextarg); if(!curl_strequal(config->proxy_tls_authtype, "SRP")) return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ } else return PARAM_LIBCURL_DOESNT_SUPPORT; break; case 'x': /* certificate file for proxy */ GetFileAndPassword(nextarg, &config->proxy_cert, &config->proxy_key_passwd); break; case 'y': /* cert file type for proxy */ GetStr(&config->proxy_cert_type, nextarg); break; case 'z': /* private key file for proxy */ GetStr(&config->proxy_key, nextarg); break; case '0': /* private key file type for proxy */ GetStr(&config->proxy_key_type, nextarg); break; case '1': /* private key passphrase for proxy */ GetStr(&config->proxy_key_passwd, nextarg); cleanarg(nextarg); break; case '2': /* ciphers for proxy */ GetStr(&config->proxy_cipher_list, nextarg); break; case '3': /* CRL file for proxy */ GetStr(&config->proxy_crlfile, nextarg); break; case '4': /* no empty SSL fragments for proxy */ if(curlinfo->features & CURL_VERSION_SSL) config->proxy_ssl_allow_beast = toggle; break; case '5': /* --login-options */ GetStr(&config->login_options, nextarg); break; case '6': /* CA info PEM file for proxy */ GetStr(&config->proxy_cacert, nextarg); break; case '7': /* CA cert directory for proxy */ GetStr(&config->proxy_capath, nextarg); break; case '8': /* allow insecure SSL connects for proxy */ config->proxy_insecure_ok = toggle; break; case '9': /* --proxy-tlsv1 */ /* TLS version 1 for proxy */ config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; break; case 'A': /* --socks5-basic */ if(toggle) config->socks5_auth |= CURLAUTH_BASIC; else config->socks5_auth &= ~CURLAUTH_BASIC; break; case 'B': /* --socks5-gssapi */ if(toggle) config->socks5_auth |= CURLAUTH_GSSAPI; else config->socks5_auth &= ~CURLAUTH_GSSAPI; break; case 'C': GetStr(&config->etag_save_file, nextarg); break; case 'D': GetStr(&config->etag_compare_file, nextarg); break; default: /* unknown flag */ return PARAM_OPTION_UNKNOWN; } break; case 'f': switch(subletter) { case 'a': /* --fail-early */ global->fail_early = toggle; break; case 'b': /* --styled-output */ global->styled_output = toggle; break; case 'c': /* --mail-rcpt-allowfails */ config->mail_rcpt_allowfails = toggle; break; default: /* --fail (hard on errors) */ config->failonerror = toggle; } break; case 'F': /* "form data" simulation, this is a little advanced so lets do our best to sort this out slowly and carefully */ if(formparse(config, nextarg, &config->mimeroot, &config->mimecurrent, (subletter == 's')?TRUE:FALSE)) /* 's' is literal string */ return PARAM_BAD_USE; if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq)) return PARAM_BAD_USE; break; case 'g': /* g disables URLglobbing */ config->globoff = toggle; break; case 'G': /* HTTP GET */ if(subletter == 'a') { /* --request-target */ GetStr(&config->request_target, nextarg); } else config->use_httpget = TRUE; break; case 'h': /* h for help */ if(toggle) { return PARAM_HELP_REQUESTED; } /* we now actually support --no-help too! */ break; case 'H': /* A custom header to append to a list */ if(nextarg[0] == '@') { /* read many headers from a file or stdin */ char *string; size_t len; bool use_stdin = !strcmp(&nextarg[1], "-"); FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT); if(!file) warnf(global, "Failed to open %s!\n", &nextarg[1]); else { err = file2memory(&string, &len, file); if(!err && string) { /* Allow strtok() here since this isn't used threaded */ /* !checksrc! disable BANNEDFUNC 2 */ char *h = strtok(string, "\r\n"); while(h) { if(subletter == 'p') /* --proxy-header */ err = add2list(&config->proxyheaders, h); else err = add2list(&config->headers, h); if(err) break; h = strtok(NULL, "\r\n"); } free(string); } if(!use_stdin) fclose(file); if(err) return err; } } else { if(subletter == 'p') /* --proxy-header */ err = add2list(&config->proxyheaders, nextarg); else err = add2list(&config->headers, nextarg); if(err) return err; } break; case 'i': config->show_headers = toggle; /* show the headers as well in the general output stream */ break; case 'j': config->cookiesession = toggle; break; case 'I': /* --head */ config->no_body = toggle; config->show_headers = toggle; if(SetHTTPrequest(config, (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, &config->httpreq)) return PARAM_BAD_USE; break; case 'J': /* --remote-header-name */ if(config->show_headers) { warnf(global, "--include and --remote-header-name cannot be combined.\n"); return PARAM_BAD_USE; } config->content_disposition = toggle; break; case 'k': /* allow insecure SSL connects */ config->insecure_ok = toggle; break; case 'K': /* parse config file */ if(parseconfig(nextarg, global)) warnf(global, "error trying read config from the '%s' file\n", nextarg); break; case 'l': config->dirlistonly = toggle; /* only list the names of the FTP dir */ break; case 'L': config->followlocation = toggle; /* Follow Location: HTTP headers */ switch(subletter) { case 't': /* Continue to send authentication (user+password) when following * locations, even when hostname changed */ config->unrestricted_auth = toggle; break; } break; case 'm': /* specified max time */ err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000); if(err) return err; break; case 'M': /* M for manual, huge help */ if(toggle) { /* --no-manual shows no manual... */ #ifdef USE_MANUAL return PARAM_MANUAL_REQUESTED; #else warnf(global, "built-in manual was disabled at build-time!\n"); return PARAM_OPTION_UNKNOWN; #endif } break; case 'n': switch(subletter) { case 'o': /* use .netrc or URL */ config->netrc_opt = toggle; break; case 'e': /* netrc-file */ GetStr(&config->netrc_file, nextarg); break; default: /* pick info from .netrc, if this is used for http, curl will automatically enfore user+password with the request */ config->netrc = toggle; break; } break; case 'N': /* disable the output I/O buffering. note that the option is called --buffer but is mostly used in the negative form: --no-buffer */ if(longopt) config->nobuffer = (!toggle)?TRUE:FALSE; else config->nobuffer = toggle; break; case 'O': /* --remote-name */ if(subletter == 'a') { /* --remote-name-all */ config->default_node_flags = toggle?GETOUT_USEREMOTE:0; break; } /* FALLTHROUGH */ case 'o': /* --output */ /* output file */ { struct getout *url; if(!config->url_out) config->url_out = config->url_list; if(config->url_out) { /* there's a node here, if it already is filled-in continue to find an "empty" node */ while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) config->url_out = config->url_out->next; } /* now there might or might not be an available node to fill in! */ if(config->url_out) /* existing node */ url = config->url_out; else /* there was no free node, create one! */ config->url_out = url = new_getout(config); if(!url) return PARAM_NO_MEM; /* fill in the outfile */ if('o' == letter) { GetStr(&url->outfile, nextarg); url->flags &= ~GETOUT_USEREMOTE; /* switch off */ } else { url->outfile = NULL; /* leave it */ if(toggle) url->flags |= GETOUT_USEREMOTE; /* switch on */ else url->flags &= ~GETOUT_USEREMOTE; /* switch off */ } url->flags |= GETOUT_OUTFILE; } break; case 'P': /* This makes the FTP sessions use PORT instead of PASV */ /* use or <192.168.10.10> style addresses. Anything except this will make us try to get the "default" address. NOTE: this is a changed behaviour since the released 4.1! */ GetStr(&config->ftpport, nextarg); break; case 'p': /* proxy tunnel for non-http protocols */ config->proxytunnel = toggle; break; case 'q': /* if used first, already taken care of, we do it like this so we don't cause an error! */ break; case 'Q': /* QUOTE command to send to FTP server */ switch(nextarg[0]) { case '-': /* prefixed with a dash makes it a POST TRANSFER one */ nextarg++; err = add2list(&config->postquote, nextarg); break; case '+': /* prefixed with a plus makes it a just-before-transfer one */ nextarg++; err = add2list(&config->prequote, nextarg); break; default: err = add2list(&config->quote, nextarg); break; } if(err) return err; break; case 'r': /* Specifying a range WITHOUT A DASH will create an illegal HTTP range (and won't actually be range by definition). The man page previously claimed that to be a good way, why this code is added to work-around it. */ if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { char buffer[32]; curl_off_t off; if(curlx_strtoofft(nextarg, NULL, 10, &off)) { warnf(global, "unsupported range point\n"); return PARAM_BAD_USE; } warnf(global, "A specified range MUST include at least one dash (-). " "Appending one for you!\n"); msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); Curl_safefree(config->range); config->range = strdup(buffer); if(!config->range) return PARAM_NO_MEM; } { /* byte range requested */ const char *tmp_range = nextarg; while(*tmp_range != '\0') { if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { warnf(global, "Invalid character is found in given range. " "A specified range MUST have only digits in " "\'start\'-\'stop\'. The server's response to this " "request is uncertain.\n"); break; } tmp_range++; } /* byte range requested */ GetStr(&config->range, nextarg); } break; case 'R': /* use remote file's time */ config->remote_time = toggle; break; case 's': /* don't show progress meter, don't show errors : */ if(toggle) global->mute = global->noprogress = TRUE; else global->mute = global->noprogress = FALSE; if(global->showerror < 0) /* if still on the default value, set showerror to the reverse of toggle. This is to allow -S and -s to be used in an independent order but still have the same effect. */ global->showerror = (!toggle)?TRUE:FALSE; /* toggle off */ break; case 'S': /* show errors */ global->showerror = toggle?1:0; /* toggle on if used with -s */ break; case 't': /* Telnet options */ err = add2list(&config->telnet_options, nextarg); if(err) return err; break; case 'T': /* we are uploading */ { struct getout *url; if(!config->url_ul) config->url_ul = config->url_list; if(config->url_ul) { /* there's a node here, if it already is filled-in continue to find an "empty" node */ while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD)) config->url_ul = config->url_ul->next; } /* now there might or might not be an available node to fill in! */ if(config->url_ul) /* existing node */ url = config->url_ul; else /* there was no free node, create one! */ config->url_ul = url = new_getout(config); if(!url) return PARAM_NO_MEM; url->flags |= GETOUT_UPLOAD; /* mark -T used */ if(!*nextarg) url->flags |= GETOUT_NOUPLOAD; else { /* "-" equals stdin, but keep the string around for now */ GetStr(&url->infile, nextarg); } } break; case 'u': /* user:password */ GetStr(&config->userpwd, nextarg); cleanarg(nextarg); break; case 'U': /* Proxy user:password */ GetStr(&config->proxyuserpwd, nextarg); cleanarg(nextarg); break; case 'v': if(toggle) { /* the '%' thing here will cause the trace get sent to stderr */ Curl_safefree(global->trace_dump); global->trace_dump = strdup("%"); if(!global->trace_dump) return PARAM_NO_MEM; if(global->tracetype && (global->tracetype != TRACE_PLAIN)) warnf(global, "-v, --verbose overrides an earlier trace/verbose option\n"); global->tracetype = TRACE_PLAIN; } else /* verbose is disabled here */ global->tracetype = TRACE_NONE; break; case 'V': if(toggle) /* --no-version yields no output! */ return PARAM_VERSION_INFO_REQUESTED; break; case 'w': /* get the output string */ if('@' == *nextarg) { /* the data begins with a '@' letter, it means that a file name or - (stdin) follows */ FILE *file; const char *fname; nextarg++; /* pass the @ */ if(!strcmp("-", nextarg)) { fname = ""; file = stdin; } else { fname = nextarg; file = fopen(nextarg, FOPEN_READTEXT); } Curl_safefree(config->writeout); err = file2string(&config->writeout, file); if(file && (file != stdin)) fclose(file); if(err) return err; if(!config->writeout) warnf(global, "Failed to read %s", fname); } else GetStr(&config->writeout, nextarg); break; case 'x': switch(subletter) { case 'a': /* --preproxy */ GetStr(&config->preproxy, nextarg); break; default: /* --proxy */ GetStr(&config->proxy, nextarg); config->proxyver = CURLPROXY_HTTP; break; } break; case 'X': /* set custom request */ GetStr(&config->customrequest, nextarg); break; case 'y': /* low speed time */ err = str2unum(&config->low_speed_time, nextarg); if(err) return err; if(!config->low_speed_limit) config->low_speed_limit = 1; break; case 'Y': /* low speed limit */ err = str2unum(&config->low_speed_limit, nextarg); if(err) return err; if(!config->low_speed_time) config->low_speed_time = 30; break; case 'Z': switch(subletter) { case '\0': /* --parallel */ global->parallel = toggle; break; case 'b': /* --parallel-max */ err = str2unum(&global->parallel_max, nextarg); if(err) return err; if((global->parallel_max > MAX_PARALLEL) || (global->parallel_max < 1)) global->parallel_max = PARALLEL_DEFAULT; break; case 'c': /* --parallel-connect */ global->parallel_connect = toggle; break; } break; case 'z': /* time condition coming up */ switch(*nextarg) { case '+': nextarg++; /* FALLTHROUGH */ default: /* If-Modified-Since: (section 14.28 in RFC2068) */ config->timecond = CURL_TIMECOND_IFMODSINCE; break; case '-': /* If-Unmodified-Since: (section 14.24 in RFC2068) */ config->timecond = CURL_TIMECOND_IFUNMODSINCE; nextarg++; break; case '=': /* Last-Modified: (section 14.29 in RFC2068) */ config->timecond = CURL_TIMECOND_LASTMOD; nextarg++; break; } now = time(NULL); config->condtime = (curl_off_t)curl_getdate(nextarg, &now); if(-1 == config->condtime) { /* now let's see if it is a file name to get the time from instead! */ curl_off_t filetime = getfiletime(nextarg, config->global->errors); if(filetime >= 0) { /* pull the time out from the file */ config->condtime = filetime; } else { /* failed, remove time condition */ config->timecond = CURL_TIMECOND_NONE; warnf(global, "Illegal date format for -z, --time-cond (and not " "a file name). Disabling time condition. " "See curl_getdate(3) for valid date syntax.\n"); } } break; default: /* unknown flag */ return PARAM_OPTION_UNKNOWN; } hit = -1; } while(!longopt && !singleopt && *++parse && !*usedarg); return PARAM_OK; } ParameterError parse_args(struct GlobalConfig *global, int argc, argv_item_t argv[]) { int i; bool stillflags; char *orig_opt = NULL; ParameterError result = PARAM_OK; struct OperationConfig *config = global->first; for(i = 1, stillflags = TRUE; i < argc && !result; i++) { orig_opt = argv[i]; if(stillflags && ('-' == argv[i][0])) { bool passarg; char *flag = argv[i]; if(!strcmp("--", argv[i])) /* This indicates the end of the flags and thus enables the following (URL) argument to start with -. */ stillflags = FALSE; else { char *nextarg = (i < (argc - 1)) ? argv[i + 1] : NULL; result = getparameter(flag, nextarg, &passarg, global, config); if(result == PARAM_NEXT_OPERATION) { /* Reset result as PARAM_NEXT_OPERATION is only used here and not returned from this function */ result = PARAM_OK; if(config->url_list && config->url_list->url) { /* Allocate the next config */ config->next = malloc(sizeof(struct OperationConfig)); if(config->next) { /* Initialise the newly created config */ config_init(config->next); /* Set the global config pointer */ config->next->global = global; /* Update the last config pointer */ global->last = config->next; /* Move onto the new config */ config->next->prev = config; config = config->next; } else result = PARAM_NO_MEM; } } else if(!result && passarg) i++; /* we're supposed to skip this */ } } else { bool used; /* Just add the URL please */ result = getparameter((char *)"--url", argv[i], &used, global, config); } } if(result && result != PARAM_HELP_REQUESTED && result != PARAM_MANUAL_REQUESTED && result != PARAM_VERSION_INFO_REQUESTED && result != PARAM_ENGINES_REQUESTED) { const char *reason = param2text(result); if(orig_opt && strcmp(":", orig_opt)) helpf(global->errors, "option %s: %s\n", orig_opt, reason); else helpf(global->errors, "%s\n", reason); } return result; } davix-0.8.0/deps/curl/src/tool_paramhlp.h0000644000000000000000000000421414121063461017030 0ustar rootroot#ifndef HEADER_CURL_TOOL_PARAMHLP_H #define HEADER_CURL_TOOL_PARAMHLP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" struct getout *new_getout(struct OperationConfig *config); ParameterError file2string(char **bufp, FILE *file); ParameterError file2memory(char **bufp, size_t *size, FILE *file); void cleanarg(char *str); ParameterError str2num(long *val, const char *str); ParameterError str2unum(long *val, const char *str); ParameterError str2unummax(long *val, const char *str, long max); ParameterError str2udouble(double *val, const char *str, long max); long proto2num(struct OperationConfig *config, long *val, const char *str); int check_protocol(const char *str); ParameterError str2offset(curl_off_t *val, const char *str); CURLcode get_args(struct OperationConfig *config, const size_t i); ParameterError add2list(struct curl_slist **list, const char *ptr); int ftpfilemethod(struct OperationConfig *config, const char *str); int ftpcccmethod(struct OperationConfig *config, const char *str); long delegation(struct OperationConfig *config, const char *str); ParameterError str2tls_max(long *val, const char *str); #endif /* HEADER_CURL_TOOL_PARAMHLP_H */ davix-0.8.0/deps/curl/src/tool_cb_rea.h0000644000000000000000000000274614121063461016447 0ustar rootroot#ifndef HEADER_CURL_TOOL_CB_REA_H #define HEADER_CURL_TOOL_CB_REA_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" /* ** callback for CURLOPT_READFUNCTION */ size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); /* ** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads */ int tool_readbusy_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); #endif /* HEADER_CURL_TOOL_CB_REA_H */ davix-0.8.0/deps/curl/src/tool_formparse.h0000644000000000000000000000550514121063461017226 0ustar rootroot#ifndef HEADER_CURL_TOOL_FORMPARSE_H #define HEADER_CURL_TOOL_FORMPARSE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" /* Private structure for mime/parts. */ typedef enum { TOOLMIME_NONE = 0, TOOLMIME_PARTS, TOOLMIME_DATA, TOOLMIME_FILE, TOOLMIME_FILEDATA, TOOLMIME_STDIN, TOOLMIME_STDINDATA } toolmimekind; typedef struct tool_mime tool_mime; struct tool_mime { /* Structural fields. */ toolmimekind kind; /* Part kind. */ tool_mime *parent; /* Parent item. */ tool_mime *prev; /* Previous sibling (reverse order link). */ /* Common fields. */ const char *data; /* Actual data or data filename. */ const char *name; /* Part name. */ const char *filename; /* Part's filename. */ const char *type; /* Part's mime type. */ const char *encoder; /* Part's requested encoding. */ struct curl_slist *headers; /* User-defined headers. */ /* TOOLMIME_PARTS fields. */ tool_mime *subparts; /* Part's subparts. */ /* TOOLMIME_STDIN/TOOLMIME_STDINDATA fields. */ curl_off_t origin; /* Stdin read origin offset. */ curl_off_t size; /* Stdin data size. */ curl_off_t curpos; /* Stdin current read position. */ struct GlobalConfig *config; /* For access from callback. */ }; size_t tool_mime_stdin_read(char *buffer, size_t size, size_t nitems, void *arg); int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence); int formparse(struct OperationConfig *config, const char *input, tool_mime **mimeroot, tool_mime **mimecurrent, bool literal_value); CURLcode tool2curlmime(CURL *curl, tool_mime *m, curl_mime **mime); void tool_mime_free(tool_mime *mime); #endif /* HEADER_CURL_TOOL_FORMPARSE_H */ davix-0.8.0/deps/curl/src/tool_filetime.c0000644000000000000000000001301114121063461017010 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_filetime.h" #ifdef HAVE_UTIME_H # include #elif defined(HAVE_SYS_UTIME_H) # include #endif curl_off_t getfiletime(const char *filename, FILE *error_stream) { curl_off_t result = -1; /* Windows stat() may attempt to adjust the unix GMT file time by a daylight saving time offset and since it's GMT that is bad behavior. When we have access to a 64-bit type we can bypass stat and get the times directly. */ #if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8) HANDLE hfile; hfile = CreateFileA(filename, FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, NULL); if(hfile != INVALID_HANDLE_VALUE) { FILETIME ft; if(GetFileTime(hfile, NULL, NULL, &ft)) { curl_off_t converted = (curl_off_t)ft.dwLowDateTime | ((curl_off_t)ft.dwHighDateTime) << 32; if(converted < CURL_OFF_T_C(116444736000000000)) { fprintf(error_stream, "Failed to get filetime: underflow\n"); } else { result = (converted - CURL_OFF_T_C(116444736000000000)) / 10000000; } } else { fprintf(error_stream, "Failed to get filetime: " "GetFileTime failed: GetLastError %u\n", (unsigned int)GetLastError()); } CloseHandle(hfile); } else if(GetLastError() != ERROR_FILE_NOT_FOUND) { fprintf(error_stream, "Failed to get filetime: " "CreateFile failed: GetLastError %u\n", (unsigned int)GetLastError()); } #else struct_stat statbuf; if(-1 != stat(filename, &statbuf)) { result = (curl_off_t)statbuf.st_mtime; } else if(errno != ENOENT) { fprintf(error_stream, "Failed to get filetime: %s\n", strerror(errno)); } #endif return result; } #if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) void setfiletime(curl_off_t filetime, const char *filename, FILE *error_stream) { if(filetime >= 0) { /* Windows utime() may attempt to adjust the unix GMT file time by a daylight saving time offset and since it's GMT that is bad behavior. When we have access to a 64-bit type we can bypass utime and set the times directly. */ #if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8) HANDLE hfile; /* 910670515199 is the maximum unix filetime that can be used as a Windows FILETIME without overflow: 30827-12-31T23:59:59. */ if(filetime > CURL_OFF_T_C(910670515199)) { fprintf(error_stream, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T " on outfile: overflow\n", filetime); return; } hfile = CreateFileA(filename, FILE_WRITE_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, NULL); if(hfile != INVALID_HANDLE_VALUE) { curl_off_t converted = ((curl_off_t)filetime * 10000000) + CURL_OFF_T_C(116444736000000000); FILETIME ft; ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF); ft.dwHighDateTime = (DWORD)(converted >> 32); if(!SetFileTime(hfile, NULL, &ft, &ft)) { fprintf(error_stream, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T " on outfile: SetFileTime failed: GetLastError %u\n", filetime, (unsigned int)GetLastError()); } CloseHandle(hfile); } else { fprintf(error_stream, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T " on outfile: CreateFile failed: GetLastError %u\n", filetime, (unsigned int)GetLastError()); } #elif defined(HAVE_UTIMES) struct timeval times[2]; times[0].tv_sec = times[1].tv_sec = (time_t)filetime; times[0].tv_usec = times[1].tv_usec = 0; if(utimes(filename, times)) { fprintf(error_stream, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T " on outfile: %s\n", filetime, strerror(errno)); } #elif defined(HAVE_UTIME) struct utimbuf times; times.actime = (time_t)filetime; times.modtime = (time_t)filetime; if(utime(filename, ×)) { fprintf(error_stream, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T " on outfile: %s\n", filetime, strerror(errno)); } #endif } } #endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */ davix-0.8.0/deps/curl/src/tool_sleep.c0000644000000000000000000000320014121063461016321 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_POLL_H # include #elif defined(HAVE_SYS_POLL_H) # include #endif #ifdef MSDOS # include #endif #include "tool_sleep.h" #include "memdebug.h" /* keep this as LAST include */ void tool_go_sleep(long ms) { #if defined(MSDOS) delay(ms); #elif defined(WIN32) Sleep(ms); #elif defined(HAVE_POLL_FINE) (void)poll((void *)0, 0, (int)ms); #else struct timeval timeout; timeout.tv_sec = ms / 1000L; ms = ms % 1000L; timeout.tv_usec = (int)ms * 1000; select(0, NULL, NULL, NULL, &timeout); #endif } davix-0.8.0/deps/curl/src/tool_hugehelp.h0000644000000000000000000000224214121063461017024 0ustar rootroot#ifndef HEADER_CURL_TOOL_HUGEHELP_H #define HEADER_CURL_TOOL_HUGEHELP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" void hugehelp(void); #endif /* HEADER_CURL_TOOL_HUGEHELP_H */ davix-0.8.0/deps/curl/src/tool_helpers.h0000644000000000000000000000260114121063461016664 0ustar rootroot#ifndef HEADER_CURL_TOOL_HELPERS_H #define HEADER_CURL_TOOL_HELPERS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" const char *param2text(int res); int SetHTTPrequest(struct OperationConfig *config, HttpReq req, HttpReq *store); void customrequest_helper(struct OperationConfig *config, HttpReq req, char *method); #endif /* HEADER_CURL_TOOL_HELPERS_H */ davix-0.8.0/deps/curl/src/tool_cb_dbg.c0000644000000000000000000002052014121063461016415 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" #include "tool_cfgable.h" #include "tool_convert.h" #include "tool_msgs.h" #include "tool_cb_dbg.h" #include "tool_util.h" #include "memdebug.h" /* keep this as LAST include */ static void dump(const char *timebuf, const char *text, FILE *stream, const unsigned char *ptr, size_t size, trace tracetype, curl_infotype infotype); /* ** callback for CURLOPT_DEBUGFUNCTION */ int tool_debug_cb(CURL *handle, curl_infotype type, char *data, size_t size, void *userdata) { struct OperationConfig *operation = userdata; struct GlobalConfig *config = operation->global; FILE *output = config->errors; const char *text; struct timeval tv; char timebuf[20]; time_t secs; (void)handle; /* not used */ if(config->tracetime) { struct tm *now; static time_t epoch_offset; static int known_offset; tv = tvnow(); if(!known_offset) { epoch_offset = time(NULL) - tv.tv_sec; known_offset = 1; } secs = epoch_offset + tv.tv_sec; now = localtime(&secs); /* not thread safe but we don't care */ msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ", now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); } else timebuf[0] = 0; if(!config->trace_stream) { /* open for append */ if(!strcmp("-", config->trace_dump)) config->trace_stream = stdout; else if(!strcmp("%", config->trace_dump)) /* Ok, this is somewhat hackish but we do it undocumented for now */ config->trace_stream = config->errors; /* aka stderr */ else { config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT); config->trace_fopened = TRUE; } } if(config->trace_stream) output = config->trace_stream; if(!output) { warnf(config, "Failed to create/open output"); return 0; } if(config->tracetype == TRACE_PLAIN) { /* * This is the trace look that is similar to what libcurl makes on its * own. */ static const char * const s_infotype[] = { "*", "<", ">", "{", "}", "{", "}" }; static bool newl = FALSE; static bool traced_data = FALSE; switch(type) { case CURLINFO_HEADER_OUT: if(size > 0) { size_t st = 0; size_t i; for(i = 0; i < size - 1; i++) { if(data[i] == '\n') { /* LF */ if(!newl) { fprintf(output, "%s%s ", timebuf, s_infotype[type]); } (void)fwrite(data + st, i - st + 1, 1, output); st = i + 1; newl = FALSE; } } if(!newl) fprintf(output, "%s%s ", timebuf, s_infotype[type]); (void)fwrite(data + st, i - st + 1, 1, output); } newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; traced_data = FALSE; break; case CURLINFO_TEXT: case CURLINFO_HEADER_IN: if(!newl) fprintf(output, "%s%s ", timebuf, s_infotype[type]); (void)fwrite(data, size, 1, output); newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; traced_data = FALSE; break; case CURLINFO_DATA_OUT: case CURLINFO_DATA_IN: case CURLINFO_SSL_DATA_IN: case CURLINFO_SSL_DATA_OUT: if(!traced_data) { /* if the data is output to a tty and we're sending this debug trace to stderr or stdout, we don't display the alert about the data not being shown as the data _is_ shown then just not via this function */ if(!config->isatty || ((output != stderr) && (output != stdout))) { if(!newl) fprintf(output, "%s%s ", timebuf, s_infotype[type]); fprintf(output, "[%zu bytes data]\n", size); newl = FALSE; traced_data = TRUE; } } break; default: /* nada */ newl = FALSE; traced_data = FALSE; break; } return 0; } #ifdef CURL_DOES_CONVERSIONS /* Special processing is needed for CURLINFO_HEADER_OUT blocks * if they contain both headers and data (separated by CRLFCRLF). * We dump the header text and then switch type to CURLINFO_DATA_OUT. */ if((type == CURLINFO_HEADER_OUT) && (size > 4)) { size_t i; for(i = 0; i < size - 4; i++) { if(memcmp(&data[i], "\r\n\r\n", 4) == 0) { /* dump everything through the CRLFCRLF as a sent header */ text = "=> Send header"; dump(timebuf, text, output, (unsigned char *)data, i + 4, config->tracetype, type); data += i + 3; size -= i + 4; type = CURLINFO_DATA_OUT; data += 1; break; } } } #endif /* CURL_DOES_CONVERSIONS */ switch(type) { case CURLINFO_TEXT: fprintf(output, "%s== Info: %s", timebuf, data); /* FALLTHROUGH */ default: /* in case a new one is introduced to shock us */ return 0; case CURLINFO_HEADER_OUT: text = "=> Send header"; break; case CURLINFO_DATA_OUT: text = "=> Send data"; break; case CURLINFO_HEADER_IN: text = "<= Recv header"; break; case CURLINFO_DATA_IN: text = "<= Recv data"; break; case CURLINFO_SSL_DATA_IN: text = "<= Recv SSL data"; break; case CURLINFO_SSL_DATA_OUT: text = "=> Send SSL data"; break; } dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype, type); return 0; } static void dump(const char *timebuf, const char *text, FILE *stream, const unsigned char *ptr, size_t size, trace tracetype, curl_infotype infotype) { size_t i; size_t c; unsigned int width = 0x10; if(tracetype == TRACE_ASCII) /* without the hex output, we can fit more on screen */ width = 0x40; fprintf(stream, "%s%s, %zu bytes (0x%zx)\n", timebuf, text, size, size); for(i = 0; i < size; i += width) { fprintf(stream, "%04zx: ", i); if(tracetype == TRACE_BIN) { /* hex not disabled, show it */ for(c = 0; c < width; c++) if(i + c < size) fprintf(stream, "%02x ", ptr[i + c]); else fputs(" ", stream); } for(c = 0; (c < width) && (i + c < size); c++) { /* check for 0D0A; if found, skip past and start a new line of output */ if((tracetype == TRACE_ASCII) && (i + c + 1 < size) && (ptr[i + c] == 0x0D) && (ptr[i + c + 1] == 0x0A)) { i += (c + 2 - width); break; } #ifdef CURL_DOES_CONVERSIONS /* repeat the 0D0A check above but use the host encoding for CRLF */ if((tracetype == TRACE_ASCII) && (i + c + 1 < size) && (ptr[i + c] == '\r') && (ptr[i + c + 1] == '\n')) { i += (c + 2 - width); break; } /* convert to host encoding and print this character */ fprintf(stream, "%c", convert_char(infotype, ptr[i + c])); #else (void)infotype; fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80)) ? ptr[i + c] : UNPRINTABLE_CHAR); #endif /* CURL_DOES_CONVERSIONS */ /* check again for 0D0A, to avoid an extra \n if it's at width */ if((tracetype == TRACE_ASCII) && (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) && (ptr[i + c + 2] == 0x0A)) { i += (c + 3 - width); break; } } fputc('\n', stream); /* newline */ } fflush(stream); } davix-0.8.0/deps/curl/src/tool_getparam.h0000644000000000000000000000424314121063461017026 0ustar rootroot#ifndef HEADER_CURL_TOOL_GETPARAM_H #define HEADER_CURL_TOOL_GETPARAM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" typedef enum { PARAM_OK = 0, PARAM_OPTION_AMBIGUOUS, PARAM_OPTION_UNKNOWN, PARAM_REQUIRES_PARAMETER, PARAM_BAD_USE, PARAM_HELP_REQUESTED, PARAM_MANUAL_REQUESTED, PARAM_VERSION_INFO_REQUESTED, PARAM_ENGINES_REQUESTED, PARAM_GOT_EXTRA_PARAMETER, PARAM_BAD_NUMERIC, PARAM_NEGATIVE_NUMERIC, PARAM_LIBCURL_DOESNT_SUPPORT, PARAM_LIBCURL_UNSUPPORTED_PROTOCOL, PARAM_NO_MEM, PARAM_NEXT_OPERATION, PARAM_NO_PREFIX, PARAM_NUMBER_TOO_LARGE, PARAM_NO_NOT_BOOLEAN, PARAM_LAST } ParameterError; struct GlobalConfig; struct OperationConfig; ParameterError getparameter(const char *flag, char *nextarg, bool *usedarg, struct GlobalConfig *global, struct OperationConfig *operation); #ifdef UNITTESTS void parse_cert_parameter(const char *cert_parameter, char **certname, char **passphrase); #endif ParameterError parse_args(struct GlobalConfig *config, int argc, argv_item_t argv[]); #endif /* HEADER_CURL_TOOL_GETPARAM_H */ davix-0.8.0/deps/curl/src/Makefile.m320000644000000000000000000002505614121063461016065 0ustar rootroot#*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | # / __| | | | |_) | | # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # # Copyright (C) 1999 - 2018, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://curl.haxx.se/docs/copyright.html. # # You may opt to use, copy, modify, merge, publish, distribute and/or sell # copies of the Software, and permit persons to whom the Software is # furnished to do so, under the terms of the COPYING file. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # #*************************************************************************** ########################################################################### # ## Makefile for building curl.exe with MingW (GCC-3.2 or later or LLVM/Clang) ## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4), ## brotli (1.0.1) ## ## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn ## ## Hint: you can also set environment vars to control the build, f.e.: ## set ZLIB_PATH=c:/zlib-1.2.8 ## set ZLIB=1 # ########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH ZLIB_PATH = ../../zlib-1.2.8 endif # Edit the path below to point to the base of your Brotli sources. ifndef BROTLI_PATH BROTLI_PATH = ../../brotli-1.0.1 endif # Edit the path below to point to the base of your OpenSSL package. ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-1.0.2a endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH LIBSSH2_PATH = ../../libssh2-1.5.0 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.4 endif # Edit the path below to point to the base of your libmetalink package. ifndef LIBMETALINK_PATH LIBMETALINK_PATH = ../../libmetalink-0.1.3 endif # Edit the path below to point to the base of your libexpat package. ifndef LIBEXPAT_PATH LIBEXPAT_PATH = ../../expat-2.1.0 endif # Edit the path below to point to the base of your libxml2 package. ifndef LIBXML2_PATH LIBXML2_PATH = ../../libxml2-2.9.2 endif # Edit the path below to point to the base of your libidn2 package. ifndef LIBIDN2_PATH LIBIDN2_PATH = ../../libidn2-2.0.3 endif # Edit the path below to point to the base of your MS IDN package. # Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 # https://www.microsoft.com/en-us/download/details.aspx?id=734 ifndef WINIDN_PATH WINIDN_PATH = ../../Microsoft IDN Mitigation APIs endif # Edit the path below to point to the base of your Novell LDAP NDK. ifndef LDAP_SDK LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif # Edit the path below to point to the base of your nghttp2 package. ifndef NGHTTP2_PATH NGHTTP2_PATH = ../../nghttp2-1.0.0 endif PROOT = .. # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = $(PROOT)/ares endif ifeq ($(CURL_CC),) CURL_CC := $(CROSSPREFIX)gcc endif ifeq ($(CURL_AR),) CURL_AR := $(CROSSPREFIX)ar endif CC = $(CURL_CC) CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W CFLAGS += -fno-strict-aliasing # comment LDFLAGS below to keep debug info LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_EXE) -s AR = $(CURL_AR) RC = $(CROSSPREFIX)windres RCFLAGS = --include-dir=$(PROOT)/include -O COFF -DCURL_EMBED_MANIFEST STRIP = $(CROSSPREFIX)strip -g # We may need these someday # PERL = perl # NROFF = nroff # Set environment var ARCH to your architecture to override autodetection. ifndef ARCH ifeq ($(findstring x86_64,$(shell $(CC) -dumpmachine)),x86_64) ARCH = w64 else ARCH = w32 endif endif ifeq ($(ARCH),w64) CFLAGS += -m64 -D_AMD64_ LDFLAGS += -m64 RCFLAGS += -F pe-x86-64 else CFLAGS += -m32 LDFLAGS += -m32 RCFLAGS += -F pe-i386 endif # Platform-dependent helper tool macros ifeq ($(findstring /sh,$(SHELL)),/sh) DEL = rm -f $1 RMDIR = rm -fr $1 MKDIR = mkdir -p $1 COPY = -cp -afv $1 $2 #COPYR = -cp -afr $1/* $2 COPYR = -rsync -aC $1/* $2 TOUCH = touch $1 CAT = cat ECHONL = echo "" DL = ' else ifeq "$(OS)" "Windows_NT" DEL = -del 2>NUL /q /f $(subst /,\,$1) RMDIR = -rd 2>NUL /q /s $(subst /,\,$1) else DEL = -del 2>NUL $(subst /,\,$1) RMDIR = -deltree 2>NUL /y $(subst /,\,$1) endif MKDIR = -md 2>NUL $(subst /,\,$1) COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2) COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2) TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,, CAT = type ECHONL = $(ComSpec) /c echo. endif ######################################################## ## Nothing more to do below this line! ifeq ($(findstring -dyn,$(CFG)),-dyn) DYN = 1 endif ifeq ($(findstring -ares,$(CFG)),-ares) ARES = 1 endif ifeq ($(findstring -sync,$(CFG)),-sync) SYNC = 1 endif ifeq ($(findstring -rtmp,$(CFG)),-rtmp) RTMP = 1 SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssh2,$(CFG)),-ssh2) SSH2 = 1 SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssl,$(CFG)),-ssl) SSL = 1 endif ifeq ($(findstring -zlib,$(CFG)),-zlib) ZLIB = 1 endif ifeq ($(findstring -brotli,$(CFG)),-brotli) BROTLI = 1 endif ifeq ($(findstring -idn2,$(CFG)),-idn2) IDN2 = 1 endif ifeq ($(findstring -winidn,$(CFG)),-winidn) WINIDN = 1 endif ifeq ($(findstring -sspi,$(CFG)),-sspi) SSPI = 1 endif ifeq ($(findstring -ldaps,$(CFG)),-ldaps) LDAPS = 1 endif ifeq ($(findstring -ipv6,$(CFG)),-ipv6) IPV6 = 1 endif ifeq ($(findstring -metalink,$(CFG)),-metalink) METALINK = 1 endif ifeq ($(findstring -winssl,$(CFG)),-winssl) WINSSL = 1 SSPI = 1 endif ifeq ($(findstring -nghttp2,$(CFG)),-nghttp2) NGHTTP2 = 1 endif INCLUDES = -I. -I../include -I../lib ifdef SSL ifdef WINSSL CFLAGS += -DCURL_WITH_MULTI_SSL endif endif ifdef DYN curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll curl_LDADD = -L$(PROOT)/lib -lcurldll else curl_DEPENDENCIES = $(PROOT)/lib/libcurl.a curl_LDADD = -L$(PROOT)/lib -lcurl CFLAGS += -DCURL_STATICLIB LDFLAGS += -static endif ifdef SYNC CFLAGS += -DUSE_SYNC_DNS else ifdef ARES ifndef DYN curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a endif CFLAGS += -DUSE_ARES -DCARES_STATICLIB curl_LDADD += -L"$(LIBCARES_PATH)" -lcares endif endif ifdef RTMP CFLAGS += -DUSE_LIBRTMP curl_LDADD += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm endif ifdef NGHTTP2 CFLAGS += -DUSE_NGHTTP2 curl_LDADD += -L"$(NGHTTP2_PATH)/lib" -lnghttp2 endif ifdef SSH2 CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2 ifdef WINSSL ifndef DYN curl_LDADD += -lbcrypt -lcrypt32 endif endif endif ifdef SSL ifndef OPENSSL_INCLUDE ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc" OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc endif ifeq "$(wildcard $(OPENSSL_PATH)/include)" "$(OPENSSL_PATH)/include" OPENSSL_INCLUDE = $(OPENSSL_PATH)/include endif endif ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h" $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) endif ifndef OPENSSL_LIBPATH OPENSSL_LIBS = -lssl -lcrypto ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out" OPENSSL_LIBPATH = $(OPENSSL_PATH)/out ifdef DYN OPENSSL_LIBS = -lssl32 -leay32 endif endif ifeq "$(wildcard $(OPENSSL_PATH)/lib)" "$(OPENSSL_PATH)/lib" OPENSSL_LIBPATH = $(OPENSSL_PATH)/lib endif endif ifndef DYN OPENSSL_LIBS += -lgdi32 -lcrypt32 endif INCLUDES += -I"$(OPENSSL_INCLUDE)" CFLAGS += -DUSE_OPENSSL curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) endif ifdef WINSSL CFLAGS += -DUSE_SCHANNEL curl_LDADD += -lcrypt32 endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H curl_LDADD += -L"$(ZLIB_PATH)" -lz endif ifdef BROTLI INCLUDES += -I"$(BROTLI_PATH)/include" CFLAGS += -DHAVE_BROTLI curl_LDADD += -L"$(BROTLI_PATH)/lib" ifdef BROTLI_LIBS curl_LDADD += $(BROTLI_LIBS) else curl_LDADD += -lbrotlidec endif endif ifdef IDN2 CFLAGS += -DUSE_LIBIDN2 curl_LDADD += -L"$(LIBIDN2_PATH)/lib" -lidn2 else ifdef WINIDN CFLAGS += -DUSE_WIN32_IDN curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz endif endif ifdef METALINK INCLUDES += -I"$(LIBMETALINK_PATH)/include" CFLAGS += -DUSE_METALINK curl_LDADD += -L"$(LIBMETALINK_PATH)/lib" -lmetalink ifndef DYN ifeq ($(findstring libexpat_metalink_parser.o,$(shell $(AR) t "$(LIBMETALINK_PATH)/lib/libmetalink.a")),libexpat_metalink_parser.o) curl_LDADD += -L"$(LIBEXPAT_PATH)/lib" -lexpat else curl_LDADD += -L"$(LIBXML2_PATH)/lib" -lxml2 endif endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif ifdef IPV6 CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL endif ifdef USE_LDAP_NOVELL CFLAGS += -DCURL_HAS_NOVELL_LDAPSDK curl_LDADD += -L"$(LDAP_SDK)/lib/mscvc" -lldapsdk -lldapssl -lldapx endif ifdef USE_LDAP_OPENLDAP CFLAGS += -DCURL_HAS_OPENLDAP_LDAPSDK curl_LDADD += -L"$(LDAP_SDK)/lib" -lldap -llber endif ifndef USE_LDAP_NOVELL ifndef USE_LDAP_OPENLDAP curl_LDADD += -lwldap32 endif endif curl_LDADD += -lws2_32 # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc curl_PROGRAMS = curl.exe curl_OBJECTS := $(patsubst %.c,%.o,$(strip $(CURL_CFILES))) curlx_OBJECTS := $(patsubst %.c,%.o,$(notdir $(strip $(CURLX_CFILES)))) ifdef DYN curl_OBJECTS += $(curlx_OBJECTS) vpath %.c $(PROOT)/lib endif RESOURCE = curl.res all: $(curl_PROGRAMS) curl.exe: $(RESOURCE) $(curl_OBJECTS) $(curl_DEPENDENCIES) $(call DEL, $@) $(CC) $(LDFLAGS) -o $@ $< $(curl_OBJECTS) $(curl_LDADD) # We don't have nroff normally under win32 # tool_hugehelp.c: $(PROOT)/docs/MANUAL $(PROOT)/docs/curl.1 mkhelp.pl # @$(call DEL, tool_hugehelp.c) # $(NROFF) -man $(PROOT)/docs/curl.1 | $(PERL) mkhelp.pl $(PROOT)/docs/MANUAL > tool_hugehelp.c tool_hugehelp.c: @echo Creating $@ @$(call COPY, $@.cvs, $@) %.o: %.c $(CC) $(INCLUDES) $(CFLAGS) -c $< %.res: %.rc $(RC) $(RCFLAGS) -i $< -o $@ clean: ifeq "$(wildcard tool_hugehelp.c.cvs)" "tool_hugehelp.c.cvs" @$(call DEL, tool_hugehelp.c) endif @$(call DEL, $(curl_OBJECTS) $(curlx_OBJECTS) $(RESOURCE)) distclean vclean: clean @$(call DEL, $(curl_PROGRAMS)) davix-0.8.0/deps/curl/src/macos/0000755000000000000000000000000014121063461015117 5ustar rootrootdavix-0.8.0/deps/curl/src/macos/MACINSTALL.TXT0000644000000000000000000000331014121063461017144 0ustar rootrootMACOS (not MACOS X) =================== This is the first attempt at porting curl to MacOS. http, ftp, dict and telnet seems to work fine, other protocols and advanced features have not been all tested. This port is heavily based on the GUSI library from Matthias Neeracher. GUSI (Grand Unified Socket Interface) is a POSIX/Pthreads/Sockets library bringing some of the comforts of UNIX 98 to traditional MacOS. The latest GUSI release can be downloaded from sourceforge at I have also written a few functions to help port Unix applications to MacOS. These functions are part of the GUSI Extra library that can be downloaded at OpenSSL support is still experimental but I hope to deliver a version including SSL soon. curl for MacOS requires using the CodeWarrior compiler from Metrowerks. First download GUSI, GUSI Extra and curl. Access paths have been setup so that GUSI, GUSI Extra and curl directories should have the same parent directory. Follow the instructions in GUSI Extra "readme.txt" mainly the ones related to SIOUX and GUSI patches. If you do not apply these patches curl will not behave correctly. In the 'curl/src/macos' directory, decode "curl.mcp.xml.sit.hqx" (This is a stuffit binhexed file) From the CodeWarrior IDE, import 'curl/src/macos/curl.xml', adjust the access paths if required. Then you should be able to build: - the libcurl libraries for PPC and 68K. - the curl application (also available for PPC and 68K) which is the command line version of curl. If the file "tool_hugehelp.c" is missing rename "curl/src/tool_hugehelp.c.cvs" to "tool_hugehelp.c" and make sure its file type is 'TEXT' davix-0.8.0/deps/curl/src/macos/src/0000755000000000000000000000000014121063461015706 5ustar rootrootdavix-0.8.0/deps/curl/src/macos/src/curl_GUSIConfig.cpp0000644000000000000000000000333214121063461021335 0ustar rootroot/**************** BEGIN GUSI CONFIGURATION **************************** * * GUSI Configuration section generated by GUSI Configurator * last modified: Mon Oct 29 15:41:51 2001 * * This section will be overwritten by the next run of Configurator. */ #define GUSI_SOURCE #include #include /* Declarations of Socket Factories */ __BEGIN_DECLS void GUSIwithInetSockets(); void GUSIwithLocalSockets(); void GUSIwithMTInetSockets(); void GUSIwithMTTcpSockets(); void GUSIwithMTUdpSockets(); void GUSIwithOTInetSockets(); void GUSIwithOTTcpSockets(); void GUSIwithOTUdpSockets(); void GUSIwithPPCSockets(); void GUSISetupFactories(); __END_DECLS /* Configure Socket Factories */ void GUSISetupFactories() { #ifdef GUSISetupFactories_BeginHook GUSISetupFactories_BeginHook #endif GUSIwithInetSockets(); #ifdef GUSISetupFactories_EndHook GUSISetupFactories_EndHook #endif } /* Declarations of File Devices */ __BEGIN_DECLS void GUSIwithNullSockets(); void GUSISetupDevices(); __END_DECLS /* Configure File Devices */ void GUSISetupDevices() { #ifdef GUSISetupDevices_BeginHook GUSISetupDevices_BeginHook #endif GUSIwithNullSockets(); #ifdef GUSISetupDevices_EndHook GUSISetupDevices_EndHook #endif } #ifndef __cplusplus #error GUSISetupConfig() needs to be written in C++ #endif GUSIConfiguration::FileSuffix sSuffices[] = { "", '????', '????' }; extern "C" void GUSISetupConfig() { GUSIConfiguration * config = GUSIConfiguration::CreateInstance(GUSIConfiguration::kNoResource); config->ConfigureDefaultTypeCreator('TEXT', 'CWIE'); config->ConfigureSuffices( sizeof(sSuffices)/sizeof(GUSIConfiguration::FileSuffix)-1, sSuffices); } /**************** END GUSI CONFIGURATION *************************/ davix-0.8.0/deps/curl/src/macos/src/macos_main.cpp0000644000000000000000000000243214121063461020521 0ustar rootroot/* ========================================================================= Copyright (C) 2001 Eric Lavigne Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: - The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. - The origin of this software must not be misrepresented, either by explicit claim or by omission. - You are allowed to distributed modified copies of the software, in source and binary form, provided they are marked plainly as altered versions, and are not misrepresented as being the original software. ========================================================================= */ #include #include #include #include #include #include /* ========================================================================= */ DECLARE_MAIN(curl) REGISTER_MAIN_START REGISTER_MAIN(curl) REGISTER_MAIN_END /* ========================================================================= */ int main() { ::MaxApplZone(); for (int i = 1; i <= 10; i++) ::MoreMasters(); (void) exec_commands(); return 0; } davix-0.8.0/deps/curl/src/macos/curl.mcp.xml.sit.hqx0000644000000000000000000002332614121063461020767 0ustar rootroot(This file must be converted with BinHex 4.0) :%'0eFQ`ZE@0`,RKYE#jcDA3!8dP8090*9#%!N!3F@`#3")EF8h4eCQC*G#!SBbN a16Nh,6)`-$%J3@aKC'4TEL"6HA0dC@ec,#"*EQ-Z,#"SG(4`1Lm[Gj!$,Q&XB@4 ND@jcHA-ZBfpY,e0dG@CQ5A3[$3SD!!83!!!F@`#3!h)!!3#3!h)0,`fPT9*PFf9 bGQ9NTD8!TC!%!3!!2!!3Z$+T+EJbU5N!N!d-['F!"*UP!!!E'J#3"!m!Bh9bE#j YBh!ZH'eX!!%`!P4&@&4$9dP&!3$rN!3!N!U!!*!*!CS!N!0K!*!%$`"#`G6)[bB "`A,RBHAV3f@ZJUhAq'5,9!EjE+@0l9R9ECKR4kTRRh2Tr@@VMJ"@0,FaU4R&FMa LBT)4LbVeb+BC%jqHQQI4[fPBGXP3'T4BeHdDm#H-`9$4'EUJEJ186cE)3X(8K-U 1KiJ4+5-HVi0DI[@5XBTQHb300K2--ZQmjPHEfdA)NhXMSJc'A+@kemq4P`'SeCB TD8QEYXMK8Kk4YZRkc1,G%m39"[dp8Zmc'[eKd,jpTVh555HQXd2`S9"KrGB`laE (r+!)8r8DP'9kbYVQeY-aSjVQRA2k-`'2pqTr9EP6Z&H-%4eK4@qp1Z(fDAd1&`A H1IYG&T86QUHmp*%cdr$@G4fJrQ[9'8p)f"FPKmMQH6!kGBGeTA5Im1Pp*(P69-* b8ld+I'KQIH`@CNfcIEGE&Zbb`3f,4IkZ#4Ve"2%R-a#MLYefeG"*FSMj,RD`aaE DHh6$h8hF"r`SK84RjI*$KFfI&J3ZTk"r!J2$Nr#%K(IA803e(bAG645j1231E'$ C5$(Nr9Z2LZbqJPSH&9[h1(,+e"8!I$4XKrIeH6Y"")PlSQG2V4#-hZAbb2jBT25 (IUG-bFQ+0[bbfAlrpIDlpCradaS5G(*4d%[i*ISQ&5*3e$NVT#A+!Y3P%V*@HX9 6AGI"h1N`D@lj56PX8fB95NekUL&lk'15a*Z(38rC`Ii%$Y$E-A"!QfHG(Ed)Uhd $e&Ckrm4jfVikK&j$D[%H)*lGX!FUK'&[Ck*%#lJUT9qiT13X#T4mK2)e"`%-JFe )*)Sa9b+92'@Gb8N6d9E+kJ#VEA(c6+d`%E82FXcNKJYM'a,FD@Jf-Bhe0i+B2b' 4,T!!lq1IYLpFITlMfGiYPc0f$6,+MDV5TI9#X-SpJhU%)Fb8cp2EjaJ6Y-)DC*f e'FGC5B'BdQV'H!@cS`XJID*-@m3!EFmNq*Ve20Pc0%pLrF4I`MH*iE!bAI`TJ6f fIkZ$4)P"bTla%@'ZL"8pmd(L(R3XEa8KPe@FkheL$l%E1UF89BS&afbE`RN#pXJ IUFD+"e#6RG6PSV[,G0B8l,Ipa2UU$4a@eA6jr+8Y,jkA1f9)d0!)UcD8pc1PCaS $4e#PcC8bCKD'Ar-2Yr"-%XLQh@AF!9p6rj`FhAk@,R*F(2h!LB#ca(F'im+pi,L Bf4LJV+icK26r2XR2)q9fr#K3PQ3PU)3V#9KqDVJL&pEb*`f)lAAq9FdpFU[$8N6 H43&)*h$BNrd0,c(!ICCA2Nh-i-b#,A9)Dq6b0QXcb4Cb)HG0c,H"E8"bQ0V82+K (6bpND%LUfp6S(mNAhkhHBJTdab-6GA&I%2cqe4`NjKlSpKDmI6m!h0,h!`LC-2j pCCGeT6#1Y62eS"hVZBAlj!YPi8DS1XV14b!3d)r5Z1C(*KTB'Df3!+cZN!#aJMU am2DQK54epTl55RJcT[d$'Q5Me1@)lDI#N6S,Rb-#2%BpdZePl2&DZb9GH)-0FR` 3N!!5&mlD,Sp)"5ZC2f@E-bpUflPTaUfFJ4mZUlcp#`iNNNl#eBaVI1&m0!dP'F[ lT`UUYVZpKX&HPmBMVf"+'fS0*6pRfA+HccXLd0PXk",eKDrh`@MYIGqm(MRcMcP UCb#C$m'[dhBrb438Hbh4+bDe&0"BSF1P+PPP4@i`%iP22P9ibJHTcBXRN5!leUL LkN%bVNT!r-qGI('DMAp8jc1e[eH9VBp1+DSk0V(-aMaJD(6FHQ+T'%'h8"e3LeY *2ldFPa@Tem)!l+PBLXN#idPfFC0i-V-9Ed2X@hEhCC!!e2J+JDccb1@@XE`Ch+V @!I1YF"Jf&8Kc*-A[5BT"cFJ3I8rP#Vb#NHYS+"%q25(pP2,aD$5KBV4"&PiN--c f!&h'b,[%ZDE0!j&ZY32dZD3h)p'VEr2p@kU8c8kU,K'lh$A8,)`efrhRPmImIpI YXG)SXje6-1Z$'lrlYNl#ECVlA2V[1h9Ej6X"Q-(LA%P65$-Ka92rah%dQmeF#KH (%CE56(aEpX$BKjEHj(6mN!"l3iEi(2#eJXU2$BHK`913!#8U6q3!&-VfilRY05# +CbP+)RJR0D'943,GI+$+0I0+'SNaNUMBZ[q4'kLpb*c)iGMP,'c'hFQc1B6@@J6 fXPPfGrc`"VaZDc5@lD1*@AIr'1UT5C'NI$HV@!e*U##m)62YSNd$`'p*J1[@ZVM 5D'GRTkrhF6"1D9-DV'2YVR*$RV,I`+QmTjICq92DT-f+SL1lD&kp)C8`64h*aY* AaJiFNQBGVU!$p6A1-m-e*1L9Iic!B!lQ,rZIkda"cB%TJ`U*0QP,'JVEhkFUFU& (X5K4`r3eG5!0T0`KfYQ6-I-E-mUbb&1TIGYrd"X"EXL$@U!J)EB+%q8mMd,dFeJ fLGJA5!N*4MXRSYfk8"8Vp9RY*4rXaR0dQ"3d!1R%CAQZRaPE1*MZ&DHdelBBaaA (CTA1k$H!##ZMT'i$kB0JJPc9Y"5Em&M)DRM*#SIahMpP`2T[3F,Sr2JX9E@,U5L 10Sdd1Y(qAG#,G'hX$PibcN@!,X`qX*,'eM#B)#S*k1PLLI*REMpB"UmhHT-j!0& TG)jc$@3BLI"em*jDf-B%qLmRR$,BQ1q)YN!*Q1ZNVH,YL#f$!C3-1#@Lch3a2+D 1S3dIq-1a[1C*E$*P+KPQG`THP&p'TQ$JJ-*$cK9F03c3F-aJGGic8i,3hd[fAQ( X2Zr!KU)Rlj!!cer8P'[-pmXiEG4ETUADfi2e!+XIM"@%f)[i)Ikd3c!4jR!-4ar q1T6*aH(Xp6eP)1"JRKV00!kq!BaZa-p*GA93QrN2e@l5U!bDcH)QqRTh9BT04b$ 5Yml1!p$+q9ILbSc)r+'IfN,jLH0'9S)Z+ji4P'1GBK9MHCmrhF8AVC(Xmm"IHl# QFBJ"3PC,19FjeHrVT3AV%qCIqAh1VJm(G,#b$Gh-aRS@jXNFTGXV8@2Eq&L#U%L bf**dKC),j0c9*P0&V!XPRpA0'`jEQG1PDJ+Zdb`[PpRLe34(EcHI-CPm54(VIbE 2J3S%q'`"i`+,HjI3D&@MmVRC5ffqFSVlc[1eQP`@)$eHGrSTSGA@,fc&Yd%c#-[ c`N5)bZ%5b!`+QA-C%YBp[NpG`fMrU'VklXR-he$9jRbE5pBEJR2GeER[mN'1,[` *5HDBYJFl#DN&kKi#mVHiL2@'H4Lb-%(#jb5!e"`RQeJJPfD*L#l$'($NZ1*53#4 P"Z19[8kVVN86PN0#LLPpq&`6QI1)ZR-h3b"[H'qCf&q%J1$CRiFD6AhC'iAdA!5 &9qaeYeVcr,1k'F2P%TlIY-mjXqRIMK+"1cJjQ1[ad0mTG53!aa[IQhlKS@)N-(a pUJ$DahNB2HZ[!!fJ,p(-ACep@IGH86&XYZf#UZd`6HTD`e66bA,VjkUkQpeq)%J hajLPmXp(SipKb*'k%k1f[e'0!D&Sh80Q"$BH&jiJb+SEbpTbQBkE2Qp,5[hLS@1 1pUZ(*&)`(+D+RH8$Z0,+br4iTZJ2rZVP,UC!FP8[XHa#3+"aHC!!DMcpKpFDeIe D%2`@$YX20DB&iIcJUS-R%eCPc4&MSE2f3qfA9IJK5I@,R4403FVlTR'JKYF'NBr eC`jcaFi8Bl$9bp,K,TCp"cJ33fq@Z6`!DldUA,C8J[(2MaI2,p!`$5YT12Mei`2 kEK")F$6(J8GAiLMFaTiMqpE8KiZGrrk"D3Fi#8(4*fVmGK4GIb9Pb9N,%Qh2V&b G`4BR#1B@ZrmSF@DdRU#!!i64LJXc9abPYpjfa+I*FSZ(&IkqF2,@5XqlSfe(pJ5 @FBNcIm6`B$SBQ19pA0k8'bmMac8kRP[Q#l4qV9P3ibU$dmlE'[@*Dj1JGRJe4[Z 5M#`*0UYGpeTAFQV4)hc"Frq0Qe88T#fG+YrEd%GD5VaN8ee69)@GJLMaCTYZJ$h Y`PmD[A8fB#4GP0TV(G5&@%i-DBILl&5HUC*fk#qhfiL-VdMPEK`@*G5aB'3@1DI `Gmq!%mJhD-m-E@ei1#pf)H!Y)#hdYf5,Kre61KKr6-k+iC&[6#!,*8aC4V,dBda *G-Ea,kcp`EQYmI)q(TSXdpT[&6NmmVela*&ZrNk#!a*Ek1U9e(A-C#MTiFrU*8# GRIPS(IG0NC0@D@C,ef!3$-V,f1MmeU$hMNGflfPjdA1l$m'dhT6mE$5k,&09Rk* 35$B&A8hc`Q,f[MCL'()&ZSp9"F43Y6Gp$d@GQ1*-IFE)fQ`!Gl+4bY!)4&ME!i1 S(e$jM(!B0$aPZUklAZC&R6Q$q(JE0b`QVJ8l2ELL'2i"i$m4hNQq3$S*@r,KlPV @0aB$#$cij*NFIiA[#P'Hmk'D%mJh*T,r&0T!Sj!!I%QRN!"4J!C25i'JdhRAG4# +iPZ,'C)pS[%JqMbf%5Z@HYTRpTjm`P9K-jj6!9j,5+E8[jbd,$Qb,rLerVlm'a" EJ,NAIG%b0S`!KTfSi1,Hlm6&Tl86i@XA-SjmDCVVm2JR[U[ZUaabTc`"ZLc''*T MA06`8"HaVhrb,12m0TYp8$49BH,J(bC-qMij8S3`iIJLm!&DUAX,NDT4j(cCZq` Sjr#YLPbe+8AqUc@cBNPJ0I"'D`jmfZPUpmQhXQ'2G"i,XrX6PZh5*UdATE`QBJT 2*-NNJ'H03hDLq3NLl8V#BcH(SN53!&)l)I#5DJXfUc)pbK*kKMMdhlkIbRYcdU* -kaTcDabVQGjqY*`D1++%&&hPjA0$mc46dA5Pa&+%QbaXIY(9*40iKhGhE(!d(Zj TU%6JfY"(KHR"&-pfT-D8AB"c'iDKcqH'9"0#TcflZJ5YE#(YDU4QTYFS*`lY2+' HUH+"N6hThTfY$V%@bmP3RrZVqj*lIM!qQ&'(*R8#YUX0ViVa-8c1cLi5mSh423Y c"ZTZ&UCCXZeRVUh#+(cU-p`4R%4,2aCl@ZeXXYH'f1j5r6'Fdp6k&d9CITqHK#@ jRIp9LG#d$jCXIJ9ZTRb1X1r#JCA&JjmSEMUfVbL!D[6I$5#JScE6Na9lmKfF0EH V"15k'@bDdk%miP"ThZ@A0I0@V`65l5S9deFHd#$hUXR5GDT"DMik$YJL+GmY#CB f%KC+a"&%)ihiBfR+0I#@&ENYGGfGh1ZaX"RlLlZ$l-9X9H*LaaQqEZ6LZ'rpIM* GCa`prJ+&V"j-rb!(B[h8XVQbRfQhYc,GJ(J65aIbPCVha(mX8UAS2e@%VYZYMF( $UMM#pf[eK66(Dj1)d*GNK+[I"ZK52ijfp01Pj098q,AA1GUbRR,5Z)jBdJMD1LZ Y8$2iKCVB!R2!PiF*N!$Ycb2#1Nh6&f-fSDEc2YH1jp9GM@!XI'*ilG-Qc4qT0fe dIZdlC9qP)X!!&@4T9A$EaNq-AZKQ6%R$$a54DScX[R*,M*!!k)K4LrB9Ma0[+II jcUfa44M*R18DLAMSp36ELf),#2#qPidNRI[QVFj%D95q)Xa`RS6EjCd+5BN6MeV %!,Q1a$r!B1`Bp3FM8IpLD)S+$G#+BR1)d#!hB9'5GRjMXFLAC-06*FkSLrBpG6X ,q$JVU-a-"TBp@F)+T`$8S[Dj!EIek6Ei!CIBUAGZpERj!eKb9(,X'RqjiBH5bbP -M*hrM9L`Xhl"GqM#U-f9*jXA"IQeZ[b#&`DqGehATT!!(S$6dqLGCl@A-NeefUB CPHNb!6cQp-!L[%Qal$RBVE9ZN!#qrF#!'d&V@ceTH8bbU3`DV0!06TamU$%('FZ l0N`a41a+-&6)Jcjl2XS1jHBp[HE"-PTaj6*#rZXdIX8%X8XRqJXc(FN5iG%bELS +b,60YmQf"J65!j!!D%+B#Ik0&-B3B@*GM[jJlJBU$RkG93B`&-#!h+HerJ8PT,@ b4!M[IeX(5fA%bFZLUp@K6(mkd@BTHhBcDkGaJh0`$CA2N!#3!%G1-Ne!SYh%drH F,BQM`')#DqM&#U(*Y-1lG45[6@GDN!#,bMKZRMG8"D$T2Kc192P!mSK@0AC8#3E D5,p-B+X2ZcmCQAIc,2AEdK5!+1N5*`cl9qJ@N!")h+G,fYaRJrRN`dd1NQ"E$VL ki6&AIilJU6[Z6pR5B*U9Rm1S[dr`a6mp3Fd`ArhVJQ!TR9T#ZhI+MpjYcFC*Tpf JP)[hkrKT5D`IVBCl"QA0TS2!TdYN8%E#epb&4PA9Q-hQ50A5SA@GjUa`kE-X-HM +d28*r*JYMjd!ICRc,(ZrmcU5e(4KNd[IAR$U[Tm*rdK"&(P&HE,U5c&(#0[`'-D 5f6@Qdr3dIB[VAlQbBHEiXrVYae)ZjkP@,'U[dE)NKfe95B9"Jk0'I$A8b$VC&CI hj0TB-$9m0"N8$CIaHe"M2@3-GQ$(12rHGfTrFM[EP9BMH3B`fcFE2PM'VNZ+fSm R[kIC&VabE@DX[9ZChF-R3*X*[Gmakl`@[!XBM"Iq3#d4e2`)6dE"fe2&5r'*3)D fB!kY""qf-#Xh!5DUNqDYG(&`URfpc*RAAS-#r+D@!A[j8r[eAi!S-rimJJ'!JGb %*BZ5$!f,GjJjLa5D")q,RL4XR[Ppi(r8RNiP$2e@ALL+bU&lUIljbU5MXf56RSK #8KbRX8C@f&kmYX-V,K+TmASNfml4&HPfSV$Y(&Y&J8ER)M[,N!"VmB&c'$a2h'h c`MAp!+rpRY(4Qe8@Z#el[0+YYH#ZYd3EMkbHRechUKDqX5k8m)cfAKj'mJ*[h6' 6)pLEDAqcBBi5[CE[rpIkcC%LIUe3f4@8TFUBfZ9B6FYY-F)N[fBV'h3@(m&iB,a )d1HkSQUS"C91!eHTUrHa9J[FLDk'K8-H9XmKc$L*'V5H'-5[*p)TC'El!$b2J"k T0Ul!A)(4ZlVY!Te#X5V)+@[J"r1e-BdkRFe`N!#r0DcM"VUBekGkJe,*5cpX0PS T(d3588LNcfA!1-TB8GQ`K0eIIl0N96)Nd!Rb%&4LIRETS'P3+jA+Bi9SY#qCmGI 5Ai,[V-NK#La5439PX&LDc8hTl$aLj359-bqmDJZ)GiaX1k1[k)bMZ2r(U*c[Gej %D)m*@@+eGqbF249V)fRpkp)6e0JrHiB*[K8*9fGR-AU+jTcpi#f0+U0+L@Yc'U2 dc04kb961J1JdC5PLEV30PJSYZXJ#jfdlb$,0UrY"jX[RkUY8JLY)-L`Gj6ieH'6 %C*LCT`)3ZS@[X2!%!-SJKp1jEL2Cml64,qZhPa)'AidDL1Ybp@6`iI80l+RfHpd Y1XF"[0[r!$B*PqDdHB95)l8[1I%*Nr,#e&Y3CCiNFC[8dj9TDKdh)Q6,,fCk(S# pQbBT0TY@PD(I@lDhBV%Pk9GrD%IY,YpIM-V9cE(UBbG2&Xck6c5I1BcMA-YcJFA 0,Q"*[F1C16*jHTMMPV0@6HYDU5V0`dPbD&X+MPSlR&+hbi36I8(5pBhrN!$Nj*a Z#!akZ&EGD+M,95XdGQGpfB`RY9BjCa9"Jp0EhH,EFY$Xp0#fq5DI#KVJBj,10hZ `Bq#LBCm2%H@E,+X9!b92Xb3iDFh4MVPIpfIVl"rkr%Eie%$X)MHS6PM!XTB'1$H kR%(U%"b&pq)aqe3a9TkCmFDMGk2qq%"HEh*XqVLk9-A,*pAd(dpZSG2Q#&qCJP2 X5cRMX'hX$'L5*+0!i`51"Yaj''JmqAJA#qUqe!P,MR-!NDje18N(qV3@5C1&B`D IqHRl9X2i2T6ZJH'e!jK,MY#3!+TSYiGI*AaPcjIbGE,pQ5[0Bk@%Ahrf#aQ$NkU d!GNU@XiVQ!T6'EHGZC4@(Qf-icF'*X1,1elXp1L)jmi`Y"F,'Fll%A@'$Mp1IT% 4pZjYGj%b,8rhMFlIh1-NN!#MD$'mrpeRD+18mX9YJ+9kiQE-B&U''*jE1*6raUl $40TV"8Aj2`cF3YHakZ6%05+TZ8&#e4HlCpJjL2$)l&2RNVNKBEAbL2UqijV4C,4 !9bq*`lQDp-&$iV8-!)S2)(el3Gp5lfekXY%TkcB%-PkqfD`DRD,R`APCTf%SkYi YkMk9pc01i''-FlHj6bF6QU%PJ+-@4DbAp91&Q,4`0mc1'1(,P6j)j1fMGbAf%BG ,M8&e!2R'Uk,%Rcm9JkL53'"eTe@IXaCCY!0!33RNL)DY5CYmjN%VhK,U8GXFG+[ 8jmX*Z2'(9BE)F'c"[r"4(UF4E*Qa[Nk-j&"MM!B6UZ*0YpL'!+9)G*&k,&2l@&& AbpQL&q)IrbB+ED(J8lRM"*Ii6%VUADiNE'dVU'q%[LHeia*6Y%89acHSZLZH(mq I[jRmr6$mVc-RTPb8+)ZMjI@hNG(F0VT&bU@(Hq1!F"2j881[Z$Nm5SC@1$41qHC Z*B%dX0kZFfcHDPjCH`GJrbU5DkEdIaTUI+NaK"PdSmI[LPTLJ9IJ8KA#kV"2Uia KdERdQFN93d"lqUqXj@Mr+*qi6&"UECZ-#,*iEC&C`bZqlMfYpM(epQ)*%&C![LJ hPR8L[G0#*-Pj,5P*C$cF+BTi2&i!bX+hlrFri`8+M'SNkXcMM(Q3!%%A2MlD*28 VCqT[JjMIq0PTUq0qPSAf4a0$XLC)-48j(c*)V1K5Pc(m%SGL+($j+p8S%dQ3!&Z lQ%+#S[eP8p$5$[$Vq)R)6HaCkZT5CT&*Rb,2I'PA"EVrJTPJKBE@Xi$J%rQAiUE $fqc2ald8l1R&r%FZ(Gq*VR(@l'M!MiUBId*-Kd&S!pP"YBNkYP[B[Z%YlT5SmY! 2rJF43CSX-e@Gp1FDa-d'!JQ@al9raL0r$[fkG0#D5VmHClHGEqhD`fmVA[jC+rM (&qL@f"N"(1DT-#2bD)j)N3!`Tr&$Rep"LN@aR!Rl(5lcE1UYTUmcVKrX(f1)40K Y4RQl"CKXF9C08YC(*$aR5a@QalMZGITR05QRZ"+h`52GmMN4pj6iXh*6MZFb8ke arcTIYkJ%@!F4TNFBfCKU#I3SZViZSKC0e*!!"cFIrhEC%XbSMX6jaS5&9#h@!`d [Y&`V)j*NiURXkhF0DP5e2dAG*Z,9N!$*D[l1$KF5SNi[b"J@Z2Di),1E93CDGmd Gb1)8,k@iE`R'kNHkLYb%dGd34Y,C013(''CiPAT2BRL[dYPHEY6ZE'`i0f-mp)a X&[HT"f3K+8rfE`T!,%MI)YZKJqZ#ZDTfGRYe'+5[Ke+2E%ecBS3pPC!!rU*,drD &884$ZmbC%Y-Iea(IUfjblN-*cX2hB`Mr+aG#AhMaaJfKPbd5P[+H$9A'(jGqcQ- 2pAc0'J[b`hF4+N1dYV[8#-aHm&FiqHbK`R8PpZ*be,`-[a"P"q1lcb$Z8I%0RA2 X8bcClk*cpGU1Q5c6VI%#`63X"PYE,*Hi3bF21r2JTij#%Q3J'cij@e+-99)rZqB $DdVZbrG[S8$eBj!!@$Z3!%C,DD1H[Dr+iFXKGGD&**8$2mqBZG+M+&`P%``#e8Y 13020cm&rj9ND(4q*S+D%eYGi'X(IT1lA+fV1,T!!6(fcKe2S6"!X-C-F-TqlSTB BJTb$,U'!bY8!!!:davix-0.8.0/deps/curl/src/tool_cb_hdr.h0000644000000000000000000000401514121063461016444 0ustar rootroot#ifndef HEADER_CURL_TOOL_CB_HDR_H #define HEADER_CURL_TOOL_CB_HDR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" /* * curl operates using a single HdrCbData struct variable, a * pointer to this is passed as userdata pointer to tool_header_cb. * * 'outs' member is a pointer to the OutStruct variable used to keep * track of information relative to curl's output writing. * * 'heads' member is a pointer to the OutStruct variable used to keep * track of information relative to header response writing. * * 'honor_cd_filename' member is TRUE when tool_header_cb is allowed * to honor Content-Disposition filename property and accordingly * set 'outs' filename, otherwise FALSE; */ struct HdrCbData { struct GlobalConfig *global; struct OperationConfig *config; struct OutStruct *outs; struct OutStruct *heads; struct OutStruct *etag_save; bool honor_cd_filename; }; /* ** callback for CURLOPT_HEADERFUNCTION */ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata); #endif /* HEADER_CURL_TOOL_CB_HDR_H */ davix-0.8.0/deps/curl/src/tool_help.c0000644000000000000000000005076714121063461016165 0ustar rootroot/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include "tool_setup.h" #if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H) #include #endif #include "tool_panykey.h" #include "tool_help.h" #include "tool_libinfo.h" #include "tool_version.h" #include "memdebug.h" /* keep this as LAST include */ #ifdef MSDOS # define USE_WATT32 #endif /* * The help output is generated with the following command --------------------------------------------------------- cd $srcroot/docs/cmdline-opts ./gen.pl listhelp */ struct helptxt { const char *opt; const char *desc; }; static const struct helptxt helptext[] = { {" --abstract-unix-socket ", "Connect via abstract Unix domain socket"}, {" --alt-svc ", "Enable alt-svc with this cache file"}, {" --anyauth", "Pick any authentication method"}, {"-a, --append", "Append to target file when uploading"}, {" --basic", "Use HTTP Basic Authentication"}, {" --cacert ", "CA certificate to verify peer against"}, {" --capath ", "CA directory to verify peer against"}, {"-E, --cert ", "Client certificate file and password"}, {" --cert-status", "Verify the status of the server certificate"}, {" --cert-type ", "Certificate file type (DER/PEM/ENG)"}, {" --ciphers ", "SSL ciphers to use"}, {" --compressed", "Request compressed response"}, {" --compressed-ssh", "Enable SSH compression"}, {"-K, --config ", "Read config from a file"}, {" --connect-timeout ", "Maximum time allowed for connection"}, {" --connect-to ", "Connect to host"}, {"-C, --continue-at ", "Resumed transfer offset"}, {"-b, --cookie ", "Send cookies from string/file"}, {"-c, --cookie-jar ", "Write cookies to after operation"}, {" --create-dirs", "Create necessary local directory hierarchy"}, {" --crlf", "Convert LF to CRLF in upload"}, {" --crlfile ", "Get a CRL list in PEM format from the given file"}, {"-d, --data ", "HTTP POST data"}, {" --data-ascii ", "HTTP POST ASCII data"}, {" --data-binary ", "HTTP POST binary data"}, {" --data-raw ", "HTTP POST data, '@' allowed"}, {" --data-urlencode ", "HTTP POST data url encoded"}, {" --delegation ", "GSS-API delegation permission"}, {" --digest", "Use HTTP Digest Authentication"}, {"-q, --disable", "Disable .curlrc"}, {" --disable-eprt", "Inhibit using EPRT or LPRT"}, {" --disable-epsv", "Inhibit using EPSV"}, {" --disallow-username-in-url", "Disallow username in url"}, {" --dns-interface ", "Interface to use for DNS requests"}, {" --dns-ipv4-addr
", "IPv4 address to use for DNS requests"}, {" --dns-ipv6-addr
", "IPv6 address to use for DNS requests"}, {" --dns-servers ", "DNS server addrs to use"}, {" --doh-url ", "Resolve host names over DOH"}, {"-D, --dump-header ", "Write the received headers to "}, {" --egd-file ", "EGD socket path for random data"}, {" --engine ", "Crypto engine to use"}, {" --etag-save ", "Get an ETag from response header and save it to a FILE"}, {" --etag-compare ", "Get an ETag from a file and send a conditional request"}, {" --expect100-timeout ", "How long to wait for 100-continue"}, {"-f, --fail", "Fail silently (no output at all) on HTTP errors"}, {" --fail-early", "Fail on first transfer error, do not continue"}, {" --false-start", "Enable TLS False Start"}, {"-F, --form ", "Specify multipart MIME data"}, {" --form-string ", "Specify multipart MIME data"}, {" --ftp-account ", "Account data string"}, {" --ftp-alternative-to-user ", "String to replace USER [name]"}, {" --ftp-create-dirs", "Create the remote dirs if not present"}, {" --ftp-method ", "Control CWD usage"}, {" --ftp-pasv", "Use PASV/EPSV instead of PORT"}, {"-P, --ftp-port
", "Use PORT instead of PASV"}, {" --ftp-pret", "Send PRET before PASV"}, {" --ftp-skip-pasv-ip", "Skip the IP address for PASV"}, {" --ftp-ssl-ccc", "Send CCC after authenticating"}, {" --ftp-ssl-ccc-mode ", "Set CCC mode"}, {" --ftp-ssl-control", "Require SSL/TLS for FTP login, clear for transfer"}, {"-G, --get", "Put the post data in the URL and use GET"}, {"-g, --globoff", "Disable URL sequences and ranges using {} and []"}, {" --happy-eyeballs-timeout-ms ", "How long to wait in milliseconds for IPv6 before trying IPv4"}, {" --haproxy-protocol", "Send HAProxy PROXY protocol v1 header"}, {"-I, --head", "Show document info only"}, {"-H, --header
", "Pass custom header(s) to server"}, {"-h, --help", "This help text"}, {" --hostpubmd5 ", "Acceptable MD5 hash of the host public key"}, {" --http0.9", "Allow HTTP 0.9 responses"}, {"-0, --http1.0", "Use HTTP 1.0"}, {" --http1.1", "Use HTTP 1.1"}, {" --http2", "Use HTTP 2"}, {" --http2-prior-knowledge", "Use HTTP 2 without HTTP/1.1 Upgrade"}, {" --http3", "Use HTTP v3"}, {" --ignore-content-length", "Ignore the size of the remote resource"}, {"-i, --include", "Include protocol response headers in the output"}, {"-k, --insecure", "Allow insecure server connections when using SSL"}, {" --interface ", "Use network INTERFACE (or address)"}, {"-4, --ipv4", "Resolve names to IPv4 addresses"}, {"-6, --ipv6", "Resolve names to IPv6 addresses"}, {"-j, --junk-session-cookies", "Ignore session cookies read from file"}, {" --keepalive-time ", "Interval time for keepalive probes"}, {" --key ", "Private key file name"}, {" --key-type ", "Private key file type (DER/PEM/ENG)"}, {" --krb ", "Enable Kerberos with security "}, {" --libcurl ", "Dump libcurl equivalent code of this command line"}, {" --limit-rate ", "Limit transfer speed to RATE"}, {"-l, --list-only", "List only mode"}, {" --local-port ", "Force use of RANGE for local port numbers"}, {"-L, --location", "Follow redirects"}, {" --location-trusted", "Like --location, and send auth to other hosts"}, {" --login-options ", "Server login options"}, {" --mail-auth
", "Originator address of the original email"}, {" --mail-from
", "Mail from this address"}, {" --mail-rcpt
", "Mail to this address"}, {" --mail-rcpt-allowfails", "Allow RCPT TO command to fail for some recipients"}, {"-M, --manual", "Display the full manual"}, {" --max-filesize ", "Maximum file size to download"}, {" --max-redirs ", "Maximum number of redirects allowed"}, {"-m, --max-time ", "Maximum time allowed for the transfer"}, {" --metalink", "Process given URLs as metalink XML file"}, {" --negotiate", "Use HTTP Negotiate (SPNEGO) authentication"}, {"-n, --netrc", "Must read .netrc for user name and password"}, {" --netrc-file ", "Specify FILE for netrc"}, {" --netrc-optional", "Use either .netrc or URL"}, {"-:, --next", "Make next URL use its separate set of options"}, {" --no-alpn", "Disable the ALPN TLS extension"}, {"-N, --no-buffer", "Disable buffering of the output stream"}, {" --no-keepalive", "Disable TCP keepalive on the connection"}, {" --no-npn", "Disable the NPN TLS extension"}, {" --no-progress-meter", "Do not show the progress meter"}, {" --no-sessionid", "Disable SSL session-ID reusing"}, {" --noproxy ", "List of hosts which do not use proxy"}, {" --ntlm", "Use HTTP NTLM authentication"}, {" --ntlm-wb", "Use HTTP NTLM authentication with winbind"}, {" --oauth2-bearer ", "OAuth 2 Bearer Token"}, {"-o, --output ", "Write to file instead of stdout"}, {"-Z, --parallel", "Perform transfers in parallel"}, {" --parallel-immediate", "Do not wait for multiplexing (with --parallel)"}, {" --parallel-max", "Maximum concurrency for parallel transfers"}, {" --pass ", "Pass phrase for the private key"}, {" --path-as-is", "Do not squash .. sequences in URL path"}, {" --pinnedpubkey ", "FILE/HASHES Public key to verify peer against"}, {" --post301", "Do not switch to GET after following a 301"}, {" --post302", "Do not switch to GET after following a 302"}, {" --post303", "Do not switch to GET after following a 303"}, {" --preproxy [protocol://]host[:port]", "Use this proxy first"}, {"-#, --progress-bar", "Display transfer progress as a bar"}, {" --proto ", "Enable/disable PROTOCOLS"}, {" --proto-default ", "Use PROTOCOL for any URL missing a scheme"}, {" --proto-redir ", "Enable/disable PROTOCOLS on redirect"}, {"-x, --proxy [protocol://]host[:port]", "Use this proxy"}, {" --proxy-anyauth", "Pick any proxy authentication method"}, {" --proxy-basic", "Use Basic authentication on the proxy"}, {" --proxy-cacert ", "CA certificate to verify peer against for proxy"}, {" --proxy-capath ", "CA directory to verify peer against for proxy"}, {" --proxy-cert ", "Set client certificate for proxy"}, {" --proxy-cert-type ", "Client certificate type for HTTPS proxy"}, {" --proxy-ciphers ", "SSL ciphers to use for proxy"}, {" --proxy-crlfile ", "Set a CRL list for proxy"}, {" --proxy-digest", "Use Digest authentication on the proxy"}, {" --proxy-header
", "Pass custom header(s) to proxy"}, {" --proxy-insecure", "Do HTTPS proxy connections without verifying the proxy"}, {" --proxy-key ", "Private key for HTTPS proxy"}, {" --proxy-key-type ", "Private key file type for proxy"}, {" --proxy-negotiate", "Use HTTP Negotiate (SPNEGO) authentication on the proxy"}, {" --proxy-ntlm", "Use NTLM authentication on the proxy"}, {" --proxy-pass ", "Pass phrase for the private key for HTTPS proxy"}, {" --proxy-pinnedpubkey ", "FILE/HASHES public key to verify proxy with"}, {" --proxy-service-name ", "SPNEGO proxy service name"}, {" --proxy-ssl-allow-beast", "Allow security flaw for interop for HTTPS proxy"}, {" --proxy-tls13-ciphers ", "TLS 1.3 ciphersuites for proxy (OpenSSL)"}, {" --proxy-tlsauthtype ", "TLS authentication type for HTTPS proxy"}, {" --proxy-tlspassword ", "TLS password for HTTPS proxy"}, {" --proxy-tlsuser ", "TLS username for HTTPS proxy"}, {" --proxy-tlsv1", "Use TLSv1 for HTTPS proxy"}, {"-U, --proxy-user ", "Proxy user and password"}, {" --proxy1.0 ", "Use HTTP/1.0 proxy on given port"}, {"-p, --proxytunnel", "Operate through an HTTP proxy tunnel (using CONNECT)"}, {" --pubkey ", "SSH Public key file name"}, {"-Q, --quote", "Send command(s) to server before transfer"}, {" --random-file ", "File for reading random data from"}, {"-r, --range ", "Retrieve only the bytes within RANGE"}, {" --raw", "Do HTTP \"raw\"; no transfer decoding"}, {"-e, --referer ", "Referrer URL"}, {"-J, --remote-header-name", "Use the header-provided filename"}, {"-O, --remote-name", "Write output to a file named as the remote file"}, {" --remote-name-all", "Use the remote file name for all URLs"}, {"-R, --remote-time", "Set the remote file's time on the local output"}, {"-X, --request ", "Specify request command to use"}, {" --request-target", "Specify the target for this request"}, {" --resolve ", "Resolve the host+port to this address"}, {" --retry ", "Retry request if transient problems occur"}, {" --retry-connrefused", "Retry on connection refused (use with --retry)"}, {" --retry-delay ", "Wait time between retries"}, {" --retry-max-time ", "Retry only within this period"}, {" --sasl-authzid ", "Use this identity to act as during SASL PLAIN authentication"}, {" --sasl-ir", "Enable initial response in SASL authentication"}, {" --service-name ", "SPNEGO service name"}, {"-S, --show-error", "Show error even when -s is used"}, {"-s, --silent", "Silent mode"}, {" --socks4 ", "SOCKS4 proxy on given host + port"}, {" --socks4a ", "SOCKS4a proxy on given host + port"}, {" --socks5 ", "SOCKS5 proxy on given host + port"}, {" --socks5-basic", "Enable username/password auth for SOCKS5 proxies"}, {" --socks5-gssapi", "Enable GSS-API auth for SOCKS5 proxies"}, {" --socks5-gssapi-nec", "Compatibility with NEC SOCKS5 server"}, {" --socks5-gssapi-service ", "SOCKS5 proxy service name for GSS-API"}, {" --socks5-hostname ", "SOCKS5 proxy, pass host name to proxy"}, {"-Y, --speed-limit ", "Stop transfers slower than this"}, {"-y, --speed-time ", "Trigger 'speed-limit' abort after this time"}, {" --ssl", "Try SSL/TLS"}, {" --ssl-allow-beast", "Allow security flaw to improve interop"}, {" --ssl-no-revoke", "Disable cert revocation checks (Schannel)"}, {" --ssl-reqd", "Require SSL/TLS"}, {"-2, --sslv2", "Use SSLv2"}, {"-3, --sslv3", "Use SSLv3"}, {" --stderr", "Where to redirect stderr"}, {" --styled-output", "Enable styled output for HTTP headers"}, {" --suppress-connect-headers", "Suppress proxy CONNECT response headers"}, {" --tcp-fastopen", "Use TCP Fast Open"}, {" --tcp-nodelay", "Use the TCP_NODELAY option"}, {"-t, --telnet-option ", "Set telnet option"}, {" --tftp-blksize ", "Set TFTP BLKSIZE option"}, {" --tftp-no-options", "Do not send any TFTP options"}, {"-z, --time-cond