1
0
Эх сурвалжийг харах

ENH: Update Curl to 7.16.1

Andy Cedilnik 19 жил өмнө
parent
commit
9314bb49e0
100 өөрчлөгдсөн 12809 нэмэгдсэн , 6810 устгасан
  1. 75 0
      Utilities/cmcurl/CMake/CheckCSourceCompiles.cmake
  2. 78 0
      Utilities/cmcurl/CMake/CheckCSourceRuns.cmake
  3. 245 0
      Utilities/cmcurl/CMake/OtherTests.cmake
  4. 94 12
      Utilities/cmcurl/CMakeLists.txt
  5. 0 1
      Utilities/cmcurl/Platforms/WindowsCache.cmake
  6. 33 8
      Utilities/cmcurl/amigaos.c
  7. 11 5
      Utilities/cmcurl/amigaos.h
  8. 2 2
      Utilities/cmcurl/arpa_telnet.h
  9. 115 37
      Utilities/cmcurl/base64.c
  10. 9 8
      Utilities/cmcurl/base64.h
  11. 240 36
      Utilities/cmcurl/config.h.in
  12. 263 146
      Utilities/cmcurl/connect.c
  13. 5 3
      Utilities/cmcurl/connect.h
  14. 147 86
      Utilities/cmcurl/content_encoding.c
  15. 9 9
      Utilities/cmcurl/content_encoding.h
  16. 255 117
      Utilities/cmcurl/cookie.c
  17. 15 3
      Utilities/cmcurl/cookie.h
  18. 1 1
      Utilities/cmcurl/curl.copyright
  19. 376 87
      Utilities/cmcurl/curl/curl.h
  20. 15 14
      Utilities/cmcurl/curl/curlver.h
  21. 7 7
      Utilities/cmcurl/curl/easy.h
  22. 37 21
      Utilities/cmcurl/curl/mprintf.h
  23. 166 60
      Utilities/cmcurl/curl/multi.h
  24. 14 2
      Utilities/cmcurl/curlx.h
  25. 101 42
      Utilities/cmcurl/dict.c
  26. 7 7
      Utilities/cmcurl/dict.h
  27. 393 81
      Utilities/cmcurl/easy.c
  28. 40 0
      Utilities/cmcurl/easyif.h
  29. 55 9
      Utilities/cmcurl/escape.c
  30. 6 8
      Utilities/cmcurl/escape.h
  31. 70 53
      Utilities/cmcurl/file.c
  32. 8 8
      Utilities/cmcurl/file.h
  33. 273 63
      Utilities/cmcurl/formdata.c
  34. 9 4
      Utilities/cmcurl/formdata.h
  35. 2665 1387
      Utilities/cmcurl/ftp.c
  36. 18 12
      Utilities/cmcurl/ftp.h
  37. 0 2471
      Utilities/cmcurl/getdate.c
  38. 0 37
      Utilities/cmcurl/getdate.h
  39. 11 12
      Utilities/cmcurl/getenv.c
  40. 72 12
      Utilities/cmcurl/getinfo.c
  41. 640 0
      Utilities/cmcurl/gtls.c
  42. 46 0
      Utilities/cmcurl/gtls.h
  43. 83 35
      Utilities/cmcurl/hash.c
  44. 19 18
      Utilities/cmcurl/hash.h
  45. 29 23
      Utilities/cmcurl/hostares.c
  46. 33 29
      Utilities/cmcurl/hostasyn.c
  47. 152 56
      Utilities/cmcurl/hostip.c
  48. 60 44
      Utilities/cmcurl/hostip.h
  49. 53 120
      Utilities/cmcurl/hostip4.c
  50. 83 40
      Utilities/cmcurl/hostip6.c
  51. 16 27
      Utilities/cmcurl/hostsyn.c
  52. 378 89
      Utilities/cmcurl/hostthre.c
  53. 422 183
      Utilities/cmcurl/http.c
  54. 31 7
      Utilities/cmcurl/http.h
  55. 125 29
      Utilities/cmcurl/http_chunks.c
  56. 24 8
      Utilities/cmcurl/http_chunks.h
  57. 34 12
      Utilities/cmcurl/http_digest.c
  58. 12 7
      Utilities/cmcurl/http_digest.h
  59. 10 15
      Utilities/cmcurl/http_negotiate.c
  60. 626 118
      Utilities/cmcurl/http_ntlm.c
  61. 10 7
      Utilities/cmcurl/http_ntlm.h
  62. 19 27
      Utilities/cmcurl/if2ip.c
  63. 5 7
      Utilities/cmcurl/if2ip.h
  64. 35 0
      Utilities/cmcurl/inet_ntoa_r.h
  65. 40 20
      Utilities/cmcurl/inet_ntop.c
  66. 4 4
      Utilities/cmcurl/inet_ntop.h
  67. 126 125
      Utilities/cmcurl/inet_pton.c
  68. 14 9
      Utilities/cmcurl/inet_pton.h
  69. 38 21
      Utilities/cmcurl/krb4.c
  70. 49 6
      Utilities/cmcurl/krb4.h
  71. 140 63
      Utilities/cmcurl/ldap.c
  72. 7 7
      Utilities/cmcurl/ldap.h
  73. 19 11
      Utilities/cmcurl/llist.c
  74. 27 23
      Utilities/cmcurl/llist.h
  75. 16 12
      Utilities/cmcurl/md5.c
  76. 1 1
      Utilities/cmcurl/md5.h
  77. 17 12
      Utilities/cmcurl/memdebug.c
  78. 37 20
      Utilities/cmcurl/memdebug.h
  79. 5 5
      Utilities/cmcurl/memory.h
  80. 21 18
      Utilities/cmcurl/mprintf.c
  81. 1100 279
      Utilities/cmcurl/multi.c
  82. 46 0
      Utilities/cmcurl/multiif.h
  83. 12 12
      Utilities/cmcurl/netrc.c
  84. 1 1
      Utilities/cmcurl/nwlib.c
  85. 425 0
      Utilities/cmcurl/parsedate.c
  86. 28 0
      Utilities/cmcurl/parsedate.h
  87. 6 8
      Utilities/cmcurl/progress.c
  88. 6 6
      Utilities/cmcurl/progress.h
  89. 22 12
      Utilities/cmcurl/security.c
  90. 0 72
      Utilities/cmcurl/security.h
  91. 315 0
      Utilities/cmcurl/select.c
  92. 63 0
      Utilities/cmcurl/select.h
  93. 317 150
      Utilities/cmcurl/sendf.c
  94. 24 8
      Utilities/cmcurl/sendf.h
  95. 198 110
      Utilities/cmcurl/setup.h
  96. 153 0
      Utilities/cmcurl/setup_once.h
  97. 4 4
      Utilities/cmcurl/share.c
  98. 20 19
      Utilities/cmcurl/share.h
  99. 38 0
      Utilities/cmcurl/sockaddr.h
  100. 585 0
      Utilities/cmcurl/socks.c

+ 75 - 0
Utilities/cmcurl/CMake/CheckCSourceCompiles.cmake

@@ -0,0 +1,75 @@
+# - Check if the source code provided in the SOURCE argument compiles.
+# CHECK_C_SOURCE_COMPILES(SOURCE VAR)
+# - macro which checks if the source code compiles
+#  SOURCE   - source code to try to compile
+#  VAR      - variable to store whether the source code compiled
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_INCLUDES = list of include directories
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_C_SOURCE_COMPILES SOURCE VAR)
+  IF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
+    SET(message "${VAR}")
+    # If the number of arguments is greater than 2 (SOURCE VAR)
+    IF(${ARGC} GREATER 2)
+      # then add the third argument as a message
+      SET(message "${ARGV2} (${VAR})")
+    ENDIF(${ARGC} GREATER 2)
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ELSE(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+    IF(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    ELSE(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    ENDIF(CMAKE_REQUIRED_INCLUDES)
+    SET(src "")
+    FOREACH(def ${EXTRA_DEFINES})
+      SET(src "${src}#define ${def} 1\n")
+    ENDFOREACH(def)
+    FOREACH(inc ${HEADER_INCLUDES})
+      SET(src "${src}#include <${inc}>\n")
+    ENDFOREACH(inc)
+
+    SET(src "${src}\nint main() { ${SOURCE} ; return 0; }")
+    SET(CMAKE_CONFIGURABLE_FILE_CONTENT "${src}")
+    CONFIGURE_FILE(${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in
+      "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      IMMEDIATE)
+    MESSAGE(STATUS "Performing Test ${message}")
+    TRY_COMPILE(${VAR}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(${VAR})
+      SET(${VAR} 1 CACHE INTERNAL "Test ${message}")
+      MESSAGE(STATUS "Performing Test ${message} - Success")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${message} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${src}\n")
+    ELSE(${VAR})
+      MESSAGE(STATUS "Performing Test ${message} - Failed")
+      SET(${VAR} "" CACHE INTERNAL "Test ${message}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${message} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${src}\n")
+    ENDIF(${VAR})
+  ENDIF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
+ENDMACRO(CHECK_C_SOURCE_COMPILES)

+ 78 - 0
Utilities/cmcurl/CMake/CheckCSourceRuns.cmake

@@ -0,0 +1,78 @@
+# - Check if the source code provided in the SOURCE argument compiles and runs.
+# CHECK_C_SOURCE_RUNS(SOURCE VAR)
+# - macro which checks if the source code runs
+#  SOURCE   - source code to try to compile
+#  VAR - variable to store size if the type exists.
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_INCLUDES = list of include directories
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_C_SOURCE_RUNS SOURCE VAR)
+  IF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS 
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ELSE(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+    IF(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    ELSE(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    ENDIF(CMAKE_REQUIRED_INCLUDES)
+    SET(src "")
+    FOREACH(def ${EXTRA_DEFINES})
+      SET(src "${src}#define ${def} 1\n")
+    ENDFOREACH(def)
+    FOREACH(inc ${HEADER_INCLUDES})
+      SET(src "${src}#include <${inc}>\n")
+    ENDFOREACH(inc)
+
+    SET(src "${src}\nint main() { ${SOURCE} ; return 0; }")
+    FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src2.c"
+      "${src}\n")
+    EXEC_PROGRAM("${CMAKE_COMMAND}" 
+      "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp"
+      ARGS -E copy src2.c src.c)
+    MESSAGE(STATUS "Performing Test ${VAR}")
+    TRY_RUN(${VAR} ${VAR}_COMPILED
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+    # if it did not compile make the return value fail code of 1
+    IF(NOT ${VAR}_COMPILED)
+      SET(${VAR} 1)
+    ENDIF(NOT ${VAR}_COMPILED)
+    # if the return value was 0 then it worked
+    SET(result_var ${${VAR}})
+    IF("${result_var}" EQUAL 0)
+      SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      MESSAGE(STATUS "Performing Test ${VAR} - Success")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${${VAR}}\n"
+        "Source file was:\n${src}\n")
+    ELSE("${result_var}" EQUAL 0)
+      MESSAGE(STATUS "Performing Test ${VAR} - Failed")
+      SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${result_var}\n"
+        "Source file was:\n${src}\n")
+    ENDIF("${result_var}" EQUAL 0)
+  ENDIF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
+ENDMACRO(CHECK_C_SOURCE_RUNS)

+ 245 - 0
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -0,0 +1,245 @@
+INCLUDE(CheckCSourceCompiles)
+SET(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2")
+SET(HEADER_INCLUDES)
+SET(headers_hack)
+MACRO(add_header_include check header)
+  IF(${check})
+    SET(headers_hack
+      "${headers_hack}\n#include <${header}>")
+    #SET(HEADER_INCLUDES
+    #  ${HEADER_INCLUDES}
+    #  "${header}")
+  ENDIF(${check})
+ENDMACRO(add_header_include)
+SET(signature_call_conv)
+IF(HAVE_WINDOWS_H)
+  add_header_include(HAVE_WINDOWS_H "windows.h")
+  add_header_include(HAVE_WINSOCK2_H "winsock2.h")
+  add_header_include(HAVE_WINSOCK_H "winsock.h")
+  SET(EXTRA_DEFINES ${EXTRA_DEFINES}
+    "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3")
+  SET(signature_call_conv "PASCAL")
+ELSE(HAVE_WINDOWS_H)
+  add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
+  add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
+ENDIF(HAVE_WINDOWS_H)
+
+SET(EXTRA_DEFINES_BACKUP "${EXTRA_DEFINES}")
+SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
+CHECK_C_SOURCE_COMPILES("recv(0, 0, 0, 0)" curl_cv_recv)
+IF(curl_cv_recv)
+  #    AC_CACHE_CHECK([types of arguments and return type for recv],
+  #[curl_cv_func_recv_args], [
+  #SET(curl_cv_func_recv_args "unknown")
+  #for recv_retv in 'int' 'ssize_t'; do
+  IF(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
+    FOREACH(recv_retv "ssize_t" "int")
+      FOREACH(recv_arg1 "int" "ssize_t" "SOCKET")
+        FOREACH(recv_arg2 "void *" "char *")
+          FOREACH(recv_arg3 "size_t" "int" "socklen_t" "unsigned int")
+            FOREACH(recv_arg4 "int" "unsigned int")
+              IF(NOT curl_cv_func_recv_done)
+                SET(curl_cv_func_recv_test "UNKNOWN")
+                SET(extern_line "extern ${recv_retv} ${signature_call_conv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})\;")
+                SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
+                CHECK_C_SOURCE_COMPILES("
+                    ${recv_arg1} s=0;
+                    ${recv_arg2} buf=0;
+                    ${recv_arg3} len=0;
+                    ${recv_arg4} flags=0;
+                    ${recv_retv} res = recv(s, buf, len, flags)"
+                    curl_cv_func_recv_test
+                    "${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(curl_cv_func_recv_test)
+              ENDIF(NOT curl_cv_func_recv_done)
+            ENDFOREACH(recv_arg4)
+          ENDFOREACH(recv_arg3)
+        ENDFOREACH(recv_arg2)
+      ENDFOREACH(recv_arg1)
+    ENDFOREACH(recv_retv) 
+  ELSE(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
+    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}")
+    #MESSAGE("RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}")
+    #MESSAGE("RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}")
+    #MESSAGE("RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}")
+    #MESSAGE("RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}")
+    #MESSAGE("RECV_TYPE_RETV ${RECV_TYPE_RETV}")
+  ENDIF(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
+  
+  IF("${curl_cv_func_recv_args}" STREQUAL "unknown")
+    MESSAGE(FATAL_ERROR "Cannot find proper types to use for recv args")
+  ENDIF("${curl_cv_func_recv_args}" STREQUAL "unknown")
+ELSE(curl_cv_recv)
+  MESSAGE(FATAL_ERROR "Unable to link function recv")
+ENDIF(curl_cv_recv)
+SET(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv")
+SET(HAVE_RECV 1)
+
+CHECK_C_SOURCE_COMPILES("send(0, 0, 0, 0)" curl_cv_send)
+IF(curl_cv_send)
+  #    AC_CACHE_CHECK([types of arguments and return type for send],
+  #[curl_cv_func_send_args], [
+  #SET(curl_cv_func_send_args "unknown")
+  #for send_retv in 'int' 'ssize_t'; do
+  IF(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
+    FOREACH(send_retv "ssize_t" "int")
+      FOREACH(send_arg1 "int" "ssize_t" "SOCKET")
+        FOREACH(send_arg2 "const void *" "void *" "char *" "const char *")
+          FOREACH(send_arg3 "size_t" "int" "socklen_t" "unsigned int")
+            FOREACH(send_arg4 "int" "unsigned int")
+              IF(NOT curl_cv_func_send_done)
+                SET(curl_cv_func_send_test "UNKNOWN")
+                SET(extern_line "extern ${send_retv} ${signature_call_conv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})\;")
+                SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
+                CHECK_C_SOURCE_COMPILES("
+                    ${send_arg1} s=0;
+                    ${send_arg2} buf=0;
+                    ${send_arg3} len=0;
+                    ${send_arg4} flags=0;
+                    ${send_retv} res = send(s, buf, len, flags)"
+                    curl_cv_func_send_test
+                    "${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})")
+                IF(curl_cv_func_send_test)
+                  #MESSAGE("Found arguments: ${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(curl_cv_func_send_test)
+              ENDIF(NOT curl_cv_func_send_done)
+            ENDFOREACH(send_arg4)
+          ENDFOREACH(send_arg3)
+        ENDFOREACH(send_arg2)
+      ENDFOREACH(send_arg1)
+    ENDFOREACH(send_retv) 
+  ELSE(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
+    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}")
+    #MESSAGE("SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}")
+    #MESSAGE("SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}")
+    #MESSAGE("SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}")
+    #MESSAGE("SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}")
+    #MESSAGE("SEND_TYPE_RETV ${SEND_TYPE_RETV}")
+    #MESSAGE("SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}")
+  ENDIF(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
+  
+  IF("${curl_cv_func_send_args}" STREQUAL "unknown")
+    MESSAGE(FATAL_ERROR "Cannot find proper types to use for send args")
+  ENDIF("${curl_cv_func_send_args}" STREQUAL "unknown")
+  SET(SEND_QUAL_ARG2 "const")
+ELSE(curl_cv_send)
+  MESSAGE(FATAL_ERROR "Unable to link function send")
+ENDIF(curl_cv_send)
+SET(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send")
+SET(HAVE_SEND 1)
+
+SET(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5")
+CHECK_C_SOURCE_COMPILES("int flag = MSG_NOSIGNAL" HAVE_MSG_NOSIGNAL)
+
+SET(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2")
+SET(HEADER_INCLUDES)
+SET(headers_hack)
+MACRO(add_header_include check header)
+  IF(${check})
+    SET(headers_hack
+      "${headers_hack}\n#include <${header}>")
+    #SET(HEADER_INCLUDES
+    #  ${HEADER_INCLUDES}
+    #  "${header}")
+  ENDIF(${check})
+ENDMACRO(add_header_include header)
+IF(HAVE_WINDOWS_H)
+  SET(EXTRA_DEFINES ${EXTRA_DEFINES}
+    "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3")
+  add_header_include(HAVE_WINDOWS_H "windows.h")
+  add_header_include(HAVE_WINSOCK2_H "winsock2.h")
+  add_header_include(HAVE_WINSOCK_H "winsock.h")
+ELSE(HAVE_WINDOWS_H)
+  add_header_include(HAVE_SYS_TYPES_H "sys/types.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(HAVE_WINDOWS_H)
+SET(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5")
+CHECK_C_SOURCE_COMPILES("struct timeval ts;\nts.tv_sec  = 0;\nts.tv_usec = 0" HAVE_STRUCT_TIMEVAL)
+
+
+INCLUDE(CheckCSourceRuns)
+SET(EXTRA_DEFINES)
+SET(HEADER_INCLUDES)
+IF(HAVE_SYS_POLL_H)
+  SET(HEADER_INCLUDES "sys/poll.h")
+ENDIF(HAVE_SYS_POLL_H)
+CHECK_C_SOURCE_RUNS("return poll((void *)0, 0, 10 /*ms*/)" HAVE_POLL_FINE)
+
+SET(HAVE_SIG_ATOMIC_T 1)
+SET(EXTRA_DEFINES)
+SET(HEADER_INCLUDES)
+IF(HAVE_SIGNAL_H)
+  SET(HEADER_INCLUDES "signal.h")
+  SET(CMAKE_EXTRA_INCLUDE_FILES "signal.h")
+ENDIF(HAVE_SIGNAL_H)
+CHECK_TYPE_SIZE("sig_atomic_t" SIZEOF_SIG_ATOMIC_T)
+IF(HAVE_SIZEOF_SIG_ATOMIC_T)
+  CHECK_C_SOURCE_COMPILES("static volatile sig_atomic_t dummy = 0" HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+  IF(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+    SET(HAVE_SIG_ATOMIC_T_VOLATILE 1)
+  ENDIF(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+ENDIF(HAVE_SIZEOF_SIG_ATOMIC_T)
+
+SET(CHECK_TYPE_SIZE_PREINCLUDE
+  "#undef inline")
+
+IF(HAVE_WINDOWS_H)
+  SET(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE}
+  #ifndef WIN32_LEAN_AND_MEAN
+  #define WIN32_LEAN_AND_MEAN
+  #endif
+  #include <windows.h>")
+  IF(HAVE_WINSOCK2_H)
+    SET(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE}\n#include <winsock2.h>")
+  ENDIF(HAVE_WINSOCK2_H)
+ELSE(HAVE_WINDOWS_H)
+  IF(HAVE_SYS_SOCKET_H)
+    SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
+      "sys/socket.h")
+  ENDIF(HAVE_SYS_SOCKET_H)
+  IF(HAVE_NETINET_IN_H)
+    SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
+      "netinet/in.h")
+  ENDIF(HAVE_NETINET_IN_H)
+  IF(HAVE_ARPA_INET_H)
+    SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
+      "arpa/inet.h")
+  ENDIF(HAVE_ARPA_INET_H)
+ENDIF(HAVE_WINDOWS_H)
+CHECK_TYPE_SIZE("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
+IF(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
+  SET(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+ENDIF(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
+

+ 94 - 12
Utilities/cmcurl/CMakeLists.txt

@@ -5,7 +5,7 @@ INCLUDE_REGULAR_EXPRESSION("^.*$")
 
 # Setup package meta-data
 SET(PACKAGE "curl")
-SET(VERSION "7.12.1")
+SET(VERSION "7.16.1")
 SET(PACKAGE_TARNAME "curl")
 SET(PACKAGE_BUGREPORT " ")
 SET(PACKAGE_NAME "curl")
@@ -38,6 +38,7 @@ INCLUDE (CheckSymbolExists)
 INCLUDE (CheckTypeSize)
 
 SET(libCurl_SRCS
+  #  amigaos.c - does not build on AmigaOS
   base64.c
   connect.c
   content_encoding.c
@@ -48,15 +49,15 @@ SET(libCurl_SRCS
   file.c
   formdata.c
   ftp.c
-  getdate.c
   getenv.c
   getinfo.c
+  gtls.c
   hash.c
   hostares.c
   hostasyn.c
-  hostip.c
   hostip4.c
   hostip6.c
+  hostip.c
   hostsyn.c
   hostthre.c
   http.c
@@ -68,20 +69,33 @@ SET(libCurl_SRCS
   inet_ntop.c
   inet_pton.c
   krb4.c
+  ldap.c
   llist.c
   md5.c
   memdebug.c
   mprintf.c
   multi.c
   netrc.c
+  # nwlib.c - Not used
+  parsedate.c
   progress.c
+  security.c
+  select.c
   sendf.c
   share.c
+  socks.c
   speedcheck.c
+  splay.c
+  ssh.c
+  sslgen.c
   ssluse.c
+  strdup.c
   strequal.c
   strerror.c
+  # strtok.c - specify later
+  strtoofft.c
   telnet.c
+  tftp.c
   timeval.c
   transfer.c
   url.c
@@ -152,13 +166,16 @@ IF(NOT CURL_SPECIAL_LIBZ)
   CHECK_LIBRARY_EXISTS_CONCAT("z"      inflateEnd   HAVE_LIBZ)
 ENDIF(NOT CURL_SPECIAL_LIBZ)
 
-#OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" OFF)
+OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ON)
 MARK_AS_ADVANCED(CMAKE_USE_OPENSSL)
 IF(CMAKE_USE_OPENSSL)
   CHECK_LIBRARY_EXISTS_CONCAT("crypto" CRYPTO_lock  HAVE_LIBCRYPTO)
   CHECK_LIBRARY_EXISTS_CONCAT("ssl"    SSL_connect  HAVE_LIBSSL)
 ENDIF(CMAKE_USE_OPENSSL)
 
+# Check for idn
+CHECK_LIBRARY_EXISTS_CONCAT("idn" idna_to_ascii_lz HAVE_LIBIDN)
+
 # Check for symbol dlopen (same as HAVE_LIBDL)
 CHECK_LIBRARY_EXISTS("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
 
@@ -202,7 +219,11 @@ MACRO(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE)
 ENDMACRO(CHECK_INCLUDE_FILE_CONCAT)
 
 # Check for header files
+CHECK_INCLUDE_FILE_CONCAT("ws2tcpip.h"       HAVE_WS2TCPIP_H)
+CHECK_INCLUDE_FILE_CONCAT("winsock2.h"       HAVE_WINSOCK2_H)
 CHECK_INCLUDE_FILE_CONCAT("stdio.h"          HAVE_STDIO_H)
+CHECK_INCLUDE_FILE_CONCAT("windows.h"        HAVE_WINDOWS_H)
+CHECK_INCLUDE_FILE_CONCAT("winsock.h"        HAVE_WINSOCK_H)
 CHECK_INCLUDE_FILE_CONCAT("stddef.h"         HAVE_STDDEF_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/types.h"      HAVE_SYS_TYPES_H)
 CHECK_INCLUDE_FILE_CONCAT("inttypes.h"       HAVE_INTTYPES_H)
@@ -226,6 +247,7 @@ IF(CMAKE_USE_OPENSSL)
   CHECK_INCLUDE_FILE_CONCAT("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
   CHECK_INCLUDE_FILE_CONCAT("openssl/err.h"    HAVE_OPENSSL_ERR_H)
   CHECK_INCLUDE_FILE_CONCAT("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H)
 ENDIF(CMAKE_USE_OPENSSL)
 
 IF(NOT CURL_SPECIAL_LIBZ)
@@ -250,26 +272,35 @@ CHECK_INCLUDE_FILE_CONCAT("strings.h"       HAVE_STRINGS_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/param.h"     HAVE_SYS_PARAM_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/resource.h"  HAVE_SYS_RESOURCE_H)
 CHECK_INCLUDE_FILE_CONCAT("termios.h"       HAVE_TERMIOS_H)
 CHECK_INCLUDE_FILE_CONCAT("termio.h"        HAVE_TERMIO_H)
 CHECK_INCLUDE_FILE_CONCAT("io.h"            HAVE_IO_H)
 CHECK_INCLUDE_FILE_CONCAT("time.h"          HAVE_TIME_H)
 CHECK_INCLUDE_FILE_CONCAT("unistd.h"        HAVE_UNISTD_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/utime.h"     HAVE_SYS_UTIME_H)
-CHECK_INCLUDE_FILE_CONCAT("winsock.h"       HAVE_WINSOCK_H)
 CHECK_INCLUDE_FILE_CONCAT("sockio.h"        HAVE_SOCKIO_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h"    HAVE_SYS_SOCKIO_H)
 CHECK_INCLUDE_FILE_CONCAT("x509.h"          HAVE_X509_H)
+CHECK_INCLUDE_FILE_CONCAT("locale.h"        HAVE_LOCALE_H)
 CHECK_INCLUDE_FILE_CONCAT("setjmp.h"        HAVE_SETJMP_H)
 CHECK_INCLUDE_FILE_CONCAT("signal.h"        HAVE_SIGNAL_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h"     HAVE_SYS_IOCTL_H)
 CHECK_INCLUDE_FILE_CONCAT("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
+CHECK_INCLUDE_FILE_CONCAT("idn-free.h"      HAVE_IDN_FREE_H)
+CHECK_INCLUDE_FILE_CONCAT("idna.h"          HAVE_IDNA_H)
+CHECK_INCLUDE_FILE_CONCAT("tld.h"           HAVE_TLD_H)
+CHECK_INCLUDE_FILE_CONCAT("arpa/tftp.h"     HAVE_ARPA_TFTP_H)
+CHECK_INCLUDE_FILE_CONCAT("errno.h"         HAVE_ERRNO_H)
+CHECK_INCLUDE_FILE_CONCAT("libgen.h"        HAVE_LIBGEN_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/filio.h"     HAVE_SYS_FILIO_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("__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)
@@ -281,11 +312,49 @@ ENDIF(NOT HAVE_SIZEOF_SSIZE_T)
 
 IF(HAVE_SIZEOF_LONG_LONG)
   SET(HAVE_LONGLONG 1)
+  SET(HAVE_LL 1)
 ENDIF(HAVE_SIZEOF_LONG_LONG)
 
 FIND_FILE(RANDOM_FILE urandom /dev)
 MARK_AS_ADVANCED(RANDOM_FILE)
 
+#strtoll \
+#socket \
+#select \
+#strdup \
+#strstr \
+#strtok_r \
+#uname \
+#strcasecmp \
+#stricmp \
+#strcmpi \
+#gethostbyaddr \
+#gettimeofday \
+#inet_addr \
+#inet_ntoa \
+#inet_pton \
+#perror \
+#closesocket \
+#siginterrupt \
+#sigaction \
+#signal \
+#getpass_r \
+#strlcat \
+#getpwuid \
+#geteuid \
+#dlopen \
+#utime \
+#sigsetjmp \
+#basename \
+#setlocale \
+#ftruncate \
+#pipe \
+#poll \
+#getprotobyname \
+#getrlimit \
+#setrlimit \
+#fork
+
 # Check for some functions that are used
 CHECK_SYMBOL_EXISTS(socket        "${CURL_INCLUDES}" HAVE_SOCKET)
 CHECK_SYMBOL_EXISTS(poll          "${CURL_INCLUDES}" HAVE_POLL)
@@ -338,12 +407,22 @@ CHECK_SYMBOL_EXISTS(SIGALRM       "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
 IF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
   SET(HAVE_SIGNAL 1)
 ENDIF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
-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(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(pipe           "${CURL_INCLUDES}" HAVE_PIPE)
+CHECK_SYMBOL_EXISTS(ftruncate      "${CURL_INCLUDES}" HAVE_FTRUNCATE)
+CHECK_SYMBOL_EXISTS(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
+CHECK_SYMBOL_EXISTS(getrlimit      "${CURL_INCLUDES}" HAVE_GETRLIMIT)
+CHECK_SYMBOL_EXISTS(idn_free       "${CURL_INCLUDES}" HAVE_IDN_FREE)
+CHECK_SYMBOL_EXISTS(idna_strerror  "${CURL_INCLUDES}" HAVE_IDNA_STRERROR)
+CHECK_SYMBOL_EXISTS(tld_strerror   "${CURL_INCLUDES}" HAVE_TLD_STRERROR)
+CHECK_SYMBOL_EXISTS(setlocale      "${CURL_INCLUDES}" HAVE_SETLOCALE)
+CHECK_SYMBOL_EXISTS(setrlimit      "${CURL_INCLUDES}" HAVE_SETRLIMIT)
 
 # only build compat strtok if we need to
 IF (NOT HAVE_STRTOK_R)
@@ -588,11 +667,14 @@ IF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
     COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS})
 ENDIF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
 
+INCLUDE(CMake/OtherTests.cmake)
+
 # The rest of the build
 
 INCLUDE_DIRECTORIES(${LIBCURL_SOURCE_DIR})
 INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR})
-ADD_DEFINITIONS(-DHAVE_CONFIG_H)
+ADD_DEFINITIONS(-DHAVE_CONFIG_H
+  -DCURL_STATICLIB)
 CONFIGURE_FILE(${LIBCURL_SOURCE_DIR}/config.h.in
   ${LIBCURL_BINARY_DIR}/config.h)
 

+ 0 - 1
Utilities/cmcurl/Platforms/WindowsCache.cmake

@@ -46,7 +46,6 @@ IF(NOT UNIX)
     SET(HAVE_TIME_H 1)
     SET(HAVE_UNISTD_H 0)
     SET(HAVE_UTIME_H 0)
-    SET(HAVE_WINSOCK_H 1)
     SET(HAVE_X509_H 0)
     SET(HAVE_ZLIB_H 0)
 

+ 33 - 8
Utilities/cmcurl/amigaos.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,28 +22,53 @@
  ***************************************************************************/
 
 #include "amigaos.h"
-#include <stdio.h> /* for stderr */
+#include <amitcp/socketbasetags.h>
 
 struct Library *SocketBase = NULL;
+extern int errno, h_errno;
+
+#ifdef __libnix__
+#include <stabs.h>
+void __request(const char *msg);
+#else
+# define __request( msg )  Printf( msg "\n\a")
+#endif
 
 void amiga_cleanup()
 {
-  if(SocketBase)
+  if(SocketBase) {
     CloseLibrary(SocketBase);
-        
-  SocketBase = NULL;
+    SocketBase = NULL;
+  }
 }
 
 BOOL amiga_init()
 {
   if(!SocketBase)
     SocketBase = OpenLibrary("bsdsocket.library", 4);
-        
+  
   if(!SocketBase) {
-    fprintf(stderr, "No TCP/IP Stack running!\n\a");
+    __request("No TCP/IP Stack running!");
     return FALSE;
   }
-        
+  
+  if(SocketBaseTags(
+    SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
+//    SBTM_SETVAL(SBTC_HERRNOLONGPTR),     (ULONG) &h_errno,
+    SBTM_SETVAL(SBTC_LOGTAGPTR),       (ULONG) "cURL",
+  TAG_DONE)) {
+    
+    __request("SocketBaseTags ERROR");
+    return FALSE;
+  }
+  
+#ifndef __libnix__
   atexit(amiga_cleanup);
+#endif
+  
   return TRUE;
 }
+
+#ifdef __libnix__
+ADD2EXIT(amiga_cleanup,-50);
+#endif

+ 11 - 5
Utilities/cmcurl/amigaos.h

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -32,13 +32,19 @@
 #include <proto/exec.h>
 #include <proto/dos.h>
 
-#include <bsdsocket.h>
+#include <sys/socket.h>
 
 #include "config-amigaos.h"
 
-#define select(args...) WaitSelect( args, NULL)
-#define inet_ntoa(x)    Inet_NtoA( x ## .s_addr)
-#define ioctl(a,b,c,d)  IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
+#ifndef select
+# define select(args...) WaitSelect( args, NULL)
+#endif
+#ifndef inet_ntoa
+# define inet_ntoa(x)    Inet_NtoA( x ## .s_addr)
+#endif
+#ifndef ioctl
+# define ioctl(a,b,c,d)  IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
+#endif
 #define _AMIGASF        1
 
 extern void amiga_cleanup();

+ 2 - 2
Utilities/cmcurl/arpa_telnet.h

@@ -39,7 +39,7 @@
 /*
  * The telnet options represented as strings
  */
-static const char *telnetoptions[]=
+static const char * const telnetoptions[]=
 {
   "BINARY",      "ECHO",           "RCP",           "SUPPRESS GO AHEAD",
   "NAME",        "STATUS",         "TIMING MARK",   "RCTE",
@@ -78,7 +78,7 @@ static const char *telnetoptions[]=
 /*
  * Then those numbers represented as strings:
  */
-static const char *telnetcmds[]=
+static const char * const telnetcmds[]=
 {
   "EOF",  "SUSP",  "ABORT", "EOR",  "SE",
   "NOP",  "DMARK", "BRK",   "IP",   "AO",

+ 115 - 37
Utilities/cmcurl/base64.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -40,28 +40,27 @@
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
+#include "urldata.h" /* for the SessionHandle definition */
+#include "easyif.h"  /* for Curl_convert_... prototypes */
 #include "base64.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 /* include memdebug.h last */
 #include "memdebug.h"
 
+/* ---- Base64 Encoding/Decoding Table --- */
+static const char table64[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 static void decodeQuantum(unsigned char *dest, const char *src)
 {
   unsigned int x = 0;
   int i;
+  char *found;
+
   for(i = 0; i < 4; i++) {
-    if(src[i] >= 'A' && src[i] <= 'Z')
-      x = (x << 6) + (unsigned int)(src[i] - 'A' + 0);
-    else if(src[i] >= 'a' && src[i] <= 'z')
-      x = (x << 6) + (unsigned int)(src[i] - 'a' + 26);
-    else if(src[i] >= '0' && src[i] <= '9')
-      x = (x << 6) + (unsigned int)(src[i] - '0' + 52);
-    else if(src[i] == '+')
-      x = (x << 6) + 62;
-    else if(src[i] == '/')
-      x = (x << 6) + 63;
+    if((found = strchr(table64, src[i])))
+      x = (x << 6) + (unsigned int)(found - table64);
     else if(src[i] == '=')
       x = (x << 6);
   }
@@ -76,43 +75,63 @@ static void decodeQuantum(unsigned char *dest, const char *src)
 /*
  * Curl_base64_decode()
  *
- * Given a base64 string at src, decode it into the memory pointed to by
- * dest. Returns the length of the decoded data.
+ * Given a base64 string at src, decode it and return an allocated memory in
+ * the *outptr. Returns the length of the decoded data.
  */
-size_t Curl_base64_decode(const char *src, char *dest)
+size_t Curl_base64_decode(const char *src, unsigned char **outptr)
 {
   int length = 0;
   int equalsTerm = 0;
   int i;
   int numQuantums;
   unsigned char lastQuantum[3];
-  size_t rawlen;
+  size_t rawlen=0;
+  unsigned char *newstr;
+
+  *outptr = NULL;
 
   while((src[length] != '=') && src[length])
     length++;
-  while(src[length+equalsTerm] == '=')
+  /* A maximum of two = padding characters is allowed */
+  if(src[length] == '=') {
     equalsTerm++;
-
+    if(src[length+equalsTerm] == '=')
+      equalsTerm++;
+  }
   numQuantums = (length + equalsTerm) / 4;
 
+  /* Don't allocate a buffer if the decoded length is 0 */
+  if (numQuantums <= 0)
+    return 0;
+
   rawlen = (numQuantums * 3) - equalsTerm;
 
+  /* The buffer must be large enough to make room for the last quantum
+  (which may be partially thrown out) and the zero terminator. */
+  newstr = malloc(rawlen+4);
+  if(!newstr)
+    return 0;
+
+  *outptr = newstr;
+
+  /* Decode all but the last quantum (which may not decode to a
+  multiple of 3 bytes) */
   for(i = 0; i < numQuantums - 1; i++) {
-    decodeQuantum((unsigned char *)dest, src);
-    dest += 3; src += 4;
+    decodeQuantum((unsigned char *)newstr, src);
+    newstr += 3; src += 4;
   }
 
+  /* This final decode may actually read slightly past the end of the buffer
+  if the input string is missing pad bytes.  This will almost always be
+  harmless. */
   decodeQuantum(lastQuantum, src);
   for(i = 0; i < 3 - equalsTerm; i++)
-    dest[i] = lastQuantum[i];
+    newstr[i] = lastQuantum[i];
 
+  newstr[i] = 0; /* zero terminate */
   return rawlen;
 }
 
-/* ---- Base64 Encoding --- */
-static char table64[]=
-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
 /*
  * Curl_base64_encode()
  *
@@ -121,7 +140,8 @@ static char table64[]=
  * went wrong, -1 is returned.
  *
  */
-size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
+size_t Curl_base64_encode(struct SessionHandle *data,
+                          const char *inp, size_t insize, char **outptr)
 {
   unsigned char ibuf[3];
   unsigned char obuf[4];
@@ -129,6 +149,9 @@ size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
   int inputparts;
   char *output;
   char *base64data;
+#ifdef CURL_DOES_CONVERSIONS
+  char *convbuf;
+#endif
 
   char *indata = (char *)inp;
 
@@ -141,6 +164,28 @@ size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
   if(NULL == output)
     return 0;
 
+#ifdef CURL_DOES_CONVERSIONS
+  /*
+   * 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.
+   */
+  if(data) {
+    convbuf = (char*)malloc(insize);
+    if(!convbuf) {
+      return 0;
+    }
+    memcpy(convbuf, indata, insize);
+    if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) {
+      free(convbuf);
+      return 0;
+    }
+    indata = convbuf; /* switch to the converted buffer */
+  }
+#else
+  (void)data;
+#endif
+
   while(insize > 0) {
     for (i = inputparts = 0; i < 3; i++) {
       if(insize > 0) {
@@ -153,10 +198,12 @@ size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
         ibuf[i] = 0;
     }
 
-    obuf [0] = (ibuf [0] & 0xFC) >> 2;
-    obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
-    obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
-    obuf [3] = ibuf [2] & 0x3F;
+    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 */
@@ -183,6 +230,10 @@ size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
   *output=0;
   *outptr = base64data; /* make it return the actual data memory */
 
+#ifdef CURL_DOES_CONVERSIONS
+  if(data)
+    free(convbuf);
+#endif
   return strlen(base64data); /* return the length of the new data */
 }
 /* ---- End of Base64 Encoding ---- */
@@ -205,14 +256,26 @@ int main(int argc, char **argv, char **envp)
   size_t base64Len;
   unsigned char *data;
   int dataLen;
+  struct SessionHandle *handle = NULL;
 
+#ifdef CURL_DOES_CONVERSIONS
+  /* get a Curl handle so Curl_base64_encode can translate properly */
+  handle = curl_easy_init();
+  if(handle == NULL) {
+    fprintf(stderr, "Error: curl_easy_init failed\n");
+    return 0;
+  }
+#endif
   data = (unsigned char *)suck(&dataLen);
-  base64Len = Curl_base64_encode(data, dataLen, &base64);
+  base64Len = Curl_base64_encode(handle, data, dataLen, &base64);
 
   fprintf(stderr, "%d\n", base64Len);
-  fprintf(stdout, "%s",   base64);
+  fprintf(stdout, "%s\n", base64);
 
   free(base64); free(data);
+#ifdef CURL_DOES_CONVERSIONS
+  curl_easy_cleanup(handle);
+#endif
   return 0;
 }
 #endif
@@ -235,10 +298,17 @@ int main(int argc, char **argv, char **envp)
   unsigned char *data;
   int dataLen;
   int i, j;
+#ifdef CURL_DOES_CONVERSIONS
+  /* get a Curl handle so main can translate properly */
+  struct SessionHandle *handle = curl_easy_init();
+  if(handle == NULL) {
+    fprintf(stderr, "Error: curl_easy_init failed\n");
+    return 0;
+  }
+#endif
 
   base64 = (char *)suck(&base64Len);
-  data = (unsigned char *)malloc(base64Len * 3/4 + 8);
-  dataLen = Curl_base64_decode(base64, data);
+  dataLen = Curl_base64_decode(base64, &data);
 
   fprintf(stderr, "%d\n", dataLen);
 
@@ -253,13 +323,21 @@ int main(int argc, char **argv, char **envp)
     printf(" | ");
 
     for(j=0; j < 0x10; j++)
-      if((j+i) < dataLen)
-        printf("%c", isgraph(data[i+j])?data[i+j]:'.');
-      else
+      if((j+i) < dataLen) {
+#ifdef CURL_DOES_CONVERSIONS
+        if(CURLE_OK !=
+             Curl_convert_from_network(handle, &data[i+j], (size_t)1))
+          data[i+j] = '.';
+#endif /* CURL_DOES_CONVERSIONS */
+        printf("%c", ISGRAPH(data[i+j])?data[i+j]:'.');
+      } else
         break;
     puts("");
   }
 
+#ifdef CURL_DOES_CONVERSIONS
+  curl_easy_cleanup(handle);
+#endif
   free(base64); free(data);
   return 0;
 }

+ 9 - 8
Utilities/cmcurl/base64.h

@@ -1,18 +1,18 @@
 #ifndef __BASE64_H
 #define __BASE64_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -22,6 +22,7 @@
  *
  * $Id$
  ***************************************************************************/
-size_t Curl_base64_encode(const char *input, size_t size, char **str);
-size_t Curl_base64_decode(const char *source, char *dest);
+size_t Curl_base64_encode(struct SessionHandle *data,
+                          const char *input, size_t size, char **str);
+size_t Curl_base64_decode(const char *source, unsigned char **outptr);
 #endif

+ 240 - 36
Utilities/cmcurl/config.h.in

@@ -1,4 +1,13 @@
-/* lib/config.h.in.  Generated from configure.in by autoheader.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* when building libcurl itself */
+#cmakedefine BUILDING_LIBCURL ${BUILDING_LIBCURL}
+
+/* to disable cookies support */
+#cmakedefine CURL_DISABLE_COOKIES ${CURL_DISABLE_COOKIES}
+
+/* to disable cryptographic authentication */
+#cmakedefine CURL_DISABLE_CRYPTO_AUTH ${CURL_DISABLE_CRYPTO_AUTH}
 
 /* to disable DICT */
 #cmakedefine CURL_DISABLE_DICT ${CURL_DISABLE_DICT}
@@ -9,9 +18,6 @@
 /* to disable FTP */
 #cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
 
-/* to disable GOPHER */
-#cmakedefine CURL_DISABLE_GOPHER ${CURL_DISABLE_GOPHER}
-
 /* to disable HTTP */
 #cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
 
@@ -21,24 +27,66 @@
 /* to disable TELNET */
 #cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
 
+/* to disable TFTP */
+#cmakedefine CURL_DISABLE_TFTP ${CURL_DISABLE_TFTP}
+
+/* to disable verbose strings */
+#cmakedefine CURL_DISABLE_VERBOSE_STRINGS ${CURL_DISABLE_VERBOSE_STRINGS}
+
+/* to make a symbol visible */
+#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
+
+/* to enable hidden symbols */
+#cmakedefine CURL_HIDDEN_SYMBOLS ${CURL_HIDDEN_SYMBOLS}
+
+/* when not building a shared library */
+#cmakedefine CURL_STATICLIB ${CURL_STATICLIB}
+
 /* Set to explicitly specify we don't want to use thread-safe functions */
 #cmakedefine DISABLED_THREADSAFE ${DISABLED_THREADSAFE}
 
+/* lber dynamic library file */
+#cmakedefine DL_LBER_FILE ${DL_LBER_FILE}
+
+/* ldap dynamic library file */
+#cmakedefine DL_LDAP_FILE ${DL_LDAP_FILE}
+
 /* your Entropy Gathering Daemon socket pathname */
 #cmakedefine EGD_SOCKET ${EGD_SOCKET}
 
 /* Define if you want to enable IPv6 support */
 #cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
 
+/* 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}
+
 /* Define to 1 if you have the <alloca.h> header file. */
 #cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
 
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #cmakedefine HAVE_ARPA_INET_H ${HAVE_ARPA_INET_H}
 
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#cmakedefine HAVE_ARPA_TFTP_H ${HAVE_ARPA_TFTP_H}
+
 /* Define to 1 if you have the <assert.h> header file. */
 #cmakedefine HAVE_ASSERT_H ${HAVE_ASSERT_H}
 
+/* Define to 1 if you have the `basename' function. */
+#cmakedefine HAVE_BASENAME ${HAVE_BASENAME}
+
 /* Define to 1 if you have the `closesocket' function. */
 #cmakedefine HAVE_CLOSESOCKET ${HAVE_CLOSESOCKET}
 
@@ -60,6 +108,12 @@
 /* Define to 1 if you have the `dlopen' function. */
 #cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
 
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES ${HAVE_ENGINE_LOAD_BUILTIN_ENGINES}
+
+/* Define to 1 if you have the <errno.h> header file. */
+#cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H}
+
 /* Define to 1 if you have the <err.h> header file. */
 #cmakedefine HAVE_ERR_H ${HAVE_ERR_H}
 
@@ -69,6 +123,12 @@
 /* use FIONBIO for non-blocking sockets */
 #cmakedefine HAVE_FIONBIO ${HAVE_FIONBIO}
 
+/* Define to 1 if you have the `fork' function. */
+#cmakedefine HAVE_FORK ${HAVE_FORK}
+
+/* Define to 1 if you have the `ftruncate' function. */
+#cmakedefine HAVE_FTRUNCATE ${HAVE_FTRUNCATE}
+
 /* Define if getaddrinfo exists and works */
 #cmakedefine HAVE_GETADDRINFO ${HAVE_GETADDRINFO}
 
@@ -93,12 +153,21 @@
 /* gethostbyname_r() takes 6 args */
 #cmakedefine HAVE_GETHOSTBYNAME_R_6 ${HAVE_GETHOSTBYNAME_R_6}
 
+/* Define to 1 if you have the getnameinfo function. */
+#cmakedefine HAVE_GETNAMEINFO ${HAVE_GETNAMEINFO}
+
 /* Define to 1 if you have the `getpass_r' function. */
 #cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
 
+/* Define to 1 if you have the `getprotobyname' function. */
+#cmakedefine HAVE_GETPROTOBYNAME ${HAVE_GETPROTOBYNAME}
+
 /* Define to 1 if you have the `getpwuid' function. */
 #cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
 
+/* Define to 1 if you have the `getrlimit' function. */
+#cmakedefine HAVE_GETRLIMIT ${HAVE_GETRLIMIT}
+
 /* Define to 1 if you have the `gettimeofday' function. */
 #cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
 
@@ -111,12 +180,18 @@
 /* if you have the gssapi libraries */
 #cmakedefine HAVE_GSSAPI ${HAVE_GSSAPI}
 
+/* if you have the GNU gssapi libraries */
+#cmakedefine HAVE_GSSGNU ${HAVE_GSSGNU}
+
 /* if you have the Heimdal gssapi libraries */
 #cmakedefine HAVE_GSSHEIMDAL ${HAVE_GSSHEIMDAL}
 
 /* if you have the MIT gssapi libraries */
 #cmakedefine HAVE_GSSMIT ${HAVE_GSSMIT}
 
+/* Define to 1 if you have the `idna_strerror' function. */
+#cmakedefine HAVE_IDNA_STRERROR ${HAVE_IDNA_STRERROR}
+
 /* Define to 1 if you have the `idn_free' function. */
 #cmakedefine HAVE_IDN_FREE ${HAVE_IDN_FREE}
 
@@ -159,12 +234,12 @@
 /* Define to 1 if you have the <krb.h> header file. */
 #cmakedefine HAVE_KRB_H ${HAVE_KRB_H}
 
-/* Define to 1 if you have the `crypto' library (-lcrypto). */
-#cmakedefine HAVE_LIBCRYPTO ${HAVE_LIBCRYPTO}
-
 /* Define to 1 if you have the `dl' library (-ldl). */
 #cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
 
+/* Define to 1 if you have the <libgen.h> header file. */
+#cmakedefine HAVE_LIBGEN_H ${HAVE_LIBGEN_H}
+
 /* Define to 1 if you have the `idn' library (-lidn). */
 #cmakedefine HAVE_LIBIDN ${HAVE_LIBIDN}
 
@@ -177,6 +252,12 @@
 /* Define to 1 if you have the `socket' library (-lsocket). */
 #cmakedefine HAVE_LIBSOCKET ${HAVE_LIBSOCKET}
 
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+#cmakedefine HAVE_LIBSSH2 ${HAVE_LIBSSH2}
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+#cmakedefine HAVE_LIBSSH2_H ${HAVE_LIBSSH2_H}
+
 /* Define to 1 if you have the `ssl' library (-lssl). */
 #cmakedefine HAVE_LIBSSL ${HAVE_LIBSSL}
 
@@ -186,18 +267,27 @@
 /* Define to 1 if you have the <limits.h> header file. */
 #cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
 
+/* if your compiler supports LL */
+#cmakedefine HAVE_LL ${HAVE_LL}
+
+/* Define to 1 if you have the <locale.h> header file. */
+#cmakedefine HAVE_LOCALE_H ${HAVE_LOCALE_H}
+
 /* Define to 1 if you have the `localtime_r' function. */
 #cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
 
-/* if your compiler supports 'long long' */
+/* if your compiler supports long long */
 #cmakedefine HAVE_LONGLONG ${HAVE_LONGLONG}
 
-/* Define to 1 if you have the <malloc.h> header file. */
+/* Define to 1 if you have the malloc.h header file. */
 #cmakedefine HAVE_MALLOC_H ${HAVE_MALLOC_H}
 
 /* Define to 1 if you have the <memory.h> header file. */
 #cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H}
 
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#cmakedefine HAVE_MSG_NOSIGNAL ${HAVE_MSG_NOSIGNAL}
+
 /* Define to 1 if you have the <netdb.h> header file. */
 #cmakedefine HAVE_NETDB_H ${HAVE_NETDB_H}
 
@@ -210,9 +300,12 @@
 /* Define to 1 if you have the <net/if.h> header file. */
 #cmakedefine HAVE_NET_IF_H ${HAVE_NET_IF_H}
 
-/* Define if NI_WITHSCOPEID exists and works */
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
 #cmakedefine HAVE_NI_WITHSCOPEID ${HAVE_NI_WITHSCOPEID}
 
+/* Defined if no inet_pton() prototype available */
+#cmakedefine HAVE_NO_INET_PTON_PROTO ${HAVE_NO_INET_PTON_PROTO}
+
 /* we have no strerror_r() proto */
 #cmakedefine HAVE_NO_STRERROR_R_DECL ${HAVE_NO_STRERROR_R_DECL}
 
@@ -228,6 +321,9 @@
 /* Define to 1 if you have the <openssl/pem.h> header file. */
 #cmakedefine HAVE_OPENSSL_PEM_H ${HAVE_OPENSSL_PEM_H}
 
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+#cmakedefine HAVE_OPENSSL_PKCS12_H ${HAVE_OPENSSL_PKCS12_H}
+
 /* Define to 1 if you have the <openssl/rsa.h> header file. */
 #cmakedefine HAVE_OPENSSL_RSA_H ${HAVE_OPENSSL_RSA_H}
 
@@ -246,6 +342,9 @@
 /* Define to 1 if you have the `perror' function. */
 #cmakedefine HAVE_PERROR ${HAVE_PERROR}
 
+/* Define to 1 if you have the `pipe' function. */
+#cmakedefine HAVE_PIPE ${HAVE_PIPE}
+
 /* Define to 1 if you have the `poll' function. */
 #cmakedefine HAVE_POLL ${HAVE_POLL}
 
@@ -267,15 +366,27 @@
 /* Define to 1 if you have the `RAND_status' function. */
 #cmakedefine HAVE_RAND_STATUS ${HAVE_RAND_STATUS}
 
+/* Define to 1 if you have the recv function. */
+#cmakedefine HAVE_RECV ${HAVE_RECV}
+
 /* Define to 1 if you have the <rsa.h> header file. */
 #cmakedefine HAVE_RSA_H ${HAVE_RSA_H}
 
-/* Define to 1 if you have the `select' function. */
+/* Define to 1 if you have the select function. */
 #cmakedefine HAVE_SELECT ${HAVE_SELECT}
 
+/* Define to 1 if you have the send function. */
+#cmakedefine HAVE_SEND ${HAVE_SEND}
+
 /* Define to 1 if you have the <setjmp.h> header file. */
 #cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H}
 
+/* Define to 1 if you have the `setlocale' function. */
+#cmakedefine HAVE_SETLOCALE ${HAVE_SETLOCALE}
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine HAVE_SETRLIMIT ${HAVE_SETRLIMIT}
+
 /* Define to 1 if you have the <sgtty.h> header file. */
 #cmakedefine HAVE_SGTTY_H ${HAVE_SGTTY_H}
 
@@ -288,9 +399,18 @@
 /* Define to 1 if you have the `signal' function. */
 #cmakedefine HAVE_SIGNAL ${HAVE_SIGNAL}
 
+/* Define to 1 if you have the <signal.h> header file. */
+#cmakedefine HAVE_SIGNAL_H ${HAVE_SIGNAL_H}
+
 /* If you have sigsetjmp */
 #cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
 
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#cmakedefine HAVE_SIG_ATOMIC_T ${HAVE_SIG_ATOMIC_T}
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE ${HAVE_SIG_ATOMIC_T_VOLATILE}
+
 /* Define to 1 if you have the `socket' function. */
 #cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
 
@@ -306,6 +426,9 @@
 /* Define to 1 if you have the <stdint.h> header file. */
 #cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
 
+/* Define to 1 if you have the <stdio.h> header file. */
+#cmakedefine HAVE_STDIO_H ${HAVE_STDIO_H}
+
 /* Define to 1 if you have the <stdlib.h> header file. */
 #cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H}
 
@@ -321,9 +444,6 @@
 /* Define to 1 if you have the `strerror_r' function. */
 #cmakedefine HAVE_STRERROR_R ${HAVE_STRERROR_R}
 
-/* Define to 1 if you have the `strftime' function. */
-#cmakedefine HAVE_STRFTIME ${HAVE_STRFTIME}
-
 /* Define to 1 if you have the `stricmp' function. */
 #cmakedefine HAVE_STRICMP ${HAVE_STRICMP}
 
@@ -348,6 +468,15 @@
 /* Define to 1 if you have the `strtoll' function. */
 #cmakedefine HAVE_STRTOLL ${HAVE_STRTOLL}
 
+/* if struct sockaddr_storage is defined */
+#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_STRUCT_SOCKADDR_STORAGE}
+
+/* Define to 1 if you have the timeval struct. */
+#cmakedefine HAVE_STRUCT_TIMEVAL ${HAVE_STRUCT_TIMEVAL}
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#cmakedefine HAVE_SYS_FILIO_H ${HAVE_SYS_FILIO_H}
+
 /* Define to 1 if you have the <sys/ioctl.h> header file. */
 #cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H}
 
@@ -357,6 +486,9 @@
 /* Define to 1 if you have the <sys/poll.h> header file. */
 #cmakedefine HAVE_SYS_POLL_H ${HAVE_SYS_POLL_H}
 
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H ${HAVE_SYS_RESOURCE_H}
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H}
 
@@ -378,12 +510,6 @@
 /* Define to 1 if you have the <sys/utime.h> header file. */
 #cmakedefine HAVE_SYS_UTIME_H ${HAVE_SYS_UTIME_H}
 
-/* Define to 1 if you have the `tcgetattr' function. */
-#cmakedefine HAVE_TCGETATTR ${HAVE_TCGETATTR}
-
-/* Define to 1 if you have the `tcsetattr' function. */
-#cmakedefine HAVE_TCSETATTR ${HAVE_TCSETATTR}
-
 /* Define to 1 if you have the <termios.h> header file. */
 #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
 
@@ -393,6 +519,12 @@
 /* Define to 1 if you have the <time.h> header file. */
 #cmakedefine HAVE_TIME_H ${HAVE_TIME_H}
 
+/* Define to 1 if you have the <tld.h> header file. */
+#cmakedefine HAVE_TLD_H ${HAVE_TLD_H}
+
+/* Define to 1 if you have the `tld_strerror' function. */
+#cmakedefine HAVE_TLD_STRERROR ${HAVE_TLD_STRERROR}
+
 /* Define to 1 if you have the `uname' function. */
 #cmakedefine HAVE_UNAME ${HAVE_UNAME}
 
@@ -405,44 +537,74 @@
 /* Define to 1 if you have the <utime.h> header file. */
 #cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H}
 
-/* Define to 1 if you have the <winsock.h> header file. */
+/* Define to 1 if you have the windows.h header file. */
+#cmakedefine HAVE_WINDOWS_H ${HAVE_WINDOWS_H}
+
+/* Define to 1 if you have the winsock2.h header file. */
+#cmakedefine HAVE_WINSOCK2_H ${HAVE_WINSOCK2_H}
+
+/* Define to 1 if you have the winsock.h header file. */
 #cmakedefine HAVE_WINSOCK_H ${HAVE_WINSOCK_H}
 
 /* Define this symbol if your OS supports changing the contents of argv */
 #cmakedefine HAVE_WRITABLE_ARGV ${HAVE_WRITABLE_ARGV}
 
+/* Define to 1 if you have the ws2tcpip.h header file. */
+#cmakedefine HAVE_WS2TCPIP_H ${HAVE_WS2TCPIP_H}
+
 /* Define to 1 if you have the <x509.h> header file. */
 #cmakedefine HAVE_X509_H ${HAVE_X509_H}
 
 /* if you have the zlib.h header file */
 #cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
 
+/* If you lack a fine basename() prototype */
+#cmakedefine NEED_BASENAME_PROTO ${NEED_BASENAME_PROTO}
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#cmakedefine NEED_MALLOC_H ${NEED_MALLOC_H}
+
 /* need REENTRANT defined */
 #cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
 
 /* cpu-machine-OS */
-#define OS         "${OPERATING_SYSTEM}"
+#define OS "${OPERATING_SYSTEM}"
 
 /* Name of package */
-#cmakedefine PACKAGE            "${PACKAGE}"
+#cmakedefine PACKAGE "${PACKAGE}"
 
 /* Define to the address where bug reports for this package should be sent. */
-#cmakedefine PACKAGE_BUGREPORT          "${PACKAGE_BUGREPORT}"
+#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}"
 
 /* Define to the full name of this package. */
-#cmakedefine PACKAGE_NAME               "${PACKAGE_NAME}"
+#cmakedefine PACKAGE_NAME "${PACKAGE_NAME}"
 
 /* Define to the full name and version of this package. */
-#cmakedefine PACKAGE_STRING             "${PACKAGE_STRING}"
+#cmakedefine PACKAGE_STRING "${PACKAGE_STRING}"
 
 /* Define to the one symbol short name of this package. */
-#cmakedefine PACKAGE_TARNAME            "${PACKAGE_TARNAME}"
+#cmakedefine PACKAGE_TARNAME "${PACKAGE_TARNAME}"
 
 /* Define to the version of this package. */
-#cmakedefine PACKAGE_VERSION            "${PACKAGE_VERSION}"
+#cmakedefine PACKAGE_VERSION "${PACKAGE_VERSION}"
 
 /* a suitable file to read random data from */
-#cmakedefine RANDOM_FILE                "${RANDOM_FILE}"
+#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
+
+/* 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}
@@ -456,12 +618,36 @@
 /* Define to the type of arg 5 for `select'. */
 #cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
 
-/* The size of a `curl_off_t', as computed by sizeof. */
+/* 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}
+
+/* The size of `curl_off_t', as computed by sizeof. */
 #cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T}
 
-/* The size of a `size_t', as computed by sizeof. */
+/* The size of `long', as computed by sizeof. */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* The size of `size_t', as computed by sizeof. */
 #cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
 
+/* The size of `time_t', as computed by sizeof. */
+#cmakedefine SIZEOF_TIME_T ${SIZEOF_TIME_T}
+
 /* Define to 1 if you have the ANSI C header files. */
 #cmakedefine STDC_HEADERS ${STDC_HEADERS}
 
@@ -471,11 +657,29 @@
 /* Define if you want to enable ares support */
 #cmakedefine USE_ARES ${USE_ARES}
 
+/* if GnuTLS is enabled */
+#cmakedefine USE_GNUTLS ${USE_GNUTLS}
+
+/* if libSSH2 is in use */
+#cmakedefine USE_LIBSSH2 ${USE_LIBSSH2}
+
 /* If you want to build curl with the built-in manual */
 #cmakedefine USE_MANUAL ${USE_MANUAL}
 
+/* if OpenSSL is in use */
+#cmakedefine USE_OPENSSL ${USE_OPENSSL}
+
+/* if SSL is enabled */
+#cmakedefine USE_SSLEAY ${USE_SSLEAY}
+
+/* to enable SSPI support */
+#cmakedefine USE_WINDOWS_SSPI ${USE_WINDOWS_SSPI}
+
 /* Version number of package */
-#cmakedefine VERSION            "${VERSION}"
+#cmakedefine VERSION "${VERSION}"
+
+/* Define to avoid automatic inclusion of winsock.h */
+#cmakedefine WIN32_LEAN_AND_MEAN ${WIN32_LEAN_AND_MEAN}
 
 /* Define to 1 if on AIX 3.
    System headers sometimes define this.
@@ -490,13 +694,16 @@
 /* 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 if not defined */
 #cmakedefine in_addr_t ${in_addr_t}
 
-/* Define to `unsigned' if <sys/types.h> does not define. */
+/* Define to `unsigned int' if <sys/types.h> does not define. */
 #cmakedefine size_t ${size_t}
 
 /* type to use in place of socklen_t if not defined */
@@ -505,8 +712,5 @@
 /* the signed version of size_t */
 #cmakedefine ssize_t ${ssize_t}
 
-/* define if the compiler supports number 0x3627676LL */
-#cmakedefine HAVE_LONG_LONG_CONSTANT ${HAVE_LONG_LONG_CONSTANT}
-
 /* Special handling of zlib library */
 #cmakedefine CURL_SPECIAL_ZLIB_H "${CURL_SPECIAL_ZLIB_H}"

+ 263 - 146
Utilities/cmcurl/connect.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,7 +25,9 @@
 
 #ifndef WIN32
 /* headers for non-win32 */
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -67,7 +69,7 @@
 #undef in_addr_t
 #define in_addr_t unsigned long
 #endif
-#ifdef  VMS
+#ifdef VMS
 #include <in.h>
 #include <inet.h>
 #endif
@@ -82,8 +84,7 @@
 #define FALSE 0
 #endif
 
-#ifdef WIN32
-#include <windows.h>
+#ifdef USE_WINSOCK
 #define EINPROGRESS WSAEINPROGRESS
 #define EWOULDBLOCK WSAEWOULDBLOCK
 #define EISCONN     WSAEISCONN
@@ -96,7 +97,12 @@
 #include "if2ip.h"
 #include "strerror.h"
 #include "connect.h"
-#include "curl_memory.h"
+#include "memory.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"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -105,18 +111,18 @@ static bool verifyconnect(curl_socket_t sockfd, int *error);
 
 static curl_socket_t
 singleipconnect(struct connectdata *conn,
-                Curl_addrinfo *ai, /* start connecting to this */
+                const Curl_addrinfo *ai, /* start connecting to this */
                 long timeout_ms,
                 bool *connected);
 
 /*
- * Curl_ourerrno() returns the errno (or equivalent) on this platform to
- * hide platform specific for the function that calls this.
+ * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this
+ * platform to hide platform specific for the function that calls this.
  */
-int Curl_ourerrno(void)
+int Curl_sockerrno(void)
 {
-#ifdef WIN32
-  return (int)GetLastError();
+#ifdef USE_WINSOCK
+  return (int)WSAGetLastError();
 #else
   return errno;
 #endif
@@ -131,72 +137,62 @@ int Curl_nonblock(curl_socket_t sockfd,    /* operate on this */
                   int nonblock   /* TRUE or FALSE */)
 {
 #undef SETBLOCK
+#define SETBLOCK 0
 #ifdef HAVE_O_NONBLOCK
-    {
-    /* most recent unix versions */
-    int flags;
+  /* most recent unix versions */
+  int flags;
 
-    flags = fcntl(sockfd, F_GETFL, 0);
-    if (TRUE == nonblock)
-      return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
-    else
-      return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
-    }
+  flags = fcntl(sockfd, F_GETFL, 0);
+  if (TRUE == nonblock)
+    return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+  else
+    return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+#undef SETBLOCK
 #define SETBLOCK 1
 #endif
 
-#ifdef HAVE_FIONBIO
-    {
-    /* older unix versions */
-    int flags;
+#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
+  /* older unix versions */
+  int flags;
 
-    flags = nonblock;
-    return ioctl(sockfd, FIONBIO, &flags);
-    }
-#ifdef SETBLOCK
-# undef SETBLOCK
-#endif
+  flags = nonblock;
+  return ioctl(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
 #define SETBLOCK 2
 #endif
 
-#ifdef HAVE_IOCTLSOCKET
+#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
   /* Windows? */
   unsigned long flags;
   flags = nonblock;
+
   return ioctlsocket(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
 #define SETBLOCK 3
 #endif
 
-#ifdef HAVE_IOCTLSOCKET_CASE
+#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
   /* presumably for Amiga */
   return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
-#ifdef SETBLOCK
-# undef SETBLOCK
-#endif
+#undef SETBLOCK
 #define SETBLOCK 4
 #endif
 
-#ifdef HAVE_SO_NONBLOCK
+#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
   /* BeOS */
   long b = nonblock ? 1 : 0;
   return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
-#ifdef SETBLOCK
-# undef SETBLOCK
-#endif
+#undef SETBLOCK
 #define SETBLOCK 5
 #endif
 
 #ifdef HAVE_DISABLED_NONBLOCKING
-  (void)nonblock;
-  (void)sockfd;
   return 0; /* returns success */
-#ifdef SETBLOCK
-# undef SETBLOCK
-#endif
+#undef SETBLOCK
 #define SETBLOCK 6
 #endif
 
-#ifndef SETBLOCK
+#if (SETBLOCK == 0)
 #error "no non-blocking method was found/used/set"
 #endif
 }
@@ -219,30 +215,16 @@ static
 int waitconnect(curl_socket_t sockfd, /* socket */
                 long timeout_msec)
 {
-  fd_set fd;
-  fd_set errfd;
-  struct timeval interval;
   int rc;
 #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. */
-  verifyconnect(sockfd, NULL);
+  (void)verifyconnect(sockfd, NULL);
 #endif
 
   /* now select() until we get connect or timeout */
-  FD_ZERO(&fd);
-  FD_SET(sockfd, &fd);
-
-  FD_ZERO(&errfd);
-  FD_SET(sockfd, &errfd);
-
-  interval.tv_sec = (int)(timeout_msec/1000);
-  timeout_msec -= interval.tv_sec*1000;
-
-  interval.tv_usec = timeout_msec*1000;
-
-  rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
+  rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
   if(-1 == rc)
     /* error, no connect here, try next */
     return WAITCONN_SELECT_ERROR;
@@ -251,7 +233,7 @@ int waitconnect(curl_socket_t sockfd, /* socket */
     /* timeout, no connect today */
     return WAITCONN_TIMEOUT;
 
-  if(FD_ISSET(sockfd, &errfd))
+  if(rc & CSELECT_ERR)
     /* error condition caught */
     return WAITCONN_FDSET_ERROR;
 
@@ -262,14 +244,19 @@ int waitconnect(curl_socket_t sockfd, /* socket */
 static CURLcode bindlocal(struct connectdata *conn,
                           curl_socket_t sockfd)
 {
-#ifdef HAVE_INET_NTOA
-  bool bindworked = FALSE;
   struct SessionHandle *data = conn->data;
+  struct sockaddr_in me;
+  struct sockaddr *sock = NULL;  /* bind to this address */
+  socklen_t socksize; /* size of the data sock points to */
+  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;
 
   /*************************************************************
    * Select device to bind socket to
    *************************************************************/
-  if (strlen(data->set.device)<255) {
+  if (data->set.device && (strlen(data->set.device)<255) ) {
     struct Curl_dns_entry *h=NULL;
     char myhost[256] = "";
     in_addr_t in;
@@ -288,8 +275,10 @@ static CURLcode bindlocal(struct connectdata *conn,
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_wait_for_resolv(conn, &h);
 
-      if(h)
+      if(h) {
         was_iface = TRUE;
+        Curl_resolv_unlock(data, h);
+      }
     }
 
     if(!was_iface) {
@@ -301,9 +290,17 @@ static CURLcode bindlocal(struct connectdata *conn,
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_wait_for_resolv(conn, &h);
 
-      if(h)
-        /* we know data->set.device is shorter than the myhost array */
-        strcpy(myhost, data->set.device);
+      if(h) {
+        if(in == CURL_INADDR_NONE)
+          /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+          Curl_inet_ntop(h->addr->ai_addr->sa_family,
+                         &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
+                         myhost, sizeof myhost);
+        else
+          /* we know data->set.device is shorter than the myhost array */
+          strcpy(myhost, data->set.device);
+        Curl_resolv_unlock(data, h);
+      }
     }
 
     if(! *myhost) {
@@ -317,7 +314,7 @@ static CURLcode bindlocal(struct connectdata *conn,
       return CURLE_HTTP_PORT_FAILED;
     }
 
-    infof(data, "We bind local end to %s\n", myhost);
+    infof(data, "Bind local address to %s\n", myhost);
 
 #ifdef SO_BINDTODEVICE
     /* I am not sure any other OSs than Linux that provide this feature, and
@@ -335,7 +332,7 @@ static CURLcode bindlocal(struct connectdata *conn,
       if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                      data->set.device, strlen(data->set.device)+1) != 0) {
         /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
-           sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
+           sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */
         infof(data, "SO_BINDTODEVICE %s failed\n",
               data->set.device);
         /* This is typically "errno 1, error: Operation not permitted" if
@@ -345,59 +342,78 @@ static CURLcode bindlocal(struct connectdata *conn,
 #endif
 
     in=inet_addr(myhost);
-    if (CURL_INADDR_NONE != in) {
+    if (CURL_INADDR_NONE == in) {
+      failf(data,"couldn't find my own IP address (%s)", myhost);
+      return CURLE_HTTP_PORT_FAILED;
+    } /* end of inet_addr */
 
-      if ( h ) {
-        Curl_addrinfo *addr = h->addr;
+    if ( h ) {
+      Curl_addrinfo *addr = h->addr;
+      sock = addr->ai_addr;
+      socksize = addr->ai_addrlen;
+    }
+    else
+      return CURLE_HTTP_PORT_FAILED;
 
-        Curl_resolv_unlock(data, h);
-        /* we don't need it anymore after this function has returned */
+  }
+  else if(port) {
+    /* if a local port number is requested but no local IP, extract the
+       address from the socket */
+    memset(&me, 0, sizeof(struct sockaddr));
+    me.sin_family = AF_INET;
+    me.sin_addr.s_addr = INADDR_ANY;
 
-        if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
-          /* we succeeded to bind */
-#ifdef ENABLE_IPV6
-          struct sockaddr_in6 add;
-#else
-          struct sockaddr_in add;
-#endif
+    sock = (struct sockaddr *)&me;
+    socksize = sizeof(struct sockaddr);
 
-#ifdef __hpux
-          int gsize = sizeof(add);
-#else
-          socklen_t gsize = sizeof(add);
-#endif
-          bindworked = TRUE;
+  }
+  else
+    /* no local kind of binding was requested */
+    return CURLE_OK;
 
-          if(getsockname(sockfd, (struct sockaddr *) &add,
-                         &gsize)<0) {
-            failf(data, "getsockname() failed");
-            return CURLE_HTTP_PORT_FAILED;
-          }
-        }
+  do {
 
-        if(!bindworked) {
-          failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
-          return CURLE_HTTP_PORT_FAILED;
-        }
+    /* Set port number to bind to, 0 makes the system pick one */
+    if(sock->sa_family == AF_INET)
+      ((struct sockaddr_in *)sock)->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+    else
+      ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
+#endif
+
+    if( bind(sockfd, sock, socksize) >= 0) {
+      /* we succeeded to bind */
+      struct Curl_sockaddr_storage add;
+      socklen_t size;
 
-      } /* end of if  h */
-      else {
-        failf(data,"could't find my own IP address (%s)", myhost);
+      size = sizeof(add);
+      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+        failf(data, "getsockname() failed");
         return CURLE_HTTP_PORT_FAILED;
       }
-    } /* end of inet_addr */
-
-    else {
-      failf(data, "could't find my own IP address (%s)", myhost);
-      return CURLE_HTTP_PORT_FAILED;
+      /* We re-use/clobber the port variable here below */
+      if(((struct sockaddr *)&add)->sa_family == AF_INET)
+        port = ntohs(((struct sockaddr_in *)&add)->sin_port);
+#ifdef ENABLE_IPV6
+      else
+        port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
+#endif
+      infof(data, "Local port: %d\n", port);
+      return CURLE_OK;
     }
+    if(--portnum > 0) {
+      infof(data, "Bind to local port %d failed, trying next\n", port);
+      port++; /* try next port */
+    }
+    else
+      break;
+  } while(1);
 
-    return CURLE_OK;
-
-  } /* end of device selection support */
-#endif /* end of HAVE_INET_NTOA */
-
+  data->state.os_errno = Curl_sockerrno();
+  failf(data, "bind failure: %s",
+        Curl_strerror(conn, data->state.os_errno));
   return CURLE_HTTP_PORT_FAILED;
+
 }
 
 /*
@@ -405,15 +421,10 @@ static CURLcode bindlocal(struct connectdata *conn,
  */
 static bool verifyconnect(curl_socket_t sockfd, int *error)
 {
-  bool rc;
+  bool rc = TRUE;
 #ifdef SO_ERROR
   int err = 0;
-#ifdef __hpux
-  int errSize = sizeof(err);
-#else
   socklen_t errSize = sizeof(err);
-#endif
-
 
 #ifdef WIN32
   /*
@@ -431,12 +442,24 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
    *
    *    Someone got to verify this on Win-NT 4.0, 2000."
    */
+
+#ifdef _WIN32_WCE
+  Sleep(0);
+#else
   SleepEx(0, FALSE);
+#endif
+
 #endif
 
   if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
                        (void *)&err, &errSize))
-    err = Curl_ourerrno();
+    err = Curl_sockerrno();
+
+#ifdef _WIN32_WCE
+  /* Always returns this error, bug in CE? */
+  if(WSAENOPROTOOPT==err)
+    err=0;
+#endif
 
   if ((0 == err) || (EISCONN == err))
     /* we are connected, awesome! */
@@ -449,11 +472,30 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
 #else
   (void)sockfd;
   if (error)
-    *error = Curl_ourerrno();
+    *error = Curl_sockerrno();
 #endif
   return rc;
 }
 
+CURLcode Curl_store_ip_addr(struct connectdata *conn)
+{
+  char addrbuf[256];
+  Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
+
+  /* save the string */
+  Curl_safefree(conn->ip_addr_str);
+  conn->ip_addr_str = strdup(addrbuf);
+  if(!conn->ip_addr_str)
+    return CURLE_OUT_OF_MEMORY; /* FAIL */
+
+#ifdef PF_INET6
+  if(conn->ip_addr->ai_family == PF_INET6)
+    conn->bits.ipv6 = TRUE;
+#endif
+
+  return CURLE_OK;
+}
+
 /* Used within the multi interface. Try next IP address, return TRUE if no
    more address exists */
 static bool trynextip(struct connectdata *conn,
@@ -463,6 +505,11 @@ static bool trynextip(struct connectdata *conn,
   curl_socket_t sockfd;
   Curl_addrinfo *ai;
 
+  /* first close the failed socket */
+  sclose(conn->sock[sockindex]);
+  conn->sock[sockindex] = CURL_SOCKET_BAD;
+  *connected = FALSE;
+
   if(sockindex != FIRSTSOCKET)
     return TRUE; /* no next */
 
@@ -475,6 +522,8 @@ static bool trynextip(struct connectdata *conn,
       /* store the new socket descriptor */
       conn->sock[sockindex] = sockfd;
       conn->ip_addr = ai;
+
+      Curl_store_ip_addr(conn);
       return FALSE;
     }
     ai = ai->ai_next;
@@ -496,6 +545,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   CURLcode code = CURLE_OK;
   curl_socket_t sockfd = conn->sock[sockindex];
   long allow = DEFAULT_CONNECT_TIMEOUT;
+  long allow_total = 0;
   long has_passed;
 
   curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
@@ -503,17 +553,17 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   *connected = FALSE; /* a very negative world view is best */
 
   /* Evaluate in milliseconds how much time that has passed */
-  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
 
   /* subtract the most strict timeout of the ones */
   if(data->set.timeout && data->set.connecttimeout) {
     if (data->set.timeout < data->set.connecttimeout)
-      allow = data->set.timeout*1000;
+      allow_total = allow = data->set.timeout*1000;
     else
       allow = data->set.connecttimeout*1000;
   }
   else if(data->set.timeout) {
-    allow = data->set.timeout*1000;
+    allow_total = allow = data->set.timeout*1000;
   }
   else if(data->set.connecttimeout) {
     allow = data->set.connecttimeout*1000;
@@ -526,30 +576,45 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   }
   if(conn->bits.tcpconnect) {
     /* we are connected already! */
+    Curl_expire(data, allow_total);
     *connected = TRUE;
     return CURLE_OK;
   }
 
+  Curl_expire(data, allow);
+
   /* check for connect without timeout as we want to return immediately */
   rc = waitconnect(sockfd, 0);
 
   if(WAITCONN_CONNECTED == rc) {
-    if (verifyconnect(sockfd, NULL)) {
+    int error;
+    if (verifyconnect(sockfd, &error)) {
       /* we are connected, awesome! */
       *connected = TRUE;
       return CURLE_OK;
     }
     /* nope, not connected for real */
+    data->state.os_errno = error;
     infof(data, "Connection failed\n");
     if(trynextip(conn, sockindex, connected)) {
       code = CURLE_COULDNT_CONNECT;
     }
   }
   else if(WAITCONN_TIMEOUT != rc) {
+    int error = 0;
+
     /* nope, not connected  */
-    infof(data, "Connection failed\n");
+    if (WAITCONN_FDSET_ERROR == rc) {
+      (void)verifyconnect(sockfd, &error);
+      data->state.os_errno = error;
+      infof(data, "%s\n",Curl_strerror(conn,error));
+    }
+    else
+      infof(data, "Connection failed\n");
+
     if(trynextip(conn, sockindex, connected)) {
-      int error = Curl_ourerrno();
+      error = Curl_sockerrno();
+      data->state.os_errno = error;
       failf(data, "Failed connect to %s:%d; %s",
             conn->host.name, conn->port, Curl_strerror(conn,error));
       code = CURLE_COULDNT_CONNECT;
@@ -569,10 +634,18 @@ static void tcpnodelay(struct connectdata *conn,
 #ifdef TCP_NODELAY
   struct SessionHandle *data= conn->data;
   socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
-  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&onoff,
+  int proto = IPPROTO_TCP;
+
+#ifdef HAVE_GETPROTOBYNAME
+  struct protoent *pe = getprotobyname("tcp");
+  if (pe)
+    proto = pe->p_proto;
+#endif
+
+  if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
                 sizeof(onoff)) < 0)
     infof(data, "Could not set TCP_NODELAY: %s\n",
-          Curl_strerror(conn, Curl_ourerrno()));
+          Curl_strerror(conn, Curl_sockerrno()));
   else
     infof(data,"TCP_NODELAY set\n");
 #else
@@ -581,21 +654,42 @@ static void tcpnodelay(struct connectdata *conn,
 #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 SessionHandle *data= conn->data;
+  int onoff = 1;
+  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
+                sizeof(onoff)) < 0)
+    infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+          Curl_strerror(conn, Curl_sockerrno()));
+}
+#else
+#define nosigpipe(x,y)
+#endif
+
 /* singleipconnect() connects to the given IP only, and it may return without
    having connected if used from the multi interface. */
 static curl_socket_t
 singleipconnect(struct connectdata *conn,
-                Curl_addrinfo *ai,
+                const Curl_addrinfo *ai,
                 long timeout_ms,
                 bool *connected)
 {
   char addr_buf[128];
   int rc;
   int error;
-  bool conected;
+  bool isconnected;
   struct SessionHandle *data = conn->data;
-  curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
-                                ai->ai_protocol);
+  curl_socket_t sockfd;
+  CURLcode res;
+
+  sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
   if (sockfd == CURL_SOCKET_BAD)
     return CURL_SOCKET_BAD;
 
@@ -607,21 +701,37 @@ singleipconnect(struct connectdata *conn,
   if(data->set.tcp_nodelay)
     tcpnodelay(conn, sockfd);
 
-  if(conn->data->set.device) {
-    /* user selected to bind the outgoing socket to a specified "device"
-       before doing connect */
-    CURLcode res = bindlocal(conn, sockfd);
-    if(res)
-      return res;
+  nosigpipe(conn, sockfd);
+
+  if(data->set.fsockopt) {
+    /* activate callback for setting socket options */
+    error = data->set.fsockopt(data->set.sockopt_client,
+                               sockfd,
+                               CURLSOCKTYPE_IPCXN);
+    if (error) {
+      sclose(sockfd); /* close the socket and bail out */
+      return CURL_SOCKET_BAD;
+    }
+  }
+
+  /* possibly bind the local end to an IP, interface or port */
+  res = bindlocal(conn, sockfd);
+  if(res) {
+    sclose(sockfd); /* close socket and bail out */
+    return CURL_SOCKET_BAD;
   }
 
   /* set socket non-blocking */
   Curl_nonblock(sockfd, TRUE);
 
-  rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
+  /* Connect TCP sockets, bind UDP */
+  if(conn->socktype == SOCK_STREAM)
+    rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
+  else
+    rc = 0;
 
   if(-1 == rc) {
-    error = Curl_ourerrno();
+    error = Curl_sockerrno();
 
     switch (error) {
     case EINPROGRESS:
@@ -639,6 +749,7 @@ singleipconnect(struct connectdata *conn,
       /* unknown error, fallthrough and try another address! */
       failf(data, "Failed to connect to %s: %s",
             addr_buf, Curl_strerror(conn,error));
+      data->state.os_errno = error;
       break;
     }
   }
@@ -651,9 +762,9 @@ singleipconnect(struct connectdata *conn,
     return sockfd;
   }
 
-  conected = verifyconnect(sockfd, &error);
+  isconnected = verifyconnect(sockfd, &error);
 
-  if(!rc && conected) {
+  if(!rc && isconnected) {
     /* we are connected, awesome! */
     *connected = TRUE; /* this is a true connect */
     infof(data, "connected\n");
@@ -661,8 +772,10 @@ singleipconnect(struct connectdata *conn,
   }
   else if(WAITCONN_TIMEOUT == rc)
     infof(data, "Timeout\n");
-  else
+  else {
+    data->state.os_errno = error;
     infof(data, "%s\n", Curl_strerror(conn, error));
+  }
 
   /* connect failed or timed out */
   sclose(sockfd);
@@ -677,7 +790,7 @@ singleipconnect(struct connectdata *conn,
  */
 
 CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
-                          struct Curl_dns_entry *remotehost, /* use this one */
+                          const struct Curl_dns_entry *remotehost, /* use this one */
                           curl_socket_t *sockconn,   /* the connected socket */
                           Curl_addrinfo **addr,      /* the one we used */
                           bool *connected)           /* really connected? */
@@ -704,7 +817,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
     long has_passed;
 
     /* Evaluate in milliseconds how much time that has passed */
-    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
 
 #ifndef min
 #define min(a, b)   ((a) < (b) ? (a) : (b))
@@ -731,6 +844,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
       return CURLE_OPERATION_TIMEOUTED;
     }
   }
+  Curl_expire(data, timeout_ms);
 
   /* Max time for each address */
   num_addr = Curl_num_addresses(remotehost->addr);
@@ -744,7 +858,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 
   if(data->state.used_interface == Curl_if_multi)
     /* don't hang when doing multi */
-    timeout_per_addr = timeout_ms = 0;
+    timeout_per_addr = 0;
 
   /*
    * Connecting with a Curl_addrinfo chain
@@ -771,6 +885,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   if (sockfd == CURL_SOCKET_BAD) {
     /* no good connect was made */
     *sockconn = CURL_SOCKET_BAD;
+    failf(data, "couldn't connect to host");
     return CURLE_COULDNT_CONNECT;
   }
 
@@ -784,5 +899,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   if(sockconn)
     *sockconn = sockfd;    /* the socket descriptor we've connected */
 
+  data->info.numconnects++; /* to track the number of connections made */
+
   return CURLE_OK;
 }

+ 5 - 3
Utilities/cmcurl/connect.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,13 +31,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,
                            bool *connected);
 
 CURLcode Curl_connecthost(struct connectdata *conn,
-                          struct Curl_dns_entry *host, /* connect to this */
+                          const struct Curl_dns_entry *host, /* connect to this */
                           curl_socket_t *sockconn, /* not set if error */
                           Curl_addrinfo **addr, /* the one we used */
                           bool *connected /* truly connected? */
                           );
 
-int Curl_ourerrno(void);
+int Curl_sockerrno(void);
+
+CURLcode Curl_store_ip_addr(struct connectdata *conn);
 
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
 

+ 147 - 86
Utilities/cmcurl/content_encoding.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -32,10 +32,14 @@
 #include <curl/curl.h>
 #include "sendf.h"
 #include "content_encoding.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 #include "memdebug.h"
 
+/* 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 DSIZ 0x10000             /* buffer size for decompressed data */
 
 #define GZIP_MAGIC_0 0x1f
@@ -49,14 +53,23 @@
 #define COMMENT      0x10 /* bit 4 set: file comment present */
 #define RESERVED     0xE0 /* bits 5..7: reserved */
 
+enum zlibState {
+  ZLIB_UNINIT,          /* uninitialized */
+  ZLIB_INIT,            /* initialized */
+  ZLIB_GZIP_HEADER,     /* reading gzip header */
+  ZLIB_GZIP_INFLATING,  /* inflating gzip stream */
+  ZLIB_INIT_GZIP        /* initialized in transparent gzip mode */
+};
+
 static CURLcode
-process_zlib_error(struct SessionHandle *data, z_stream *z)
+process_zlib_error(struct connectdata *conn, z_stream *z)
 {
+  struct SessionHandle *data = conn->data;
   if (z->msg)
-    failf (data, "Error while processing content unencoding.\n%s",
+    failf (data, "Error while processing content unencoding: %s",
            z->msg);
   else
-    failf (data, "Error while processing content unencoding.\n"
+    failf (data, "Error while processing content unencoding: "
            "Unknown failure within decompression software.");
 
   return CURLE_BAD_CONTENT_ENCODING;
@@ -66,71 +79,113 @@ static CURLcode
 exit_zlib(z_stream *z, bool *zlib_init, CURLcode result)
 {
   inflateEnd(z);
-  *zlib_init = 0;
+  *zlib_init = ZLIB_UNINIT;
   return result;
 }
 
-CURLcode
-Curl_unencode_deflate_write(struct SessionHandle *data,
-                            struct Curl_transfer_keeper *k,
-                            ssize_t nread)
+static CURLcode
+inflate_stream(struct connectdata *conn,
+               struct Curl_transfer_keeper *k)
 {
+  int allow_restart = 1;
+  z_stream *z = &k->z;          /* zlib state structure */
+  uInt nread = z->avail_in;
+  Bytef *orig_in = z->next_in;
   int status;                   /* zlib status */
   CURLcode result = CURLE_OK;   /* Curl_client_write status */
-  char decomp[DSIZ];            /* Put the decompressed data here. */
-  z_stream *z = &k->z;          /* zlib state structure */
+  char *decomp;                 /* Put the decompressed data here. */
 
-  /* Initialize zlib? */
-  if (!k->zlib_init) {
-    z->zalloc = (alloc_func)Z_NULL;
-    z->zfree = (free_func)Z_NULL;
-    z->opaque = 0;
-    z->next_in = NULL;
-    z->avail_in = 0;
-    if (inflateInit(z) != Z_OK)
-      return process_zlib_error(data, z);
-    k->zlib_init = 1;
+  /* Dynamically allocate a buffer for decompression because it's uncommonly
+     large to hold on the stack */
+  decomp = (char*)malloc(DSIZ);
+  if (decomp == NULL) {
+    return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
   }
 
-  /* Set the compressed input when this function is called */
-  z->next_in = (Bytef *)k->str;
-  z->avail_in = (uInt)nread;
-
-  /* because the buffer size is fixed, iteratively decompress
-     and transfer to the client via client_write. */
+  /* because the buffer size is fixed, iteratively decompress and transfer to
+     the client via client_write. */
   for (;;) {
     /* (re)set buffer for decompressed output for every iteration */
-    z->next_out = (Bytef *)&decomp[0];
+    z->next_out = (Bytef *)decomp;
     z->avail_out = DSIZ;
 
     status = inflate(z, Z_SYNC_FLUSH);
     if (status == Z_OK || status == Z_STREAM_END) {
-      if (DSIZ - z->avail_out) {
-        result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
+      allow_restart = 0;
+      if(DSIZ - z->avail_out) {
+        result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
                                    DSIZ - z->avail_out);
         /* if !CURLE_OK, clean up, return */
-        if (result)
+        if (result) {
+          free(decomp);
           return exit_zlib(z, &k->zlib_init, result);
+        }
       }
 
-      /* Done?; clean up, return */
+      /* Done? clean up, return */
       if (status == Z_STREAM_END) {
+        free(decomp);
         if (inflateEnd(z) == Z_OK)
           return exit_zlib(z, &k->zlib_init, result);
         else
-          return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+          return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
       }
 
       /* Done with these bytes, exit */
-      if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
+      if (status == Z_OK && z->avail_in == 0) {
+        free(decomp);
         return result;
+      }
+    }
+    else if (allow_restart && status == Z_DATA_ERROR) {
+      /* some servers seem to not generate zlib headers, so this is an attempt
+         to fix and continue anyway */
+
+      inflateReset(z);
+      if (inflateInit2(z, -MAX_WBITS) != Z_OK) {
+        return process_zlib_error(conn, z);
+      }
+      z->next_in = orig_in;
+      z->avail_in = nread;
+      allow_restart = 0;
+      continue;
     }
     else {                      /* Error; exit loop, handle below */
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+      free(decomp);
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
     }
   }
+  /* Will never get here */
+}
+
+CURLcode
+Curl_unencode_deflate_write(struct connectdata *conn,
+                            struct Curl_transfer_keeper *k,
+                            ssize_t nread)
+{
+  z_stream *z = &k->z;          /* zlib state structure */
+
+  /* Initialize zlib? */
+  if (k->zlib_init == ZLIB_UNINIT) {
+    z->zalloc = (alloc_func)Z_NULL;
+    z->zfree = (free_func)Z_NULL;
+    z->opaque = 0;
+    z->next_in = NULL;
+    z->avail_in = 0;
+    if (inflateInit(z) != Z_OK)
+      return process_zlib_error(conn, z);
+    k->zlib_init = ZLIB_INIT;
+  }
+
+  /* Set the compressed input when this function is called */
+  z->next_in = (Bytef *)k->str;
+  z->avail_in = (uInt)nread;
+
+  /* Now uncompress the data */
+  return inflate_stream(conn, k);
 }
 
+#ifdef OLD_ZLIB_SUPPORT
 /* Skip over the gzip header */
 static enum {
   GZIP_OK,
@@ -172,6 +227,7 @@ static enum {
       return GZIP_UNDERFLOW;
 
     len -= (extra_len + 2);
+    data += (extra_len + 2);
   }
 
   if (flags & ORIG_NAME) {
@@ -213,38 +269,67 @@ static enum {
   *headerlen = totallen - len;
   return GZIP_OK;
 }
+#endif
 
 CURLcode
-Curl_unencode_gzip_write(struct SessionHandle *data,
+Curl_unencode_gzip_write(struct connectdata *conn,
                          struct Curl_transfer_keeper *k,
                          ssize_t nread)
 {
-  int status;                   /* zlib status */
-  CURLcode result = CURLE_OK;   /* Curl_client_write status */
-  char decomp[DSIZ];            /* Put the decompressed data here. */
   z_stream *z = &k->z;          /* zlib state structure */
 
   /* Initialize zlib? */
-  if (!k->zlib_init) {
+  if (k->zlib_init == ZLIB_UNINIT) {
     z->zalloc = (alloc_func)Z_NULL;
     z->zfree = (free_func)Z_NULL;
     z->opaque = 0;
     z->next_in = NULL;
     z->avail_in = 0;
-    if (inflateInit2(z, -MAX_WBITS) != Z_OK)
-      return process_zlib_error(data, z);
-    k->zlib_init = 1;   /* Initial call state */
+
+    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);
+        }
+        k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+
+    } else {
+        /* we must parse the gzip header ourselves */
+        if (inflateInit2(z, -MAX_WBITS) != Z_OK) {
+          return process_zlib_error(conn, z);
+        }
+        k->zlib_init = ZLIB_INIT;   /* Initial call state */
+    }
   }
 
+  if (k->zlib_init == ZLIB_INIT_GZIP) {
+     /* Let zlib handle the gzip decompression entirely */
+     z->next_in = (Bytef *)k->str;
+     z->avail_in = (uInt)nread;
+     /* Now uncompress the data */
+     return inflate_stream(conn, k);
+  }
+
+#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(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);
+
+#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 (k->zlib_init) {
   /* Skip over gzip header? */
-  if (k->zlib_init == 1) {
+  case ZLIB_INIT:
+  {
     /* Initial call state */
     ssize_t hlen;
 
@@ -252,7 +337,7 @@ Curl_unencode_gzip_write(struct SessionHandle *data,
     case GZIP_OK:
       z->next_in = (Bytef *)k->str + hlen;
       z->avail_in = (uInt)(nread - hlen);
-      k->zlib_init = 3; /* Inflating stream state */
+      k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
       break;
 
     case GZIP_UNDERFLOW:
@@ -269,17 +354,20 @@ Curl_unencode_gzip_write(struct SessionHandle *data,
         return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
       }
       memcpy(z->next_in, k->str, z->avail_in);
-      k->zlib_init = 2;   /* Need more gzip header data state */
+      k->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(z, &k->zlib_init, process_zlib_error(data, z));
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
     }
 
   }
-  else if (k->zlib_init == 2) {
+  break;
+
+  case ZLIB_GZIP_HEADER:
+  {
     /* Need more gzip header data state */
     ssize_t hlen;
     unsigned char *oldblock = z->next_in;
@@ -300,7 +388,7 @@ Curl_unencode_gzip_write(struct SessionHandle *data,
       /* Don't point into the malloced block since we just freed it */
       z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
       z->avail_in = (uInt)(z->avail_in - hlen);
-      k->zlib_init = 3;   /* Inflating stream state */
+      k->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
       break;
 
     case GZIP_UNDERFLOW:
@@ -310,14 +398,18 @@ Curl_unencode_gzip_write(struct SessionHandle *data,
     case GZIP_BAD:
     default:
       free(z->next_in);
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
     }
 
   }
-  else {
+  break;
+
+  case ZLIB_GZIP_INFLATING:
+  default:
     /* Inflating stream state */
     z->next_in = (Bytef *)k->str;
     z->avail_in = (uInt)nread;
+    break;
   }
 
   if (z->avail_in == 0) {
@@ -325,39 +417,8 @@ Curl_unencode_gzip_write(struct SessionHandle *data,
     return CURLE_OK;
   }
 
-  /* because the buffer size is fixed, iteratively decompress and transfer to
-     the client via client_write. */
-  for (;;) {
-    /* (re)set buffer for decompressed output for every iteration */
-    z->next_out = (Bytef *)&decomp[0];
-    z->avail_out = DSIZ;
-
-    status = inflate(z, Z_SYNC_FLUSH);
-    if (status == Z_OK || status == Z_STREAM_END) {
-      if(DSIZ - z->avail_out) {
-        result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
-                                   DSIZ - z->avail_out);
-        /* if !CURLE_OK, clean up, return */
-        if (result)
-          return exit_zlib(z, &k->zlib_init, result);
-      }
-
-      /* Done?; clean up, return */
-      /* We should really check the gzip CRC here */
-      if (status == Z_STREAM_END) {
-        if (inflateEnd(z) == Z_OK)
-          return exit_zlib(z, &k->zlib_init, result);
-        else
-          return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
-      }
-
-      /* Done with these bytes, exit */
-      if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
-        return result;
-    }
-    else {                      /* Error; exit loop, handle below */
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
-    }
-  }
+  /* We've parsed the header, now uncompress the data */
+  return inflate_stream(conn, k);
+#endif
 }
 #endif /* HAVE_LIBZ */

+ 9 - 9
Utilities/cmcurl/content_encoding.h

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -31,11 +31,11 @@
 #define ALL_CONTENT_ENCODINGS "identity"
 #endif
 
-CURLcode Curl_unencode_deflate_write(struct SessionHandle *data, 
-                                     struct Curl_transfer_keeper *k, 
+CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
+                                     struct Curl_transfer_keeper *k,
                                      ssize_t nread);
 
 CURLcode
-Curl_unencode_gzip_write(struct SessionHandle *data, 
+Curl_unencode_gzip_write(struct connectdata *conn,
                          struct Curl_transfer_keeper *k,
                          ssize_t nread);

+ 255 - 117
Utilities/cmcurl/cookie.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -80,25 +80,30 @@ Example set of cookies:
 
 #include "setup.h"
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
 
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
+
+#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
+#include <curl/mprintf.h>
 
 #include "urldata.h"
 #include "cookie.h"
-#include "getdate.h"
 #include "strequal.h"
 #include "strtok.h"
 #include "sendf.h"
-#include "curl_memory.h"
+#include "memory.h"
+#include "share.h"
+#include "strtoofft.h"
 
 /* The last #include file should be: */
 #ifdef CURLDEBUG
 #include "memdebug.h"
 #endif
 
+#define my_isspace(x) ((x == ' ') || (x == '\t'))
+
 static void freecookie(struct Cookie *co)
 {
   if(co->expirestr)
@@ -111,6 +116,10 @@ static void freecookie(struct Cookie *co)
     free(co->name);
   if(co->value)
     free(co->value);
+  if(co->maxage)
+    free(co->maxage);
+  if(co->version)
+    free(co->version);
 
   free(co);
 }
@@ -126,6 +135,27 @@ static bool tailmatch(const char *little, const char *bigone)
   return (bool)strequal(little, bigone+biglen-littlelen);
 }
 
+/*
+ * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
+ */
+void Curl_cookie_loadfiles(struct SessionHandle *data)
+{
+  struct curl_slist *list = data->change.cookielist;
+  if(list) {
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+    while(list) {
+      data->cookies = Curl_cookie_init(data,
+                                       list->data,
+                                       data->cookies,
+                                       data->set.cookiesession);
+      list = list->next;
+    }
+    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    curl_slist_free_all(data->change.cookielist); /* clean up list */
+    data->change.cookielist = NULL; /* don't do this again! */
+  }
+}
+
 /****************************************************************************
  *
  * Curl_cookie_add()
@@ -156,7 +186,7 @@ Curl_cookie_add(struct SessionHandle *data,
   struct Cookie *co;
   struct Cookie *lastc=NULL;
   time_t now = time(NULL);
-  bool replace_old;
+  bool replace_old = FALSE;
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
 
   /* First, alloc and init a new struct for it */
@@ -176,7 +206,7 @@ Curl_cookie_add(struct SessionHandle *data,
 
     semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
 
-    while(*lineptr && isspace((int)*lineptr))
+    while(*lineptr && my_isspace(*lineptr))
       lineptr++;
 
     ptr = lineptr;
@@ -199,14 +229,14 @@ Curl_cookie_add(struct SessionHandle *data,
 
           /* Strip off trailing whitespace from the 'what' */
           size_t len=strlen(what);
-          while(len && isspace((int)what[len-1])) {
+          while(len && my_isspace(what[len-1])) {
             what[len-1]=0;
             len--;
           }
 
           /* Skip leading whitespace from the 'what' */
           whatptr=what;
-          while(isspace((int)*whatptr)) {
+          while(my_isspace(*whatptr)) {
             whatptr++;
           }
 
@@ -305,7 +335,7 @@ Curl_cookie_add(struct SessionHandle *data,
               break;
             }
             co->expires =
-              atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
+              atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
           }
           else if(strequal("expires", name)) {
             co->expirestr=strdup(whatptr);
@@ -348,7 +378,7 @@ Curl_cookie_add(struct SessionHandle *data,
       }
 
       ptr=semiptr+1;
-      while(ptr && *ptr && isspace((int)*ptr))
+      while(ptr && *ptr && my_isspace(*ptr))
         ptr++;
       semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
 
@@ -466,7 +496,7 @@ Curl_cookie_add(struct SessionHandle *data,
         co->secure = (bool)strequal(ptr, "TRUE");
         break;
       case 4:
-        co->expires = atoi(ptr);
+        co->expires = curlx_strtoofft(ptr, NULL, 10);
         break;
       case 5:
         co->name = strdup(ptr);
@@ -647,6 +677,10 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
     fp = stdin;
     fromfile=FALSE;
   }
+  else if(file && !*file) {
+    /* points to a "" string */
+    fp = NULL;
+  }
   else
     fp = file?fopen(file, "r"):NULL;
 
@@ -668,7 +702,7 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
           lineptr=line;
           headerline=FALSE;
         }
-        while(*lineptr && isspace((int)*lineptr))
+        while(*lineptr && my_isspace(*lineptr))
           lineptr++;
 
         Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
@@ -699,68 +733,85 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
                                    char *host, char *path, bool secure)
 {
-   struct Cookie *newco;
-   struct Cookie *co;
-   time_t now = time(NULL);
-   struct Cookie *mainco=NULL;
-
-   if(!c || !c->cookies)
-      return NULL; /* no cookie struct or no cookies in the struct */
-
-   co = c->cookies;
-
-   while(co) {
-     /* only process this cookie if it is not expired or had no expire
-        date AND that if the cookie requires we're secure we must only
-        continue if we are! */
-     if( (co->expires<=0 || (co->expires> now)) &&
-         (co->secure?secure:TRUE) ) {
-
-       /* now check if the domain is correct */
-       if(!co->domain ||
-          (co->tailmatch && tailmatch(co->domain, host)) ||
-          (!co->tailmatch && strequal(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->path ||
-            checkprefix(co->path, path) ) {
-
-           /* and now, we know this is a match and we should create an
-              entry for the return-linked-list */
-
-           newco = (struct Cookie *)malloc(sizeof(struct Cookie));
-           if(newco) {
-             /* first, copy the whole source cookie: */
-             memcpy(newco, co, sizeof(struct Cookie));
-
-             /* then modify our next */
-             newco->next = mainco;
-
-             /* point the main to us */
-             mainco = newco;
-           }
-           else {
-              /* failure, clear up the allocated chain and return NULL */
-             while(mainco) {
-               co = mainco->next;
-               free(mainco);
-               mainco = co;
-             }
-
-             return NULL;
-           }
-         }
-       }
-     }
-     co = co->next;
-   }
-
-   return mainco; /* return the new list */
+  struct Cookie *newco;
+  struct Cookie *co;
+  time_t now = time(NULL);
+  struct Cookie *mainco=NULL;
+
+  if(!c || !c->cookies)
+    return NULL; /* no cookie struct or no cookies in the struct */
+
+  co = c->cookies;
+
+  while(co) {
+    /* only process this cookie if it is not expired or had no expire
+       date AND that if the cookie requires we're secure we must only
+       continue if we are! */
+    if( (co->expires<=0 || (co->expires> now)) &&
+        (co->secure?secure:TRUE) ) {
+
+      /* now check if the domain is correct */
+      if(!co->domain ||
+         (co->tailmatch && tailmatch(co->domain, host)) ||
+         (!co->tailmatch && strequal(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->path ||
+           /* not using checkprefix() because matching should be
+              case-sensitive */
+           !strncmp(co->path, path, strlen(co->path)) ) {
+
+          /* and now, we know this is a match and we should create an
+             entry for the return-linked-list */
+
+          newco = (struct Cookie *)malloc(sizeof(struct Cookie));
+          if(newco) {
+            /* first, copy the whole source cookie: */
+            memcpy(newco, co, sizeof(struct Cookie));
+
+            /* then modify our next */
+            newco->next = mainco;
+
+            /* point the main to us */
+            mainco = newco;
+          }
+          else {
+            /* failure, clear up the allocated chain and return NULL */
+            while(mainco) {
+              co = mainco->next;
+              free(mainco);
+              mainco = co;
+            }
+
+            return NULL;
+          }
+        }
+      }
+    }
+    co = co->next;
+  }
+
+  return mainco; /* return the new list */
 }
 
+/*****************************************************************************
+ *
+ * Curl_cookie_clearall()
+ *
+ * Clear all existing cookies and reset the counter.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+  if(cookies) {
+    Curl_cookie_freelist(cookies->cookies);
+    cookies->cookies = NULL;
+    cookies->numcookies = 0;
+  }
+}
 
 /*****************************************************************************
  *
@@ -772,17 +823,56 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
 
 void Curl_cookie_freelist(struct Cookie *co)
 {
-   struct Cookie *next;
-   if(co) {
-      while(co) {
-         next = co->next;
-         free(co); /* we only free the struct since the "members" are all
+  struct Cookie *next;
+  if(co) {
+    while(co) {
+      next = co->next;
+      free(co); /* we only free the struct since the "members" are all
                       just copied! */
-         co = next;
-      }
-   }
+      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;
+
+  if(!cookies->cookies)
+    return;
+
+  first = curr = prev = cookies->cookies;
+
+  for(; curr; curr = next) {
+    next = curr->next;
+    if(!curr->expires) {
+      if(first == curr)
+        first = next;
+
+      if(prev == curr)
+        prev = next;
+      else
+        prev->next = next;
+
+      free(curr);
+      cookies->numcookies--;
+    }
+    else
+      prev = curr;
+  }
+
+  cookies->cookies = first;
 }
 
+
 /*****************************************************************************
  *
  * Curl_cookie_cleanup()
@@ -792,20 +882,48 @@ void Curl_cookie_freelist(struct Cookie *co)
  ****************************************************************************/
 void Curl_cookie_cleanup(struct CookieInfo *c)
 {
-   struct Cookie *co;
-   struct Cookie *next;
-   if(c) {
-      if(c->filename)
-         free(c->filename);
-      co = c->cookies;
-
-      while(co) {
-         next = co->next;
-         freecookie(co);
-         co = next;
-      }
-      free(c); /* free the base struct as well */
-   }
+  struct Cookie *co;
+  struct Cookie *next;
+  if(c) {
+    if(c->filename)
+      free(c->filename);
+    co = c->cookies;
+
+    while(co) {
+      next = co->next;
+      freecookie(co);
+      co = next;
+    }
+    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%s\t" /* domain */
+    "%s\t"   /* tailmatch */
+    "%s\t"   /* path */
+    "%s\t"   /* secure */
+    "%" FORMAT_OFF_T "\t"   /* expires */
+    "%s\t"   /* name */
+    "%s",    /* value */
+    /* 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:"");
 }
 
 /*
@@ -839,33 +957,22 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
   }
 
   if(c) {
+    char *format_ptr;
+
     fputs("# Netscape HTTP Cookie File\n"
-          "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
+          "# http://curlm.haxx.se/rfc/cookie_spec.html\n"
           "# This file was generated by libcurl! Edit at your own risk.\n\n",
           out);
     co = c->cookies;
 
     while(co) {
-      fprintf(out,
-              "%s%s\t" /* domain */
-              "%s\t" /* tailmatch */
-              "%s\t" /* path */
-              "%s\t" /* secure */
-              "%u\t" /* expires */
-              "%s\t" /* name */
-              "%s\n", /* value */
-
-              /* 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",
-              (unsigned int)co->expires,
-              co->name,
-              co->value?co->value:"");
-
+      format_ptr = get_netscape_format(co);
+      if (format_ptr == NULL) {
+        fprintf(out, "#\n# Fatal libcurl error\n");
+        return 1;
+      }
+      fprintf(out, "%s\n", format_ptr);
+      free(format_ptr);
       co=co->next;
     }
   }
@@ -876,4 +983,35 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
   return 0;
 }
 
-#endif /* CURL_DISABLE_HTTP */
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
+{
+  struct curl_slist *list = NULL;
+  struct curl_slist *beg;
+  struct Cookie *c;
+  char *line;
+
+  if ((data->cookies == NULL) ||
+      (data->cookies->numcookies == 0))
+    return NULL;
+
+  c = data->cookies->cookies;
+
+  beg = list;
+  while (c) {
+    /* fill the list with _all_ the cookies we know */
+    line = get_netscape_format(c);
+    if (line == NULL) {
+      /* get_netscape_format returns null only if we run out of memory */
+
+      curl_slist_free_all(beg); /* free some memory */
+      return NULL;
+    }
+    list = curl_slist_append(list, line);
+    free(line);
+    c = c->next;
+  }
+
+  return list;
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */

+ 15 - 3
Utilities/cmcurl/cookie.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,11 +24,13 @@
  ***************************************************************************/
 
 #include <stdio.h>
-#ifdef WIN32
+#if defined(WIN32)
 #include <time.h>
 #else
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#endif
 
 #include <curl/curl.h>
 
@@ -38,7 +40,7 @@ struct Cookie {
   char *value;       /* name = <this> */
   char *path;         /* path = <this> */
   char *domain;      /* domain = <this> */
-  long expires;    /* expires = <this> */
+  curl_off_t expires;  /* expires = <this> */
   char *expirestr;   /* the plain text version */
   bool tailmatch;    /* weather we do tail-matchning of the domain name */
 
@@ -89,7 +91,17 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
                                     char *, struct CookieInfo *, bool);
 struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);
 void Curl_cookie_freelist(struct Cookie *);
+void Curl_cookie_clearall(struct CookieInfo *cookies);
+void Curl_cookie_clearsess(struct CookieInfo *cookies);
 void Curl_cookie_cleanup(struct CookieInfo *);
 int Curl_cookie_output(struct CookieInfo *, char *);
 
+#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
+#define Curl_cookie_list(x) NULL
+#define Curl_cookie_loadfiles(x) do { } while (0)
+#else
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
+void Curl_cookie_loadfiles(struct SessionHandle *data);
+#endif
+
 #endif

+ 1 - 1
Utilities/cmcurl/curl.copyright

@@ -4,7 +4,7 @@ It was downloaded from http://curl.haxx.se
 
 COPYRIGHT AND PERMISSION NOTICE
 
-Copyright (c) 1996 - 2004, Daniel Stenberg, <[email protected]>.
+Copyright (c) 1996 - 2007, Daniel Stenberg, <[email protected]>.
 
 All rights reserved.
 

+ 376 - 87
Utilities/cmcurl/curl/curl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -47,16 +47,49 @@ typedef void CURL;
 extern "C" {
 #endif
 
+/*
+ * Decorate exportable functions for Win32 DLL linking.
+ * This avoids using a .def file for building libcurl.dll.
+ */
+#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB)
+#if defined(BUILDING_LIBCURL)
+#define CURL_EXTERN  __declspec(dllexport)
+#else
+#define CURL_EXTERN  __declspec(dllimport)
+#endif
+#else
+
+#ifdef CURL_HIDDEN_SYMBOLS
+/*
+ * This definition is used to make external definitions visibile in the
+ * shared library when symbols are hidden by default.  It makes no
+ * difference when compiling applications whether this is set or not,
+ * only when compiling the library.
+ */
+#define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+#define CURL_EXTERN
+#endif
+#endif
+
 /*
  * We want the typedef curl_off_t setup for large file support on all
  * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf
  * format strings when outputting a variable of type curl_off_t.
+ *
+ * Note: "pocc -Ze" is MSVC compatibily mode and this sets _MSC_VER!
  */
-#if defined(_MSC_VER) || defined(__LCC__)
+
+#if (defined(_MSC_VER) && !defined(__POCC__)) || (defined(__LCC__) && defined(WIN32))
 /* MSVC */
+#ifdef _WIN32_WCE
+  typedef long curl_off_t;
+#define CURL_FORMAT_OFF_T "%ld"
+#else
   typedef signed __int64 curl_off_t;
 #define CURL_FORMAT_OFF_T "%I64d"
-#else /* _MSC_VER || __LCC__ */
+#endif
+#else /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */
 #if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__)
 /* gcc on windows or Watcom */
   typedef long long curl_off_t;
@@ -88,7 +121,7 @@ extern "C" {
 #define CURL_FORMAT_OFF_T "%ld"
 #endif
 #endif /* GCC or Watcom on Windows */
-#endif /* _MSC_VER || __LCC__ */
+#endif /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */
 
 #ifdef UNDEF_FILE_OFFSET_BITS
 /* this was defined above for our checks, undefine it again */
@@ -100,6 +133,49 @@ extern "C" {
 #undef FILESIZEBITS
 #endif
 
+#if defined(_WIN32) && !defined(WIN32)
+/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
+   make this adjustment to catch this. */
+#define WIN32 1
+#endif
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \
+  !defined(__CYGWIN__) || defined(__MINGW32__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+   included, since they can't co-exist without problems */
+#include <winsock2.h>
+#endif
+#else
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+   libc5-based Linux systems. Only include it on system that are known to
+   require it! */
+#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(__minix)
+#include <sys/select.h>
+#endif
+
+#ifndef _WIN32_WCE
+#include <sys/socket.h>
+#endif
+#ifndef __WATCOMC__
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#ifdef WIN32
+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 */
+
 struct curl_httppost {
   struct curl_httppost *next;       /* next entry in the list */
   char *name;                       /* pointer to allocated name */
@@ -143,19 +219,47 @@ typedef size_t (*curl_write_callback)(char *buffer,
                                       size_t nitems,
                                       void *outstream);
 
-/* This is a brand new return code for the read callback that will signal
-   the caller to immediately abort the current transfer. */
+/* 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
 typedef size_t (*curl_read_callback)(char *buffer,
-                                     size_t size,
-                                     size_t nitems,
-                                     void *instream);
+                                      size_t size,
+                                      size_t nitems,
+                                      void *instream);
+
+typedef enum  {
+  CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
+  CURLSOCKTYPE_LAST   /* never use */
+} curlsocktype;
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+                                     curl_socket_t curlfd,
+                                     curlsocktype purpose);
 
+#ifndef CURL_NO_OLDIES
   /* not used since 7.10.8, will be removed in a future release */
 typedef int (*curl_passwd_callback)(void *clientp,
                                     const char *prompt,
                                     char *buffer,
                                     int buflen);
+#endif
+
+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);
 
 /*
  * The following typedef's are signatures of malloc, free, realloc, strdup and
@@ -200,13 +304,15 @@ typedef enum {
   CURLE_UNSUPPORTED_PROTOCOL,    /* 1 */
   CURLE_FAILED_INIT,             /* 2 */
   CURLE_URL_MALFORMAT,           /* 3 */
-  CURLE_URL_MALFORMAT_USER,      /* 4 (NOT USED) */
+  CURLE_URL_MALFORMAT_USER,      /* 4 - NOT USED */
   CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
   CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
   CURLE_COULDNT_CONNECT,         /* 7 */
   CURLE_FTP_WEIRD_SERVER_REPLY,  /* 8 */
-  CURLE_FTP_ACCESS_DENIED,       /* 9 */
-  CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 */
+  CURLE_FTP_ACCESS_DENIED,       /* 9 a service was denied by the FTP server
+                                    due to lack of access - when login fails
+                                    this is not returned. */
+  CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 - NOT USED */
   CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
   CURLE_FTP_WEIRD_USER_REPLY,    /* 12 */
   CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
@@ -224,6 +330,10 @@ typedef enum {
   CURLE_FTP_COULDNT_STOR_FILE,   /* 25 - failed FTP upload */
   CURLE_READ_ERROR,              /* 26 - could 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_TIMEOUTED,     /* 28 - the timeout time was reached */
   CURLE_FTP_COULDNT_SET_ASCII,   /* 29 - TYPE A failed */
   CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
@@ -262,10 +372,39 @@ typedef enum {
   CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
   CURLE_FTP_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_TFTP_DISKFULL,           /* 70 - out of disk space on server */
+  CURLE_TFTP_ILLEGAL,            /* 71 - Illegal TFTP operation */
+  CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
+  CURLE_TFTP_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 */
   CURL_LAST /* never use! */
 } CURLcode;
 
+/* 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 SSL_CTX */
@@ -274,9 +413,12 @@ typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
 /* Make a spelling correction for the operation timed-out define */
 #define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED
 
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
 /* backwards compatibility with older names */
 #define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
 #define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#endif
 
 typedef enum {
   CURLPROXY_HTTP = 0,
@@ -292,17 +434,29 @@ typedef enum {
 #define CURLAUTH_ANY ~0               /* all types set */
 #define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC)
 
+#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_DEFAULT CURLSSH_AUTH_ANY
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
 /* 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
 
-/* This is just to make older programs not break: */
+/* These are just to make older programs not break: */
 #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
 #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+#endif
 
 #define CURL_ERROR_SIZE 256
 
+/* parameter for the CURLOPT_FTP_SSL option */
 typedef enum {
   CURLFTPSSL_NONE,    /* do not attempt to use SSL */
   CURLFTPSSL_TRY,     /* try using SSL, proceed anyway otherwise */
@@ -311,6 +465,23 @@ typedef enum {
   CURLFTPSSL_LAST     /* not an option, never use */
 } curl_ftpssl;
 
+/* 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_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;
+
 /* long may be 32 or 64 bits, but we should never depend on anything else
    but 32 */
 #define CURLOPTTYPE_LONG          0
@@ -332,7 +503,8 @@ typedef enum {
  * platforms.
  */
 #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
-  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__)
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__)
   /* This compiler is believed to have an ISO compatible preprocessor */
 #define CURL_ISOCPP
 #else
@@ -655,7 +827,7 @@ typedef enum {
   CINIT(SSLENGINE_DEFAULT, LONG, 90),
 
   /* Non-zero value means to use the global dns cache */
-  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */
+  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeO BSOLETE soon */
 
   /* DNS cache timeout */
   CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
@@ -785,33 +957,102 @@ typedef enum {
   /* Enable/disable the TCP Nagle algorithm */
   CINIT(TCP_NODELAY, LONG, 121),
 
-  /* When doing 3rd party transfer, set the source host name with this */
-  CINIT(SOURCE_HOST, OBJECTPOINT, 122),
+  /* 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_FTP_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
+  */
+  CINIT(FTPSSLAUTH, LONG, 129),
+
+  CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+  CINIT(IOCTLDATA, 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 */
+  CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+
+  /* feed cookies into cookie engine */
+  CINIT(COOKIELIST, OBJECTPOINT, 135),
+
+  /* ignore Content-Length */
+  CINIT(IGNORE_CONTENT_LENGTH, 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. */
+  CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
+  /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+     above. */
+  CINIT(FTP_FILEMETHOD, LONG, 138),
+
+  /* Local port number to bind the socket to */
+  CINIT(LOCALPORT, 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.
+  */
+  CINIT(LOCALPORTRANGE, LONG, 140),
+
+  /* no transfer, set up connection and let application use the socket by
+     extracting it with CURLINFO_LASTSOCKET */
+  CINIT(CONNECT_ONLY, LONG, 141),
+
+  /* Function that will be called to convert from the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+
+  /* Function that will be called to convert to the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
 
-  /* When doing 3rd party transfer, set the source user and password with
-     this */
-  CINIT(SOURCE_USERPWD, OBJECTPOINT, 123),
+  /* 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 */
+  CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
 
-  /* When doing 3rd party transfer, set the source file path with this */
-  CINIT(SOURCE_PATH, OBJECTPOINT, 124),
+  /* if the connection proceeds too quickly then need to slow it down */
+  /* limit-rate: maximum number of bytes per second to send or receive */
+  CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
+  CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
 
-  /* When doing 3rd party transfer, set the source server's port number
-     with this */
-  CINIT(SOURCE_PORT, LONG, 125),
+  /* Pointer to command string to send if USER/PASS fails. */
+  CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
 
-  /* When doing 3rd party transfer, decide which server that should get the
-     PASV command (and the other gets the PORT).
-     0 (default) - The target host issues PASV.
-     1           - The source host issues PASV */
-  CINIT(PASV_HOST, LONG, 126),
+  /* callback function for setting socket options */
+  CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
+  CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
 
-  /* When doing 3rd party transfer, set the source pre-quote linked list
-     of commands with this */
-  CINIT(SOURCE_PREQUOTE, OBJECTPOINT, 127),
+  /* set to 0 to disable session ID re-use for this transfer, default is
+     enabled (== 1) */
+  CINIT(SSL_SESSIONID_CACHE, LONG, 150),
 
-  /* When doing 3rd party transfer, set the source post-quote linked list
-     of commands with this */
-  CINIT(SOURCE_POSTQUOTE, OBJECTPOINT, 128),
+  /* allowed SSH authentication methods */
+  CINIT(SSH_AUTH_TYPES, LONG, 151),
+
+  /* Used by scp/sftp to do public/private key authentication */
+  CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
+  CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+
+  /* Send CCC (Clear Command Channel) after authentication */
+  CINIT(FTP_SSL_CCC, LONG, 154),
 
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
@@ -831,13 +1072,6 @@ typedef enum {
 
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                           the obsolete stuff removed! */
-#define CURLOPT_HTTPREQUEST    -1
-#define CURLOPT_FTPASCII       CURLOPT_TRANSFERTEXT
-#define CURLOPT_MUTE           -2
-#define CURLOPT_PASSWDFUNCTION -3
-#define CURLOPT_PASSWDDATA     -4
-#define CURLOPT_CLOSEFUNCTION  -5
-
 #else
 /* This is set if CURL_NO_OLDIES is defined at compile-time */
 #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
@@ -894,8 +1128,8 @@ typedef enum {
 
 /* curl_strequal() and curl_strnequal() are subject for removal in a future
    libcurl, see lib/README.curlx for details */
-extern int (curl_strequal)(const char *s1, const char *s2);
-extern int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+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);
 
 /* name is uppercase CURLFORM_<name> */
 #ifdef CFINIT
@@ -941,8 +1175,8 @@ typedef enum {
 
 /* structure to be used as parameter for CURLFORM_ARRAY */
 struct curl_forms {
-  CURLformoption    option;
-  const char    *value;
+  CURLformoption option;
+  const char     *value;
 };
 
 /* use this for multipart formpost building */
@@ -984,10 +1218,30 @@ typedef enum {
  * adds one part that together construct a full post. Then use
  * CURLOPT_HTTPPOST to send it off to libcurl.
  */
-CURLFORMcode curl_formadd(struct curl_httppost **httppost,
-                          struct curl_httppost **last_post,
-                          ...);
+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()
  *
@@ -995,7 +1249,7 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  *
  * Free a multipart formpost previously built with curl_formadd().
  */
-void curl_formfree(struct curl_httppost *form);
+CURL_EXTERN void curl_formfree(struct curl_httppost *form);
 
 /*
  * NAME curl_getenv()
@@ -1005,7 +1259,7 @@ void curl_formfree(struct curl_httppost *form);
  * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
  * complete. DEPRECATED - see lib/README.curlx
  */
-char *curl_getenv(const char *variable);
+CURL_EXTERN char *curl_getenv(const char *variable);
 
 /*
  * NAME curl_version()
@@ -1014,10 +1268,10 @@ char *curl_getenv(const char *variable);
  *
  * Returns a static ascii string of the libcurl version.
  */
-char *curl_version(void);
+CURL_EXTERN char *curl_version(void);
 
 /*
- * NAME curl_escape()
+ * NAME curl_easy_escape()
  *
  * DESCRIPTION
  *
@@ -1025,18 +1279,34 @@ char *curl_version(void);
  * %XX versions). This function returns a new allocated string or NULL if an
  * error occurred.
  */
-char *curl_escape(const char *string, int length);
+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_unescape()
+ * 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.
  */
-char *curl_unescape(const char *string, int length);
+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()
@@ -1046,7 +1316,7 @@ char *curl_unescape(const char *string, int length);
  * Provided for de-allocation in the same translation unit that did the
  * allocation. Added in libcurl 7.10
  */
-void curl_free(void *p);
+CURL_EXTERN void curl_free(void *p);
 
 /*
  * NAME curl_global_init()
@@ -1056,7 +1326,7 @@ void curl_free(void *p);
  * curl_global_init() should be invoked exactly once for each application that
  * uses libcurl
  */
-CURLcode curl_global_init(long flags);
+CURL_EXTERN CURLcode curl_global_init(long flags);
 
 /*
  * NAME curl_global_init_mem()
@@ -1071,12 +1341,12 @@ CURLcode curl_global_init(long flags);
  * callback routines with be invoked by this library instead of the system
  * memory management routines like malloc, free etc.
  */
-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);
+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()
@@ -1086,7 +1356,7 @@ CURLcode curl_global_init_mem(long flags,
  * curl_global_cleanup() should be invoked exactly once for each application
  * that uses libcurl
  */
-void curl_global_cleanup(void);
+CURL_EXTERN void curl_global_cleanup(void);
 
 /* linked-list structure for the CURLOPT_QUOTE option (and other) */
 struct curl_slist {
@@ -1102,7 +1372,8 @@ struct curl_slist {
  * Appends a string to a linked list. If no list exists, it will be created
  * first. Returns the new list, after appending.
  */
-struct curl_slist *curl_slist_append(struct curl_slist *, const char *);
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
+                                                 const char *);
 
 /*
  * NAME curl_slist_free_all()
@@ -1111,7 +1382,7 @@ struct curl_slist *curl_slist_append(struct curl_slist *, const char *);
  *
  * free a previously built curl_slist.
  */
-void curl_slist_free_all(struct curl_slist *);
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
 
 /*
  * NAME curl_getdate()
@@ -1119,15 +1390,15 @@ void curl_slist_free_all(struct curl_slist *);
  * 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 for cases
- * where the specified time is relative now, like 'two weeks' or 'tomorrow'
- * etc.
+ * the first argument. The time argument in the second parameter is unused
+ * and should be set to NULL.
  */
-time_t curl_getdate(const char *p, const time_t *now);
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
 
 #define CURLINFO_STRING   0x100000
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
+#define CURLINFO_SLIST    0x400000
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_TYPEMASK 0xf00000
 
@@ -1157,9 +1428,15 @@ typedef enum {
   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,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 23
+  CURLINFO_LASTONE          = 30
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -1242,9 +1519,9 @@ typedef enum {
   CURLSHOPT_LAST  /* never use */
 } CURLSHoption;
 
-CURLSH *curl_share_init(void);
-CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
-CURLSHcode curl_share_cleanup(CURLSH *);
+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.
@@ -1254,15 +1531,16 @@ typedef enum {
   CURLVERSION_FIRST,
   CURLVERSION_SECOND,
   CURLVERSION_THIRD,
+  CURLVERSION_FOURTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
 /* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
    basicly 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 redfine the NOW to another enum
+   expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_THIRD
+#define CURLVERSION_NOW CURLVERSION_FOURTH
 
 typedef struct {
   CURLversion age;          /* age of the returned struct */
@@ -1270,18 +1548,26 @@ typedef struct {
   unsigned int version_num; /* LIBCURL_VERSION_NUM */
   const char *host;         /* OS/host/cpu/machine when configured */
   int features;             /* bitmask, see defines below */
-  char *ssl_version;        /* human readable string */
-  long ssl_version_num;     /* number */
-  const char *libz_version;       /* human readable string */
+  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 **protocols;
+  const char * const *protocols;
 
   /* The fields below this were added in CURLVERSION_SECOND */
   const char *ares;
   int ares_num;
 
-  /* This field was aded in CURLVERSION_THIRD */
+  /* 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 */
+
 } curl_version_info_data;
 
 #define CURL_VERSION_IPV6      (1<<0)  /* IPv6-enabled */
@@ -1295,6 +1581,9 @@ typedef struct {
 #define CURL_VERSION_SPNEGO    (1<<8)  /* SPNEGO auth */
 #define CURL_VERSION_LARGEFILE (1<<9)  /* supports files bigger than 2GB */
 #define CURL_VERSION_IDN       (1<<10) /* International Domain Names support */
+#define CURL_VERSION_SSPI      (1<<11) /* SSPI is supported */
+#define CURL_VERSION_CONV      (1<<12) /* character conversions are
+                                          supported */
 
 /*
  * NAME curl_version_info()
@@ -1304,7 +1593,7 @@ typedef struct {
  * This function returns a pointer to a static copy of the version info
  * struct. See above.
  */
-curl_version_info_data *curl_version_info(CURLversion);
+CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
 
 /*
  * NAME curl_easy_strerror()
@@ -1315,7 +1604,7 @@ curl_version_info_data *curl_version_info(CURLversion);
  * into the equivalent human readable error string.  This is useful
  * for printing meaningful error messages.
  */
-const char *curl_easy_strerror(CURLcode);
+CURL_EXTERN const char *curl_easy_strerror(CURLcode);
 
 /*
  * NAME curl_share_strerror()
@@ -1326,7 +1615,7 @@ const char *curl_easy_strerror(CURLcode);
  * into the equivalent human readable error string.  This is useful
  * for printing meaningful error messages.
  */
-const char *curl_share_strerror(CURLSHcode);
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
 
 #ifdef  __cplusplus
 }

+ 15 - 14
Utilities/cmcurl/curl/curlver.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -28,7 +28,13 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.12.1"
+#define LIBCURL_VERSION "7.16.1"
+
+/* The numeric version number is also available "in parts" by using these
+   defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 16
+#define LIBCURL_VERSION_PATCH 1
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
@@ -37,19 +43,14 @@
          0xXXYYZZ
 
    Where XX, YY and ZZ are the main version, release and patch numbers in
-   hexadecimal. All three numbers are always represented using two digits.  1.2
-   would appear as "0x010200" while version 9.11.7 appears as "0x090b07".
+   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 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.
+   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.
 */
-#define LIBCURL_VERSION_NUM 0x70C01
-
-/* The numeric version number is also available "in parts" by using these
-   defines: */
-#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 12
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_NUM 0x071001
 
 #endif /* __CURL_CURLVER_H */

+ 7 - 7
Utilities/cmcurl/curl/easy.h

@@ -26,10 +26,10 @@
 extern "C" {
 #endif
 
-CURL *curl_easy_init(void);
-CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
-CURLcode curl_easy_perform(CURL *curl);
-void curl_easy_cleanup(CURL *curl);
+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()
@@ -44,7 +44,7 @@ void curl_easy_cleanup(CURL *curl);
  * performed transfer, all results from this function are undefined until the
  * transfer is completed.
  */
-CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
 
 
 /*
@@ -59,7 +59,7 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
  * curl_easy_duphandle() for each new thread to avoid a series of identical
  * curl_easy_setopt() invokes in every thread.
  */
-CURL* curl_easy_duphandle(CURL *curl);
+CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
 
 /*
  * NAME curl_easy_reset()
@@ -72,7 +72,7 @@ CURL* curl_easy_duphandle(CURL *curl);
  * It does keep: live connections, the Session ID cache, the DNS cache and the
  * cookies.
  */
-void curl_easy_reset(CURL *curl);
+CURL_EXTERN void curl_easy_reset(CURL *curl);
 
 #ifdef  __cplusplus
 }

+ 37 - 21
Utilities/cmcurl/curl/mprintf.h

@@ -1,16 +1,18 @@
+#ifndef __CURL_MPRINTF_H
+#define __CURL_MPRINTF_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -21,34 +23,48 @@
  * $Id$
  ***************************************************************************/
 
-#ifndef H_MPRINTF
-#define H_MPRINTF
-
 #include <stdarg.h>
 #include <stdio.h> /* needed for FILE */
 
-int curl_mprintf(const char *format, ...);
-int curl_mfprintf(FILE *fd, const char *format, ...);
-int curl_msprintf(char *buffer, const char *format, ...);
-int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...);
-int curl_mvprintf(const char *format, va_list args);
-int curl_mvfprintf(FILE *fd, const char *format, va_list args);
-int curl_mvsprintf(char *buffer, const char *format, va_list args);
-int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args);
-char *curl_maprintf(const char *format, ...);
-char *curl_mvaprintf(const char *format, va_list args);
+#include "curl.h"
+
+#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 _MPRINTF_REPLACE
 # define printf curl_mprintf
 # define fprintf curl_mfprintf
+#ifdef CURLDEBUG
+/* When built with CURLDEBUG we define away the sprintf() functions since we
+   don't want internal code to be using them */
+# define sprintf sprintf_was_used
+# define vsprintf vsprintf_was_used
+#else
 # define sprintf curl_msprintf
+# define vsprintf curl_mvsprintf
+#endif
 # define snprintf curl_msnprintf
 # define vprintf curl_mvprintf
 # define vfprintf curl_mvfprintf
-# define vsprintf curl_mvsprintf
 # define vsnprintf curl_mvsnprintf
 # define aprintf curl_maprintf
 # define vaprintf curl_mvaprintf
 #endif
 
-#endif /* H_MPRINTF */
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __CURL_MPRINTF_H */

+ 166 - 60
Utilities/cmcurl/curl/multi.h

@@ -1,18 +1,18 @@
 #ifndef __CURL_MULTI_H
 #define __CURL_MULTI_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -23,16 +23,8 @@
  * $Id$
  ***************************************************************************/
 /*
-  This is meant to be the "external" header file. Don't give away any
-  internals here!
-
-  This document presents a mixture of ideas from at least:
-  - Daniel Stenberg
-  - Steve Dekorte
-  - Sterling Hughes
-  - Ben Greear
+  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
@@ -43,30 +35,18 @@
 
   o Enable the application to select() on its own file descriptors and curl's
     file descriptors simultaneous easily.
-  
-*/
-#if defined(_WIN32) && !defined(WIN32)
-/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
-   make this adjustment to catch this. */
-#define WIN32 1
-#endif
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock2.h>
-#else
-
-/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
-   libc5-based Linux systems. Only include it on system that are known to
-   require it! */
-#if defined(_AIX) || defined(NETWARE)
-#include <sys/select.h>
-#endif
 
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#endif
+*/
 
+/*
+ * 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
+ * <curl/curl.h> 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
@@ -76,15 +56,23 @@ extern "C" {
 typedef void CURLM;
 
 typedef enum {
-  CURLM_CALL_MULTI_PERFORM=-1, /* please call curl_multi_perform() soon */
+  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_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
+
 typedef enum {
   CURLMSG_NONE, /* first, not used */
   CURLMSG_DONE, /* This easy handle has completed. 'result' contains
@@ -106,27 +94,30 @@ typedef struct CURLMsg CURLMsg;
  * Name:    curl_multi_init()
  *
  * Desc:    inititalize multi-style curl usage
+ *
  * Returns: a new CURLM handle to use in all 'curl_multi' functions.
  */
-CURLM *curl_multi_init(void);
+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.
  */
-CURLMcode curl_multi_add_handle(CURLM *multi_handle,
-                                CURL *curl_handle);
+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.
   */
-CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
-                                   CURL *curl_handle);
+CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+                                               CURL *curl_handle);
 
  /*
   * Name:    curl_multi_fdset()
@@ -134,13 +125,14 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
   * 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.
   */
-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);
+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_perform()
@@ -158,8 +150,8 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
   *          still have occurred problems on invidual transfers even when this
   *          returns OK.
   */
-CURLMcode curl_multi_perform(CURLM *multi_handle,
-                             int *running_handles);
+CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
+                                         int *running_handles);
 
  /*
   * Name:    curl_multi_cleanup()
@@ -168,9 +160,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle,
   *          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.
   */
-CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
 
 /*
  * Name:    curl_multi_info_read()
@@ -200,22 +193,135 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle);
  *          queue (after this read) in the integer the second argument points
  *          to.
  */
-CURLMsg *curl_multi_info_read(CURLM *multi_handle,
-                              int *msgs_in_queue);
+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
+
+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_all(CURLM *multi_handle,
+                                            int *running_handles);
+
+/*
+ * 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);
+
+#undef CINIT /* re-using the same name as in curl.h */
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG          CURLOPTTYPE_LONG
+#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T         CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
+#endif
+
+typedef enum {
+  /* This is the socket callback function pointer */
+  CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+
+  /* This is the argument passed to the socket callback */
+  CINIT(SOCKETDATA, OBJECTPOINT, 2),
+
+    /* set to 1 to enable pipelining for this multi handle */
+  CINIT(PIPELINING, LONG, 3),
+
+   /* This is the timer callback function pointer */
+  CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+  /* This is the argument passed to the timer callback */
+  CINIT(TIMERDATA, OBJECTPOINT, 5),
+
+  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_strerror()
+ * Name:    curl_multi_assign()
  *
- * DESCRIPTION
+ * 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.
  *
- * 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: CURLM error code.
  */
-const char *curl_multi_strerror(CURLMcode);
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+                                        curl_socket_t sockfd, void *sockp);
 
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif
-  
+
 #endif

+ 14 - 2
Utilities/cmcurl/curlx.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -79,7 +79,19 @@
 #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 transparant and
-   easier to understand/patch. */
+   easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE
+   is set. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+
 # define printf curlx_mprintf
 # define fprintf curlx_mfprintf
 # define sprintf curlx_msprintf

+ 101 - 42
Utilities/cmcurl/dict.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -23,18 +23,22 @@
 
 #include "setup.h"
 
+#ifndef CURL_DISABLE_DICT
+
 /* -- WIN32 approved -- */
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
 
-#include <errno.h>
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef WIN32
 #include <time.h>
 #include <io.h>
 #else
@@ -42,7 +46,9 @@
 #include <sys/socket.h>
 #endif
 #include <netinet/in.h>
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -79,20 +85,59 @@
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
-CURLcode Curl_dict(struct connectdata *conn)
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static char *unescape_word(struct SessionHandle *data, char *inp)
+{
+  char *newp;
+  char *dictp;
+  char *ptr;
+  int len;
+  unsigned char byte;
+  int olen=0;
+
+  newp = curl_easy_unescape(data, inp, 0, &len);
+  if(!newp)
+    return NULL;
+
+  dictp = malloc(len*2 + 1); /* add one for terminating zero */
+  if(dictp) {
+    /* According to RFC2229 section 2.2, these letters need to be escaped with
+       \[letter] */
+    for(ptr = newp;
+        (byte = (unsigned char)*ptr) != 0;
+        ptr++) {
+      if ((byte <= 32) || (byte == 127) ||
+          (byte == '\'') || (byte == '\"') || (byte == '\\')) {
+        dictp[olen++] = '\\';
+      }
+      dictp[olen++] = byte;
+    }
+    dictp[olen]=0;
+
+    free(newp);
+  }
+  return dictp;
+}
+
+CURLcode Curl_dict(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;
+  CURLcode result=CURLE_OK;
   struct SessionHandle *data=conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
-  char *path = conn->path;
-  curl_off_t *bytecount = &conn->bytecount;
+  char *path = data->reqdata.path;
+  curl_off_t *bytecount = &data->reqdata.keep.bytecount;
+
+  *done = TRUE; /* unconditionally */
 
   if(conn->bits.user_passwd) {
     /* AUTH is missing */
@@ -101,7 +146,7 @@ CURLcode Curl_dict(struct connectdata *conn)
   if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
       strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
       strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
-      
+
     word = strchr(path, ':');
     if (word) {
       word++;
@@ -118,7 +163,7 @@ CURLcode Curl_dict(struct connectdata *conn)
         }
       }
     }
-      
+
     if ((word == NULL) || (*word == (char)0)) {
       failf(data, "lookup word is missing");
     }
@@ -128,31 +173,38 @@ CURLcode Curl_dict(struct connectdata *conn)
     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 "\n"
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
                         "MATCH "
                         "%s "    /* database */
                         "%s "    /* strategy */
-                        "%s\n"   /* word */
-                        "QUIT\n",
-                        
+                        "%s\r\n" /* word */
+                        "QUIT\r\n",
+
                         database,
                         strategy,
-                        word
+                        eword
                         );
+
+    free(eword);
+
     if(result)
       failf(data, "Failed sending DICT request");
     else
-      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-                             -1, NULL); /* no upload */      
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                                   -1, NULL); /* no upload */
     if(result)
       return result;
   }
   else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
            strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
            strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
-    
+
     word = strchr(path, ':');
     if (word) {
       word++;
@@ -165,57 +217,64 @@ CURLcode Curl_dict(struct connectdata *conn)
         }
       }
     }
-      
+
     if ((word == NULL) || (*word == (char)0)) {
       failf(data, "lookup word is missing");
     }
     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 "\n"
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
                         "DEFINE "
                         "%s "     /* database */
-                        "%s\n"    /* word */
-                        "QUIT\n",
+                        "%s\r\n"  /* word */
+                        "QUIT\r\n",
                         database,
-                        word);
+                        eword);
+
+    free(eword);
+
     if(result)
       failf(data, "Failed sending DICT request");
     else
-      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-                             -1, NULL); /* no upload */
-    
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                                   -1, NULL); /* no upload */
+
     if(result)
       return result;
-      
+
   }
   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 "\n"
-                          "%s\n"
-                          "QUIT\n", ppath);
+                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                          "%s\r\n"
+                          "QUIT\r\n", ppath);
       if(result)
         failf(data, "Failed sending DICT request");
       else
-        result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-                               -1, NULL);
+        result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                                     -1, NULL);
       if(result)
         return result;
     }
   }
-  (void)nthdef;
 
   return CURLE_OK;
 }
+#endif /*CURL_DISABLE_DICT*/

+ 7 - 7
Utilities/cmcurl/dict.h

@@ -2,18 +2,18 @@
 #define __DICT_H
 
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,7 +24,7 @@
  * $Id$
  ***************************************************************************/
 #ifndef CURL_DISABLE_DICT
-CURLcode Curl_dict(struct connectdata *conn);
+CURLcode Curl_dict(struct connectdata *conn, bool *done);
 CURLcode Curl_dict_done(struct connectdata *conn);
 #endif
 #endif

+ 393 - 81
Utilities/cmcurl/easy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -29,14 +29,18 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
 
 #include <errno.h>
 
 #include "strequal.h"
 
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef WIN32
 #include <time.h>
 #include <io.h>
 #else
@@ -44,7 +48,9 @@
 #include <sys/socket.h>
 #endif
 #include <netinet/in.h>
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -71,20 +77,37 @@
 #include "urldata.h"
 #include <curl/curl.h>
 #include "transfer.h"
-#include "ssluse.h"
+#include "sslgen.h"
 #include "url.h"
 #include "getinfo.h"
 #include "hostip.h"
 #include "share.h"
-#include "curl_memory.h"
+#include "strdup.h"
+#include "memory.h"
+#include "progress.h"
+#include "easyif.h"
+#include "sendf.h" /* for failf function prototype */
+#include <ca-bundle.h>
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+/* 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 /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
 /* The last #include file should be: */
 #include "memdebug.h"
 
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef USE_WINSOCK
 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
    of win32_init() */
 static void win32_cleanup(void)
@@ -100,12 +123,12 @@ static CURLcode win32_init(void)
   WSADATA wsaData;
   int err;
 
-#ifdef ENABLE_IPV6
-  wVersionRequested = MAKEWORD(2, 0);
-#else
-  wVersionRequested = MAKEWORD(1, 1);
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+  Error IPV6_requires_winsock2
 #endif
 
+  wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
   err = WSAStartup(wVersionRequested, &wsaData);
 
   if (err != 0)
@@ -160,17 +183,31 @@ static void idna_init (void)
 #endif  /* USE_LIBIDN */
 
 /* true globals -- for curl_global_init() and curl_global_cleanup() */
-static unsigned int  initialized = 0;
-static long          init_flags  = 0;
+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 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)strdup;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
 
 /**
@@ -179,18 +216,19 @@ curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
  */
 CURLcode curl_global_init(long flags)
 {
-  if (initialized)
+  if (initialized++)
     return CURLE_OK;
 
   /* 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)strdup;
+  Curl_cstrdup = (curl_strdup_callback)system_strdup;
   Curl_ccalloc = (curl_calloc_callback)calloc;
 
   if (flags & CURL_GLOBAL_SSL)
-    Curl_SSL_init();
+    if (!Curl_ssl_init())
+      return CURLE_FAILED_INIT;
 
   if (flags & CURL_GLOBAL_WIN32)
     if (win32_init() != CURLE_OK)
@@ -205,7 +243,6 @@ CURLcode curl_global_init(long flags)
   idna_init();
 #endif
 
-  initialized = 1;
   init_flags  = flags;
 
   return CURLE_OK;
@@ -219,7 +256,7 @@ 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)
 {
-  CURLcode code;
+  CURLcode code = CURLE_OK;
 
   /* Invalid input, return immediately */
   if (!m || !f || !r || !s || !c)
@@ -251,10 +288,13 @@ void curl_global_cleanup(void)
   if (!initialized)
     return;
 
+  if (--initialized)
+    return;
+
   Curl_global_host_cache_dtor();
 
   if (init_flags & CURL_GLOBAL_SSL)
-    Curl_SSL_cleanup();
+    Curl_ssl_cleanup();
 
   if (init_flags & CURL_GLOBAL_WIN32)
     win32_cleanup();
@@ -263,7 +303,6 @@ void curl_global_cleanup(void)
   amiga_cleanup();
 #endif
 
-  initialized = 0;
   init_flags  = 0;
 }
 
@@ -296,14 +335,10 @@ CURL *curl_easy_init(void)
  * curl_easy_setopt() is the external interface for setting options on an
  * easy handle.
  */
-typedef int (*func_T)(void);
+
 CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
 {
   va_list arg;
-  func_T param_func;
-  long param_long;
-  void *param_obj;
-  curl_off_t param_offset;
   struct SessionHandle *data = curl;
   CURLcode ret;
 
@@ -312,38 +347,95 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
 
   va_start(arg, tag);
 
-  /* PORTING NOTE:
-     Object pointers can't necessarily be casted to function pointers and
-     therefore we need to know what type it is and read the correct type
-     at once. This should also correct problems with different sizes of
-     the types.
-  */
-
-  if(tag < CURLOPTTYPE_OBJECTPOINT) {
-    /* This is a LONG type */
-    param_long = va_arg(arg, long);
-    ret = Curl_setopt(data, tag, param_long);
-  }
-  else if(tag < CURLOPTTYPE_FUNCTIONPOINT) {
-    /* This is a object pointer type */
-    param_obj = va_arg(arg, void *);
-    ret = Curl_setopt(data, tag, param_obj);
-  }
-  else if(tag < CURLOPTTYPE_OFF_T) {
-    /* This is a function pointer type */
-    param_func = va_arg(arg, func_T );
-    ret = Curl_setopt(data, tag, param_func);
-  }
-  else {
-    /* This is a curl_off_t type */
-    param_offset = va_arg(arg, curl_off_t);
-    ret = Curl_setopt(data, tag, param_offset);
-  }
+  ret = Curl_setopt(data, tag, arg);
 
   va_end(arg);
   return ret;
 }
 
+#ifdef CURL_MULTIEASY
+/***************************************************************************
+ * This function is still only for testing purposes. It makes a great way
+ * to run the full test suite on the multi interface instead of the easy one.
+ ***************************************************************************
+ *
+ * The *new* curl_easy_perform() is the external interface that performs a
+ * transfer previously setup.
+ *
+ * Wrapper-function that: 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. This will make everything internally use and assume multi interface.
+ */
+CURLcode curl_easy_perform(CURL *easy)
+{
+  CURLM *multi;
+  CURLMcode mcode;
+  CURLcode code = CURLE_OK;
+  int still_running;
+  struct timeval timeout;
+  int rc;
+  CURLMsg *msg;
+  fd_set fdread;
+  fd_set fdwrite;
+  fd_set fdexcep;
+  int maxfd;
+
+  if(!easy)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  multi = curl_multi_init();
+  if(!multi)
+    return CURLE_OUT_OF_MEMORY;
+
+  mcode = curl_multi_add_handle(multi, easy);
+  if(mcode) {
+    curl_multi_cleanup(multi);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* we start some action by calling perform right away */
+
+  do {
+    while(CURLM_CALL_MULTI_PERFORM ==
+          curl_multi_perform(multi, &still_running));
+
+    if(!still_running)
+      break;
+
+    FD_ZERO(&fdread);
+    FD_ZERO(&fdwrite);
+    FD_ZERO(&fdexcep);
+
+    /* timeout once per second */
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 0;
+
+    /* get file descriptors from the transfers */
+    curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
+
+    rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+
+    if(rc == -1)
+      /* select error */
+      break;
+
+    /* timeout or data to send/receive => loop! */
+  } while(still_running);
+
+  msg = curl_multi_info_read(multi, &rc);
+  if(msg)
+    code = msg->data.result;
+
+  mcode = curl_multi_remove_handle(multi, easy);
+  /* what to do if it fails? */
+
+  mcode = curl_multi_cleanup(multi);
+  /* what to do if it fails? */
+
+  return code;
+}
+#else
 /*
  * curl_easy_perform() is the external interface that performs a transfer
  * previously setup.
@@ -358,16 +450,18 @@ CURLcode curl_easy_perform(CURL *curl)
   if ( ! (data->share && data->share->hostcache) ) {
 
     if (Curl_global_host_cache_use(data) &&
-        data->hostcache != Curl_global_host_cache_get()) {
-      if (data->hostcache)
-        Curl_hash_destroy(data->hostcache);
-      data->hostcache = Curl_global_host_cache_get();
+        (data->dns.hostcachetype != HCACHE_GLOBAL)) {
+      if (data->dns.hostcachetype == HCACHE_PRIVATE)
+        Curl_hash_destroy(data->dns.hostcache);
+      data->dns.hostcache = Curl_global_host_cache_get();
+      data->dns.hostcachetype = HCACHE_GLOBAL;
     }
 
-    if (!data->hostcache) {
-      data->hostcache = Curl_mk_dnscache();
+    if (!data->dns.hostcache) {
+      data->dns.hostcachetype = HCACHE_PRIVATE;
+      data->dns.hostcache = Curl_mk_dnscache();
 
-      if(!data->hostcache)
+      if(!data->dns.hostcache)
         /* While we possibly could survive and do good without a host cache,
            the fact that creating it failed indicates that things are truly
            screwed up and we should bail out! */
@@ -376,8 +470,16 @@ CURLcode curl_easy_perform(CURL *curl)
 
   }
 
+  if(!data->state.connc) {
+    /* oops, no connection cache, make one up */
+    data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
+    if(!data->state.connc)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
   return Curl_perform(data);
 }
+#endif
 
 /*
  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
@@ -390,14 +492,25 @@ void curl_easy_cleanup(CURL *curl)
   if(!data)
     return;
 
-  if ( ! (data->share && data->share->hostcache) ) {
-    if ( !Curl_global_host_cache_use(data)) {
-      Curl_hash_destroy(data->hostcache);
-    }
-  }
   Curl_close(data);
 }
 
+/*
+ * Store a pointed to the multi handle within the easy handle's data struct.
+ */
+void Curl_easy_addmulti(struct SessionHandle *data,
+                        void *multi)
+{
+  data->multi = multi;
+}
+
+void Curl_easy_initHandleData(struct SessionHandle *data)
+{
+    memset(&data->reqdata, 0, sizeof(struct HandleData));
+
+    data->reqdata.maxdownload = -1;
+}
+
 /*
  * curl_easy_getinfo() is an external interface that allows an app to retrieve
  * information from a performed transfer and similar.
@@ -445,21 +558,21 @@ CURL *curl_easy_duphandle(CURL *incurl)
 
     /* copy all userdefined values */
     outcurl->set = data->set;
-    outcurl->state.numconnects = data->state.numconnects;
-    outcurl->state.connects = (struct connectdata **)
-      malloc(sizeof(struct connectdata *) * outcurl->state.numconnects);
 
-    if(!outcurl->state.connects) {
+    if(data->state.used_interface == Curl_if_multi)
+      outcurl->state.connc = data->state.connc;
+    else
+      outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
+
+    if(!outcurl->state.connc)
       break;
-    }
 
-    memset(outcurl->state.connects, 0,
-           sizeof(struct connectdata *)*outcurl->state.numconnects);
+    outcurl->state.lastconnect = -1;
 
     outcurl->progress.flags    = data->progress.flags;
     outcurl->progress.callback = data->progress.callback;
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
     if(data->cookies) {
       /* If cookies are enabled in the parent handle, we enable them
          in the clone as well! */
@@ -474,18 +587,14 @@ CURL *curl_easy_duphandle(CURL *incurl)
 #endif   /* CURL_DISABLE_HTTP */
 
     /* duplicate all values in 'change' */
+
     if(data->change.url) {
       outcurl->change.url = strdup(data->change.url);
       if(!outcurl->change.url)
         break;
       outcurl->change.url_alloc = TRUE;
     }
-    if(data->change.proxy) {
-      outcurl->change.proxy = strdup(data->change.proxy);
-      if(!outcurl->change.proxy)
-        break;
-      outcurl->change.proxy_alloc = TRUE;
-    }
+
     if(data->change.referer) {
       outcurl->change.referer = strdup(data->change.referer);
       if(!outcurl->change.referer)
@@ -499,18 +608,29 @@ CURL *curl_easy_duphandle(CURL *incurl)
       break;
 #endif
 
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+    outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                     CURL_ICONV_CODESET_OF_NETWORK);
+    outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                                      CURL_ICONV_CODESET_OF_HOST);
+    outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                  CURL_ICONV_CODESET_FOR_UTF8);
+#endif
+
+    Curl_easy_initHandleData(outcurl);
+
+    outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
     fail = FALSE; /* we reach this point and thus we are OK */
 
   } while(0);
 
   if(fail) {
     if(outcurl) {
-      if(outcurl->state.connects)
-        free(outcurl->state.connects);
+      if(outcurl->state.connc->type == CONNCACHE_PRIVATE)
+        Curl_rm_connc(outcurl->state.connc);
       if(outcurl->state.headerbuff)
         free(outcurl->state.headerbuff);
-      if(outcurl->change.proxy)
-        free(outcurl->change.proxy);
       if(outcurl->change.url)
         free(outcurl->change.url);
       if(outcurl->change.referer)
@@ -531,12 +651,21 @@ void curl_easy_reset(CURL *curl)
 {
   struct SessionHandle *data = (struct SessionHandle *)curl;
 
+  Curl_safefree(data->reqdata.pathbuffer);
+  data->reqdata.pathbuffer=NULL;
+
+  Curl_safefree(data->reqdata.proto.generic);
+  data->reqdata.proto.generic=NULL;
+
   /* zero out UserDefined data: */
   memset(&data->set, 0, sizeof(struct UserDefined));
 
   /* zero out Progress data: */
   memset(&data->progress, 0, sizeof(struct Progress));
 
+  /* init Handle data */
+  Curl_easy_initHandleData(data);
+
   /* The remainder of these calls have been taken from Curl_open() */
 
   data->set.out = stdout; /* default output to stdout */
@@ -550,6 +679,7 @@ void curl_easy_reset(CURL *curl)
   data->set.fread = (curl_read_callback)fread;
 
   data->set.infilesize = -1; /* we don't know any size */
+  data->set.postfieldsize = -1;
 
   data->state.current_speed = -1; /* init to negative == impossible */
 
@@ -561,6 +691,7 @@ void curl_easy_reset(CURL *curl)
 
   /* make libcurl quiet by default: */
   data->set.hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
+  data->progress.flags |= PGRS_HIDE;
 
   /* Set the default size of the SSL session ID cache */
   data->set.ssl.numsessions = 5;
@@ -580,4 +711,185 @@ void curl_easy_reset(CURL *curl)
   /* This is our prefered CA cert bundle since install time */
   data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
 #endif
+
+  data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
+                                                      type */
 }
+
+#ifdef CURL_DOES_CONVERSIONS
+/*
+ * Curl_convert_to_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+                                 char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convtonetwork) {
+    /* use translation callback */
+    rc = data->set.convtonetwork(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
+            rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  } else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    char *input_ptr, *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->outbound_cd == (iconv_t)-1) {
+      data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                                     CURL_ICONV_CODESET_OF_HOST);
+      if(data->outbound_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(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    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.
+ */
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+                                      char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convfromnetwork) {
+    /* use translation callback */
+    rc = data->set.convfromnetwork(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
+            rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  } else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    char *input_ptr, *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->inbound_cd == (iconv_t)-1) {
+      data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                    CURL_ICONV_CODESET_OF_NETWORK);
+      if(data->inbound_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(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
+      failf(data,
+        "The 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 SessionHandle *data,
+                                     char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convfromutf8) {
+    /* use translation callback */
+    rc = data->set.convfromutf8(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
+            rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  } else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    char *input_ptr, *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->utf8_cd == (iconv_t)-1) {
+      data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                 CURL_ICONV_CODESET_FOR_UTF8);
+      if(data->utf8_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(data->utf8_cd, (const char**)&input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    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;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */

+ 40 - 0
Utilities/cmcurl/easyif.h

@@ -0,0 +1,40 @@
+#ifndef __EASYIF_H
+#define __EASYIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by easy.c
+ */
+void Curl_easy_addmulti(struct SessionHandle *data, void *multi);
+
+void Curl_easy_initHandleData(struct SessionHandle *data);
+
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+
+#endif /* __EASYIF_H */

+ 55 - 9
Utilities/cmcurl/escape.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,7 +31,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "curl_memory.h"
+#include "memory.h"
+/* urldata.h and easyif.h are included for Curl_convert_... prototypes */
+#include "urldata.h"
+#include "easyif.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -39,16 +42,32 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+/* 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(CURL *handle, const char *string, int inlength)
 {
   size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
   char *ns;
-  char *testing_ptr;
+  char *testing_ptr = NULL;
   unsigned char in;
   size_t newlen = alloc;
   int strindex=0;
   size_t length;
 
+#ifndef CURL_DOES_CONVERSIONS
+  /* avoid compiler warnings */
+  (void)handle;
+#endif
   ns = malloc(alloc);
   if(!ns)
     return NULL;
@@ -72,6 +91,17 @@ char *curl_escape(const char *string, int inlength)
           ns = testing_ptr;
         }
       }
+
+#ifdef CURL_DOES_CONVERSIONS
+/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
+      if (!handle ||
+          (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) {
+        /* Curl_convert_to_network calls failf if unsuccessful */
+        free(ns);
+        return NULL;
+      }
+#endif /* CURL_DOES_CONVERSIONS */
+
       snprintf(&ns[strindex], 4, "%%%02X", in);
 
       strindex+=3;
@@ -86,11 +116,8 @@ char *curl_escape(const char *string, int inlength)
   return ns;
 }
 
-#define ishex(in) ((in >= 'a' && in <= 'f') || \
-                   (in >= 'A' && in <= 'F') || \
-                   (in >= '0' && in <= '9'))
-
-char *curl_unescape(const char *string, int length)
+char *curl_easy_unescape(CURL *handle, const char *string, int length,
+                         int *olen)
 {
   int alloc = (length?length:(int)strlen(string))+1;
   char *ns = malloc(alloc);
@@ -98,12 +125,16 @@ char *curl_unescape(const char *string, int length)
   int strindex=0;
   long hex;
 
+#ifndef CURL_DOES_CONVERSIONS
+  /* avoid compiler warnings */
+  (void)handle;
+#endif
   if( !ns )
     return NULL;
 
   while(--alloc > 0) {
     in = *string;
-    if(('%' == in) && ishex(string[1]) && ishex(string[2])) {
+    if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
       /* this is two hexadecimal digits following a '%' */
       char hexstr[3];
       char *ptr;
@@ -114,6 +145,17 @@ char *curl_unescape(const char *string, int length)
       hex = strtol(hexstr, &ptr, 16);
 
       in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
+
+#ifdef CURL_DOES_CONVERSIONS
+/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
+      if (!handle ||
+          (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) {
+        /* Curl_convert_from_network calls failf if unsuccessful */
+        free(ns);
+        return NULL;
+      }
+#endif /* CURL_DOES_CONVERSIONS */
+
       string+=2;
       alloc-=2;
     }
@@ -122,6 +164,10 @@ char *curl_unescape(const char *string, int length)
     string++;
   }
   ns[strindex]=0; /* terminate it */
+
+  if(olen)
+    /* store output size */
+    *olen = strindex;
   return ns;
 }
 

+ 6 - 8
Utilities/cmcurl/escape.h

@@ -2,18 +2,18 @@
 #define __ESCAPE_H
 
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -26,7 +26,5 @@
 /* Escape and unescape URL encoding in strings. The functions return a new
  * allocated string or NULL if an error occurred.  */
 
-char *curl_escape(const char *string, int length);
-char *curl_unescape(const char *string, int length);
 
 #endif

+ 70 - 53
Utilities/cmcurl/file.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -30,12 +30,14 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
 
-#include <errno.h>
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef WIN32
 #include <time.h>
 #include <io.h>
 #include <fcntl.h>
@@ -46,7 +48,9 @@
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -66,9 +70,6 @@
 #include <sys/param.h>
 #endif
 
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
@@ -85,7 +86,8 @@
 #include "getinfo.h"
 #include "transfer.h"
 #include "url.h"
-#include "curl_memory.h"
+#include "memory.h"
+#include "parsedate.h" /* for the week day and month names */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -100,10 +102,10 @@
  */
 CURLcode Curl_file_connect(struct connectdata *conn)
 {
-  char *real_path = curl_unescape(conn->path, 0);
+  char *real_path = curl_easy_unescape(conn->data, conn->data->reqdata.path, 0, NULL);
   struct FILEPROTO *file;
   int fd;
-#if defined(WIN32) || defined(__EMX__)
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
   int i;
   char *actual_path;
 #endif
@@ -117,9 +119,13 @@ CURLcode Curl_file_connect(struct connectdata *conn)
     return CURLE_OUT_OF_MEMORY;
   }
 
-  conn->proto.file = file;
+  if (conn->data->reqdata.proto.file) {
+    free(conn->data->reqdata.proto.file);
+  }
+
+  conn->data->reqdata.proto.file = file;
 
-#if defined(WIN32) || defined(__EMX__)
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
   /* 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
@@ -143,7 +149,7 @@ CURLcode Curl_file_connect(struct connectdata *conn)
     actual_path++;
   }
 
-  /* change path separators from '/' to '\\' for Windows and OS/2 */
+  /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
   for (i=0; actual_path[i] != '\0'; ++i)
     if (actual_path[i] == '/')
       actual_path[i] = '\\';
@@ -156,31 +162,31 @@ CURLcode Curl_file_connect(struct connectdata *conn)
 #endif
   file->freepath = real_path; /* free this when done */
 
+  file->fd = fd;
   if(!conn->data->set.upload && (fd == -1)) {
-    failf(conn->data, "Couldn't open file %s", conn->path);
-    Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE);
+    failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path);
+    Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
     return CURLE_FILE_COULDNT_READ_FILE;
   }
-  file->fd = fd;
 
   return CURLE_OK;
 }
 
-#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
-#define lseek(x,y,z) _lseeki64(x, y, z)
-#endif
-
 CURLcode Curl_file_done(struct connectdata *conn,
-                        CURLcode status)
+                        CURLcode status, bool premature)
 {
-  struct FILEPROTO *file = conn->proto.file;
+  struct FILEPROTO *file = conn->data->reqdata.proto.file;
   (void)status; /* not used */
+  (void)premature; /* not used */
   Curl_safefree(file->freepath);
 
+  if(file->fd != -1)
+    close(file->fd);
+
   return CURLE_OK;
 }
 
-#if defined(WIN32) || defined(__EMX__)
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
 #define DIRSEP '\\'
 #else
 #define DIRSEP '/'
@@ -188,7 +194,7 @@ CURLcode Curl_file_done(struct connectdata *conn,
 
 static CURLcode file_upload(struct connectdata *conn)
 {
-  struct FILEPROTO *file = conn->proto.file;
+  struct FILEPROTO *file = conn->data->reqdata.proto.file;
   char *dir = strchr(file->path, DIRSEP);
   FILE *fp;
   CURLcode res=CURLE_OK;
@@ -205,7 +211,7 @@ static CURLcode file_upload(struct connectdata *conn)
    */
   conn->fread = data->set.fread;
   conn->fread_in = data->set.in;
-  conn->upload_fromhere = buf;
+  conn->data->reqdata.upload_fromhere = buf;
 
   if(!dir)
     return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
@@ -227,13 +233,13 @@ static CURLcode file_upload(struct connectdata *conn)
     int readcount;
     res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
     if(res)
-      return res;
-
-    nread = (size_t)readcount;
+      break;
 
-    if (nread <= 0)
+    if (readcount <= 0)  /* fix questionable compare error. curlvms */
       break;
 
+    nread = (size_t)readcount;
+
     /* write the data to the target */
     nwrite = fwrite(buf, 1, nread, fp);
     if(nwrite != nread) {
@@ -266,7 +272,7 @@ static CURLcode file_upload(struct connectdata *conn)
  * opposed to sockets) we instead perform the whole do-operation in this
  * function.
  */
-CURLcode Curl_file(struct connectdata *conn)
+CURLcode Curl_file(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)
@@ -274,7 +280,9 @@ CURLcode Curl_file(struct connectdata *conn)
      (via NFS, Samba, NT sharing) can be accessed through a file:// URL
   */
   CURLcode res = CURLE_OK;
-  struct stat statbuf;
+  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 fstated=FALSE;
   ssize_t nread;
@@ -284,6 +292,8 @@ CURLcode Curl_file(struct connectdata *conn)
   int fd;
   struct timeval now = Curl_tvnow();
 
+  *done = TRUE; /* unconditionally */
+
   Curl_readwrite_init(conn);
   Curl_initinfo(data);
   Curl_pgrsStartNow(data);
@@ -292,7 +302,7 @@ CURLcode Curl_file(struct connectdata *conn)
     return file_upload(conn);
 
   /* get the fd from the connection phase */
-  fd = conn->proto.file->fd;
+  fd = conn->data->reqdata.proto.file->fd;
 
   /* VMS: This only works reliable for STREAMLF files */
   if( -1 != fstat(fd, &statbuf)) {
@@ -308,40 +318,45 @@ CURLcode Curl_file(struct connectdata *conn)
     CURLcode result;
     snprintf(buf, sizeof(data->state.buffer),
              "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
-    result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
     if(result)
       return result;
 
-    result = Curl_client_write(data, CLIENTWRITE_BOTH,
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH,
                                (char *)"Accept-ranges: bytes\r\n", 0);
     if(result)
       return result;
 
-#ifdef HAVE_STRFTIME
     if(fstated) {
       struct tm *tm;
-      time_t cuClock = (time_t)statbuf.st_mtime;
+      time_t clock = (time_t)statbuf.st_mtime;
 #ifdef HAVE_GMTIME_R
       struct tm buffer;
-      tm = (struct tm *)gmtime_r(&cuClock, &buffer);
+      tm = (struct tm *)gmtime_r(&clock, &buffer);
 #else
-      tm = gmtime(&cuClock);
+      tm = gmtime(&clock);
 #endif
       /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
-               tm);
-      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+      snprintf(buf, BUFSIZE-1,
+               "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, buf, 0);
     }
-#endif
     return result;
   }
 
-  /* Added by Dolbneff A.V & Spiridonoff A.V */
-  if (conn->resume_from <= expected_size)
-    expected_size -= conn->resume_from;
-  else
-    /* Is this error code suitable in such situation? */
-    return CURLE_FTP_BAD_DOWNLOAD_RESUME;
+  if (data->reqdata.resume_from <= expected_size)
+    expected_size -= data->reqdata.resume_from;
+  else {
+    failf(data, "failed to resume file:// transfer");
+    return CURLE_BAD_DOWNLOAD_RESUME;
+  }
 
   if (fstated && (expected_size == 0))
     return CURLE_OK;
@@ -353,8 +368,11 @@ CURLcode Curl_file(struct connectdata *conn)
   if(fstated)
     Curl_pgrsSetDownloadSize(data, expected_size);
 
-  if(conn->resume_from)
-    lseek(fd, conn->resume_from, SEEK_SET);
+  if(data->reqdata.resume_from) {
+    if(data->reqdata.resume_from !=
+       lseek(fd, data->reqdata.resume_from, SEEK_SET))
+      return CURLE_BAD_DOWNLOAD_RESUME;
+  }
 
   Curl_pgrsTime(data, TIMER_STARTTRANSFER);
 
@@ -369,7 +387,7 @@ CURLcode Curl_file(struct connectdata *conn)
 
     bytecount += nread;
 
-    res = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
+    res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
     if(res)
       return res;
 
@@ -383,8 +401,7 @@ CURLcode Curl_file(struct connectdata *conn)
   if(Curl_pgrsUpdate(conn))
     res = CURLE_ABORTED_BY_CALLBACK;
 
-  close(fd);
-
   return res;
 }
+
 #endif

+ 8 - 8
Utilities/cmcurl/file.h

@@ -2,18 +2,18 @@
 #define __FILE_H
 
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,8 +24,8 @@
  * $Id$
  ***************************************************************************/
 #ifndef CURL_DISABLE_FILE
-CURLcode Curl_file(struct connectdata *);
-CURLcode Curl_file_done(struct connectdata *, CURLcode);
+CURLcode Curl_file(struct connectdata *, bool *done);
+CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature);
 CURLcode Curl_file_connect(struct connectdata *);
 #endif
 #endif

+ 273 - 63
Utilities/cmcurl/formdata.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,7 +24,7 @@
 /*
   Debug the form generator stand-alone by compiling this source file with:
 
-  gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
+  gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c
 
   run the 'formdata' executable the output should end with:
   All Tests seem to have worked ...
@@ -63,7 +63,7 @@ Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
 Content-Disposition: attachment; filename="inet_ntoa_r.h"
 Content-Type: text/plain
 ...
-Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Disposition: attachment; filename="Makefile.b32"
 Content-Type: text/plain
 ...
 
@@ -73,7 +73,7 @@ Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
 Content-Disposition: attachment; filename="inet_ntoa_r.h"
 Content-Type: text/plain
 ...
-Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Disposition: attachment; filename="Makefile.b32"
 Content-Type: text/plain
 ...
 Content-Disposition: attachment; filename="inet_ntoa_r.h"
@@ -87,7 +87,7 @@ Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
 Content-Disposition: attachment; filename="inet_ntoa_r.h"
 Content-Type: text/plain
 ...
-Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Disposition: attachment; filename="Makefile.b32"
 Content-Type: text/plain
 ...
 Content-Disposition: attachment; filename="inet_ntoa_r.h"
@@ -105,17 +105,24 @@ Content-Disposition: form-data; name="FILECONTENT"
 /* Length of the random boundary string. */
 #define BOUNDARY_LENGTH 40
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <time.h>
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+#include "urldata.h" /* for struct SessionHandle */
+#include "easyif.h" /* for Curl_convert_... prototypes */
 #include "formdata.h"
 #include "strequal.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -123,6 +130,17 @@ Content-Disposition: form-data; name="FILECONTENT"
 /* The last #include file should be: */
 #include "memdebug.h"
 
+#endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
+
+#ifndef CURL_DISABLE_HTTP
+
+#if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO)
+/* This system has a basename() but no prototype for it! */
+char *basename(char *path);
+#endif
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size);
+
 /* What kind of Content-Type to use on un-specified files with unrecognized
    extensions. */
 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
@@ -241,7 +259,7 @@ static FormInfo * AddFormInfo(char *value,
 static const char * ContentTypeForFilename (const char *filename,
                                             const char *prevtype)
 {
-  const char *contenttype;
+  const char *contenttype = NULL;
   unsigned int i;
   /*
    * No type was specified, we scan through a few well-known
@@ -251,7 +269,7 @@ static const char * ContentTypeForFilename (const char *filename,
     const char *extension;
     const char *type;
   };
-  static struct ContentType ctts[]={
+  static const struct ContentType ctts[]={
     {".gif",  "image/gif"},
     {".jpg",  "image/jpeg"},
     {".jpeg", "image/jpeg"},
@@ -374,7 +392,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
   FormInfo *first_form, *current_form, *form = NULL;
   CURLFORMcode return_value = CURL_FORMADD_OK;
   const char *prevtype = NULL;
-  struct curl_httppost *post;
+  struct curl_httppost *post = NULL;
   CURLformoption option;
   struct curl_forms *forms = NULL;
   char *array_value=NULL; /* value read from an array */
@@ -436,7 +454,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
        * Set the Name property.
        */
     case CURLFORM_PTRNAME:
+#ifdef CURL_DOES_CONVERSIONS
+      /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
+         have safe memory for the eventual conversion */
+#else
       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+#endif
     case CURLFORM_COPYNAME:
       if (current_form->name)
         return_value = CURL_FORMADD_OPTION_TWICE;
@@ -454,7 +477,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         return_value = CURL_FORMADD_OPTION_TWICE;
       else
         current_form->namelength =
-          array_state?(long)array_value:va_arg(params, long);
+          array_state?(long)array_value:(long)va_arg(params, long);
       break;
 
       /*
@@ -512,8 +535,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         if (current_form->value) {
           if (current_form->flags & HTTPPOST_FILENAME) {
             if (filename) {
-              if (!(current_form = AddFormInfo(strdup(filename),
-                                               NULL, current_form)))
+              if ((current_form = AddFormInfo(strdup(filename),
+                                              NULL, current_form)) == NULL)
                 return_value = CURL_FORMADD_MEMORY;
             }
             else
@@ -546,8 +569,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         if (current_form->value) {
           if (current_form->flags & HTTPPOST_BUFFER) {
             if (filename) {
-              if (!(current_form = AddFormInfo(strdup(filename),
-                                               NULL, current_form)))
+              if ((current_form = AddFormInfo(strdup(filename),
+                                              NULL, current_form)) == NULL)
                 return_value = CURL_FORMADD_MEMORY;
             }
             else
@@ -598,9 +621,9 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         if (current_form->contenttype) {
           if (current_form->flags & HTTPPOST_FILENAME) {
             if (contenttype) {
-              if (!(current_form = AddFormInfo(NULL,
-                                               strdup(contenttype),
-                                               current_form)))
+              if ((current_form = AddFormInfo(NULL,
+                                              strdup(contenttype),
+                                              current_form)) == NULL)
                 return_value = CURL_FORMADD_MEMORY;
             }
             else
@@ -626,15 +649,9 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
       {
         /* this "cast increases required alignment of target type" but
            we consider it OK anyway */
-        struct curl_slist* list = 0;
-        if ( array_state )
-          {
-          memcpy(&list, &array_value, sizeof(struct curl_slist*));
-          }
-        else
-          {
-          list = va_arg(params, struct curl_slist*);
-          }
+        struct curl_slist* list = array_state?
+          (struct curl_slist*)array_value:
+          va_arg(params, struct curl_slist*);
 
         if( current_form->contentheader )
           return_value = CURL_FORMADD_OPTION_TWICE;
@@ -825,13 +842,13 @@ static CURLcode AddFormData(struct FormData **formp,
     *formp = newform;
 
   if (size) {
-    if(type == FORM_DATA)
+    if((type == FORM_DATA) || (type == FORM_CONTENT))
       *size += length;
     else {
       /* Since this is a file to be uploaded here, add the size of the actual
          file */
       if(!strequal("-", newform->line)) {
-        struct stat file;
+        struct_stat file;
         if(!stat(newform->line, &file)) {
           *size += file.st_size;
         }
@@ -862,10 +879,11 @@ static CURLcode AddFormDataf(struct FormData **formp,
  * Curl_formclean() is used from http.c, this cleans a built FormData linked
  * list
  */
-void Curl_formclean(struct FormData *form)
+void Curl_formclean(struct FormData **form_ptr)
 {
-  struct FormData *next;
+  struct FormData *next, *form;
 
+  form = *form_ptr;
   if(!form)
     return;
 
@@ -874,7 +892,84 @@ void Curl_formclean(struct FormData *form)
     free(form->line); /* free the line */
     free(form);       /* free the struct */
 
-  } while((form=next)); /* continue */
+  } while ((form = next) != NULL); /* continue */
+
+  *form_ptr = NULL;
+}
+
+#ifdef CURL_DOES_CONVERSIONS
+/*
+ * Curl_formcovert() is used from http.c, this converts any
+   form items that need to be sent in the network encoding.
+   Returns CURLE_OK on success.
+ */
+CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
+{
+  struct FormData *next;
+  CURLcode rc;
+
+  if(!form)
+    return CURLE_OK;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  do {
+    next=form->next;  /* the following form line */
+    if (form->type == FORM_DATA) {
+      rc = Curl_convert_to_network(data, form->line, form->length);
+      /* Curl_convert_to_network calls failf if unsuccessful */
+      if (rc != CURLE_OK)
+        return rc;
+    }
+  } while ((form = next) != NULL); /* continue */
+  return CURLE_OK;
+}
+#endif /* CURL_DOES_CONVERSIONS */
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  CURLcode rc;
+  curl_off_t size;
+  struct FormData *data, *ptr;
+
+  rc = Curl_getFormData(&data, form, NULL, &size);
+  if (rc != CURLE_OK)
+    return (int)rc;
+
+  for (ptr = data; ptr; ptr = ptr->next) {
+    if (ptr->type == FORM_FILE) {
+      char buffer[8192];
+      size_t read;
+      struct Form temp;
+
+      Curl_FormInit(&temp, ptr);
+
+      do {
+        read = readfromfile(&temp, buffer, sizeof(buffer));
+        if ((read == (size_t) -1) || (read != append(arg, buffer, read))) {
+          if (temp.fp) {
+            fclose(temp.fp);
+          }
+          Curl_formclean(&data);
+          return -1;
+        }
+      } while (read == sizeof(buffer));
+    } else {
+      if (ptr->length != append(arg, ptr->line, ptr->length)) {
+        Curl_formclean(&data);
+        return -1;
+      }
+    }
+  }
+  Curl_formclean(&data);
+  return 0;
 }
 
 /*
@@ -906,7 +1001,69 @@ void curl_formfree(struct curl_httppost *form)
       free(form->showfilename); /* free the faked file name */
     free(form);       /* free the struct */
 
-  } while((form=next)); /* continue */
+  } while ((form = next) != NULL); /* continue */
+}
+
+#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 *basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementaion 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;
+}
+#endif
+
+static char *strippath(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! */
 }
 
 /*
@@ -914,10 +1071,13 @@ void curl_formfree(struct curl_httppost *form)
  * (possibly huge) multipart formdata. The input list is in 'post', while the
  * output resulting linked lists gets stored in '*finalform'. *sizep will get
  * the total size of the whole POST.
+ * A multipart/form_data content-type is built, unless a custom content-type
+ * is passed in 'custom_content_type'.
  */
 
 CURLcode Curl_getFormData(struct FormData **finalform,
                           struct curl_httppost *post,
+                          const char *custom_content_type,
                           curl_off_t *sizep)
 {
   struct FormData *form = NULL;
@@ -941,9 +1101,11 @@ CURLcode Curl_getFormData(struct FormData **finalform,
 
   /* Make the first line of the output */
   result = AddFormDataf(&form, NULL,
-                        "Content-Type: multipart/form-data;"
-                        " boundary=%s\r\n",
+                        "%s; boundary=%s\r\n",
+                        custom_content_type?custom_content_type:
+                        "Content-Type: multipart/form-data",
                         boundary);
+
   if (result) {
     free(boundary);
     return result;
@@ -966,6 +1128,10 @@ CURLcode Curl_getFormData(struct FormData **finalform,
     if (result)
       break;
 
+    /* Maybe later this should be disabled when a custom_content_type is
+       passed, since Content-Disposition is not meaningful for all multipart
+       types.
+    */
     result = AddFormDataf(&form, &size,
                           "Content-Disposition: form-data; name=\"");
     if (result)
@@ -1004,22 +1170,33 @@ CURLcode Curl_getFormData(struct FormData **finalform,
 
       if(post->more) {
         /* if multiple-file */
+        char *filebasename=
+          (!file->showfilename)?strippath(file->contents):NULL;
+
         result = AddFormDataf(&form, &size,
                               "\r\n--%s\r\nContent-Disposition: "
                               "attachment; filename=\"%s\"",
                               fileboundary,
                               (file->showfilename?file->showfilename:
-                               file->contents));
+                               filebasename));
+        if (filebasename)
+          free(filebasename);
         if (result)
           break;
       }
       else if((post->flags & HTTPPOST_FILENAME) ||
               (post->flags & HTTPPOST_BUFFER)) {
 
+        char *filebasename=
+          (!post->showfilename)?strippath(post->contents):NULL;
+
         result = AddFormDataf(&form, &size,
                               "; filename=\"%s\"",
                               (post->showfilename?post->showfilename:
-                               post->contents));
+                               filebasename));
+        if (filebasename)
+          free(filebasename);
+
         if (result)
           break;
       }
@@ -1042,7 +1219,7 @@ CURLcode Curl_getFormData(struct FormData **finalform,
         curList = curList->next;
       }
       if (result) {
-        Curl_formclean(firstform);
+        Curl_formclean(&firstform);
         free(boundary);
         return result;
       }
@@ -1057,7 +1234,10 @@ CURLcode Curl_getFormData(struct FormData **finalform,
       if(file->contenttype &&
          !checkprefix("text/", file->contenttype)) {
         /* this is not a text content, mention our binary encoding */
-        size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
+        result = AddFormDataf(&form, &size,
+                              "\r\nContent-Transfer-Encoding: binary");
+        if (result)
+          break;
       }
 #endif
 
@@ -1094,22 +1274,27 @@ CURLcode Curl_getFormData(struct FormData **finalform,
              */
             size_t nread;
             char buffer[512];
-            while((nread = fread(buffer, 1, sizeof(buffer), fileread))) {
-              result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
+            while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
+              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
               if (result)
                 break;
             }
           }
 
           if (result) {
-            Curl_formclean(firstform);
+            Curl_formclean(&firstform);
             free(boundary);
             return result;
           }
 
         }
         else {
-          Curl_formclean(firstform);
+#ifdef _FORM_DEBUG
+          fprintf(stderr,
+                  "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
+                  file->contents);
+#endif
+          Curl_formclean(&firstform);
           free(boundary);
           *finalform = NULL;
           return CURLE_READ_ERROR;
@@ -1118,7 +1303,7 @@ CURLcode Curl_getFormData(struct FormData **finalform,
       }
       else if (post->flags & HTTPPOST_BUFFER) {
         /* include contents of buffer */
-        result = AddFormData(&form, FORM_DATA, post->buffer,
+        result = AddFormData(&form, FORM_CONTENT, post->buffer,
                              post->bufferlength, &size);
           if (result)
             break;
@@ -1126,14 +1311,14 @@ CURLcode Curl_getFormData(struct FormData **finalform,
 
       else {
         /* include the contents we got */
-        result = AddFormData(&form, FORM_DATA, post->contents,
+        result = AddFormData(&form, FORM_CONTENT, post->contents,
                              post->contentslength, &size);
         if (result)
           break;
       }
-    } while((file = file->more)); /* for each specified file for this field */
+    } while ((file = file->more) != NULL); /* for each specified file for this field */
     if (result) {
-      Curl_formclean(firstform);
+      Curl_formclean(&firstform);
       free(boundary);
       return result;
     }
@@ -1149,9 +1334,9 @@ CURLcode Curl_getFormData(struct FormData **finalform,
         break;
     }
 
-  } while((post=post->next)); /* for each field */
+  } while ((post = post->next) != NULL); /* for each field */
   if (result) {
-    Curl_formclean(firstform);
+    Curl_formclean(&firstform);
     free(boundary);
     return result;
   }
@@ -1161,7 +1346,7 @@ CURLcode Curl_getFormData(struct FormData **finalform,
                        "\r\n--%s--\r\n",
                        boundary);
   if (result) {
-    Curl_formclean(firstform);
+    Curl_formclean(&firstform);
     free(boundary);
     return result;
   }
@@ -1198,12 +1383,12 @@ static size_t readfromfile(struct Form *form, char *buffer, size_t size)
     /* this file hasn't yet been opened */
     form->fp = fopen(form->data->line, "rb"); /* b is for binary */
     if(!form->fp)
-      return -1; /* failure */
+      return (size_t)-1; /* failure */
   }
   nread = fread(buffer, 1, size, form->fp);
 
   if(nread != size) {
-    /* this is the last chunk form the file, move on */
+    /* this is the last chunk from the file, move on */
     fclose(form->fp);
     form->fp = NULL;
     form->data = form->data->next;
@@ -1232,9 +1417,13 @@ size_t Curl_FormReader(char *buffer,
   if(!form->data)
     return 0; /* nothing, error, empty */
 
-  if(form->data->type == FORM_FILE)
-    return readfromfile(form, buffer, wantedsize);
+  if(form->data->type == FORM_FILE) {
+    gotsize = readfromfile(form, buffer, wantedsize);
 
+    if(gotsize)
+      /* If positive or -1, return. If zero, continue! */
+      return gotsize;
+  }
   do {
 
     if( (form->data->length - form->sent ) > wantedsize - gotsize) {
@@ -1256,7 +1445,7 @@ size_t Curl_FormReader(char *buffer,
 
     form->data = form->data->next; /* advance */
 
-  } while(form->data && (form->data->type == FORM_DATA));
+  } while(form->data && (form->data->type != FORM_FILE));
   /* If we got an empty line and we have more data, we proceed to the next
      line immediately to avoid returning zero before we've reached the end.
      This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
@@ -1323,7 +1512,7 @@ int main()
   char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
   char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
   char value7[] = "inet_ntoa_r.h";
-  char value8[] = "Makefile.b32.resp";
+  char value8[] = "Makefile.b32";
   char type2[] = "image/gif";
   char type6[] = "text/plain";
   char type7[] = "text/html";
@@ -1332,7 +1521,8 @@ int main()
   int value5length = strlen(value4);
   int value6length = strlen(value5);
   int errors = 0;
-  int size;
+  CURLcode rc;
+  size_t size;
   size_t nread;
   char buffer[4096];
   struct curl_httppost *httppost=NULL;
@@ -1408,7 +1598,14 @@ int main()
                   CURLFORM_END))
     ++errors;
 
-  form=Curl_getFormData(httppost, &size);
+  rc = Curl_getFormData(&form, httppost, NULL, &size);
+  if(rc != CURLE_OK) {
+    if(rc != CURLE_READ_ERROR) {
+      const char *errortext = curl_easy_strerror(rc);
+      fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
+    }
+    return 0;
+  }
 
   Curl_FormInit(&formread, form);
 
@@ -1416,7 +1613,7 @@ int main()
     nread = Curl_FormReader(buffer, 1, sizeof(buffer),
                             (FILE *)&formread);
 
-    if(-1 == nread)
+    if(nread < 1)
       break;
     fwrite(buffer, nread, 1, stdout);
   } while(1);
@@ -1430,7 +1627,7 @@ int main()
   return 0;
 }
 
-#endif
+#endif  /* _FORM_DEBUG */
 
 #else  /* CURL_DISABLE_HTTP */
 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
@@ -1442,6 +1639,15 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
   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;
@@ -1450,6 +1656,8 @@ void curl_formfree(struct curl_httppost *form)
 
 #endif  /* CURL_DISABLE_HTTP */
 
+#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
+
 /*
  * Curl_FormBoundary() creates a suitable boundary string and returns an
  * allocated one. This is also used by SSL-code so it must be present even
@@ -1458,18 +1666,18 @@ void curl_formfree(struct curl_httppost *form)
 char *Curl_FormBoundary(void)
 {
   char *retstring;
-  static int randomizer=0; /* this is just so that two boundaries within
+  static int randomizer;   /* this is just so that two boundaries within
                               the same form won't be identical */
   size_t i;
 
-  static char table16[]="abcdef0123456789";
+  static const char table16[]="abcdef0123456789";
 
   retstring = (char *)malloc(BOUNDARY_LENGTH+1);
 
   if(!retstring)
     return NULL; /* failed */
 
-  srand((unsigned int)((time(NULL)+randomizer++))); /* seed */
+  srand((unsigned int)time(NULL)+randomizer++); /* seed */
 
   strcpy(retstring, "----------------------------");
 
@@ -1482,3 +1690,5 @@ char *Curl_FormBoundary(void)
 
   return retstring;
 }
+
+#endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */

+ 9 - 4
Utilities/cmcurl/formdata.h

@@ -8,7 +8,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,8 +25,10 @@
  ***************************************************************************/
 
 enum formtype {
-  FORM_DATA, /* regular data */
-  FORM_FILE  /* 'line' points to a file name we should read from */
+  FORM_DATA,    /* form metadata (convert to network encoding if necessary) */
+  FORM_CONTENT, /* form content  (never convert) */
+  FORM_FILE     /* 'line' points to a file name we should read from 
+                    to create the form data (never convert) */
 };
 
 /* plain and simple linked list with lines to send */
@@ -69,6 +71,7 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata );
 CURLcode
 Curl_getFormData(struct FormData **,
                  struct curl_httppost *post,
+                 const char *custom_contenttype,
                  curl_off_t *size);
 
 /* fread() emulation */
@@ -86,7 +89,9 @@ char *Curl_formpostheader(void *formp, size_t *len);
 
 char *Curl_FormBoundary(void);
 
-void Curl_formclean(struct FormData *);
+void Curl_formclean(struct FormData **);
+
+CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *);
 
 #endif
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 2665 - 1387
Utilities/cmcurl/ftp.c


+ 18 - 12
Utilities/cmcurl/ftp.h

@@ -1,18 +1,18 @@
 #ifndef __FTP_H
 #define __FTP_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,14 +24,20 @@
  ***************************************************************************/
 
 #ifndef CURL_DISABLE_FTP
-CURLcode Curl_ftp(struct connectdata *conn);
-CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode);
-CURLcode Curl_ftp_connect(struct connectdata *conn);
+CURLcode Curl_ftp(struct connectdata *conn, bool *done);
+CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature);
+CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done);
 CURLcode Curl_ftp_disconnect(struct connectdata *conn);
 CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
+CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...);
 CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
                              int *ftpcode);
 CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
-#endif
-
-#endif
+CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done);
+int Curl_ftp_getsock(struct connectdata *conn,
+                     curl_socket_t *socks,
+                     int numsocks);
+CURLcode Curl_ftp_doing(struct connectdata *conn,
+                        bool *dophase_done);
+#endif /* CURL_DISABLE_FTP */
+#endif /* __FTP_H */

+ 0 - 2471
Utilities/cmcurl/getdate.c

@@ -1,2471 +0,0 @@
-/* A Bison parser, made by GNU Bison 1.875a.  */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, when this file is copied by Bison into a
-   Bison output file, you may use that output file without restriction.
-   This special exception was added by the Free Software Foundation
-   in version 1.24 of Bison.  */
-
-/* Written by Richard Stallman by simplifying the original so called
-   ``semantic'' parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 1
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     tAGO = 258,
-     tDAY = 259,
-     tDAY_UNIT = 260,
-     tDAYZONE = 261,
-     tDST = 262,
-     tHOUR_UNIT = 263,
-     tID = 264,
-     tMERIDIAN = 265,
-     tMINUTE_UNIT = 266,
-     tMONTH = 267,
-     tMONTH_UNIT = 268,
-     tSEC_UNIT = 269,
-     tSNUMBER = 270,
-     tUNUMBER = 271,
-     tYEAR_UNIT = 272,
-     tZONE = 273
-   };
-#endif
-#define tAGO 258
-#define tDAY 259
-#define tDAY_UNIT 260
-#define tDAYZONE 261
-#define tDST 262
-#define tHOUR_UNIT 263
-#define tID 264
-#define tMERIDIAN 265
-#define tMINUTE_UNIT 266
-#define tMONTH 267
-#define tMONTH_UNIT 268
-#define tSEC_UNIT 269
-#define tSNUMBER 270
-#define tUNUMBER 271
-#define tYEAR_UNIT 272
-#define tZONE 273
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 1 "getdate.y"
-
-/*
-**  Originally written by Steven M. Bellovin <[email protected]> while
-**  at the University of North Carolina at Chapel Hill.  Later tweaked by
-**  a couple of people on Usenet.  Completely overhauled by Rich $alz
-**  <[email protected]> and Jim Berets <[email protected]> in August, 1990.
-**
-**  This code has been modified since it was included in curl, to make it
-**  thread-safe and to make compilers complain less about it.
-**
-**  This code is in the public domain and has no copyright.
-*/
-
-#include "setup.h"
-
-# ifdef HAVE_ALLOCA_H
-#  include <alloca.h>
-# endif
-
-# ifdef HAVE_TIME_H
-#  include <time.h>
-# endif
-
-#ifndef YYDEBUG
-  /* to satisfy gcc -Wundef, we set this to 0 */
-#define YYDEBUG 0
-#endif
-
-#ifndef YYSTACK_USE_ALLOCA
-  /* to satisfy gcc -Wundef, we set this to 0 */
-#define YYSTACK_USE_ALLOCA 0
-#endif
-
-/* Since the code of getdate.y is not included in the Emacs executable
-   itself, there is no need to #define static in this file.  Even if
-   the code were included in the Emacs executable, it probably
-   wouldn't do any harm to #undef it here; this will only cause
-   problems if we try to write to a static variable, which I don't
-   think this code needs to do.  */
-#ifdef emacs
-# undef static
-#endif
-
-#ifdef __APPLE__
-#include <sys/types.h>
-#include <sys/malloc.h>
-#else
-
-#endif
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#if HAVE_STDLIB_H
-# include <stdlib.h> /* for `free'; used by Bison 1.27 */
-#else
-
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
-#endif
-
-#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
-# define IN_CTYPE_DOMAIN(c) 1
-#else
-# define IN_CTYPE_DOMAIN(c) isascii(c)
-#endif
-
-#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
-#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
-#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
-#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
-
-/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
-   - Its arg may be any int or unsigned int; it need not be an unsigned char.
-   - It's guaranteed to evaluate its argument exactly once.
-   - It's typically faster.
-   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
-   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
-   it's important to use the locale's definition of `digit' even when the
-   host does not conform to Posix.  */
-#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
-
-#if defined (STDC_HEADERS) || defined (USG)
-# include <string.h>
-#endif
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#ifndef YYMAXDEPTH
-#define YYMAXDEPTH 0
-#endif
-
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
-# define __attribute__(x)
-#endif
-
-#ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#endif
-
-/* Some old versions of bison generate parsers that use bcopy.
-   That loses on systems that don't provide the function, so we have
-   to redefine it here.  */
-#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
-# define bcopy(from, to, len) memcpy ((to), (from), (len))
-#endif
-
-/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
-   as well as gratuitiously global symbol names, so we can have multiple
-   yacc generated parsers in the same program.  Note that these are only
-   the variables produced by yacc.  If other parser generators (bison,
-   byacc, etc) produce additional global names that conflict at link time,
-   then those parser generators need to be fixed instead of adding those
-   names to this list. */
-
-#define yymaxdepth Curl_gd_maxdepth
-#define yyparse Curl_gd_parse
-#define yylex   Curl_gd_lex
-#define yyerror Curl_gd_error
-#define yylval  Curl_gd_lval
-#define yychar  Curl_gd_char
-#define yydebug Curl_gd_debug
-#define yypact  Curl_gd_pact
-#define yyr1    Curl_gd_r1
-#define yyr2    Curl_gd_r2
-#define yydef   Curl_gd_def
-#define yychk   Curl_gd_chk
-#define yypgo   Curl_gd_pgo
-#define yyact   Curl_gd_act
-#define yyexca  Curl_gd_exca
-#define yyerrflag Curl_gd_errflag
-#define yynerrs Curl_gd_nerrs
-#define yyps    Curl_gd_ps
-#define yypv    Curl_gd_pv
-#define yys     Curl_gd_s
-#define yy_yys  Curl_gd_yys
-#define yystate Curl_gd_state
-#define yytmp   Curl_gd_tmp
-#define yyv     Curl_gd_v
-#define yy_yyv  Curl_gd_yyv
-#define yyval   Curl_gd_val
-#define yylloc  Curl_gd_lloc
-#define yyreds  Curl_gd_reds          /* With YYDEBUG defined */
-#define yytoks  Curl_gd_toks          /* With YYDEBUG defined */
-#define yylhs   Curl_gd_yylhs
-#define yylen   Curl_gd_yylen
-#define yydefred Curl_gd_yydefred
-#define yydgoto Curl_gd_yydgoto
-#define yysindex Curl_gd_yysindex
-#define yyrindex Curl_gd_yyrindex
-#define yygindex Curl_gd_yygindex
-#define yytable  Curl_gd_yytable
-#define yycheck  Curl_gd_yycheck
-
-#define EPOCH           1970
-#define HOUR(x)         ((x) * 60)
-
-#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
-
-/*
-**  An entry in the lexical lookup table.
-*/
-typedef struct _TABLE {
-    const char  *name;
-    int         type;
-    int         value;
-} TABLE;
-
-
-/*
-**  Meridian:  am, pm, or 24-hour style.
-*/
-typedef enum _MERIDIAN {
-    MERam, MERpm, MER24
-} MERIDIAN;
-
-/* parse results and input string */
-typedef struct _CURL_CONTEXT {
-    const char  *yyInput;
-    int         yyDayOrdinal;
-    int         yyDayNumber;
-    int         yyHaveDate;
-    int         yyHaveDay;
-    int         yyHaveRel;
-    int         yyHaveTime;
-    int         yyHaveZone;
-    int         yyTimezone;
-    int         yyDay;
-    int         yyHour;
-    int         yyMinutes;
-    int         yyMonth;
-    int         yySeconds;
-    int         yyYear;
-    MERIDIAN    yyMeridian;
-    int         yyRelDay;
-    int         yyRelHour;
-    int         yyRelMinutes;
-    int         yyRelMonth;
-    int         yyRelSeconds;
-    int         yyRelYear;
-} CURL_CONTEXT;
-
-/* enable use of extra argument to yyparse and yylex which can be used to pass
-**  in a user defined value (CURL_CONTEXT struct in our case)
-*/
-#define YYPARSE_PARAM cookie
-#define YYLEX_PARAM cookie
-#define context ((CURL_CONTEXT *) cookie)
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-#line 223 "getdate.y"
-typedef union YYSTYPE {
-    int                 Number;
-    enum _MERIDIAN      Meridian;
-} YYSTYPE;
-/* Line 191 of yacc.c.  */
-#line 331 "y.tab.c"
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-#line 228 "getdate.y"
-
-static int yylex (YYSTYPE *yylval, void *cookie);
-static int yyerror (const char *s);
-
-
-/* Line 214 of yacc.c.  */
-#line 347 "y.tab.c"
-
-#if ! defined (yyoverflow) || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# if YYSTACK_USE_ALLOCA
-#  define YYSTACK_ALLOC alloca
-# else
-#  ifndef YYSTACK_USE_ALLOCA
-#   if defined (alloca) || defined (_ALLOCA_H)
-#    define YYSTACK_ALLOC alloca
-#   else
-#    ifdef __GNUC__
-#     define YYSTACK_ALLOC __builtin_alloca
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning. */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-# else
-#  if defined (__STDC__) || defined (__cplusplus)
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   define YYSIZE_T size_t
-#  endif
-#  define YYSTACK_ALLOC malloc
-#  define YYSTACK_FREE free
-# endif
-#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
-
-
-#if (! defined (yyoverflow) \
-     && (! defined (__cplusplus) \
-         || (YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  short yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))                         \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)              \
-      do                                        \
-        {                                       \
-          register YYSIZE_T yyi;                \
-          for (yyi = 0; yyi < (Count); yyi++)   \
-            (To)[yyi] = (From)[yyi];            \
-        }                                       \
-      while (0)
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)                                        \
-    do                                                                  \
-      {                                                                 \
-        YYSIZE_T yynewbytes;                                            \
-        YYCOPY (&yyptr->Stack, Stack, yysize);                          \
-        Stack = &yyptr->Stack;                                          \
-        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / sizeof (*yyptr);                          \
-        (void)yyptr;                                                    \
-      }                                                                 \
-    while (0)
-
-#endif
-
-#if defined (__STDC__) || defined (__cplusplus)
-   typedef signed char yysigned_char;
-#else
-   typedef short yysigned_char;
-#endif
-
-/* YYFINAL -- State number of the termination state. */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   50
-
-/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  22
-/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS  11
-/* YYNRULES -- Number of rules. */
-#define YYNRULES  51
-/* YYNRULES -- Number of states. */
-#define YYNSTATES  61
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   273
-
-#define YYTRANSLATE(YYX)                                                \
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const unsigned char yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    20,     2,     2,    21,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    19,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const unsigned char yyprhs[] =
-{
-       0,     0,     3,     4,     7,     9,    11,    13,    15,    17,
-      19,    22,    27,    32,    39,    46,    48,    50,    53,    55,
-      58,    61,    65,    71,    75,    79,    82,    87,    90,    94,
-      97,    99,   102,   105,   107,   110,   113,   115,   118,   121,
-     123,   126,   129,   131,   134,   137,   139,   142,   145,   147,
-     149,   150
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yysigned_char yyrhs[] =
-{
-      23,     0,    -1,    -1,    23,    24,    -1,    25,    -1,    26,
-      -1,    28,    -1,    27,    -1,    29,    -1,    31,    -1,    16,
-      10,    -1,    16,    19,    16,    32,    -1,    16,    19,    16,
-      15,    -1,    16,    19,    16,    19,    16,    32,    -1,    16,
-      19,    16,    19,    16,    15,    -1,    18,    -1,     6,    -1,
-      18,     7,    -1,     4,    -1,     4,    20,    -1,    16,     4,
-      -1,    16,    21,    16,    -1,    16,    21,    16,    21,    16,
-      -1,    16,    15,    15,    -1,    16,    12,    15,    -1,    12,
-      16,    -1,    12,    16,    20,    16,    -1,    16,    12,    -1,
-      16,    12,    16,    -1,    30,     3,    -1,    30,    -1,    16,
-      17,    -1,    15,    17,    -1,    17,    -1,    16,    13,    -1,
-      15,    13,    -1,    13,    -1,    16,     5,    -1,    15,     5,
-      -1,     5,    -1,    16,     8,    -1,    15,     8,    -1,     8,
-      -1,    16,    11,    -1,    15,    11,    -1,    11,    -1,    16,
-      14,    -1,    15,    14,    -1,    14,    -1,    16,    -1,    -1,
-      10,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const unsigned short yyrline[] =
-{
-       0,   244,   244,   245,   248,   251,   254,   257,   260,   263,
-     266,   272,   278,   287,   293,   305,   308,   312,   317,   321,
-     325,   331,   335,   353,   359,   365,   369,   374,   378,   385,
-     393,   396,   399,   402,   405,   408,   411,   414,   417,   420,
-     423,   426,   429,   432,   435,   438,   441,   444,   447,   452,
-     487,   490
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "tAGO", "tDAY", "tDAY_UNIT", "tDAYZONE", 
-  "tDST", "tHOUR_UNIT", "tID", "tMERIDIAN", "tMINUTE_UNIT", "tMONTH", 
-  "tMONTH_UNIT", "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tYEAR_UNIT", 
-  "tZONE", "':'", "','", "'/'", "$accept", "spec", "item", "time", "zone", 
-  "day", "date", "rel", "relunit", "number", "o_merid", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const unsigned short yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,    58,
-      44,    47
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const unsigned char yyr1[] =
-{
-       0,    22,    23,    23,    24,    24,    24,    24,    24,    24,
-      25,    25,    25,    25,    25,    26,    26,    26,    27,    27,
-      27,    28,    28,    28,    28,    28,    28,    28,    28,    29,
-      29,    30,    30,    30,    30,    30,    30,    30,    30,    30,
-      30,    30,    30,    30,    30,    30,    30,    30,    30,    31,
-      32,    32
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const unsigned char yyr2[] =
-{
-       0,     2,     0,     2,     1,     1,     1,     1,     1,     1,
-       2,     4,     4,     6,     6,     1,     1,     2,     1,     2,
-       2,     3,     5,     3,     3,     2,     4,     2,     3,     2,
-       1,     2,     2,     1,     2,     2,     1,     2,     2,     1,
-       2,     2,     1,     2,     2,     1,     2,     2,     1,     1,
-       0,     1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const unsigned char yydefact[] =
-{
-       2,     0,     1,    18,    39,    16,    42,    45,     0,    36,
-      48,     0,    49,    33,    15,     3,     4,     5,     7,     6,
-       8,    30,     9,    19,    25,    38,    41,    44,    35,    47,
-      32,    20,    37,    40,    10,    43,    27,    34,    46,     0,
-      31,     0,     0,    17,    29,     0,    24,    28,    23,    50,
-      21,    26,    51,    12,     0,    11,     0,    50,    22,    14,
-      13
-};
-
-/* YYDEFGOTO[NTERM-NUM]. */
-static const yysigned_char yydefgoto[] =
-{
-      -1,     1,    15,    16,    17,    18,    19,    20,    21,    22,
-      55
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -20
-static const yysigned_char yypact[] =
-{
-     -20,     0,   -20,   -19,   -20,   -20,   -20,   -20,   -13,   -20,
-     -20,    30,    15,   -20,    14,   -20,   -20,   -20,   -20,   -20,
-     -20,    19,   -20,   -20,     4,   -20,   -20,   -20,   -20,   -20,
-     -20,   -20,   -20,   -20,   -20,   -20,    -6,   -20,   -20,    16,
-     -20,    17,    23,   -20,   -20,    24,   -20,   -20,   -20,    27,
-      28,   -20,   -20,   -20,    29,   -20,    32,    -8,   -20,   -20,
-     -20
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yysigned_char yypgoto[] =
-{
-     -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,
-      -7
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -1
-static const unsigned char yytable[] =
-{
-       2,    23,    52,    24,     3,     4,     5,    59,     6,    46,
-      47,     7,     8,     9,    10,    11,    12,    13,    14,    31,
-      32,    43,    44,    33,    45,    34,    35,    36,    37,    38,
-      39,    48,    40,    49,    41,    25,    42,    52,    26,    50,
-      51,    27,    53,    28,    29,    57,    54,    30,    58,    56,
-      60
-};
-
-static const unsigned char yycheck[] =
-{
-       0,    20,    10,    16,     4,     5,     6,    15,     8,    15,
-      16,    11,    12,    13,    14,    15,    16,    17,    18,     4,
-       5,     7,     3,     8,    20,    10,    11,    12,    13,    14,
-      15,    15,    17,    16,    19,     5,    21,    10,     8,    16,
-      16,    11,    15,    13,    14,    16,    19,    17,    16,    21,
-      57
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const unsigned char yystos[] =
-{
-       0,    23,     0,     4,     5,     6,     8,    11,    12,    13,
-      14,    15,    16,    17,    18,    24,    25,    26,    27,    28,
-      29,    30,    31,    20,    16,     5,     8,    11,    13,    14,
-      17,     4,     5,     8,    10,    11,    12,    13,    14,    15,
-      17,    19,    21,     7,     3,    20,    15,    16,    15,    16,
-      16,    16,    10,    15,    19,    32,    21,    16,    16,    15,
-      32
-};
-
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
-#define yyerrok         (yyerrstatus = 0)
-#define yyclearin       (yychar = YYEMPTY)
-#define YYEMPTY         (-2)
-#define YYEOF           0
-
-#define YYACCEPT        goto yyacceptlab
-#define YYABORT         goto yyabortlab
-#define YYERROR         goto yyerrlab1
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL          goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                  \
-do                                                              \
-  if (yychar == YYEMPTY && yylen == 1)                          \
-    {                                                           \
-      yychar = (Token);                                         \
-      yylval = (Value);                                         \
-      yytoken = YYTRANSLATE (yychar);                           \
-      YYPOPSTACK;                                               \
-      goto yybackup;                                            \
-    }                                                           \
-  else                                                          \
-    {                                                           \
-      yyerror ("syntax error: cannot back up");\
-      YYERROR;                                                  \
-    }                                                           \
-while (0)
-
-#define YYTERROR        1
-#define YYERRCODE       256
-
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
-   are run).  */
-
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)         \
-  Current.first_line   = Rhs[1].first_line;      \
-  Current.first_column = Rhs[1].first_column;    \
-  Current.last_line    = Rhs[N].last_line;       \
-  Current.last_column  = Rhs[N].last_column;
-#endif
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval)
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                        \
-do {                                            \
-  if (yydebug)                                  \
-    YYFPRINTF Args;                             \
-} while (0)
-
-# define YYDSYMPRINT(Args)                      \
-do {                                            \
-  if (yydebug)                                  \
-    yysymprint Args;                            \
-} while (0)
-
-# define YYDSYMPRINTF(Title, Token, Value, Location)            \
-do {                                                            \
-  if (yydebug)                                                  \
-    {                                                           \
-      YYFPRINTF (stderr, "%s ", Title);                         \
-      yysymprint (stderr,                                       \
-                  Token, Value);        \
-      YYFPRINTF (stderr, "\n");                                 \
-    }                                                           \
-} while (0)
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded).                                                   |
-`------------------------------------------------------------------*/
-
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yy_stack_print (short *bottom, short *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    short *bottom;
-    short *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (/* Nothing. */; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)                            \
-do {                                                            \
-  if (yydebug)                                                  \
-    yy_stack_print ((Bottom), (Top));                           \
-} while (0)
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yy_reduce_print (int yyrule)
-#else
-static void
-yy_reduce_print (yyrule)
-    int yyrule;
-#endif
-{
-  int yyi;
-  unsigned int yylineno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
-             yyrule - 1, yylineno);
-  /* Print the symbols being reduced, and their result.  */
-  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
-    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
-  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
-}
-
-# define YY_REDUCE_PRINT(Rule)          \
-do {                                    \
-  if (yydebug)                          \
-    yy_reduce_print (Rule);             \
-} while (0)
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined (__GLIBC__) && defined (_STRING_H)
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-static YYSIZE_T
-#   if defined (__STDC__) || defined (__cplusplus)
-yystrlen (const char *yystr)
-#   else
-yystrlen (yystr)
-     const char *yystr;
-#   endif
-{
-  register const char *yys = yystr;
-
-  while (*yys++ != '\0')
-    continue;
-
-  return yys - yystr - 1;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-static char *
-#   if defined (__STDC__) || defined (__cplusplus)
-yystpcpy (char *yydest, const char *yysrc)
-#   else
-yystpcpy (yydest, yysrc)
-     char *yydest;
-     const char *yysrc;
-#   endif
-{
-  register char *yyd = yydest;
-  register const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-#endif /* !YYERROR_VERBOSE */
-
-
-
-#if YYDEBUG
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yysymprint (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  /* Pacify ``unused variable'' warnings.  */
-  (void) yyvaluep;
-
-  if (yytype < YYNTOKENS)
-    {
-      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
-      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
-    }
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  switch (yytype)
-    {
-      default:
-        break;
-    }
-  YYFPRINTF (yyoutput, ")");
-}
-
-#endif /* ! YYDEBUG */
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yytype, yyvaluep)
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  /* Pacify ``unused variable'' warnings.  */
-  (void) yyvaluep;
-
-  switch (yytype)
-    {
-
-      default:
-        break;
-    }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void *YYPARSE_PARAM);
-# else
-int yyparse ();
-# endif
-#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void *YYPARSE_PARAM)
-# else
-int yyparse (YYPARSE_PARAM)
-  void *YYPARSE_PARAM;
-# endif
-#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  /* The lookahead symbol.  */
-int yychar;
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-  register int yystate;
-  register int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  short yyssa[YYINITDEPTH];
-  short *yyss = yyssa;
-  register short *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  register YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK   (yyvsp--, yyssp--)
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* When reducing, the number of symbols on the RHS of the reduced
-     rule.  */
-  int yylen;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;             /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed. so pushing a state here evens the stacks.
-     */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = (YYSIZE_T)(yyssp - yyss + 1);
-
-#ifdef yyoverflow
-      {
-        /* Give user a chance to reallocate the stack. Use copies of
-           these so that the &'s don't force the real ones into
-           memory.  */
-        YYSTYPE *yyvs1 = yyvs;
-        short *yyss1 = yyss;
-
-
-        /* Each stack pointer address is followed by the size of the
-           data in use in that stack, in bytes.  This used to be a
-           conditional around just the two extra args, but that might
-           be undefined if yyoverflow is a macro.  */
-        yyoverflow ("parser stack overflow",
-                    &yyss1, yysize * sizeof (*yyssp),
-                    &yyvs1, yysize * sizeof (*yyvsp),
-
-                    &yystacksize);
-
-        yyss = yyss1;
-        yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyoverflowlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-        goto yyoverflowlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-        yystacksize = YYMAXDEPTH;
-
-      {
-        short *yyss1 = yyss;
-        union yyalloc *yyptr =
-          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-        if (! yyptr)
-          goto yyoverflowlab;
-        YYSTACK_RELOCATE (yyss);
-        YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-        if (yyss1 != yyssa)
-          YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-        YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-/* Do appropriate processing given the current state.  */
-/* Read a lookahead token if we need one and don't already have one.  */
-/* yyresume: */
-
-  /* First try to decide what to do without reference to lookahead token.  */
-
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-        goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Shift the lookahead token.  */
-  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
-
-  /* Discard the token being shifted unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  *++yyvsp = yylval;
-
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 4:
-#line 248 "getdate.y"
-    {
-            context->yyHaveTime++;
-        }
-    break;
-
-  case 5:
-#line 251 "getdate.y"
-    {
-            context->yyHaveZone++;
-        }
-    break;
-
-  case 6:
-#line 254 "getdate.y"
-    {
-            context->yyHaveDate++;
-        }
-    break;
-
-  case 7:
-#line 257 "getdate.y"
-    {
-            context->yyHaveDay++;
-        }
-    break;
-
-  case 8:
-#line 260 "getdate.y"
-    {
-            context->yyHaveRel++;
-        }
-    break;
-
-  case 10:
-#line 266 "getdate.y"
-    {
-            context->yyHour = yyvsp[-1].Number;
-            context->yyMinutes = 0;
-            context->yySeconds = 0;
-            context->yyMeridian = yyvsp[0].Meridian;
-        }
-    break;
-
-  case 11:
-#line 272 "getdate.y"
-    {
-            context->yyHour = yyvsp[-3].Number;
-            context->yyMinutes = yyvsp[-1].Number;
-            context->yySeconds = 0;
-            context->yyMeridian = yyvsp[0].Meridian;
-        }
-    break;
-
-  case 12:
-#line 278 "getdate.y"
-    {
-            context->yyHour = yyvsp[-3].Number;
-            context->yyMinutes = yyvsp[-1].Number;
-            context->yyMeridian = MER24;
-            context->yyHaveZone++;
-            context->yyTimezone = (yyvsp[0].Number < 0
-                                   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
-                                   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
-        }
-    break;
-
-  case 13:
-#line 287 "getdate.y"
-    {
-            context->yyHour = yyvsp[-5].Number;
-            context->yyMinutes = yyvsp[-3].Number;
-            context->yySeconds = yyvsp[-1].Number;
-            context->yyMeridian = yyvsp[0].Meridian;
-        }
-    break;
-
-  case 14:
-#line 293 "getdate.y"
-    {
-            context->yyHour = yyvsp[-5].Number;
-            context->yyMinutes = yyvsp[-3].Number;
-            context->yySeconds = yyvsp[-1].Number;
-            context->yyMeridian = MER24;
-            context->yyHaveZone++;
-            context->yyTimezone = (yyvsp[0].Number < 0
-                                   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
-                                   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
-        }
-    break;
-
-  case 15:
-#line 305 "getdate.y"
-    {
-            context->yyTimezone = yyvsp[0].Number;
-        }
-    break;
-
-  case 16:
-#line 308 "getdate.y"
-    {
-            context->yyTimezone = yyvsp[0].Number - 60;
-        }
-    break;
-
-  case 17:
-#line 312 "getdate.y"
-    {
-            context->yyTimezone = yyvsp[-1].Number - 60;
-        }
-    break;
-
-  case 18:
-#line 317 "getdate.y"
-    {
-            context->yyDayOrdinal = 1;
-            context->yyDayNumber = yyvsp[0].Number;
-        }
-    break;
-
-  case 19:
-#line 321 "getdate.y"
-    {
-            context->yyDayOrdinal = 1;
-            context->yyDayNumber = yyvsp[-1].Number;
-        }
-    break;
-
-  case 20:
-#line 325 "getdate.y"
-    {
-            context->yyDayOrdinal = yyvsp[-1].Number;
-            context->yyDayNumber = yyvsp[0].Number;
-        }
-    break;
-
-  case 21:
-#line 331 "getdate.y"
-    {
-            context->yyMonth = yyvsp[-2].Number;
-            context->yyDay = yyvsp[0].Number;
-        }
-    break;
-
-  case 22:
-#line 335 "getdate.y"
-    {
-          /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
-             The goal in recognizing YYYY/MM/DD is solely to support legacy
-             machine-generated dates like those in an RCS log listing.  If
-             you want portability, use the ISO 8601 format.  */
-          if (yyvsp[-4].Number >= 1000)
-            {
-              context->yyYear = yyvsp[-4].Number;
-              context->yyMonth = yyvsp[-2].Number;
-              context->yyDay = yyvsp[0].Number;
-            }
-          else
-            {
-              context->yyMonth = yyvsp[-4].Number;
-              context->yyDay = yyvsp[-2].Number;
-              context->yyYear = yyvsp[0].Number;
-            }
-        }
-    break;
-
-  case 23:
-#line 353 "getdate.y"
-    {
-            /* ISO 8601 format.  yyyy-mm-dd.  */
-            context->yyYear = yyvsp[-2].Number;
-            context->yyMonth = -yyvsp[-1].Number;
-            context->yyDay = -yyvsp[0].Number;
-        }
-    break;
-
-  case 24:
-#line 359 "getdate.y"
-    {
-            /* e.g. 17-JUN-1992.  */
-            context->yyDay = yyvsp[-2].Number;
-            context->yyMonth = yyvsp[-1].Number;
-            context->yyYear = -yyvsp[0].Number;
-        }
-    break;
-
-  case 25:
-#line 365 "getdate.y"
-    {
-            context->yyMonth = yyvsp[-1].Number;
-            context->yyDay = yyvsp[0].Number;
-        }
-    break;
-
-  case 26:
-#line 369 "getdate.y"
-    {
-            context->yyMonth = yyvsp[-3].Number;
-            context->yyDay = yyvsp[-2].Number;
-            context->yyYear = yyvsp[0].Number;
-        }
-    break;
-
-  case 27:
-#line 374 "getdate.y"
-    {
-            context->yyMonth = yyvsp[0].Number;
-            context->yyDay = yyvsp[-1].Number;
-        }
-    break;
-
-  case 28:
-#line 378 "getdate.y"
-    {
-            context->yyMonth = yyvsp[-1].Number;
-            context->yyDay = yyvsp[-2].Number;
-            context->yyYear = yyvsp[0].Number;
-        }
-    break;
-
-  case 29:
-#line 385 "getdate.y"
-    {
-            context->yyRelSeconds = -context->yyRelSeconds;
-            context->yyRelMinutes = -context->yyRelMinutes;
-            context->yyRelHour = -context->yyRelHour;
-            context->yyRelDay = -context->yyRelDay;
-            context->yyRelMonth = -context->yyRelMonth;
-            context->yyRelYear = -context->yyRelYear;
-        }
-    break;
-
-  case 31:
-#line 396 "getdate.y"
-    {
-            context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 32:
-#line 399 "getdate.y"
-    {
-            context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 33:
-#line 402 "getdate.y"
-    {
-            context->yyRelYear += yyvsp[0].Number;
-        }
-    break;
-
-  case 34:
-#line 405 "getdate.y"
-    {
-            context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 35:
-#line 408 "getdate.y"
-    {
-            context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 36:
-#line 411 "getdate.y"
-    {
-            context->yyRelMonth += yyvsp[0].Number;
-        }
-    break;
-
-  case 37:
-#line 414 "getdate.y"
-    {
-            context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 38:
-#line 417 "getdate.y"
-    {
-            context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 39:
-#line 420 "getdate.y"
-    {
-            context->yyRelDay += yyvsp[0].Number;
-        }
-    break;
-
-  case 40:
-#line 423 "getdate.y"
-    {
-            context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 41:
-#line 426 "getdate.y"
-    {
-            context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 42:
-#line 429 "getdate.y"
-    {
-            context->yyRelHour += yyvsp[0].Number;
-        }
-    break;
-
-  case 43:
-#line 432 "getdate.y"
-    {
-            context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 44:
-#line 435 "getdate.y"
-    {
-            context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 45:
-#line 438 "getdate.y"
-    {
-            context->yyRelMinutes += yyvsp[0].Number;
-        }
-    break;
-
-  case 46:
-#line 441 "getdate.y"
-    {
-            context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 47:
-#line 444 "getdate.y"
-    {
-            context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
-        }
-    break;
-
-  case 48:
-#line 447 "getdate.y"
-    {
-            context->yyRelSeconds += yyvsp[0].Number;
-        }
-    break;
-
-  case 49:
-#line 453 "getdate.y"
-    {
-            if (context->yyHaveTime && context->yyHaveDate &&
-                !context->yyHaveRel)
-              context->yyYear = yyvsp[0].Number;
-            else
-              {
-                if (yyvsp[0].Number>10000)
-                  {
-                    context->yyHaveDate++;
-                    context->yyDay= (yyvsp[0].Number)%100;
-                    context->yyMonth= (yyvsp[0].Number/100)%100;
-                    context->yyYear = yyvsp[0].Number/10000;
-                  }
-                else
-                  {
-                    context->yyHaveTime++;
-                    if (yyvsp[0].Number < 100)
-                      {
-                        context->yyHour = yyvsp[0].Number;
-                        context->yyMinutes = 0;
-                      }
-                    else
-                      {
-                        context->yyHour = yyvsp[0].Number / 100;
-                        context->yyMinutes = yyvsp[0].Number % 100;
-                      }
-                    context->yySeconds = 0;
-                    context->yyMeridian = MER24;
-                  }
-              }
-          }
-    break;
-
-  case 50:
-#line 487 "getdate.y"
-    {
-            yyval.Meridian = MER24;
-          }
-    break;
-
-  case 51:
-#line 491 "getdate.y"
-    {
-            yyval.Meridian = yyvsp[0].Meridian;
-          }
-    break;
-
-
-    }
-
-/* Line 999 of yacc.c.  */
-#line 1688 "y.tab.c"
-
-  yyvsp -= yylen;
-  yyssp -= yylen;
-
-
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if YYERROR_VERBOSE
-      yyn = yypact[yystate];
-
-      if (YYPACT_NINF < yyn && yyn < YYLAST)
-        {
-          YYSIZE_T yysize = 0;
-          int yytype = YYTRANSLATE (yychar);
-          char *yymsg;
-          int yyx, yycount;
-
-          yycount = 0;
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  */
-          for (yyx = yyn < 0 ? -yyn : 0;
-               yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-              yysize += yystrlen (yytname[yyx]) + 15, yycount++;
-          yysize += yystrlen ("syntax error, unexpected ") + 1;
-          yysize += yystrlen (yytname[yytype]);
-          yymsg = (char *) YYSTACK_ALLOC (yysize);
-          if (yymsg != 0)
-            {
-              char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
-              yyp = yystpcpy (yyp, yytname[yytype]);
-
-              if (yycount < 5)
-                {
-                  yycount = 0;
-                  for (yyx = yyn < 0 ? -yyn : 0;
-                       yyx < (int) (sizeof (yytname) / sizeof (char *));
-                       yyx++)
-                    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-                      {
-                        const char *yyq = ! yycount ? ", expecting " : " or ";
-                        yyp = yystpcpy (yyp, yyq);
-                        yyp = yystpcpy (yyp, yytname[yyx]);
-                        yycount++;
-                      }
-                }
-              yyerror (yymsg);
-              YYSTACK_FREE (yymsg);
-            }
-          else
-            yyerror ("syntax error; also virtual memory exhausted");
-        }
-      else
-#endif /* YYERROR_VERBOSE */
-        yyerror ("syntax error");
-    }
-  (void)yynerrs;
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse lookahead token after an
-         error, discard it.  */
-
-      /* Return failure if at end of input.  */
-      if (yychar == YYEOF)
-        {
-          /* Pop the error token.  */
-          YYPOPSTACK;
-          /* Pop the rest of the stack.  */
-          while (yyss < yyssp)
-            {
-              YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-              yydestruct (yystos[*yyssp], yyvsp);
-              YYPOPSTACK;
-            }
-          YYABORT;
-        }
-
-      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
-      yydestruct (yytoken, &yylval);
-      yychar = YYEMPTY;
-
-    }
-
-  /* Else will try to reuse lookahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action.  |
-`----------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-        {
-          yyn += YYTERROR;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-            {
-              yyn = yytable[yyn];
-              if (0 < yyn)
-                break;
-            }
-        }
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-        YYABORT;
-
-      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-      yydestruct (yystos[yystate], yyvsp);
-      yyvsp--;
-      yystate = *--yyssp;
-
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  YYDPRINTF ((stderr, "Shifting error token, "));
-
-  *++yyvsp = yylval;
-
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here.  |
-`----------------------------------------------*/
-yyoverflowlab:
-  yyerror ("parser stack overflow");
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-  return yyresult;
-}
-
-
-#line 496 "getdate.y"
-
-
-/* Include this file down here because bison inserts code above which
-   may define-away `const'.  We want the prototype for get_date to have
-   the same signature as the function definition does. */
-#include "getdate.h"
-
-#ifndef WIN32 /* the windows dudes don't need these, does anyone really? */
-extern struct tm        *gmtime (const time_t *);
-extern struct tm        *localtime (const time_t *);
-extern time_t           mktime (struct tm *);
-#endif
-
-/* Month and day table. */
-static TABLE const MonthDayTable[] = {
-    { "january",        tMONTH,  1 },
-    { "february",       tMONTH,  2 },
-    { "march",          tMONTH,  3 },
-    { "april",          tMONTH,  4 },
-    { "may",            tMONTH,  5 },
-    { "june",           tMONTH,  6 },
-    { "july",           tMONTH,  7 },
-    { "august",         tMONTH,  8 },
-    { "september",      tMONTH,  9 },
-    { "sept",           tMONTH,  9 },
-    { "october",        tMONTH, 10 },
-    { "november",       tMONTH, 11 },
-    { "december",       tMONTH, 12 },
-    { "sunday",         tDAY, 0 },
-    { "monday",         tDAY, 1 },
-    { "tuesday",        tDAY, 2 },
-    { "tues",           tDAY, 2 },
-    { "wednesday",      tDAY, 3 },
-    { "wednes",         tDAY, 3 },
-    { "thursday",       tDAY, 4 },
-    { "thur",           tDAY, 4 },
-    { "thurs",          tDAY, 4 },
-    { "friday",         tDAY, 5 },
-    { "saturday",       tDAY, 6 },
-    { NULL, 0, 0 }
-};
-
-/* Time units table. */
-static TABLE const UnitsTable[] = {
-    { "year",           tYEAR_UNIT,     1 },
-    { "month",          tMONTH_UNIT,    1 },
-    { "fortnight",      tDAY_UNIT,      14 },
-    { "week",           tDAY_UNIT,      7 },
-    { "day",            tDAY_UNIT,      1 },
-    { "hour",           tHOUR_UNIT,     1 },
-    { "minute",         tMINUTE_UNIT,   1 },
-    { "min",            tMINUTE_UNIT,   1 },
-    { "second",         tSEC_UNIT,      1 },
-    { "sec",            tSEC_UNIT,      1 },
-    { NULL, 0, 0 }
-};
-
-/* Assorted relative-time words. */
-static TABLE const OtherTable[] = {
-    { "tomorrow",       tMINUTE_UNIT,   1 * 24 * 60 },
-    { "yesterday",      tMINUTE_UNIT,   -1 * 24 * 60 },
-    { "today",          tMINUTE_UNIT,   0 },
-    { "now",            tMINUTE_UNIT,   0 },
-    { "last",           tUNUMBER,       -1 },
-    { "this",           tMINUTE_UNIT,   0 },
-    { "next",           tUNUMBER,       1 },
-    { "first",          tUNUMBER,       1 },
-/*  { "second",         tUNUMBER,       2 }, */
-    { "third",          tUNUMBER,       3 },
-    { "fourth",         tUNUMBER,       4 },
-    { "fifth",          tUNUMBER,       5 },
-    { "sixth",          tUNUMBER,       6 },
-    { "seventh",        tUNUMBER,       7 },
-    { "eighth",         tUNUMBER,       8 },
-    { "ninth",          tUNUMBER,       9 },
-    { "tenth",          tUNUMBER,       10 },
-    { "eleventh",       tUNUMBER,       11 },
-    { "twelfth",        tUNUMBER,       12 },
-    { "ago",            tAGO,   1 },
-    { NULL, 0, 0 }
-};
-
-/* The timezone table. */
-static TABLE const TimezoneTable[] = {
-    { "gmt",    tZONE,     HOUR ( 0) }, /* Greenwich Mean */
-    { "ut",     tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
-    { "utc",    tZONE,     HOUR ( 0) },
-    { "wet",    tZONE,     HOUR ( 0) }, /* Western European */
-    { "bst",    tDAYZONE,  HOUR ( 0) }, /* British Summer */
-    { "wat",    tZONE,     HOUR ( 1) }, /* West Africa */
-    { "at",     tZONE,     HOUR ( 2) }, /* Azores */
-#if     0
-    /* For completeness.  BST is also British Summer, and GST is
-     * also Guam Standard. */
-    { "bst",    tZONE,     HOUR ( 3) }, /* Brazil Standard */
-    { "gst",    tZONE,     HOUR ( 3) }, /* Greenland Standard */
-#endif
-#if 0
-    { "nft",    tZONE,     HOUR (3.5) },        /* Newfoundland */
-    { "nst",    tZONE,     HOUR (3.5) },        /* Newfoundland Standard */
-    { "ndt",    tDAYZONE,  HOUR (3.5) },        /* Newfoundland Daylight */
-#endif
-    { "ast",    tZONE,     HOUR ( 4) }, /* Atlantic Standard */
-    { "adt",    tDAYZONE,  HOUR ( 4) }, /* Atlantic Daylight */
-    { "est",    tZONE,     HOUR ( 5) }, /* Eastern Standard */
-    { "edt",    tDAYZONE,  HOUR ( 5) }, /* Eastern Daylight */
-    { "cst",    tZONE,     HOUR ( 6) }, /* Central Standard */
-    { "cdt",    tDAYZONE,  HOUR ( 6) }, /* Central Daylight */
-    { "mst",    tZONE,     HOUR ( 7) }, /* Mountain Standard */
-    { "mdt",    tDAYZONE,  HOUR ( 7) }, /* Mountain Daylight */
-    { "pst",    tZONE,     HOUR ( 8) }, /* Pacific Standard */
-    { "pdt",    tDAYZONE,  HOUR ( 8) }, /* Pacific Daylight */
-    { "yst",    tZONE,     HOUR ( 9) }, /* Yukon Standard */
-    { "ydt",    tDAYZONE,  HOUR ( 9) }, /* Yukon Daylight */
-    { "hst",    tZONE,     HOUR (10) }, /* Hawaii Standard */
-    { "hdt",    tDAYZONE,  HOUR (10) }, /* Hawaii Daylight */
-    { "cat",    tZONE,     HOUR (10) }, /* Central Alaska */
-    { "ahst",   tZONE,     HOUR (10) }, /* Alaska-Hawaii Standard */
-    { "nt",     tZONE,     HOUR (11) }, /* Nome */
-    { "idlw",   tZONE,     HOUR (12) }, /* International Date Line West */
-    { "cet",    tZONE,     -HOUR (1) }, /* Central European */
-    { "met",    tZONE,     -HOUR (1) }, /* Middle European */
-    { "mewt",   tZONE,     -HOUR (1) }, /* Middle European Winter */
-    { "mest",   tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
-    { "mesz",   tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
-    { "swt",    tZONE,     -HOUR (1) }, /* Swedish Winter */
-    { "sst",    tDAYZONE,  -HOUR (1) }, /* Swedish Summer */
-    { "fwt",    tZONE,     -HOUR (1) }, /* French Winter */
-    { "fst",    tDAYZONE,  -HOUR (1) }, /* French Summer */
-    { "eet",    tZONE,     -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
-    { "bt",     tZONE,     -HOUR (3) }, /* Baghdad, USSR Zone 2 */
-#if 0
-    { "it",     tZONE,     -HOUR (3.5) },/* Iran */
-#endif
-    { "zp4",    tZONE,     -HOUR (4) }, /* USSR Zone 3 */
-    { "zp5",    tZONE,     -HOUR (5) }, /* USSR Zone 4 */
-#if 0
-    { "ist",    tZONE,     -HOUR (5.5) },/* Indian Standard */
-#endif
-    { "zp6",    tZONE,     -HOUR (6) }, /* USSR Zone 5 */
-#if     0
-    /* For completeness.  NST is also Newfoundland Standard, and SST is
-     * also Swedish Summer. */
-    { "nst",    tZONE,     -HOUR (6.5) },/* North Sumatra */
-    { "sst",    tZONE,     -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
-#endif  /* 0 */
-    { "wast",   tZONE,     -HOUR (7) }, /* West Australian Standard */
-    { "wadt",   tDAYZONE,  -HOUR (7) }, /* West Australian Daylight */
-#if 0
-    { "jt",     tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
-#endif
-    { "cct",    tZONE,     -HOUR (8) }, /* China Coast, USSR Zone 7 */
-    { "jst",    tZONE,     -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
-#if 0
-    { "cast",   tZONE,     -HOUR (9.5) },/* Central Australian Standard */
-    { "cadt",   tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
-#endif
-    { "east",   tZONE,     -HOUR (10) },        /* Eastern Australian Standard */
-    { "eadt",   tDAYZONE,  -HOUR (10) },        /* Eastern Australian Daylight */
-    { "gst",    tZONE,     -HOUR (10) },        /* Guam Standard, USSR Zone 9 */
-    { "nzt",    tZONE,     -HOUR (12) },        /* New Zealand */
-    { "nzst",   tZONE,     -HOUR (12) },        /* New Zealand Standard */
-    { "nzdt",   tDAYZONE,  -HOUR (12) },        /* New Zealand Daylight */
-    { "idle",   tZONE,     -HOUR (12) },        /* International Date Line East */
-    {  NULL, 0, 0  }
-};
-
-/* Military timezone table. */
-static TABLE const MilitaryTable[] = {
-    { "a",      tZONE,  HOUR (  1) },
-    { "b",      tZONE,  HOUR (  2) },
-    { "c",      tZONE,  HOUR (  3) },
-    { "d",      tZONE,  HOUR (  4) },
-    { "e",      tZONE,  HOUR (  5) },
-    { "f",      tZONE,  HOUR (  6) },
-    { "g",      tZONE,  HOUR (  7) },
-    { "h",      tZONE,  HOUR (  8) },
-    { "i",      tZONE,  HOUR (  9) },
-    { "k",      tZONE,  HOUR ( 10) },
-    { "l",      tZONE,  HOUR ( 11) },
-    { "m",      tZONE,  HOUR ( 12) },
-    { "n",      tZONE,  HOUR (- 1) },
-    { "o",      tZONE,  HOUR (- 2) },
-    { "p",      tZONE,  HOUR (- 3) },
-    { "q",      tZONE,  HOUR (- 4) },
-    { "r",      tZONE,  HOUR (- 5) },
-    { "s",      tZONE,  HOUR (- 6) },
-    { "t",      tZONE,  HOUR (- 7) },
-    { "u",      tZONE,  HOUR (- 8) },
-    { "v",      tZONE,  HOUR (- 9) },
-    { "w",      tZONE,  HOUR (-10) },
-    { "x",      tZONE,  HOUR (-11) },
-    { "y",      tZONE,  HOUR (-12) },
-    { "z",      tZONE,  HOUR (  0) },
-    { NULL, 0, 0 }
-};
-
-
-
-
-/* ARGSUSED */
-static int
-yyerror (const char *s ATTRIBUTE_UNUSED)
-{
-  return 0;
-}
-
-static int
-ToHour (int Hours, MERIDIAN Meridian)
-{
-  switch (Meridian)
-    {
-    case MER24:
-      if (Hours < 0 || Hours > 23)
-        return -1;
-      return Hours;
-    case MERam:
-      if (Hours < 1 || Hours > 12)
-        return -1;
-      if (Hours == 12)
-        Hours = 0;
-      return Hours;
-    case MERpm:
-      if (Hours < 1 || Hours > 12)
-        return -1;
-      if (Hours == 12)
-        Hours = 0;
-      return Hours + 12;
-    default:
-      break; /* used to do abort() here */
-    }
-  /* NOTREACHED - but make gcc happy! */
-  return -1;
-}
-
-static int
-ToYear (int Year)
-{
-  if (Year < 0)
-    Year = -Year;
-
-  /* XPG4 suggests that years 00-68 map to 2000-2068, and
-     years 69-99 map to 1969-1999.  */
-  if (Year < 69)
-    Year += 2000;
-  else if (Year < 100)
-    Year += 1900;
-
-  return Year;
-}
-
-static int
-LookupWord (YYSTYPE *yylval, char *buff)
-{
-  char *p;
-  char *q;
-  const TABLE *tp;
-  size_t i;
-  int abbrev;
-
-  /* Make it lowercase. */
-  for (p = buff; *p; p++)
-    if (ISUPPER ((unsigned char) *p))
-      *p = tolower ((int)*p);
-
-  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
-    {
-      yylval->Meridian = MERam;
-      return tMERIDIAN;
-    }
-  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
-    {
-      yylval->Meridian = MERpm;
-      return tMERIDIAN;
-    }
-
-  /* See if we have an abbreviation for a month. */
-  if (strlen (buff) == 3)
-    abbrev = 1;
-  else if (strlen (buff) == 4 && buff[3] == '.')
-    {
-      abbrev = 1;
-      buff[3] = '\0';
-    }
-  else
-    abbrev = 0;
-
-  for (tp = MonthDayTable; tp->name; tp++)
-    {
-      if (abbrev)
-        {
-          if (strncmp (buff, tp->name, 3) == 0)
-            {
-              yylval->Number = tp->value;
-              return tp->type;
-            }
-        }
-      else if (strcmp (buff, tp->name) == 0)
-        {
-          yylval->Number = tp->value;
-          return tp->type;
-        }
-    }
-
-  for (tp = TimezoneTable; tp->name; tp++)
-    if (strcmp (buff, tp->name) == 0)
-      {
-        yylval->Number = tp->value;
-        return tp->type;
-      }
-
-  if (strcmp (buff, "dst") == 0)
-    return tDST;
-
-  for (tp = UnitsTable; tp->name; tp++)
-    if (strcmp (buff, tp->name) == 0)
-      {
-        yylval->Number = tp->value;
-        return tp->type;
-      }
-
-  /* Strip off any plural and try the units table again. */
-  i = strlen (buff) - 1;
-  if (buff[i] == 's')
-    {
-      buff[i] = '\0';
-      for (tp = UnitsTable; tp->name; tp++)
-        if (strcmp (buff, tp->name) == 0)
-          {
-            yylval->Number = tp->value;
-            return tp->type;
-          }
-      buff[i] = 's';            /* Put back for "this" in OtherTable. */
-    }
-
-  for (tp = OtherTable; tp->name; tp++)
-    if (strcmp (buff, tp->name) == 0)
-      {
-        yylval->Number = tp->value;
-        return tp->type;
-      }
-
-  /* Military timezones. */
-  if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff))
-    {
-      for (tp = MilitaryTable; tp->name; tp++)
-        if (strcmp (buff, tp->name) == 0)
-          {
-            yylval->Number = tp->value;
-            return tp->type;
-          }
-    }
-
-  /* Drop out any periods and try the timezone table again. */
-  for (i = 0, p = q = buff; *q; q++)
-    if (*q != '.')
-      *p++ = *q;
-    else
-      i++;
-  *p = '\0';
-  if (i)
-    for (tp = TimezoneTable; tp->name; tp++)
-      if (strcmp (buff, tp->name) == 0)
-        {
-          yylval->Number = tp->value;
-          return tp->type;
-        }
-
-  return tID;
-}
-
-static int
-yylex (YYSTYPE *yylval, void *cookie)
-{
-  register unsigned char c;
-  register char *p;
-  char buff[20];
-  int Count;
-  int sign;
-
-  for (;;)
-    {
-      while (ISSPACE ((unsigned char) *context->yyInput))
-        context->yyInput++;
-
-      if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
-        {
-          if (c == '-' || c == '+')
-            {
-              sign = c == '-' ? -1 : 1;
-              if (!ISDIGIT (*++context->yyInput))
-                /* skip the '-' sign */
-                continue;
-            }
-          else
-            sign = 0;
-          for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
-            yylval->Number = 10 * yylval->Number + c - '0';
-          context->yyInput--;
-          if (sign < 0)
-            yylval->Number = -yylval->Number;
-          return sign ? tSNUMBER : tUNUMBER;
-        }
-      if (ISALPHA (c))
-        {
-          for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';)
-            if (p < &buff[sizeof buff - 1])
-              *p++ = c;
-          *p = '\0';
-          context->yyInput--;
-          return LookupWord (yylval, buff);
-        }
-      if (c != '(')
-        return *context->yyInput++;
-      Count = 0;
-      do
-        {
-          c = *context->yyInput++;
-          if (c == '\0')
-            return c;
-          if (c == '(')
-            Count++;
-          else if (c == ')')
-            Count--;
-        }
-      while (Count > 0);
-    }
-}
-
-#define TM_YEAR_ORIGIN 1900
-
-/* Yield A - B, measured in seconds.  */
-static long
-difftm (struct tm *a, struct tm *b)
-{
-  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
-  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
-  long days = (
-  /* difference in day of year */
-                a->tm_yday - b->tm_yday
-  /* + intervening leap days */
-                + ((ay >> 2) - (by >> 2))
-                - (ay / 100 - by / 100)
-                + ((ay / 100 >> 2) - (by / 100 >> 2))
-  /* + difference in years * 365 */
-                + (long) (ay - by) * 365
-  );
-  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
-                + (a->tm_min - b->tm_min))
-          + (a->tm_sec - b->tm_sec));
-}
-
-time_t
-curl_getdate (const char *p, const time_t *now)
-{
-  struct tm tm, tm0, *tmp;
-  time_t Start;
-  CURL_CONTEXT cookie;
-#ifdef HAVE_LOCALTIME_R
-  struct tm keeptime;
-#endif
-  cookie.yyInput = p;
-  Start = now ? *now : time ((time_t *) NULL);
-#ifdef HAVE_LOCALTIME_R
-  tmp = (struct tm *)localtime_r(&Start, &keeptime);
-#else
-  tmp = localtime (&Start);
-#endif
-  if (!tmp)
-    return -1;
-  cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
-  cookie.yyMonth = tmp->tm_mon + 1;
-  cookie.yyDay = tmp->tm_mday;
-  cookie.yyHour = tmp->tm_hour;
-  cookie.yyMinutes = tmp->tm_min;
-  cookie.yySeconds = tmp->tm_sec;
-  tm.tm_isdst = tmp->tm_isdst;
-  cookie.yyMeridian = MER24;
-  cookie.yyRelSeconds = 0;
-  cookie.yyRelMinutes = 0;
-  cookie.yyRelHour = 0;
-  cookie.yyRelDay = 0;
-  cookie.yyRelMonth = 0;
-  cookie.yyRelYear = 0;
-  cookie.yyHaveDate = 0;
-  cookie.yyHaveDay = 0;
-  cookie.yyHaveRel = 0;
-  cookie.yyHaveTime = 0;
-  cookie.yyHaveZone = 0;
-
-  if (yyparse ((void*)&cookie)
-      || cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
-      cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
-    return -1;
-
-  tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
-  tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
-  tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
-  if (cookie.yyHaveTime ||
-      (cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay))
-    {
-      tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian);
-      if (tm.tm_hour < 0)
-        return -1;
-      tm.tm_min = cookie.yyMinutes;
-      tm.tm_sec = cookie.yySeconds;
-    }
-  else
-    {
-      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
-    }
-  tm.tm_hour += cookie.yyRelHour;
-  tm.tm_min += cookie.yyRelMinutes;
-  tm.tm_sec += cookie.yyRelSeconds;
-
-  /* Let mktime deduce tm_isdst if we have an absolute timestamp,
-     or if the relative timestamp mentions days, months, or years.  */
-  if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime |
-      cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear)
-    tm.tm_isdst = -1;
-
-  tm0 = tm;
-
-  Start = mktime (&tm);
-
-  if (Start == (time_t) -1)
-    {
-
-      /* Guard against falsely reporting errors near the time_t boundaries
-         when parsing times in other time zones.  For example, if the min
-         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
-         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
-         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
-         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
-         zone by 24 hours to compensate.  This algorithm assumes that
-         there is no DST transition within a day of the time_t boundaries.  */
-      if (cookie.yyHaveZone)
-        {
-          tm = tm0;
-          if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
-            {
-              tm.tm_mday++;
-              cookie.yyTimezone -= 24 * 60;
-            }
-          else
-            {
-              tm.tm_mday--;
-              cookie.yyTimezone += 24 * 60;
-            }
-          Start = mktime (&tm);
-        }
-
-      if (Start == (time_t) -1)
-        return Start;
-    }
-
-  if (cookie.yyHaveDay && !cookie.yyHaveDate)
-    {
-      tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
-                     + 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
-      Start = mktime (&tm);
-      if (Start == (time_t) -1)
-        return Start;
-    }
-
-  if (cookie.yyHaveZone)
-    {
-      long delta;
-      struct tm *gmt;
-#ifdef HAVE_GMTIME_R
-      /* thread-safe version */
-      struct tm keeptime2;
-      gmt = (struct tm *)gmtime_r(&Start, &keeptime2);
-#else
-      gmt = gmtime(&Start);
-#endif
-      if (!gmt)
-        return -1;
-      delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
-      if ((Start + delta < Start) != (delta < 0))
-        return -1;              /* time_t overflow */
-      Start += delta;
-    }
-
-  return Start;
-}
-
-

+ 0 - 37
Utilities/cmcurl/getdate.h

@@ -1,37 +0,0 @@
-/*
-**  Originally written by Steven M. Bellovin <[email protected]> while
-**  at the University of North Carolina at Chapel Hill.  Later tweaked by
-**  a couple of people on Usenet.  Completely overhauled by Rich $alz
-**  <[email protected]> and Jim Berets <[email protected]> in August, 1990.
-**
-**  This code is in the public domain and has no copyright.
-*/
-
-# include "setup.h"
-
-#ifndef PARAMS
-# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
-#  define PARAMS(Args) Args
-# else
-#  define PARAMS(Args) ()
-# endif
-#endif
-
-#ifdef vms
-# include <types.h>
-# include <time.h>
-#else
-# include <sys/types.h>
-# if TIME_WITH_SYS_TIME
-#  include <sys/time.h>
-#  include <time.h>
-# else
-#  if HAVE_SYS_TIME_H
-#   include <sys/time.h>
-#  else
-#   include <time.h>
-#  endif
-# endif
-#endif /* defined (vms) */
-
-time_t curl_getdate PARAMS ((const char *p, const time_t *now));

+ 11 - 12
Utilities/cmcurl/getenv.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -27,24 +27,22 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef WIN32
-#include <windows.h>
-#endif
-
 #ifdef VMS
 #include <unixlib.h>
 #endif
 
 #include <curl/curl.h>
-#include "curl_memory.h"
+#include "memory.h"
 
 #include "memdebug.h"
 
 static
 char *GetEnv(const char *variable)
 {
+#ifdef _WIN32_WCE
+  return NULL;
+#else
 #ifdef WIN32
-  /* This shit requires windows.h (HUGE) to be included */
   char env[MAX_PATH]; /* MAX_PATH is from windef.h */
   char *temp = getenv(variable);
   env[0] = '\0';
@@ -62,6 +60,7 @@ char *GetEnv(const char *variable)
 #endif
 #endif
   return (env && env[0])?strdup(env):NULL;
+#endif
 }
 
 char *curl_getenv(const char *v)

+ 72 - 12
Utilities/cmcurl/getinfo.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -32,13 +32,14 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
-#include "curl_memory.h"
+#include "memory.h"
+#include "sslgen.h"
 
 /* Make this the last #include */
 #include "memdebug.h"
 
 /*
- * This is supposed to be called in the beginning of a permform() session
+ * This is supposed to be called in the beginning of a perform() session
  * and should reset all session-info variables
  */
 CURLcode Curl_initinfo(struct SessionHandle *data)
@@ -56,13 +57,14 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
   info->httpcode = 0;
   info->httpversion=0;
   info->filetime=-1; /* -1 is an illegal time and thus means unknown */
-  
+
   if (info->contenttype)
     free(info->contenttype);
   info->contenttype = NULL;
 
   info->header_size = 0;
   info->request_size = 0;
+  info->numconnects = 0;
   return CURLE_OK;
 }
 
@@ -72,13 +74,19 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
   long *param_longp=NULL;
   double *param_doublep=NULL;
   char **param_charp=NULL;
+  struct curl_slist **param_slistp=NULL;
+  char buf;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
   va_start(arg, info);
 
   switch(info&CURLINFO_TYPEMASK) {
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   case CURLINFO_STRING:
-    param_charp = va_arg(arg, char **);  
+    param_charp = va_arg(arg, char **);
     if(NULL == param_charp)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     break;
@@ -92,8 +100,13 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
     if(NULL == param_doublep)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     break;
+  case CURLINFO_SLIST:
+    param_slistp = va_arg(arg, struct curl_slist **);
+    if(NULL == param_slistp)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
   }
-  
+
   switch(info) {
   case CURLINFO_EFFECTIVE_URL:
     *param_charp = data->change.url?data->change.url:(char *)"";
@@ -159,7 +172,7 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
     *param_charp = data->info.contenttype;
     break;
   case CURLINFO_PRIVATE:
-    *param_charp = data->set.private;
+    *param_charp = data->set.private_data;
     break;
   case CURLINFO_HTTPAUTH_AVAIL:
     *param_longp = data->info.httpauthavail;
@@ -167,6 +180,53 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
   case CURLINFO_PROXYAUTH_AVAIL:
     *param_longp = 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_SSL_ENGINES:
+    *param_slistp = Curl_ssl_engines_list(data);
+    break;
+  case CURLINFO_COOKIELIST:
+    *param_slistp = Curl_cookie_list(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_LASTSOCKET:
+    if((data->state.lastconnect != -1) &&
+       (data->state.connc->connects[data->state.lastconnect] != NULL)) {
+      struct connectdata *c = data->state.connc->connects
+        [data->state.lastconnect];
+      *param_longp = c->sock[FIRSTSOCKET];
+      /* we have a socket connected, let's determine if the server shut down */
+      /* determine if ssl */
+      if(c->ssl[FIRSTSOCKET].use) {
+        /* use the SSL context */
+        if (!Curl_ssl_check_cxn(c))
+          *param_longp = -1;   /* FIN received */
+      }
+/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
+#ifdef MSG_PEEK
+      else {
+        /* use the socket */
+        if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+                (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
+          *param_longp = -1;   /* FIN received */
+        }
+      }
+#endif
+    }
+    else
+      *param_longp = -1;
+    break;
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }

+ 640 - 0
Utilities/cmcurl/gtls.c

@@ -0,0 +1,640 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
+ * but sslgen.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 "setup.h"
+#ifdef USE_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "gtls.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+#include "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
+
+/*
+ * 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 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.
+ */
+static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
+{
+  return swrite(s, buf, len);
+}
+
+static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
+{
+  return sread(s, buf, len);
+}
+
+/* Global GnuTLS init, called from Curl_ssl_init() */
+int Curl_gtls_init(void)
+{
+  gnutls_global_init();
+#ifdef GTLSDEBUG
+  gnutls_global_set_log_function(tls_log_func);
+  gnutls_global_set_log_level(2);
+#endif
+  return 1;
+}
+
+int Curl_gtls_cleanup(void)
+{
+  gnutls_global_deinit();
+  return 1;
+}
+
+static void showtime(struct SessionHandle *data,
+                     const char *text,
+                     time_t stamp)
+{
+  struct tm *tm;
+#ifdef HAVE_GMTIME_R
+  struct tm buffer;
+  tm = (struct tm *)gmtime_r(&stamp, &buffer);
+#else
+  tm = gmtime(&stamp);
+#endif
+  snprintf(data->state.buffer,
+           BUFSIZE,
+           "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
+           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", data->state.buffer);
+}
+
+/* this function does a BLOCKING SSL/TLS (re-)handshake */
+static CURLcode handshake(struct connectdata *conn,
+                          gnutls_session session,
+                          int sockindex,
+                          bool duringconnect)
+{
+  struct SessionHandle *data = conn->data;
+  int rc;
+
+  do {
+    rc = gnutls_handshake(session);
+
+    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
+      long timeout_ms = DEFAULT_CONNECT_TIMEOUT;
+      long has_passed;
+
+      if(duringconnect && data->set.connecttimeout)
+        timeout_ms = data->set.connecttimeout*1000;
+
+      if(data->set.timeout) {
+        /* get the strictest timeout of the ones converted to milliseconds */
+        if((data->set.timeout*1000) < timeout_ms)
+          timeout_ms = data->set.timeout*1000;
+      }
+
+      /* Evaluate in milliseconds how much time that has passed */
+      has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+
+      /* subtract the passed time */
+      timeout_ms -= has_passed;
+
+      if(timeout_ms < 0) {
+        /* a precaution, no need to continue if time already is up */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEOUTED;
+      }
+
+      rc = Curl_select(conn->sock[sockindex],
+                       conn->sock[sockindex], (int)timeout_ms);
+      if(rc > 0)
+        /* reabable or writable, go loop*/
+        continue;
+      else if(0 == rc) {
+        /* timeout */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else
+      break;
+  } while(1);
+
+  if (rc < 0) {
+    failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+static gnutls_x509_crt_fmt do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return GNUTLS_X509_FMT_PEM;
+  if(curl_strequal(type, "PEM"))
+    return GNUTLS_X509_FMT_PEM;
+  if(curl_strequal(type, "DER"))
+    return GNUTLS_X509_FMT_DER;
+  return -1;
+}
+
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic.
+ */
+CURLcode
+Curl_gtls_connect(struct connectdata *conn,
+                  int sockindex)
+
+{
+  const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+  struct SessionHandle *data = conn->data;
+  gnutls_session session;
+  int rc;
+  unsigned int cert_list_size;
+  const gnutls_datum *chainp;
+  unsigned int verify_status;
+  gnutls_x509_crt x509_cert;
+  char certbuf[256]; /* big enough? */
+  size_t size;
+  unsigned int algo;
+  unsigned int bits;
+  time_t clock;
+  const char *ptr;
+  void *ssl_sessionid;
+  size_t ssl_idsize;
+
+  /* GnuTLS only supports TLSv1 (and SSLv3?) */
+  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+    failf(data, "GnuTLS does not support SSLv2");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* allocate a cred struct */
+  rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
+  if(rc < 0) {
+    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(data->set.ssl.CAfile) {
+    /* set the trusted CA cert bundle file */
+    gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
+                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+    rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
+                                                data->set.ssl.CAfile,
+                                                GNUTLS_X509_FMT_PEM);
+    if(rc < 0) {
+      infof(data, "error reading ca cert file %s (%s)\n",
+            data->set.ssl.CAfile, gnutls_strerror(rc));
+      if (data->set.ssl.verifypeer)
+        return CURLE_SSL_CACERT_BADFILE;
+    }
+    else
+      infof(data, "found %d certificates in %s\n",
+            rc, data->set.ssl.CAfile);
+  }
+
+  /* Initialize TLS session as a client */
+  rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
+  if(rc) {
+    failf(data, "gnutls_init() failed: %d", rc);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* convenient assign */
+  session = conn->ssl[sockindex].session;
+
+  /* Use default priorities */
+  rc = gnutls_set_default_priority(session);
+  if(rc < 0)
+    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 < 0)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  if(data->set.cert) {
+    if( gnutls_certificate_set_x509_key_file(
+          conn->ssl[sockindex].cred, data->set.cert,
+          data->set.key != 0 ? data->set.key : data->set.cert,
+          do_file_type(data->set.cert_type) ) ) {
+      failf(data, "error reading X.509 key or certificate file");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  /* put the credentials to the current session */
+  rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+                              conn->ssl[sockindex].cred);
+
+  /* set the connection handle (file descriptor for the socket) */
+  gnutls_transport_set_ptr(session,
+                           (gnutls_transport_ptr)conn->sock[sockindex]);
+
+  /* register callback functions to send and receive data. */
+  gnutls_transport_set_push_function(session, Curl_gtls_push);
+  gnutls_transport_set_pull_function(session, Curl_gtls_pull);
+
+  /* lowat must be set to zero when using custom push and pull functions. */
+  gnutls_transport_set_lowat(session, 0);
+
+  /* This might be a reconnect, so we check for a session ID in the cache
+     to speed up things */
+
+  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
+    /* 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");
+  }
+
+  rc = handshake(conn, session, sockindex, TRUE);
+  if(rc)
+    /* handshake() sets its own error message with failf() */
+    return rc;
+
+  /* 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(data->set.ssl.verifyhost) {
+      failf(data, "failed to get server cert");
+      return CURLE_SSL_PEER_CERTIFICATE;
+    }
+    infof(data, "\t common name: WARNING couldn't obtain\n");
+  }
+
+  /* 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 (data->set.ssl.verifypeer) {
+      failf(data, "server certificate verification failed. CAfile: %s",
+            data->set.ssl.CAfile?data->set.ssl.CAfile:"none");
+      return CURLE_SSL_CACERT;
+    }
+    else
+      infof(data, "\t server certificate verification FAILED\n");
+  }
+  else
+      infof(data, "\t server certificate verification OK\n");
+
+  /* initialize an X.509 certificate structure. */
+  gnutls_x509_crt_init(&x509_cert);
+
+  /* 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);
+
+  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, conn->host.name);
+
+  if(!rc) {
+    if (data->set.ssl.verifyhost > 1) {
+      failf(data, "SSL: certificate subject name (%s) does not match "
+            "target host name '%s'", certbuf, conn->host.dispname);
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_SSL_PEER_CERTIFICATE;
+    }
+    else
+      infof(data, "\t common name: %s (does not match '%s')\n",
+            certbuf, conn->host.dispname);
+  }
+  else
+    infof(data, "\t common name: %s (matched)\n", certbuf);
+
+  /* Show:
+
+  - ciphers used
+  - subject
+  - start date
+  - expire date
+  - common name
+  - issuer
+
+  */
+
+  /* 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);
+
+  clock = gnutls_x509_crt_get_activation_time(x509_cert);
+  showtime(data, "start date", clock);
+
+  clock = gnutls_x509_crt_get_expiration_time(x509_cert);
+  showtime(data, "expire date", clock);
+
+  size = sizeof(certbuf);
+  gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
+  infof(data, "\t issuer: %s\n", certbuf);
+
+  gnutls_x509_crt_deinit(x509_cert);
+
+  /* compression algorithm (if any) */
+  ptr = gnutls_compression_get_name(gnutls_compression_get(session));
+  /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
+  infof(data, "\t compression: %s\n", ptr);
+
+  /* the name of the cipher used. ie 3DES. */
+  ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
+  infof(data, "\t cipher: %s\n", ptr);
+
+  /* the MAC algorithms name. ie SHA1 */
+  ptr = gnutls_mac_get_name(gnutls_mac_get(session));
+  infof(data, "\t MAC: %s\n", ptr);
+
+  if(!ssl_sessionid) {
+    /* this session was not previously in the cache, add it now */
+
+    /* get the session ID data size */
+    gnutls_session_get_data(session, NULL, &ssl_idsize);
+    ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */
+
+    if(ssl_sessionid) {
+      /* extract session ID to the allocated buffer */
+      gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize);
+
+      /* store this session id */
+      return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize);
+    }
+  }
+
+  return CURLE_OK;
+}
+
+
+/* return number of sent (non-SSL) bytes */
+ssize_t Curl_gtls_send(struct connectdata *conn,
+                   int sockindex,
+                   void *mem,
+                   size_t len)
+{
+  ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
+
+  if(rc < 0 ) {
+    if(rc == GNUTLS_E_AGAIN)
+      return 0; /* EWOULDBLOCK equivalent */
+    rc = -1; /* generic error code for send failure */
+  }
+
+  return rc;
+}
+
+void Curl_gtls_close_all(struct SessionHandle *data)
+{
+  /* FIX: make the OpenSSL code more generic and use parts of it here */
+  (void)data;
+}
+
+static void close_one(struct connectdata *conn,
+                      int index)
+{
+  if(conn->ssl[index].session) {
+    gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR);
+    gnutls_deinit(conn->ssl[index].session);
+  }
+  gnutls_certificate_free_credentials(conn->ssl[index].cred);
+}
+
+void Curl_gtls_close(struct connectdata *conn)
+{
+  if(conn->ssl[0].use)
+    close_one(conn, 0);
+  if(conn->ssl[1].use)
+    close_one(conn, 1);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+{
+  int result;
+  int retval = 0;
+  struct SessionHandle *data = conn->data;
+  int done = 0;
+  ssize_t nread;
+  char buf[120];
+
+  /* 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(conn->ssl[sockindex].session) {
+    while(!done) {
+      int what = Curl_select(conn->sock[sockindex],
+                             CURL_SOCKET_BAD, 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(conn->ssl[sockindex].session,
+                                    buf, sizeof(buf));
+        switch(result) {
+        case 0:
+          /* This is the expected response. There was no data but only
+             the close notify alert */
+          done = 1;
+          break;
+        case GNUTLS_E_AGAIN:
+        case GNUTLS_E_INTERRUPTED:
+          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+          break;
+        default:
+          retval = -1;
+          done = 1;
+          break;
+        }
+      }
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL shutdown timeout");
+        done = 1;
+        break;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
+        retval = -1;
+        done = 1;
+      }
+    }
+    gnutls_deinit(conn->ssl[sockindex].session);
+  }
+  gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+
+  conn->ssl[sockindex].session = NULL;
+  conn->ssl[sockindex].use = FALSE;
+
+  return retval;
+}
+
+/*
+ * If the read would block we return -1 and set 'wouldblock' to TRUE.
+ * Otherwise we return the amount of data read. Other errors should return -1
+ * and set 'wouldblock' to FALSE.
+ */
+ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
+                       int num,                  /* socketindex */
+                       char *buf,                /* store read data here */
+                       size_t buffersize,        /* max amount to read */
+                       bool *wouldblock)
+{
+  ssize_t ret;
+
+  ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
+  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+    *wouldblock = TRUE;
+    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 rc = handshake(conn, conn->ssl[num].session, num, FALSE);
+    if(rc)
+      /* handshake() writes error message on its own */
+      return rc;
+    *wouldblock = TRUE; /* then return as if this was a wouldblock */
+    return -1;
+  }
+
+  *wouldblock = FALSE;
+  if (!ret) {
+    failf(conn->data, "Peer closed the TLS connection");
+    return -1;
+  }
+
+  if (ret < 0) {
+    failf(conn->data, "GnuTLS recv error (%d): %s",
+          (int)ret, gnutls_strerror(ret));
+    return -1;
+  }
+
+  return ret;
+}
+
+void Curl_gtls_session_free(void *ptr)
+{
+  free(ptr);
+}
+
+size_t Curl_gtls_version(char *buffer, size_t size)
+{
+  return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL));
+}
+
+#endif /* USE_GNUTLS */

+ 46 - 0
Utilities/cmcurl/gtls.h

@@ -0,0 +1,46 @@
+#ifndef __GTLS_H
+#define __GTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+int Curl_gtls_init(void);
+int Curl_gtls_cleanup(void);
+CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
+
+/* tell GnuTLS to close down all open information regarding connections (and
+   thus session ID caching etc) */
+void Curl_gtls_close_all(struct SessionHandle *data);
+void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */
+
+/* return number of sent (non-SSL) bytes */
+ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex,
+                       void *mem, size_t len);
+ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
+                       int num,                  /* socketindex */
+                       char *buf,                /* store read data here */
+                       size_t buffersize,        /* max amount to read */
+                       bool *wouldblock);
+void Curl_gtls_session_free(void *ptr);
+size_t Curl_gtls_version(char *buffer, size_t size);
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
+
+#endif

+ 83 - 35
Utilities/cmcurl/hash.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -28,7 +28,7 @@
 
 #include "hash.h"
 #include "llist.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 /* this must be the last include file */
 #include "memdebug.h"
@@ -50,12 +50,11 @@ hash_str(const char *key, size_t key_length)
 static void
 hash_element_dtor(void *user, void *element)
 {
-  curl_hash         *h = (curl_hash *) user;
-  curl_hash_element *e = (curl_hash_element *) element;
+  struct curl_hash *h = (struct curl_hash *) user;
+  struct curl_hash_element *e = (struct curl_hash_element *) element;
 
-  if (e->key) {
+  if (e->key)
     free(e->key);
-  }
 
   h->dtor(e->ptr);
 
@@ -64,7 +63,7 @@ hash_element_dtor(void *user, void *element)
 
 /* return 1 on error, 0 is fine */
 int
-Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
+Curl_hash_init(struct curl_hash *h, int slots, curl_hash_dtor dtor)
 {
   int i;
 
@@ -72,7 +71,7 @@ Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
   h->size = 0;
   h->slots = slots;
 
-  h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
+  h->table = (struct curl_llist **) malloc(slots * sizeof(struct curl_llist *));
   if(h->table) {
     for (i = 0; i < slots; ++i) {
       h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
@@ -89,12 +88,12 @@ Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
     return 1; /* failure */
 }
 
-curl_hash *
+struct curl_hash *
 Curl_hash_alloc(int slots, curl_hash_dtor dtor)
 {
-  curl_hash *h;
+  struct curl_hash *h;
 
-  h = (curl_hash *) malloc(sizeof(curl_hash));
+  h = (struct curl_hash *) malloc(sizeof(struct curl_hash));
   if (h) {
     if(Curl_hash_init(h, slots, dtor)) {
       /* failure */
@@ -118,15 +117,18 @@ hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len)
   return 0;
 }
 
-static curl_hash_element *
+static struct curl_hash_element *
 mk_hash_element(char *key, size_t key_len, const void *p)
 {
-  curl_hash_element *he =
-    (curl_hash_element *) malloc(sizeof(curl_hash_element));
+  struct curl_hash_element *he =
+    (struct curl_hash_element *) malloc(sizeof(struct curl_hash_element));
 
   if(he) {
-    char *dup = strdup(key);
+    char *dup = malloc(key_len);
     if(dup) {
+      /* copy the key */
+      memcpy(dup, key, key_len);
+
       he->key = dup;
       he->key_len = key_len;
       he->ptr = (void *) p;
@@ -147,14 +149,14 @@ mk_hash_element(char *key, size_t key_len, const void *p)
 /* Return the data in the hash. If there already was a match in the hash,
    that data is returned. */
 void *
-Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p)
+Curl_hash_add(struct curl_hash *h, char *key, size_t key_len, void *p)
 {
-  curl_hash_element  *he;
-  curl_llist_element *le;
-  curl_llist *l = FETCH_LIST(h, key, key_len);
+  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 = (curl_hash_element *) le->ptr;
+    he = (struct curl_hash_element *) le->ptr;
     if (hash_key_compare(he->key, he->key_len, key, key_len)) {
       h->dtor(p);     /* remove the NEW entry */
       return he->ptr; /* return the EXISTING entry */
@@ -180,16 +182,31 @@ Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p)
   return NULL; /* failure */
 }
 
+/* remove the identified hash entry, returns non-zero on failure */
+int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len)
+{
+  struct curl_llist_element *le;
+  struct curl_hash_element  *he;
+  struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+  for (le = l->head; le; le = le->next) {
+    he = le->ptr;
+    if (hash_key_compare(he->key, he->key_len, key, key_len)) {
+      Curl_llist_remove(l, le, (void *) h);
+      return 0;
+    }
+  }
+  return 1;
+}
+
 void *
-Curl_hash_pick(curl_hash *h, char *key, size_t key_len)
+Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len)
 {
-  curl_llist_element *le;
-  curl_hash_element  *he;
-  curl_llist *l = FETCH_LIST(h, key, key_len);
+  struct curl_llist_element *le;
+  struct curl_hash_element  *he;
+  struct curl_llist *l = FETCH_LIST(h, key, key_len);
 
-  for (le = l->head;
-       le;
-       le = le->next) {
+  for (le = l->head; le; le = le->next) {
     he = le->ptr;
     if (hash_key_compare(he->key, he->key_len, key, key_len)) {
       return he->ptr;
@@ -204,7 +221,7 @@ void
 Curl_hash_apply(curl_hash *h, void *user,
                 void (*cb)(void *user, void *ptr))
 {
-  curl_llist_element  *le;
+  struct curl_llist_element  *le;
   int                  i;
 
   for (i = 0; i < h->slots; ++i) {
@@ -219,7 +236,7 @@ Curl_hash_apply(curl_hash *h, void *user,
 #endif
 
 void
-Curl_hash_clean(curl_hash *h)
+Curl_hash_clean(struct curl_hash *h)
 {
   int i;
 
@@ -231,19 +248,19 @@ Curl_hash_clean(curl_hash *h)
 }
 
 void
-Curl_hash_clean_with_criterium(curl_hash *h, void *user,
+Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
                                int (*comp)(void *, void *))
 {
-  curl_llist_element *le;
-  curl_llist_element *lnext;
-  curl_llist *list;
+  struct curl_llist_element *le;
+  struct curl_llist_element *lnext;
+  struct curl_llist *list;
   int i;
 
   for (i = 0; i < h->slots; ++i) {
     list = h->table[i];
     le = list->head; /* get first list entry */
     while(le) {
-      curl_hash_element *he = le->ptr;
+      struct curl_hash_element *he = le->ptr;
       lnext = le->next;
       /* ask the callback function if we shall remove this entry or not */
       if (comp(user, he->ptr)) {
@@ -256,7 +273,7 @@ Curl_hash_clean_with_criterium(curl_hash *h, void *user,
 }
 
 void
-Curl_hash_destroy(curl_hash *h)
+Curl_hash_destroy(struct curl_hash *h)
 {
   if (!h)
     return;
@@ -265,3 +282,34 @@ Curl_hash_destroy(curl_hash *h)
   free(h);
 }
 
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct curl_hash *h,
+                     void (*func)(void *))
+{
+  int i;
+  struct curl_llist_element *le;
+  struct curl_llist *list;
+  struct curl_hash_element  *he;
+  if (!h)
+    return;
+
+  fprintf(stderr, "=Hash dump=\n");
+
+  for (i = 0; i < h->slots; i++) {
+    list = h->table[i];
+    le = list->head; /* get first list entry */
+    if(le) {
+      fprintf(stderr, "index %d:", i);
+      while(le) {
+        he = le->ptr;
+        if(func)
+          func(he->ptr);
+        else
+          fprintf(stderr, " [%p]", he->ptr);
+        le = le->next;
+      }
+      fprintf(stderr, "\n");
+    }
+  }
+}
+#endif

+ 19 - 18
Utilities/cmcurl/hash.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,30 +31,31 @@
 
 typedef void (*curl_hash_dtor)(void *);
 
-typedef struct _curl_hash {
-  curl_llist     **table;
+struct curl_hash {
+  struct curl_llist **table;
   curl_hash_dtor   dtor;
-  int              slots;
-  size_t           size;
-} curl_hash;
+  int slots;
+  size_t size;
+};
 
-typedef struct _curl_hash_element {
+struct curl_hash_element {
   void   *ptr;
   char   *key;
   size_t key_len;
-} curl_hash_element;
+};
 
 
-int Curl_hash_init(curl_hash *, int, curl_hash_dtor);
-curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
-void *Curl_hash_add(curl_hash *, char *, size_t, void *);
-int Curl_hash_delete(curl_hash *h, char *key, size_t key_len);
-void *Curl_hash_pick(curl_hash *, char *, size_t);
-void Curl_hash_apply(curl_hash *h, void *user,
+int Curl_hash_init(struct curl_hash *, int, curl_hash_dtor);
+struct curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
+void *Curl_hash_add(struct curl_hash *, char *, size_t, void *);
+int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len);
+void *Curl_hash_pick(struct curl_hash *, char *, size_t);
+void Curl_hash_apply(struct curl_hash *h, void *user,
                      void (*cb)(void *user, void *ptr));
-int Curl_hash_count(curl_hash *h);
-void Curl_hash_clean(curl_hash *h);
-void Curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *, void *));
-void Curl_hash_destroy(curl_hash *h);
+int Curl_hash_count(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 *));
+void Curl_hash_destroy(struct curl_hash *h);
 
 #endif

+ 29 - 23
Utilities/cmcurl/hostares.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,13 +24,10 @@
 #include "setup.h"
 
 #include <string.h>
-#include <errno.h>
 
-#define _REENTRANT
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,13 +54,12 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #endif
 
@@ -79,6 +75,8 @@
 #include "share.h"
 #include "strerror.h"
 #include "url.h"
+#include "multiif.h"
+#include "connect.h" /* for the Curl_sockerrno() proto */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -87,7 +85,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -99,7 +97,7 @@
 #ifdef CURLRES_ARES
 
 /*
- * Curl_fdset() is called when someone from the outside world (using
+ * Curl_resolv_fdset() 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.
@@ -107,17 +105,26 @@
  * Returns: CURLE_OK always!
  */
 
-CURLcode Curl_fdset(struct connectdata *conn,
-                    fd_set *read_fd_set,
-                    fd_set *write_fd_set,
-                    int *max_fdp)
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
 
 {
-  int max = ares_fds(conn->data->state.areschannel,
-                     read_fd_set, write_fd_set);
-  *max_fdp = max;
+  struct timeval maxtime;
+  struct timeval timeout;
+  int max = ares_getsock(conn->data->state.areschannel,
+                         (int *)socks, numsocks);
 
-  return CURLE_OK;
+
+  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+  maxtime.tv_usec = 0;
+
+  ares_timeout(conn->data->state.areschannel, &maxtime, &timeout);
+
+  Curl_expire(conn->data,
+              (timeout.tv_sec * 1000) + (timeout.tv_usec/1000) );
+
+  return max;
 }
 
 /*
@@ -213,7 +220,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
       break;
     tvp = ares_timeout(data->state.areschannel, &store, &tv);
     count = select(nfds, &read_fds, &write_fds, NULL, tvp);
-    if (count < 0 && errno != EINVAL)
+    if (count < 0 && Curl_sockerrno() != EINVAL)
       break;
 
     ares_process(data->state.areschannel, &read_fds, &write_fds);
@@ -249,7 +256,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
 
     /* close the connection, since we can't return failure here without
        cleaning up this connection properly */
-    Curl_disconnect(conn);
+    conn->bits.close = TRUE;
   }
 
   return rc;
@@ -264,7 +271,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
  * Curl_freeaddrinfo(), nothing else.
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp)
 {
@@ -291,11 +298,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
     /* areschannel is already setup in the Curl_open() function */
     ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
-                       Curl_addrinfo4_callback, conn);
+                       (ares_host_callback)Curl_addrinfo4_callback, conn);
 
     *waitp = TRUE; /* please wait for the response */
   }
   return NULL; /* no struct yet */
 }
-
 #endif /* CURLRES_ARES */

+ 33 - 29
Utilities/cmcurl/hostasyn.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,13 +24,10 @@
 #include "setup.h"
 
 #include <string.h>
-#include <errno.h>
 
-#define _REENTRANT
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,21 +54,15 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #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"
@@ -87,7 +78,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -108,21 +99,21 @@
  *
  * The storage operation locks and unlocks the DNS cache.
  */
-static void addrinfo_callback(void *arg, /* "struct connectdata *" */
-                              int status,
-                              void *addr)
+static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
+                                  int status,
+                                  void *addr)
 {
   struct connectdata *conn = (struct connectdata *)arg;
   struct Curl_dns_entry *dns = NULL;
+  CURLcode rc = CURLE_OK;
 
-  conn->async.done = TRUE;
   conn->async.status = status;
 
   if(CURL_ASYNC_SUCCESS == status) {
 
     /*
-     * IPv4: Curl_addrinfo_copy() copies the address and returns an allocated
-     * version.
+     * IPv4/ares: Curl_addrinfo_copy() copies the address and returns an
+     * allocated version.
      *
      * IPv6: Curl_addrinfo_copy() returns the input pointer!
      */
@@ -136,34 +127,47 @@ static void addrinfo_callback(void *arg, /* "struct connectdata *" */
       dns = Curl_cache_addr(data, ai,
                             conn->async.hostname,
                             conn->async.port);
-      if(!dns)
+      if(!dns) {
         /* failed to store, cleanup and return error */
         Curl_freeaddrinfo(ai);
+        rc = CURLE_OUT_OF_MEMORY;
+      }
 
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
     }
+    else
+      rc = 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 rc;
 }
 
-void Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
-                             int status,
-                             struct hostent *hostent)
+CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
+                                 int status,
+                                 struct hostent *hostent)
 {
-  addrinfo_callback(arg, status, hostent);
+  return addrinfo_callback(arg, status, hostent);
 }
 
 #ifdef CURLRES_IPV6
-void Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
-                             int status,
-                             struct addrinfo *ai)
+CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
+                                 int status,
+                                 struct addrinfo *ai)
 {
-  addrinfo_callback(arg, status, ai);
+ /* NOTE: for CURLRES_ARES, the 'ai' argument is really a
+  * 'struct hostent' pointer.
+  */
+  return addrinfo_callback(arg, status, ai);
 }
 #endif
 

+ 152 - 56
Utilities/cmcurl/hostip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,13 +24,10 @@
 #include "setup.h"
 
 #include <string.h>
-#include <errno.h>
 
-#define _REENTRANT
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,21 +54,15 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #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"
@@ -88,7 +79,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -105,8 +96,7 @@
  * defined.
  *
  * CURLRES_ARES - is defined if libcurl is built to use c-ares for
- * asynchronous name resolves. It cannot have ENABLE_IPV6 defined at the same
- * time, as c-ares has no ipv6 support. This can be Windows or *nix.
+ * 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
@@ -131,7 +121,7 @@
  */
 
 /* These two symbols are for the global DNS cache */
-static curl_hash hostname_cache;
+static struct curl_hash hostname_cache;
 static int host_cache_initialized;
 
 static void freednsentry(void *freethis);
@@ -152,7 +142,7 @@ void Curl_global_host_cache_init(void)
 /*
  * Return a pointer to the global cache
  */
-curl_hash *Curl_global_host_cache_get(void)
+struct curl_hash *Curl_global_host_cache_get(void)
 {
   return &hostname_cache;
 }
@@ -174,20 +164,11 @@ void Curl_global_host_cache_dtor(void)
 int Curl_num_addresses(const Curl_addrinfo *addr)
 {
   int i;
-  for (i = 0; addr; addr = addr->ai_next, i++);
+  for (i = 0; addr; addr = addr->ai_next, i++)
+    ;  /* empty loop */
   return i;
 }
 
-#define GET_SIN_ADDR_FROM_CURL_ADDRINFO(ai_addr, si, sin, sinaddr, ip) \
-  { \
-  union { \
-    struct si* vsi; \
-    struct sin* vsin;\
-  } vi; \
-  vi.vsi = ai_addr; \
-  ip = &(vi.vsin->sinaddr); \
-  }
-
 /*
  * 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
@@ -198,17 +179,13 @@ int Curl_num_addresses(const Curl_addrinfo *addr)
 const char *Curl_printable_address(const Curl_addrinfo *ip,
                                    char *buf, size_t bufsize)
 {
+  const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
   int af = ip->ai_family;
-  const void *ip4;
 #ifdef CURLRES_IPV6
-  const void *ip6;
-  GET_SIN_ADDR_FROM_CURL_ADDRINFO(ip->ai_addr, sockaddr, sockaddr_in6,
-    sin6_addr, ip6);
+  const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
 #else
   const void *ip6 = NULL;
 #endif
-  GET_SIN_ADDR_FROM_CURL_ADDRINFO(ip->ai_addr, sockaddr, sockaddr_in,
-    sin_addr, ip4);
 
   return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
 }
@@ -218,7 +195,7 @@ const char *Curl_printable_address(const Curl_addrinfo *ip,
  * the DNS caching.
  */
 static char *
-create_hostcache_id(char *server, int port)
+create_hostcache_id(const char *server, int port)
 {
   /* create and return the new allocated entry */
   return aprintf("%s:%d", server, port);
@@ -257,7 +234,7 @@ hostcache_timestamp_remove(void *datap, void *hc)
  * Prune the DNS cache. This assumes that a lock has already been taken.
  */
 static void
-hostcache_prune(curl_hash *hostcache, int cache_timeout, time_t now)
+hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now)
 {
   struct hostcache_prune_data user;
 
@@ -277,8 +254,9 @@ void Curl_hostcache_prune(struct SessionHandle *data)
 {
   time_t now;
 
-  if(data->set.dns_cache_timeout == -1)
-    /* cache forever means never prune! */
+  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)
@@ -287,7 +265,7 @@ void Curl_hostcache_prune(struct SessionHandle *data)
   time(&now);
 
   /* Remove outdated and unused entries from the hostcache */
-  hostcache_prune(data->hostcache,
+  hostcache_prune(data->dns.hostcache,
                   data->set.dns_cache_timeout,
                   now);
 
@@ -295,6 +273,39 @@ void Curl_hostcache_prune(struct SessionHandle *data)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
 }
 
+static int
+remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
+{
+  struct hostcache_prune_data user;
+
+  if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
+    /* cache forever means never prune, and NULL hostcache means
+       we can't do it */
+    return 0;
+
+  time(&user.now);
+  user.cache_timeout = data->set.dns_cache_timeout;
+
+  if ( !hostcache_timestamp_remove(&user,dns) )
+    return 0;
+
+  /* ok, we do need to clear the cache. although we need to remove just a
+     single entry we clean the entire hash, as no explicit delete function
+     is provided */
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  Curl_hash_clean_with_criterium(data->dns.hostcache,
+                                 (void *) &user,
+                                 hostcache_timestamp_remove);
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+  return 1;
+}
+
+
 #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
@@ -315,7 +326,7 @@ sigjmp_buf curl_jmpenv;
 struct Curl_dns_entry *
 Curl_cache_addr(struct SessionHandle *data,
                 Curl_addrinfo *addr,
-                char *hostname,
+                const char *hostname,
                 int port)
 {
   char *entry_id;
@@ -332,7 +343,7 @@ Curl_cache_addr(struct SessionHandle *data,
   entry_len = strlen(entry_id);
 
   /* Create a new cache entry */
-  dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
+  dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
   if (!dns) {
     free(entry_id);
     return NULL;
@@ -344,7 +355,8 @@ Curl_cache_addr(struct SessionHandle *data,
   /* Store the resolved data in our DNS cache. This function may return a
      pointer to an existing struct already present in the hash, and it may
      return the same argument we pass in. Make no assumptions. */
-  dns2 = Curl_hash_add(data->hostcache, entry_id, entry_len+1, (void *)dns);
+  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+                       (void *)dns);
   if(!dns2) {
     /* Major badness, run away. */
     free(dns);
@@ -381,31 +393,30 @@ Curl_cache_addr(struct SessionHandle *data,
  */
 
 int Curl_resolv(struct connectdata *conn,
-                char *hostname,
+                const char *hostname,
                 int port,
                 struct Curl_dns_entry **entry)
 {
-  char *entry_id;
+  char *entry_id = NULL;
   struct Curl_dns_entry *dns = NULL;
   size_t entry_len;
   int wait;
   struct SessionHandle *data = conn->data;
   CURLcode result;
-
-  /* default to failure */
   int rc;
   *entry = NULL;
 
 #ifdef HAVE_SIGSETJMP
   /* this allows us to time-out from the name resolver, as the timeout
      will generate a signal and we will siglongjmp() from that here */
-  if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
-    /* this is coming from a siglongjmp() */
-    failf(data, "name lookup timed out");
-    return CURLRESOLV_ERROR;
+  if(!data->set.no_signal) {
+    if (sigsetjmp(curl_jmpenv, 1)) {
+      /* this is coming from a siglongjmp() */
+      failf(data, "name lookup timed out");
+      return CURLRESOLV_ERROR;
+    }
   }
 #endif
-  rc = CURLRESOLV_ERROR;
 
   /* Create an entry id, based upon the hostname and port */
   entry_id = create_hostcache_id(hostname, port);
@@ -419,7 +430,7 @@ int Curl_resolv(struct connectdata *conn,
     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->hostcache, entry_id, entry_len+1);
+  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
 
   if(data->share)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -427,6 +438,13 @@ int Curl_resolv(struct connectdata *conn,
   /* free the allocated entry_id again */
   free(entry_id);
 
+  /* See whether the returned entry is stale. Deliberately done after the
+     locked block */
+  if ( remove_entry_if_stale(data,dns) )
+    dns = NULL; /* the memory deallocation is being handled by the hash */
+
+  rc = CURLRESOLV_ERROR; /* default to failure */
+
   if (!dns) {
     /* The entry was not in the cache. Resolve it to IP address */
 
@@ -474,7 +492,11 @@ int Curl_resolv(struct connectdata *conn,
     }
   }
   else {
+    if(data->share)
+      Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
     dns->inuse++; /* we use it! */
+    if(data->share)
+      Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
     rc = CURLRESOLV_RESOLVED;
   }
 
@@ -516,7 +538,7 @@ static void freednsentry(void *freethis)
 /*
  * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
  */
-curl_hash *Curl_mk_dnscache(void)
+struct curl_hash *Curl_mk_dnscache(void)
 {
   return Curl_hash_alloc(7, freednsentry);
 }
@@ -531,10 +553,84 @@ curl_hash *Curl_mk_dnscache(void)
  * returns a pointer to the malloc()ed copy. You need to call free() on the
  * returned buffer when you're done with it.
  */
-Curl_addrinfo *Curl_addrinfo_copy(void *org, int port)
+Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
 {
-  struct hostent *orig = org;
+  const struct hostent *orig = org;
 
   return Curl_he2ai(orig, port);
 }
 #endif /* CURLRES_ADDRINFO_COPY */
+
+/***********************************************************************
+ * Only for plain-ipv4 and c-ares builds
+ **********************************************************************/
+
+#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
+/*
+ * This is a function for freeing name information in a protocol independent
+ * way.
+ */
+void Curl_freeaddrinfo(Curl_addrinfo *ai)
+{
+  Curl_addrinfo *next;
+
+  /* walk over the list and free all entries */
+  while(ai) {
+    next = ai->ai_next;
+    free(ai);
+    ai = next;
+  }
+}
+
+struct namebuf {
+  struct hostent hostentry;
+  char *h_addr_list[2];
+  struct in_addr addrentry;
+  char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
+};
+
+/*
+ * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
+ * together with a pointer to the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for this
+ * address/host.
+ *
+ * The input parameters ARE NOT checked for validity but they are expected
+ * to have been checked already when this is called.
+ */
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
+{
+  Curl_addrinfo *ai;
+  struct hostent *h;
+  struct in_addr *addrentry;
+  struct namebuf buffer;
+  struct namebuf *buf = &buffer;
+
+  h = &buf->hostentry;
+  h->h_addr_list = &buf->h_addr_list[0];
+  addrentry = &buf->addrentry;
+#ifdef _CRAYC
+  /* On UNICOS, s_addr is a bit field and for some reason assigning to it
+   * doesn't work.  There must be a better fix than this ugly hack.
+   */
+  memcpy(addrentry, &num, SIZEOF_in_addr);
+#else
+  addrentry->s_addr = num;
+#endif
+  h->h_addr_list[0] = (char*)addrentry;
+  h->h_addr_list[1] = NULL;
+  h->h_addrtype = AF_INET;
+  h->h_length = sizeof(*addrentry);
+  h->h_name = &buf->h_name[0];
+  h->h_aliases = NULL;
+
+  /* Now store the dotted version of the address */
+  snprintf((char *)h->h_name, 16, "%s", hostname);
+
+  ai = Curl_he2ai(h, port);
+
+  return ai;
+}
+#endif
+
+

+ 60 - 44
Utilities/cmcurl/hostip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,8 +26,9 @@
 #include "setup.h"
 #include "hash.h"
 
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t uint32_t
 #endif
 
 /*
@@ -55,14 +56,14 @@
 #define CURLRES_IPV4
 #endif
 
-#ifdef CURLRES_IPV4
+#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
 #if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH)
 /* If built for ipv4 and missing gethostbyname_r(), or if using async name
    resolve, we need the Curl_addrinfo_copy() function (which itself needs the
-   Curl_hostent_relocate() function)) */
+   Curl_he2ai() function)) */
 #define CURLRES_ADDRINFO_COPY
 #endif
-#endif /* IPv4-only */
+#endif /* IPv4/ares-only */
 
 #ifndef CURLRES_ASYNCH
 #define CURLRES_SYNCH
@@ -86,6 +87,8 @@
 #define CURL_ASYNC_SUCCESS ARES_SUCCESS
 #else
 #define CURL_ASYNC_SUCCESS CURLE_OK
+#define ares_cancel(x) do {} while(0)
+#define ares_destroy(x) do {} while(0)
 #endif
 
 /*
@@ -97,25 +100,26 @@ typedef struct addrinfo Curl_addrinfo;
 /* OK, so some ipv4-only include tree probably have the addrinfo struct, but
    to work even on those that don't, we provide our own look-alike! */
 struct Curl_addrinfo {
-  int     ai_flags;
-  int     ai_family;
-  int     ai_socktype;
-  int     ai_protocol;
-  size_t  ai_addrlen;
-  struct sockaddr *ai_addr;
-  char   *ai_canonname;
+  int                   ai_flags;
+  int                   ai_family;
+  int                   ai_socktype;
+  int                   ai_protocol;
+  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;
 #endif
 
 struct addrinfo;
+struct hostent;
 struct SessionHandle;
 struct connectdata;
 
 void Curl_global_host_cache_init(void);
 void Curl_global_host_cache_dtor(void);
-curl_hash *Curl_global_host_cache_get(void);
+struct curl_hash *Curl_global_host_cache_get(void);
 
 #define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
 
@@ -137,7 +141,7 @@ struct Curl_dns_entry {
 #define CURLRESOLV_ERROR    -1
 #define CURLRESOLV_RESOLVED  0
 #define CURLRESOLV_PENDING   1
-int Curl_resolv(struct connectdata *conn, char *hostname,
+int Curl_resolv(struct connectdata *conn, const char *hostname,
                 int port, struct Curl_dns_entry **dnsentry);
 
 /*
@@ -153,7 +157,7 @@ bool Curl_ipvalid(struct SessionHandle *data);
  * of arguments
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp);
 
@@ -162,15 +166,19 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
 CURLcode Curl_wait_for_resolv(struct connectdata *conn,
                               struct Curl_dns_entry **dnsentry);
 
-/* Curl_fdset() is a generic function that exists in multiple versions
-   depending on what name resolve technology we've built to use. The function
-   is called from the curl_multi_fdset() function */
-CURLcode Curl_fdset(struct connectdata *conn,
-                    fd_set *read_fd_set,
-                    fd_set *write_fd_set,
-                    int *max_fdp);
+/* Curl_resolv_getsock() is a generic function that exists in multiple
+   versions depending on what name resolve technology we've built to use. The
+   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_resolv_getsock(struct connectdata *conn, curl_socket_t *sock,
+                        int numsocks);
+
 /* unlock a previously resolved dns entry */
-void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
+void Curl_resolv_unlock(struct SessionHandle *data,
+                        struct Curl_dns_entry *dns);
 
 /* for debugging purposes only: */
 void Curl_scan_cache_used(void *user, void *ptr);
@@ -179,7 +187,7 @@ void Curl_scan_cache_used(void *user, void *ptr);
 void Curl_freeaddrinfo(Curl_addrinfo *freeaddr);
 
 /* make a new dns cache and return the handle */
-curl_hash *Curl_mk_dnscache(void);
+struct curl_hash *Curl_mk_dnscache(void);
 
 /* prune old entries from the DNS cache */
 void Curl_hostcache_prune(struct SessionHandle *data);
@@ -190,41 +198,42 @@ int Curl_num_addresses (const Curl_addrinfo *addr);
 #ifdef CURLDEBUG
 void curl_dofreeaddrinfo(struct addrinfo *freethis,
                          int line, const char *source);
-int curl_dogetaddrinfo(char *hostname, char *service,
+int curl_dogetaddrinfo(const char *hostname, const char *service,
                        struct addrinfo *hints,
                        struct addrinfo **result,
                        int line, const char *source);
-int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
-                       char *host, size_t hostlen,
-                       char *serv, size_t servlen, int flags,
+#ifdef 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
+#endif
 
 /* This is the callback function that is used when we build with asynch
    resolve, ipv4 */
-void Curl_addrinfo4_callback(void *arg,
-                            int status,
-                            struct hostent *hostent);
+CURLcode Curl_addrinfo4_callback(void *arg,
+                                 int status,
+                                 struct hostent *hostent);
 /* This is the callback function that is used when we build with asynch
    resolve, ipv6 */
-void Curl_addrinfo6_callback(void *arg,
-                            int status,
-                            struct addrinfo *ai);
+CURLcode Curl_addrinfo6_callback(void *arg,
+                                 int status,
+                                 struct addrinfo *ai);
 
 
-/* [ipv4 only] Creates a Curl_addrinfo struct from a numerical-only IP
+/* [ipv4/ares only] Creates a Curl_addrinfo struct from a numerical-only IP
    address */
-Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port);
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port);
 
-/* [ipv4 only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain
+/* [ipv4/ares only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain
    and returns it */
-Curl_addrinfo *Curl_he2ai(struct hostent *, int port);
-
-/* relocate a hostent struct */
-void Curl_hostent_relocate(struct hostent *h, long offset);
+Curl_addrinfo *Curl_he2ai(const struct hostent *, int port);
 
 /* Clone a Curl_addrinfo struct, works protocol independently */
-Curl_addrinfo *Curl_addrinfo_copy(void *orig, int port);
+Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port);
 
 /*
  * Curl_printable_address() returns a printable version of the 1st address
@@ -241,7 +250,14 @@ const char *Curl_printable_address(const Curl_addrinfo *ip,
  */
 struct Curl_dns_entry *
 Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
-                char *hostname, int port);
+                const char *hostname, int port);
+
+/*
+ * Curl_destroy_thread_data() cleans up async resolver data.
+ * Complementary of ares_destroy.
+ */
+struct Curl_async; /* forward-declaration */
+void Curl_destroy_thread_data(struct Curl_async *async);
 
 #ifndef INADDR_NONE
 #define CURL_INADDR_NONE (in_addr_t) ~0

+ 53 - 120
Utilities/cmcurl/hostip4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,11 +26,9 @@
 #include <string.h>
 #include <errno.h>
 
-#define _REENTRANT
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,21 +55,15 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #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"
@@ -79,6 +71,7 @@
 #include "share.h"
 #include "strerror.h"
 #include "url.h"
+#include "inet_pton.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -87,7 +80,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -95,23 +88,6 @@
  * Only for plain-ipv4 builds
  **********************************************************************/
 #ifdef CURLRES_IPV4 /* plain ipv4 code coming up */
-
-/*
- * This is a function for freeing name information in a protocol independent
- * way.
- */
-void Curl_freeaddrinfo(Curl_addrinfo *ai)
-{
-  Curl_addrinfo *next;
-
-  /* walk over the list and free all entries */
-  while(ai) {
-    next = ai->ai_next;
-    free(ai);
-    ai = next;
-  }
-}
-
 /*
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
@@ -125,57 +101,13 @@ bool Curl_ipvalid(struct SessionHandle *data)
   return TRUE; /* OK, proceed */
 }
 
-struct namebuf {
-  struct hostent hostentry;
-  char *h_addr_list[2];
-  struct in_addr addrentry;
-  char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
-};
-
-/*
- * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
- * together with a pointer to the string version of the address, and it
- * returns a Curl_addrinfo chain filled in correctly with information for this
- * address/host.
- *
- * The input parameters ARE NOT checked for validity but they are expected
- * to have been checked already when this is called.
- */
-Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port)
-{
-  Curl_addrinfo *ai;
-  struct hostent *h;
-  struct in_addr *addrentry;
-  struct namebuf buffer;
-  struct namebuf *buf = &buffer;
-
-  h = &buf->hostentry;
-  h->h_addr_list = &buf->h_addr_list[0];
-  addrentry = &buf->addrentry;
-  addrentry->s_addr = num;
-  h->h_addr_list[0] = (char*)addrentry;
-  h->h_addr_list[1] = NULL;
-  h->h_addrtype = AF_INET;
-  h->h_length = sizeof(*addrentry);
-  h->h_name = &buf->h_name[0];
-  h->h_aliases = NULL;
-
-  /* Now store the dotted version of the address */
-  snprintf((char*)(h->h_name), 16, "%s", hostname);
-
-  ai = Curl_he2ai(h, port);
-
-  return ai;
-}
-
 #ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
 
 /*
  * Curl_getaddrinfo() - the ipv4 synchronous version.
  *
- * The original code to this function was once stolen from the Dancer source
- * code, written by Bjorn Reese, it has since been patched and modified
- * considerably.
+ * 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
@@ -188,7 +120,7 @@ Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port)
  *
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp)
 {
@@ -202,11 +134,9 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
   *waitp = 0; /* don't wait, we act synchronously */
 
-  in=inet_addr(hostname);
-  if (in != CURL_INADDR_NONE) {
+  if(1 == Curl_inet_pton(AF_INET, hostname, &in))
     /* This is a dotted IP address 123.123.123.123-style */
     return Curl_ip2addr(in, hostname, port);
-  }
 
 #if defined(HAVE_GETHOSTBYNAME_R)
   /*
@@ -370,55 +300,55 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 }
 
 #endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV4 */
 
 /*
  * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
  * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
  * stacks, but for all hosts and environments.
+ *
+ *   Curl_addrinfo defined in "lib/hostip.h"
+ *
+ *     struct Curl_addrinfo {
+ *       int                   ai_flags;
+ *       int                   ai_family;
+ *       int                   ai_socktype;
+ *       int                   ai_protocol;
+ *       socklen_t             ai_addrlen;   * Follow rfc3493 struct addrinfo *
+ *       char                 *ai_canonname;
+ *       struct sockaddr      *ai_addr;
+ *       struct Curl_addrinfo *ai_next;
+ *     };
+ *
+ *   hostent defined in <netdb.h>
+ *
+ *     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]
+ */
 
-struct Curl_addrinfo {
-  int     ai_flags;
-  int     ai_family;
-  int     ai_socktype;
-  int     ai_protocol;
-  size_t  ai_addrlen;
-  struct sockaddr *ai_addr;
-  char   *ai_canonname;
-  struct addrinfo *ai_next;
-};
-
-struct hostent {
-  char    *h_name;        * official name of host *
-  char    **h_aliases;    * alias list *
-  int     h_addrtype;     * host address type *
-  int     h_length;       * length of address *
-  char    **h_addr_list;  * list of addresses *
-}
-#define h_addr  h_addr_list[0]  * for backward compatibility *
-
-*/
-
-Curl_addrinfo *Curl_he2ai(struct hostent *he, int port)
+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;
   int i;
-
-  union {
-    struct in_addr *addr;
-    char* list;
-  } curr;
-  union {
-    struct sockaddr_in* addr_in;
-    struct sockaddr* addr;
-  } address;
+  struct in_addr *curr;
 
   if(!he)
     /* no input == no output! */
     return NULL;
 
-  for(i=0; (curr.list = he->h_addr_list[i]); i++) {
+  for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) {
 
     ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in));
 
@@ -434,23 +364,26 @@ Curl_addrinfo *Curl_he2ai(struct hostent *he, int port)
       prevai->ai_next = ai;
 
     ai->ai_family = AF_INET;              /* we only support this */
-    ai->ai_socktype = SOCK_STREAM;        /* we only support this */
+
+    /* 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 = sizeof(struct sockaddr_in);
     /* make the ai_addr point to the address immediately following this struct
        and use that area to store the address */
-    ai->ai_addr = (struct sockaddr *) (ai + 1);
+    ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo));
 
     /* leave the rest of the struct filled with zero */
 
-    address.addr = ai->ai_addr; /* storage area for this info */
+    addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */
 
-    memcpy((char *)&(address.addr_in->sin_addr), curr.addr, sizeof(struct in_addr));
-    address.addr_in->sin_family = he->h_addrtype;
-    address.addr_in->sin_port = htons((unsigned short)port);
+    memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr));
+    addr->sin_family = he->h_addrtype;
+    addr->sin_port = htons((unsigned short)port);
 
     prevai = ai;
   }
   return firstai;
 }
 
-#endif /* CURLRES_IPV4 */

+ 83 - 40
Utilities/cmcurl/hostip6.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,13 +24,10 @@
 #include "setup.h"
 
 #include <string.h>
-#include <errno.h>
-
-#define _REENTRANT
 
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,21 +54,15 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #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"
@@ -79,6 +70,8 @@
 #include "share.h"
 #include "strerror.h"
 #include "url.h"
+#include "inet_pton.h"
+#include "connect.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -87,7 +80,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -95,6 +88,7 @@
  * Only for ipv6-enabled builds
  **********************************************************************/
 #ifdef CURLRES_IPV6
+#ifndef CURLRES_ARES
 /*
  * This is a wrapper function for freeing name information in a protocol
  * independent way. This takes care of using the appropriate underlaying
@@ -111,19 +105,20 @@ void Curl_freeaddrinfo(Curl_addrinfo *p)
  * address. But this is an ipv6 build and then we don't copy the address, we
  * just return the same pointer!
  */
-Curl_addrinfo *Curl_addrinfo_copy(void *source, int port)
+Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port)
 {
   (void) port;
-  return source;
+  return (Curl_addrinfo*)orig;
 }
-#endif
+#endif  /* CURLRES_ASYNCH */
+#endif  /* CURLRES_ARES */
 
 #ifdef CURLDEBUG
 /* These are 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 wanna include in memdebug.c
  */
-int curl_dogetaddrinfo(char *hostname, char *service,
+int curl_dogetaddrinfo(const char *hostname, const char *service,
                        struct addrinfo *hints,
                        struct addrinfo **result,
                        int line, const char *source)
@@ -143,12 +138,22 @@ int curl_dogetaddrinfo(char *hostname, char *service,
   return res;
 }
 
-int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
-                       char *host, size_t hostlen,
-                       char *serv, size_t servlen, int flags,
+/*
+ * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
+ * (ignoring the fact c-ares doesn't return 'serv').
+ */
+#ifdef 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)
 {
-  int res=(getnameinfo)(sa, salen, host, hostlen, serv, servlen, flags);
+  int res = (getnameinfo)(sa, salen,
+                          host, hostlen,
+                          serv, servlen,
+                          flags);
   if(0 == res) {
     /* success */
     if(logfile)
@@ -162,6 +167,7 @@ int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
   }
   return res;
 }
+#endif
 
 void curl_dofreeaddrinfo(struct addrinfo *freethis,
                          int line, const char *source)
@@ -171,8 +177,7 @@ void curl_dofreeaddrinfo(struct addrinfo *freethis,
     fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
             source, line, (void *)freethis);
 }
-
-#endif
+#endif  /* CURLDEBUG */
 
 /*
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
@@ -191,9 +196,30 @@ bool Curl_ipvalid(struct SessionHandle *data)
   return TRUE;
 }
 
-#ifndef USE_THREADING_GETADDRINFO
+#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES)
+
+#ifdef DEBUG_ADDRINFO
+static void dump_addrinfo(struct connectdata *conn, const struct 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 : "<none>");
+    if (Curl_printable_address(ai, buf, sizeof(buf)))
+      printf("%s\n", buf);
+    else
+      printf("failed; %s\n", Curl_strerror(conn, Curl_sockerrno()));
+  }
+}
+#else
+#define dump_addrinfo(x,y)
+#endif
+
 /*
- * Curl_getaddrinfo() when built ipv6-enabled (non-threading version).
+ * 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
@@ -201,13 +227,15 @@ bool Curl_ipvalid(struct SessionHandle *data)
  * Curl_freeaddrinfo(), nothing else.
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp)
 {
   struct addrinfo hints, *res;
   int error;
   char sbuf[NI_MAXSERV];
+  char *sbufptr = NULL;
+  char addrbuf[128];
   curl_socket_t s;
   int pf;
   struct SessionHandle *data = conn->data;
@@ -216,7 +244,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
   /* see if we have an IPv6 stack */
   s = socket(PF_INET6, SOCK_DGRAM, 0);
-  if (s < 0) {
+  if (s == CURL_SOCKET_BAD) {
     /* Some non-IPv6 stacks have been found to make very slow name resolves
      * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
      * the stack seems to be a non-ipv6 one. */
@@ -244,20 +272,35 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
       break;
     }
   }
- 
+
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_flags = AI_CANONNAME;
-  snprintf(sbuf, sizeof(sbuf), "%d", port);
-  error = getaddrinfo(hostname, sbuf, &hints, &res);
+  hints.ai_socktype = conn->socktype;
+
+  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;
+  }
+#if 0 /* removed nov 8 2005 before 7.15.1 */
+  else
+    hints.ai_flags = AI_CANONNAME;
+#endif
+
+  if(port) {
+    snprintf(sbuf, sizeof(sbuf), "%d", port);
+    sbufptr=sbuf;
+  }
+  error = getaddrinfo(hostname, sbufptr, &hints, &res);
   if (error) {
-    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);    
+    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
     return NULL;
   }
 
+  dump_addrinfo(conn, res);
+
   return res;
 }
-#endif /* USE_THREADING_GETADDRINFO */
+#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */
 #endif /* ipv6 */
 

+ 16 - 27
Utilities/cmcurl/hostsyn.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,13 +24,10 @@
 #include "setup.h"
 
 #include <string.h>
-#include <errno.h>
-
-#define _REENTRANT
 
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,21 +54,15 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #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"
@@ -87,7 +78,7 @@
 #include "inet_ntoa_r.h"
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -133,17 +124,15 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
  * It is present here to keep #ifdefs out from multi.c
  */
 
-CURLcode Curl_fdset(struct connectdata *conn,
-                    fd_set *read_fd_set,
-                    fd_set *write_fd_set,
-                    int *max_fdp)
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *sock,
+                        int numsocks)
 {
   (void)conn;
-  (void)read_fd_set;
-  (void)write_fd_set;
-  (void)max_fdp;
+  (void)sock;
+  (void)numsocks;
 
-  return CURLE_OK;
+  return 0; /* no bits since we don't use any socks */
 }
 
 #endif /* truly sync */

+ 378 - 89
Utilities/cmcurl/hostthre.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,11 +26,9 @@
 #include <string.h>
 #include <errno.h>
 
-#define _REENTRANT
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#ifdef NEED_MALLOC_H
 #include <malloc.h>
-#else
+#endif
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -57,13 +55,12 @@
 #include <inet.h>
 #include <stdlib.h>
 #endif
-#endif
 
 #ifdef HAVE_SETJMP_H
 #include <setjmp.h>
 #endif
 
-#ifdef WIN32
+#ifdef HAVE_PROCESS_H
 #include <process.h>
 #endif
 
@@ -79,16 +76,21 @@
 #include "share.h"
 #include "strerror.h"
 #include "url.h"
+#include "multiif.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 
 #include "inet_ntop.h"
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
+#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
+#pragma message ("No _beginthreadex() available in this RTL")
+#endif
+
 /***********************************************************************
  * Only for Windows threaded name resolves builds
  **********************************************************************/
@@ -154,13 +156,126 @@ struct thread_data {
   HANDLE thread_hnd;
   unsigned thread_id;
   DWORD  thread_status;
-  curl_socket_t dummy_sock;   /* dummy for Curl_fdset() */
-  FILE *stderr_file;
+  curl_socket_t dummy_sock;   /* dummy for Curl_resolv_fdset() */
+  HANDLE mutex_waiting;  /* marks that we are still waiting for a resolve */
+  HANDLE event_resolved; /* marks that the thread obtained the information */
+  HANDLE event_thread_started; /* marks that the thread has initialized and
+                                  started */
+  HANDLE mutex_terminate; /* serializes access to flag_terminate */
+  HANDLE event_terminate; /* flag for thread to terminate instead of calling
+                             callbacks */
 #ifdef CURLRES_IPV6
   struct addrinfo hints;
 #endif
 };
 
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+  HANDLE mutex_waiting;   /* thread_data.mutex_waiting duplicate */
+  HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
+  HANDLE event_terminate; /* thread_data.event_terminate duplicate */
+  char * hostname;        /* hostname to resolve, Curl_async.hostname
+                             duplicate */
+};
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data * tsd)
+{
+  if (tsd->hostname) {
+    free(tsd->hostname);
+    tsd->hostname = NULL;
+  }
+  if (tsd->event_terminate) {
+    CloseHandle(tsd->event_terminate);
+    tsd->event_terminate = NULL;
+  }
+  if (tsd->mutex_terminate) {
+    CloseHandle(tsd->mutex_terminate);
+    tsd->mutex_terminate = NULL;
+  }
+  if (tsd->mutex_waiting) {
+    CloseHandle(tsd->mutex_waiting);
+    tsd->mutex_waiting = NULL;
+  }
+}
+
+/* Initialize resolver thread synchronization data */
+static
+BOOL init_thread_sync_data(struct thread_data * td,
+                           char * hostname,
+                           struct thread_sync_data * tsd)
+{
+  HANDLE curr_proc = GetCurrentProcess();
+
+  memset(tsd, 0, sizeof(*tsd));
+  if (!DuplicateHandle(curr_proc, td->mutex_waiting,
+                       curr_proc, &tsd->mutex_waiting, 0, FALSE,
+                       DUPLICATE_SAME_ACCESS)) {
+    /* failed to duplicate the mutex, no point in continuing */
+    destroy_thread_sync_data(tsd);
+    return FALSE;
+  }
+  if (!DuplicateHandle(curr_proc, td->mutex_terminate,
+                       curr_proc, &tsd->mutex_terminate, 0, FALSE,
+                       DUPLICATE_SAME_ACCESS)) {
+    /* failed to duplicate the mutex, no point in continuing */
+    destroy_thread_sync_data(tsd);
+    return FALSE;
+  }
+  if (!DuplicateHandle(curr_proc, td->event_terminate,
+                       curr_proc, &tsd->event_terminate, 0, FALSE,
+                       DUPLICATE_SAME_ACCESS)) {
+    /* failed to duplicate the event, no point in continuing */
+    destroy_thread_sync_data(tsd);
+    return FALSE;
+  }
+  /* Copying hostname string because original can be destroyed by parent
+   * thread during gethostbyname execution.
+   */
+  tsd->hostname = strdup(hostname);
+  if (!tsd->hostname) {
+    /* Memory allocation failed */
+    destroy_thread_sync_data(tsd);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/* acquire resolver thread synchronization */
+static
+BOOL acquire_thread_sync(struct thread_sync_data * tsd)
+{
+  /* is the thread initiator still waiting for us ? */
+  if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
+    /* yes, it is */
+
+    /* Waiting access to event_terminate */
+    if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
+      /* Something went wrong - now just ignoring */
+    }
+    else {
+      if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
+        /* Parent thread signaled us to terminate.
+         * This means that all data in conn->async is now destroyed
+         * and we cannot use it.
+         */
+      }
+      else {
+        return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
+
+/* release resolver thread synchronization */
+static
+void release_thread_sync(struct thread_sync_data * tsd)
+{
+  ReleaseMutex(tsd->mutex_terminate);
+}
+
 #if defined(CURLRES_IPV4)
 /*
  * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
@@ -174,26 +289,45 @@ static unsigned __stdcall gethostbyname_thread (void *arg)
   struct connectdata *conn = (struct connectdata*) arg;
   struct thread_data *td = (struct thread_data*) conn->async.os_specific;
   struct hostent *he;
-  int    rc;
+  int    rc = 0;
 
-  /* Sharing the same _iob[] element with our parent thread should
-   * hopefully make printouts synchronised. I'm not sure it works
-   * with a static runtime lib (MSVC's libc.lib).
+  /* Duplicate the passed mutex and event handles.
+   * This allows us to use it even after the container gets destroyed
+   * due to a resolver timeout.
    */
-  *stderr = *td->stderr_file;
+  struct thread_sync_data tsd = { 0,0,0,NULL };
+  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
+    /* thread synchronization data initialization failed */
+    return (unsigned)-1;
+  }
 
   WSASetLastError (conn->async.status = NO_DATA); /* pending status */
-  he = gethostbyname (conn->async.hostname);
-  if (he) {
-    Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
-    rc = 1;
-  }
-  else {
-    Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
-    rc = 0;
+
+  /* Signaling that we have initialized all copies of data and handles we
+     need */
+  SetEvent(td->event_thread_started);
+
+  he = gethostbyname (tsd.hostname);
+
+  /* is parent thread waiting for us and are we able to access conn members? */
+  if (acquire_thread_sync(&tsd)) {
+    /* Mark that we have obtained the information, and that we are calling
+     * back with it. */
+    SetEvent(td->event_resolved);
+    if (he) {
+      rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
+    }
+    else {
+      rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
+    }
+    TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
+           he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
+    release_thread_sync(&tsd);
   }
-  TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
-         he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
+
+  /* clean up */
+  destroy_thread_sync_data(&tsd);
+
   return (rc);
   /* An implicit _endthreadex() here */
 }
@@ -214,44 +348,99 @@ static unsigned __stdcall getaddrinfo_thread (void *arg)
   struct addrinfo    *res;
   char   service [NI_MAXSERV];
   int    rc;
+  struct addrinfo hints = td->hints;
 
-  *stderr = *td->stderr_file;
+  /* Duplicate the passed mutex handle.
+   * This allows us to use it even after the container gets destroyed
+   * due to a resolver timeout.
+   */
+  struct thread_sync_data tsd = { 0,0,0,NULL };
+  if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
+    /* thread synchronization data initialization failed */
+    return -1;
+  }
 
   itoa(conn->async.port, service, 10);
 
   WSASetLastError(conn->async.status = NO_DATA); /* pending status */
 
-  rc = getaddrinfo(conn->async.hostname, service, &td->hints, &res);
+  /* Signaling that we have initialized all copies of data and handles we
+     need */
+  SetEvent(td->event_thread_started);
 
-  if (rc == 0) {
+  rc = getaddrinfo(tsd.hostname, service, &hints, &res);
+
+  /* is parent thread waiting for us and are we able to access conn members? */
+  if (acquire_thread_sync(&tsd)) {
+    /* Mark that we have obtained the information, and that we are calling
+       back with it. */
+    SetEvent(td->event_resolved);
+
+    if (rc == 0) {
 #ifdef DEBUG_THREADING_GETADDRINFO
-    dump_addrinfo (conn, res);
+      dump_addrinfo (conn, res);
 #endif
-    Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
-  }
-  else {
-    Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
-    TRACE(("Winsock-error %d, no address\n", conn->async.status));
+      rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
+    }
+    else {
+      rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
+      TRACE(("Winsock-error %d, no address\n", conn->async.status));
+    }
+    release_thread_sync(&tsd);
   }
+
+  /* clean up */
+  destroy_thread_sync_data(&tsd);
+
   return (rc);
   /* An implicit _endthreadex() here */
 }
 #endif
 
 /*
- * destroy_thread_data() cleans up async resolver data.
+ * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
  * Complementary of ares_destroy.
  */
-static void destroy_thread_data (struct Curl_async *async)
+void Curl_destroy_thread_data (struct Curl_async *async)
 {
   if (async->hostname)
     free(async->hostname);
 
   if (async->os_specific) {
-    curl_socket_t sock = ((const struct thread_data*)async->os_specific)->dummy_sock;
+    struct thread_data *td = (struct thread_data*) async->os_specific;
+    curl_socket_t sock = td->dummy_sock;
+
+    if (td->mutex_terminate && td->event_terminate) {
+      /* Signaling resolver thread to terminate */
+      if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
+        SetEvent(td->event_terminate);
+        ReleaseMutex(td->mutex_terminate);
+      }
+      else {
+        /* Something went wrong - just ignoring it */
+      }
+    }
+
+    if (td->mutex_terminate)
+      CloseHandle(td->mutex_terminate);
+    if (td->event_terminate)
+      CloseHandle(td->event_terminate);
+    if (td->event_thread_started)
+      CloseHandle(td->event_thread_started);
 
     if (sock != CURL_SOCKET_BAD)
       sclose(sock);
+
+    /* destroy the synchronization objects */
+    if (td->mutex_waiting)
+      CloseHandle(td->mutex_waiting);
+    td->mutex_waiting = NULL;
+    if (td->event_resolved)
+      CloseHandle(td->event_resolved);
+
+    if (td->thread_hnd)
+      CloseHandle(td->thread_hnd);
+
     free(async->os_specific);
   }
   async->hostname = NULL;
@@ -269,6 +458,7 @@ static bool init_resolve_thread (struct connectdata *conn,
                                  const Curl_addrinfo *hints)
 {
   struct thread_data *td = calloc(sizeof(*td), 1);
+  HANDLE thread_and_event[2] = {0};
 
   if (!td) {
     SetLastError(ENOMEM);
@@ -288,11 +478,62 @@ static bool init_resolve_thread (struct connectdata *conn,
   conn->async.status = 0;
   conn->async.dns = NULL;
   conn->async.os_specific = (void*) td;
-
   td->dummy_sock = CURL_SOCKET_BAD;
-  td->stderr_file = stderr;
+
+  /* Create the mutex used to inform the resolver thread that we're
+   * still waiting, and take initial ownership.
+   */
+  td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
+  if (td->mutex_waiting == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SetLastError(EAGAIN);
+    return FALSE;
+  }
+
+  /* Create the event that the thread uses to inform us that it's
+   * done resolving. Do not signal it.
+   */
+  td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
+  if (td->event_resolved == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SetLastError(EAGAIN);
+    return FALSE;
+  }
+  /* Create the mutex used to serialize access to event_terminated
+   * between us and resolver thread.
+   */
+  td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
+  if (td->mutex_terminate == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SetLastError(EAGAIN);
+    return FALSE;
+  }
+  /* Create the event used to signal thread that it should terminate.
+   */
+  td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
+  if (td->event_terminate == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SetLastError(EAGAIN);
+    return FALSE;
+  }
+  /* Create the event used by thread to inform it has initialized its own data.
+   */
+  td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
+  if (td->event_thread_started == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SetLastError(EAGAIN);
+    return FALSE;
+  }
+
+#ifdef _WIN32_WCE
+  td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
+                                         (LPTHREAD_START_ROUTINE) THREAD_FUNC,
+                                         conn, 0, &td->thread_id);
+#else
   td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
                                            conn, 0, &td->thread_id);
+#endif
+
 #ifdef CURLRES_IPV6
   curlassert(hints);
   td->hints = *hints;
@@ -301,14 +542,30 @@ static bool init_resolve_thread (struct connectdata *conn,
 #endif
 
   if (!td->thread_hnd) {
+#ifdef _WIN32_WCE
+     TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn,GetLastError())));
+#else
      SetLastError(errno);
      TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
-     destroy_thread_data(&conn->async);
+#endif
+     Curl_destroy_thread_data(&conn->async);
      return FALSE;
   }
-  /* This socket is only to keep Curl_fdset() and select() happy; should never
-   * become signalled for read/write since it's unbound but Windows needs
-   * atleast 1 socket in select().
+  /* Waiting until the thread will initialize its data or it will exit due errors.
+   */
+  thread_and_event[0] = td->thread_hnd;
+  thread_and_event[1] = td->event_thread_started;
+  if (WaitForMultipleObjects(sizeof(thread_and_event) /
+                             sizeof(thread_and_event[0]),
+                             (const HANDLE*)thread_and_event, FALSE,
+                             INFINITE) == WAIT_FAILED) {
+    /* The resolver thread has been created,
+     * most probably it works now - ignoring this "minor" error
+     */
+  }
+  /* This socket is only to keep Curl_resolv_fdset() and select() happy;
+   * should never become signalled for read/write since it's unbound but
+   * Windows needs atleast 1 socket in select().
    */
   td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
   return TRUE;
@@ -341,28 +598,49 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
     conn->data->set.timeout ? conn->data->set.timeout :
     CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
   ticks = GetTickCount();
-  (void)ticks;
-
-  status = WaitForSingleObject(td->thread_hnd, 1000UL*timeout);
-  if (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) {
-     /* Thread finished before timeout; propagate Winsock error to this thread.
-      * 'conn->async.done = TRUE' is set in Curl_addrinfo4/6_callback().
-      */
-     WSASetLastError(conn->async.status);
-     GetExitCodeThread(td->thread_hnd, &td->thread_status);
-     TRACE(("%s() status %lu, thread retval %lu, ",
-            THREAD_NAME, status, td->thread_status));
+
+  /* wait for the thread to resolve the name */
+  status = WaitForSingleObject(td->event_resolved, 1000UL*timeout);
+
+  /* mark that we are now done waiting */
+  ReleaseMutex(td->mutex_waiting);
+
+  /* close our handle to the mutex, no point in hanging on to it */
+  CloseHandle(td->mutex_waiting);
+  td->mutex_waiting = NULL;
+
+  /* close the event handle, it's useless now */
+  CloseHandle(td->event_resolved);
+  td->event_resolved = NULL;
+
+  /* has the resolver thread succeeded in resolving our query ? */
+  if (status == WAIT_OBJECT_0) {
+    /* wait for the thread to exit, it's in the callback sequence */
+    if (WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
+      TerminateThread(td->thread_hnd, 0);
+      conn->async.done = TRUE;
+      td->thread_status = (DWORD)-1;
+      TRACE(("%s() thread stuck?!, ", THREAD_NAME));
+    }
+    else {
+      /* Thread finished before timeout; propagate Winsock error to this
+       * thread.  'conn->async.done = TRUE' is set in
+       * Curl_addrinfo4/6_callback().
+       */
+      WSASetLastError(conn->async.status);
+      GetExitCodeThread(td->thread_hnd, &td->thread_status);
+      TRACE(("%s() status %lu, thread retval %lu, ",
+             THREAD_NAME, status, td->thread_status));
+    }
   }
   else {
-     conn->async.done = TRUE;
-     td->thread_status = (DWORD)-1;
-     TRACE(("%s() timeout, ", THREAD_NAME));
+    conn->async.done = TRUE;
+    td->thread_status = (DWORD)-1;
+    TRACE(("%s() timeout, ", THREAD_NAME));
   }
 
   TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
 
-  CloseHandle(td->thread_hnd);
-
   if(entry)
     *entry = conn->async.dns;
 
@@ -370,25 +648,34 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
 
   if (!conn->async.dns) {
     /* a name was not resolved */
-    if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
-      failf(data, "Resolving host timed out: %s", conn->host.name);
-      rc = CURLE_OPERATION_TIMEDOUT;
+    if (td->thread_status == CURLE_OUT_OF_MEMORY) {
+      rc = CURLE_OUT_OF_MEMORY;
+      failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
     }
     else if(conn->async.done) {
-      failf(data, "Could not resolve host: %s; %s",
-            conn->host.name, Curl_strerror(conn,conn->async.status));
-      rc = CURLE_COULDNT_RESOLVE_HOST;
+      if(conn->bits.httpproxy) {
+        failf(data, "Could not resolve proxy: %s; %s",
+              conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
+        rc = CURLE_COULDNT_RESOLVE_PROXY;
+      }
+      else {
+        failf(data, "Could not resolve host: %s; %s",
+              conn->host.name, Curl_strerror(conn, conn->async.status));
+        rc = CURLE_COULDNT_RESOLVE_HOST;
+      }
+    }
+    else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
+      failf(data, "Resolving host timed out: %s", conn->host.name);
+      rc = CURLE_OPERATION_TIMEDOUT;
     }
     else
       rc = CURLE_OPERATION_TIMEDOUT;
   }
 
-  destroy_thread_data(&conn->async);
+  Curl_destroy_thread_data(&conn->async);
 
-  if(CURLE_OK != rc)
-    /* close the connection, since we must not return failure from here
-       without cleaning up this connection properly */
-    Curl_disconnect(conn);
+  if(!conn->async.dns)
+    conn->bits.close = TRUE;
 
   return (rc);
 }
@@ -405,7 +692,7 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
 
   if (conn->async.done) {
     /* we're done */
-    destroy_thread_data(&conn->async);
+    Curl_destroy_thread_data(&conn->async);
     if (!conn->async.dns) {
       TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
       return CURLE_COULDNT_RESOLVE_HOST;
@@ -413,25 +700,25 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
     *entry = conn->async.dns;
     TRACE(("resolved okay, dns %p\n", *entry));
   }
-  else
-    TRACE(("not yet\n"));
   return CURLE_OK;
 }
 
-CURLcode Curl_fdset(struct connectdata *conn,
-                    fd_set *read_fd_set,
-                    fd_set *write_fd_set,
-                    int *max_fdp)
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
 {
   const struct thread_data *td =
     (const struct thread_data *) conn->async.os_specific;
 
   if (td && td->dummy_sock != CURL_SOCKET_BAD) {
-    FD_SET(td->dummy_sock,write_fd_set);
-    *max_fdp = td->dummy_sock;
+    if(numsocks) {
+      /* return one socket waiting for writable, even though this is just
+         a dummy */
+      socks[0] = td->dummy_sock;
+      return GETSOCK_WRITESOCK(0);
+    }
   }
-  (void) read_fd_set;
-  return CURLE_OK;
+  return 0;
 }
 
 #ifdef CURLRES_IPV4
@@ -439,11 +726,11 @@ CURLcode Curl_fdset(struct connectdata *conn,
  * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp)
 {
-  struct hostent *h;
+  struct hostent *h = NULL;
   struct SessionHandle *data = conn->data;
   in_addr_t in;
 
@@ -461,8 +748,8 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   }
 
   /* fall-back to blocking version */
-  infof(data, "init_resolve_thread() failed for %s; code %lu\n",
-        hostname, GetLastError());
+  infof(data, "init_resolve_thread() failed for %s; %s\n",
+        hostname, Curl_strerror(conn,GetLastError()));
 
   h = gethostbyname(hostname);
   if (!h) {
@@ -479,7 +766,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
  * Curl_getaddrinfo() - for Windows threading IPv6 enabled
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                char *hostname,
+                                const char *hostname,
                                 int port,
                                 int *waitp)
 {
@@ -525,8 +812,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_socktype = conn->socktype;
+#if 0 /* removed nov 8 2005 before 7.15.1 */
   hints.ai_flags = AI_CANONNAME;
+#endif
   itoa(port, sbuf, 10);
 
   /* fire up a new resolver thread! */
@@ -536,8 +825,8 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   }
 
   /* fall-back to blocking version */
-  infof(data, "init_resolve_thread() failed for %s; code %lu\n",
-        hostname, GetLastError());
+  infof(data, "init_resolve_thread() failed for %s; %s\n",
+        hostname, Curl_strerror(conn,GetLastError()));
 
   error = getaddrinfo(hostname, sbuf, &hints, &res);
   if (error) {

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 422 - 183
Utilities/cmcurl/http.c


+ 31 - 7
Utilities/cmcurl/http.h

@@ -8,7 +8,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -29,14 +29,18 @@ bool Curl_compareheader(char *headerline,     /* line to check */
                         const char *content); /* content string to find */
 
 /* ftp can use this as well */
-CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
-                                     int tunnelsocket,
-                                     char *hostname, int remote_port);
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+                           int tunnelsocket,
+                           char *hostname, int remote_port);
 
 /* protocol-specific functions set up to be called by the main engine */
-CURLcode Curl_http(struct connectdata *conn);
-CURLcode Curl_http_done(struct connectdata *, CURLcode);
-CURLcode Curl_http_connect(struct connectdata *conn);
+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);
+CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
+int Curl_https_getsock(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks);
 
 /* The following functions are defined in http_chunks.c */
 void Curl_httpchunk_init(struct connectdata *conn);
@@ -57,5 +61,25 @@ int Curl_http_should_fail(struct connectdata *conn);
    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 uncondtionally 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
+
+#ifndef TINY_INITIAL_POST_SIZE
+#define TINY_INITIAL_POST_SIZE 1024
+#endif
+
 #endif
 #endif

+ 125 - 29
Utilities/cmcurl/http_chunks.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -35,7 +35,8 @@
 
 #include "content_encoding.h"
 #include "http.h"
-#include "curl_memory.h"
+#include "memory.h"
+#include "easyif.h" /* for Curl_convert_to_network prototype */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -43,7 +44,7 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-/* 
+/*
  * Chunk format (simplified):
  *
  * <HEX SIZE>[ chunk extension ] CRLF
@@ -83,7 +84,7 @@
 
 void Curl_httpchunk_init(struct connectdata *conn)
 {
-  struct Curl_chunker *chunk = &conn->proto.http->chunk;
+  struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk;
   chunk->hexindex=0; /* start at 0 */
   chunk->dataleft=0; /* no data left yet! */
   chunk->state = CHUNK_HEX; /* we get hex first! */
@@ -96,6 +97,9 @@ void Curl_httpchunk_init(struct connectdata *conn)
  * 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,
@@ -103,8 +107,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
                               ssize_t *wrotep)
 {
   CURLcode result=CURLE_OK;
-  struct Curl_chunker *ch = &conn->proto.http->chunk;
-  struct Curl_transfer_keeper *k = &conn->keep;
+  struct SessionHandle *data = conn->data;
+  struct Curl_chunker *ch = &data->reqdata.proto.http->chunk;
+  struct Curl_transfer_keeper *k = &data->reqdata.keep;
   size_t piece;
   size_t length = (size_t)datalen;
   size_t *wrote = (size_t *)wrotep;
@@ -114,7 +119,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
   while(length) {
     switch(ch->state) {
     case CHUNK_HEX:
-      if(isxdigit((int)*datap)) {
+       /* Check for an ASCII hex digit.
+          We avoid the use of isxdigit to accommodate non-ASCII hosts. */
+       if((*datap >= 0x30 && *datap <= 0x39)    /* 0-9 */
+       || (*datap >= 0x41 && *datap <= 0x46)    /* A-F */
+       || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */
         if(ch->hexindex < MAXNUM_SIZE) {
           ch->hexbuffer[ch->hexindex] = *datap;
           datap++;
@@ -133,6 +142,17 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
         }
         /* length and datap are unmodified */
         ch->hexbuffer[ch->hexindex]=0;
+#ifdef CURL_DOES_CONVERSIONS
+        /* convert to host encoding before calling strtoul */
+        result = Curl_convert_from_network(conn->data,
+                                           ch->hexbuffer,
+                                           ch->hexindex);
+        if(result != CURLE_OK) {
+          /* Curl_convert_from_network calls failf if unsuccessful */
+          /* Treat it as a bad hex character */
+          return(CHUNKE_ILLEGAL_HEX);
+        }
+#endif /* CURL_DOES_CONVERSIONS */
         ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
         ch->state = CHUNK_POSTHEX;
       }
@@ -142,7 +162,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       /* In this state, we're waiting for CRLF to arrive. We support
          this to allow so called chunk-extensions to show up here
          before the CRLF comes. */
-      if(*datap == '\r')
+      if(*datap == 0x0d)
         ch->state = CHUNK_CR;
       length--;
       datap++;
@@ -150,13 +170,20 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
     case CHUNK_CR:
       /* waiting for the LF */
-      if(*datap == '\n') {
+      if(*datap == 0x0a) {
         /* we're now expecting data to come, unless size was zero! */
         if(0 == ch->datasize) {
-          ch->state = CHUNK_STOP; /* stop reading! */
-          if(1 == length) {
-            /* This was the final byte, return right now */
-            return CHUNKE_STOP;
+          if (conn->bits.trailerHdrPresent!=TRUE) {
+            /* No Trailer: header found - revert to original Curl processing */
+            ch->state = CHUNK_STOP;
+            if (1 == length) {
+               /* This is the final byte, return right now */
+               return CHUNKE_STOP;
+            }
+          }
+          else {
+            ch->state = CHUNK_TRAILER; /* attempt to read trailers */
+            conn->trlPos=0;
           }
         }
         else
@@ -179,26 +206,26 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
       /* Write the data portion available */
 #ifdef HAVE_LIBZ
-      switch (conn->keep.content_encoding) {
+      switch (data->reqdata.keep.content_encoding) {
         case IDENTITY:
 #endif
           if(!k->ignorebody)
-            result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
+            result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
                                        piece);
 #ifdef HAVE_LIBZ
           break;
 
-        case DEFLATE: 
-          /* update conn->keep.str to point to the chunk data. */
-          conn->keep.str = datap;
-          result = Curl_unencode_deflate_write(conn->data, &conn->keep,
+        case DEFLATE:
+          /* update data->reqdata.keep.str to point to the chunk data. */
+          data->reqdata.keep.str = datap;
+          result = Curl_unencode_deflate_write(conn, &data->reqdata.keep,
                                                (ssize_t)piece);
           break;
 
         case GZIP:
-          /* update conn->keep.str to point to the chunk data. */
-          conn->keep.str = datap;
-          result = Curl_unencode_gzip_write(conn->data, &conn->keep,
+          /* update data->reqdata.keep.str to point to the chunk data. */
+          data->reqdata.keep.str = datap;
+          result = Curl_unencode_gzip_write(conn, &data->reqdata.keep,
                                             (ssize_t)piece);
           break;
 
@@ -227,7 +254,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       break;
 
     case CHUNK_POSTCR:
-      if(*datap == '\r') {
+      if(*datap == 0x0d) {
         ch->state = CHUNK_POSTLF;
         datap++;
         length--;
@@ -237,7 +264,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       break;
 
     case CHUNK_POSTLF:
-      if(*datap == '\n') {
+      if(*datap == 0x0a) {
         /*
          * The last one before we go back to hex state and start all
          * over.
@@ -250,6 +277,75 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
         return CHUNKE_BAD_CHUNK;
       break;
 
+    case CHUNK_TRAILER:
+      /* conn->trailer is assumed to be freed in url.c on a
+         connection basis */
+      if (conn->trlPos >= conn->trlMax) {
+        char *ptr;
+        if(conn->trlMax) {
+          conn->trlMax *= 2;
+          ptr = (char*)realloc(conn->trailer,conn->trlMax);
+        }
+        else {
+          conn->trlMax=128;
+          ptr = (char*)malloc(conn->trlMax);
+        }
+        if(!ptr)
+          return CHUNKE_OUT_OF_MEMORY;
+        conn->trailer = ptr;
+      }
+      conn->trailer[conn->trlPos++]=*datap;
+
+      if(*datap == 0x0d)
+        ch->state = CHUNK_TRAILER_CR;
+      else {
+        datap++;
+        length--;
+     }
+      break;
+
+    case CHUNK_TRAILER_CR:
+      if(*datap == 0x0d) {
+        ch->state = CHUNK_TRAILER_POSTCR;
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
+    case CHUNK_TRAILER_POSTCR:
+      if (*datap == 0x0a) {
+        conn->trailer[conn->trlPos++]=0x0a;
+        conn->trailer[conn->trlPos]=0;
+        if (conn->trlPos==2) {
+          ch->state = CHUNK_STOP;
+          return CHUNKE_STOP;
+        }
+        else {
+#ifdef CURL_DOES_CONVERSIONS
+          /* Convert to host encoding before calling Curl_client_write */
+          result = Curl_convert_from_network(conn->data,
+                                             conn->trailer,
+                                             conn->trlPos);
+          if(result != CURLE_OK) {
+            /* Curl_convert_from_network calls failf if unsuccessful */
+            /* Treat it as a bad chunk */
+            return(CHUNKE_BAD_CHUNK);
+          }
+#endif /* CURL_DOES_CONVERSIONS */
+          Curl_client_write(conn, CLIENTWRITE_HEADER,
+                            conn->trailer, conn->trlPos);
+        }
+        ch->state = CHUNK_TRAILER;
+        conn->trlPos=0;
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
     case CHUNK_STOP:
       /* If we arrive here, there is data left in the end of the buffer
          even if there's no more chunks to read */

+ 24 - 8
Utilities/cmcurl/http_chunks.h

@@ -1,18 +1,18 @@
 #ifndef __HTTP_CHUNKS_H
 #define __HTTP_CHUNKS_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -52,8 +52,8 @@ typedef enum {
   /* POSTCR should get a CR and nothing else, then move to POSTLF */
   CHUNK_POSTCR,
 
-  /* POSTLF should get a LF and nothing else, then move back to HEX as
-     the CRLF combination marks the end of a chunk */
+  /* POSTLF should get a LF and nothing else, then move back to HEX as the
+     CRLF combination marks the end of a chunk */
   CHUNK_POSTLF,
 
   /* This is mainly used to really mark that we're out of the game.
@@ -62,7 +62,22 @@ typedef enum {
      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,
+
   CHUNK_LAST /* never use */
+
 } ChunkyState;
 
 typedef enum {
@@ -74,6 +89,7 @@ typedef enum {
   CHUNKE_WRITE_ERROR,
   CHUNKE_STATE_ERROR,
   CHUNKE_BAD_ENCODING,
+  CHUNKE_OUT_OF_MEMORY,
   CHUNKE_LAST
 } CHUNKcode;
 

+ 34 - 12
Utilities/cmcurl/http_digest.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,7 +22,7 @@
  ***************************************************************************/
 #include "setup.h"
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
 /* -- WIN32 approved -- */
 #include <stdio.h>
 #include <string.h>
@@ -38,7 +38,8 @@
 #include "http_digest.h"
 #include "strtok.h"
 #include "url.h" /* for Curl_safefree() */
-#include "curl_memory.h"
+#include "memory.h"
+#include "easyif.h" /* included for Curl_convert_... prototypes */
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -59,8 +60,8 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
                                               header */
 {
   bool more = TRUE;
-  char *token;
-  char *tmp;
+  char *token = NULL;
+  char *tmp = NULL;
   bool foundAuth = FALSE;
   bool foundAuthInt = FALSE;
   struct SessionHandle *data=conn->data;
@@ -75,7 +76,7 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
   }
 
   /* skip initial whitespaces */
-  while(*header && isspace((int)*header))
+  while(*header && ISSPACE(*header))
     header++;
 
   if(checkprefix("Digest", header)) {
@@ -91,9 +92,9 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
     while(more) {
       char value[32];
       char content[128];
-      size_t totlen;
+      size_t totlen=0;
 
-      while(*header && isspace((int)*header))
+      while(*header && ISSPACE(*header))
         header++;
 
       /* how big can these strings be? */
@@ -224,7 +225,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   unsigned char ha2[33];/* 32 digits and 1 zero byte */
   char cnoncebuf[7];
   char *cnonce;
-  char *tmp;
+  char *tmp = NULL;
   struct timeval now;
 
   char **allocuserpwd;
@@ -234,6 +235,21 @@ CURLcode Curl_output_digest(struct connectdata *conn,
 
   struct SessionHandle *data = conn->data;
   struct digestdata *d;
+#ifdef CURL_DOES_CONVERSIONS
+  CURLcode rc;
+/* 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) \
+  rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
+  if (rc != CURLE_OK) { \
+    free(b); \
+    return rc; \
+  }
+#else
+#define CURL_OUTPUT_DIGEST_CONV(a, b)
+#endif /* CURL_DOES_CONVERSIONS */
 
   if(proxy) {
     d = &data->state.proxydigest;
@@ -270,7 +286,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
     /* Generate a cnonce */
     now = Curl_tvnow();
     snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec);
-    if(Curl_base64_encode(cnoncebuf, strlen(cnoncebuf), &cnonce))
+    if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce))
       d->cnonce = cnonce;
     else
       return CURLE_OUT_OF_MEMORY;
@@ -291,6 +307,8 @@ CURLcode Curl_output_digest(struct connectdata *conn,
     aprintf("%s:%s:%s", userp, d->realm, passwdp);
   if(!md5this)
     return CURLE_OUT_OF_MEMORY;
+
+  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
   Curl_md5it(md5buf, md5this);
   free(md5this); /* free this again */
 
@@ -303,10 +321,12 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   if(d->algo == CURLDIGESTALGO_MD5SESS) {
     /* nonce and cnonce are OUTSIDE the hash */
     tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
-    free(ha1);
     if(!tmp)
       return CURLE_OUT_OF_MEMORY;
-    ha1 = (unsigned char *)tmp;
+    CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
+    Curl_md5it(md5buf, (unsigned char *)tmp);
+    free(tmp); /* free this again */
+    md5_to_ascii(md5buf, ha1);
   }
 
   /*
@@ -333,6 +353,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
        entity-body here */
     /* TODO: Append H(entity-body)*/
   }
+  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
   Curl_md5it(md5buf, md5this);
   free(md5this); /* free this again */
   md5_to_ascii(md5buf, ha2);
@@ -356,6 +377,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   if(!md5this)
     return CURLE_OUT_OF_MEMORY;
 
+  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
   Curl_md5it(md5buf, md5this);
   free(md5this); /* free this again */
   md5_to_ascii(md5buf, request_digest);

+ 12 - 7
Utilities/cmcurl/http_digest.h

@@ -1,18 +1,18 @@
 #ifndef __HTTP_DIGEST_H
 #define __HTTP_DIGEST_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -47,7 +47,12 @@ CURLcode Curl_output_digest(struct connectdata *conn,
                             bool proxy,
                             unsigned char *request,
                             unsigned char *uripath);
-void Curl_digest_cleanup(struct SessionHandle *data);
 void Curl_digest_cleanup_one(struct digestdata *dig);
 
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+void Curl_digest_cleanup(struct SessionHandle *data);
+#else
+#define Curl_digest_cleanup(x) do {} while(0)
+#endif
+
 #endif

+ 10 - 15
Utilities/cmcurl/http_negotiate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -34,14 +34,13 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <ctype.h>
-#include <errno.h>
 
 #include "urldata.h"
 #include "sendf.h"
 #include "strequal.h"
 #include "base64.h"
 #include "http_negotiate.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -111,7 +110,7 @@ log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
     gss_release_buffer(&min_stat, &status_string);
   } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
 
-  infof(conn->data, buf);
+  infof(conn->data, "%s", buf);
 }
 
 int Curl_input_negotiate(struct connectdata *conn, char *header)
@@ -125,7 +124,7 @@ int Curl_input_negotiate(struct connectdata *conn, char *header)
   bool gss;
   const char* protocol;
 
-  while(*header && isspace((int)*header))
+  while(*header && ISSPACE(*header))
     header++;
   if(checkprefix("GSS-Negotiate", header)) {
     protocol = "GSS-Negotiate";
@@ -161,17 +160,12 @@ int Curl_input_negotiate(struct connectdata *conn, char *header)
     return ret;
 
   header += strlen(neg_ctx->protocol);
-  while(*header && isspace((int)*header))
+  while(*header && ISSPACE(*header))
     header++;
 
   len = strlen(header);
   if (len > 0) {
-    int rawlen;
-    input_token.length = (len+3)/4 * 3;
-    input_token.value = malloc(input_token.length);
-    if (input_token.value == NULL)
-      return ENOMEM;
-    rawlen = Curl_base64_decode(header, input_token.value);
+    int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value);
     if (rawlen < 0)
       return -1;
     input_token.length = rawlen;
@@ -211,7 +205,7 @@ int Curl_input_negotiate(struct connectdata *conn, char *header)
           input_token.length = mechTokenLength;
           free(mechToken);
           mechToken = NULL;
-          infof(conn->data, "Parse SPNEGO Target Token succeded\n");
+          infof(conn->data, "Parse SPNEGO Target Token succeeded\n");
         }
     }
 #endif
@@ -292,11 +286,12 @@ CURLcode Curl_output_negotiate(struct connectdata *conn)
       neg_ctx->output_token.length = spnegoTokenLength;
       free(spnegoToken);
       spnegoToken = NULL;
-      infof(conn->data, "Make SPNEGO Initial Token succeded\n");
+      infof(conn->data, "Make SPNEGO Initial Token succeeded\n");
     }
   }
 #endif
-  len = Curl_base64_encode(neg_ctx->output_token.value,
+  len = Curl_base64_encode(conn->data,
+                           neg_ctx->output_token.value,
                            neg_ctx->output_token.length,
                            &encoded);
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 626 - 118
Utilities/cmcurl/http_ntlm.c


+ 10 - 7
Utilities/cmcurl/http_ntlm.h

@@ -1,18 +1,18 @@
 #ifndef __HTTP_NTLM_H
 #define __HTTP_NTLM_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -38,7 +38,10 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header);
 /* this is for creating ntlm header output */
 CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
 
-void Curl_ntlm_cleanup(struct SessionHandle *data);
+void Curl_ntlm_cleanup(struct connectdata *conn);
+#ifndef USE_NTLM
+#define Curl_ntlm_cleanup(x)
+#endif
 
 
 /* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */

+ 19 - 27
Utilities/cmcurl/if2ip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,8 +31,15 @@
 #include <unistd.h>
 #endif
 
-#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
-    !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE)
+#include "if2ip.h"
+
+/*
+ * This test can probably be simplified to #if defined(SIOCGIFADDR) and
+ * moved after the following includes.
+ */
+#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN__) && \
+    !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE) && \
+    !defined(_AMIGASF) && !defined(__minix)
 
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -55,7 +62,6 @@
 #include <sys/ioctl.h>
 #endif
 
-/* -- if2ip() -- */
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -64,16 +70,12 @@
 #include <sys/sockio.h>
 #endif
 
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#ifdef  VMS
+#ifdef VMS
 #include <inet.h>
 #endif
 
-#include "if2ip.h"
-#include "curl_memory.h"
+#include "inet_ntop.h"
+#include "memory.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -100,7 +102,7 @@ char *Curl_if2ip(const char *interface, char *buf, int buf_size)
       return NULL; /* this can't be a fine interface name */
     memcpy(req.ifr_name, interface, len+1);
     req.ifr_addr.sa_family = AF_INET;
-#ifdef  IOCTL_3_ARGS
+#ifdef IOCTL_3_ARGS
     if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) {
 #else
     if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) {
@@ -111,19 +113,9 @@ char *Curl_if2ip(const char *interface, char *buf, int buf_size)
     else {
       struct in_addr in;
 
-      union {
-        struct sockaddr_in *sin;
-        struct sockaddr *s;
-      } soadd;
-
-      soadd.s = &req.ifr_dstaddr;
-      memcpy(&in, &(soadd.sin->sin_addr.s_addr), sizeof(in));
-#if defined(HAVE_INET_NTOA_R)
-      ip = inet_ntoa_r(in,buf,buf_size);
-#else
-      ip = strncpy(buf,inet_ntoa(in),buf_size);
-      ip[buf_size - 1] = 0;
-#endif
+      struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr;
+      memcpy(&in, &s->sin_addr, sizeof(in));
+      ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
     }
     sclose(dummy);
   }
@@ -132,9 +124,9 @@ char *Curl_if2ip(const char *interface, char *buf, int buf_size)
 
 /* -- end of if2ip() -- */
 #else
-char *Curl_if2ip(const char *interface, char *buf, int buf_size)
+char *Curl_if2ip(const char *interf, char *buf, int buf_size)
 {
-    (void) interface;
+    (void) interf;
     (void) buf;
     (void) buf_size;
     return NULL;

+ 5 - 7
Utilities/cmcurl/if2ip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,13 +24,11 @@
  ***************************************************************************/
 #include "setup.h"
 
-#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
-    !defined(__riscos__) && !defined(__INTERIX)
-extern char *Curl_if2ip(const char *interface, char *buf, int buf_size);
-#else
-#define Curl_if2ip(a,b,c) NULL
-#endif
+extern char *Curl_if2ip(const char *interf, char *buf, int buf_size);
+
 #ifdef __INTERIX
+#include <sys/socket.h>
+
 /* Nedelcho Stanev's work-around for SFU 3.0 */
 struct ifreq {
 #define IFNAMSIZ 16

+ 35 - 0
Utilities/cmcurl/inet_ntoa_r.h

@@ -1,5 +1,38 @@
 #ifndef __INET_NTOA_R_H
 #define __INET_NTOA_R_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_INET_NTOA_R_2_ARGS
+/*
+ * uClibc 0.9.26 (at least) doesn't define this prototype. The buffer
+ * must be at least 16 characters long.
+ */
+char *inet_ntoa_r(const struct in_addr in, char buffer[]);
+
+#else
 /*
  * My solaris 5.6 system running gcc 2.8.1 does *not* have this prototype
  * in any system include file! Isn't that weird?
@@ -7,3 +40,5 @@
 char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen);
 
 #endif
+
+#endif

+ 40 - 20
Utilities/cmcurl/inet_ntop.c

@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 1996-2001  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.
  */
@@ -39,7 +55,7 @@
 #define INADDRSZ         4
 #define INT16SZ          2
 
-#ifdef WIN32
+#ifdef USE_WINSOCK
 #define EAFNOSUPPORT    WSAEAFNOSUPPORT
 #define SET_ERRNO(e)    WSASetLastError(errno = (e))
 #else
@@ -52,20 +68,21 @@
  * Returns `dst' (as a const)
  * Note:
  *  - uses no statics
- *  - takes a u_char* not an in_addr as input
+ *  - takes a unsigned char* not an in_addr as input
  */
-static const char *inet_ntop4 (const u_char *src, char *dst, size_t size)
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
 {
-#ifdef HAVE_INET_NTOA_R
+#if defined(HAVE_INET_NTOA_R_2_ARGS)
+  const char *ptr;
+  curlassert(size >= 16);
+  ptr = inet_ntoa_r(*(struct in_addr*)src, dst);
+  return (char *)memmove(dst, ptr, strlen(ptr)+1);
+
+#elif defined(HAVE_INET_NTOA_R)
   return inet_ntoa_r(*(struct in_addr*)src, dst, size);
+
 #else
-  union {
-    const u_char* uch;
-    const struct in_addr* iad;
-  } srcaddr;
-  const char *addr;
-  srcaddr.uch = src;
-  addr = inet_ntoa(*srcaddr.iad);
+  const char *addr = inet_ntoa(*(struct in_addr*)src);
 
   if (strlen(addr) >= size)
   {
@@ -80,7 +97,7 @@ static const char *inet_ntop4 (const u_char *src, char *dst, size_t size)
 /*
  * Convert IPv6 binary address into presentation (printable) format.
  */
-static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
+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
@@ -89,25 +106,28 @@ static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
    * 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 tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
   char *tp;
   struct {
     long base;
     long len;
   } best, cur;
-  u_long words [IN6ADDRSZ / INT16SZ];
-  int    i;
+  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));
+  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)
@@ -184,17 +204,17 @@ static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
 /*
  * Convert a network format address to presentation format.
  *
- * Returns pointer to presentation format address (`dst'),
+ * Returns pointer to presentation format address (`buf'),
  * Returns NULL on error (see errno).
  */
-const char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
 {
   switch (af) {
   case AF_INET:
-    return inet_ntop4((const u_char*)src, buf, size);
+    return inet_ntop4((const unsigned char*)src, buf, size);
 #ifdef ENABLE_IPV6
   case AF_INET6:
-    return inet_ntop6((const u_char*)src, buf, size);
+    return inet_ntop6((const unsigned char*)src, buf, size);
 #endif
   default:
     SET_ERRNO(EAFNOSUPPORT);

+ 4 - 4
Utilities/cmcurl/inet_ntop.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,13 +25,13 @@
 
 #include "setup.h"
 
+char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+
 #ifdef HAVE_INET_NTOP
-#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size)
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#else
-const char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size)
 #endif
 
 #endif /* __INET_NTOP_H */

+ 126 - 125
Utilities/cmcurl/inet_pton.c

@@ -44,7 +44,7 @@
 #define INADDRSZ         4
 #define INT16SZ          2
 
-#ifdef WIN32
+#ifdef USE_WINSOCK
 #define EAFNOSUPPORT    WSAEAFNOSUPPORT
 #endif
 
@@ -72,21 +72,21 @@ static int      inet_pton6(const char *src, unsigned char *dst);
 int
 Curl_inet_pton(int af, const char *src, void *dst)
 {
-        switch (af) {
-        case AF_INET:
-                return (inet_pton4(src, dst));
+  switch (af) {
+  case AF_INET:
+    return (inet_pton4(src, (unsigned char *)dst));
 #ifdef ENABLE_IPV6
 #ifndef AF_INET6
-#define AF_INET6        AF_MAX+1        /* just to let this compile */
+#define AF_INET6        (AF_MAX+1)        /* just to let this compile */
 #endif
-        case AF_INET6:
-                return (inet_pton6(src, dst));
+  case AF_INET6:
+    return (inet_pton6(src, (unsigned char *)dst));
 #endif
-        default:
-                errno = EAFNOSUPPORT;
-                return (-1);
-        }
-        /* NOTREACHED */
+  default:
+    errno = EAFNOSUPPORT;
+    return (-1);
+  }
+  /* NOTREACHED */
 }
 
 /* int
@@ -102,40 +102,41 @@ Curl_inet_pton(int af, const char *src, void *dst)
 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) = 0;
-        while ((ch = *src++) != '\0') {
-                const char *pch;
-
-                if ((pch = strchr(digits, ch)) != NULL) {
-                        size_t new = *tp * 10 + (pch - digits);
-
-                        if (new > 255)
-                                return (0);
-                        *tp = (unsigned char)new;
-                        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);
-        /* bcopy(tmp, dst, INADDRSZ); */
-        memcpy(dst, tmp, INADDRSZ);
-        return (1);
+  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;
+
+    if ((pch = strchr(digits, ch)) != NULL) {
+      unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
+
+      if (val > 255)
+        return (0);
+      *tp = 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);
+  /* bcopy(tmp, dst, INADDRSZ); */
+  memcpy(dst, tmp, INADDRSZ);
+  return (1);
 }
 
 #ifdef ENABLE_IPV6
@@ -155,85 +156,85 @@ inet_pton4(const char *src, unsigned char *dst)
 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 *xdigits, *curtok;
-        int ch, saw_xdigit;
-        u_int 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 *pch;
-
-                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
-                        pch = strchr((xdigits = xdigits_u), ch);
-                if (pch != NULL) {
-                        val <<= 4;
-                        val |= (pch - xdigits);
-                        if (val > 0xffff)
-                                return (0);
-                        saw_xdigit = 1;
-                        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 int n = tp - colonp;
-                int i;
-
-                for (i = 1; i <= n; i++) {
-                        endp[- i] = colonp[n - i];
-                        colonp[n - i] = 0;
-                }
-                tp = endp;
-        }
-        if (tp != endp)
-                return (0);
-        /* bcopy(tmp, dst, IN6ADDRSZ); */
-        memcpy(dst, tmp, IN6ADDRSZ);
-        return (1);
+  static const char xdigits_l[] = "0123456789abcdef",
+    xdigits_u[] = "0123456789ABCDEF";
+  unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+  const char *xdigits, *curtok;
+  int ch, saw_xdigit;
+  unsigned int 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 *pch;
+
+    if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+      pch = strchr((xdigits = xdigits_u), ch);
+    if (pch != NULL) {
+      val <<= 4;
+      val |= (pch - xdigits);
+      if (val > 0xffff)
+        return (0);
+      saw_xdigit = 1;
+      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 int n = tp - colonp;
+    int i;
+
+    for (i = 1; i <= n; i++) {
+      endp[- i] = colonp[n - i];
+      colonp[n - i] = 0;
+    }
+    tp = endp;
+  }
+  if (tp != endp)
+    return (0);
+  /* bcopy(tmp, dst, IN6ADDRSZ); */
+  memcpy(dst, tmp, IN6ADDRSZ);
+  return (1);
 }
 #endif /* ENABLE_IPV6 */
 

+ 14 - 9
Utilities/cmcurl/inet_pton.h

@@ -1,18 +1,18 @@
 #ifndef __INET_PTON_H
 #define __INET_PTON_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -25,13 +25,18 @@
 
 #include "setup.h"
 
+int Curl_inet_pton(int, const char *, void *);
+
 #ifdef HAVE_INET_PTON
-#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+
+#if defined(HAVE_NO_INET_PTON_PROTO)
+int inet_pton(int af, const char *src, void *dst);
+#endif
+
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#else
-int Curl_inet_pton(int, const char *, void *);
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
 #endif
 
 #endif /* __INET_PTON_H */

+ 38 - 21
Utilities/cmcurl/krb4.c

@@ -1,14 +1,13 @@
 /* This source code was modified by Martin Hedenfalk <[email protected]> for
- * use in Curl. His latest changes were done 2000-09-18.
+ * use in Curl. Martin's latest changes were done 2000-09-18.
  *
- * It has since been patched away like a madman by Daniel Stenberg
- * <[email protected]> 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.
+ * It has since been patched away like a madman by Daniel Stenberg to make it
+ * better applied to curl conditions, and to make it not use globals, pollute
+ * name space and more.
  *
  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2007 Daniel Stenberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,15 +35,16 @@
  * 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.  */
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
 
 #include "setup.h"
 
 #ifndef CURL_DISABLE_FTP
 #ifdef HAVE_KRB4
 
-#include "security.h"
-#include "base64.h"
 #include <stdlib.h>
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
@@ -57,10 +57,12 @@
 #include <unistd.h> /* for getpid() */
 #endif
 
+#include "urldata.h"
+#include "base64.h"
 #include "ftp.h"
 #include "sendf.h"
 #include "krb4.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
 #include "inet_ntoa_r.h"
@@ -199,7 +201,8 @@ krb4_auth(void *app_data, struct connectdata *conn)
 {
   int ret;
   char *p;
-  int len;
+  unsigned char *ptr;
+  size_t len;
   KTEXT_ST adat;
   MSG_DAT msg_data;
   int checksum;
@@ -220,7 +223,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
   if(ret == KDC_PR_UNKNOWN)
     ret = mk_auth(d, &adat, "rcmd", host, checksum);
   if(ret) {
-    Curl_infof(data, "%s\n", krb_get_err_text(ret));
+    infof(data, "%s\n", krb_get_err_text(ret));
     return AUTH_CONTINUE;
   }
 
@@ -232,7 +235,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
     if (krb_get_our_ip_for_realm(krb_realmofhost(host),
                                  &natAddr) != KSUCCESS
         && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
-      Curl_infof(data, "Can't get address for realm %s\n",
+      infof(data, "Can't get address for realm %s\n",
                  krb_realmofhost(host));
     else {
       if (natAddr.s_addr != localaddr->sin_addr.s_addr) {
@@ -242,14 +245,14 @@ krb4_auth(void *app_data, struct connectdata *conn)
 #else
         char *ip = (char *)inet_ntoa(natAddr);
 #endif
-        Curl_infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
+        infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
         localaddr->sin_addr = natAddr;
       }
     }
   }
 #endif
 
-  if(Curl_base64_encode((char *)adat.dat, adat.length, &p) < 1) {
+  if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) {
     Curl_failf(data, "Out of memory base64-encoding");
     return AUTH_CONTINUE;
   }
@@ -275,11 +278,17 @@ krb4_auth(void *app_data, struct connectdata *conn)
     return AUTH_ERROR;
   }
   p += 5;
-  len = Curl_base64_decode(p, (char *)adat.dat);
-  if(len < 0) {
+  len = Curl_base64_decode(p, &ptr);
+  if(len > sizeof(adat.dat)-1) {
+    free(ptr);
+    len=0;
+  }
+  if(!len || !ptr) {
     Curl_failf(data, "Failed to decode base64 from server");
     return AUTH_ERROR;
   }
+  memcpy((char *)adat.dat, ptr, len);
+  free(ptr);
   adat.length = len;
   ret = krb_rd_safe(adat.dat, adat.length, &d->key,
                     (struct sockaddr_in *)hisctladdr,
@@ -317,10 +326,11 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   char *name;
   char *p;
   char passwd[100];
-  int tmp;
+  size_t tmp;
   ssize_t nread;
   int save;
   CURLcode result;
+  unsigned char *ptr;
 
   save = Curl_set_command_prot(conn, prot_private);
 
@@ -346,12 +356,18 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   }
 
   p += 2;
-  tmp = Curl_base64_decode(p, (char *)tkt.dat);
-  if(tmp < 0) {
+  tmp = Curl_base64_decode(p, &ptr);
+  if(tmp >= sizeof(tkt.dat)) {
+    free(ptr);
+    tmp=0;
+  }
+  if(!tmp || !ptr) {
     Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
     Curl_set_command_prot(conn, save);
     return CURLE_FTP_WEIRD_SERVER_REPLY;
   }
+  memcpy((char *)tkt.dat, ptr, tmp);
+  free(ptr);
   tkt.length = tmp;
   tktcopy.length = tkt.length;
 
@@ -384,7 +400,8 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
   memset(key, 0, sizeof(key));
   memset(schedule, 0, sizeof(schedule));
   memset(passwd, 0, sizeof(passwd));
-  if(Curl_base64_encode((char *)tktcopy.dat, tktcopy.length, &p) < 1) {
+  if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p)
+     < 1) {
     failf(conn->data, "Out of memory base64-encoding.");
     Curl_set_command_prot(conn, save);
     return CURLE_OUT_OF_MEMORY;

+ 49 - 6
Utilities/cmcurl/krb4.h

@@ -1,18 +1,18 @@
 #ifndef __KRB4_H
 #define __KRB4_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -22,6 +22,49 @@
  *
  * $Id$
  ***************************************************************************/
+
+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 *, void*, int, int, void**, struct connectdata *);
+  int (*decode)(void *, void*, int, int, struct connectdata *);
+};
+
+
+#define AUTH_OK         0
+#define AUTH_CONTINUE   1
+#define AUTH_ERROR      2
+
+extern struct Curl_sec_client_mech Curl_krb4_client_mech;
+
 CURLcode Curl_krb_kauth(struct connectdata *conn);
+int Curl_sec_fflush_fd(struct connectdata *conn, int fd);
+int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...);
+int Curl_sec_getc (struct connectdata *conn, FILE *);
+int Curl_sec_putc (struct connectdata *conn, int, FILE *);
+int Curl_sec_read (struct connectdata *conn, int, void *, int);
+int Curl_sec_read_msg (struct connectdata *conn, char *, int);
+
+int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list);
+int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...);
+int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list);
+ssize_t Curl_sec_send(struct connectdata *conn, int, char *, int);
+int Curl_sec_write(struct connectdata *conn, int, char *, int);
+
+void Curl_sec_end (struct connectdata *);
+int Curl_sec_login (struct connectdata *);
+void Curl_sec_prot (int, char **);
+int Curl_sec_request_prot (struct connectdata *conn, const char *level);
+void Curl_sec_set_protection_level(struct connectdata *conn);
+void Curl_sec_status (void);
+
+enum protection_level Curl_set_command_prot(struct connectdata *,
+                                            enum protection_level);
+
 
 #endif

+ 140 - 63
Utilities/cmcurl/ldap.c

@@ -3,9 +3,9 @@
  *  Project         ___| | | |  _ \| |
  *                 / __| | | | |_) | |
  *                | (__| |_| |  _ <| |___
- *                \___|\___/|_| \_\_____|
+ *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -30,14 +30,19 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
 #include <errno.h>
 
 #if defined(WIN32)
-# include <windows.h>
-# include <malloc.h>
-# include <WinLdap.h>
+# include <winldap.h>
 #endif
 
 #ifdef HAVE_UNISTD_H
@@ -56,7 +61,8 @@
 #include "strequal.h"
 #include "strtok.h"
 #include "ldap.h"
-#include "curl_memory.h"
+#include "memory.h"
+#include "base64.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -64,7 +70,8 @@
 #include "memdebug.h"
 
 /* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl
- * pointers in case libcurl was compiled as fastcall (-Gr).
+ * pointers in case libcurl was compiled as fastcall (cl -Gr). Watcom
+ * uses fastcall by default.
  */
 #if !defined(WIN32) && !defined(__cdecl)
 #define __cdecl
@@ -73,8 +80,17 @@
 #ifndef LDAP_SIZELIMIT_EXCEEDED
 #define LDAP_SIZELIMIT_EXCEEDED 4
 #endif
+#ifndef LDAP_VERSION2
+#define LDAP_VERSION2 2
+#endif
+#ifndef LDAP_VERSION3
+#define LDAP_VERSION3 3
+#endif
+#ifndef LDAP_OPT_PROTOCOL_VERSION
+#define LDAP_OPT_PROTOCOL_VERSION 0x0011
+#endif
 
-#define DLOPEN_MODE   RTLD_LAZY  /*! assume all dlopen() implementations have 
+#define DLOPEN_MODE   RTLD_LAZY  /*! assume all dlopen() implementations have
                                    this */
 
 #if defined(RTLD_LAZY_GLOBAL)    /* It turns out some systems use this: */
@@ -99,43 +115,60 @@
 #undef HAVE_LIBDL
 #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
+
 typedef void * (*dynafunc)(void *input);
 
 /***********************************************************************
  */
+#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) || defined(WIN32)
 static void *libldap = NULL;
-#ifndef WIN32
+#if defined(DL_LBER_FILE)
 static void *liblber = NULL;
 #endif
+#endif
+
+struct bv {
+  unsigned long bv_len;
+  char  *bv_val;
+};
 
 static int DynaOpen(const char **mod_name)
 {
 #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
   if (libldap == NULL) {
     /*
-     * libldap.so should be able to resolve its dependency on
-     * liblber.so automatically, but since it does not we will
+     * libldap.so can normally resolve its dependency on liblber.so
+     * automatically, but in broken installation it does not so
      * handle it here by opening liblber.so as global.
      */
-    *mod_name = "liblber.so";
+#ifdef DL_LBER_FILE
+    *mod_name = DL_LBER_FILE;
     liblber = dlopen(*mod_name, DLOPEN_MODE);
+    if (!liblber)
+      return 0;
+#endif
 
     /* Assume loading libldap.so will fail if loading of liblber.so failed
      */
-    if (liblber)  {
-      *mod_name = "libldap.so";
-      libldap = dlopen(*mod_name, RTLD_LAZY);
-    }
+    *mod_name = DL_LDAP_FILE;
+    libldap = dlopen(*mod_name, RTLD_LAZY);
   }
-  return (libldap != NULL && liblber != NULL);
+  return (libldap != NULL);
 
 #elif defined(WIN32)
-  *mod_name = "wldap32.dll";
+  *mod_name = DL_LDAP_FILE;
   if (!libldap)
     libldap = (void*)LoadLibrary(*mod_name);
   return (libldap != NULL);
 
 #else
+  *mod_name = "";
   return (0);
 #endif
 }
@@ -147,10 +180,12 @@ static void DynaClose(void)
     dlclose(libldap);
     libldap=NULL;
   }
+#ifdef DL_LBER_FILE
   if (liblber) {
     dlclose(liblber);
     liblber=NULL;
   }
+#endif
 #elif defined(WIN32)
   if (libldap) {
     FreeLibrary ((HMODULE)libldap);
@@ -161,7 +196,7 @@ static void DynaClose(void)
 
 static dynafunc DynaGetFunction(const char *name)
 {
-  dynafunc func = (dynafunc)NULL;
+  dynafunc func = (dynafunc)ZERO_NULL;
 
 #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
   if (libldap) {
@@ -175,6 +210,8 @@ static dynafunc DynaGetFunction(const char *name)
   if (libldap) {
     func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name);
   }
+#else
+  (void) name;
 #endif
   return func;
 }
@@ -214,7 +251,7 @@ static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc;
 #endif
 
 
-CURLcode Curl_ldap(struct connectdata *conn)
+CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 {
   CURLcode status = CURLE_OK;
   int rc = 0;
@@ -233,10 +270,11 @@ CURLcode Curl_ldap(struct connectdata *conn)
   char  *(__cdecl *ldap_get_dn)(void *, void *);
   char  *(__cdecl *ldap_first_attribute)(void *, void *, void **);
   char  *(__cdecl *ldap_next_attribute)(void *, void *, void *);
-  char **(__cdecl *ldap_get_values)(void *, void *, const char *);
-  void   (__cdecl *ldap_value_free)(char **);
+  void **(__cdecl *ldap_get_values_len)(void *, void *, const char *);
+  void   (__cdecl *ldap_value_free_len)(void **);
   void   (__cdecl *ldap_memfree)(void *);
   void   (__cdecl *ber_free)(void *, int);
+  int    (__cdecl *ldap_set_option)(void *, int, void *);
 
   void *server;
   LDAPURLDesc *ludp = NULL;
@@ -245,7 +283,11 @@ CURLcode Curl_ldap(struct connectdata *conn)
   void *entryIterator;     /*! type should be 'LDAPMessage *' */
   int num = 0;
   struct SessionHandle *data=conn->data;
+  int ldap_proto;
+  char *val_b64;
+  size_t val_b64_sz;
 
+  *done = TRUE; /* unconditionally */
   infof(data, "LDAP local: %s\n", data->change.url);
 
   if (!DynaOpen(&mod_name)) {
@@ -256,25 +298,30 @@ CURLcode Curl_ldap(struct connectdata *conn)
   /* The types are needed because ANSI C distinguishes between
    * pointer-to-object (data) and pointer-to-function.
    */
-  DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init);
-  DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s);
-  DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s);
+  DYNA_GET_FUNCTION(void *(__cdecl *)(char *, int), ldap_init);
+  DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *),
+                    ldap_simple_bind_s);
+  DYNA_GET_FUNCTION(int (__cdecl *)(void *), ldap_unbind_s);
 #ifndef WIN32
   DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse);
   DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc);
 #endif
-  DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int,
-                            void **), ldap_search_s);
-  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry);
-  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry);
-  DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string);
-  DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn);
-  DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute);
-  DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute);
-  DYNA_GET_FUNCTION(char **(*)(void *, void *, const char *), ldap_get_values);
-  DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free);
-  DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree);
-  DYNA_GET_FUNCTION(void (*)(void *, int), ber_free);
+  DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, int, char *, char **, int,
+                                    void **), ldap_search_s);
+  DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_first_entry);
+  DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_next_entry);
+  DYNA_GET_FUNCTION(char *(__cdecl *)(int), ldap_err2string);
+  DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *), ldap_get_dn);
+  DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **),
+                    ldap_first_attribute);
+  DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *),
+                    ldap_next_attribute);
+  DYNA_GET_FUNCTION(void **(__cdecl *)(void *, void *, const char *),
+                    ldap_get_values_len);
+  DYNA_GET_FUNCTION(void (__cdecl *)(void **), ldap_value_free_len);
+  DYNA_GET_FUNCTION(void (__cdecl *)(void *), ldap_memfree);
+  DYNA_GET_FUNCTION(void (__cdecl *)(void *, int), ber_free);
+  DYNA_GET_FUNCTION(int (__cdecl *)(void *, int, void *), ldap_set_option);
 
   server = (*ldap_init)(conn->host.name, (int)conn->port);
   if (server == NULL) {
@@ -284,9 +331,18 @@ CURLcode Curl_ldap(struct connectdata *conn)
     goto quit;
   }
 
+  ldap_proto = LDAP_VERSION3;
+  (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
   rc = (*ldap_simple_bind_s)(server,
                              conn->bits.user_passwd ? conn->user : NULL,
                              conn->bits.user_passwd ? conn->passwd : NULL);
+  if (rc != 0) {
+    ldap_proto = LDAP_VERSION2;
+    (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+    rc = (*ldap_simple_bind_s)(server,
+                               conn->bits.user_passwd ? conn->user : NULL,
+                               conn->bits.user_passwd ? conn->passwd : NULL);
+  }
   if (rc != 0) {
      failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
      status = CURLE_LDAP_CANNOT_BIND;
@@ -323,35 +379,51 @@ CURLcode Curl_ldap(struct connectdata *conn)
     char  *dn = (*ldap_get_dn)(server, entryIterator);
     int i;
 
-    Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
-    Curl_client_write(data, CLIENTWRITE_BODY, (char *)dn, 0);
-    Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
 
     for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber);
          attribute;
          attribute = (*ldap_next_attribute)(server, entryIterator, ber))
     {
-      char **vals = (*ldap_get_values)(server, entryIterator, attribute);
+      struct bv **vals = (struct bv **)
+        (*ldap_get_values_len)(server, entryIterator, attribute);
 
       if (vals != NULL)
       {
         for (i = 0; (vals[i] != NULL); i++)
         {
-          Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
-          Curl_client_write(data, CLIENTWRITE_BODY, (char*) attribute, 0);
-          Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
-          Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0);
-          Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+          if ((strlen(attribute) > 7) &&
+              (strcmp(";binary",
+                      (char *)attribute +
+                      (strlen((char *)attribute) - 7)) == 0)) {
+            /* Binary attribute, encode to base64. */
+            val_b64_sz = Curl_base64_encode(conn->data,
+                                            vals[i]->bv_val,
+                                            vals[i]->bv_len,
+                                            &val_b64);
+            if (val_b64_sz > 0) {
+              Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
+              free(val_b64);
+            }
+          } else
+            Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+                              vals[i]->bv_len);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
         }
 
         /* Free memory used to store values */
-        (*ldap_value_free)(vals);
+        (*ldap_value_free_len)((void **)vals);
       }
-      Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+      Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
 
       (*ldap_memfree)(attribute);
-      (*ldap_memfree)(dn);
     }
+    (*ldap_memfree)(dn);
     if (ber)
        (*ber_free)(ber, 0);
   }
@@ -368,7 +440,8 @@ quit:
   DynaClose();
 
   /* no data to transfer */
-  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+  conn->bits.close = TRUE;
 
   return status;
 }
@@ -436,36 +509,36 @@ static char **split_str (char *str)
 /*
  * Unescape the LDAP-URL components
  */
-static bool unescape_elements (LDAPURLDesc *ludp)
+static bool unescape_elements (void *data, LDAPURLDesc *ludp)
 {
   int i;
 
   if (ludp->lud_filter) {
-    ludp->lud_filter = curl_unescape(ludp->lud_filter, 0);
+    ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL);
     if (!ludp->lud_filter)
        return (FALSE);
   }
 
   for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
-    ludp->lud_attrs[i] = curl_unescape(ludp->lud_attrs[i], 0);
+    ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL);
     if (!ludp->lud_attrs[i])
        return (FALSE);
   }
 
   for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) {
-    ludp->lud_exts[i] = curl_unescape(ludp->lud_exts[i], 0);
+    ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL);
     if (!ludp->lud_exts[i])
        return (FALSE);
   }
 
   if (ludp->lud_dn) {
     char *dn = ludp->lud_dn;
-    char *new_dn = curl_unescape(dn, 0);
+    char *new_dn = curl_easy_unescape(data, dn, 0, NULL);
 
     free(dn);
+    ludp->lud_dn = new_dn;
     if (!new_dn)
        return (FALSE);
-    ludp->lud_dn = new_dn;
   }
   return (TRUE);
 }
@@ -477,8 +550,10 @@ static bool unescape_elements (LDAPURLDesc *ludp)
  *
  * <hostname> already known from 'conn->host.name'.
  * <port>     already known from 'conn->remote_port'.
- * extract the rest from 'conn->path+1'. All fields are optional. e.g.
- *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter> yields ludp->lud_dn = "".
+ * extract the rest from 'conn->data->reqdata.path+1'. All fields are optional.
+ * e.g.
+ *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
+ * yields ludp->lud_dn = "".
  *
  * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915
  */
@@ -487,7 +562,9 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
   char *p, *q;
   int i;
 
-  if (!conn->path || conn->path[0] != '/' ||
+  if (!conn->data ||
+      !conn->data->reqdata.path ||
+       conn->data->reqdata.path[0] != '/' ||
       !checkprefix(conn->protostr, conn->data->change.url))
      return LDAP_INVALID_SYNTAX;
 
@@ -497,13 +574,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
 
   /* parse DN (Distinguished Name).
    */
-  ludp->lud_dn = strdup(conn->path+1);
+  ludp->lud_dn = strdup(conn->data->reqdata.path+1);
   if (!ludp->lud_dn)
      return LDAP_NO_MEMORY;
 
   p = strchr(ludp->lud_dn, '?');
-  LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : strlen(ludp->lud_dn),
-               ludp->lud_dn));
+  LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) :
+               strlen(ludp->lud_dn), ludp->lud_dn));
 
   if (!p)
      goto success;
@@ -571,7 +648,7 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
       LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i]));
 
 success:
-  if (!unescape_elements(ludp))
+  if (!unescape_elements(conn->data, ludp))
      return LDAP_NO_MEMORY;
   return LDAP_SUCCESS;
 }

+ 7 - 7
Utilities/cmcurl/ldap.h

@@ -2,18 +2,18 @@
 #define __LDAP_H
 
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -24,6 +24,6 @@
  * $Id$
  ***************************************************************************/
 #ifndef CURL_DISABLE_LDAP
-CURLcode Curl_ldap(struct connectdata *conn);
+CURLcode Curl_ldap(struct connectdata *conn, bool *done);
 #endif
 #endif /* __LDAP_H */

+ 19 - 11
Utilities/cmcurl/llist.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -27,13 +27,13 @@
 #include <stdlib.h>
 
 #include "llist.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 /* this must be the last include file */
 #include "memdebug.h"
 
 void
-Curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
+Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
 {
   l->size = 0;
   l->dtor = dtor;
@@ -41,12 +41,12 @@ Curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
   l->tail = NULL;
 }
 
-curl_llist *
+struct curl_llist *
 Curl_llist_alloc(curl_llist_dtor dtor)
 {
-  curl_llist *list;
+  struct curl_llist *list;
 
-  list = (curl_llist *)malloc(sizeof(curl_llist));
+  list = (struct curl_llist *)malloc(sizeof(struct curl_llist));
   if(NULL == list)
     return NULL;
 
@@ -59,10 +59,11 @@ Curl_llist_alloc(curl_llist_dtor dtor)
  * Curl_llist_insert_next() returns 1 on success and 0 on failure.
  */
 int
-Curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
+Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
+                       const void *p)
 {
-  curl_llist_element *ne =
-    (curl_llist_element *) malloc(sizeof(curl_llist_element));
+  struct curl_llist_element *ne =
+    (struct curl_llist_element *) malloc(sizeof(struct curl_llist_element));
   if(!ne)
     return 0;
 
@@ -91,7 +92,8 @@ Curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
 }
 
 int
-Curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
+Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
+                  void *user)
 {
   if (e == NULL || list->size == 0)
     return 1;
@@ -119,7 +121,7 @@ Curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
 }
 
 void
-Curl_llist_destroy(curl_llist *list, void *user)
+Curl_llist_destroy(struct curl_llist *list, void *user)
 {
   if(list) {
     while (list->size > 0)
@@ -128,3 +130,9 @@ Curl_llist_destroy(curl_llist *list, void *user)
     free(list);
   }
 }
+
+size_t
+Curl_llist_count(struct curl_llist *list)
+{
+  return list->size;
+}

+ 27 - 23
Utilities/cmcurl/llist.h

@@ -1,18 +1,18 @@
 #ifndef __LLIST_H
 #define __LLIST_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -28,29 +28,33 @@
 
 typedef void (*curl_llist_dtor)(void *, void *);
 
-typedef struct _curl_llist_element {
+struct curl_llist_element {
   void *ptr;
 
-  struct _curl_llist_element *prev;
-  struct _curl_llist_element *next;
-} curl_llist_element;
+  struct curl_llist_element *prev;
+  struct curl_llist_element *next;
+};
 
-typedef struct _curl_llist {
-  curl_llist_element *head;
-  curl_llist_element *tail;
+struct curl_llist {
+  struct curl_llist_element *head;
+  struct curl_llist_element *tail;
 
   curl_llist_dtor dtor;
 
   size_t size;
-} curl_llist;
-
-void Curl_llist_init(curl_llist *, curl_llist_dtor);
-curl_llist *Curl_llist_alloc(curl_llist_dtor);
-int Curl_llist_insert_next(curl_llist *, curl_llist_element *, const void *);
-int Curl_llist_insert_prev(curl_llist *, curl_llist_element *, const void *);
-int Curl_llist_remove(curl_llist *, curl_llist_element *, void *);
-int Curl_llist_remove_next(curl_llist *, curl_llist_element *, void *);
-size_t Curl_llist_count(curl_llist *);
-void Curl_llist_destroy(curl_llist *, void *);
+};
+
+void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
+struct curl_llist *Curl_llist_alloc(curl_llist_dtor);
+int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
+                           const void *);
+int Curl_llist_insert_prev(struct curl_llist *, struct curl_llist_element *,
+                           const void *);
+int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
+                      void *);
+int Curl_llist_remove_next(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

+ 16 - 12
Utilities/cmcurl/md5.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___ 
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -23,7 +23,9 @@
 
 #include "setup.h"
 
-#ifndef USE_SSLEAY
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#if !defined(USE_SSLEAY) || !defined(USE_OPENSSL)
 /* This code segment is only used if OpenSSL is not provided, as if it is
    we use the MD5-function provided there instead. No good duplicating
    code! */
@@ -65,7 +67,7 @@ struct md5_ctx {
 typedef struct md5_ctx MD5_CTX;
 
 static void MD5_Init(struct md5_ctx *);
-static void MD5_Update(struct md5_ctx *, unsigned char *, unsigned int);
+static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int);
 static void MD5_Final(unsigned char [16], struct md5_ctx *);
 
 /* Constants for MD5Transform routine.
@@ -88,11 +90,11 @@ static void MD5_Final(unsigned char [16], struct md5_ctx *);
 #define S43 15
 #define S44 21
 
-static void MD5Transform(UINT4 [4], unsigned char [64]);
+static void MD5Transform(UINT4 [4], const unsigned char [64]);
 static void Encode(unsigned char *, UINT4 *, unsigned int);
-static void Decode(UINT4 *, unsigned char *, unsigned int);
+static void Decode(UINT4 *, const unsigned char *, unsigned int);
 
-static unsigned char PADDING[64] = {
+static const unsigned char PADDING[64] = {
   0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -149,9 +151,9 @@ static void MD5_Init(struct md5_ctx *context)
   operation, processing another message block, and updating the
   context.
  */
-static void MD5_Update (struct md5_ctx *context, /* context */
-                        unsigned char *input, /* input block */
-                        unsigned int inputLen)/* length of input block */
+static void MD5_Update (struct md5_ctx *context,    /* context */
+                        const unsigned char *input, /* input block */
+                        unsigned int inputLen)      /* length of input block */
 {
   unsigned int i, bufindex, partLen;
 
@@ -212,7 +214,7 @@ static void MD5_Final(unsigned char digest[16], /* message digest */
 
 /* MD5 basic transformation. Transforms state based on block. */
 static void MD5Transform(UINT4 state[4],
-                         unsigned char block[64])
+                         const unsigned char block[64])
 {
   UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
 
@@ -320,7 +322,7 @@ static void Encode (unsigned char *output,
    a multiple of 4.
 */
 static void Decode (UINT4 *output,
-                    unsigned char *input,
+                    const unsigned char *input,
                     unsigned int len)
 {
   unsigned int i, j;
@@ -339,10 +341,12 @@ static void Decode (UINT4 *output,
 #include "md5.h"
 
 void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
-                unsigned char *input)
+                const unsigned char *input)
 {
   MD5_CTX ctx;
   MD5_Init(&ctx);
   MD5_Update(&ctx, input, (unsigned int)strlen((char *)input));
   MD5_Final(outbuffer, &ctx);
 }
+
+#endif

+ 1 - 1
Utilities/cmcurl/md5.h

@@ -24,6 +24,6 @@
  ***************************************************************************/
 
 void Curl_md5it(unsigned char *output,
-                unsigned char *input);
+                const unsigned char *input);
 
 #endif

+ 17 - 12
Utilities/cmcurl/memdebug.c

@@ -6,7 +6,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -42,7 +42,7 @@
 #endif
 
 #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
-#include "curl_memory.h"
+#include "memory.h"
 #include "memdebug.h"
 
 struct memdebug {
@@ -61,25 +61,29 @@ struct memdebug {
  */
 
 #define logfile curl_debuglogfile
-FILE *curl_debuglogfile;
-static bool memlimit; /* enable memory limit */
-static long memsize;  /* set number of mallocs allowed */
+FILE *curl_debuglogfile = 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_memdebug(const char *logname)
 {
-  if(logname)
-    logfile = fopen(logname, "w");
-  else
-    logfile = stderr;
+  if (!logfile) {
+    if(logname)
+      logfile = fopen(logname, "w");
+    else
+      logfile = stderr;
+  }
 }
 
 /* This function sets the number of malloc() calls that should return
    successfully! */
 void curl_memlimit(long limit)
 {
-  memlimit = TRUE;
-  memsize = limit;
+  if (!memlimit) {
+    memlimit = TRUE;
+    memsize = limit;
+  }
 }
 
 /* returns TRUE if this isn't allowed! */
@@ -95,6 +99,7 @@ static bool countcheck(const char *func, int line, const char *source)
       if(source)
         fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
                 source, line, func);
+      errno = ENOMEM;
       return TRUE; /* RETURN ERROR! */
     }
     else
@@ -200,7 +205,7 @@ void *curl_dorealloc(void *ptr, size_t wantedsize,
 
   mem=(struct memdebug *)(Curl_crealloc)(mem, size);
   if(logfile)
-    fprintf(logfile, "MEM %s:%d realloc(0x%x, %zd) = %p\n",
+    fprintf(logfile, "MEM %s:%d realloc(%p, %zd) = %p\n",
             source, line, ptr, wantedsize, mem?mem->mem:NULL);
 
   if(mem) {

+ 37 - 20
Utilities/cmcurl/memdebug.h

@@ -2,18 +2,18 @@
 #ifndef _CURL_MEDEBUG_H
 #define _CURL_MEDEBUG_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -31,6 +31,8 @@
 
 #include "setup.h"
 
+#include <curl/curl.h>
+
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -48,24 +50,24 @@
 extern FILE *logfile;
 
 /* memory functions */
-void *curl_domalloc(size_t size, int line, const char *source);
-void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
-void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
-void curl_dofree(void *ptr, int line, const char *source);
-char *curl_dostrdup(const char *str, int line, const char *source);
-void curl_memdebug(const char *logname);
-void curl_memlimit(long limit);
+CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
+CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
+CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
+CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
+CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
+CURL_EXTERN void curl_memdebug(const char *logname);
+CURL_EXTERN void curl_memlimit(long limit);
 
 /* file descriptor manipulators */
-int curl_socket(int domain, int type, int protocol, int line , const char *);
-int curl_sclose(int sockfd, int, const char *source);
-int curl_accept(int s, void *addr, void *addrlen,
-                int line, const char *source);
+CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *);
+CURL_EXTERN int curl_sclose(int sockfd, int, const char *source);
+CURL_EXTERN int curl_accept(int s, void *addr, void *addrlen,
+                            int line, const char *source);
 
 /* FILE functions */
-FILE *curl_fopen(const char *file, const char *mode, int line,
-                 const char *source);
-int curl_fclose(FILE *file, int line, const char *source);
+CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
+                             const char *source);
+CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
 
 #ifndef MEMDEBUG_NODEFINES
 
@@ -83,11 +85,26 @@ int curl_fclose(FILE *file, int line, const char *source);
 #define accept(sock,addr,len)\
  curl_accept(sock,addr,len,__LINE__,__FILE__)
 
+#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_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#else
+#undef getaddrinfo
 #define getaddrinfo(host,serv,hint,res) \
   curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#endif
+
+#ifdef HAVE_GETNAMEINFO
+#undef getnameinfo
 #define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
   curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
   __FILE__)
+#endif
+
+#undef freeaddrinfo
 #define freeaddrinfo(data) \
   curl_dofreeaddrinfo(data,__LINE__,__FILE__)
 

+ 5 - 5
Utilities/cmcurl/curl_memory.h → Utilities/cmcurl/memory.h

@@ -1,10 +1,10 @@
 #ifndef _CURL_MEMORY_H
 #define _CURL_MEMORY_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
@@ -12,7 +12,7 @@
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.

+ 21 - 18
Utilities/cmcurl/mprintf.c

@@ -38,6 +38,10 @@
 #include <ctype.h>
 #include <string.h>
 
+#if defined(DJGPP) && (DJGPP_MINOR < 4)
+#undef _MPRINTF_REPLACE /* don't use x_was_used() here */
+#endif
+
 #include <curl/mprintf.h>
 
 #ifndef SIZEOF_LONG_DOUBLE
@@ -55,7 +59,7 @@
 #define ENABLE_64BIT
 #endif
 
-#include "curl_memory.h"
+#include "memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -75,6 +79,9 @@
 # define BOOL char
 #endif
 
+#ifdef _AMIGASF
+# undef FORMAT_INT
+#endif
 
 /* Lower-case digits.  */
 static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
@@ -164,7 +171,7 @@ int curl_msprintf(char *buffer, const char *format, ...);
 static long dprintf_DollarString(char *input, char **end)
 {
   int number=0;
-  while(isdigit((int)*input)) {
+  while(ISDIGIT(*input)) {
     number *= 10;
     number += *input-'0';
     input++;
@@ -619,10 +626,10 @@ static int dprintf_formatf(
     char alt;
 
     /* Width of a field.  */
-    ssize_t width;
+    long width;
 
     /* Precision of a field.  */
-    ssize_t prec;
+    long prec;
 
     /* Decimal integer is negative.  */
     char is_neg;
@@ -759,8 +766,8 @@ static int dprintf_formatf(
           *w-- = digits[num % base];
           num /= base;
         }
-        width -= workend - w;
-        prec -= workend - w;
+        width -= (long)(workend - w);
+        prec -= (long)(workend - w);
 
         if (alt && base == 8 && prec <= 0) {
           *w-- = '0';
@@ -816,8 +823,8 @@ static int dprintf_formatf(
     case FORMAT_STRING:
             /* String.  */
       {
-        static char null[] = "(nil)";
-        char *str;
+        static const char null[] = "(nil)";
+        const char *str;
         size_t len;
 
         str = (char *) p->data.str;
@@ -830,7 +837,7 @@ static int dprintf_formatf(
             p->flags &= (~FLAGS_ALT);
           }
           else {
-            str = (char *)"";
+            str = "";
             len = 0;
           }
         }
@@ -839,7 +846,7 @@ static int dprintf_formatf(
 
         if (prec != -1 && (size_t) prec < len)
           len = prec;
-        width -= len;
+        width -= (long)len;
 
         if (p->flags & FLAGS_ALT)
           OUTCHAR('"');
@@ -869,14 +876,14 @@ static int dprintf_formatf(
           base = 16;
           digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
           alt = 1;
-          num = (unsigned long) ptr;
+          num = (size_t) ptr;
           is_neg = 0;
           goto number;
         }
         else {
           /* Write "(nil)" for a nil pointer.  */
-          static char strnil[] = "(nil)";
-          char *point;
+          static const char strnil[] = "(nil)";
+          const char *point;
 
           width -= sizeof(strnil) - 1;
           if (p->flags & FLAGS_LEFT)
@@ -933,7 +940,6 @@ static int dprintf_formatf(
           fptr += len;
           left -= len;
         }
-        (void)left;
         if (p->flags & FLAGS_LONG)
           *fptr++ = 'l';
 
@@ -1134,15 +1140,12 @@ int curl_msprintf(char *buffer, const char *format, ...)
   return retcode;
 }
 
-#if !(defined( WIN32) || defined(__UCLIBC__)) /* not needed on win32 */
-extern int fputc(int, FILE *);
-#endif
-
 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;

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1100 - 279
Utilities/cmcurl/multi.c


+ 46 - 0
Utilities/cmcurl/multiif.h

@@ -0,0 +1,46 @@
+#ifndef __MULTIIF_H
+#define __MULTIIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by multi.c
+ */
+void Curl_expire(struct SessionHandle *data, long milli);
+
+void Curl_multi_rmeasy(void *multi, CURL *data);
+
+bool Curl_multi_canPipeline(struct Curl_multi* multi);
+
+/* 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))
+
+#endif /* __MULTIIF_H */

+ 12 - 12
Utilities/cmcurl/netrc.c

@@ -1,16 +1,16 @@
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -45,7 +45,7 @@
 
 #include "strequal.h"
 #include "strtok.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -83,7 +83,7 @@ int Curl_parsenetrc(char *host,
   FILE *file;
   int retcode=1;
   int specific_login = (login[0] != 0);
-  char *home = NULL; 
+  char *home = NULL;
   bool home_alloc = FALSE;
   bool netrc_alloc = FALSE;
   int state=NOTHING;
@@ -103,7 +103,7 @@ int Curl_parsenetrc(char *host,
     char *override = curl_getenv("CURL_DEBUG_NETRC");
 
     if (override) {
-      printf("NETRC: overridden " NETRC " file: %s\n", home);
+      fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override);
       netrcfile = override;
       netrc_alloc = TRUE;
     }
@@ -171,7 +171,7 @@ int Curl_parsenetrc(char *host,
             /* and yes, this is our host! */
             state=HOSTVALID;
 #ifdef _NETRC_DEBUG
-            printf("HOST: %s\n", tok);
+            fprintf(stderr, "HOST: %s\n", tok);
 #endif
             retcode=0; /* we did find our host */
           }
@@ -188,7 +188,7 @@ int Curl_parsenetrc(char *host,
             else {
               strncpy(login, tok, LOGINSIZE-1);
 #ifdef _NETRC_DEBUG
-              printf("LOGIN: %s\n", login);
+              fprintf(stderr, "LOGIN: %s\n", login);
 #endif
             }
             state_login=0;
@@ -197,7 +197,7 @@ int Curl_parsenetrc(char *host,
             if (state_our_login || !specific_login) {
               strncpy(password, tok, PASSWORDSIZE-1);
 #ifdef _NETRC_DEBUG
-              printf("PASSWORD: %s\n", password);
+              fprintf(stderr, "PASSWORD: %s\n", password);
 #endif
             }
             state_password=0;

+ 1 - 1
Utilities/cmcurl/nwlib.c

@@ -30,7 +30,7 @@
 #include <nks/thread.h>
 #include <nks/synch.h>
 
-#include "curl_memory.h"
+#include "memory.h"
 #include "memdebug.h"
 
 typedef struct

+ 425 - 0
Utilities/cmcurl/parsedate.c

@@ -0,0 +1,425 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+/*
+  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 "setup.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* for strtol() */
+#endif
+
+#include <curl/curl.h>
+
+static time_t Curl_parsedate(const char *date);
+
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+  "Friday", "Saturday", "Sunday" };
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+struct tzinfo {
+  const char *name;
+  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 */
+  {"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 */
+};
+
+/* returns:
+   -1 no day
+   0 monday - 6 sunday
+*/
+
+static int checkday(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(curl_strequal(check, what[0])) {
+      found=TRUE;
+      break;
+    }
+    what++;
+  }
+  return found?i:-1;
+}
+
+static int checkmonth(char *check)
+{
+  int i;
+  const char * const *what;
+  bool found= FALSE;
+
+  what = &Curl_month[0];
+  for(i=0; i<12; i++) {
+    if(curl_strequal(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(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(curl_strequal(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
+};
+
+static time_t Curl_parsedate(const char *date)
+{
+  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 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;
+      sscanf(date, "%31[A-Za-z]", buf);
+      len = strlen(buf);
+
+      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 -1; /* bad string */
+
+      date += len;
+    }
+    else if(ISDIGIT(*date)) {
+      /* a digit */
+      int val;
+      char *end;
+      if((secnum == -1) &&
+         (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
+        /* time stamp! */
+        date += 8;
+        found = TRUE;
+      }
+      else {
+        val = (int)strtol(date, &end, 10);
+
+        if((tzoff == -1) &&
+           ((end - date) == 4) &&
+           (val < 1300) &&
+           (indate< date) &&
+           ((date[-1] == '+' || date[-1] == '-'))) {
+          /* four digits and a value less than 1300 and it is preceeded with
+             a plus or minus. This is a time zone indication. */
+          found = TRUE;
+          tzoff = (val/100 * 60 + val%100)*60;
+
+          /* the + and - prefix indicates the local time compared to GMT,
+             this we need ther 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 < 1900) {
+            if (yearnum > 70)
+              yearnum += 1900;
+            else
+              yearnum += 2000;
+          }
+          if(mdaynum == -1)
+            dignext = DATE_MDAY;
+        }
+
+        if(!found)
+          return -1;
+
+        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 -1;
+
+#if SIZEOF_TIME_T < 5
+  /* 32 bit time_t can only hold dates to the beginning of 2038 */
+  if(yearnum > 2037)
+    return 0x7fffffff;
+#endif
+
+  tm.tm_sec = secnum;
+  tm.tm_min = minnum;
+  tm.tm_hour = hournum;
+  tm.tm_mday = mdaynum;
+  tm.tm_mon = monnum;
+  tm.tm_year = yearnum - 1900;
+  tm.tm_wday = 0;
+  tm.tm_yday = 0;
+  tm.tm_isdst = 0;
+
+  /* mktime() returns a time_t. time_t is often 32 bits, even on many
+     architectures that feature 64 bit 'long'.
+
+     Some systems have 64 bit time_t and deal with years beyond 2038. However,
+     even some of the systems with 64 bit time_t returns -1 for dates beyond
+     03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+  */
+  t = mktime(&tm);
+
+  /* time zone adjust (cast t to int to compare to negative one) */
+  if(-1 != (int)t) {
+    struct tm *gmt;
+    long delta;
+    time_t t2;
+
+#ifdef HAVE_GMTIME_R
+    /* thread-safe version */
+    struct tm keeptime2;
+    gmt = (struct tm *)gmtime_r(&t, &keeptime2);
+    if(!gmt)
+      return -1; /* illegal date/time */
+    t2 = mktime(gmt);
+#else
+    /* It seems that at least the MSVC version of mktime() doesn't work
+       properly if it gets the 'gmt' pointer passed in (which is a pointer
+       returned from gmtime() pointing to static memory), so instead we copy
+       the tm struct to a local struct and pass a pointer to that struct as
+       input to mktime(). */
+    struct tm gmt2;
+    gmt = gmtime(&t); /* use gmtime_r() if available */
+    if(!gmt)
+      return -1; /* illegal date/time */
+    gmt2 = *gmt;
+    t2 = mktime(&gmt2);
+#endif
+
+    /* Add the time zone diff (between the given timezone and GMT) and the
+       diff between the local time zone and GMT. */
+    delta = (long)((tzoff!=-1?tzoff:0) + (t - t2));
+
+    if((delta>0) && (t + delta < t))
+      return -1; /* time_t overflow */
+
+    t += delta;
+  }
+
+  return t;
+}
+
+time_t curl_getdate(const char *p, const time_t *now)
+{
+  (void)now;
+  return Curl_parsedate(p);
+}

+ 28 - 0
Utilities/cmcurl/parsedate.h

@@ -0,0 +1,28 @@
+#ifndef __PARSEDATE_H
+#define __PARSEDATEL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+extern const char * const Curl_wkday[7];
+extern const char * const Curl_month[12];
+
+#endif

+ 6 - 8
Utilities/cmcurl/progress.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -139,10 +139,8 @@ void Curl_pgrsDone(struct connectdata *conn)
   struct SessionHandle *data = conn->data;
   data->progress.lastshow=0;
   Curl_pgrsUpdate(conn); /* the final (forced) update */
-  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 */
 }
 
 /* reset all times except redirect */
@@ -254,11 +252,11 @@ int Curl_pgrsUpdate(struct connectdata *conn)
          even when not displayed! */
   else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
     if (!data->progress.callback) {
-      if(conn->resume_from)
+      if(data->reqdata.resume_from)
         fprintf(data->set.err,
                 "** Resuming transfer from byte position %" FORMAT_OFF_T
                 "\n",
-                conn->resume_from);
+                data->reqdata.resume_from);
       fprintf(data->set.err,
               "  %% Total    %% Received %% Xferd  Average Speed   Time    Time     Time  Current\n"
               "                                 Dload  Upload   Total   Spent    Left  Speed\n");
@@ -328,7 +326,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
       curl_off_t amount = data->progress.speeder[nowindex]-
         data->progress.speeder[checkindex];
 
-      if(amount > 0xffffffff/1000)
+      if(amount > 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)

+ 6 - 6
Utilities/cmcurl/progress.h

@@ -1,10 +1,10 @@
 #ifndef __PROGRESS_H
 #define __PROGRESS_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
@@ -12,7 +12,7 @@
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -37,7 +37,7 @@ typedef enum {
   TIMER_REDIRECT,
   TIMER_LAST /* must be last */
 } timerid;
-  
+
 void Curl_pgrsDone(struct connectdata *);
 void Curl_pgrsStartNow(struct SessionHandle *data);
 void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);

+ 22 - 12
Utilities/cmcurl/security.c

@@ -46,7 +46,6 @@
 #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
 #include <curl/mprintf.h>
 
-#include "security.h"
 #include <stdlib.h>
 #include <string.h>
 #include <netdb.h>
@@ -55,17 +54,19 @@
 #include <unistd.h>
 #endif
 
+#include "urldata.h"
+#include "krb4.h"
 #include "base64.h"
 #include "sendf.h"
 #include "ftp.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
 
 #define min(a, b)   ((a) < (b) ? (a) : (b))
 
-static struct {
+static const struct {
     enum protection_level level;
     const char *name;
 } level_names[] = {
@@ -80,12 +81,12 @@ name_to_level(const char *name)
 {
   int i;
   for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
-    if(!strncasecmp(level_names[i].name, name, strlen(name)))
+    if(curl_strnequal(level_names[i].name, name, strlen(name)))
       return level_names[i].level;
   return (enum protection_level)-1;
 }
 
-static struct Curl_sec_client_mech *mechs[] = {
+static const struct Curl_sec_client_mech * const mechs[] = {
 #ifdef KRB5
   /* not supported */
 #endif
@@ -277,6 +278,13 @@ Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
   return tx;
 }
 
+ssize_t
+Curl_sec_send(struct connectdata *conn, int num, char *buffer, int length)
+{
+  curl_socket_t fd = conn->sock[num];
+  return (ssize_t)Curl_sec_write(conn, fd, buffer, length);
+}
+
 int
 Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
 {
@@ -297,13 +305,15 @@ int
 Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
 {
   int len;
-  char *buf;
+  unsigned char *buf;
   int code;
 
-  buf = malloc(strlen(s));
-  len = Curl_base64_decode(s + 4, buf); /* XXX */
+  len = Curl_base64_decode(s + 4, &buf); /* XXX */
+  if(len > 0)
+    len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
+  else
+    return -1;
 
-  len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
   if(len < 0) {
     free(buf);
     return -1;
@@ -314,10 +324,10 @@ Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
   if(buf[3] == '-')
     code = 0;
   else
-    sscanf(buf, "%d", &code);
+    sscanf((char *)buf, "%d", &code);
   if(buf[len-1] == '\n')
     buf[len-1] = '\0';
-  strcpy(s, buf);
+  strcpy(s, (char *)buf);
   free(buf);
   return code;
 }
@@ -400,7 +410,7 @@ int
 Curl_sec_login(struct connectdata *conn)
 {
   int ret;
-  struct Curl_sec_client_mech **m;
+  const struct Curl_sec_client_mech * const *m;
   ssize_t nread;
   struct SessionHandle *data=conn->data;
   int ftpcode;

+ 0 - 72
Utilities/cmcurl/security.h

@@ -1,72 +0,0 @@
-#ifndef __SECURITY_H
-#define __SECURITY_H
-/***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* this is a re-write */
-
-#include <stdarg.h>
-#include "urldata.h"  /* for struct connectdata * */
-
-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 *, void*, int, int, void**, struct connectdata *);
-  int (*decode)(void *, void*, int, int, struct connectdata *);
-};
-
-
-#define AUTH_OK         0
-#define AUTH_CONTINUE   1
-#define AUTH_ERROR      2
-
-extern struct Curl_sec_client_mech Curl_krb4_client_mech;
-
-int Curl_sec_fflush_fd(struct connectdata *conn, int fd);
-int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...);
-int Curl_sec_getc (struct connectdata *conn, FILE *);
-int Curl_sec_putc (struct connectdata *conn, int, FILE *);
-int Curl_sec_read (struct connectdata *conn, int, void *, int);
-int Curl_sec_read_msg (struct connectdata *conn, char *, int);
-
-int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list);
-int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...);
-int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list);
-int Curl_sec_write (struct connectdata *conn, int, char *, int);
-
-void Curl_sec_end (struct connectdata *);
-int Curl_sec_login (struct connectdata *);
-void Curl_sec_prot (int, char **);
-int Curl_sec_request_prot (struct connectdata *conn, const char *level);
-void Curl_sec_set_protection_level(struct connectdata *conn);
-void Curl_sec_status (void);
-
-enum protection_level Curl_set_command_prot(struct connectdata *,
-                                            enum protection_level);
-
-#endif

+ 315 - 0
Utilities/cmcurl/select.c

@@ -0,0 +1,315 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifndef HAVE_SELECT
+#error "We can't compile without select() support!"
+#endif
+
+#ifdef __BEOS__
+/* BeOS has FD_SET defined in socket.h */
+#include <socket.h>
+#endif
+
+#ifdef __MSDOS__
+#include <dos.h>  /* delay() */
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "connect.h"
+#include "select.h"
+
+#if defined(USE_WINSOCK) || defined(TPF)
+#define VERIFY_SOCK(x)  /* sockets are not in range [0..FD_SETSIZE] */
+#else
+#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
+#define VERIFY_SOCK(x) do { \
+  if(!VALID_SOCK(x)) { \
+    errno = EINVAL; \
+    return -1; \
+  } \
+} while(0)
+#endif
+
+/*
+ * This is an internal function used for waiting for read or write
+ * events on single file descriptors.  It attempts to replace select()
+ * in order to avoid limits with FD_SETSIZE.
+ *
+ * Return values:
+ *   -1 = system call error
+ *    0 = timeout
+ *    CSELECT_IN | CSELECT_OUT | CSELECT_ERR
+ */
+int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
+{
+#if defined(HAVE_POLL_FINE) || defined(CURL_HAVE_WSAPOLL)
+  struct pollfd pfd[2];
+  int num;
+  int r;
+  int ret;
+
+  num = 0;
+  if (readfd != CURL_SOCKET_BAD) {
+    pfd[num].fd = readfd;
+    pfd[num].events = POLLIN;
+    num++;
+  }
+  if (writefd != CURL_SOCKET_BAD) {
+    pfd[num].fd = writefd;
+    pfd[num].events = POLLOUT;
+    num++;
+  }
+
+#ifdef HAVE_POLL_FINE
+  do {
+    r = poll(pfd, num, timeout_ms);
+  } while((r == -1) && (errno == EINTR));
+#else
+  r = WSAPoll(pfd, num, timeout_ms);
+#endif
+
+  if (r < 0)
+    return -1;
+  if (r == 0)
+    return 0;
+
+  ret = 0;
+  num = 0;
+  if (readfd != CURL_SOCKET_BAD) {
+    if (pfd[num].revents & (POLLIN|POLLHUP))
+      ret |= CSELECT_IN;
+    if (pfd[num].revents & POLLERR) {
+#ifdef __CYGWIN__
+      /* Cygwin 1.5.21 needs this hack to pass test 160 */
+      if (errno == EINPROGRESS)
+        ret |= CSELECT_IN;
+      else
+#endif
+        ret |= CSELECT_ERR;
+    }
+    num++;
+  }
+  if (writefd != CURL_SOCKET_BAD) {
+    if (pfd[num].revents & POLLOUT)
+      ret |= CSELECT_OUT;
+    if (pfd[num].revents & (POLLERR|POLLHUP))
+      ret |= CSELECT_ERR;
+  }
+
+  return ret;
+#else
+  struct timeval timeout;
+  fd_set fds_read;
+  fd_set fds_write;
+  fd_set fds_err;
+  curl_socket_t maxfd;
+  int r;
+  int ret;
+
+  timeout.tv_sec = timeout_ms / 1000;
+  timeout.tv_usec = (timeout_ms % 1000) * 1000;
+
+  if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) {
+    /* According to POSIX we should pass in NULL pointers if we don't want to
+       wait for anything in particular but just use the timeout function.
+       Windows however returns immediately if done so. I copied the MSDOS
+       delay() use from src/main.c that already had this work-around. */
+#ifdef WIN32
+    Sleep(timeout_ms);
+#elif defined(__MSDOS__)
+    delay(timeout_ms);
+#else
+    select(0, NULL, NULL, NULL, &timeout);
+#endif
+    return 0;
+  }
+
+  FD_ZERO(&fds_err);
+  maxfd = (curl_socket_t)-1;
+
+  FD_ZERO(&fds_read);
+  if (readfd != CURL_SOCKET_BAD) {
+    VERIFY_SOCK(readfd);
+    FD_SET(readfd, &fds_read);
+    FD_SET(readfd, &fds_err);
+    maxfd = readfd;
+  }
+
+  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;
+  }
+
+  do {
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
+  } while((r == -1) && (Curl_sockerrno() == EINTR));
+
+  if (r < 0)
+    return -1;
+  if (r == 0)
+    return 0;
+
+  ret = 0;
+  if (readfd != CURL_SOCKET_BAD) {
+    if (FD_ISSET(readfd, &fds_read))
+      ret |= CSELECT_IN;
+    if (FD_ISSET(readfd, &fds_err))
+      ret |= CSELECT_ERR;
+  }
+  if (writefd != CURL_SOCKET_BAD) {
+    if (FD_ISSET(writefd, &fds_write))
+      ret |= CSELECT_OUT;
+    if (FD_ISSET(writefd, &fds_err))
+      ret |= CSELECT_ERR;
+  }
+
+  return ret;
+#endif
+}
+
+/*
+ * 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 too large for FD_SETSIZE.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    1 = number of structures with non zero revent fields
+ */
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
+{
+  int r;
+#ifdef HAVE_POLL_FINE
+  do {
+    r = poll(ufds, nfds, timeout_ms);
+  } while((r == -1) && (errno == EINTR));
+#elif defined(CURL_HAVE_WSAPOLL)
+  r = WSAPoll(ufds, nfds, timeout_ms);
+#else
+  struct timeval timeout;
+  struct timeval *ptimeout;
+  fd_set fds_read;
+  fd_set fds_write;
+  fd_set fds_err;
+  curl_socket_t maxfd;
+  unsigned int i;
+
+  FD_ZERO(&fds_read);
+  FD_ZERO(&fds_write);
+  FD_ZERO(&fds_err);
+  maxfd = (curl_socket_t)-1;
+
+  for (i = 0; i < nfds; i++) {
+    if (ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+#ifndef USE_WINSOCK  /* winsock sockets are not in range [0..FD_SETSIZE] */
+    if (ufds[i].fd >= FD_SETSIZE) {
+      errno = EINVAL;
+      return -1;
+    }
+#endif
+    if (ufds[i].fd > maxfd)
+      maxfd = ufds[i].fd;
+    if (ufds[i].events & POLLIN)
+      FD_SET(ufds[i].fd, &fds_read);
+    if (ufds[i].events & POLLOUT)
+      FD_SET(ufds[i].fd, &fds_write);
+    if (ufds[i].events & POLLERR)
+      FD_SET(ufds[i].fd, &fds_err);
+  }
+
+  if (timeout_ms < 0) {
+    ptimeout = NULL;      /* wait forever */
+  } else {
+    timeout.tv_sec = timeout_ms / 1000;
+    timeout.tv_usec = (timeout_ms % 1000) * 1000;
+    ptimeout = &timeout;
+  }
+
+  do {
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+  } while((r == -1) && (Curl_sockerrno() == EINTR));
+
+  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 |= POLLERR;
+    if (ufds[i].revents != 0)
+      r++;
+  }
+#endif
+  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 */

+ 63 - 0
Utilities/cmcurl/select.h

@@ -0,0 +1,63 @@
+#ifndef __SELECT_H
+#define __SELECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+/* for Vista, use WSAPoll(). */
+#include <winsock2.h>
+#define CURL_HAVE_WSAPOLL
+#else
+
+#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
+
+#define CSELECT_IN   0x01
+#define CSELECT_OUT  0x02
+#define CSELECT_ERR  0x04
+
+int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms);
+
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
+
+#ifdef TPF
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+                       fd_set* excepts, struct timeval* tv);
+#endif
+
+#endif

+ 317 - 150
Utilities/cmcurl/sendf.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -43,16 +43,25 @@
 #include <curl/curl.h>
 #include "urldata.h"
 #include "sendf.h"
-#include "connect.h" /* for the Curl_ourerrno() proto */
+#include "connect.h" /* for the Curl_sockerrno() proto */
+#include "sslgen.h"
+#include "ssh.h"
+#include "multiif.h"
 
 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
 #include <curl/mprintf.h>
 
 #ifdef HAVE_KRB4
-#include "security.h"
+#include "krb4.h"
+#else
+#define Curl_sec_send(a,b,c,d) -1
+#define Curl_sec_read(a,b,c,d) -1
 #endif
+
 #include <string.h>
-#include "curl_memory.h"
+#include "memory.h"
+#include "strerror.h"
+#include "easyif.h" /* for the Curl_convert_from_network prototype */
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -88,10 +97,10 @@ struct curl_slist *curl_slist_append(struct curl_slist *list,
 
   new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
   if (new_item) {
-    char *cuDup = strdup(data);
-    if(cuDup) {
+    char *dup = strdup(data);
+    if(dup) {
       new_item->next = NULL;
-      new_item->data = cuDup;
+      new_item->data = dup;
     }
     else {
       free(new_item);
@@ -132,17 +141,102 @@ void curl_slist_free_all(struct curl_slist *list)
   } while (next);
 }
 
+#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 SessionHandle *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 == TRUE) {
+    /* 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 */
+      memcpy(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++;
+      inPtr++;
+    }
+    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 */
+
 /* Curl_infof() is for info message along the way */
 
 void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
 {
   if(data && data->set.verbose) {
     va_list ap;
+    size_t len;
     char print_buffer[1024 + 1];
     va_start(ap, fmt);
     vsnprintf(print_buffer, 1024, fmt, ap);
     va_end(ap);
-    Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer), NULL);
+    len = strlen(print_buffer);
+    Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
   }
 }
 
@@ -153,25 +247,24 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
 void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
 {
   va_list ap;
+  size_t len;
   va_start(ap, fmt);
+
+  vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
+
   if(data->set.errorbuffer && !data->state.errorbuf) {
-    vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap);
+    snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
     data->state.errorbuf = TRUE; /* wrote error string */
-
-    if(data->set.verbose) {
-      size_t len = strlen(data->set.errorbuffer);
-      bool doneit=FALSE;
-      if(len < CURL_ERROR_SIZE - 1) {
-        doneit = TRUE;
-        data->set.errorbuffer[len] = '\n';
-        data->set.errorbuffer[++len] = '\0';
-      }
-      Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
-      if(doneit)
-        /* cut off the newline again */
-        data->set.errorbuffer[--len]=0;
+  }
+  if(data->set.verbose) {
+    len = strlen(data->state.buffer);
+    if(len < BUFSIZE - 1) {
+      data->state.buffer[len] = '\n';
+      data->state.buffer[++len] = '\0';
     }
+    Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
   }
+
   va_end(ap);
 }
 
@@ -182,7 +275,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
   struct SessionHandle *data = conn->data;
   ssize_t bytes_written;
   size_t write_len;
-  CURLcode res;
+  CURLcode res = CURLE_OK;
   char *s;
   char *sptr;
   va_list ap;
@@ -204,8 +297,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
       break;
 
     if(data->set.verbose)
-      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
-                 conn->host.dispname);
+      Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
 
     if((size_t)bytes_written != write_len) {
       /* if not all was written at once, we must advance the pointer, decrease
@@ -222,9 +314,40 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
   return res;
 }
 
+static ssize_t Curl_plain_send(struct connectdata *conn,
+                               int num,
+                               void *mem,
+                               size_t len)
+{
+  curl_socket_t sockfd = conn->sock[num];
+  ssize_t bytes_written = swrite(sockfd, mem, len);
+
+  if(-1 == bytes_written) {
+    int err = Curl_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 therefor
+         treat both error codes the same here */
+      (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+      )
+      /* this is just a case of EWOULDBLOCK */
+      bytes_written=0;
+    else
+      failf(conn->data, "Send failure: %s",
+            Curl_strerror(conn, err));
+  }
+  return bytes_written;
+}
+
 /*
- * Curl_write() is an internal write function that sends plain (binary) data
- * to the server. Works with plain sockets, SSL or kerberos.
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
  */
 CURLcode Curl_write(struct connectdata *conn,
                     curl_socket_t sockfd,
@@ -234,84 +357,22 @@ CURLcode Curl_write(struct connectdata *conn,
 {
   ssize_t bytes_written;
   CURLcode retcode;
-
-#ifdef USE_SSLEAY
-  /* 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]);
-  /* SSL_write() is said to return 'int' while write() and send() returns
-     'size_t' */
-  if (conn->ssl[num].use) {
-    int err;
-    char error_buffer[120]; /* OpenSSL documents that this must be at least
-                               120 bytes long. */
-    unsigned long sslerror;
-    int rc = SSL_write(conn->ssl[num].handle, mem, (int)len);
-
-    if(rc < 0) {
-      err = SSL_get_error(conn->ssl[num].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 basicly an EWOULDBLOCK
-           equivalent. */
-        *written = 0;
-        return CURLE_OK;
-      case SSL_ERROR_SYSCALL:
-        failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n",
-              Curl_ourerrno());
-        return CURLE_SEND_ERROR;
-      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();
-        failf(conn->data, "SSL_write() error: %s\n",
-              ERR_error_string(sslerror, error_buffer));
-        return CURLE_SEND_ERROR;
-      }
-      /* a true error */
-      failf(conn->data, "SSL_write() return error %d\n", err);
-      return CURLE_SEND_ERROR;
-    }
-    bytes_written = rc;
-  }
-  else {
-#else
-  (void)conn;
-#endif
-#ifdef HAVE_KRB4
-    if(conn->sec_complete) {
-      bytes_written = Curl_sec_write(conn, sockfd, mem, len);
-    }
-    else
-#endif /* HAVE_KRB4 */
-    {
-      bytes_written = (ssize_t)swrite(sockfd, mem, len);
-    }
-    if(-1 == bytes_written) {
-      int err = Curl_ourerrno();
 
-      if(
-#ifdef WSAEWOULDBLOCK
-        /* This is how Windows does it */
-        (WSAEWOULDBLOCK == err)
-#else
-        /* As pointed out by Christophe Demory on March 11 2003, errno
-           may be EWOULDBLOCK or on some systems EAGAIN when it returned
-           due to its inability to send off data without blocking. We
-           therefor treat both error codes the same here */
-        (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
-#endif
-        )
-        /* this is just a case of EWOULDBLOCK */
-        bytes_written=0;
-    }
-#ifdef USE_SSLEAY
-  }
-#endif
+  if (conn->ssl[num].use)
+    /* only TRUE if SSL enabled */
+    bytes_written = Curl_ssl_send(conn, num, mem, len);
+#ifdef USE_LIBSSH2
+  else if (conn->protocol & PROT_SCP)
+    bytes_written = Curl_scp_send(conn, num, mem, len);
+  else if (conn->protocol & PROT_SFTP)
+    bytes_written = Curl_sftp_send(conn, num, mem, len);
+#endif /* !USE_LIBSSH2 */
+  else if(conn->sec_complete)
+    /* only TRUE if krb4 enabled */
+    bytes_written = Curl_sec_send(conn, num, mem, len);
+  else
+    bytes_written = Curl_plain_send(conn, num, mem, len);
 
   *written = bytes_written;
   retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
@@ -324,23 +385,53 @@ CURLcode Curl_write(struct connectdata *conn,
    The bit pattern defines to what "streams" to write to. Body and/or header.
    The defines are in sendf.h of course.
  */
-CURLcode Curl_client_write(struct SessionHandle *data,
+CURLcode Curl_client_write(struct connectdata *conn,
                            int type,
                            char *ptr,
                            size_t len)
 {
+  struct SessionHandle *data = conn->data;
   size_t wrote;
 
+  if (data->state.cancelled) {
+      /* We just suck everything into a black hole */
+      return CURLE_OK;
+  }
+
   if(0 == len)
     len = strlen(ptr);
 
   if(type & CLIENTWRITE_BODY) {
-    wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+    if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') {
+#ifdef CURL_DOES_CONVERSIONS
+      /* convert from the network encoding */
+      size_t rc;
+      rc = Curl_convert_from_network(data, ptr, len);
+      /* Curl_convert_from_network calls failf if unsuccessful */
+      if(rc != CURLE_OK)
+        return rc;
+#endif /* CURL_DOES_CONVERSIONS */
+
+#ifdef CURL_DO_LINEEND_CONV
+      /* convert end-of-line markers */
+      len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
+    }
+    /* If the previous block of data ended with CR and this block of data is
+       just a NL, then the length might be zero */
+    if (len) {
+      wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+    }
+    else {
+      wrote = len;
+    }
+
     if(wrote != len) {
       failf (data, "Failed writing body");
       return CURLE_WRITE_ERROR;
     }
   }
+
   if((type & CLIENTWRITE_HEADER) &&
      (data->set.fwrite_header || data->set.writeheader) ) {
     /*
@@ -350,6 +441,9 @@ CURLcode Curl_client_write(struct SessionHandle *data,
     curl_write_callback writeit=
       data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite;
 
+    /* Note: The header is in the host encoding
+       regardless of the ftp transfer mode (ASCII/Image) */
+
     wrote = writeit(ptr, 1, len, data->set.writeheader);
     if(wrote != len) {
       failf (data, "Failed writing header");
@@ -360,6 +454,10 @@ CURLcode Curl_client_write(struct SessionHandle *data,
   return CURLE_OK;
 }
 
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
 /*
  * Internal read-from-socket function. This is meant to deal with plain
  * sockets, SSL sockets and kerberos sockets.
@@ -370,11 +468,15 @@ CURLcode Curl_client_write(struct SessionHandle *data,
 int Curl_read(struct connectdata *conn, /* connection data */
               curl_socket_t sockfd,     /* read from this socket */
               char *buf,                /* store read data here */
-              size_t buffersize,        /* max amount to read */
+              size_t sizerequested,     /* max amount to read */
               ssize_t *n)               /* amount bytes read */
 {
   ssize_t nread;
-#ifdef USE_SSLEAY
+  size_t bytesfromsocket = 0;
+  char *buffertofill = NULL;
+  bool pipelining = (bool)(conn->data->multi &&
+                     Curl_multi_canPipeline(conn->data->multi));
+
   /* 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. */
@@ -382,61 +484,75 @@ int Curl_read(struct connectdata *conn, /* connection data */
 
   *n=0; /* reset amount to zero */
 
-  if (conn->ssl[num].use) {
-    nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, (int)buffersize);
-
-    if(nread < 0) {
-      /* failed SSL_read */
-      int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
-
-      switch(err) {
-      case SSL_ERROR_NONE: /* this is not an error */
-      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() */
-        return -1; /* basicly EWOULDBLOCK */
-      default:
-        /* openssl/ssl.h says "look at error stack/return value/errno" */
-        {
-          char error_buffer[120]; /* OpenSSL documents that this must be at
-                                     least 120 bytes long. */
-          unsigned long sslerror = ERR_get_error();
-          failf(conn->data, "SSL read: %s, errno %d",
-                ERR_error_string(sslerror, error_buffer),
-                Curl_ourerrno() );
-        }
-        return CURLE_RECV_ERROR;
-      }
+  /* If session can pipeline, check connection buffer  */
+  if(pipelining) {
+    size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
+
+    /* Copy from our master buffer first if we have some unread data there*/
+    if (bytestocopy > 0) {
+      memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
+      conn->read_pos += bytestocopy;
+      conn->bits.stream_was_rewound = FALSE;
+
+      *n = (ssize_t)bytestocopy;
+      return CURLE_OK;
     }
+    /* If we come here, it means that there is no data to read from the buffer,
+     * so we read from the socket */
+    bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));
+    buffertofill = conn->master_buffer;
   }
   else {
-#else
-    (void)conn;
-#endif
-    *n=0; /* reset amount to zero */
-#ifdef HAVE_KRB4
+    bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ?
+                          conn->data->set.buffer_size : BUFSIZE);
+    buffertofill = buf;
+  }
+
+  if(conn->ssl[num].use) {
+    nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket);
+
+    if(nread == -1) {
+      return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
+    }
+  }
+#ifdef USE_LIBSSH2
+  else if (conn->protocol & PROT_SCP) {
+    nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket);
+    /* TODO: return CURLE_OK also for nread <= 0
+             read failures and timeouts ? */
+  }
+  else if (conn->protocol & PROT_SFTP) {
+    nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket);
+  }
+#endif /* !USE_LIBSSH2 */
+  else {
     if(conn->sec_complete)
-      nread = Curl_sec_read(conn, sockfd, buf, buffersize);
+      nread = Curl_sec_read(conn, sockfd, buffertofill,
+                            bytesfromsocket);
     else
-#endif
-      nread = sread(sockfd, buf, buffersize);
+      nread = sread(sockfd, buffertofill, bytesfromsocket);
 
     if(-1 == nread) {
-      int err = Curl_ourerrno();
-#ifdef WIN32
+      int err = Curl_sockerrno();
+#ifdef USE_WINSOCK
       if(WSAEWOULDBLOCK == err)
 #else
       if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
 #endif
         return -1;
     }
+  }
+
+  if (nread >= 0) {
+    if(pipelining) {
+      memcpy(buf, conn->master_buffer, nread);
+      conn->buf_len = nread;
+      conn->read_pos = nread;
+    }
 
-#ifdef USE_SSLEAY
+    *n += nread;
   }
-#endif /* USE_SSLEAY */
-  *n = nread;
+
   return CURLE_OK;
 }
 
@@ -447,6 +563,46 @@ static int showit(struct SessionHandle *data, curl_infotype type,
   static const char * const s_infotype[CURLINFO_END] = {
     "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
 
+#ifdef CURL_DOES_CONVERSIONS
+  char buf[BUFSIZE+1];
+  size_t conv_size = 0;
+
+  switch(type) {
+  case CURLINFO_HEADER_OUT:
+    /* assume output headers are ASCII */
+    /* copy the data into my buffer so the original is unchanged */
+    if (size > BUFSIZE) {
+      size = BUFSIZE; /* truncate if necessary */
+      buf[BUFSIZE] = '\0';
+    }
+    conv_size = size;
+    memcpy(buf, ptr, 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 everthing 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)
     return (*data->set.fdebug)(data, type, ptr, size,
                                data->set.debugdata);
@@ -457,6 +613,12 @@ static int showit(struct SessionHandle *data, curl_infotype type,
   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;
@@ -465,18 +627,22 @@ static int showit(struct SessionHandle *data, curl_infotype type,
 }
 
 int Curl_debug(struct SessionHandle *data, curl_infotype type,
-               char *ptr, size_t size, char *host)
+               char *ptr, size_t size,
+               struct connectdata *conn)
 {
   int rc;
-  if(data->set.printhost && host) {
+  if(data->set.printhost && conn && conn->host.dispname) {
     char buffer[160];
     const char *t=NULL;
+    const char *w="Data";
     switch (type) {
     case CURLINFO_HEADER_IN:
+      w = "Header";
     case CURLINFO_DATA_IN:
       t = "from";
       break;
     case CURLINFO_HEADER_OUT:
+      w = "Header";
     case CURLINFO_DATA_OUT:
       t = "to";
       break;
@@ -485,7 +651,8 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
     }
 
     if(t) {
-      snprintf(buffer, sizeof(buffer), "[Data %s %s]", t, host);
+      snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
+               conn->host.dispname);
       rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
       if(rc)
         return rc;

+ 24 - 8
Utilities/cmcurl/sendf.h

@@ -1,18 +1,18 @@
 #ifndef __SENDF_H
 #define __SENDF_H
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -28,16 +28,31 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
 void Curl_infof(struct SessionHandle *, const char *fmt, ...);
 void Curl_failf(struct SessionHandle *, const char *fmt, ...);
 
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+#if defined(__GNUC__)
+/* This style of variable argument macros is a gcc extension */
+#define infof(x...) /*ignore*/
+#else
+/* C99 compilers could use this if we could detect them */
+/*#define infof(...) */
+/* Cast the args to void to make them a noop, side effects notwithstanding */
+#define infof (void)
+#endif
+#else
 #define infof Curl_infof
+#endif
 #define failf Curl_failf
 
 #define CLIENTWRITE_BODY   1
 #define CLIENTWRITE_HEADER 2
 #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
 
-CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr,
+CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
                            size_t len);
 
+void Curl_read_rewind(struct connectdata *conn,
+                      size_t extraBytesRead);
+
 /* internal read-function, does plain socket, SSL and krb4 */
 int Curl_read(struct connectdata *conn, curl_socket_t sockfd,
               char *buf, size_t buffersize,
@@ -50,7 +65,8 @@ CURLcode Curl_write(struct connectdata *conn,
 
 /* the function used to output verbose information */
 int Curl_debug(struct SessionHandle *handle, curl_infotype type,
-               char *data, size_t size, char *host);
+               char *data, size_t size,
+               struct connectdata *conn);
 
 
 #endif

+ 198 - 110
Utilities/cmcurl/setup.h

@@ -1,5 +1,5 @@
-#ifndef __SETUP_H
-#define __SETUP_H
+#ifndef __LIB_CURL_SETUP_H
+#define __LIB_CURL_SETUP_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,37 +24,104 @@
  ***************************************************************************/
 
 #ifdef HTTP_ONLY
+#define CURL_DISABLE_TFTP
 #define CURL_DISABLE_FTP
 #define CURL_DISABLE_LDAP
 #define CURL_DISABLE_TELNET
 #define CURL_DISABLE_DICT
 #define CURL_DISABLE_FILE
-#define CURL_DISABLE_GOPHER
-#endif
+#endif /* HTTP_ONLY */
 
 #if !defined(WIN32) && defined(__WIN32__)
-/* This should be a good Borland fix. Alexander J. Oss told us! */
+/* Borland fix */
+#define WIN32
+#endif
+
+#if !defined(WIN32) && defined(_WIN32)
+/* VS2005 on x64 fix */
 #define WIN32
 #endif
 
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
 #ifdef HAVE_CONFIG_H
-#include "config.h" /* the configure script results */
+#include "config.h"
+#else
+
+/*
+#ifdef _WIN32_WCE
+#include "config-win32ce.h"
 #else
 #ifdef WIN32
-/* hand-modified win32 config.h! */
 #include "config-win32.h"
 #endif
 #endif
+*/
 
 #ifdef macintosh
-/* hand-modified MacOS config.h! */
 #include "config-mac.h"
 #endif
+
 #ifdef AMIGA
-/* hand-modified AmigaOS config.h! */
 #include "amigaos.h"
 #endif
 
+#ifdef TPF
+#include "config-tpf.h" /* hand-modified TPF config.h */
+/* change which select is used for libcurl */
+#define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preproessor 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 independant block.  Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) 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
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
+#  ifdef HAVE_WINSOCK2_H
+#    include <winsock2.h>
+#    ifdef HAVE_WS2TCPIP_H
+#       include <ws2tcpip.h>
+#    endif
+#  else
+#    ifdef HAVE_WINSOCK_H
+#      include <winsock.h>
+#    endif
+#  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
+
+
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -62,7 +129,7 @@
 #define FALSE 0
 #endif
 
-#if !defined(__cplusplus) && !defined(__BEOS__)
+#if !defined(__cplusplus) && !defined(__BEOS__) && !defined(__ECOS) && !defined(typedef_bool)
 typedef unsigned char bool;
 #define typedef_bool
 #endif
@@ -74,7 +141,7 @@ typedef unsigned char bool;
 #ifdef _MSC_VER
 #define LONG_LONG __int64
 #define ENABLE_64BIT
-#endif
+#endif /* _MSC_VER */
 #endif /* HAVE_LONGLONG */
 
 #ifndef SIZEOF_CURL_OFF_T
@@ -89,12 +156,13 @@ typedef unsigned char bool;
 #define FORMAT_OFF_T "lld"
 #else
 #define FORMAT_OFF_T "ld"
-#endif
+#endif /* SIZEOF_CURL_OFF_T */
 
-#ifdef NEED_REENTRANT
-/* Solaris machines needs _REENTRANT set for a few function prototypes and
-   things to appear in the #include files. We need to #define it before all
-   #include files */
+#ifndef _REENTRANT
+/* Solaris needs _REENTRANT set for a few function prototypes and things to
+   appear in the #include files. We need to #define it before all #include
+   files. Unixware needs it to build proper reentrant code. Others may also
+   need it. */
 #define _REENTRANT
 #endif
 
@@ -108,25 +176,34 @@ typedef unsigned char bool;
 #include <floss.h>
 #endif
 
-#if defined(HAVE_X509_H) && defined(HAVE_SSL_H) && defined(HAVE_RSA_H) && \
-defined(HAVE_PEM_H) && defined(HAVE_ERR_H) && defined(HAVE_CRYPTO_H) && \
-defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
-  /* the six important includes files all exist and so do both libs,
-     defined SSLeay usage */
-#define USE_SSLEAY 1
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
 #endif
-#if defined(HAVE_OPENSSL_X509_H) && defined(HAVE_OPENSSL_SSL_H) && \
-defined(HAVE_OPENSSL_RSA_H) && defined(HAVE_OPENSSL_PEM_H) && \
-defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_CRYPTO_H) && \
-defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
-  /* the six important includes files all exist and so do both libs,
-     defined SSLeay usage */
-#define USE_SSLEAY 1
-#define USE_OPENSSL 1
+
+/*
+ * PellesC cludge section (yikes);
+ *  - It has 'ssize_t', but it is in <unistd.h>. The way the headers
+ *    on Win32 are included, forces me to include this header here.
+ *  - sys_nerr, EINTR is missing in v4.0 or older.
+ */
+#ifdef __POCC__
+  #include <sys/types.h>
+  #include <unistd.h>
+  #if (__POCC__ <= 400)
+  #define sys_nerr EILSEQ  /* for strerror.c */
+  #define EINTR    -1      /* for select.c */
+  #endif
 #endif
 
-#ifndef STDC_HEADERS /* no standard C headers! */
-#include <curl/stdcheaders.h>
+/*
+ * Salford-C cludge 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 <clib.h>
 #endif
 
 #if defined(CURLDEBUG) && defined(HAVE_ASSERT_H)
@@ -136,20 +213,22 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
 #define curlassert(x)
 #endif
 
-#ifdef MSG_NOSIGNAL
-/* If we have the MSG_NOSIGNAL define, we make sure to use that in the forth
-   argument to send() and recv() */
-#define SEND_4TH_ARG MSG_NOSIGNAL
-#define HAVE_MSG_NOSIGNAL 1 /* we have MSG_NOSIGNAL */
+
+/* To make large file support transparent even on Windows */
+#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
+#include <sys/stat.h>   /* must come first before we redefine stat() */
+#include <io.h>
+#define lseek(x,y,z) _lseeki64(x, y, z)
+#define struct_stat struct _stati64
+#define stat(file,st) _stati64(file,st)
+#define fstat(fd,st) _fstati64(fd,st)
 #else
-#define SEND_4TH_ARG 0
-#endif
+#define struct_stat struct stat
+#endif /* Win32 with large file support */
 
 
-/* Below we define four functions. They should
+/* Below we define some functions. They should
    1. close a socket
-   2. read from a socket
-   3. write to a socket
 
    4. set the SIGALRM signal timeout
    5. set dir/file naming defines
@@ -157,49 +236,24 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
 
 #ifdef WIN32
 
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN  /* Prevent including <winsock*.h> in <windows.h> */
-#endif
-
-#if (defined(ENABLE_IPV6) || defined(CURLDEBUG)) && defined(_MSC_VER) && \
-    (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0500)
-/*
- * Needed to pull in the real getaddrinfo() and not the inline version
- * in <wspiAPI.H> which doesn't support IPv6 (IPv4 only). <wspiAPI.H> is
- * included from <ws2tcpip.h> for <= 0x0500 SDKs.
- */
-#undef  _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-
-#include <winsock2.h>        /* required by telnet.c */
-
-#if defined(ENABLE_IPV6) || defined(USE_SSLEAY)
-#include <ws2tcpip.h>
-#endif
-
-#if !defined(__GNUC__) || defined(__MINGW32__)
+#if !defined(__CYGWIN__)
 #define sclose(x) closesocket(x)
-#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
-#define swrite(x,y,z) (size_t)send(x,y,z, SEND_4TH_ARG)
+
 #undef HAVE_ALARM
 #else
      /* gcc-for-win is still good :) */
 #define sclose(x) close(x)
-#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
-#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
 #define HAVE_ALARM
-#endif
+#endif /* !GNU or mingw */
 
 #define DIR_CHAR      "\\"
 #define DOT_CHAR      "_"
 
-#else
+#else /* WIN32 */
 
-#ifdef DJGPP
+#ifdef MSDOS  /* Watt-32 */
+#include <sys/ioctl.h>
 #define sclose(x)         close_s(x)
-#define sread(x,y,z)      read_s(x,y,z)
-#define swrite(x,y,z)     write_s(x,y,z)
 #define select(n,r,w,x,t) select_s(n,r,w,x,t)
 #define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
 #define IOCTL_3_ARGS
@@ -208,21 +262,17 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
 #undef word
 #endif
 
-#else
+#else /* MSDOS */
 
 #ifdef __BEOS__
 #define sclose(x) closesocket(x)
-#define sread(x,y,z) (ssize_t)recv(x,y,z, SEND_4TH_ARG)
-#define swrite(x,y,z) (ssize_t)send(x,y,z, SEND_4TH_ARG)
-#else
+#else /* __BEOS__ */
 #define sclose(x) close(x)
-#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
-#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
-#endif
+#endif /* __BEOS__ */
 
 #define HAVE_ALARM
 
-#endif
+#endif /* MSDOS */
 
 #ifdef _AMIGASF
 #undef HAVE_ALARM
@@ -231,9 +281,11 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
 #endif
 
 #define DIR_CHAR      "/"
+#ifndef DOT_CHAR
 #define DOT_CHAR      "."
+#endif
 
-#ifdef DJGPP
+#ifdef MSDOS
 #undef DOT_CHAR
 #define DOT_CHAR      "_"
 #endif
@@ -242,20 +294,7 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
 int fileno( FILE *stream);
 #endif
 
-#endif
-
-/* now typedef our socket type */
-#ifdef WIN32
-typedef SOCKET curl_socket_t;
-#define CURL_SOCKET_BAD INVALID_SOCKET
-#else
-typedef int curl_socket_t;
-#define CURL_SOCKET_BAD -1
-#endif
-
-#if defined(ENABLE_IPV6) && defined(USE_ARES)
-#error "ares does not yet support IPv6. Disable IPv6 or ares and rebuild"
-#endif
+#endif /* WIN32 */
 
 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
     !defined(__LCC__)  /* lcc-win32 doesn't have _beginthreadex() */
@@ -266,29 +305,78 @@ typedef int curl_socket_t;
 #endif
 #endif
 
-#ifdef mpeix
-#define IOCTL_3_ARGS
+/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
+   _beginthreadex() is not available */
+#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES)
+#undef USE_THREADING_GETADDRINFO
+#undef USE_THREADING_GETHOSTBYNAME
+#define CURL_NO__BEGINTHREADEX
 #endif
 
-#ifndef ECONNRESET
-#ifdef WSAECONNRESET
-#define ECONNRESET WSAECONNRESET
-#else
-/* This will effectively prevent the code from working in this particular
-   aspect, but it still compile fine! */
-#define ECONNRESET 10000
+/*
+ * 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.
+ */
+
+#ifdef _MSC_VER
+#if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
 #endif
 #endif
 
+#ifdef mpeix
+#define IOCTL_3_ARGS
+#endif
+
 #ifdef NETWARE
 #undef HAVE_ALARM
 #endif
 
-#ifdef HAVE_LIBIDN
-/* This could benefit from additional checks that some of the used/important
-   header files are present as well before we define the USE_* define. */
+#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H)
+/* The lib was present and the tld.h header (which is missing in libidn 0.3.X
+   but we only work with libidn 0.4.1 or later) */
 #define USE_LIBIDN
+#endif
+
+#ifndef SIZEOF_TIME_T
+/* assume default size of time_t to be 32 bit */
+#define SIZEOF_TIME_T 4
+#endif
+
 #define LIBIDN_REQUIRED_VERSION "0.4.1"
+
+#ifdef __UCLIBC__
+#define HAVE_INET_NTOA_R_2_ARGS 1
+#endif
+
+#if defined(USE_GNUTLS) || defined(USE_SSLEAY)
+#define USE_SSL    /* Either OpenSSL || GnuTLS */
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
+#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI)
+#define USE_NTLM
+#endif
+#endif
+
+#ifdef CURLDEBUG
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x)
+#endif
+
+/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
+#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
+#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef __SETUP_ONCE_H
+#include "setup_once.h"
 #endif
 
-#endif /* __CONFIG_H */
+#endif /* __LIB_CURL_SETUP_H */

+ 153 - 0
Utilities/cmcurl/setup_once.h

@@ -0,0 +1,153 @@
+#ifndef __SETUP_ONCE_H
+#define __SETUP_ONCE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+
+/********************************************************************
+ *                              NOTICE                              *
+ *                             ========                             *
+ *                                                                  *
+ *  Content of header files lib/setup_once.h and ares/setup_once.h  *
+ *  must be kept in sync. Modify the other one if you change this.  *
+ *                                                                  *
+ ********************************************************************/
+
+
+/*
+ * 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
+
+
+/*
+ * 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.
+ */
+
+#ifdef HAVE_RECV
+#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 */
+
+#ifdef 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_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 */
+
+
+/*
+ * Uppercase macro versions of ANSI/ISO is*() functions/macros which
+ * avoid negative number inputs with argument byte codes > 127.
+ */
+
+#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)))
+
+
+/*
+ * 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
+
+
+/*
+ * Default return type for signal handlers.
+ */
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+
+#endif /* __SETUP_ONCE_H */
+

+ 4 - 4
Utilities/cmcurl/share.c

@@ -28,7 +28,7 @@
 #include <curl/curl.h>
 #include "urldata.h"
 #include "share.h"
-#include "curl_memory.h"
+#include "memory.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -77,7 +77,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
       }
       break;
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
     case CURL_LOCK_DATA_COOKIE:
       if (!share->cookies) {
         share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
@@ -108,7 +108,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
         }
         break;
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
       case CURL_LOCK_DATA_COOKIE:
         if (share->cookies) {
           Curl_cookie_cleanup(share->cookies);
@@ -171,7 +171,7 @@ curl_share_cleanup(CURLSH *sh)
   if(share->hostcache)
     Curl_hash_destroy(share->hostcache);
 
-#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
   if(share->cookies)
     Curl_cookie_cleanup(share->cookies);
 #endif   /* CURL_DISABLE_HTTP */

+ 20 - 19
Utilities/cmcurl/share.h

@@ -2,18 +2,18 @@
 #define __CURL_SHARE_H
 
 /***************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
- * 
+ *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
  * furnished to do so, under the terms of the COPYING file.
@@ -28,28 +28,29 @@
 #include <curl/curl.h>
 #include "cookie.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;
-  volatile unsigned int dirty;
-  
+  CURL_VOLATILE unsigned int dirty;
+
   curl_lock_function lockfunc;
   curl_unlock_function unlockfunc;
   void *clientdata;
 
-  curl_hash *hostcache;
+  struct curl_hash *hostcache;
   struct CookieInfo *cookies;
 };
 
-CURLSHcode Curl_share_lock (
-    struct SessionHandle *, 
-    curl_lock_data,
-    curl_lock_access
-    );
-
-CURLSHcode Curl_share_unlock (
-    struct SessionHandle *, 
-    curl_lock_data
-    );
+CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data,
+                            curl_lock_access);
+CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data);
 
 #endif /* __CURL_SHARE_H */

+ 38 - 0
Utilities/cmcurl/sockaddr.h

@@ -0,0 +1,38 @@
+#ifndef __SOCKADDR_H
+#define __SOCKADDR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+struct Curl_sockaddr_storage {
+  struct sockaddr_storage buffer;
+};
+#else
+struct Curl_sockaddr_storage {
+  char buffer[256];   /* this should be big enough to fit a lot */
+};
+#endif
+
+#endif /* __SOCKADDR_H */

+ 585 - 0
Utilities/cmcurl/socks.c

@@ -0,0 +1,585 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "select.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * 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 behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+static int 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 */
+                         long conn_timeout)        /* timeout for data wait
+                                                      relative to
+                                                      conn->created */
+{
+  ssize_t nread;
+  ssize_t allread = 0;
+  int result;
+  struct timeval tvnow;
+  long conntime;
+  *n = 0;
+  do {
+    tvnow = Curl_tvnow();
+    /* calculating how long connection is establishing */
+    conntime = Curl_tvdiff(tvnow, conn->created);
+    if(conntime > conn_timeout) {
+      /* we already got the timeout */
+      result = ~CURLE_OK;
+      break;
+    }
+    if(Curl_select(sockfd, CURL_SOCKET_BAD,
+                   (int)(conn_timeout - conntime)) <= 0) {
+      result = ~CURLE_OK;
+      break;
+    }
+    result = Curl_read(conn, sockfd, buf, buffersize, &nread);
+    if(result)
+      break;
+
+    if(buffersize == nread) {
+      allread += nread;
+      *n = allread;
+      result = CURLE_OK;
+      break;
+    }
+    buffersize -= nread;
+    buf += nread;
+    allread += nread;
+  } while(1);
+  return result;
+}
+
+/*
+* This function logs in to a SOCKS4 proxy and sends the specifics to the final
+* destination server.
+*
+* Reference :
+*   http://socks.permeo.com/protocol/socks4.protocol
+*
+* Note :
+*   Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
+*   Nonsupport "Identification Protocol (RFC1413)"
+*/
+CURLcode Curl_SOCKS4(const char *proxy_name,
+                     struct connectdata *conn)
+{
+  unsigned char socksreq[262]; /* room for SOCKS4 request incl. user id */
+  int result;
+  CURLcode code;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  long timeout;
+  struct SessionHandle *data = conn->data;
+
+  /* get timeout */
+  if(data->set.timeout && data->set.connecttimeout) {
+    if (data->set.timeout < data->set.connecttimeout)
+      timeout = data->set.timeout*1000;
+    else
+      timeout = data->set.connecttimeout*1000;
+  }
+  else if(data->set.timeout)
+    timeout = data->set.timeout*1000;
+  else if(data->set.connecttimeout)
+    timeout = data->set.connecttimeout*1000;
+  else
+    timeout = DEFAULT_CONNECT_TIMEOUT;
+
+  Curl_nonblock(sock, FALSE);
+
+  /*
+   * 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 */
+  *((unsigned short*)&socksreq[2]) = htons(conn->remote_port);
+
+  /* DNS resolve */
+  {
+    struct Curl_dns_entry *dns;
+    Curl_addrinfo *hp=NULL;
+    int rc;
+
+    rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
+
+    if(rc == CURLRESOLV_ERROR)
+      return CURLE_COULDNT_RESOLVE_PROXY;
+
+    if(rc == CURLRESOLV_PENDING)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+
+    /*
+     * 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) {
+      char buf[64];
+      unsigned short ip[4];
+      Curl_printable_address(hp, buf, sizeof(buf));
+
+      if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
+                      &ip[0], &ip[1], &ip[2], &ip[3])) {
+        /* Set DSTIP */
+        socksreq[4] = (unsigned char)ip[0];
+        socksreq[5] = (unsigned char)ip[1];
+        socksreq[6] = (unsigned char)ip[2];
+        socksreq[7] = (unsigned char)ip[3];
+      }
+      else
+        hp = NULL; /* fail! */
+
+      Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+
+    }
+    if(!hp) {
+      failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
+            conn->host.name);
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+  }
+
+  /*
+   * This is currently not supporting "Identification Protocol (RFC1413)".
+   */
+  socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
+  if (proxy_name)
+    strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8);
+
+  /*
+   * Make connection
+   */
+  {
+    ssize_t actualread;
+    ssize_t written;
+    int packetsize = 9 +
+      (int)strlen((char*)socksreq + 8); /* size including NUL */
+
+    /* Send request */
+    code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
+    if ((code != CURLE_OK) || (written != packetsize)) {
+      failf(data, "Failed to send SOCKS4 connect request.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    packetsize = 8; /* receive data size */
+
+    /* Receive response */
+    result = blockread_all(conn, sock, (char *)socksreq, packetsize,
+                           &actualread, timeout);
+    if ((result != CURLE_OK) || (actualread != packetsize)) {
+      failf(data, "Failed to receive SOCKS4 connect request ack.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /*
+     * 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 4.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* Result */
+    switch(socksreq[1])
+    {
+    case 90:
+      infof(data, "SOCKS4 request granted.\n");
+      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 int)ntohs(*(unsigned short*)(&socksreq[8])),
+            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 int)ntohs(*(unsigned short*)(&socksreq[8])),
+            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 int)ntohs(*(unsigned short*)(&socksreq[8])),
+            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 int)ntohs(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  Curl_nonblock(sock, 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_name,
+                     const char *proxy_password,
+                     struct connectdata *conn)
+{
+  /*
+    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[600]; /* room for large user/pw (255 max each) */
+  ssize_t actualread;
+  ssize_t written;
+  int result;
+  CURLcode code;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  struct SessionHandle *data = conn->data;
+  long timeout;
+
+  /* get timeout */
+  if(data->set.timeout && data->set.connecttimeout) {
+    if (data->set.timeout < data->set.connecttimeout)
+      timeout = data->set.timeout*1000;
+    else
+      timeout = data->set.connecttimeout*1000;
+  }
+  else if(data->set.timeout)
+    timeout = data->set.timeout*1000;
+  else if(data->set.connecttimeout)
+    timeout = data->set.connecttimeout*1000;
+  else
+    timeout = DEFAULT_CONNECT_TIMEOUT;
+
+  Curl_nonblock(sock, TRUE);
+
+  /* wait until socket gets connected */
+  result = Curl_select(CURL_SOCKET_BAD, sock, (int)timeout);
+
+  if(-1 == result) {
+    failf(conn->data, "SOCKS5: no connection here");
+    return CURLE_COULDNT_CONNECT;
+  }
+  else if(0 == result) {
+    failf(conn->data, "SOCKS5: connection timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(result & CSELECT_ERR) {
+    failf(conn->data, "SOCKS5: error occured during connection");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  socksreq[0] = 5; /* version */
+  socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
+  socksreq[2] = 0; /* no authentication */
+  socksreq[3] = 2; /* username/password */
+
+  Curl_nonblock(sock, FALSE);
+
+  code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+                      &written);
+  if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
+    failf(data, "Unable to send initial SOCKS5 request.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  Curl_nonblock(sock, TRUE);
+
+  result = Curl_select(sock, CURL_SOCKET_BAD, (int)timeout);
+
+  if(-1 == result) {
+    failf(conn->data, "SOCKS5 nothing to read");
+    return CURLE_COULDNT_CONNECT;
+  }
+  else if(0 == result) {
+    failf(conn->data, "SOCKS5 read timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(result & CSELECT_ERR) {
+    failf(conn->data, "SOCKS5 read error occured");
+    return CURLE_RECV_ERROR;
+  }
+
+  Curl_nonblock(sock, FALSE);
+
+  result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, timeout);
+  if ((result != CURLE_OK) || (actualread != 2)) {
+    failf(data, "Unable to receive initial SOCKS5 response.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if (socksreq[0] != 5) {
+    failf(data, "Received invalid version in initial SOCKS5 response.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  if (socksreq[1] == 0) {
+    /* Nothing to do, no authentication needed */
+    ;
+  }
+  else if (socksreq[1] == 2) {
+    /* Needs user name and password */
+    size_t userlen, pwlen;
+    int len;
+    if(proxy_name && proxy_password) {
+      userlen = strlen(proxy_name);
+      pwlen = proxy_password?strlen(proxy_password):0;
+    }
+    else {
+      userlen = 0;
+      pwlen = 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++] = (char) userlen;
+    memcpy(socksreq + len, proxy_name, (int) userlen);
+    len += userlen;
+    socksreq[len++] = (char) pwlen;
+    memcpy(socksreq + len, proxy_password, (int) pwlen);
+    len += pwlen;
+
+    code = Curl_write(conn, sock, (char *)socksreq, len, &written);
+    if ((code != CURLE_OK) || (len != written)) {
+      failf(data, "Failed to send SOCKS5 sub-negotiation request.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
+                         timeout);
+    if ((result != CURLE_OK) || (actualread != 2)) {
+      failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* 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! */
+  }
+  else {
+    /* error */
+    if (socksreq[1] == 1) {
+      failf(data,
+            "SOCKS5 GSSAPI per-message authentication is not supported.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    else if (socksreq[1] == 255) {
+      if (!proxy_name || !*proxy_name) {
+        failf(data,
+              "No authentication method was acceptable. (It is quite likely"
+              " that the SOCKS5 server wanted a username/password, since none"
+              " was supplied to the server on this connection.)");
+      }
+      else {
+        failf(data, "No authentication method was acceptable.");
+      }
+      return CURLE_COULDNT_CONNECT;
+    }
+    else {
+      failf(data,
+            "Undocumented SOCKS5 mode attempted to be used by server.");
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  /* Authentication is complete, now specify destination to the proxy */
+  socksreq[0] = 5; /* version (SOCKS5) */
+  socksreq[1] = 1; /* connect */
+  socksreq[2] = 0; /* must be zero */
+  socksreq[3] = 1; /* IPv4 = 1 */
+
+  {
+    struct Curl_dns_entry *dns;
+    Curl_addrinfo *hp=NULL;
+    int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
+
+    if(rc == CURLRESOLV_ERROR)
+      return CURLE_COULDNT_RESOLVE_HOST;
+
+    if(rc == CURLRESOLV_PENDING)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+
+    /*
+     * 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) {
+      char buf[64];
+      unsigned short ip[4];
+      Curl_printable_address(hp, buf, sizeof(buf));
+
+      if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
+                      &ip[0], &ip[1], &ip[2], &ip[3])) {
+        socksreq[4] = (unsigned char)ip[0];
+        socksreq[5] = (unsigned char)ip[1];
+        socksreq[6] = (unsigned char)ip[2];
+        socksreq[7] = (unsigned char)ip[3];
+      }
+      else
+        hp = NULL; /* fail! */
+
+      Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+    }
+    if(!hp) {
+      failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+            conn->host.name);
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+  }
+
+  *((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
+
+  {
+    const int packetsize = 10;
+
+    code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
+    if ((code != CURLE_OK) || (written != packetsize)) {
+      failf(data, "Failed to send SOCKS5 connect request.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    result = blockread_all(conn, sock, (char *)socksreq, packetsize,
+                           &actualread, timeout);
+    if ((result != CURLE_OK) || (actualread != packetsize)) {
+      failf(data, "Failed to receive SOCKS5 connect request ack.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if (socksreq[0] != 5) { /* version */
+      failf(data,
+            "SOCKS5 reply has wrong version, version should be 5.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    if (socksreq[1] != 0) { /* Anything besides 0 is an error */
+        failf(data,
+              "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
+              (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+              (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+              (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
+              socksreq[1]);
+        return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  Curl_nonblock(sock, TRUE);
+  return CURLE_OK; /* Proxy was successful! */
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно