From bf3759020a49a2f36284624f0a067dc7b70667b3 Mon Sep 17 00:00:00 2001 From: zone117x Date: Thu, 23 Apr 2015 00:44:21 -0600 Subject: [PATCH] MoreThanTv now working on mono with libcurl --- src/CurlSharp/Callbacks/CurlEasyCallbacks.cs | 239 ++ src/CurlSharp/Callbacks/CurlShareCallbacks.cs | 75 + src/CurlSharp/Curl.cs | 170 ++ src/CurlSharp/CurlEasy.cs | 2161 +++++++++++++++++ src/CurlSharp/CurlHttpMultiPartForm.cs | 388 +++ src/CurlSharp/CurlMulti.cs | 302 +++ src/CurlSharp/CurlMultiInfo.cs | 65 + src/CurlSharp/CurlShare.cs | 276 +++ src/CurlSharp/CurlSharp.csproj | 88 + src/CurlSharp/CurlSlist.cs | 144 ++ src/CurlSharp/CurlSslContext.cs | 49 + src/CurlSharp/CurlVersionInfoData.cs | 207 ++ src/CurlSharp/Enums/CurlClosePolicy.cs | 46 + src/CurlSharp/Enums/CurlCode.cs | 403 +++ src/CurlSharp/Enums/CurlFormCode.cs | 76 + src/CurlSharp/Enums/CurlFormOption.cs | 142 ++ src/CurlSharp/Enums/CurlFtpAuth.cs | 31 + src/CurlSharp/Enums/CurlFtpSsl.cs | 37 + src/CurlSharp/Enums/CurlHttpAuth.cs | 65 + src/CurlSharp/Enums/CurlHttpVersion.cs | 31 + src/CurlSharp/Enums/CurlInfo.cs | 222 ++ src/CurlSharp/Enums/CurlInfoType.cs | 50 + src/CurlSharp/Enums/CurlInitFlag.cs | 34 + src/CurlSharp/Enums/CurlIoCommand.cs | 27 + src/CurlSharp/Enums/CurlIoError.cs | 30 + src/CurlSharp/Enums/CurlIpResolve.cs | 26 + src/CurlSharp/Enums/CurlLockAccess.cs | 31 + src/CurlSharp/Enums/CurlLockData.cs | 48 + src/CurlSharp/Enums/CurlMessage.cs | 25 + src/CurlSharp/Enums/CurlMultiCode.cs | 46 + src/CurlSharp/Enums/CurlNetrcOption.cs | 43 + src/CurlSharp/Enums/CurlOption.cs | 1603 ++++++++++++ src/CurlSharp/Enums/CurlProxyType.cs | 27 + src/CurlSharp/Enums/CurlShareCode.cs | 40 + src/CurlSharp/Enums/CurlShareOption.cs | 53 + src/CurlSharp/Enums/CurlSslVersion.cs | 36 + src/CurlSharp/Enums/CurlTimeCond.cs | 39 + src/CurlSharp/Enums/CurlVersion.cs | 34 + .../Enums/CurlVersionFeatureBitmask.cs | 71 + src/CurlSharp/NativeMethods.cs | 393 +++ src/CurlSharp/Properties/AssemblyInfo.cs | 22 + src/Jackett.sln | 7 +- src/Jackett/CookieContainerExtensions.cs | 33 +- src/Jackett/Curl.cs | 137 ++ src/Jackett/Indexers/BitHdtv.cs | 227 +- src/Jackett/Indexers/BitMeTV.cs | 273 +-- src/Jackett/Indexers/Freshon.cs | 271 +-- src/Jackett/Indexers/IPTorrents.cs | 278 +-- src/Jackett/Indexers/MoreThanTV.cs | 75 +- src/Jackett/Jackett.csproj | 17 +- src/Jackett/Program.cs | 135 +- src/Jackett/Server.cs | 44 +- 52 files changed, 8719 insertions(+), 673 deletions(-) create mode 100644 src/CurlSharp/Callbacks/CurlEasyCallbacks.cs create mode 100644 src/CurlSharp/Callbacks/CurlShareCallbacks.cs create mode 100644 src/CurlSharp/Curl.cs create mode 100644 src/CurlSharp/CurlEasy.cs create mode 100644 src/CurlSharp/CurlHttpMultiPartForm.cs create mode 100644 src/CurlSharp/CurlMulti.cs create mode 100644 src/CurlSharp/CurlMultiInfo.cs create mode 100644 src/CurlSharp/CurlShare.cs create mode 100644 src/CurlSharp/CurlSharp.csproj create mode 100644 src/CurlSharp/CurlSlist.cs create mode 100644 src/CurlSharp/CurlSslContext.cs create mode 100644 src/CurlSharp/CurlVersionInfoData.cs create mode 100644 src/CurlSharp/Enums/CurlClosePolicy.cs create mode 100644 src/CurlSharp/Enums/CurlCode.cs create mode 100644 src/CurlSharp/Enums/CurlFormCode.cs create mode 100644 src/CurlSharp/Enums/CurlFormOption.cs create mode 100644 src/CurlSharp/Enums/CurlFtpAuth.cs create mode 100644 src/CurlSharp/Enums/CurlFtpSsl.cs create mode 100644 src/CurlSharp/Enums/CurlHttpAuth.cs create mode 100644 src/CurlSharp/Enums/CurlHttpVersion.cs create mode 100644 src/CurlSharp/Enums/CurlInfo.cs create mode 100644 src/CurlSharp/Enums/CurlInfoType.cs create mode 100644 src/CurlSharp/Enums/CurlInitFlag.cs create mode 100644 src/CurlSharp/Enums/CurlIoCommand.cs create mode 100644 src/CurlSharp/Enums/CurlIoError.cs create mode 100644 src/CurlSharp/Enums/CurlIpResolve.cs create mode 100644 src/CurlSharp/Enums/CurlLockAccess.cs create mode 100644 src/CurlSharp/Enums/CurlLockData.cs create mode 100644 src/CurlSharp/Enums/CurlMessage.cs create mode 100644 src/CurlSharp/Enums/CurlMultiCode.cs create mode 100644 src/CurlSharp/Enums/CurlNetrcOption.cs create mode 100644 src/CurlSharp/Enums/CurlOption.cs create mode 100644 src/CurlSharp/Enums/CurlProxyType.cs create mode 100644 src/CurlSharp/Enums/CurlShareCode.cs create mode 100644 src/CurlSharp/Enums/CurlShareOption.cs create mode 100644 src/CurlSharp/Enums/CurlSslVersion.cs create mode 100644 src/CurlSharp/Enums/CurlTimeCond.cs create mode 100644 src/CurlSharp/Enums/CurlVersion.cs create mode 100644 src/CurlSharp/Enums/CurlVersionFeatureBitmask.cs create mode 100644 src/CurlSharp/NativeMethods.cs create mode 100644 src/CurlSharp/Properties/AssemblyInfo.cs create mode 100644 src/Jackett/Curl.cs diff --git a/src/CurlSharp/Callbacks/CurlEasyCallbacks.cs b/src/CurlSharp/Callbacks/CurlEasyCallbacks.cs new file mode 100644 index 000000000..303b3789b --- /dev/null +++ b/src/CurlSharp/Callbacks/CurlEasyCallbacks.cs @@ -0,0 +1,239 @@ +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// Called when cURL has debug information for the client. + /// + /// + /// For usage, see the sample Upload.cs. + /// Arguments passed to the recipient include: + /// + /// + /// Argument + /// Description + /// + /// + /// infoType + /// + /// Type of debug information, see + /// . + /// + /// + /// + /// message + /// Debug information as a string. + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// + public delegate void CurlDebugCallback(CurlInfoType infoType, String message, Object extraData); + + /// + /// Called when cURL has header data for the client. + /// + /// + /// For usage, see the sample Headers.cs. + /// Arguments passed to the recipient include: + /// + /// + /// Argument + /// Description + /// + /// + /// buf + /// Header data from cURL to the client. + /// + /// + /// size + /// Size of a character, in bytes. + /// + /// + /// nmemb + /// Number of characters. + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// Your implementation should return the number of bytes (not + /// characters) processed. Usually this is size * nmemb. + /// Return -1 to abort the transfer. + /// + public delegate int CurlHeaderCallback(byte[] buf, int size, int nmemb, Object extraData); + + /// + /// Called when cURL needs for the client to perform an + /// IOCTL operation. An example might be when an FTP + /// upload requires rewinding of the input file to deal + /// with a resend occasioned by an error. + /// + /// + /// + /// + /// Argument + /// Description + /// + /// + /// cmd + /// + /// A ; for now, only + /// RestartRead should be passed. + /// + /// + /// + /// extraData + /// + /// Client-provided extra data; in the + /// case of an FTP upload, it might be a + /// FileStream object. + /// + /// + /// + /// Your implementation should return a , + /// which should be if everything + /// is okay. + /// + public delegate CurlIoError CurlIoctlCallback(CurlIoCommand cmd, Object extraData); + + /// + /// Called when cURL wants to report progress. + /// + /// + /// For usage, see the sample Upload.cs. + /// Arguments passed to the recipient include: + /// + /// + /// Argument + /// Description + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// dlTotal + /// Number of bytes to download. + /// + /// + /// dlNow + /// Number of bytes downloaded so far. + /// + /// + /// ulTotal + /// Number of bytes to upload. + /// + /// + /// ulNow + /// Number of bytes uploaded so far. + /// + /// + /// Your implementation should return 0 to continue, or a non-zero + /// value to abort the transfer. + /// + public delegate int CurlProgressCallback(Object extraData, double dlTotal, double dlNow, + double ulTotal, double ulNow); + + /// + /// Called when cURL wants to read data from the client. + /// + /// + /// For usage, see the sample Upload.cs. + /// Arguments passed to the recipient include: + /// + /// + /// Argument + /// Description + /// + /// + /// buf + /// + /// Buffer into which your client should write data + /// for cURL. + /// + /// + /// + /// size + /// Size of a character, usually 1. + /// + /// + /// nmemb + /// Number of characters. + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// Your implementation should return the number of bytes (not + /// characters) written to buf. Return 0 to abort the transfer. + /// + public delegate int CurlReadCallback([Out] byte[] buf, int size, int nmemb, Object extraData); + + /// + /// Called when cURL wants to report an Ssl event. + /// + /// + /// For usage, see the sample SSLGet.cs. + /// Arguments passed to the recipient include: + /// + /// + /// Argument + /// Description + /// + /// + /// ctx + /// + /// An object that wraps an + /// OpenSSL SSL_CTX pointer. + /// + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// Your implementation should return a , + /// which should be if everything + /// is okay. + /// + public delegate CurlCode CurlSslContextCallback(CurlSslContext ctx, Object extraData); + + /// + /// Called when cURL has data for the client. + /// + /// + /// For usage, see the example EasyGet.cs. + /// Arguments passed to the delegate implementation include: + /// + /// + /// Argument + /// Description + /// + /// + /// buf + /// Data cURL is providing to the client. + /// + /// + /// size + /// Size of a character, usually 1. + /// + /// + /// nmemb + /// Number of characters. + /// + /// + /// extraData + /// Client-provided extra data. + /// + /// + /// Your implementation should return the number of bytes (not + /// characters) processed. Return 0 to abort the transfer. + /// + public delegate int CurlWriteCallback(byte[] buf, int size, int nmemb, Object extraData); +} \ No newline at end of file diff --git a/src/CurlSharp/Callbacks/CurlShareCallbacks.cs b/src/CurlSharp/Callbacks/CurlShareCallbacks.cs new file mode 100644 index 000000000..9efb7e6ae --- /dev/null +++ b/src/CurlSharp/Callbacks/CurlShareCallbacks.cs @@ -0,0 +1,75 @@ +using System; + +namespace CurlSharp +{ + /// + /// Called when cURL wants to lock a shared resource. + /// + /// + /// For a usage example, refer to the ShareDemo.cs sample. + /// Arguments passed to your delegate implementation include: + /// + /// + /// Argument + /// Description + /// + /// + /// data + /// + /// Type of data to lock; one of the values in the + /// enumeration. + /// + /// + /// + /// access + /// + /// Lock access requested; one of the values in the + /// enumeration. + /// + /// + /// + /// userData + /// + /// Client-provided data that is not touched internally by + /// cURL. This is set via + /// when calling the + /// member of the + /// class. + /// + /// + /// + /// + public delegate void CurlShareLockCallback(CurlLockData data, CurlLockAccess access, Object userData); + + /// + /// Called when cURL wants to unlock a shared resource. + /// + /// + /// For a usage example, refer to the ShareDemo.cs sample. + /// Arguments passed to your delegate implementation include: + /// + /// + /// Argument + /// Description + /// + /// + /// data + /// + /// Type of data to unlock; one of the values in the + /// enumeration. + /// + /// + /// + /// userData + /// + /// Client-provided data that is not touched internally by + /// cURL. This is set via + /// when calling the + /// member of the + /// class. + /// + /// + /// + /// + public delegate void CurlShareUnlockCallback(CurlLockData data, Object userData); +} \ No newline at end of file diff --git a/src/CurlSharp/Curl.cs b/src/CurlSharp/Curl.cs new file mode 100644 index 000000000..abb7de8c7 --- /dev/null +++ b/src/CurlSharp/Curl.cs @@ -0,0 +1,170 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// Top-level class for initialization and cleanup. + /// + /// + /// It also implements static methods for capabilities that don't + /// logically belong in a class. + /// + public static class Curl + { + // for state management + private static CurlCode _initCode; + + /// + /// Class constructor - initialize global status. + /// + static Curl() + { + _initCode = CurlCode.FailedInit; + } + + // hidden instance stuff + + /// + /// Get the underlying cURL version as a string, example "7.12.2". + /// + /// + /// Thrown if cURL isn't properly initialized. + /// + public static string Version + { + get + { + EnsureCurl(); + return Marshal.PtrToStringAnsi(NativeMethods.curl_version()); + } + } + + /// + /// Process-wide initialization -- call only once per process. + /// + /// + /// An or'd combination of + /// members. + /// + /// + /// A , hopefully + /// CurlCode.Ok. + /// + public static CurlCode GlobalInit(CurlInitFlag flags) + { + _initCode = NativeMethods.curl_global_init((int)flags); +#if USE_LIBCURLSHIM + if (_initCode == CurlCode.Ok) + NativeMethods.curl_shim_initialize(); +#endif + return _initCode; + } + + /// + /// Process-wide cleanup -- call just before exiting process. + /// + /// + /// While it's not necessary that your program call this method + /// before exiting, doing so will prevent leaks of native cURL resources. + /// + public static void GlobalCleanup() + { + if (_initCode == CurlCode.Ok) + { +#if USE_LIBCURLSHIM + NativeMethods.curl_shim_cleanup(); +#endif + NativeMethods.curl_global_cleanup(); + _initCode = CurlCode.FailedInit; + } + } + + /// + /// URL encode a String. + /// + /// The string to URL encode. + /// + /// Input string length; + /// use 0 for cURL to determine. + /// + /// A new URL encoded string. + /// + /// Thrown if cURL isn't properly initialized. + /// + public static string Escape(string url, int length) + { + EnsureCurl(); + var p = NativeMethods.curl_escape(url, length); + var s = Marshal.PtrToStringAnsi(p); + NativeMethods.curl_free(p); + return s; + } + + /// + /// URL decode a String. + /// + /// The string to URL decode. + /// + /// Input string length; + /// use 0 for cURL to determine. + /// + /// A new URL decoded string. + /// + /// Thrown if cURL isn't properly initialized. + /// + public static string Unescape(string url, int length) + { + EnsureCurl(); + var p = NativeMethods.curl_unescape(url, length); + var s = Marshal.PtrToStringAnsi(p); + NativeMethods.curl_free(p); + return s; + } + + /// + /// Get a object. + /// + /// + /// Specify a , such as + /// CurlVersion.Now. + /// + /// A object. + /// + /// Thrown if cURL isn't properly initialized. + /// + public static CurlVersionInfoData GetVersionInfo(CurlVersion ver) + { + EnsureCurl(); + return new CurlVersionInfoData(ver); + } + + /// + /// Called by other classes to ensure valid cURL state. + /// + internal static void EnsureCurl() + { + if (_initCode != CurlCode.Ok) + throw new InvalidOperationException("cURL not initialized"); + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlEasy.cs b/src/CurlSharp/CurlEasy.cs new file mode 100644 index 000000000..6c462834c --- /dev/null +++ b/src/CurlSharp/CurlEasy.cs @@ -0,0 +1,2161 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// Implements the curl_easy_xxx API. + /// + /// + /// This is the most important class in libcurl.NET. It wraps a + /// CURL* handle and provides delegates through which callbacks + /// (such as CurlWriteCallback and CurlReadCallback) + /// are implemented. + /// + public class CurlEasy : IDisposable + { + // constants (used internally only) + private const int CURLOPTTYPE_OBJECTPOINT = 10000; + private const int CURLOPTTYPE_FUNCTIONPOINT = 20000; + private const int CURLOPTTYPE_OFF_T = 30000; + private const int CURLINFO_STRING = 0x100000; + private const int CURLINFO_LONG = 0x200000; + private const int CURLINFO_DOUBLE = 0x300000; + private const int CURLINFO_SLIST = 0x400000; +#if USE_LIBCURLSHIM + private readonly IntPtr _pMyStrings; +#endif + private bool _autoReferer; + private int _bufferSize; + private string _caInfo; + private string _caPath; + private CurlClosePolicy _closePolicy; + private int _connectTimeout; + private string _cookie; + private string _cookieFile; + private string _cookieJar; + private bool _cookieSession; + private CurlShare _curlShare; + private string _customRequest; + private Object _debugData; + private int _dnsCacheTimeout; + private bool _dnsUseGlobalCache; + private string _egdSocket; + private string _encoding; + private string _errorBuffer; + private bool _failOnError; + private bool _filetime; + private bool _followLocation; + private bool _forbidReuse; + private bool _freshConnect; + private string _ftpAccount; + private bool _ftpAppend; + private CurlFtpAuth _ftpAuth; + private bool _ftpCreateMissingDirs; + private bool _ftpListOnly; + private string _ftpPort; + private int _ftpResponseTimeout; + private bool _ftpSkipPasvIp; + private CurlFtpSsl _ftpSsl; + private bool _ftpUseEprt; + private bool _ftpUseEpsv; + private GCHandle _hThis; + private Object _headerData; + private CurlHttpAuth _httpAuth; + private bool _httpGet; + private CurlHttpMultiPartForm _httpMultiPartForm; + private bool _httpProxyTunnel; + private CurlHttpVersion _httpVersion; + private bool _ignoreContentLength; + private long _infileSize; + private string _interface; + private Object _ioctlData; + private string _krb4Level; + private CurlCode _lastErrorCode; + private string _lastErrorDescription; + private int _lowSpeedLimit; + private int _lowSpeedTime; + private int _maxConnects; + private long _maxFileSize; + private int _maxRedirs; + private string _netRcFile; + private bool _noBody; + private bool _noProgress; + private bool _noSignal; + private IntPtr _pCurl; +#if USE_LIBCURLSHIM + private NativeMethods._ShimDebugCallback _pcbDebug; + private NativeMethods._ShimHeaderCallback _pcbHeader; + private NativeMethods._ShimIoctlCallback _pcbIoctl; + private NativeMethods._ShimProgressCallback _pcbProgress; + private NativeMethods._ShimReadCallback _pcbRead; + private NativeMethods._ShimSslCtxCallback _pcbSslCtx; + private NativeMethods._ShimWriteCallback _pcbWrite; + private IntPtr _ptrThis; +#else + private NativeMethods._CurlGenericCallback _pcbWrite; + private NativeMethods._CurlGenericCallback _pcbRead; + private NativeMethods._CurlGenericCallback _pcbHeader; + private NativeMethods._CurlDebugCallback _pcbDebug; + private NativeMethods._CurlIoctlCallback _pcbIoctl; + private NativeMethods._CurlProgressCallback _pcbProgress; + private NativeMethods._CurlSslCtxCallback _pcbSslCtx; +#endif + private CurlDebugCallback _pfCurlDebug; + private CurlHeaderCallback _pfCurlHeader; + private CurlIoctlCallback _pfCurlIoctl; + private CurlProgressCallback _pfCurlProgress; + private CurlReadCallback _pfCurlRead; + private CurlSslContextCallback _pfCurlSslContext; + private CurlWriteCallback _pfCurlWrite; + private int _port; + private bool _post; + private int _postFieldSize; + private string _postFields; + private Object _privateData; + private Object _progressData; + private string _proxy; + private int _proxyPort; + private string _proxyUserPwd; + private bool _put; + private string _randomFile; + private string _range; + private Object _readData; + private string _referer; + private int _resumeFrom; + private string _sourceUrl; + private string _sslCert; + private string _sslCertPasswd; + private string _sslCipherList; + private Object _sslContextData; + private string _sslEngine; + private bool _sslEngineDefault; + private string _sslKey; + private string _sslKeyPasswd; + private bool _sslVerifyPeer; + private bool _tcpNoDelay; + private int _timeValue; + private int _timeout; + private bool _transferText; + private bool _unrestrictedAuth; + private bool _upload; + private string _url; + private string _userAgent; + private string _userPwd; + private bool _verbose; + private Object _writeData; + private string _writeInfo; + + /// + /// Constructor + /// + /// + /// This is thrown + /// if hasn't bee properly initialized. + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlEasy() + { + Curl.EnsureCurl(); + _pCurl = NativeMethods.curl_easy_init(); + ensureHandle(); + NativeMethods.curl_easy_setopt(_pCurl, CurlOption.NoProgress, IntPtr.Zero); +#if USE_LIBCURLSHIM + _pMyStrings = NativeMethods.curl_shim_alloc_strings(); +#endif + resetPrivateVariables(); + installDelegates(); + } + + private CurlEasy(CurlEasy from) + { + _pCurl = NativeMethods.curl_easy_duphandle(from._pCurl); + ensureHandle(); +#if USE_LIBCURLSHIM + _pMyStrings = NativeMethods.curl_shim_alloc_strings(); +#endif + resetPrivateVariables(); + installDelegates(); + } + + public object Private + { + get { return _privateData; } + set { _privateData = value; } + } + + public object WriteData + { + get { return _writeData; } + set + { + _writeData = value; +#if !USE_LIBCURLSHIM + setWriteData(value); +#endif + } + } + +#if !USE_LIBCURLSHIM + private IntPtr _curlWriteData = IntPtr.Zero; + + /// + /// Object to pass to OnWriteCallback. + /// + /// + /// + private CurlCode setWriteData(object data) + { + _curlWriteData = getHandle(data); + return setCurlOpt(_curlWriteData, CurlOption.WriteData); + } + + private CurlCode setCurlOpt(IntPtr data, CurlOption opt) + { + var retCode = NativeMethods.curl_easy_setopt(_pCurl, opt, data); + setLastError(retCode, opt); + return retCode; + } + + private IntPtr _curlReadData = IntPtr.Zero; + + /// + /// Object to pass to OnReadCallback. + /// Use to convert the passed IntPtr back into the object, then cast. + /// + /// + /// + private CurlCode setReadData(object data) + { + _curlReadData = getHandle(data); + return setCurlOpt(_curlReadData, CurlOption.ReadData); + } + + private IntPtr _curlProgressData = IntPtr.Zero; + + /// + /// Object to pass to OnProgressCallback. + /// Use to convert the passed IntPtr back into the object, then cast. + /// + /// + /// + private CurlCode setProgressData(object data) + { + _curlProgressData = getHandle(data); + return setCurlOpt(_curlProgressData, CurlOption.ProgressData); + } + + private IntPtr _curlHeaderData = IntPtr.Zero; + + /// + /// Object to pass to OnHeaderCallback. + /// + /// + /// + private CurlCode setHeaderData(object data) + { + _curlHeaderData = getHandle(data); + return setCurlOpt(_curlHeaderData, CurlOption.HeaderData); + } + + private IntPtr _curlDebugData = IntPtr.Zero; + + /// + /// Object to pass to OnDebugCallback. + /// + /// + /// + private CurlCode setDebugData(object data) + { + _curlDebugData = getHandle(data); + return setCurlOpt(_curlDebugData, CurlOption.DebugData); + } + + private IntPtr _curlSslCtxData = IntPtr.Zero; + + /// + /// Object to pass to OnSslCtxCallback. + /// + /// + /// + private CurlCode setSslCtxData(object data) + { + _curlSslCtxData = getHandle(data); + return setCurlOpt(_curlSslCtxData, CurlOption.SslCtxData); + } + + private IntPtr _curlIoctlData = IntPtr.Zero; + + /// + /// Object to pass to OnIoctlCallback. + /// + /// + /// + private CurlCode setIoctlData(object data) + { + _curlIoctlData = getHandle(data); + return setCurlOpt(_curlIoctlData, CurlOption.IoctlData); + } +#endif + + public object ReadData + { + get { return _readData; } + set + { + _readData = value; +#if !USE_LIBCURLSHIM + setReadData(value); +#endif + } + } + + public object ProgressData + { + get { return _progressData; } + set + { + _progressData = value; +#if !USE_LIBCURLSHIM + setProgressData(value); +#endif + } + } + + public object DebugData + { + get { return _debugData; } + set + { + _debugData = value; +#if !USE_LIBCURLSHIM + setDebugData(value); +#endif + } + } + + public object HeaderData + { + get { return _headerData; } + set + { + _headerData = value; +#if !USE_LIBCURLSHIM + setHeaderData(value); +#endif + } + } + + public object SslCtxData + { + get { return _sslContextData; } + set + { + _sslContextData = value; +#if !USE_LIBCURLSHIM + setSslCtxData(value); +#endif + } + } + + public object IoctlData + { + get { return _ioctlData; } + set + { + _ioctlData = value; +#if !USE_LIBCURLSHIM + setIoctlData(value); +#endif + } + } + + public CurlShare Share + { + get { return _curlShare; } + set + { + _curlShare = value; + setShareObject(); + } + } + + public CurlHttpMultiPartForm HttpPost + { + get { return _httpMultiPartForm; } + set + { + _httpMultiPartForm = value; + setMultiPartFormObject(); + } + } + + public CurlSlist HttpHeader + { + set { setSlistObject(CurlOption.HttpHeader, value); } + } + + public CurlSlist Prequote + { + set { setSlistObject(CurlOption.Prequote, value); } + } + + public CurlSlist Quote + { + set { setSlistObject(CurlOption.Quote, value); } + } + + public CurlSlist Postquote + { + set { setSlistObject(CurlOption.Postquote, value); } + } + + public CurlSlist SourceQuote + { + set { setSlistObject(CurlOption.SourceQuote, value); } + } + + public CurlSlist Http200Aliases + { + set { setSlistObject(CurlOption.Http200Aliases, value); } + } + + public CurlFtpAuth FtpAuth + { + get { return _ftpAuth; } + set + { + _ftpAuth = value; + var l = Convert.ToInt32(value); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.FtpSslAuth, (IntPtr) l), + CurlOption.FtpSslAuth); + } + } + + public CurlHttpVersion HttpVersion + { + get { return _httpVersion; } + set + { + _httpVersion = value; + var l = Convert.ToInt32(value); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpVersion, (IntPtr) l), + CurlOption.HttpVersion); + } + } + + public CurlHttpAuth HttpAuth + { + get { return _httpAuth; } + set + { + _httpAuth = value; + var l = Convert.ToInt32(value); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpAuth, (IntPtr) l), + CurlOption.HttpAuth); + } + } + + public CurlFtpSsl FtpSsl + { + get { return _ftpSsl; } + set + { + _ftpSsl = value; + var l = Convert.ToInt32(value); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.FtpSsl, (IntPtr) l), + CurlOption.FtpSsl); + } + } + + public CurlClosePolicy ClosePolicy + { + get { return _closePolicy; } + set + { + _closePolicy = value; + var l = Convert.ToInt32(value); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.ClosePolicy, (IntPtr) l), + CurlOption.ClosePolicy); + } + } + + public CurlWriteCallback WriteFunction + { + get { return _pfCurlWrite; } + set { setFunctionOptions(CurlOption.WriteFunction, value); } + } + + public CurlReadCallback ReadFunction + { + get { return _pfCurlRead; } + set { setFunctionOptions(CurlOption.ReadFunction, value); } + } + + public CurlHeaderCallback HeaderFunction + { + get { return _pfCurlHeader; } + set { setFunctionOptions(CurlOption.HeaderFunction, value); } + } + + public CurlDebugCallback DebugFunction + { + get { return _pfCurlDebug; } + set { setFunctionOptions(CurlOption.DebugFunction, value); } + } + + public CurlProgressCallback ProgressFunction + { + get { return _pfCurlProgress; } + set { setFunctionOptions(CurlOption.ProgressFunction, value); } + } + + public CurlIoctlCallback IoctlFunction + { + get { return _pfCurlIoctl; } + set { setFunctionOptions(CurlOption.IoctlFunction, value); } + } + + public CurlSslContextCallback SslContextFunction + { + get { return _pfCurlSslContext; } + set { setFunctionOptions(CurlOption.SslCtxFunction, value); } + } + + public string LastErrorDescription + { + get { return _lastErrorDescription; } + } + + public bool NoProgress + { + get { return _noProgress; } + set { setBoolOption(CurlOption.NoProgress, ref _noProgress, value); } + } + + public bool NoBody + { + get { return _noBody; } + set { setBoolOption(CurlOption.NoBody, ref _noBody, value); } + } + + public bool FailOnError + { + get { return _failOnError; } + set { setBoolOption(CurlOption.FailOnError, ref _failOnError, value); } + } + + public bool Upload + { + get { return _upload; } + set { setBoolOption(CurlOption.Upload, ref _upload, value); } + } + + public bool Post + { + get { return _post; } + set { setBoolOption(CurlOption.Post, ref _post, value); } + } + + public bool FtpListOnly + { + get { return _ftpListOnly; } + set { setBoolOption(CurlOption.FtpListOnly, ref _ftpListOnly, value); } + } + + public bool FtpAppend + { + get { return _ftpAppend; } + set { setBoolOption(CurlOption.FtpAppend, ref _ftpAppend, value); } + } + + public bool FollowLocation + { + get { return _followLocation; } + set { setBoolOption(CurlOption.FollowLocation, ref _followLocation, value); } + } + + public bool TransferText + { + get { return _transferText; } + set { setBoolOption(CurlOption.TransferText, ref _transferText, value); } + } + + public bool Put + { + get { return _put; } + set { setBoolOption(CurlOption.Put, ref _put, value); } + } + + public bool HttpProxyTunnel + { + get { return _httpProxyTunnel; } + set { setBoolOption(CurlOption.HttpProxyTunnel, ref _httpProxyTunnel, value); } + } + + public bool SslVerifyPeer + { + get { return _sslVerifyPeer; } + set { setBoolOption(CurlOption.SslVerifyPeer, ref _sslVerifyPeer, value); } + } + + public bool FreshConnect + { + get { return _freshConnect; } + set { setBoolOption(CurlOption.FreshConnect, ref _freshConnect, value); } + } + + public bool ForbidReuse + { + get { return _forbidReuse; } + set { setBoolOption(CurlOption.ForbidReuse, ref _forbidReuse, value); } + } + + public bool HttpGet + { + get { return _httpGet; } + set { setBoolOption(CurlOption.HttpGet, ref _httpGet, value); } + } + + public bool FtpUseEpsv + { + get { return _ftpUseEpsv; } + set { setBoolOption(CurlOption.FtpUseEpsv, ref _ftpUseEpsv, value); } + } + + public bool Filetime + { + get { return _filetime; } + set { setBoolOption(CurlOption.Filetime, ref _filetime, value); } + } + + public bool UnrestrictedAuth + { + get { return _unrestrictedAuth; } + set { setBoolOption(CurlOption.UnrestrictedAuth, ref _unrestrictedAuth, value); } + } + + public bool FtpUseEprt + { + get { return _ftpUseEprt; } + set { setBoolOption(CurlOption.FtpUseEprt, ref _ftpUseEprt, value); } + } + + public bool AutoReferer + { + get { return _autoReferer; } + set { setBoolOption(CurlOption.AutoReferer, ref _autoReferer, value); } + } + + public bool CookieSession + { + get { return _cookieSession; } + set { setBoolOption(CurlOption.CookieSession, ref _cookieSession, value); } + } + + public bool SslEngineDefault + { + get { return _sslEngineDefault; } + set { setBoolOption(CurlOption.SslEngineDefault, ref _sslEngineDefault, value); } + } + + public bool DnsUseGlobalCache + { + get { return _dnsUseGlobalCache; } + set { setBoolOption(CurlOption.DnsUseGlobalCache, ref _dnsUseGlobalCache, value); } + } + + public bool NoSignal + { + get { return _noSignal; } + set { setBoolOption(CurlOption.NoSignal, ref _noSignal, value); } + } + + public bool FtpCreateMissingDirs + { + get { return _ftpCreateMissingDirs; } + set { setBoolOption(CurlOption.FtpCreateMissingDirs, ref _ftpCreateMissingDirs, value); } + } + + public bool TcpNoDelay + { + get { return _tcpNoDelay; } + set { setBoolOption(CurlOption.TcpNoDelay, ref _tcpNoDelay, value); } + } + + public bool IgnoreContentLength + { + get { return _ignoreContentLength; } + set { setBoolOption(CurlOption.IgnoreContentLength, ref _ignoreContentLength, value); } + } + + public bool FtpSkipPasvIp + { + get { return _ftpSkipPasvIp; } + set { setBoolOption(CurlOption.FtpSkipPasvIp, ref _ftpSkipPasvIp, value); } + } + + public int Port + { + get { return _port; } + set { setIntOption(CurlOption.Port, ref _port, value); } + } + + public int Timeout + { + get { return _timeout; } + set { setIntOption(CurlOption.Timeout, ref _timeout, value); } + } + + public int LowSpeedLimit + { + get { return _lowSpeedLimit; } + set { setIntOption(CurlOption.LowSpeedLimit, ref _lowSpeedLimit, value); } + } + + public int LowSpeedTime + { + get { return _lowSpeedTime; } + set { setIntOption(CurlOption.LowSpeedTime, ref _lowSpeedTime, value); } + } + + public int ResumeFrom + { + get { return _resumeFrom; } + set { setIntOption(CurlOption.ResumeFrom, ref _resumeFrom, value); } + } + + public int TimeValue + { + get { return _timeValue; } + set { setIntOption(CurlOption.TimeValue, ref _timeValue, value); } + } + + public int ProxyPort + { + get { return _proxyPort; } + set { setIntOption(CurlOption.ProxyPort, ref _proxyPort, value); } + } + + public int PostFieldSize + { + get { return _postFieldSize; } + set { setIntOption(CurlOption.PostFieldSize, ref _postFieldSize, value); } + } + + public int MaxRedirs + { + get { return _maxRedirs; } + set { setIntOption(CurlOption.MaxRedirs, ref _maxRedirs, value); } + } + + public int MaxConnects + { + get { return _maxConnects; } + set { setIntOption(CurlOption.MaxConnects, ref _maxConnects, value); } + } + + public int ConnectTimeout + { + get { return _connectTimeout; } + set { setIntOption(CurlOption.ConnectTimeout, ref _connectTimeout, value); } + } + + public int BufferSize + { + get { return _bufferSize; } + set { setIntOption(CurlOption.BufferSize, ref _bufferSize, value); } + } + + public int DnsCacheTimeout + { + get { return _dnsCacheTimeout; } + set { setIntOption(CurlOption.DnsCacheTimeout, ref _dnsCacheTimeout, value); } + } + + public int FtpResponseTimeout + { + get { return _ftpResponseTimeout; } + set { setIntOption(CurlOption.FtpResponseTimeout, ref _ftpResponseTimeout, value); } + } + + public long InfileSize + { + get { return _infileSize; } + set { setLongOption(CurlOption.InfileSize, ref _infileSize, value); } + } + + public long MaxFileSize + { + get { return _maxFileSize; } + set { setLongOption(CurlOption.MaxFileSize, ref _maxFileSize, value); } + } + + public string Url + { + get { return _url; } + set { setStringOption(CurlOption.Url, out _url, value); } + } + + public string Proxy + { + get { return _proxy; } + set { setStringOption(CurlOption.Proxy, out _proxy, value); } + } + + public string UserPwd + { + get { return _userPwd; } + set { setStringOption(CurlOption.UserPwd, out _userPwd, value); } + } + + public string ProxyUserPwd + { + get { return _proxyUserPwd; } + set { setStringOption(CurlOption.ProxyUserPwd, out _proxyUserPwd, value); } + } + + public string Range + { + get { return _range; } + set { setStringOption(CurlOption.Range, out _range, value); } + } + + public string PostFields + { + get { return _postFields; } + set { setStringOption(CurlOption.PostFields, out _postFields, value); } + } + + public string Referer + { + get { return _referer; } + set { setStringOption(CurlOption.Referer, out _referer, value); } + } + + public string FtpPort + { + get { return _ftpPort; } + set { setStringOption(CurlOption.FtpPort, out _ftpPort, value); } + } + + public string UserAgent + { + get { return _userAgent; } + set { setStringOption(CurlOption.UserAgent, out _userAgent, value); } + } + + public string Cookie + { + get { return _cookie; } + set { setStringOption(CurlOption.Cookie, out _cookie, value); } + } + + public string SslCert + { + get { return _sslCert; } + set { setStringOption(CurlOption.SslCert, out _sslCert, value); } + } + + public string SslCertPasswd + { + get { return _sslCertPasswd; } + set { setStringOption(CurlOption.SslCertPasswd, out _sslCertPasswd, value); } + } + + public string CustomRequest + { + get { return _customRequest; } + set { setStringOption(CurlOption.CustomRequest, out _customRequest, value); } + } + + public string Interface + { + get { return _interface; } + set { setStringOption(CurlOption.Interface, out _interface, value); } + } + + public string Encoding + { + get { return _encoding; } + set { setStringOption(CurlOption.Encoding, out _encoding, value); } + } + + public string Krb4Level + { + get { return _krb4Level; } + set { setStringOption(CurlOption.Krb4Level, out _krb4Level, value); } + } + + public string CaInfo + { + get { return _caInfo; } + set { setStringOption(CurlOption.CaInfo, out _caInfo, value); } + } + + public string RandomFile + { + get { return _randomFile; } + set { setStringOption(CurlOption.RandomFile, out _randomFile, value); } + } + + public string EgdSocket + { + get { return _egdSocket; } + set { setStringOption(CurlOption.EgdSocket, out _egdSocket, value); } + } + + public string CookieJar + { + get { return _cookieJar; } + set { setStringOption(CurlOption.CookieJar, out _cookieJar, value); } + } + + public string CookieFile + { + get { return _cookieFile; } + set { setStringOption(CurlOption.CookieFile, out _cookieFile, value); } + } + + public string SslCipherList + { + get { return _sslCipherList; } + set { setStringOption(CurlOption.SslCipherList, out _sslCipherList, value); } + } + + public string WriteInfo + { + get { return _writeInfo; } + set { setStringOption(CurlOption.WriteInfo, out _writeInfo, value); } + } + + public string CaPath + { + get { return _caPath; } + set { setStringOption(CurlOption.CaPath, out _caPath, value); } + } + + public string SslKey + { + get { return _sslKey; } + set { setStringOption(CurlOption.SslKey, out _sslKey, value); } + } + + public string SslEngine + { + get { return _sslEngine; } + set { setStringOption(CurlOption.SslEngine, out _sslEngine, value); } + } + + public string SslKeyPasswd + { + get { return _sslKeyPasswd; } + set { setStringOption(CurlOption.SslKeyPasswd, out _sslKeyPasswd, value); } + } + + public string ErrorBuffer + { + get { return _errorBuffer; } + set { setStringOption(CurlOption.ErrorBuffer, out _errorBuffer, value); } + } + + public string NetRcFile + { + get { return _netRcFile; } + set { setStringOption(CurlOption.NetRcFile, out _netRcFile, value); } + } + + public string FtpAccount + { + get { return _ftpAccount; } + set { setStringOption(CurlOption.FtpAccount, out _ftpAccount, value); } + } + + public string SourceUrl + { + get { return _sourceUrl; } + set { setStringOption(CurlOption.SourceUrl, out _sourceUrl, value); } + } + + public string EffectiveUrl + { + get { return getStringInfo(CurlInfo.EffectiveUrl); } + } + + public string ContentType + { + get { return getStringInfo(CurlInfo.ContentType); } + } + + public int ResponseCode + { + get { return getIntInfo(CurlInfo.ResponseCode); } + } + + public int HeaderSize + { + get { return getIntInfo(CurlInfo.HeaderSize); } + } + + public int RequestSize + { + get { return getIntInfo(CurlInfo.RequestSize); } + } + + public bool Verbose + { + get { return _verbose; } + set { setBoolOption(CurlOption.Verbose, ref _verbose, value); } + } + + public int HttpAuthAvail + { + get { return getIntInfo(CurlInfo.HttpAuthAvail); } + } + + public int SslVerifyResult + { + get { return getIntInfo(CurlInfo.SslVerifyResult); } + } + + public int RedirectCount + { + get { return getIntInfo(CurlInfo.RedirectCount); } + } + + public int ProxyAuthAvail + { + get { return getIntInfo(CurlInfo.ProxyAuthAvail); } + } + + public int OsErrno + { + get { return getIntInfo(CurlInfo.OsErrno); } + } + + public int NumConnects + { + get { return getIntInfo(CurlInfo.NumConnects); } + } + + public int HttpConnectCode + { + get { return getIntInfo(CurlInfo.HttpConnectCode); } + } + + public DateTime FileTime + { + get { return getDateTimeInfo(CurlInfo.Filetime); } + } + + public double TotalTime + { + get { return getDoubleInfo(CurlInfo.TotalTime); } + } + + public double NameLookupTime + { + get { return getDoubleInfo(CurlInfo.NameLookupTime); } + } + + public double ConnectTime + { + get { return getDoubleInfo(CurlInfo.ConnectTime); } + } + + public double PreTransferTime + { + get { return getDoubleInfo(CurlInfo.PreTransferTime); } + } + + public double SizeUpload + { + get { return getDoubleInfo(CurlInfo.SizeUpload); } + } + + public double SizeDownload + { + get { return getDoubleInfo(CurlInfo.SizeDownload); } + } + + public double SpeedDownload + { + get { return getDoubleInfo(CurlInfo.SpeedDownload); } + } + + public double SpeedUpload + { + get { return getDoubleInfo(CurlInfo.SpeedUpload); } + } + + public double StartTransferTime + { + get { return getDoubleInfo(CurlInfo.StartTransferTime); } + } + + public double ContentLengthDownload + { + get { return getDoubleInfo(CurlInfo.ContentLengthDownload); } + } + + public double ContentLengthUpload + { + get { return getDoubleInfo(CurlInfo.ContentLengthUpload); } + } + + public double RedirectTime + { + get { return getDoubleInfo(CurlInfo.RedirectTime); } + } + + public CurlSlist SslEngines + { + get { return getSlistInfo(CurlInfo.SslEngines); } + } + + public CurlCode LastErrorCode + { + get { return _lastErrorCode; } + } + + /// + /// Cleanup unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void resetPrivateVariables() + { + _privateData = null; + + _pfCurlWrite = null; + _writeData = null; + + _pfCurlRead = null; + _readData = null; + + _pfCurlProgress = null; + _progressData = null; + + _pfCurlDebug = null; + _debugData = null; + + _pfCurlHeader = null; + _headerData = null; + + _pfCurlSslContext = null; + _sslContextData = null; + + _pfCurlIoctl = null; + _ioctlData = null; + } + + private CurlCode setMultiPartFormObject() + { + ensureHandle(); + var retCode = _httpMultiPartForm == null + ? CurlCode.BadFunctionArgument + : NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpPost, _httpMultiPartForm.GetHandle()); + setLastError(retCode, CurlOption.HttpPost); + return retCode; + } + + private CurlCode setSlistObject(CurlOption option, CurlSlist slist) + { + ensureHandle(); + var retCode = NativeMethods.curl_easy_setopt(_pCurl, option, slist == null ? IntPtr.Zero : slist.Handle); + setLastError(retCode, option); + return retCode; + } + + private CurlCode setShareObject() + { + ensureHandle(); + var retCode = _curlShare == null + ? CurlCode.BadFunctionArgument + : NativeMethods.curl_easy_setopt(_pCurl, CurlOption.Share, _curlShare.GetHandle()); + setLastError(retCode, CurlOption.Share); + return retCode; + } + + /// + /// Handles return code from all calls to 'curl_easy_xxx' functions. + /// + private void setLastError(CurlCode code, CurlOption opt) + { + if (LastErrorCode == CurlCode.Ok && code != CurlCode.Ok) + { + _lastErrorCode = code; + _lastErrorDescription = string.Format("Error: {0} setting option {1}", StrError(code), opt); + } + } + + /// + /// Handles return code from all calls to 'curl_easy_xxx' functions. + /// + private void setLastError(CurlCode code, CurlInfo info) + { + if (LastErrorCode == CurlCode.Ok && code != CurlCode.Ok) + { + _lastErrorCode = code; + _lastErrorDescription = string.Format("Error: {0} getting info {1}", StrError(code), info); + } + } + + /// + /// Destructor + /// + ~CurlEasy() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + lock (this) + { + if (disposing) + { + // free managed resources + //if (managedResource != null) + //{ + // managedResource.Dispose(); + // managedResource = null; + //} + } + + // free native resources if there are any. + if (_pCurl != IntPtr.Zero) + { +#if USE_LIBCURLSHIM + NativeMethods.curl_shim_cleanup_delegates(_ptrThis); + NativeMethods.curl_shim_free_strings(_pMyStrings); +#else + freeHandle(ref _curlWriteData); + freeHandle(ref _curlReadData); + freeHandle(ref _curlDebugData); + freeHandle(ref _curlProgressData); + freeHandle(ref _curlHeaderData); + freeHandle(ref _curlIoctlData); + freeHandle(ref _curlSslCtxData); +#endif + NativeMethods.curl_easy_cleanup(_pCurl); + + _hThis.Free(); + _pCurl = IntPtr.Zero; + } + } + } + + private void ensureHandle() + { + if (_pCurl == IntPtr.Zero) + throw new NullReferenceException("No internal easy handle"); + } + + internal IntPtr Handle + { + get + { + ensureHandle(); + return _pCurl; + } + } + + /// + /// Reset the internal cURL handle. + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public void Reset() + { + ensureHandle(); + NativeMethods.curl_easy_reset(_pCurl); + } + + private void setBoolOption(CurlOption option, ref bool field, bool value) + { + ensureHandle(); + field = value; + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) Convert.ToInt32(value)), option); + } + + private void setIntOption(CurlOption option, ref int field, int value) + { + ensureHandle(); + field = value; + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) value), option); + } + + private void setLongOption(CurlOption option, ref long field, long value) + { + ensureHandle(); + field = value; + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) value), option); + } + + private void setStringOption(CurlOption option, out string field, string value) + { + setStringOption(option, value); + field = value; + } + + private void setStringOption(CurlOption option, string value) + { + ensureHandle(); + if (string.IsNullOrEmpty(value)) + { + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, IntPtr.Zero), option); + } + else + { +#if USE_LIBCURLSHIM + var pCurlStr = NativeMethods.curl_shim_add_string(_pMyStrings, value); + if (pCurlStr != IntPtr.Zero) + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, pCurlStr), option); +#else + // convert the string to a null-terminated one + var buffer = System.Text.Encoding.UTF8.GetBytes(value + "\0"); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, buffer), option); +#endif + } + } + + /// + /// Set options for this object. See the EasyGet sample for + /// basic usage. + /// + /// This should be a valid . + /// + /// This should be a parameter of a varying + /// type based on the value of the option parameter. + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + /// + /// A , typically obtained from + /// cURL internally, but sometimes a + /// + /// will be returned if the type of value of parameter is invalid. + /// + public CurlCode SetOpt(CurlOption option, Object parameter) + { + ensureHandle(); + var retCode = CurlCode.Ok; + + // numeric cases + if ((int) option < CURLOPTTYPE_OBJECTPOINT) + { + var i = 0; + if (option == CurlOption.DnsUseGlobalCache || option == CurlOption.SourcePort) + { + return CurlCode.BadFunctionArgument; + } + + if (option == CurlOption.TimeValue) + { + // unboxing may throw class cast exception + var d = (DateTime) parameter; + var startTime = new DateTime(1970, 1, 1); + var currTime = new TimeSpan(DateTime.Now.Ticks - startTime.Ticks); + i = Convert.ToInt32(currTime.TotalSeconds); + } + else + i = Convert.ToInt32(parameter); + + retCode = NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) i); + } + + // object cases: the majority + else if ((int) option < CURLOPTTYPE_FUNCTIONPOINT) + { + return setObjectOptions(option, parameter); + } + // FUNCTIONPOINT args, for delegates + else if ((int) option < CURLOPTTYPE_OFF_T) + { + return setFunctionOptions(option, parameter); + } + // otherwise, it's one of those 64-bit off_t guys! + else + { + var i = Convert.ToInt64(parameter); + retCode = NativeMethods.curl_easy_setopt(_pCurl, option, i); + } + + return retCode; + } + + private CurlCode setObjectOptions(CurlOption option, object parameter) + { + var retCode = CurlCode.Ok; + switch (option) + { + // various data items + case CurlOption.Private: + _privateData = parameter; + break; + case CurlOption.WriteData: + _writeData = parameter; + break; + case CurlOption.ReadData: + _readData = parameter; + break; + case CurlOption.ProgressData: + _progressData = parameter; + break; + case CurlOption.DebugData: + _debugData = parameter; + break; + case CurlOption.HeaderData: + _headerData = parameter; + break; + case CurlOption.SslCtxData: + _sslContextData = parameter; + break; + case CurlOption.IoctlData: + _ioctlData = parameter; + break; + + // items that can't be set externally or + // obsolete items + case CurlOption.ErrorBuffer: + case CurlOption.Stderr: + case CurlOption.SourceHost: + case CurlOption.SourcePath: + case CurlOption.PasvHost: + return CurlCode.BadFunctionArgument; + + // singular case for share + case CurlOption.Share: + { + _curlShare = parameter as CurlShare; + retCode = setShareObject(); + break; + } + + // multipart HTTP post + case CurlOption.HttpPost: + { + _httpMultiPartForm = parameter as CurlHttpMultiPartForm; + retCode = setMultiPartFormObject(); + break; + } + + // items curl wants as a curl_slist + case CurlOption.HttpHeader: + case CurlOption.Prequote: + case CurlOption.Quote: + case CurlOption.Postquote: + case CurlOption.SourceQuote: + case CurlOption.TelnetOptions: + case CurlOption.Http200Aliases: + { + var slist = parameter as CurlSlist; + retCode = setSlistObject(option, slist); + break; + } + + // string items + default: + { + var s = parameter as string; + setStringOption(option, s); + retCode = _lastErrorCode; + break; + } + } + return retCode; + } + +#if !USE_LIBCURLSHIM + + #region Object pinning support + + /// + /// Free the pinned object + /// + /// + private void freeHandle(ref IntPtr handle) + { + if (handle == IntPtr.Zero) + return; + var handleCallback = GCHandle.FromIntPtr(handle); + handleCallback.Free(); + handle = IntPtr.Zero; + } + + /// + /// Pin the object in memory so the C function can find it + /// + /// + /// + private static IntPtr getHandle(object obj) + { + if (obj == null) + return IntPtr.Zero; + return GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Pinned)); + } + + /// + /// Returns the object passed to a Set...Data function. + /// Cast back to the original object. + /// + /// + /// + private static object getObject(IntPtr userdata) + { + if (userdata == IntPtr.Zero) + return null; + var handle = GCHandle.FromIntPtr(userdata); + return handle.Target; + } + + #endregion + +#endif + + private CurlCode setFunctionOptions(CurlOption option, object pfn) + { + switch (option) + { + case CurlOption.WriteFunction: + { + var wf = pfn as CurlWriteCallback; + if (wf == null) + return CurlCode.BadFunctionArgument; + _pfCurlWrite = wf; + break; + } + + case CurlOption.ReadFunction: + { + var rf = pfn as CurlReadCallback; + if (rf == null) + return CurlCode.BadFunctionArgument; + _pfCurlRead = rf; + break; + } + + case CurlOption.ProgressFunction: + { + var pf = pfn as CurlProgressCallback; + if (pf == null) + return CurlCode.BadFunctionArgument; + _pfCurlProgress = pf; + break; + } + + case CurlOption.DebugFunction: + { + var pd = pfn as CurlDebugCallback; + if (pd == null) + return CurlCode.BadFunctionArgument; + _pfCurlDebug = pd; + break; + } + + case CurlOption.HeaderFunction: + { + var hf = pfn as CurlHeaderCallback; + if (hf == null) + return CurlCode.BadFunctionArgument; + _pfCurlHeader = hf; + break; + } + + case CurlOption.SslCtxFunction: + { + var sf = pfn as CurlSslContextCallback; + if (sf == null) + return CurlCode.BadFunctionArgument; + _pfCurlSslContext = sf; + break; + } + + case CurlOption.IoctlFunction: + { + var iof = pfn as CurlIoctlCallback; + if (iof == null) + return CurlCode.BadFunctionArgument; + _pfCurlIoctl = iof; + break; + } + + default: + return CurlCode.BadFunctionArgument; + } + return CurlCode.Ok; + } + + /// + /// Perform a transfer. + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + /// + /// The obtained from the internal + /// call to curl_easy_perform(). + /// + public CurlCode Perform() + { + ensureHandle(); + return NativeMethods.curl_easy_perform(_pCurl); + } + + /// + /// Clone an CurlEasy object. + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + /// A cloned CurlEasy object. + public CurlEasy Clone() + { + return new CurlEasy(this); + } + + /// + /// Get a string description of an error code. + /// + /// Error code. + /// String description of the error code. + public String StrError(CurlCode code) + { + return Marshal.PtrToStringAnsi(NativeMethods.curl_easy_strerror(code)); + } + + /// + /// Extract information from a cURL handle. + /// + /// + /// One of the values in the + /// enumeration. + /// + /// + /// Reference to an object into which the + /// value specified by info is written. + /// + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref Object objInfo) + { + ensureHandle(); + var retCode = CurlCode.Ok; + var ptr = IntPtr.Zero; + + if ((int) info < CURLINFO_STRING) + return CurlCode.BadFunctionArgument; + + // trickery for filetime + if (info == CurlInfo.Filetime) + return CurlCode.BadFunctionArgument; + + // private data + if (info == CurlInfo.Private) + { + objInfo = _privateData; + return retCode; + } + + // string case + if ((int) info < CURLINFO_LONG) + { + retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + if (retCode == CurlCode.Ok) + objInfo = Marshal.PtrToStringAnsi(ptr); + return retCode; + } + + // int or double: return problem + return CurlCode.BadFunctionArgument; + } + + private string getStringInfo(CurlInfo info) + { + ensureHandle(); + var ptr = IntPtr.Zero; + var retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + setLastError(retCode, info); + return retCode == CurlCode.Ok ? Marshal.PtrToStringAnsi(ptr) : string.Empty; + } + + private int getIntInfo(CurlInfo info) + { + ensureHandle(); + // ensure it's an integral type + if ((int) info < CURLINFO_LONG || (int) info >= CURLINFO_DOUBLE) + { + setLastError(CurlCode.BadFunctionArgument, info); + return -1; + } + + var ptr = IntPtr.Zero; + var retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + setLastError(retCode, info); + return retCode == CurlCode.Ok ? (int) ptr : -1; + } + + private DateTime getDateTimeInfo(CurlInfo info) + { + var dt = new DateTime(); + setLastError(GetInfo(info, ref dt), info); + return dt; + } + + private double getDoubleInfo(CurlInfo info) + { + double val = 0; + setLastError(GetInfo(info, ref val), info); + return val; + } + + private CurlSlist getSlistInfo(CurlInfo info) + { + CurlSlist val = null; + setLastError(GetInfo(info, ref val), info); + return val; + } + + /// + /// Extract CurlSlist information from an CurlEasy object. + /// + /// + /// One of the values in the + /// enumeration. In this case, it must + /// specifically be one of the members that obtains an CurlSlist. + /// + /// Reference to an CurlSlist value. + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref CurlSlist slist) + { + ensureHandle(); + var retCode = CurlCode.Ok; + IntPtr ptr = IntPtr.Zero, ptrs = IntPtr.Zero; + + if ((int) info < CURLINFO_SLIST) + return CurlCode.BadFunctionArgument; + retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + if (retCode != CurlCode.Ok) + return retCode; + slist = new CurlSlist(); + while (ptr != IntPtr.Zero) + { +#if USE_LIBCURLSHIM + ptr = NativeMethods.curl_shim_get_string_from_slist(ptr, ref ptrs); + slist.Append(Marshal.PtrToStringAnsi(ptrs)); +#else + //TODO: implement + throw new NotImplementedException(); +#endif + } + return retCode; + } + + /// + /// Extract string information from an CurlEasy object. + /// + /// + /// One of the values in the + /// enumeration. In this case, it must + /// specifically be one of the members that obtains a string. + /// + /// Reference to an string value. + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref string strVal) + { + ensureHandle(); + var retCode = CurlCode.Ok; + var ptr = IntPtr.Zero; + + if ((int) info < CURLINFO_STRING || (int) info >= CURLINFO_LONG) + return CurlCode.BadFunctionArgument; + retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + if (retCode == CurlCode.Ok) + strVal = Marshal.PtrToStringAnsi(ptr); + return retCode; + } + + /// + /// Extract int information from an CurlEasy object. + /// + /// + /// One of the values in the + /// enumeration. In this case, it must + /// specifically be one of the members that obtains a double. + /// + /// Reference to an double value. + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref double dblVal) + { + ensureHandle(); + + // ensure it's an integral type + if ((int) info < CURLINFO_DOUBLE) + return CurlCode.BadFunctionArgument; + + return NativeMethods.curl_easy_getinfo(_pCurl, info, ref dblVal); + } + + /// + /// Extract int information from an CurlEasy object. + /// + /// + /// One of the values in the + /// enumeration. In this case, it must + /// specifically be one of the members that obtains an int. + /// + /// Reference to an int value. + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref int intVal) + { + ensureHandle(); + var retCode = CurlCode.Ok; + var ptr = IntPtr.Zero; + + // ensure it's an integral type + if ((int) info < CURLINFO_LONG || (int) info >= CURLINFO_DOUBLE) + return CurlCode.BadFunctionArgument; + + retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + if (retCode == CurlCode.Ok) + intVal = (int) ptr; + return retCode; + } + + /// + /// Extract DateTime information from an CurlEasy object. + /// + /// + /// One of the values in the + /// enumeration. In this case, it must + /// specifically be . + /// + /// Reference to a DateTime value. + /// + /// The obtained from the internal + /// call to curl_easy_getinfo(). + /// + /// + /// This is thrown if + /// the native CURL* handle wasn't created successfully. + /// + public CurlCode GetInfo(CurlInfo info, ref DateTime dt) + { + ensureHandle(); + var retCode = CurlCode.Ok; + var ptr = IntPtr.Zero; + + if (info != CurlInfo.Filetime) + return CurlCode.BadFunctionArgument; + + retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); + if (retCode == CurlCode.Ok) + { + if ((int) ptr < 0) + dt = new DateTime(0); + } + return retCode; + } + + // install the fuctions that will be called from libcurlshim + private void installDelegates() + { + ensureHandle(); + _hThis = GCHandle.Alloc(this); +#if USE_LIBCURLSHIM + _pcbWrite = _shimWriteCallback; + _pcbRead = _shimReadCallback; + _pcbProgress = _shimProgressCallback; + _pcbDebug = _shimDebugCallback; + _pcbHeader = _shimHeaderCallback; + _pcbSslCtx = _shimSslCtxCallback; + _pcbIoctl = _shimIoctlCallback; + _ptrThis = (IntPtr)_hThis; + NativeMethods.curl_shim_install_delegates( + _pCurl, _ptrThis, + _pcbWrite, _pcbRead, _pcbProgress, + _pcbDebug, _pcbHeader, _pcbSslCtx, + _pcbIoctl); +#else + _pcbWrite = _curlWriteCallback; + _pcbRead = _curlReadCallback; + _pcbProgress = _curlProgressCallback; + _pcbDebug = _curlDebugCallback; + _pcbHeader = _curlHeaderCallback; + _pcbSslCtx = _curlSslCtxCallback; + _pcbIoctl = _curlIoctlCallback; + + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.WriteFunction, _pcbWrite), + CurlOption.WriteFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.ReadFunction, _pcbRead), + CurlOption.ReadFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.ProgressFunction, _pcbProgress), + CurlOption.ProgressFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.HeaderFunction, _pcbHeader), + CurlOption.HeaderFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.DebugFunction, _pcbDebug), + CurlOption.DebugFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.SslCtxFunction, _pcbSslCtx), + CurlOption.SslCtxFunction); + setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.IoctlFunction, _pcbIoctl), + CurlOption.IoctlFunction); + setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.NoProgress, (IntPtr) 0), + CurlOption.NoProgress); + + setWriteData(null); + setReadData(null); + setHeaderData(null); + setProgressData(null); + setDebugData(null); + setSslCtxData(null); + setIoctlData(null); +#endif + } + +#if USE_LIBCURLSHIM + // called by libcurlshim + private static int _shimWriteCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) + { + var bytes = sz*nmemb; + var b = new byte[bytes]; + for (var i = 0; i < bytes; i++) + b[i] = Marshal.ReadByte(buf, i); + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return 0; + if (curlEasy._pfCurlWrite == null) + return bytes; // keep going + return curlEasy._pfCurlWrite(b, sz, nmemb, curlEasy._writeData); + } + + // called by libcurlshim + private static int _shimReadCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) + { + var bytes = sz*nmemb; + var b = new byte[bytes]; + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return 0; + if (curlEasy._pfCurlRead == null) + return 0; + var nRead = curlEasy._pfCurlRead(b, sz, nmemb, curlEasy._readData); + if (nRead > 0) + { + for (var i = 0; i < nRead; i++) + Marshal.WriteByte(buf, i, b[i]); + } + return nRead; + } + + // called by libcurlshim + private static int _shimProgressCallback(IntPtr parm, double dlTotal, double dlNow, double ulTotal, double ulNow) + { + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return 0; + if (curlEasy._pfCurlProgress == null) + return 0; + var nprog = curlEasy._pfCurlProgress(curlEasy._progressData, dlTotal, dlNow, ulTotal, ulNow); + return nprog; + } + + // called by libcurlshim + private static int _shimDebugCallback(CurlInfoType infoType, IntPtr msgBuf, int msgBufSize, IntPtr parm) + { + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return 0; + if (curlEasy._pfCurlDebug == null) + return 0; + var message = Marshal.PtrToStringAnsi(msgBuf, msgBufSize); + curlEasy._pfCurlDebug(infoType, message, curlEasy._debugData); + return 0; + } + + // called by libcurlshim + private static int _shimHeaderCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) + { + var bytes = sz*nmemb; + var b = new byte[bytes]; + for (var i = 0; i < bytes; i++) + b[i] = Marshal.ReadByte(buf, i); + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return 0; + if (curlEasy._pfCurlHeader == null) + return bytes; // keep going + return curlEasy._pfCurlHeader(b, sz, nmemb, curlEasy._headerData); + } + + // called by libcurlshim + private static int _shimSslCtxCallback(IntPtr ctx, IntPtr parm) + { + const int OK_RETURN = (int) CurlCode.Ok; + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + if (curlEasy == null) + return OK_RETURN; + if (curlEasy._pfCurlSslContext == null) + return OK_RETURN; // keep going + var context = new CurlSslContext(ctx); + return (int) curlEasy._pfCurlSslContext(context, curlEasy._sslContextData); + } + + // called by libcurlshim + private static CurlIoError _shimIoctlCallback(CurlIoCommand cmd, IntPtr parm) + { + var gch = (GCHandle) parm; + var curlEasy = (CurlEasy) gch.Target; + // let's require all of these to be non-null + if (curlEasy == null || curlEasy._pfCurlIoctl == null || curlEasy._ioctlData == null) + { + return CurlIoError.UnknownCommand; + } + return curlEasy._pfCurlIoctl(cmd, curlEasy._ioctlData); + } +#else + // called by libcurl + private int _curlWriteCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserData) + { + var bytes = sz*nmemb; + if (_pfCurlWrite == null) return bytes; // keep going + var buf = new byte[bytes]; + Marshal.Copy(pBuffer, buf, 0, bytes); + var userdata = getObject(pUserData); + return _pfCurlWrite(buf, sz, nmemb, userdata); + } + + private int _curlReadCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserData) + { + var bytes = sz*nmemb; + if (_pfCurlRead == null) return bytes; // keep going + var userdata = getObject(pUserData); + var buffer = new byte[bytes]; + var nRead = _pfCurlRead(buffer, sz, nmemb, userdata); + if (nRead > 0) + Marshal.Copy(buffer, 0, pBuffer, nRead); + return nRead; + } + + private int _curlProgressCallback(IntPtr ptrUserdata, double dlTotal, double dlNow, double ulTotal, double ulNow) + { + if (_pfCurlProgress != null) + { + var userdata = getObject(ptrUserdata); + return _pfCurlProgress(userdata, dlTotal, dlNow, ulTotal, ulNow); + } + return 0; + } + + private int _curlDebugCallback(IntPtr pCurl, CurlInfoType infoType, string message, int size, IntPtr pUserData) + { + if (_pfCurlDebug != null) + { + var userdata = getObject(pUserData); + _pfCurlDebug(infoType, message, userdata); + } + return 0; + } + + private int _curlHeaderCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserdata) + { + var bytes = sz*nmemb; + if (_pfCurlHeader != null) + { + var buf = new byte[bytes]; + Marshal.Copy(pBuffer, buf, 0, bytes); + var userdata = getObject(pUserdata); + return _pfCurlHeader(buf, sz, nmemb, userdata); + } + return bytes; // keep going + } + + private int _curlSslCtxCallback(IntPtr ctx, IntPtr parm) + { + if (_pfCurlSslContext == null) + return (int) CurlCode.Ok; // keep going + var context = new CurlSslContext(ctx); + return (int) _pfCurlSslContext(context, _sslContextData); + } + + private CurlIoError _curlIoctlCallback(CurlIoCommand cmd, IntPtr parm) + { + if (_pfCurlIoctl == null || _ioctlData == null) + return CurlIoError.UnknownCommand; + return _pfCurlIoctl(cmd, _ioctlData); + } +#endif + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlHttpMultiPartForm.cs b/src/CurlSharp/CurlHttpMultiPartForm.cs new file mode 100644 index 000000000..6f814cbd1 --- /dev/null +++ b/src/CurlSharp/CurlHttpMultiPartForm.cs @@ -0,0 +1,388 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// This trivial class wraps the internal curl_forms struct. + /// + public sealed class CurlForms + { + /// The . + public CurlFormOption Option; + + /// Value for the option. + public Object Value; + } + + /// + /// Wraps a section of multipart form data to be submitted via the + /// option in the + /// member of the class. + /// + public class CurlHttpMultiPartForm : IDisposable + { + // the two curlform pointers + private readonly IntPtr[] _pItems; + + /// + /// Constructor + /// + /// + /// This is thrown + /// if hasn't bee properly initialized. + /// + public CurlHttpMultiPartForm() + { + Curl.EnsureCurl(); + _pItems = new IntPtr[2]; + _pItems[0] = IntPtr.Zero; + _pItems[1] = IntPtr.Zero; + } + + /// + /// Free unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Destructor + /// + ~CurlHttpMultiPartForm() + { + Dispose(false); + } + + // for CurlEasy.SetOpt() + internal IntPtr GetHandle() + { + return _pItems[0]; + } + + /// + /// Add a multi-part form section. + /// + /// + /// Argument list, as described in the remarks. + /// + /// + /// A , hopefully + /// CurlFormCode.Ok. + /// + /// + /// This is definitely the workhorse method for this class. It + /// should be called in roughly the same manner as + /// curl_formadd(), except you would omit the first two + /// struct curl_httppost** arguments (firstitem and + /// lastitem), which are wrapped in this class. So you should + /// pass arguments in the following sequence: + /// + /// + /// CurlHttpMultiPartForm.AddSection(option1, value1, ..., optionX, valueX, + /// CurlFormOption.End) + /// + /// ; + /// + /// + /// For a complete list of possible options, see the documentation for + /// the enumeration. + /// + /// + /// The pointer options (PtrName, etc.) make an + /// internal copy of the passed byte array. Therefore, any + /// changes you make to the client copy of this array AFTER calling + /// this method, won't be reflected internally with cURL. The + /// purpose of providing the pointer options is to support the + /// posting of non-string binary data. + /// + /// + public CurlFormCode AddSection(params object[] args) + { + var nCount = args.Length; + var nRealCount = nCount; + var retCode = CurlFormCode.Ok; + CurlForms[] aForms = null; + + // one arg or even number of args is an error + if ((nCount == 1) || (nCount%2 == 0)) + return CurlFormCode.Incomplete; + + // ensure the last argument is End + var iCode = (CurlFormOption) + Convert.ToInt32(args.GetValue(nCount - 1)); + if (iCode != CurlFormOption.End) + return CurlFormCode.Incomplete; + + // walk through any passed arrays to get the true number of + // items and ensure the child arrays are properly (and not + // prematurely) terminated with End + for (var i = 0; i < nCount; i += 2) + { + iCode = (CurlFormOption) Convert.ToInt32(args.GetValue(i)); + switch (iCode) + { + case CurlFormOption.Array: + { + aForms = args.GetValue(i + 1) as CurlForms[]; + if (aForms == null) + return CurlFormCode.Incomplete; + var nFormsCount = aForms.Length; + for (var j = 0; j < nFormsCount; j++) + { + var pcf = aForms.GetValue(j) as CurlForms; + if (pcf == null) + return CurlFormCode.Incomplete; + if (j == nFormsCount - 1) + { + if (pcf.Option != CurlFormOption.End) + return CurlFormCode.Incomplete; + } + else + { + if (pcf.Option == CurlFormOption.End) + return CurlFormCode.Incomplete; + } + } + // -2 accounts for the fact that we're a) not + // including the item with End and b) not + // including Array in what we pass to cURL + nRealCount += 2*(nFormsCount - 2); + break; + } + } + } + + // allocate the IntPtr array for the data + var aPointers = new IntPtr[nRealCount]; + for (var i = 0; i < nRealCount - 1; i++) + aPointers[i] = IntPtr.Zero; + aPointers[nRealCount - 1] = (IntPtr) CurlFormOption.End; + + // now we go through the args + aForms = null; + var formArrayPos = 0; + var argArrayPos = 0; + var ptrArrayPos = 0; + Object obj = null; + + while ((retCode == CurlFormCode.Ok) && + (ptrArrayPos < nRealCount)) + { + if (aForms != null) + { + var pcf = aForms.GetValue(formArrayPos++) + as CurlForms; + if (pcf == null) + { + retCode = CurlFormCode.UnknownOption; + break; + } + iCode = pcf.Option; + obj = pcf.Value; + } + else + { + iCode = (CurlFormOption) Convert.ToInt32( + args.GetValue(argArrayPos++)); + obj = (iCode == CurlFormOption.End) + ? null + : args.GetValue(argArrayPos++); + } + + switch (iCode) + { + // handle byte-array pointer-related items + case CurlFormOption.PtrName: + case CurlFormOption.PtrContents: + case CurlFormOption.BufferPtr: + { + var bytes = obj as byte[]; + if (bytes == null) + retCode = CurlFormCode.UnknownOption; + else + { + var nLen = bytes.Length; + var ptr = Marshal.AllocHGlobal(nLen); + if (ptr != IntPtr.Zero) + { + aPointers[ptrArrayPos++] = (IntPtr) iCode; + // copy bytes to unmanaged buffer + for (var j = 0; j < nLen; j++) + Marshal.WriteByte(ptr, bytes[j]); + aPointers[ptrArrayPos++] = ptr; + } + else + retCode = CurlFormCode.Memory; + } + break; + } + + // length values + case CurlFormOption.NameLength: + case CurlFormOption.ContentsLength: + case CurlFormOption.BufferLength: + aPointers[ptrArrayPos++] = (IntPtr) iCode; + aPointers[ptrArrayPos++] = (IntPtr) + Convert.ToInt32(obj); + break; + + // strings + case CurlFormOption.CopyName: + case CurlFormOption.CopyContents: + case CurlFormOption.FileContent: + case CurlFormOption.File: + case CurlFormOption.ContentType: + case CurlFormOption.Filename: + case CurlFormOption.Buffer: + { + aPointers[ptrArrayPos++] = (IntPtr) iCode; + var s = obj as String; + if (s == null) + retCode = CurlFormCode.UnknownOption; + else + { + var p = Marshal.StringToHGlobalAnsi(s); + if (p != IntPtr.Zero) + aPointers[ptrArrayPos++] = p; + else + retCode = CurlFormCode.Memory; + } + break; + } + + // array case: already handled + case CurlFormOption.Array: + if (aForms != null) + retCode = CurlFormCode.IllegalArray; + else + { + aForms = obj as CurlForms[]; + if (aForms == null) + retCode = CurlFormCode.UnknownOption; + } + break; + + // slist + case CurlFormOption.ContentHeader: + { + aPointers[ptrArrayPos++] = (IntPtr) iCode; + var s = obj as CurlSlist; + if (s == null) + retCode = CurlFormCode.UnknownOption; + else + aPointers[ptrArrayPos++] = s.Handle; + break; + } + + // erroneous stuff + case CurlFormOption.Nothing: + retCode = CurlFormCode.Incomplete; + break; + + // end + case CurlFormOption.End: + if (aForms != null) // end of form + { + aForms = null; + formArrayPos = 0; + } + else + aPointers[ptrArrayPos++] = (IntPtr) iCode; + break; + + // default is unknown + default: + retCode = CurlFormCode.UnknownOption; + break; + } + } + + // ensure we didn't come up short on parameters + if (ptrArrayPos != nRealCount) + retCode = CurlFormCode.Incomplete; + + // if we're OK here, call into curl + if (retCode == CurlFormCode.Ok) + { +#if USE_LIBCURLSHIM + retCode = (CurlFormCode) NativeMethods.curl_shim_formadd(_pItems, aPointers, nRealCount); +#else + retCode = (CurlFormCode) NativeMethods.curl_formadd(ref _pItems[0], ref _pItems[1], + (int) aPointers[0], aPointers[1], + (int) aPointers[2], aPointers[3], + (int) aPointers[4]); +#endif + } + + // unmarshal native allocations + for (var i = 0; i < nRealCount - 1; i += 2) + { + iCode = (CurlFormOption) (int) aPointers[i]; + switch (iCode) + { + case CurlFormOption.CopyName: + case CurlFormOption.CopyContents: + case CurlFormOption.FileContent: + case CurlFormOption.File: + case CurlFormOption.ContentType: + case CurlFormOption.Filename: + case CurlFormOption.Buffer: + // byte buffer cases + case CurlFormOption.PtrName: + case CurlFormOption.PtrContents: + case CurlFormOption.BufferPtr: + { + if (aPointers[i + 1] != IntPtr.Zero) + Marshal.FreeHGlobal(aPointers[i + 1]); + break; + } + + default: + break; + } + } + + return retCode; + } + + private void Dispose(bool disposing) + { + lock (this) + { + if (disposing) + { + // clean up managed objects + } + + // clean up native objects + if (_pItems[0] != IntPtr.Zero) + NativeMethods.curl_formfree(_pItems[0]); + _pItems[0] = IntPtr.Zero; + _pItems[1] = IntPtr.Zero; + } + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlMulti.cs b/src/CurlSharp/CurlMulti.cs new file mode 100644 index 000000000..d2f7dfd6b --- /dev/null +++ b/src/CurlSharp/CurlMulti.cs @@ -0,0 +1,302 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Collections; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// Implements the curl_multi_xxx API. + /// + public class CurlMulti : IDisposable + { + // private members + private readonly Hashtable _htEasy; + private int _maxFd; + private CurlMultiInfo[] _multiInfo; + private bool _bGotMultiInfo; +#if USE_LIBCURLSHIM + private IntPtr _fdSets; +#else + private NativeMethods.fd_set _fd_read, _fd_write, _fd_except; +#endif + private IntPtr _pMulti; + + /// + /// Constructor + /// + /// + /// This is thrown + /// if hasn't bee properly initialized. + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMulti() + { + Curl.EnsureCurl(); + _pMulti = NativeMethods.curl_multi_init(); + ensureHandle(); + _maxFd = 0; +#if USE_LIBCURLSHIM + _fdSets = IntPtr.Zero; + _fdSets = NativeMethods.curl_shim_alloc_fd_sets(); +#else + _fd_read = NativeMethods.fd_set.Create(); + _fd_read = NativeMethods.fd_set.Create(); + _fd_write = NativeMethods.fd_set.Create(); + _fd_except = NativeMethods.fd_set.Create(); +#endif + _multiInfo = null; + _bGotMultiInfo = false; + _htEasy = new Hashtable(); + } + + /// + /// Max file descriptor + /// + public int MaxFd + { + get { return _maxFd; } + } + + /// + /// Cleanup unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Destructor + /// + ~CurlMulti() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + lock (this) + { + // if (disposing) // managed member cleanup + // unmanaged cleanup + if (_pMulti != IntPtr.Zero) + { + NativeMethods.curl_multi_cleanup(_pMulti); + _pMulti = IntPtr.Zero; + } + +#if USE_LIBCURLSHIM + if (_fdSets != IntPtr.Zero) + { + NativeMethods.curl_shim_free_fd_sets(_fdSets); + _fdSets = IntPtr.Zero; + } +#else + _fd_read.Cleanup(); + _fd_write.Cleanup(); + _fd_except.Cleanup(); +#endif + } + } + + private void ensureHandle() + { + if (_pMulti == IntPtr.Zero) + throw new NullReferenceException("No internal multi handle"); + } + + /// + /// Add an CurlEasy object. + /// + /// + /// object to add. + /// + /// + /// A , hopefully CurlMultiCode.Ok + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMultiCode AddHandle(CurlEasy curlEasy) + { + ensureHandle(); + var p = curlEasy.Handle; + _htEasy.Add(p, curlEasy); + return NativeMethods.curl_multi_add_handle(_pMulti, p); + } + + /// + /// Remove an CurlEasy object. + /// + /// + /// object to remove. + /// + /// + /// A , hopefully CurlMultiCode.Ok + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMultiCode RemoveHandle(CurlEasy curlEasy) + { + ensureHandle(); + var p = curlEasy.Handle; + _htEasy.Remove(p); + return NativeMethods.curl_multi_remove_handle(_pMulti, curlEasy.Handle); + } + + /// + /// Get a string description of an error code. + /// + /// + /// The for which to obtain the error + /// string description. + /// + /// The string description. + public String StrError(CurlMultiCode errorNum) + { + return Marshal.PtrToStringAnsi(NativeMethods.curl_multi_strerror(errorNum)); + } + + /// + /// Read/write data to/from each CurlEasy object. + /// + /// + /// The number of objects still in process is + /// written by this function to this reference parameter. + /// + /// + /// A , hopefully CurlMultiCode.Ok + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMultiCode Perform(ref int runningObjects) + { + ensureHandle(); + return NativeMethods.curl_multi_perform(_pMulti, ref runningObjects); + } + + /// + /// Set internal file desriptor information before calling Select. + /// + /// + /// A , hopefully CurlMultiCode.Ok + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMultiCode FdSet() + { + ensureHandle(); +#if USE_LIBCURLSHIM + return NativeMethods.curl_shim_multi_fdset(_pMulti, _fdSets, ref _maxFd); +#else + NativeMethods.FD_ZERO(_fd_read); + NativeMethods.FD_ZERO(_fd_write); + NativeMethods.FD_ZERO(_fd_except); + return NativeMethods.curl_multi_fdset(_pMulti, ref _fd_read, ref _fd_write, ref _fd_except, ref _maxFd); +#endif + } + + /// + /// Call select() on the CurlEasy objects. + /// + /// + /// The timeout for the internal select() call, + /// in milliseconds. + /// + /// + /// Number or objects with pending reads. + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public int Select(int timeoutMillis) + { + ensureHandle(); +#if USE_LIBCURLSHIM + return NativeMethods.curl_shim_select(_maxFd + 1, _fdSets, timeoutMillis); +#else + var timeout = NativeMethods.timeval.Create(timeoutMillis); + return NativeMethods.select(_maxFd + 1, ref _fd_read, ref _fd_write, ref _fd_except, ref timeout); + //return NativeMethods.select2(_maxFd + 1, _fd_read, _fd_write, _fd_except, timeout); +#endif + } + + /// + /// Obtain status information for a CurlMulti transfer. Requires + /// CurlSharp be compiled with the libcurlshim helper. + /// + /// + /// An array of objects, one for each + /// object child. + /// + /// + /// This is thrown if the native CurlMulti handle wasn't + /// created successfully. + /// + public CurlMultiInfo[] InfoRead() + { + if (_bGotMultiInfo) + return _multiInfo; + + _bGotMultiInfo = true; + +#if USE_LIBCURLSHIM + var nMsgs = 0; + var pInfo = NativeMethods.curl_shim_multi_info_read(_pMulti, ref nMsgs); + if (pInfo != IntPtr.Zero) + { + _multiInfo = new CurlMultiInfo[nMsgs]; + for (var i = 0; i < nMsgs; i++) + { + var msg = (CurlMessage) Marshal.ReadInt32(pInfo, i*12); + var pEasy = Marshal.ReadIntPtr(pInfo, i*12 + 4); + var code = (CurlCode) Marshal.ReadInt32(pInfo, i*12 + 8); + _multiInfo[i] = new CurlMultiInfo(msg, (CurlEasy) _htEasy[pEasy], code); + } + NativeMethods.curl_shim_multi_info_free(pInfo); + } + + return _multiInfo; + +#else + + throw new NotImplementedException( + "Sorry, CurlMulti.InfoRead is not implemented on this system." + ); + +#endif + + } + } +} diff --git a/src/CurlSharp/CurlMultiInfo.cs b/src/CurlSharp/CurlMultiInfo.cs new file mode 100644 index 000000000..aa9ab9a44 --- /dev/null +++ b/src/CurlSharp/CurlMultiInfo.cs @@ -0,0 +1,65 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +namespace CurlSharp +{ + /// + /// Wraps the cURL struct CURLMsg. This class provides + /// status information following a transfer. + /// + public sealed class CurlMultiInfo + { + // private members + private readonly CurlEasy _mCurlEasy; + private readonly CurlMessage _msg; + private readonly CurlCode _result; + + internal CurlMultiInfo(CurlMessage msg, CurlEasy curlEasy, CurlCode result) + { + _msg = msg; + _mCurlEasy = curlEasy; + _result = result; + } + + /// + /// Get the status code from the enumeration. + /// + public CurlMessage Msg + { + get { return _msg; } + } + + /// + /// Get the object for this child. + /// + public CurlEasy CurlEasyHandle + { + get { return _mCurlEasy; } + } + + /// + /// Get the return code for the transfer, as a + /// . + /// + public CurlCode Result + { + get { return _result; } + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlShare.cs b/src/CurlSharp/CurlShare.cs new file mode 100644 index 000000000..636f35c84 --- /dev/null +++ b/src/CurlSharp/CurlShare.cs @@ -0,0 +1,276 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// This class provides an infrastructure for serializing access to data + /// shared by multiple objects, including cookie data + /// and Dns hosts. It implements the curl_share_xxx API. + /// + public class CurlShare : IDisposable + { + // private members + private GCHandle _hThis; // for handle extraction + private CurlShareCode _lastErrorCode; + private string _lastErrorDescription; +#if USE_LIBCURLSHIM + private NativeMethods._ShimLockCallback _pDelLock; // lock delegate + private NativeMethods._ShimUnlockCallback _pDelUnlock; // unlock delegate +#endif + private IntPtr _pShare; // share handle + private CurlShareLockCallback _pfLock; // client lock delegate + private CurlShareUnlockCallback _pfUnlock; // client unlock delegate + private IntPtr _ptrThis; // numeric handle + private Object _userData; // user data for delegates + + /// + /// Constructor + /// + /// + /// This is thrown + /// if hasn't bee properly initialized. + /// + /// + /// This is thrown if + /// the native share handle wasn't created successfully. + /// + public CurlShare() + { + Curl.EnsureCurl(); + _pShare = NativeMethods.curl_share_init(); + EnsureHandle(); + LockFunction = null; + UnlockFunction = null; + UserData = null; + installDelegates(); + } + + public object UserData + { + get { return _userData; } + set { _userData = value; } + } + + public CurlShareUnlockCallback UnlockFunction + { + get { return _pfUnlock; } + set { _pfUnlock = value; } + } + + public CurlShareLockCallback LockFunction + { + get { return _pfLock; } + set { _pfLock = value; } + } + + public CurlLockData Share + { + set { setShareOption(CurlShareOption.Share, value); } + } + + public CurlLockData Unshare + { + set { setShareOption(CurlShareOption.Unshare, value); } + } + + public CurlShareCode LastErrorCode + { + get { return _lastErrorCode; } + } + + public string LastErrorDescription + { + get { return _lastErrorDescription; } + } + + /// + /// Cleanup unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Destructor + /// + ~CurlShare() + { + Dispose(false); + } + + /// + /// Set options for this object. + /// + /// + /// One of the values in the + /// enumeration. + /// + /// + /// An appropriate object based on the value passed in the + /// option argument. See + /// for more information about the appropriate parameter type. + /// + /// + /// A , hopefully + /// CurlShareCode.Ok. + /// + /// + /// This is thrown if + /// the native share handle wasn't created successfully. + /// + public CurlShareCode SetOpt(CurlShareOption option, Object parameter) + { + EnsureHandle(); + var retCode = CurlShareCode.Ok; + + switch (option) + { + case CurlShareOption.LockFunction: + var lf = parameter as CurlShareLockCallback; + if (lf == null) + return CurlShareCode.BadOption; + _pfLock = lf; + break; + + case CurlShareOption.UnlockFunction: + var ulf = parameter as CurlShareUnlockCallback; + if (ulf == null) + return CurlShareCode.BadOption; + _pfUnlock = ulf; + break; + + case CurlShareOption.Share: + case CurlShareOption.Unshare: + { + var opt = (CurlLockData) Convert.ToInt32(parameter); + retCode = setShareOption(option, opt); + break; + } + + case CurlShareOption.UserData: + _userData = parameter; + break; + + default: + retCode = CurlShareCode.BadOption; + break; + } + return retCode; + } + + private void setLastError(CurlShareCode code, CurlShareOption opt) + { + if (_lastErrorCode == CurlShareCode.Ok && code != CurlShareCode.Ok) + { + _lastErrorCode = code; + _lastErrorDescription = string.Format("Error: {0} setting option {1}", StrError(code), opt); + } + } + + private CurlShareCode setShareOption(CurlShareOption option, CurlLockData value) + { + var retCode = (value != CurlLockData.Cookie) && (value != CurlLockData.Dns) + ? CurlShareCode.BadOption + : NativeMethods.curl_share_setopt(_pShare, option, (IntPtr) value); + setLastError(retCode, option); + return retCode; + } + + /// + /// Return a String description of an error code. + /// + /// + /// The for which to obtain the error + /// string description. + /// + /// The string description. + public String StrError(CurlShareCode errorNum) + { + return Marshal.PtrToStringAnsi(NativeMethods.curl_share_strerror(errorNum)); + } + + private void Dispose(bool disposing) + { + lock (this) + { + // if (disposing) cleanup managed objects + if (_pShare != IntPtr.Zero) + { +#if USE_LIBCURLSHIM + NativeMethods.curl_shim_cleanup_share_delegates(_pShare); +#endif + NativeMethods.curl_share_cleanup(_pShare); + _hThis.Free(); + _ptrThis = IntPtr.Zero; + _pShare = IntPtr.Zero; + } + } + } + + internal IntPtr GetHandle() + { + return _pShare; + } + + private void EnsureHandle() + { + if (_pShare == IntPtr.Zero) + throw new NullReferenceException("No internal share handle"); + } + + private void installDelegates() + { + _hThis = GCHandle.Alloc(this); + _ptrThis = (IntPtr)_hThis; +#if USE_LIBCURLSHIM + _pDelLock = LockDelegate; + _pDelUnlock = UnlockDelegate; + NativeMethods.curl_shim_install_share_delegates(_pShare, _ptrThis, _pDelLock, _pDelUnlock); +#endif + } + + internal static void LockDelegate(int data, int access, IntPtr userPtr) + { + var gch = (GCHandle) userPtr; + var share = (CurlShare) gch.Target; + if (share == null) + return; + if (share.LockFunction == null) + return; + share.LockFunction((CurlLockData) data, (CurlLockAccess) access, share.UserData); + } + + internal static void UnlockDelegate(int data, IntPtr userPtr) + { + var gch = (GCHandle) userPtr; + var share = (CurlShare) gch.Target; + if (share == null) + return; + if (share.UnlockFunction == null) + return; + share.UnlockFunction((CurlLockData) data, share.UserData); + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlSharp.csproj b/src/CurlSharp/CurlSharp.csproj new file mode 100644 index 000000000..73c924594 --- /dev/null +++ b/src/CurlSharp/CurlSharp.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {74420A79-CC16-442C-8B1E-7C1B913844F0} + Library + Properties + CurlSharp + CurlSharp + 512 + 12.0.0 + 2.0 + + + true + full + false + bin\Debug + DEBUG;LINUX + 4 + false + true + + + full + true + bin\Release + 4 + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/CurlSharp/CurlSlist.cs b/src/CurlSharp/CurlSlist.cs new file mode 100644 index 000000000..8d2423188 --- /dev/null +++ b/src/CurlSharp/CurlSlist.cs @@ -0,0 +1,144 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// This class wraps a linked list of strings used in cURL. Use it + /// to build string lists where they're required, such as when calling + /// with + /// as the option. + /// + public class CurlSlist : IDisposable + { +#if !USE_LIBCURLSHIM + [StructLayout(LayoutKind.Sequential)] + private class curl_slist + { + /// char* + [MarshalAs(UnmanagedType.LPStr)] public string data; + + /// curl_slist* + public IntPtr next; + } +#endif + private IntPtr _handle; + + /// + /// Constructor + /// + /// + /// This is thrown + /// if hasn't bee properly initialized. + /// + public CurlSlist() + { + Curl.EnsureCurl(); + _handle = IntPtr.Zero; + } + + public CurlSlist(IntPtr handle) + { + _handle = handle; + } + + /// + /// Read-only copy of the strings stored in the SList + /// + public List Strings + { + get + { + if (_handle == IntPtr.Zero) + return null; + var strings = new List(); + +#if !USE_LIBCURLSHIM + var slist = new curl_slist(); + Marshal.PtrToStructure(_handle, slist); + + while (true) + { + strings.Add(slist.data); + if (slist.next != IntPtr.Zero) + Marshal.PtrToStructure(slist.next, slist); + else + break; + } +#endif + return strings; + } + } + + /// + /// Destructor + /// + ~CurlSlist() + { + Dispose(false); + } + + /// + /// Append a string to the list. + /// + /// The string to append. + public void Append(string str) + { +#if USE_LIBCURLSHIM + _handle = NativeMethods.curl_shim_add_string_to_slist(_handle, str); +#else + _handle = NativeMethods.curl_slist_append(_handle, str); +#endif + } + + /// + /// Free all internal strings. + /// + public void Dispose() + { + GC.SuppressFinalize(this); + Dispose(true); + } + + internal IntPtr Handle + { + get { return _handle; } + } + + private void Dispose(bool disposing) + { + lock (this) + { + if (_handle != IntPtr.Zero) + { +#if USE_LIBCURLSHIM + NativeMethods.curl_shim_free_slist(_handle); +#else + NativeMethods.curl_slist_free_all(_handle); +#endif + _handle = IntPtr.Zero; + } + } + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlSslContext.cs b/src/CurlSharp/CurlSslContext.cs new file mode 100644 index 000000000..d24ef2698 --- /dev/null +++ b/src/CurlSharp/CurlSslContext.cs @@ -0,0 +1,49 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; + +namespace CurlSharp +{ + /// + /// An instance of this class is passed to the delegate + /// , if it's implemented. + /// Within that delegate, the code will have to make native calls to + /// the OpenSSL library with the value returned from the + /// property cast to an + /// SSL_CTX pointer. + /// + public sealed class CurlSslContext + { + private readonly IntPtr _pvContext; + + internal CurlSslContext(IntPtr pvContext) + { + _pvContext = pvContext; + } + + /// + /// Get the underlying OpenSSL context. + /// + public IntPtr Context + { + get { return _pvContext; } + } + } +} \ No newline at end of file diff --git a/src/CurlSharp/CurlVersionInfoData.cs b/src/CurlSharp/CurlVersionInfoData.cs new file mode 100644 index 000000000..8bd8af882 --- /dev/null +++ b/src/CurlSharp/CurlVersionInfoData.cs @@ -0,0 +1,207 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2013 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// This class wraps a curl_version_info_data struct. An instance is + /// obtained by calling . + /// + public sealed class CurlVersionInfoData + { + private const int OFFSET_AGE = 0; + private const int OFFSET_VERSION = 4; + private const int OFFSET_VERSION_NUM = 8; + private const int OFFSET_HOST = 12; + private const int OFFSET_FEATURES = 16; + private const int OFFSET_SSL_VERSION = 20; + private const int OFFSET_SSL_VERSION_NUM = 24; + private const int OFFSET_LIBZ_VERSION = 28; + private const int OFFSET_PROTOCOLS = 32; + private const int OFFSET_ARES_VERSION = 36; + private const int OFFSET_ARES_VERSION_NUM = 40; + private const int OFFSET_LIBIDN_VERSION = 44; + + private readonly IntPtr m_pVersionInfoData; + + internal CurlVersionInfoData(CurlVersion ver) + { + m_pVersionInfoData = NativeMethods.curl_version_info(ver); + } +#if USE_LIBCURLSHIM + /// + /// Age of this struct, depending on how recent the linked-in + /// libcurl is, as a . + /// + public CurlVersion Age + { + get { return (CurlVersion) NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_AGE); } + } + + /// + /// Get the internal cURL version, as a string. + /// + public string Version + { + get + { + return Marshal.PtrToStringAnsi( + NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, OFFSET_VERSION)); + } + } + + /// + /// Get the internal cURL version number, a A 24-bit number created + /// like this: [8 bits major number] | [8 bits minor number] | [8 + /// bits patch number]. For example, Version 7.12.2 is 0x070C02. + /// + public int VersionNum + { + get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_VERSION_NUM); } + } + + /// + /// Get the host information on which the underlying cURL was built. + /// + public string Host + { + get + { + return + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, OFFSET_HOST)); + } + } + + /// + /// Get a bitmask of features, containing bits or'd from the + /// enumeration. + /// + public int Features + { + get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_FEATURES); } + } + + /// + /// Get the Ssl version, if it's linked in. + /// + public string SslVersion + { + get + { + return + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, + OFFSET_SSL_VERSION)); + } + } + + /// + /// Get the Ssl version number, if Ssl is linked in. + /// + public int SSLVersionNum + { + get { return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_SSL_VERSION_NUM); } + } + + /// + /// Get the libz version, if libz is linked in. + /// + public string LibZVersion + { + get + { + return + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, + OFFSET_LIBZ_VERSION)); + } + } + + /// + /// Get the names of the supported protocols. + /// + public string[] Protocols + { + get + { + var nProts = NativeMethods.curl_shim_get_number_of_protocols( + m_pVersionInfoData, OFFSET_PROTOCOLS); + var aProts = new String[nProts]; + for (var i = 0; i < nProts; i++) + { + aProts[i] = + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_protocol_string(m_pVersionInfoData, + OFFSET_PROTOCOLS, i)); + } + return aProts; + } + } + + /// + /// Get the ARes version, if ARes is linked in. + /// + public string ARes + { + get + { + if (Age > CurlVersion.First) + { + return + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, + OFFSET_ARES_VERSION)); + } + return "n.a."; + } + } + + /// + /// Get the ARes version number, if ARes is linked in. + /// + public int AResNum + { + get + { + if (Age > CurlVersion.First) + { + return NativeMethods.curl_shim_get_version_int_value(m_pVersionInfoData, OFFSET_ARES_VERSION_NUM); + } + return 0; + } + } + + /// + /// Get the libidn version, if libidn is linked in. + /// + public string LibIdn + { + get + { + if (Age > CurlVersion.Second) + { + return + Marshal.PtrToStringAnsi(NativeMethods.curl_shim_get_version_char_ptr(m_pVersionInfoData, + OFFSET_LIBIDN_VERSION)); + } + return "n.a."; + } + } +#endif + } +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlClosePolicy.cs b/src/CurlSharp/Enums/CurlClosePolicy.cs new file mode 100644 index 000000000..a40b591c9 --- /dev/null +++ b/src/CurlSharp/Enums/CurlClosePolicy.cs @@ -0,0 +1,46 @@ +namespace CurlSharp +{ + /// + /// Contains values used to specify the order in which cached connections + /// are closed. One of these is passed as the + /// option in a call + /// to + /// + public enum CurlClosePolicy + { + /// + /// No close policy. Never use this. + /// + None = 0, + + /// + /// Close the oldest cached connections first. + /// + Oldest = 1, + + /// + /// Close the least recently used connections first. + /// + LeastRecentlyUsed = 2, + + /// + /// Close the connections with the least traffic first. + /// + LeastTraffic = 3, + + /// + /// Close the slowest connections first. + /// + Slowest = 4, + + /// + /// Currently unimplemented. + /// + Callback = 5, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 6 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlCode.cs b/src/CurlSharp/Enums/CurlCode.cs new file mode 100644 index 000000000..fc158c0eb --- /dev/null +++ b/src/CurlSharp/Enums/CurlCode.cs @@ -0,0 +1,403 @@ +namespace CurlSharp +{ + /// + /// Status code returned from functions. + /// + public enum CurlCode + { + /// + /// All fine. Proceed as usual. + /// + Ok = 0, + + /// + /// Aborted by callback. An internal callback returned "abort" + /// to libcurl. + /// + AbortedByCallback = 42, + + /// + /// Internal error. A function was called in a bad order. + /// + BadCallingOrder = 44, + + /// + /// Unrecognized transfer encoding. + /// + BadContentEncoding = 61, + + /// + /// Attempting FTP resume beyond file size. + /// + BadDownloadResume = 36, + + /// + /// Internal error. A function was called with a bad parameter. + /// + BadFunctionArgument = 43, + + /// + /// Bad password entered. An error was signaled when the password was + /// entered. This can also be the result of a "bad password" returned + /// from a specified password callback. + /// + BadPasswordEntered = 46, + + /// + /// Failed to connect to host or proxy. + /// + CouldntConnect = 7, + + /// + /// Couldn't resolve host. The given remote host was not resolved. + /// + CouldntResolveHost = 6, + + /// + /// Couldn't resolve proxy. The given proxy host could not be resolved. + /// + CouldntResolveProxy = 5, + + /// + /// Very early initialization code failed. This is likely to be an + /// internal error or problem. + /// + FailedInit = 2, + + /// + /// Maximum file size exceeded. + /// + FilesizeExceeded = 63, + + /// + /// A file given with FILE:// couldn't be opened. Most likely + /// because the file path doesn't identify an existing file. Did + /// you check file permissions? + /// + FileCouldntReadFile = 37, + + /// + /// We were denied access when trying to login to an FTP server or + /// when trying to change working directory to the one given in the URL. + /// + FtpAccessDenied = 9, + + /// + /// An internal failure to lookup the host used for the new + /// connection. + /// + FtpCantGetHost = 15, + + /// + /// A bad return code on either PASV or EPSV was sent by the FTP + /// server, preventing libcurl from being able to continue. + /// + FtpCantReconnect = 16, + + /// + /// The FTP SIZE command returned error. SIZE is not a kosher FTP + /// command, it is an extension and not all servers support it. This + /// is not a surprising error. + /// + FtpCouldntGetSize = 32, + + /// + /// This was either a weird reply to a 'RETR' command or a zero byte + /// transfer complete. + /// + FtpCouldntRetrFile = 19, + + /// + /// libcurl failed to set ASCII transfer type (TYPE A). + /// + FtpCouldntSetAscii = 29, + + /// + /// Received an error when trying to set the transfer mode to binary. + /// + FtpCouldntSetBinary = 17, + + /// + /// FTP couldn't STOR file. The server denied the STOR operation. + /// The error buffer usually contains the server's explanation to this. + /// + FtpCouldntStorFile = 25, + + /// + /// The FTP REST command returned error. This should never happen + /// if the server is sane. + /// + FtpCouldntUseRest = 31, + + /// + /// The FTP PORT command returned error. This mostly happen when + /// you haven't specified a good enough address for libcurl to use. + /// See . + /// + FtpPortFailed = 30, + + /// + /// When sending custom "QUOTE" commands to the remote server, one + /// of the commands returned an error code that was 400 or higher. + /// + FtpQuoteError = 21, + + /// + /// Requested FTP Ssl level failed. + /// + FtpSslFailed = 64, + + /// + /// The FTP server rejected access to the server after the password + /// was sent to it. It might be because the username and/or the + /// password were incorrect or just that the server is not allowing + /// you access for the moment etc. + /// + FtpUserPasswordIncorrect = 10, + + /// + /// FTP servers return a 227-line as a response to a PASV command. + /// If libcurl fails to parse that line, this return code is + /// passed back. + /// + FtpWeird227Format = 14, + + /// + /// After having sent the FTP password to the server, libcurl expects + /// a proper reply. This error code indicates that an unexpected code + /// was returned. + /// + FtpWeirdPassReply = 11, + + /// + /// libcurl failed to get a sensible result back from the server as + /// a response to either a PASV or a EPSV command. The server is flawed. + /// + FtpWeirdPasvReply = 13, + + /// + /// After connecting to an FTP server, libcurl expects to get a + /// certain reply back. This error code implies that it got a strange + /// or bad reply. The given remote server is probably not an + /// OK FTP server. + /// + FtpWeirdServerReply = 8, + + /// + /// After having sent user name to the FTP server, libcurl expects a + /// proper reply. This error code indicates that an unexpected code + /// was returned. + /// + FtpWeirdUserReply = 12, + + /// + /// After a completed file transfer, the FTP server did not respond a + /// proper "transfer successful" code. + /// + FtpWriteError = 20, + + /// + /// Function not found. A required LDAP function was not found. + /// + FunctionNotFound = 41, + + /// + /// Nothing was returned from the server, and under the circumstances, + /// getting nothing is considered an error. + /// + GotNothing = 52, + + /// + /// This is an odd error that mainly occurs due to internal confusion. + /// + HttpPostError = 34, + + /// + /// The HTTP server does not support or accept range requests. + /// + HttpRangeError = 33, + + /// + /// This is returned if + /// is set TRUE and the HTTP server returns an error code that + /// is >= 400. + /// + HttpReturnedError = 22, + + /// + /// Interface error. A specified outgoing interface could not be + /// used. Set which interface to use for outgoing connections' + /// source IP address with . + /// + InterfaceFailed = 45, + + /// + /// End-of-enumeration marker; do not use in client applications. + /// + Last = 67, + + /// + /// LDAP cannot bind. LDAP bind operation failed. + /// + LdapCannotBind = 38, + + /// + /// Invalid LDAP URL. + /// + LdapInvalidUrl = 62, + + /// + /// LDAP search failed. + /// + LdapSearchFailed = 39, + + /// + /// Library not found. The LDAP library was not found. + /// + LibraryNotFound = 40, + + /// + /// Malformat user. User name badly specified. *Not currently used* + /// + MalformatUser = 24, + + /// + /// This is not an error. This used to be another error code in an + /// old libcurl version and is currently unused. + /// + Obsolete = 50, + + /// + /// Operation timeout. The specified time-out period was reached + /// according to the conditions. + /// + OperationTimeouted = 28, + + /// + /// Out of memory. A memory allocation request failed. This is serious + /// badness and things are severely messed up if this ever occurs. + /// + OutOfMemory = 27, + + /// + /// A file transfer was shorter or larger than expected. This + /// happens when the server first reports an expected transfer size, + /// and then delivers data that doesn't match the previously + /// given size. + /// + PartialFile = 18, + + /// + /// There was a problem reading a local file or an error returned by + /// the read callback. + /// + ReadError = 26, + + /// + /// Failure with receiving network data. + /// + RecvError = 56, + + /// + /// Failed sending network data. + /// + SendError = 55, + + /// + /// Sending the data requires a rewind that failed. + /// + SendFailRewind = 65, + + /// + /// CurlShare is in use. + /// + ShareInUse = 57, + + /// + /// Problem with the CA cert (path? access rights?) + /// + SslCaCert = 60, + + /// + /// There's a problem with the local client certificate. + /// + SslCertProblem = 58, + + /// + /// Couldn't use specified cipher. + /// + SslCipher = 59, + + /// + /// A problem occurred somewhere in the Ssl/TLS handshake. You really + /// want to use the delegate and read + /// the message there as it pinpoints the problem slightly more. It + /// could be certificates (file formats, paths, permissions), + /// passwords, and others. + /// + SslConnectError = 35, + + /// + /// Failed to initialize Ssl engine. + /// + SslEngineInitFailed = 66, + + /// + /// The specified crypto engine wasn't found. + /// + SslEngineNotFound = 53, + + /// + /// Failed setting the selected Ssl crypto engine as default! + /// + SslEngineSetFailed = 54, + + /// + /// The remote server's Ssl certificate was deemed not OK. + /// + SslPeerCertificate = 51, + + /// + /// A telnet option string was improperly formatted. + /// + TelnetOptionSyntax = 49, + + /// + /// Too many redirects. When following redirects, libcurl hit the + /// maximum amount. Set your limit with + /// . + /// + TooManyRedirects = 47, + + /// + /// An option set with + /// was not recognized/known. Refer to the appropriate documentation. + /// + UnknownTelnetOption = 48, + + /// + /// The URL you passed to libcurl used a protocol that this libcurl + /// does not support. The support might be a compile-time option that + /// wasn't used, it can be a misspelled protocol string or just a + /// protocol libcurl has no code for. + /// + UnsupportedProtocol = 1, + + /// + /// The URL was not properly formatted. + /// + UrlMalformat = 3, + + /// + /// URL user malformatted. The user-part of the URL syntax was not + /// correct. + /// + UrlMalformatUser = 4, + + /// + /// An error occurred when writing received data to a local file, + /// or an error was returned to libcurl from a write callback. + /// + WriteError = 23, + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlFormCode.cs b/src/CurlSharp/Enums/CurlFormCode.cs new file mode 100644 index 000000000..037ec5803 --- /dev/null +++ b/src/CurlSharp/Enums/CurlFormCode.cs @@ -0,0 +1,76 @@ +/*************************************************************************** + * + * Project: libcurl.NET + * + * Copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + * $Id: Enums.cs,v 1.1 2005/02/17 22:47:25 jeffreyphillips Exp $ + **************************************************************************/ + +namespace CurlSharp +{ + /// + /// One of these is returned by . + /// + public enum CurlFormCode + { + /// + /// The section was added properly. + /// + Ok = 0, + + /// + /// Out-of-memory when adding the section. + /// + Memory = 1, + + /// + /// Invalid attempt to add the same option more than once to a + /// section. + /// + OptionTwice = 2, + + /// + /// Invalid attempt to pass a null string or byte array in + /// one of the arguments. + /// + Null = 3, + + /// + /// Invalid attempt to pass an unrecognized option in one of the + /// arguments. + /// + UnknownOption = 4, + + /// + /// Incomplete argument lists. + /// + Incomplete = 5, + + /// + /// Invalid attempt to provide a nested Array. + /// + IllegalArray = 6, + + /// + /// This will not be returned so long as HTTP is enabled, which + /// it always is in libcurl.NET. + /// + Disabled = 7, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 8 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlFormOption.cs b/src/CurlSharp/Enums/CurlFormOption.cs new file mode 100644 index 000000000..ed78393fb --- /dev/null +++ b/src/CurlSharp/Enums/CurlFormOption.cs @@ -0,0 +1,142 @@ +namespace CurlSharp +{ + /// + /// These are options available to build a multi-part form section + /// in a call to + /// + public enum CurlFormOption + { + /// + /// Another possibility to send options to + /// is this option, that + /// passes a array reference as its value. + /// Each array element has a + /// and a string. All available + /// options can be used in an array, except the Array + /// option itself! The last argument in such an array must always be + /// End. + /// + Array = 8, + + /// + /// Followed by a string, tells libcurl that a buffer is to be + /// used to upload data instead of using a file. + /// + Buffer = 11, + + /// + /// Followed by an int with the size of the + /// BufferPtr byte array, tells libcurl the length of + /// the data to upload. + /// + BufferLength = 13, + + /// + /// Followed by a byte[] array, tells libcurl the address of + /// the buffer containing data to upload (as indicated with + /// Buffer). You must also use + /// BufferLength to set the length of the buffer area. + /// + BufferPtr = 12, + + /// + /// Specifies extra headers for the form POST section. This takes an + /// prepared in the usual way using + /// and appends the list of headers to + /// those libcurl automatically generates. + /// + ContentHeader = 15, + + /// + /// Followed by an int setting the length of the contents. + /// + ContentsLength = 6, + + /// + /// Followed by a string with a content-type will make cURL + /// use this given content-type for this file upload part, possibly + /// instead of an internally chosen one. + /// + ContentType = 14, + + /// + /// Followed by a string is used for the contents of this part, the + /// actual data to send away. If you'd like it to contain zero bytes, + /// you need to set the length of the name with + /// ContentsLength. + /// + CopyContents = 4, + + /// + /// Followed by a string used to set the name of this part. + /// If you'd like it to contain zero bytes, you need to set the + /// length of the name with NameLength. + /// + CopyName = 1, + + /// + /// This should be the last argument to a call to + /// . + /// + End = 17, + + /// + /// Followed by a file name, makes this part a file upload part. It + /// sets the file name field to the actual file name used here, + /// it gets the contents of the file and passes as data and sets the + /// content-type if the given file match one of the new internally + /// known file extension. For File the user may send + /// one or more files in one part by providing multiple File + /// arguments each followed by the filename (and each File + /// is allowed to have a ContentType). + /// + File = 10, + + /// + /// Followed by a file name, and does the file read: the contents + /// will be used in as data in this part. + /// + FileContent = 7, + + /// + /// Followed by a string file name, will make libcurl use the + /// given name in the file upload part, instead of the actual file + /// name given to File. + /// + Filename = 16, + + /// + /// Followed by an int setting the length of the name. + /// + NameLength = 3, + + /// + /// Not used. + /// + Nothing = 0, + + /// + /// No longer used. + /// + Obsolete = 9, + + /// + /// No longer used. + /// + Obsolete2 = 18, + + /// + /// Followed by a byte[] used for the contents of this part. + /// If you'd like it to contain zero bytes, you need to set the + /// length of the name with ContentsLength. + /// + PtrContents = 5, + + /// + /// Followed by a byte[] used for the name of this part. + /// If you'd like it to contain zero bytes, you need to set the + /// length of the name with NameLength. + /// + PtrName = 2 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlFtpAuth.cs b/src/CurlSharp/Enums/CurlFtpAuth.cs new file mode 100644 index 000000000..52f862dd1 --- /dev/null +++ b/src/CurlSharp/Enums/CurlFtpAuth.cs @@ -0,0 +1,31 @@ +namespace CurlSharp +{ + /// + /// This enumeration contains values used to specify the FTP Ssl + /// authorization level using the + /// option when calling + /// + /// + public enum CurlFtpAuth + { + /// + /// Let libcurl decide on the authorization scheme. + /// + Default = 0, + + /// + /// Use "AUTH Ssl". + /// + SSL = 1, + + /// + /// Use "AUTH TLS". + /// + TLS = 2, + + /// + /// End-of-enumeration marker. Do not use in a client application. + /// + Last = 3 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlFtpSsl.cs b/src/CurlSharp/Enums/CurlFtpSsl.cs new file mode 100644 index 000000000..982f158d1 --- /dev/null +++ b/src/CurlSharp/Enums/CurlFtpSsl.cs @@ -0,0 +1,37 @@ +namespace CurlSharp +{ + /// + /// This enumeration contains values used to specify the FTP Ssl level + /// using the option when calling + /// + /// + public enum CurlFtpSsl + { + /// + /// Don't attempt to use Ssl. + /// + None = 0, + + /// + /// Try using Ssl, proceed as normal otherwise. + /// + Try = 1, + + /// + /// Require Ssl for the control connection or fail with + /// . + /// + Control = 2, + + /// + /// Require Ssl for all communication or fail with + /// . + /// + All = 3, + + /// + /// End-of-enumeration marker. Do not use in a client application. + /// + Last = 4 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlHttpAuth.cs b/src/CurlSharp/Enums/CurlHttpAuth.cs new file mode 100644 index 000000000..6cd0619cc --- /dev/null +++ b/src/CurlSharp/Enums/CurlHttpAuth.cs @@ -0,0 +1,65 @@ +namespace CurlSharp +{ + /// + /// This enumeration contains values used to specify the HTTP authentication + /// when using the option when + /// calling + /// + public enum CurlHttpAuth + { + /// + /// No authentication. + /// + None = 0, + + /// + /// HTTP Basic authentication. This is the default choice, and the + /// only method that is in wide-spread use and supported virtually + /// everywhere. This is sending the user name and password over the + /// network in plain text, easily captured by others. + /// + Basic = 1, + + /// + /// HTTP Digest authentication. Digest authentication is defined + /// in RFC2617 and is a more secure way to do authentication over + /// public networks than the regular old-fashioned Basic method. + /// + Digest = 2, + + /// + /// HTTP GSS-Negotiate authentication. The GSS-Negotiate (also known + /// as plain "Negotiate") method was designed by Microsoft and is + /// used in their web applications. It is primarily meant as a + /// support for Kerberos5 authentication but may be also used along + /// with another authentication methods. For more information see IETF + /// draft draft-brezak-spnego-http-04.txt. + /// + /// You need to use a version of libcurl.NET built with a suitable + /// GSS-API library for this to work. This is not currently standard. + /// + /// + GssNegotiate = 4, + + /// + /// HTTP Ntlm authentication. A proprietary protocol invented and + /// used by Microsoft. It uses a challenge-response and hash concept + /// similar to Digest, to prevent the password from being eavesdropped. + /// + Ntlm = 8, + + /// + /// This is a convenience macro that sets all bits and thus makes + /// libcurl pick any it finds suitable. libcurl will automatically + /// select the one it finds most secure. + /// + Any = 15, // ~0 + + /// + /// This is a convenience macro that sets all bits except Basic + /// and thus makes libcurl pick any it finds suitable. libcurl + /// will automatically select the one it finds most secure. + /// + AnySafe = 14 // ~Basic + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlHttpVersion.cs b/src/CurlSharp/Enums/CurlHttpVersion.cs new file mode 100644 index 000000000..f5b4eb115 --- /dev/null +++ b/src/CurlSharp/Enums/CurlHttpVersion.cs @@ -0,0 +1,31 @@ +namespace CurlSharp +{ + /// + /// Contains values used to specify the HTTP version level when using + /// the option in a call + /// to + /// + public enum CurlHttpVersion + { + /// + /// We don't care about what version the library uses. libcurl will + /// use whatever it thinks fit. + /// + None = 0, + + /// + /// Enforce HTTP 1.0 requests. + /// + Http1_0 = 1, + + /// + /// Enforce HTTP 1.1 requests. + /// + Http1_1 = 2, + + /// + /// Last entry in enumeration; do not use in application code. + /// + Last = 3 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlInfo.cs b/src/CurlSharp/Enums/CurlInfo.cs new file mode 100644 index 000000000..6d41e2c20 --- /dev/null +++ b/src/CurlSharp/Enums/CurlInfo.cs @@ -0,0 +1,222 @@ +namespace CurlSharp +{ + /// + /// This enumeration is used to extract information associated with an + /// transfer. Specifically, a member of this + /// enumeration is passed as the first argument to + /// CurlEasy.GetInfo specifying the item to retrieve in the + /// second argument, which is a reference to an int, a + /// double, a string, a DateTime or an object. + /// + public enum CurlInfo + { + /// + /// The second argument receives the elapsed time, as a double, + /// in seconds, from the start until the connect to the remote host + /// (or proxy) was completed. + /// + ConnectTime = 0x300005, + + /// + /// The second argument receives, as a double, the content-length + /// of the download. This is the value read from the Content-Length: field. + /// + ContentLengthDownload = 0x30000F, + + /// + /// The second argument receives, as a double, the specified size + /// of the upload. + /// + ContentLengthUpload = 0x300010, + + /// + /// The second argument receives, as a string, the content-type of + /// the downloaded object. This is the value read from the Content-Type: + /// field. If you get null, it means that the server didn't + /// send a valid Content-Type header or that the protocol used + /// doesn't support this. + /// + ContentType = 0x100012, + + /// + /// The second argument receives, as a string, the last + /// used effective URL. + /// + EffectiveUrl = 0x100001, + + /// + /// The second argument receives, as a long, the remote time + /// of the retrieved document. You should construct a DateTime + /// from this value, as shown in the InfoDemo sample. If you + /// get a date in the distant + /// past, it can be because of many reasons (unknown, the server + /// hides it or the server doesn't support the command that tells + /// document time etc) and the time of the document is unknown. Note + /// that you must tell the server to collect this information before + /// the transfer is made, by using the + /// option to + /// . (Added in 7.5) + /// + Filetime = 0x20000E, + + /// + /// The second argument receives an int specifying the total size + /// of all the headers received. + /// + HeaderSize = 0x20000B, + + /// + /// The second argument receives, as an int, a bitmask indicating + /// the authentication method(s) available. The meaning of the bits is + /// explained in the documentation of + /// . (Added in 7.10.8) + /// + HttpAuthAvail = 0x200017, + + /// + /// The second argument receives an int indicating the numeric + /// connect code for the HTTP request. + /// + HttpConnectCode = 0x200016, + + /// + /// End-of-enumeration marker; do not use in client applications. + /// + LastOne = 0x1C, + + /// + /// The second argument receives, as a double, the time, in + /// seconds it took from the start until the name resolving was + /// completed. + /// + NameLookupTime = 0x300004, + + /// + /// Never used. + /// + None = 0x0, + + /// + /// The second argument receives an int indicating the + /// number of current connections. (Added in 7.13.0) + /// + NumConnects = 0x20001A, + + /// + /// The second argument receives an int indicating the operating + /// system error number: _errro or GetLastError(), + /// depending on the platform. (Added in 7.12.2) + /// + OsErrno = 0x200019, + + /// + /// The second argument receives, as a double, the time, in + /// seconds, it took from the start until the file transfer is just about + /// to begin. This includes all pre-transfer commands and negotiations + /// that are specific to the particular protocol(s) involved. + /// + PreTransferTime = 0x300006, + + /// + /// The second argument receives a reference to the private data + /// associated with the object (set with the + /// option to + /// . (Added in 7.10.3) + /// + Private = 0x100015, + + /// + /// The second argument receives, as an int, a bitmask + /// indicating the authentication method(s) available for your + /// proxy authentication. This will be a bitmask of + /// enumeration constants. + /// (Added in 7.10.8) + /// + ProxyAuthAvail = 0x200018, + + /// + /// The second argument receives an int indicating the total + /// number of redirections that were actually followed. (Added in 7.9.7) + /// + RedirectCount = 0x200014, + + /// + /// The second argument receives, as a double, the total time, in + /// seconds, for all redirection steps include name lookup, connect, + /// pretransfer and transfer before final transaction was started. + /// RedirectTime contains the complete execution + /// time for multiple redirections. (Added in 7.9.7) + /// + RedirectTime = 0x300013, + + /// + /// The second argument receives an int containing the total size + /// of the issued requests. This is so far only for HTTP requests. Note + /// that this may be more than one request if + /// is true. + /// + RequestSize = 0x20000C, + + /// + /// The second argument receives an int with the last received HTTP + /// or FTP code. This option was known as CURLINFO_HTTP_CODE in + /// libcurl 7.10.7 and earlier. + /// + ResponseCode = 0x200002, + + /// + /// The second argument receives a double with the total amount of + /// bytes that were downloaded. The amount is only for the latest transfer + /// and will be reset again for each new transfer. + /// + SizeDownload = 0x300008, + + /// + /// The second argument receives a double with the total amount + /// of bytes that were uploaded. + /// + SizeUpload = 0x300007, + + /// + /// The second argument receives a double with the average + /// download speed that cURL measured for the complete download. + /// + SpeedDownload = 0x300009, + + /// + /// The second argument receives a double with the average + /// upload speed that libcurl measured for the complete upload. + /// + SpeedUpload = 0x30000A, + + /// + /// The second argument receives an containing + /// the names of the available Ssl engines. + /// + SslEngines = 0x40001B, + + /// + /// The second argument receives an int with the result of + /// the certificate verification that was requested (using the + /// option in + /// . + /// + SslVerifyResult = 0x20000D, + + /// + /// The second argument receives a double specifying the time, + /// in seconds, from the start until the first byte is just about to be + /// transferred. This includes PreTransferTime and + /// also the time the server needs to calculate the result. + /// + StartTransferTime = 0x300011, + + /// + /// The second argument receives a double indicating the total transaction + /// time in seconds for the previous transfer. This time does not include + /// the connect time, so if you want the complete operation time, + /// you should add the ConnectTime. + /// + TotalTime = 0x300003, + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlInfoType.cs b/src/CurlSharp/Enums/CurlInfoType.cs new file mode 100644 index 000000000..bbef37891 --- /dev/null +++ b/src/CurlSharp/Enums/CurlInfoType.cs @@ -0,0 +1,50 @@ +namespace CurlSharp +{ + /// + /// A member of this enumeration is passed as the first parameter to the + /// delegate to which libcurl passes + /// debug messages. + /// + public enum CurlInfoType + { + /// + /// The data is informational text. + /// + Text = 0, + + /// + /// The data is header (or header-like) data received from the peer. + /// + HeaderIn = 1, + + /// + /// The data is header (or header-like) data sent to the peer. + /// + HeaderOut = 2, + + /// + /// The data is protocol data received from the peer. + /// + DataIn = 3, + + /// + /// The data is protocol data sent to the peer. + /// + DataOut = 4, + + /// + /// The data is Ssl-related data sent to the peer. + /// + SslDataIn = 5, + + /// + /// The data is Ssl-related data received from the peer. + /// + SslDataOut = 6, + + /// + /// End of enumeration marker, don't use in a client application. + /// + End = 7 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlInitFlag.cs b/src/CurlSharp/Enums/CurlInitFlag.cs new file mode 100644 index 000000000..9106d92b2 --- /dev/null +++ b/src/CurlSharp/Enums/CurlInitFlag.cs @@ -0,0 +1,34 @@ +namespace CurlSharp +{ + /// + /// Contains values used to initialize libcurl internally. One of + /// these is passed in the call to . + /// + public enum CurlInitFlag + { + /// + /// Initialise nothing extra. This sets no bit. + /// + Nothing = 0, + + /// + /// Initialize Ssl. + /// + Ssl = 1, + + /// + /// Initialize the Win32 socket libraries. + /// + Win32 = 2, + + /// + /// Initialize everything possible. This sets all known bits. + /// + All = 3, + + /// + /// Equivalent to All. + /// + Default = All + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlIoCommand.cs b/src/CurlSharp/Enums/CurlIoCommand.cs new file mode 100644 index 000000000..6e15fbb30 --- /dev/null +++ b/src/CurlSharp/Enums/CurlIoCommand.cs @@ -0,0 +1,27 @@ +namespace CurlSharp +{ + /// + /// Your handler for the + /// delegate is passed one of these values as its first parameter. + /// Right now, the only supported value is + /// RestartRead. + /// + public enum CurlIoCommand + { + /// + /// No IOCTL operation; we should never see this. + /// + Nop = 0, + + /// + /// When this is sent, your callback may need to, for example, + /// rewind a local file that is being sent via FTP. + /// + RestartRead = 1, + + /// + /// End of enumeration marker, don't use in a client application. + /// + Last = 2 + } +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlIoError.cs b/src/CurlSharp/Enums/CurlIoError.cs new file mode 100644 index 000000000..e1baeccb7 --- /dev/null +++ b/src/CurlSharp/Enums/CurlIoError.cs @@ -0,0 +1,30 @@ +namespace CurlSharp +{ + /// + /// Your handler for the delegate + /// should return a member of this enumeration. + /// + public enum CurlIoError + { + /// + /// Indicate that the callback processed everything okay. + /// + Ok = 0, + + /// + /// Unknown command sent to callback. Right now, only + /// RestartRead is supported. + /// + UnknownCommand = 1, + + /// + /// Indicate to libcurl that a restart failed. + /// + FailRestart = 2, + + /// + /// End of enumeration marker, don't use in a client application. + /// + Last = 3 + } +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlIpResolve.cs b/src/CurlSharp/Enums/CurlIpResolve.cs new file mode 100644 index 000000000..847786512 --- /dev/null +++ b/src/CurlSharp/Enums/CurlIpResolve.cs @@ -0,0 +1,26 @@ +namespace CurlSharp +{ + /// + /// This enumeration contains values used to specify the IP resolution + /// method when using the + /// option in a call to + /// + public enum CurlIpResolve + { + /// + /// Default, resolves addresses to all IP versions that your system + /// allows. + /// + Whatever = 0, + + /// + /// Resolve to ipv4 addresses. + /// + V4 = 1, + + /// + /// Resolve to ipv6 addresses. + /// + V6 = 2 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlLockAccess.cs b/src/CurlSharp/Enums/CurlLockAccess.cs new file mode 100644 index 000000000..2214585c7 --- /dev/null +++ b/src/CurlSharp/Enums/CurlLockAccess.cs @@ -0,0 +1,31 @@ +namespace CurlSharp +{ + /// + /// Values containing the type of shared access requested when libcurl + /// calls the delegate. + /// + public enum CurlLockAccess + { + /// + /// Unspecified action; the delegate should never receive this. + /// + None = 0, + + /// + /// The delegate receives this call when libcurl is requesting + /// read access to the shared resource. + /// + Shared = 1, + + /// + /// The delegate receives this call when libcurl is requesting + /// write access to the shared resource. + /// + Single = 2, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 3 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlLockData.cs b/src/CurlSharp/Enums/CurlLockData.cs new file mode 100644 index 000000000..63e7247e6 --- /dev/null +++ b/src/CurlSharp/Enums/CurlLockData.cs @@ -0,0 +1,48 @@ +namespace CurlSharp +{ + /// + /// Members of this enumeration should be passed to + /// when it is called with the + /// CurlShare or Unshare options + /// provided in the enumeration. + /// + public enum CurlLockData + { + /// + /// Not used. + /// + None = 0, + + /// + /// Used internally by libcurl. + /// + Share = 1, + + /// + /// Cookie data will be shared across the objects + /// using this shared object. + /// + Cookie = 2, + + /// + /// Cached Dns hosts will be shared across the + /// objects using this shared object. + /// + Dns = 3, + + /// + /// Not supported yet. + /// + SslSession = 4, + + /// + /// Not supported yet. + /// + Connect = 5, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 6 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlMessage.cs b/src/CurlSharp/Enums/CurlMessage.cs new file mode 100644 index 000000000..d374e18f1 --- /dev/null +++ b/src/CurlSharp/Enums/CurlMessage.cs @@ -0,0 +1,25 @@ +namespace CurlSharp +{ + /// + /// The status code associated with an object in a + /// operation. One of these is returned in response + /// to reading the property. + /// + public enum CurlMessage + { + /// + /// First entry in the enumeration, not used. + /// + None = 0, + + /// + /// The associated object completed. + /// + Done = 1, + + /// + /// End-of-enumeration marker, not used. + /// + Last = 2 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlMultiCode.cs b/src/CurlSharp/Enums/CurlMultiCode.cs new file mode 100644 index 000000000..053d270a5 --- /dev/null +++ b/src/CurlSharp/Enums/CurlMultiCode.cs @@ -0,0 +1,46 @@ +namespace CurlSharp +{ + /// + /// Contains return codes for many of the functions in the + /// class. + /// + public enum CurlMultiCode + { + /// + /// You should call again before calling + /// . + /// + CallMultiPerform = -1, + + /// + /// The function succeded. + /// + Ok = 0, + + /// + /// The internal is bad. + /// + BadHandle = 1, + + /// + /// One of the handles associated with the + /// object is bad. + /// + BadEasyHandle = 2, + + /// + /// Out of memory. This is a severe problem. + /// + OutOfMemory = 3, + + /// + /// Internal error deep within the libcurl library. + /// + InternalError = 4, + + /// + /// End-of-enumeration marker, not used. + /// + Last = 5 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlNetrcOption.cs b/src/CurlSharp/Enums/CurlNetrcOption.cs new file mode 100644 index 000000000..9f24cc37e --- /dev/null +++ b/src/CurlSharp/Enums/CurlNetrcOption.cs @@ -0,0 +1,43 @@ +namespace CurlSharp +{ + /// + /// Contains values used to specify the preference of libcurl between + /// using user names and passwords from your ~/.netrc file, relative to + /// user names and passwords in the URL supplied with + /// . This is passed when using + /// the option in a call + /// to + /// + public enum CurlNetrcOption + { + /// + /// The library will ignore the file and use only the information + /// in the URL. This is the default. + /// + Ignored = 0, + + /// + /// The use of your ~/.netrc file is optional, and information in the + /// URL is to be preferred. The file will be scanned with the host + /// and user name (to find the password only) or with the host only, + /// to find the first user name and password after that machine, + /// which ever information is not specified in the URL. + /// + /// Undefined values of the option will have this effect. + /// + /// + Optional = 1, + + /// + /// This value tells the library that use of the file is required, + /// to ignore the information in the URL, and to search the file + /// with the host only. + /// + Required = 2, + + /// + /// Last entry in enumeration; do not use in application code. + /// + Last = 3 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlOption.cs b/src/CurlSharp/Enums/CurlOption.cs new file mode 100644 index 000000000..78a7fe3e3 --- /dev/null +++ b/src/CurlSharp/Enums/CurlOption.cs @@ -0,0 +1,1603 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +namespace CurlSharp +{ + /// + /// One of these is passed as the first parameter to + /// . The Description column of + /// the table describes the value that should be passed as the second parameter. + /// + public enum CurlOption + { + /// + /// Pass a true parameter to enable this. When enabled, libcurl + /// will automatically set the Referer: field in requests where it follows + /// a Location: redirect. + /// + AutoReferer = 58, + + /// + /// Pass an int specifying your preferred size for the receive buffer + /// in libcurl. The main point of this would be that the write callback gets + /// called more often and with smaller chunks. This is just treated as a + /// request, not an order. You cannot be guaranteed to actually get the + /// requested size. (Added in 7.10) + /// + BufferSize = 98, + + /// + /// Pass a string naming a file holding one or more certificates + /// to verify the peer with. This only makes sense when used in combination + /// with the SslVerifyPeer option. + /// + CaInfo = 10065, + + /// + /// Pass a string naming a directory holding multiple CA certificates + /// to verify the peer with. The certificate directory must be prepared + /// using the openssl c_rehash utility. This only makes sense when used in + /// combination with the SslVerifyPeer option. The + /// CaPath function apparently does not work in Windows due + /// to some limitation in openssl. (Added in 7.9.8) + /// + CaPath = 10097, + + /// + /// Pass an int. This option sets what policy libcurl should use when + /// the connection cache is filled and one of the open connections has to be + /// closed to make room for a new connection. This must be one of the + /// members. Use + /// to make + /// libcurl close the connection that was least recently used, that connection + /// is also least likely to be capable of re-use. Use + /// to make libcurl close + /// the oldest connection, the one that was created first among the ones in + /// the connection cache. The other close policies are not supported yet. + /// + ClosePolicy = 72, + + /// + /// Time-out connect operations after this amount of seconds, if connects + /// are OK within this time, then fine... This only aborts the connect + /// phase. [Only works on unix-style/SIGALRM operating systems] + /// + ConnectTimeout = 78, + + /// + /// Pass a string as parameter. It will be used to set a cookie + /// in the http request. The format of the string should be NAME=CONTENTS, + /// where NAME is the cookie name and CONTENTS is what the cookie should contain. + /// + /// If you need to set multiple cookies, you need to set them all using a + /// single option and thus you need to concatenate them all in one single + /// string. Set multiple cookies in one string like this: + /// "name1=content1; name2=content2;" etc. + /// + /// + /// Using this option multiple times will only make the latest string override + /// the previously ones. + /// + /// + Cookie = 10022, + + /// + /// Pass a string as parameter. It should contain the name of your + /// file holding cookie data to read. The cookie data may be in Netscape / + /// Mozilla cookie data format or just regular HTTP-style headers dumped + /// to a file. + /// + /// Given an empty or non-existing file, this option will enable cookies + /// for this CurlEasy object, making it understand and parse received cookies + /// and then use matching cookies in future request. + /// + /// + CookieFile = 10031, + + /// + /// Pass a file name as string. This will make libcurl write all + /// internally known cookies to the specified file when + /// is called. If no cookies are known, no file + /// will be created. Using this option also enables cookies for this + /// session, so if you for example follow a location it will make matching + /// cookies get sent accordingly. + /// + /// If the cookie jar file can't be created or written to + /// (when is called), libcurl will not and + /// cannot report an error for this. Using Verbose or + /// CurlDebugCallback will get a warning to display, but that + /// is the only visible feedback you get about this possibly lethal situation. + /// + /// + CookieJar = 10082, + + /// + /// Pass a bool set to true to mark this as a new cookie + /// "session". It will force libcurl to ignore all cookies it is about to + /// load that are "session cookies" from the previous session. By default, + /// libcurl always stores and loads all cookies, independent of whether they are + /// session cookies. Session cookies are cookies without expiry date and they + /// are meant to be alive and existing for this "session" only. + /// + CookieSession = 96, + + /// + /// Convert Unix newlines to CRLF newlines on transfers. + /// + CRLF = 27, + + /// + /// Pass a string as parameter. It will be used instead of GET or + /// HEAD when doing an HTTP request, or instead of LIST or NLST when + /// doing an ftp directory listing. This is useful for doing DELETE or + /// other more or less obscure HTTP requests. Don't do this at will, + /// make sure your server supports the command first. + /// + /// Restore to the internal default by setting this to null. + /// + /// + /// Many people have wrongly used this option to replace the entire + /// request with their own, including multiple headers and POST contents. + /// While that might work in many cases, it will cause libcurl to send + /// invalid requests and it could possibly confuse the remote server badly. + /// Use Post and PostFields to set POST data. + /// Use HttpHeader to replace or extend the set of headers + /// sent by libcurl. Use HttpVersion to change HTTP version. + /// + /// + CustomRequest = 10036, + + /// + /// Pass an object referene to whatever you want passed to your + /// delegate's extraData argument. + /// This reference is not used internally by libcurl, it is only passed to + /// the delegate. + /// + DebugData = 10095, + + /// + /// Pass a reference to an delegate. + /// Verbose must be in effect. This delegate receives debug + /// information, as specified with the argument. + /// This function must return 0. + /// + DebugFunction = 20094, + + /// + /// Pass an int, specifying the timeout in seconds. Name resolves + /// will be kept in memory for this number of seconds. Set to zero (0) + /// to completely disable caching, or set to -1 to make the cached + /// entries remain forever. By default, libcurl caches this info for 60 + /// seconds. + /// + DnsCacheTimeout = 92, + + /// + /// Not supported. + /// + DnsUseGlobalCache = 91, + + /// + /// Pass a string containing the path name to the Entropy Gathering + /// Daemon socket. It will be used to seed the random engine for Ssl. + /// + EgdSocket = 10077, + + /// + /// Set this option to the file name of your .netrc file you want libcurl to parse (using the CURLOPT_NETRC option). If + /// not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. + /// + NetRcFile = 118, + + /// + /// Sets the contents of the Accept-Encoding: header sent in an HTTP request, + /// and enables decoding of a response when a Content-Encoding: header is + /// received. Three encodings are supported: identity, which does + /// nothing, deflate which requests the server to compress its + /// response using the zlib algorithm, and gzip which requests the + /// gzip algorithm. If a zero-length string is set, then an Accept-Encoding: + /// header containing all supported encodings is sent. + /// + Encoding = 10102, + + /// + /// Not supported. + /// + ErrorBuffer = 10010, + + /// + /// A true parameter tells the library to fail silently if the + /// HTTP code returned is equal to or larger than 300. The default + /// action would be to return the page normally, ignoring that code. + /// + FailOnError = 45, + + /// + /// Pass a bool. If it is true, libcurl will attempt to get + /// the modification date of the remote document in this operation. This + /// requires that the remote server sends the time or replies to a time + /// querying command. The CurlEasy.GetInfo function with the + /// argument can be used after a + /// transfer to extract the received time (if any). + /// + Filetime = 69, + + /// + /// A true parameter tells the library to follow any Location: + /// header that the server sends as part of an HTTP header. + /// + /// this means that the library will re-send the same request on the + /// new location and follow new Location: headers all the way until no + /// more such headers are returned. MaxRedirs can be used + /// to limit the number of redirects libcurl will follow. + /// + /// + FollowLocation = 52, + + /// + /// Pass a bool. Set to true to make the next transfer + /// explicitly close the connection when done. Normally, libcurl keeps all + /// connections alive when done with one transfer in case there comes a + /// succeeding one that can re-use them. This option should be used with + /// caution and only if you understand what it does. Set to false + /// to have libcurl keep the connection open for possibly later re-use + /// (default behavior). + /// + ForbidReuse = 75, + + /// + /// Pass a bool. Set to true to make the next transfer use a + /// new (fresh) connection by force. If the connection cache is full before + /// this connection, one of the existing connections will be closed as + /// according to the selected or default policy. This option should be used + /// with caution and only if you understand what it does. Set this to + /// false to have libcurl attempt re-using an existing connection + /// (default behavior). + /// + FreshConnect = 74, + + /// + /// String that will be passed to the FTP server when it requests + /// account info. + /// + FtpAccount = 10134, + + /// + /// A true parameter tells the library to append to the remote + /// file instead of overwrite it. This is only useful when uploading + /// to an ftp site. + /// + FtpAppend = 50, + + /// + /// A true parameter tells the library to just list the names of + /// an ftp directory, instead of doing a full directory listing that + /// would include file sizes, dates etc. + /// + /// This causes an FTP NLST command to be sent. Beware that some FTP + /// servers list only files in their response to NLST; they might not + /// include subdirectories and symbolic links. + /// + /// + FtpListOnly = 48, + + /// + /// Pass a string as parameter. It will be used to get the IP + /// address to use for the ftp PORT instruction. The PORT instruction + /// tells the remote server to connect to our specified IP address. + /// The string may be a plain IP address, a host name, an network + /// interface name (under Unix) or just a '-' letter to let the library + /// use your systems default IP address. Default FTP operations are + /// passive, and thus won't use PORT. + /// + /// You disable PORT again and go back to using the passive version + /// by setting this option to NULL. + /// + /// + FtpPort = 10017, + + /// + /// When FTP over Ssl/TLS is selected (with FtpSsl), + /// 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. + /// + /// Pass a member of the enumeration. + /// + /// + FtpSslAuth = 129, + + /// + /// Pass a bool. If the value is true, cURL will attempt to + /// create any remote directory that it fails to CWD into. CWD is the + /// command that changes working directory. (Added in 7.10.7) + /// + FtpCreateMissingDirs = 110, + + /// + /// Pass an int. Causes libcurl to set a timeout period (in seconds) + /// on the amount of time that the server is allowed to take in order to + /// generate a response message for a command before the session is + /// considered hung. Note that while libcurl is waiting for a response, this + /// value overrides Timeout. It is recommended that if used in + /// conjunction with Timeout, you set + /// FtpResponseTimeout to a value smaller than + /// Timeout. (Added in 7.10.8) + /// + FtpResponseTimeout = 112, + + /// + /// Pass a member of the enumeration. + /// + FtpSsl = 119, + + /// + /// Pass a bool. If the value is true, it tells curl to use + /// the EPRT (and LPRT) command when doing active FTP downloads (which is + /// enabled by FtpPort). Using EPRT means that it will first attempt + /// to use EPRT and then LPRT before using PORT, but if you pass false + /// to this option, it will not try using EPRT or LPRT, only plain PORT. + /// (Added in 7.10.5) + /// + FtpUseEprt = 106, + + /// + /// Pass a bool. If the value is true, it tells curl to use + /// the EPSV command when doing passive FTP downloads (which it always does + /// by default). Using EPSV means that it will first attempt to use EPSV + /// before using PASV, but if you pass false to this option, it will + /// not try using EPSV, only plain PASV. + /// + FtpUseEpsv = 85, + + /// + /// A true parameter tells the library to include the header in + /// the body output. This is only relevant for protocols that actually + /// have headers preceding the data (like HTTP). + /// + Header = 42, + + /// + /// Object reference to pass to the + /// delegate. Note that if you specify the CurlHeaderCallback, + /// this is the reference you'll get as the extraData parameter. + /// + HeaderData = 10029, + + /// + /// Provide an delegate reference. + /// This delegate gets called by libcurl as soon as there is received + /// header data that needs to be written down. The headers are guaranteed + /// to be written one-by-one and only complete lines are written. Parsing + /// headers should be easy enough using this. The size of the data contained + /// in buf is size multiplied with nmemb. + /// Return the number of bytes actually written or return -1 to signal + /// error to the library (it will cause it to abort the transfer with a + /// return code). + /// + HeaderFunction = 20079, + + /// + /// Pass an of aliases to be treated as valid HTTP + /// 200 responses. Some servers respond with a custom header response line. + /// For example, IceCast servers respond with "ICY 200 OK". By including + /// this string in your list of aliases, the response will be treated as a + /// valid HTTP header line such as "HTTP/1.0 200 OK". (Added in 7.10.3) + /// + /// The alias itself is not parsed for any version strings. So if your alias + /// is "MYHTTP/9.9", libcurl will not treat the server as responding with + /// HTTP version 9.9. Instead libcurl will use the value set by option + /// HttpVersion. + /// + /// + Http200Aliases = 10104, + + /// + /// Pass an int as parameter, which is set to a bitmask + /// of , to tell libcurl what authentication + /// method(s) you want it to use. If more than one bit is set, libcurl will + /// first query the site to see what authentication methods it supports and + /// then pick the best one you allow it to use. Note that for some methods, + /// this will induce an extra network round-trip. Set the actual name and + /// password with the UserPwd option. (Added in 7.10.6) + /// + HttpAuth = 107, + + /// + /// Pass a bool. If it's true, this forces the HTTP request + /// to get back to GET. Usable if a POST, HEAD, PUT or a custom request + /// has been used previously using the same object. + /// + HttpGet = 80, + + /// + /// Pass an reference containing HTTP headers to pass to + /// the server in your HTTP request. If you add a header that is otherwise + /// generated and used by libcurl internally, your added one will be used + /// instead. If you add a header with no contents as in 'Accept:' (no data + /// on the right side of the colon), the internally used header will get + /// disabled. Thus, using this option you can add new headers, replace + /// internal headers and remove internal headers. The headers included in the + /// CurlSlist must not be CRLF-terminated, because curl adds CRLF after + /// each header item. Failure to comply with this will result in strange bugs + /// because the server will most likely ignore part of the headers you specified. + /// + /// The first line in a request (usually containing a GET or POST) is not + /// a header and cannot be replaced using this option. Only the lines + /// following the request-line are headers. + /// + /// + /// Pass a null to this to reset back to no custom headers. + /// + /// + /// The most commonly replaced headers have "shortcuts" in the options + /// Cookie, UserAgent and Referer. + /// + /// + HttpHeader = 10023, + + /// + /// Tells libcurl you want a multipart/formdata HTTP POST to be made and you + /// instruct what data to pass on to the server. Pass a reference to a + /// object as parameter. + /// The best and most elegant way to do this, is to use + /// as documented. + /// + /// Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" + /// header. You can disable this header with HttpHeader as usual. + /// + /// + HttpPost = 10024, + + /// + /// Set the parameter to true to get the library to tunnel all + /// operations through a given HTTP proxy. Note that there is a big + /// difference between using a proxy and tunneling through it. If you + /// don't know what this means, you probably don't want this tunneling option. + /// + HttpProxyTunnel = 61, + + /// + /// Pass a member of the enumeration. These + /// values force libcurl to use the specific HTTP versions. This is not + /// sensible to do unless you have a good reason. + /// + HttpVersion = 84, + + /// + /// Provide an delegate reference. + /// This delegate gets called by libcurl when an IOCTL operation, + /// such as a rewind of a file being sent via FTP, is required on + /// the client side. + /// + IoctlFunction = 20130, + + /// + /// Provide an object, such as a FileStream, upon which + /// you may need to perform an IOCTL operation. Right now, only + /// rewind is supported. + /// + IoctlData = 10131, + + /// + /// When uploading a file to a remote site, this option should be used to + /// tell libcurl what the expected size of the infile is. This value should + /// be passed as an int. + /// + InfileSize = 14, + + /// + /// When uploading a file to a remote site, this option should be used to + /// tell libcurl what the expected size of the infile is. This value should + /// be passed as a long. (Added in 7.11.0) + /// + InFileSizeLarge = 30115, + + /// + /// Pass a string as parameter. This sets the interface name to use + /// as the outgoing network interface. The name can be an interface name, + /// an IP address or a host name. + /// + Interface = 10062, + + /// + /// Pass one of the members of the enumeration. + /// + IpResolve = 113, + + /// + /// Pass a string as parameter. Set the kerberos4 security level; + /// this also enables kerberos4 awareness. This is a string, 'clear', 'safe', + /// 'confidential' or 'private'. If the string is set but doesn't match + /// one of these, 'private' will be used. Set the string to null + /// to disable kerberos4. The kerberos support only works for FTP. + /// + Krb4Level = 10063, + + /// + /// Pass an int as parameter. It contains the transfer speed in bytes + /// per second that the transfer should be below during + /// LowSpeedTime seconds for the library to consider it + /// too slow and abort. + /// + LowSpeedLimit = 19, + + /// + /// Pass an int as parameter. It contains the time in seconds that + /// the transfer should be below the LowSpeedLimit for the + /// library to consider it too slow and abort. + /// + LowSpeedTime = 20, + + /// + /// Pass an int. The set number will be the persistent connection + /// cache size. The set amount will be the maximum amount of simultaneously + /// open connections that libcurl may cache. Default is 5, and there isn't + /// much point in changing this value unless you are perfectly aware of how + /// this works and changes libcurl's behaviour. This concerns connections + /// using any of the protocols that support persistent connections. + /// + /// When reaching the maximum limit, cURL uses the ClosePolicy + /// to figure out which of the existing connections to close to prevent the + /// number of open connections to increase. + /// + /// + /// if you already have performed transfers with this CurlEasy object, setting a + /// smaller MaxConnects than before may cause open connections + /// to get closed unnecessarily. + /// + /// + MaxConnects = 71, + + /// + /// Pass an int as parameter. This allows you to specify the maximum + /// size (in bytes) of a file to download. If the file requested is larger + /// than this value, the transfer will not start and + /// will be returned. + /// + /// The file size is not always known prior to download, and for such files + /// this option has no effect even if the file transfer ends up being larger + /// than this given limit. This concerns both FTP and HTTP transfers. + /// + /// + MaxFileSize = 114, + + /// + /// Pass a long as parameter. This allows you to specify the + /// maximum size (in bytes) of a file to download. If the file requested + /// is larger than this value, the transfer will not start and + /// will be returned. + /// (Added in 7.11.0) + /// + /// The file size is not always known prior to download, and for such files + /// this option has no effect even if the file transfer ends up being larger + /// than this given limit. This concerns both FTP and HTTP transfers. + /// + /// + MaxFileSizeLarge = 30117, + + /// + /// Pass an int. The set number will be the redirection limit. If + /// that many redirections have been followed, the next redirect will cause + /// an error (TooManyRedirects). This option only makes sense + /// if the FollowLocation is used at the same time. + /// + MaxRedirs = 68, + + /// + /// This parameter controls the preference of libcurl between using + /// user names and passwords from your ~/.netrc file, relative to + /// user names and passwords in the URL supplied with Url. + /// + /// libcurl uses a user name (and supplied or prompted password) + /// supplied with UserPwd in preference to any of the + /// options controlled by this parameter. + /// + /// + /// Pass a member of the enumeration. + /// + /// + /// Only machine name, user name and password are taken into account + /// (init macros and similar things aren't supported). + /// + /// + /// libcurl does not verify that the file has the correct properties + /// set (as the standard Unix ftp client does). It should only be + /// readable by user. + /// + /// + Netrc = 51, + + /// + /// Pass a string as parameter, containing the full path name to the + /// file you want libcurl to use as .netrc file. If this option is omitted, + /// and Netrc is set, libcurl will attempt to find the a + /// .netrc file in the current user's home directory. (Added in 7.10.9) + /// + NetrcFile = 10118, + + /// + /// A true parameter tells the library to not include the + /// body-part in the output. This is only relevant for protocols that + /// have separate header and body parts. On HTTP(S) servers, this + /// will make libcurl do a HEAD request. + /// + /// To change back to GET, you should use HttpGet. To + /// change back to POST, you should use Post. Setting + /// NoBody to false has no effect. + /// + /// + NoBody = 44, + + /// + /// A true parameter tells the library to shut off progress + /// reporting. + /// + NoProgress = 43, + + /// + /// Pass a bool. If it is true, libcurl will not use any + /// functions that install signal handlers or any functions that cause + /// signals to be sent to the process. This option is mainly here to allow + /// multi-threaded unix applications to still set/use all timeout options + /// etc, without risking getting signals. (Added in 7.10) + /// + /// Consider using libcurl with ares built-in to enable asynchronous Dns + /// lookups. It enables nice timeouts for name resolves without signals. + /// + /// + NoSignal = 99, + + /// + /// Not supported. + /// + PasvHost = 126, + + /// + /// Pass an int specifying what remote port number to connect to, + /// instead of the one specified in the URL or the default port for the + /// used protocol. + /// + Port = 3, + + /// + /// A true parameter tells the library to do a regular HTTP post. + /// This will also make the library use the a "Content-Type: + /// application/x-www-form-urlencoded" header. (This is by far the most + /// commonly used POST method). + /// + /// Use the PostFields option to specify what data to post + /// and PostFieldSize to set the data size. Optionally, + /// you can provide data to POST using the CurlReadCallback and + /// ReadData options. + /// + /// + /// You can override the default POST Content-Type: header by setting + /// your own with HttpHeader. + /// + /// + /// Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" + /// header. You can disable this header with HttpHeader as usual. + /// + /// + /// If you use POST to a HTTP 1.1 server, you can send data without knowing + /// the size before starting the POST if you use chunked encoding. You + /// enable this by adding a header like "Transfer-Encoding: chunked" with + /// HttpHeader. With HTTP 1.0 or without chunked transfer, + /// you must specify the size in the request. + /// + /// + /// if you have issued a POST request and want to make a HEAD or GET instead, + /// you must explictly pick the new request type using NoBody + /// or HttpGet or similar. + /// + /// + Post = 47, + + /// + /// Pass a string as parameter, which should be the full data to post + /// in an HTTP POST operation. You must make sure that the data is formatted + /// the way you want the server to receive it. libcurl will not convert or + /// encode it for you. Most web servers will assume this data to be + /// url-encoded. Take note. + /// + /// This POST is a normal application/x-www-form-urlencoded kind (and + /// libcurl will set that Content-Type by default when this option is used), + /// which is the most commonly used one by HTML forms. See also the + /// Post. Using PostFields implies + /// Post. + /// + /// + /// Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" + /// header. You can disable this header with HttpHeader as usual. + /// + /// + /// to make multipart/formdata posts (aka rfc1867-posts), check out the + /// HttpPost option. + /// + /// + PostFields = 10015, + + /// + /// If you want to post data to the server without letting libcurl do a + /// strlen() to measure the data size, this option must be used. When + /// this option is used you can post fully binary data, which otherwise + /// is likely to fail. If this size is set to zero, the library will use + /// strlen() to get the size. + /// + PostFieldSize = 60, + + /// + /// Pass a long as parameter. Use this to set the size of the + /// PostFields data to prevent libcurl from doing + /// strlen() on the data to figure out the size. This is the large + /// file version of the PostFieldSize option. (Added in 7.11.1) + /// + PostFieldSizeLarge = 30120, + + /// + /// Pass an of FTP commands to pass to the server after + /// your ftp transfer request. Disable this operation again by setting this + /// option to null. + /// + Postquote = 10039, + + /// + /// Pass an containing the FTP commands to pass to + /// the server after the transfer type is set. Disable this operation + /// again by setting a null to this option. + /// + Prequote = 10093, + + /// + /// Pass an object as parameter, referencing data that should be + /// associated with this object. The object can + /// subsequently be retrieved using CurlEasy.GetInfo with the + /// option. libcurl itself does + /// nothing with this data. (Added in 7.10.3) + /// + Private = 10103, + + /// + /// Pass an object reference that will be untouched by libcurl + /// and passed as the first argument in the progress delegate set with + /// CurlProgressCallback. + /// + ProgressData = 10057, + + /// + /// Pass an delegate reference. This + /// delegate gets called by libcurl at a frequent interval during data + /// transfer. Unknown/unused argument values will be set to zero (like if + /// you only download data, the upload size will remain 0). Returning a + /// non-zero value from this delegate will cause libcurl to abort the + /// transfer and return . + /// + /// NoProgress must be set to false to make this + /// function actually get called. + /// + /// + ProgressFunction = 20056, + + /// + /// Set HTTP proxy to use. The parameter should be a string holding + /// the host name or dotted IP address. To specify port number in this + /// string, append :[port] to the end of the host name. The proxy + /// string may be prefixed with [protocol]:// since any such prefix + /// will be ignored. The proxy's port number may optionally be specified + /// with the separate option ProxyPort. + /// + /// NOTE: when you tell the library to use an HTTP proxy, libcurl will + /// transparently convert operations to HTTP even if you specify an FTP + /// URL etc. This may have an impact on what other features of the library + /// you can use, such as Quote and similar FTP specifics + /// that don't work unless you tunnel through the HTTP proxy. Such tunneling + /// is activated with HttpProxyTunnel. + /// + /// + Proxy = 10004, + + /// + /// Pass a bitmask of as the paramter, to tell + /// libcurl what authentication method(s) you want it to use for your proxy + /// authentication. If more than one bit is set, libcurl will first query the + /// site to see what authentication methods it supports and then pick the best + /// one you allow it to use. Note that for some methods, this will induce an + /// extra network round-trip. Set the actual name and password with the + /// ProxyUserPwd option. The bitmask can be constructed by + /// or'ing together the bits. As of this writing, + /// only and + /// work. (Added in 7.10.7) + /// + ProxyAuth = 111, + + /// + /// Pass an int with this option to set the proxy port to connect + /// to unless it is specified in the proxy string Proxy. + /// + ProxyPort = 59, + + /// + /// Pass a to set type of the proxy. + /// + ProxyType = 101, + + /// + /// Pass a string as parameter, which should be + /// [user name]:[password] to use for the connection to the + /// HTTP proxy. Use ProxyAuth to decide authentication method. + /// + ProxyUserPwd = 10006, + + /// + /// A true parameter tells the library to use HTTP PUT to transfer + /// data. The data should be set with ReadData and + /// InfileSize. + /// + /// This option is deprecated and starting with version 7.12.1 you should + /// instead use Upload. + /// + /// + Put = 54, + + /// + /// Pass a reference to an containing FTP commands to + /// pass to the server prior to your ftp request. This will be done before + /// any other FTP commands are issued (even before the CWD command). + /// Disable this operation again by setting a null to this option. + /// + Quote = 10028, + + /// + /// Pass a string containing the file name. The file will be used + /// to read from to seed the random engine for Ssl. The more random the + /// specified file is, the more secure the Ssl connection will become. + /// + RandomFile = 10076, + + /// + /// Pass a string as parameter, which should contain the + /// specified range you want. It should be in the format X-Y, where X + /// or Y may be left out. HTTP transfers also support several intervals, + /// separated with commas as in X-Y,N-M. Using this kind of multiple + /// intervals will cause the HTTP server to send the response document + /// in pieces (using standard MIME separation techniques). Pass a + /// null to this option to disable the use of ranges. + /// + Range = 10007, + + /// + /// Object reference to pass to the + /// delegate. Note that if you specify the CurlReadCallback, + /// this is the reference you'll get as input. + /// + ReadData = 10009, + + /// + /// Pass a reference to an delegate. + /// This delegate gets called by libcurl as soon as it needs to read data + /// in order to send it to the peer. The data area referenced by the + /// buf may be filled with at most size multiplied with + /// nmemb number of bytes. Your function must return the actual + /// number of bytes that you stored in that byte array. Returning 0 will + /// signal end-of-file to the library and cause it to stop the current transfer. + /// + /// If you stop the current transfer by returning 0 "pre-maturely" + /// (i.e before the server expected it, like when you've told you will + /// upload N bytes and you upload less than N bytes), you may experience that + /// the server "hangs" waiting for the rest of the data that won't come. + /// + /// + ReadFunction = 20012, + + /// + /// Pass a string as parameter. It will be used to set the Referer: + /// header in the http request sent to the remote server. This can be used + /// to fool servers or scripts. You can also set any custom header with + /// HttpHeader. + /// + Referer = 10016, + + /// + /// Pass an int as parameter. It contains the offset in number of + /// bytes that you want the transfer to start from. Set this option to 0 + /// to make the transfer start from the beginning (effectively disabling resume). + /// + ResumeFrom = 21, + + /// + /// Pass a long as parameter. It contains the offset in number of + /// bytes that you want the transfer to start from. (Added in 7.11.0) + /// + ResumeFromLarge = 30116, + + /// + /// Pass an initialized reference as a parameter. + /// Setting this option will make this object use the + /// data from the CurlShare object instead of keeping the data to itself. This + /// enables several CurlEasy objects to share data. If the CurlEasy objects are used + /// simultaneously, you MUST use the CurlShare object's locking methods. + /// See for details. + /// + Share = 10100, + + /// + /// Not supported. + /// + SourceHost = 10122, + + /// + /// Not supported. + /// + SourcePath = 10124, + + /// + /// Not supported. + /// + SourcePort = 125, + + /// + /// When doing a third-party transfer, set the source post-quote list, + /// as an . + /// + SourcePostquote = 10128, + + /// + /// When doing a third-party transfer, set the source pre-quote list, + /// as an . + /// + SourcePrequote = 10127, + + /// + /// When doing a third-party transfer, set a quote list, + /// as an . + /// + SourceQuote = 10133, + + /// + /// Set the source URL for a third-party transfer. + /// + SourceUrl = 10132, + + /// + /// When doing 3rd party transfer, set the source user and password, as + /// a string with format user:password. + /// + SourceUserpwd = 10123, + + /// + /// Pass a string as parameter. The string should be the file name + /// of your certificate. The default format is "PEM" and can be changed + /// with SslCertType. + /// + SslCert = 10025, + + /// + /// Pass a string as parameter. It will be used as the password + /// required to use the SslCert certificate. + /// + /// This option is replaced by SslKeyPasswd and should only + /// be used for backward compatibility. You never needed a pass phrase to + /// load a certificate but you need one to load your private key. + /// + /// + SslCertPasswd = 10026, + + /// + /// Pass a string as parameter. The string should be the format of + /// your certificate. Supported formats are "PEM" and "DER". (Added in 7.9.3) + /// + SslCertType = 10086, + + /// + /// Pass a string as parameter. It will be used as the identifier + /// for the crypto engine you want to use for your private key. + /// + /// If the crypto device cannot be loaded, + /// is returned. + /// + /// + SslEngine = 10089, + + /// + /// Sets the actual crypto engine as the default for (asymmetric) + /// crypto operations. + /// + /// If the crypto device cannot be set, + /// is returned. + /// + /// + SslEngineDefault = 90, + + /// + /// Pass a string as parameter. The string should be the file name + /// of your private key. The default format is "PEM" and can be changed + /// with SslKeyType. + /// + SslKey = 10087, + + /// + /// Pass a string as parameter. It will be used as the password + /// required to use the SslKey private key. + /// + SslKeyPasswd = 10026, + + /// + /// Pass a string as parameter. The string should be the format of + /// your private key. Supported formats are "PEM", "DER" and "ENG". + /// + /// The format "ENG" enables you to load the private key from a crypto + /// engine. In this case SslKey is used as an identifier + /// passed to the engine. You have to set the crypto engine with + /// SslEngine. "DER" format key file currently does not + /// work because of a bug in OpenSSL. + /// + /// + SslKeyType = 10088, + + /// + /// Pass a member of the enumeration as the + /// parameter to set the Ssl version to use. By default + /// the Ssl library will try to solve this by itself although some servers + /// servers make this difficult why you at times may have to use this + /// option. + /// + SslVersion = 32, + + /// + /// Pass a string holding the list of ciphers to use for the Ssl + /// connection. The list must be syntactically correct, it consists of + /// one or more cipher strings separated by colons. Commas or spaces are + /// also acceptable separators but colons are normally used, !, - and + + /// can be used as operators. Valid examples of cipher lists include + /// 'RC4-SHA', ´SHA1+DES´, 'Tlsv1' and 'DEFAULT'. The default list is + /// normally set when you compile OpenSSL. + /// + /// You'll find more details about cipher lists on this URL: + /// http://www.openssl.org/docs/apps/ciphers.html + /// + /// + SslCipherList = 10083, + + /// + /// Object reference to pass to the ssl context delegate set by the option + /// SslCtxFunction, this is the pointer you'll get as the + /// second parameter, otherwise null. (Added in 7.11.0) + /// + SslCtxData = 10109, + + /// + /// Reference to an delegate. + /// This delegate gets called by libcurl just before the initialization of + /// an Ssl connection after having processed all other Ssl related options + /// to give a last chance to an application to modify the behaviour of + /// openssl's ssl initialization. The parameter + /// wraps a pointer to an openssl SSL_CTX. If an error is returned no attempt + /// to establish a connection is made and the perform operation will return + /// the error code from this callback function. Set the parm argument with + /// the SslCtxData option. This option was introduced + /// in 7.11.0. + /// + /// To use this properly, a non-trivial amount of knowledge of the openssl + /// libraries is necessary. Using this function allows for example to use + /// openssl callbacks to add additional validation code for certificates, + /// and even to change the actual URI of an HTTPS request. + /// + /// + SslCtxFunction = 20108, + + /// + /// Pass an int. Set if we should verify the common name from the + /// peer certificate in the Ssl handshake, set 1 to check existence, 2 to + /// ensure that it matches the provided hostname. This is by default set + /// to 2. (default changed in 7.10) + /// + SslVerifyhost = 81, + + /// + /// Pass a bool that is set to false to stop curl from + /// verifying the peer's certificate (7.10 starting setting this option + /// to non-zero by default). Alternate certificates to verify against + /// can be specified with the CaInfo option or a + /// certificate directory can be specified with the CaPath + /// option. As of 7.10, curl installs a default bundle. + /// SslVerifyhost may also need to be set to 1 + /// or 0 if SslVerifyPeer is disabled (it defaults to 2). + /// + SslVerifyPeer = 64, + + /// + /// Not supported. + /// + Stderr = 10037, + + /// + /// Pass a bool specifying whether the TCP_NODELAY option should be + /// set or cleared (true = set, false = clear). The option is + /// cleared by default. This will have no effect after the connection has + /// been established. + /// + /// Setting this option will disable TCP's Nagle algorithm. The purpose of + /// this algorithm is to try to minimize the number of small packets on the + /// network (where "small packets" means TCP segments less than the Maximum + /// Segment Size (MSS) for the network). + /// + /// + /// Maximizing the amount of data sent per TCP segment is good because it + /// amortizes the overhead of the send. However, in some cases (most notably + /// telnet or rlogin) small segments may need to be sent without delay. This + /// is less efficient than sending larger amounts of data at a time, and can + /// contribute to congestion on the network if overdone. + /// + /// + TcpNoDelay = 121, + + /// + /// Pass a bool specifying whether to ignore Content-Length + /// + IgnoreContentLength = 136, + + /// + /// Set to true 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. + /// + FtpSkipPasvIp = 137, + + /// + /// Provide an with variables to pass to the telnet + /// negotiations. The variables should be in the format "option=value". + /// libcurl supports the options 'TTYPE', 'XDISPLOC' and 'NEW_ENV'. See + /// the TELNET standard for details. + /// + TelnetOptions = 10070, + + /// + /// Pass a member of the enumeration as + /// parameter. This defines how the TimeValue time + /// value is treated. This feature applies to HTTP and FTP. + /// + /// The last modification time of a file is not always known and in such + /// instances this feature will have no effect even if the given time + /// condition would have not been met. + /// + /// + TimeCondition = 33, + + /// + /// Pass a int as parameter containing the maximum time in seconds + /// that you allow the libcurl transfer operation to take. Normally, name + /// lookups can take a considerable time and limiting operations to less + /// than a few minutes risk aborting perfectly normal operations. This + /// option will cause curl to use the SIGALRM to enable time-outing + /// system calls. + /// + /// this is not recommended to use in unix multi-threaded programs, + /// as it uses signals unless NoSignal (see above) is set. + /// + /// + Timeout = 13, + + /// + /// Pass a as parameter. This time will be + /// used in a condition as specified with TimeCondition. + /// + TimeValue = 34, + + /// + /// A true parameter tells the library to use ASCII mode for ftp + /// transfers, instead of the default binary transfer. For LDAP transfers + /// it gets the data in plain text instead of HTML and for win32 systems + /// it does not set the stdout to binary mode. This option can be usable + /// when transferring text data between systems with different views on + /// certain characters, such as newlines or similar. + /// + TransferText = 53, + + /// + /// A true parameter tells the library it can continue to send + /// authentication (user+password) when following locations, even when + /// hostname changed. Note that this is meaningful only when setting + /// FollowLocation. + /// + UnrestrictedAuth = 105, + + /// + /// A true parameter tells the library to prepare for an + /// upload. The ReadData and InfileSize + /// or InFileSizeLarge are also interesting for uploads. + /// If the protocol is HTTP, uploading means using the PUT request + /// unless you tell libcurl otherwise. + /// + /// Using PUT with HTTP 1.1 implies the use of a "Expect: 100-continue" + /// header. You can disable this header with HttpHeader as usual. + /// + /// + /// If you use PUT to a HTTP 1.1 server, you can upload data without + /// knowing the size before starting the transfer if you use chunked + /// encoding. You enable this by adding a header like + /// "Transfer-Encoding: chunked" with HttpHeader. With + /// HTTP 1.0 or without chunked transfer, you must specify the size. + /// + /// + Upload = 46, + + /// + /// The actual URL to deal with. The parameter should be a string. + /// If the given URL lacks the protocol part ("http://" or "ftp://" etc), it + /// will attempt to guess which protocol to use based on the given host name. + /// + /// If the given protocol of the set URL is not supported, libcurl will return + /// an error CurlCode.() + /// when you call CurlEasy's or + /// CurlMulti's . + /// + /// + /// Use for detailed info + /// on which protocols that are supported. + /// + /// + Url = 10002, + + /// + /// Pass a string as parameter. It will be used to set the + /// User-Agent: header in the http request sent to the remote server. + /// This can be used to fool servers or scripts. You can also set any + /// custom header with HttpHeader. + /// + UserAgent = 10018, + + /// + /// Pass a string as parameter, which should be + /// [user name]:[password] to use for the connection. Use + /// HttpAuth to decide authentication method. + /// + /// When using HTTP and FollowLocation, libcurl might + /// perform several requests to possibly different hosts. libcurl will + /// only send this user and password information to hosts using the + /// initial host name (unless UnrestrictedAuth is set), + /// so if libcurl follows locations to other hosts it will not send the + /// user and password to those. This is enforced to prevent accidental + /// information leakage. + /// + /// + UserPwd = 10005, + + /// + /// Set the parameter to true to get the library to display a lot + /// of verbose information about its operations. Very useful for libcurl + /// and/or protocol debugging and understanding. The verbose information + /// will be sent to the delegate, if it's + /// implemented. You hardly ever want this set in production use, you will + /// almost always want this when you debug/report problems. + /// + Verbose = 41, + + /// + /// Object reference to pass to the + /// delegate. Note that if you specify the CurlWriteCallback, + /// this is the object you'll get as input. + /// + WriteData = 10001, + + /// + /// Pass a reference to an delegate. + /// The delegate gets called by libcurl as soon as there is data received + /// that needs to be saved. The size of the data referenced by buf + /// is size multiplied with nmemb, it will not be zero + /// terminated. Return the number of bytes actually taken care of. If + /// that amount differs from the amount passed to your function, it'll + /// signal an error to the library and it will abort the transfer and + /// return CurlCode.. + /// + /// This function may be called with zero bytes data if the + /// transfered file is empty. + /// + /// + WriteFunction = 20011, + + /// + /// Pass a string of the output using full variable-replacement + /// as described elsewhere. + /// + WriteInfo = 10040, + + + /// + /// Set to true to enable the "TE:" header in HTTP requests to ask for compressed transfer-encoded responses. Set to 0 + /// to disable the use of TE: in outgoing requests. The current default is false, but it might change in a future + /// libcurl release. libcurl will ask for the compressed methods it knows of, and if that isn't any, it will not ask + /// for transfer-encoding at all even if this option is set to true. + /// + TransferEncoding = 207, + + /// + /// Callback function for closing socket (instead of close(2)). The callback should have type curl_closesocket_callback + /// + CloseSocketFunction = 20208, + CloseSocketData = 10209, + + + /// + /// feed cookies into cookie engine + /// + CookieList = 10135, + + /// + /// Select "file method" to use when doing FTP, see the curl_ftpmethod above. + /// + FtpFileMethod = 138, + + /// + /// Local port number to bind the socket to + /// + LocalPort = 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. + /// + LocalPortRange = 140, + + /// + /// No transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET + /// + ConnectOnly = 141, + + /// + /// if the connection proceeds too quickly then need to slow it down limit-rate: maximum number of bytes per second to + /// send or receive + /// + MaxSendSpeedLarge = 30145, + MaxRecvSpeedLarge = 30146, + + /// + /// Pointer to command string to send if USER/PASS fails. + /// + FtpAlternativeToUser = 10147, + + /// + /// Callback function for setting socket options + /// + SockoptFunction = 20148, + SockoptData = 149, + + + /// + /// Set to false to disable session ID re-use for this transfer, default is enabled (== true) + /// + SslSessionidCache = 150, + + /// + /// Allowed SSH authentication methods + /// + SshAuthTypes = 151, + + /// + /// Used by scp/sftp to do public/private key authentication + /// + SshPublicKeyfile = 10152, + SshPrivateKeyfile = 10152, + + /// + /// Same as Timeout and ConnectTimeout, but with ms resolution + /// + TimeoutMs = 155, + ConnectTimeoutMs = 156, + + /// + /// Set to false to disable the libcurl's decoding and thus pass the raw body data to the application even when it is + /// encoded/compressed + /// + HttpTransferDecoding = 157, + HttpContentDecoding = 158, + + /// + /// Permission used when creating new files and directories on the remote server for protocols that support it, + /// SFTP/SCP/FILE + /// + NewFilePerms = 159, + NewDirectoryPerms = 160, + + /// + /// Set the behaviour of POST when redirecting. Values must be set to one of CURL_REDIR* defines below. This used to be + /// called CURLOPT_POST301 + /// + PostRedir = 161, + + /// + /// Used by scp/sftp to verify the host's public key + /// + SshHostPublicKeyMd5 = 10162, + + + /// + /// Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or + /// refuse to connect returning CURL_SOCKET_BAD. The callback should have type curl_opensocket_callback + /// + OpenSocketFunction = 20163, + OpenSocketData = 10164, + + /// + /// POST volatile input fields. + /// + CopyPostFields = 10165, + + /// + /// set transfer mode (;type=) when doing FTP via an HTTP proxy + /// + ProxyTransferMode = 166, + + /// + /// Callback function for seeking in the input stream + /// + SeekFunction = 20167, + SeekData = 10168, + + /// + /// CRL file + /// + CrlFile = 10169, + + /// + /// Issuer certificate + /// + IssuerCert = 10170, + + /// + /// (IPv6) Address scope + /// + AddressScope = 171, + + /// + /// Collect certificate chain info and allow it to get retrievable with CURLINFO_CERTINFO after the transfer is + /// complete. + /// + CertInfo = 172, + + /// + /// "name" and "pwd" to use when fetching. + /// + Username = 10173, + Password = 10174, + + /// + /// "name" and "pwd" to use with Proxy when fetching. + /// + ProxyUsername = 10175, + ProxyPassword = 10176, + + /// + /// Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and + /// hostnames within a domain. For example, local.com will match local.com and www.local.com, but NOT notlocal.com or + /// www.notlocal.com. For compatibility with other implementations of this, .local.com will be considered to be the + /// same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. + /// + NoProxy = 10177, + + + /// + /// block size for TFTP transfers + /// + TftpBlksize = 178, + + /// + /// Socks service + /// + Socks5GssApiService = 10179, + Socks5GssApiNec = 180, + + /// + /// set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which + /// takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to + /// CURLPROTO_ALL. + /// + Protocols = 181, + + /// + /// set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. + /// That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. Defaults to all + /// protocols except FILE and SCP. + /// + RedirProtocols = 182, + + /// + /// Set the SSH knownhost file name to use + /// + SshKnownHosts = 10183, + + /// + /// set the SSH host key callback, must point to a curl_sshkeycallback function + /// + SshKeyFunction = 20184, + + /// + /// Set the SSH host key callback custom pointer + /// + SshKeydata = 10185, + + /// + /// Set the SMTP mail originator + /// + MailFrom = 10186, + + /// + /// Set the SMTP mail receiver(s) + /// + MailRcpt = 10187, + + /// + /// FTP: send PRET before PASV + /// + FtpUsePret = 188, + + /// + /// Set the interface string to use as outgoing network interface for DNS requests. Only supported by the c-ares DNS + /// backend */ + /// + DnsInterface = 10221, + + /// + /// Set the local IPv4 address to use for outgoing DNS requests. Only supported by the c-ares DNS backend + /// + DnsLocalIp4 = 10222, + + /// + /// Set the local IPv6 address to use for outgoing DNS requests. Only supported by the c-ares DNS backend + /// + DnsLocalIp6 = 10223, + + /// + /// Set authentication options directly + /// + LoginOptions = 10224, + + /// + /// Enable/disable TLS NPN extension (http2 over ssl might fail without) + /// + SslEnableNpn = 225, + + /// + /// Enable/disable TLS ALPN extension (http2 over ssl might fail without) + /// + SslEnableAlpn = 226, + + /// + /// Time to wait for a response to a HTTP request containing an Expect: 100-continue header before sending the data + /// anyway. + /// + Expect100TimeoutMs = 227, + + /// + /// This points to a linked list of headers used for proxy requests only, struct curl_slist kind + /// + ProxyHeader = 228, + + /// + /// Pass in a bitmask of "header options" + /// + HeaderOpt = 229, + + /// + /// Last numeric entry in the enumeration. Don't use this in your + /// application code. + /// + LastEntry = 230, + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlProxyType.cs b/src/CurlSharp/Enums/CurlProxyType.cs new file mode 100644 index 000000000..8b9b7c96e --- /dev/null +++ b/src/CurlSharp/Enums/CurlProxyType.cs @@ -0,0 +1,27 @@ +namespace CurlSharp +{ + /// + /// This enumeration contains values used to specify the proxy type when + /// using the option when calling + /// + /// + public enum CurlProxyType + { + /// + /// Ordinary HTTP proxy. + /// + Http = 0, + + /// + /// Use if the proxy supports SOCKS4 user authentication. If you're + /// unfamiliar with this, consult your network administrator. + /// + Socks4 = 4, + + /// + /// Use if the proxy supports SOCKS5 user authentication. If you're + /// unfamiliar with this, consult your network administrator. + /// + Socks5 = 5 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlShareCode.cs b/src/CurlSharp/Enums/CurlShareCode.cs new file mode 100644 index 000000000..4e0919d5a --- /dev/null +++ b/src/CurlSharp/Enums/CurlShareCode.cs @@ -0,0 +1,40 @@ +namespace CurlSharp +{ + /// + /// Contains return codes from many of the functions in the + /// class. + /// + public enum CurlShareCode + { + /// + /// The function succeeded. + /// + Ok = 0, + + /// + /// A bad option was passed to . + /// + BadOption = 1, + + /// + /// An attempt was made to pass an option to + /// while the CurlShare object is in use. + /// + InUse = 2, + + /// + /// The object's internal handle is invalid. + /// + Invalid = 3, + + /// + /// Out of memory. This is a severe problem. + /// + NoMem = 4, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 5 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlShareOption.cs b/src/CurlSharp/Enums/CurlShareOption.cs new file mode 100644 index 000000000..d887e2899 --- /dev/null +++ b/src/CurlSharp/Enums/CurlShareOption.cs @@ -0,0 +1,53 @@ +namespace CurlSharp +{ + /// + /// A member of this enumeration is passed to the function + /// to configure a + /// transfer. + /// + public enum CurlShareOption + { + /// + /// Start-of-enumeration; do not use in application code. + /// + None = 0, + + /// + /// The parameter, which should be a member of the + /// enumeration, specifies a type of + /// data that should be shared. + /// + Share = 1, + + /// + /// The parameter, which should be a member of the + /// enumeration, specifies a type of + /// data that should be unshared. + /// + Unshare = 2, + + /// + /// The parameter should be a reference to a + /// delegate. + /// + LockFunction = 3, + + /// + /// The parameter should be a reference to a + /// delegate. + /// + UnlockFunction = 4, + + /// + /// The parameter allows you to specify an object reference that + /// will passed to the delegate and + /// the delegate. + /// + UserData = 5, + + /// + /// End-of-enumeration; do not use in application code. + /// + Last = 6 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlSslVersion.cs b/src/CurlSharp/Enums/CurlSslVersion.cs new file mode 100644 index 000000000..0e9b67203 --- /dev/null +++ b/src/CurlSharp/Enums/CurlSslVersion.cs @@ -0,0 +1,36 @@ +namespace CurlSharp +{ + /// + /// Contains values used to specify the Ssl version level when using + /// the option in a call + /// to + /// + public enum CurlSslVersion + { + /// + /// Use whatever version the Ssl library selects. + /// + Default = 0, + + /// + /// Use TLS version 1. + /// + Tlsv1 = 1, + + /// + /// Use Ssl version 2. This is not a good option unless it's the + /// only version supported by the remote server. + /// + Sslv2 = 2, + + /// + /// Use Ssl version 3. This is a preferred option. + /// + Sslv3 = 3, + + /// + /// Last entry in enumeration; do not use in application code. + /// + Last = 4 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlTimeCond.cs b/src/CurlSharp/Enums/CurlTimeCond.cs new file mode 100644 index 000000000..a070ca989 --- /dev/null +++ b/src/CurlSharp/Enums/CurlTimeCond.cs @@ -0,0 +1,39 @@ +namespace CurlSharp +{ + /// + /// Contains values used to specify the time condition when using + /// the option in a call + /// to + /// + public enum CurlTimeCond + { + /// + /// Use no time condition. + /// + None = 0, + + /// + /// The time condition is true if the resource has been modified + /// since the date/time passed in + /// . + /// + IfModSince = 1, + + /// + /// True if the resource has not been modified since the date/time + /// passed in . + /// + IfUnmodSince = 2, + + /// + /// True if the resource's last modification date/time equals that + /// passed in . + /// + LastMod = 3, + + /// + /// Last entry in enumeration; do not use in application code. + /// + Last = 4 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlVersion.cs b/src/CurlSharp/Enums/CurlVersion.cs new file mode 100644 index 000000000..264afd272 --- /dev/null +++ b/src/CurlSharp/Enums/CurlVersion.cs @@ -0,0 +1,34 @@ +namespace CurlSharp +{ + /// + /// A member of this enumeration is passed to the function + /// + /// + public enum CurlVersion + { + /// + /// Capabilities associated with the initial version of libcurl. + /// + First = 0, + + /// + /// Capabilities associated with the second version of libcurl. + /// + Second = 1, + + /// + /// Capabilities associated with the third version of libcurl. + /// + Third = 2, + + /// + /// Same as Third. + /// + Now = Third, + + /// + /// End-of-enumeration marker; do not use in application code. + /// + Last = 3 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/Enums/CurlVersionFeatureBitmask.cs b/src/CurlSharp/Enums/CurlVersionFeatureBitmask.cs new file mode 100644 index 000000000..98cf2f597 --- /dev/null +++ b/src/CurlSharp/Enums/CurlVersionFeatureBitmask.cs @@ -0,0 +1,71 @@ +namespace CurlSharp +{ + /// + /// A bitmask of libcurl features OR'd together as the value of the + /// property . The feature + /// bits are summarized in the table below. + /// + public enum CurlVersionFeatureBitmask + { + /// + /// Supports Ipv6. + /// + Ipv6 = 0x01, + + /// + /// Supports kerberos4 (when using FTP). + /// + Kerberos64 = 0x02, + + /// + /// Supports Ssl (HTTPS/FTPS). + /// + Ssl = 0x04, + + /// + /// Supports HTTP deflate using libz. + /// + LibZ = 0x08, + + /// + /// Supports HTTP Ntlm (added in 7.10.6). + /// + Ntlm = 0x10, + + /// + /// Supports HTTP GSS-Negotiate (added in 7.10.6). + /// + GssNegotiate = 0x20, + + /// + /// libcurl was built with extra debug capabilities built-in. This + /// is mainly of interest for libcurl hackers. (added in 7.10.6) + /// + Debug = 0x40, + + /// + /// libcurl was built with support for asynchronous name lookups, + /// which allows more exact timeouts (even on Windows) and less + /// blocking when using the multi interface. (added in 7.10.7) + /// + AsynchDns = 0x80, + + /// + /// libcurl was built with support for Spnego authentication + /// (Simple and Protected GSS-API Negotiation Mechanism, defined + /// in RFC 2478.) (added in 7.10.8) + /// + Spnego = 0x100, + + /// + /// libcurl was built with support for large files. + /// + LargeFile = 0x200, + + /// + /// libcurl was built with support for IDNA, domain names with + /// international letters. + /// + Idn = 0x400 + }; +} \ No newline at end of file diff --git a/src/CurlSharp/NativeMethods.cs b/src/CurlSharp/NativeMethods.cs new file mode 100644 index 000000000..e1227033a --- /dev/null +++ b/src/CurlSharp/NativeMethods.cs @@ -0,0 +1,393 @@ +/*************************************************************************** + * + * CurlS#arp + * + * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) + * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) + * + * This software is licensed as described in the file LICENSE, which you + * should have received as part of this distribution. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of this Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the LICENSE file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + * ANY KIND, either express or implied. + * + **************************************************************************/ + +//#define USE_LIBCURLSHIM + +using System; +using System.Runtime.InteropServices; + +namespace CurlSharp +{ + /// + /// P/Invoke signatures. + /// + internal static unsafe class NativeMethods + { + #if WIN64 + private const string CURL_LIB = "libcurl64.dll"; + + +#if USE_LIBCURLSHIM + private const string CURLSHIM_LIB = "libcurlshim64.dll"; +#endif + +#else + #if LINUX + private const string CURL_LIB = "libcurl"; + #else + private const string CURL_LIB = "libcurl.dll"; + + +#if USE_LIBCURLSHIM + private const string CURLSHIM_LIB = "libcurlshim.dll"; +#endif + #endif + #endif + #if !USE_LIBCURLSHIM + #if LINUX + private const string WINSOCK_LIB = "libc"; + #else + private const string WINSOCK_LIB = "ws2_32.dll"; +#endif + #endif + + // internal delegates from cURL + + // libcurl imports + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_global_init (int flags); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_global_cleanup (); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_escape (String url, int length); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_unescape (String url, int length); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_free (IntPtr p); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_version (); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_easy_init (); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_easy_cleanup (IntPtr pCurl); + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate int _CurlGenericCallback (IntPtr ptr, int sz, int nmemb, IntPtr userdata); + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate int _CurlProgressCallback ( + IntPtr extraData, double dlTotal, double dlNow, double ulTotal, double ulNow); + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate int _CurlDebugCallback ( + IntPtr ptrCurl, CurlInfoType infoType, string message, int size, IntPtr ptrUserData); + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate int _CurlSslCtxCallback (IntPtr ctx, IntPtr parm); + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate CurlIoError _CurlIoctlCallback (CurlIoCommand cmd, IntPtr parm); + + // curl_easy_setopt() overloads + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, IntPtr parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, string parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, byte[] parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, long parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_setopt (IntPtr pCurl, CurlOption opt, bool parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")] + internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlGenericCallback parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")] + internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlProgressCallback parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")] + internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlDebugCallback parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")] + internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlSslCtxCallback parm); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, EntryPoint = "curl_easy_setopt")] + internal static extern CurlCode curl_easy_setopt_cb (IntPtr pCurl, CurlOption opt, _CurlIoctlCallback parm); + + #if !USE_LIBCURLSHIM + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_multi_fdset (IntPtr pmulti, + [In, Out] ref fd_set read_fd_set, + [In, Out] ref fd_set write_fd_set, + [In, Out] ref fd_set exc_fd_set, + [In, Out] ref int max_fd); + + [StructLayout (LayoutKind.Sequential)] + internal struct fd_set + { + internal uint fd_count; + //[MarshalAs(UnmanagedType.ByValArray, SizeConst = FD_SETSIZE)] internal IntPtr[] fd_array; + internal fixed uint fd_array[FD_SETSIZE]; + + internal const int FD_SETSIZE = 64; + + internal void Cleanup () + { + //fd_array = null; + } + + internal static fd_set Create () + { + return new fd_set { + //fd_array = new IntPtr[FD_SETSIZE], + fd_count = 0 + }; + } + + internal static fd_set Create (IntPtr socket) + { + var handle = Create (); + handle.fd_count = 1; + handle.fd_array [0] = (uint)socket; + return handle; + } + } + + internal static void FD_ZERO (fd_set fds) + { + for (var i = 0; i < fd_set.FD_SETSIZE; i++) { + //fds.fd_array[i] = (IntPtr) 0; + fds.fd_array [i] = 0; + } + fds.fd_count = 0; + } + + [StructLayout (LayoutKind.Sequential)] + internal struct timeval + { + /// + /// Time interval, in seconds. + /// + internal int tv_sec; + + /// + /// Time interval, in microseconds. + /// + internal int tv_usec; + + internal static timeval Create (int milliseconds) + { + return new timeval { + tv_sec = milliseconds / 1000, + tv_usec = (milliseconds % 1000) * 1000 + }; + } + }; + + [DllImport (WINSOCK_LIB, EntryPoint = "select")] + internal static extern int select ( + int nfds, // number of sockets, (ignored in winsock) + [In, Out] ref fd_set readfds, // read sockets to watch + [In, Out] ref fd_set writefds, // write sockets to watch + [In, Out] ref fd_set exceptfds, // error sockets to watch + ref timeval timeout); + + //[DllImport(WINSOCK_LIB, EntryPoint = "select")] + //internal static extern int select(int ndfs, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout); + #endif + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_perform (IntPtr pCurl); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_easy_duphandle (IntPtr pCurl); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_easy_strerror (CurlCode err); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_getinfo (IntPtr pCurl, CurlInfo info, ref IntPtr pInfo); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlCode curl_easy_getinfo (IntPtr pCurl, CurlInfo info, ref double dblVal); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_easy_reset (IntPtr pCurl); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_multi_init (); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_multi_cleanup (IntPtr pmulti); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_multi_add_handle (IntPtr pmulti, IntPtr peasy); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_multi_remove_handle (IntPtr pmulti, IntPtr peasy); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_multi_strerror (CurlMultiCode errorNum); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_multi_perform (IntPtr pmulti, ref int runningHandles); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_formfree (IntPtr pForm); + + #if !USE_LIBCURLSHIM + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_formadd (ref IntPtr pHttppost, ref IntPtr pLastPost, + int codeFirst, IntPtr bufFirst, + int codeNext, IntPtr bufNext, + int codeLast); + #endif + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_share_init (); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlShareCode curl_share_cleanup (IntPtr pShare); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_share_strerror (CurlShareCode errorCode); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlShareCode curl_share_setopt (IntPtr pShare, CurlShareOption optCode, IntPtr option); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_slist_append (IntPtr slist, string data); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlShareCode curl_slist_free_all (IntPtr pList); + + [DllImport (CURL_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_version_info (CurlVersion ver); + + #if USE_LIBCURLSHIM + + // libcurlshim imports + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_initialize(); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_cleanup(); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_shim_alloc_strings(); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_shim_add_string_to_slist( + IntPtr pStrings, String str); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_shim_get_string_from_slist( + IntPtr pSlist, ref IntPtr pStr); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi)] + internal static extern IntPtr curl_shim_add_string(IntPtr pStrings, String str); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_free_strings(IntPtr pStrings); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_install_delegates(IntPtr pCurl, IntPtr pThis, + _ShimWriteCallback pWrite, _ShimReadCallback pRead, + _ShimProgressCallback pProgress, _ShimDebugCallback pDebug, + _ShimHeaderCallback pHeader, _ShimSslCtxCallback pCtx, + _ShimIoctlCallback pIoctl); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_cleanup_delegates(IntPtr pThis); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_get_file_time(int unixTime, + ref int yy, ref int mm, ref int dd, ref int hh, ref int mn, ref int ss); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_free_slist(IntPtr p); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_shim_alloc_fd_sets(); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_free_fd_sets(IntPtr fdsets); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern CurlMultiCode curl_shim_multi_fdset(IntPtr multi, + IntPtr fdsets, ref int maxFD); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_select(int maxFD, IntPtr fdsets, + int milliseconds); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_shim_multi_info_read(IntPtr multi, + ref int nMsgs); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_multi_info_free(IntPtr multiInfo); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_formadd(IntPtr[] ppForms, IntPtr[] pParams, int nParams); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_install_share_delegates(IntPtr pShare, + IntPtr pThis, _ShimLockCallback pLock, _ShimUnlockCallback pUnlock); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern void curl_shim_cleanup_share_delegates(IntPtr pShare); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_get_version_int_value(IntPtr p, int offset); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_shim_get_version_char_ptr(IntPtr p, int offset); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern int curl_shim_get_number_of_protocols(IntPtr p, int offset); + + [DllImport(CURLSHIM_LIB, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr curl_shim_get_protocol_string(IntPtr p, int offset, int index); + + internal delegate void _ShimLockCallback(int data, int access, IntPtr userPtr); + + internal delegate void _ShimUnlockCallback(int data, IntPtr userPtr); + + internal delegate int _ShimDebugCallback(CurlInfoType infoType, IntPtr msgBuf, int msgBufSize, IntPtr parm); + + internal delegate int _ShimHeaderCallback(IntPtr buf, int sz, int nmemb, IntPtr stream); + + internal delegate CurlIoError _ShimIoctlCallback(CurlIoCommand cmd, IntPtr parm); + + internal delegate int _ShimProgressCallback(IntPtr parm, double dlTotal, double dlNow, double ulTotal, double ulNow); + + internal delegate int _ShimReadCallback(IntPtr buf, int sz, int nmemb, IntPtr parm); + + internal delegate int _ShimSslCtxCallback(IntPtr ctx, IntPtr parm); + + internal delegate int _ShimWriteCallback(IntPtr buf, int sz, int nmemb, IntPtr parm); +#endif + } +} \ No newline at end of file diff --git a/src/CurlSharp/Properties/AssemblyInfo.cs b/src/CurlSharp/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2296da77a --- /dev/null +++ b/src/CurlSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("CurlSharp")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("max")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/src/Jackett.sln b/src/Jackett.sln index 1135666c2..850174ffe 100644 --- a/src/Jackett.sln +++ b/src/Jackett.sln @@ -1,10 +1,11 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jackett", "Jackett\Jackett.csproj", "{E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurlSharp", "CurlSharp\CurlSharp.csproj", "{74420A79-CC16-442C-8B1E-7C1B913844F0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +16,10 @@ Global {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E636D5F8-68B4-4903-B4ED-CCFD9C9E899F}.Release|Any CPU.Build.0 = Release|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Jackett/CookieContainerExtensions.cs b/src/Jackett/CookieContainerExtensions.cs index 23f253f9d..05bcfdc2e 100644 --- a/src/Jackett/CookieContainerExtensions.cs +++ b/src/Jackett/CookieContainerExtensions.cs @@ -8,15 +8,26 @@ using System.Threading.Tasks; namespace Jackett { - public static class CookieContainerExtensions - { - public static void FillFromJson(this CookieContainer cookies, Uri uri, JArray json) - { - foreach (var cookie in json) - { - var w = ((string)cookie).Split(':'); - cookies.Add(uri, new Cookie(w[0], w[1])); - } - } - } + public static class CookieContainerExtensions + { + public static void FillFromJson (this CookieContainer cookies, Uri uri, JArray json) + { + foreach (string cookie in json) { + + var w = cookie.Split ('='); + if (w.Length == 1) + cookies.Add (uri, new Cookie{ Name = cookie.Trim () }); + else + cookies.Add (uri, new Cookie (w [0].Trim (), w [1].Trim ())); + } + } + + public static JArray ToJson (this CookieContainer cookies, Uri baseUrl) + { + return new JArray (( + from cookie in cookies.GetCookies (baseUrl).Cast () + select cookie.Name.Trim () + "=" + cookie.Value.Trim () + ).ToArray ()); + } + } } diff --git a/src/Jackett/Curl.cs b/src/Jackett/Curl.cs new file mode 100644 index 000000000..7870ba7f2 --- /dev/null +++ b/src/Jackett/Curl.cs @@ -0,0 +1,137 @@ +using CurlSharp; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Jackett +{ + public class CurlHelper + { + private const string ChromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"; + + public static CurlHelper Shared = new CurlHelper(); + + private BlockingCollection curlRequests; + + public bool IsSupported { get; private set; } + + private class CurlRequest + { + public TaskCompletionSource TaskCompletion { get; private set; } + + public string Url { get; private set; } + + public string Cookies { get; private set; } + + public string Referer { get; private set; } + + public HttpMethod Method { get; private set; } + + public string PostData { get; set; } + + public CurlRequest(HttpMethod method, string url, string cookies = null, string referer = null) + { + TaskCompletion = new TaskCompletionSource(); + Method = method; + Url = url; + Cookies = cookies; + Referer = referer; + } + } + + public async Task GetStringAsync(string url, string cookies = null, string referer = null) + { + var curlRequest = new CurlRequest(HttpMethod.Get, url, cookies, referer); + curlRequests.Add(curlRequest); + var result = await curlRequest.TaskCompletion.Task; + return result; + } + + public CurlHelper() + { + try + { + Curl.GlobalInit(CurlInitFlag.All); + IsSupported = true; + } + catch (Exception ex) + { + IsSupported = false; + } + Task.Run((Action)CurlServicer); + } + + private void CurlServicer() + { + curlRequests = new BlockingCollection(); + foreach (var curlRequest in curlRequests.GetConsumingEnumerable()) + { + PerformCurl(curlRequest); + } + } + + private void PerformCurl(CurlRequest curlRequest) + { + var headerBuffers = new List(); + var contentBuffers = new List(); + try + { + using (var easy = new CurlEasy()) + { + easy.Url = curlRequest.Url; + easy.BufferSize = 64 * 1024; + //easy.Encoding = "UTF8"; + easy.WriteFunction = (byte[] buf, int size, int nmemb, object data) => + { + contentBuffers.Add(buf); + return size * nmemb; + }; + easy.HeaderFunction = (byte[] buf, int size, int nmemb, object extraData) => + { + headerBuffers.Add(buf); + return size * nmemb; + }; + + if (!string.IsNullOrEmpty(curlRequest.Cookies)) + easy.Cookie = curlRequest.Cookies; + + if (curlRequest.Method == HttpMethod.Post) + { + easy.Post = true; + easy.PostFields = curlRequest.PostData; + easy.PostFieldSize = Encoding.UTF8.GetByteCount(curlRequest.PostData); + } + + easy.Perform(); + } + + var headerBytes = Combine(headerBuffers.ToArray()); + var headerString = Encoding.UTF8.GetString(headerBytes); + + var contentBytes = Combine(contentBuffers.ToArray()); + var result = Encoding.UTF8.GetString(contentBytes); + curlRequest.TaskCompletion.SetResult(result); + } + catch (Exception ex) + { + curlRequest.TaskCompletion.TrySetException(ex); + } + } + + public static byte[] Combine(params byte[][] arrays) + { + byte[] ret = new byte[arrays.Sum(x => x.Length)]; + int offset = 0; + foreach (byte[] data in arrays) + { + Buffer.BlockCopy(data, 0, ret, offset, data.Length); + offset += data.Length; + } + return ret; + } + } +} diff --git a/src/Jackett/Indexers/BitHdtv.cs b/src/Jackett/Indexers/BitHdtv.cs index e93f4d504..abe52ddb0 100644 --- a/src/Jackett/Indexers/BitHdtv.cs +++ b/src/Jackett/Indexers/BitHdtv.cs @@ -12,152 +12,139 @@ using System.Web; namespace Jackett.Indexers { - public class BitHdtv : IndexerInterface - { - public string DisplayName - { - get { return "BIT-HDTV"; } - } + public class BitHdtv : IndexerInterface + { + public string DisplayName { + get { return "BIT-HDTV"; } + } - public string DisplayDescription - { - get { return "Home of high definition invites"; } - } + public string DisplayDescription { + get { return "Home of high definition invites"; } + } - public Uri SiteLink - { - get { return new Uri(BaseUrl); } - } + public Uri SiteLink { + get { return new Uri (BaseUrl); } + } - static string BaseUrl = "https://www.bit-hdtv.com"; - static string LoginUrl = BaseUrl + "/takelogin.php"; - static string SearchUrl = BaseUrl + "/torrents.php?cat=0&search="; - static string DownloadUrl = BaseUrl + "/download.php?/{0}/dl.torrent"; + static string BaseUrl = "https://www.bit-hdtv.com"; + static string LoginUrl = BaseUrl + "/takelogin.php"; + static string SearchUrl = BaseUrl + "/torrents.php?cat=0&search="; + static string DownloadUrl = BaseUrl + "/download.php?/{0}/dl.torrent"; - CookieContainer cookies; - HttpClientHandler handler; - HttpClient client; + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; - public BitHdtv() - { - IsConfigured = false; - cookies = new CookieContainer(); - handler = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = true, - UseCookies = true, - }; - client = new HttpClient(handler); - } + public BitHdtv () + { + IsConfigured = false; + cookies = new CookieContainer (); + handler = new HttpClientHandler { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient (handler); + } - public Task GetConfigurationForSetup() - { - var config = new ConfigurationDataBasicLogin(); - return Task.FromResult(config); - } + public Task GetConfigurationForSetup () + { + var config = new ConfigurationDataBasicLogin (); + return Task.FromResult (config); + } - public async Task ApplyConfiguration(JToken configJson) - { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + public async Task ApplyConfiguration (JToken configJson) + { + var config = new ConfigurationDataBasicLogin (); + config.LoadValuesFromJson (configJson); - var pairs = new Dictionary - { - { "username", config.Username.Value}, - { "password", config.Password.Value} - }; + var pairs = new Dictionary { + { "username", config.Username.Value }, + { "password", config.Password.Value } + }; - var content = new FormUrlEncodedContent(pairs); + var content = new FormUrlEncodedContent (pairs); - var response = await client.PostAsync(LoginUrl, content); - var responseContent = await response.Content.ReadAsStringAsync(); + var response = await client.PostAsync (LoginUrl, content); + var responseContent = await response.Content.ReadAsStringAsync (); - if (!responseContent.Contains("logout.php")) - { - CQ dom = responseContent; - var messageEl = dom["table.detail td.text"].Last(); - messageEl.Children("a").Remove(); - messageEl.Children("style").Remove(); - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); - } - else - { - var configSaveData = new JObject(); - configSaveData["cookies"] = new JArray(( - from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() - select cookie.Name + ":" + cookie.Value - ).ToArray()); + if (!responseContent.Contains ("logout.php")) { + CQ dom = responseContent; + var messageEl = dom ["table.detail td.text"].Last (); + messageEl.Children ("a").Remove (); + messageEl.Children ("style").Remove (); + var errorMessage = messageEl.Text ().Trim (); + throw new ExceptionWithConfigData (errorMessage, (ConfigurationData)config); + } else { + var configSaveData = new JObject (); + configSaveData ["cookies"] = cookies.ToJson (SiteLink); - if (OnSaveConfigurationRequested != null) - OnSaveConfigurationRequested(this, configSaveData); + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested (this, configSaveData); - IsConfigured = true; - } - } + IsConfigured = true; + } + } - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public bool IsConfigured { get; private set; } + public bool IsConfigured { get; private set; } - public void LoadFromSavedConfiguration(JToken jsonConfig) - { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); - IsConfigured = true; - } + public void LoadFromSavedConfiguration (JToken jsonConfig) + { + cookies.FillFromJson (new Uri (BaseUrl), (JArray)jsonConfig ["cookies"]); + IsConfigured = true; + } - public async Task PerformQuery(TorznabQuery query) - { - List releases = new List(); + public async Task PerformQuery (TorznabQuery query) + { + List releases = new List (); - foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) - { - var searchString = title + " " + query.GetEpisodeSearchString(); - var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); - var results = await client.GetStringAsync(episodeSearchUrl); - CQ dom = results; - dom["#needseed"].Remove(); - var rows = dom["table[width='750'] > tbody"].Children(); - foreach (var row in rows.Skip(1)) - { + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) { + var searchString = title + " " + query.GetEpisodeSearchString (); + var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode (searchString); + var results = await client.GetStringAsync (episodeSearchUrl); + CQ dom = results; + dom ["#needseed"].Remove (); + var rows = dom ["table[width='750'] > tbody"].Children (); + foreach (var row in rows.Skip(1)) { - var release = new ReleaseInfo(); + var release = new ReleaseInfo (); - var qRow = row.Cq(); - var qLink = qRow.Children().ElementAt(2).Cq().Children("a").First(); + var qRow = row.Cq (); + var qLink = qRow.Children ().ElementAt (2).Cq ().Children ("a").First (); - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.Title = qLink.Attr("title"); - release.Description = release.Title; - release.Guid = new Uri(BaseUrl + qLink.Attr("href")); - release.Comments = release.Guid; - release.Link = new Uri(string.Format(DownloadUrl, qLink.Attr("href").Split('=')[1])); + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.Title = qLink.Attr ("title"); + release.Description = release.Title; + release.Guid = new Uri (BaseUrl + qLink.Attr ("href")); + release.Comments = release.Guid; + release.Link = new Uri (string.Format (DownloadUrl, qLink.Attr ("href").Split ('=') [1])); - var dateString = qRow.Children().ElementAt(5).Cq().Text().Trim(); - var pubDate = DateTime.ParseExact(dateString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - release.PublishDate = pubDate; + var dateString = qRow.Children ().ElementAt (5).Cq ().Text ().Trim (); + var pubDate = DateTime.ParseExact (dateString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = pubDate; - var sizeCol = qRow.Children().ElementAt(6); - var sizeVal = sizeCol.ChildNodes[0].NodeValue; - var sizeUnit = sizeCol.ChildNodes[2].NodeValue; - release.Size = ReleaseInfo.GetBytes(sizeUnit, float.Parse(sizeVal)); + var sizeCol = qRow.Children ().ElementAt (6); + var sizeVal = sizeCol.ChildNodes [0].NodeValue; + var sizeUnit = sizeCol.ChildNodes [2].NodeValue; + release.Size = ReleaseInfo.GetBytes (sizeUnit, float.Parse (sizeVal)); - release.Seeders = int.Parse(qRow.Children().ElementAt(8).Cq().Text().Trim()); - release.Peers = int.Parse(qRow.Children().ElementAt(9).Cq().Text().Trim()) + release.Seeders; + release.Seeders = int.Parse (qRow.Children ().ElementAt (8).Cq ().Text ().Trim ()); + release.Peers = int.Parse (qRow.Children ().ElementAt (9).Cq ().Text ().Trim ()) + release.Seeders; - releases.Add(release); - } - } + releases.Add (release); + } + } - return releases.ToArray(); - } + return releases.ToArray (); + } - public Task Download(Uri link) - { - return client.GetByteArrayAsync(link); - } - } + public Task Download (Uri link) + { + return client.GetByteArrayAsync (link); + } + } } diff --git a/src/Jackett/Indexers/BitMeTV.cs b/src/Jackett/Indexers/BitMeTV.cs index f4fb222c7..af63507a3 100644 --- a/src/Jackett/Indexers/BitMeTV.cs +++ b/src/Jackett/Indexers/BitMeTV.cs @@ -13,175 +13,170 @@ using System.Web; namespace Jackett { - public class BitMeTV : IndexerInterface - { - class BmtvConfig : ConfigurationData - { - public StringItem Username { get; private set; } - public StringItem Password { get; private set; } - public ImageItem CaptchaImage { get; private set; } - public StringItem CaptchaText { get; private set; } + public class BitMeTV : IndexerInterface + { + class BmtvConfig : ConfigurationData + { + public StringItem Username { get; private set; } - public BmtvConfig() - { - Username = new StringItem { Name = "Username" }; - Password = new StringItem { Name = "Password" }; - CaptchaImage = new ImageItem { Name = "Captcha Image" }; - CaptchaText = new StringItem { Name = "Captcha Text" }; - } + public StringItem Password { get; private set; } - public override Item[] GetItems() - { - return new Item[] { Username, Password, CaptchaImage, CaptchaText }; - } - } + public ImageItem CaptchaImage { get; private set; } - static string BaseUrl = "http://www.bitmetv.org"; - static string LoginUrl = BaseUrl + "/login.php"; - static string LoginPost = BaseUrl + "/takelogin.php"; - static string CaptchaUrl = BaseUrl + "/visual.php"; - static string SearchUrl = BaseUrl + "/browse.php"; + public StringItem CaptchaText { get; private set; } - CookieContainer cookies; - HttpClientHandler handler; - HttpClient client; + public BmtvConfig () + { + Username = new StringItem { Name = "Username" }; + Password = new StringItem { Name = "Password" }; + CaptchaImage = new ImageItem { Name = "Captcha Image" }; + CaptchaText = new StringItem { Name = "Captcha Text" }; + } - public event Action OnSaveConfigurationRequested; + public override Item[] GetItems () + { + return new Item[] { Username, Password, CaptchaImage, CaptchaText }; + } + } - public BitMeTV() - { - IsConfigured = false; - cookies = new CookieContainer(); - handler = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = true, - UseCookies = true, - }; - client = new HttpClient(handler); - } + static string BaseUrl = "http://www.bitmetv.org"; + static string LoginUrl = BaseUrl + "/login.php"; + static string LoginPost = BaseUrl + "/takelogin.php"; + static string CaptchaUrl = BaseUrl + "/visual.php"; + static string SearchUrl = BaseUrl + "/browse.php"; - public string DisplayName { get { return "BitMeTV"; } } - public string DisplayDescription { get { return "TV Episode specialty tracker"; } } - public Uri SiteLink { get { return new Uri(BaseUrl); } } + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; - public bool IsConfigured { get; private set; } + public event Action OnSaveConfigurationRequested; - public async Task GetConfigurationForSetup() - { - var loginPage = await client.GetAsync(LoginUrl); - var captchaImage = await client.GetByteArrayAsync(CaptchaUrl); - var config = new BmtvConfig(); - config.CaptchaImage.Value = captchaImage; - return (ConfigurationData)config; - } + public BitMeTV () + { + IsConfigured = false; + cookies = new CookieContainer (); + handler = new HttpClientHandler { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient (handler); + } - public async Task ApplyConfiguration(JToken configJson) - { - var config = new BmtvConfig(); - config.LoadValuesFromJson(configJson); + public string DisplayName { get { return "BitMeTV"; } } - var pairs = new Dictionary - { - { "username", config.Username.Value}, - { "password", config.Password.Value}, - { "secimage", config.CaptchaText.Value} - }; + public string DisplayDescription { get { return "TV Episode specialty tracker"; } } - var content = new FormUrlEncodedContent(pairs); + public Uri SiteLink { get { return new Uri (BaseUrl); } } - var response = await client.PostAsync(LoginPost, content); - var responseContent = await response.Content.ReadAsStringAsync(); + public bool IsConfigured { get; private set; } - if (!responseContent.Contains("/logout.php")) - { - CQ dom = responseContent; - var messageEl = dom["table tr > td.embedded > h2"].Last(); - var errorMessage = messageEl.Text(); - var captchaImage = await client.GetByteArrayAsync(CaptchaUrl); - config.CaptchaImage.Value = captchaImage; - config.CaptchaText.Value = ""; - throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); - } - else - { - var configSaveData = new JObject(); - configSaveData["cookies"] = new JArray(( - from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() - select cookie.Name + ":" + cookie.Value - ).ToArray()); + public async Task GetConfigurationForSetup () + { + var loginPage = await client.GetAsync (LoginUrl); + var captchaImage = await client.GetByteArrayAsync (CaptchaUrl); + var config = new BmtvConfig (); + config.CaptchaImage.Value = captchaImage; + return (ConfigurationData)config; + } - if (OnSaveConfigurationRequested != null) - OnSaveConfigurationRequested(this, configSaveData); + public async Task ApplyConfiguration (JToken configJson) + { + var config = new BmtvConfig (); + config.LoadValuesFromJson (configJson); - IsConfigured = true; - } - } + var pairs = new Dictionary { + { "username", config.Username.Value }, + { "password", config.Password.Value }, + { "secimage", config.CaptchaText.Value } + }; - public void LoadFromSavedConfiguration(JToken jsonConfig) - { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); - IsConfigured = true; - } + var content = new FormUrlEncodedContent (pairs); - public async Task PerformQuery(TorznabQuery query) - { - List releases = new List(); + var response = await client.PostAsync (LoginPost, content); + var responseContent = await response.Content.ReadAsStringAsync (); + + if (!responseContent.Contains ("/logout.php")) { + CQ dom = responseContent; + var messageEl = dom ["table tr > td.embedded > h2"].Last (); + var errorMessage = messageEl.Text (); + var captchaImage = await client.GetByteArrayAsync (CaptchaUrl); + config.CaptchaImage.Value = captchaImage; + config.CaptchaText.Value = ""; + throw new ExceptionWithConfigData (errorMessage, (ConfigurationData)config); + } else { + var configSaveData = new JObject (); + configSaveData ["cookies"] = cookies.ToJson (SiteLink); + + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested (this, configSaveData); + + IsConfigured = true; + } + } + + public void LoadFromSavedConfiguration (JToken jsonConfig) + { + cookies.FillFromJson (new Uri (BaseUrl), (JArray)jsonConfig ["cookies"]); + IsConfigured = true; + } + + public async Task PerformQuery (TorznabQuery query) + { + List releases = new List (); - foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) - { + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) { - var searchString = title + " " + query.GetEpisodeSearchString(); - var episodeSearchUrl = string.Format("{0}?search={1}&cat=0", SearchUrl, HttpUtility.UrlEncode(searchString)); - var results = await client.GetStringAsync(episodeSearchUrl); - CQ dom = results; + var searchString = title + " " + query.GetEpisodeSearchString (); + var episodeSearchUrl = string.Format ("{0}?search={1}&cat=0", SearchUrl, HttpUtility.UrlEncode (searchString)); + var results = await client.GetStringAsync (episodeSearchUrl); + CQ dom = results; - var table = dom["tbody > tr > .latest"].Parent().Parent(); + var table = dom ["tbody > tr > .latest"].Parent ().Parent (); - foreach (var row in table.Children().Skip(1)) - { - var release = new ReleaseInfo(); + foreach (var row in table.Children().Skip(1)) { + var release = new ReleaseInfo (); - CQ qRow = row.Cq(); - CQ qDetailsCol = row.ChildElements.ElementAt(1).Cq(); - CQ qLink = qDetailsCol.Children("a").First(); + CQ qRow = row.Cq (); + CQ qDetailsCol = row.ChildElements.ElementAt (1).Cq (); + CQ qLink = qDetailsCol.Children ("a").First (); - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.Comments = new Uri(BaseUrl + "/" + qLink.Attr("href")); - release.Guid = release.Comments; - release.Title = qLink.Attr("title"); - release.Description = release.Title; + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.Comments = new Uri (BaseUrl + "/" + qLink.Attr ("href")); + release.Guid = release.Comments; + release.Title = qLink.Attr ("title"); + release.Description = release.Title; - //"Tuesday, June 11th 2013 at 03:52:53 AM" to... - //"Tuesday June 11 2013 03:52:53 AM" - var timestamp = qDetailsCol.Children("font").Text().Trim() + " "; - var timeParts = new List(timestamp.Replace(" at", "").Replace(",", "").Split(' ')); - timeParts[2] = Regex.Replace(timeParts[2], "[^0-9.]", ""); - var formattedTimeString = string.Join(" ", timeParts.ToArray()).Trim(); - release.PublishDate = DateTime.ParseExact(formattedTimeString, "dddd MMMM d yyyy hh:mm:ss tt", CultureInfo.InvariantCulture); + //"Tuesday, June 11th 2013 at 03:52:53 AM" to... + //"Tuesday June 11 2013 03:52:53 AM" + var timestamp = qDetailsCol.Children ("font").Text ().Trim () + " "; + var timeParts = new List (timestamp.Replace (" at", "").Replace (",", "").Split (' ')); + timeParts [2] = Regex.Replace (timeParts [2], "[^0-9.]", ""); + var formattedTimeString = string.Join (" ", timeParts.ToArray ()).Trim (); + release.PublishDate = DateTime.ParseExact (formattedTimeString, "dddd MMMM d yyyy hh:mm:ss tt", CultureInfo.InvariantCulture); - release.Link = new Uri(BaseUrl + "/" + row.ChildElements.ElementAt(2).Cq().Children("a.index").Attr("href")); + release.Link = new Uri (BaseUrl + "/" + row.ChildElements.ElementAt (2).Cq ().Children ("a.index").Attr ("href")); - var sizeCol = row.ChildElements.ElementAt(6); - var sizeVal = float.Parse(sizeCol.ChildNodes[0].NodeValue); - var sizeUnit = sizeCol.ChildNodes[2].NodeValue; - release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); + var sizeCol = row.ChildElements.ElementAt (6); + var sizeVal = float.Parse (sizeCol.ChildNodes [0].NodeValue); + var sizeUnit = sizeCol.ChildNodes [2].NodeValue; + release.Size = ReleaseInfo.GetBytes (sizeUnit, sizeVal); - release.Seeders = int.Parse(row.ChildElements.ElementAt(8).Cq().Text()); - release.Peers = int.Parse(row.ChildElements.ElementAt(9).Cq().Text()) + release.Seeders; - releases.Add(release); - } - } + release.Seeders = int.Parse (row.ChildElements.ElementAt (8).Cq ().Text ()); + release.Peers = int.Parse (row.ChildElements.ElementAt (9).Cq ().Text ()) + release.Seeders; + releases.Add (release); + } + } - return releases.ToArray(); + return releases.ToArray (); - } + } - public Task Download(Uri link) - { - return client.GetByteArrayAsync(link); - } - } + public Task Download (Uri link) + { + return client.GetByteArrayAsync (link); + } + } } diff --git a/src/Jackett/Indexers/Freshon.cs b/src/Jackett/Indexers/Freshon.cs index 742500f5b..ffde50db0 100644 --- a/src/Jackett/Indexers/Freshon.cs +++ b/src/Jackett/Indexers/Freshon.cs @@ -14,179 +14,168 @@ using System.Web.UI.WebControls; namespace Jackett { - public class Freshon : IndexerInterface - { + public class Freshon : IndexerInterface + { - static string BaseUrl = "https://freshon.tv"; - static string LoginUrl = BaseUrl + "/login.php"; - static string LoginPostUrl = BaseUrl + "/login.php?action=makelogin"; - static string SearchUrl = BaseUrl + "/browse.php"; + static string BaseUrl = "https://freshon.tv"; + static string LoginUrl = BaseUrl + "/login.php"; + static string LoginPostUrl = BaseUrl + "/login.php?action=makelogin"; + static string SearchUrl = BaseUrl + "/browse.php"; - static string chromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; + static string chromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; - CookieContainer cookies; - HttpClientHandler handler; - HttpClient client; + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; - public bool IsConfigured { get; private set; } + public bool IsConfigured { get; private set; } - public string DisplayName { get { return "FreshOnTV"; } } + public string DisplayName { get { return "FreshOnTV"; } } - public string DisplayDescription { get { return "Our goal is to provide the latest stuff in the TV show domain"; } } + public string DisplayDescription { get { return "Our goal is to provide the latest stuff in the TV show domain"; } } - public Uri SiteLink { get { return new Uri(BaseUrl); } } + public Uri SiteLink { get { return new Uri (BaseUrl); } } - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public Freshon() - { - IsConfigured = false; - cookies = new CookieContainer(); - handler = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = true, - UseCookies = true, - }; - client = new HttpClient(handler); - } + public Freshon () + { + IsConfigured = false; + cookies = new CookieContainer (); + handler = new HttpClientHandler { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient (handler); + } - public async Task GetConfigurationForSetup() - { - var request = CreateHttpRequest(new Uri(LoginUrl)); - var response = await client.SendAsync(request); - await response.Content.ReadAsStreamAsync(); - var config = new ConfigurationDataBasicLogin(); - return config; - } + public async Task GetConfigurationForSetup () + { + var request = CreateHttpRequest (new Uri (LoginUrl)); + var response = await client.SendAsync (request); + await response.Content.ReadAsStreamAsync (); + var config = new ConfigurationDataBasicLogin (); + return config; + } - public async Task ApplyConfiguration(JToken configJson) - { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + public async Task ApplyConfiguration (JToken configJson) + { + var config = new ConfigurationDataBasicLogin (); + config.LoadValuesFromJson (configJson); - var pairs = new Dictionary - { - { "username", config.Username.Value}, - { "password", config.Password.Value} - }; + var pairs = new Dictionary { + { "username", config.Username.Value }, + { "password", config.Password.Value } + }; - var content = new FormUrlEncodedContent(pairs); - var message = CreateHttpRequest(new Uri(LoginPostUrl)); - message.Method = HttpMethod.Post; - message.Content = content; - message.Headers.Referrer = new Uri(LoginUrl); + var content = new FormUrlEncodedContent (pairs); + var message = CreateHttpRequest (new Uri (LoginPostUrl)); + message.Method = HttpMethod.Post; + message.Content = content; + message.Headers.Referrer = new Uri (LoginUrl); - var response = await client.SendAsync(message); - var responseContent = await response.Content.ReadAsStringAsync(); + var response = await client.SendAsync (message); + var responseContent = await response.Content.ReadAsStringAsync (); - if (!responseContent.Contains("/logout.php")) - { - CQ dom = responseContent; - var messageEl = dom[".error_text"]; - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); - } - else - { - var configSaveData = new JObject(); - configSaveData["cookies"] = new JArray(( - from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() - select cookie.Name + ":" + cookie.Value - ).ToArray()); + if (!responseContent.Contains ("/logout.php")) { + CQ dom = responseContent; + var messageEl = dom [".error_text"]; + var errorMessage = messageEl.Text ().Trim (); + throw new ExceptionWithConfigData (errorMessage, (ConfigurationData)config); + } else { + var configSaveData = new JObject (); + configSaveData ["cookies"] = cookies.ToJson (SiteLink); - if (OnSaveConfigurationRequested != null) - OnSaveConfigurationRequested(this, configSaveData); + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested (this, configSaveData); - IsConfigured = true; - } - } + IsConfigured = true; + } + } - public void LoadFromSavedConfiguration(JToken jsonConfig) - { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); - IsConfigured = true; - } + public void LoadFromSavedConfiguration (JToken jsonConfig) + { + cookies.FillFromJson (new Uri (BaseUrl), (JArray)jsonConfig ["cookies"]); + IsConfigured = true; + } - HttpRequestMessage CreateHttpRequest(Uri uri) - { - var message = new HttpRequestMessage(); - message.Method = HttpMethod.Get; - message.RequestUri = uri; - message.Headers.UserAgent.ParseAdd(chromeUserAgent); - return message; - } + HttpRequestMessage CreateHttpRequest (Uri uri) + { + var message = new HttpRequestMessage (); + message.Method = HttpMethod.Get; + message.RequestUri = uri; + message.Headers.UserAgent.ParseAdd (chromeUserAgent); + return message; + } - public async Task PerformQuery(TorznabQuery query) - { - List releases = new List(); + public async Task PerformQuery (TorznabQuery query) + { + List releases = new List (); - foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) - { - string episodeSearchUrl; + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) { + string episodeSearchUrl; - if (string.IsNullOrEmpty(title)) - episodeSearchUrl = SearchUrl; - else - { - var searchString = title + " " + query.GetEpisodeSearchString(); - episodeSearchUrl = string.Format("{0}?search={1}&cat=0", SearchUrl, HttpUtility.UrlEncode(searchString)); - } + if (string.IsNullOrEmpty (title)) + episodeSearchUrl = SearchUrl; + else { + var searchString = title + " " + query.GetEpisodeSearchString (); + episodeSearchUrl = string.Format ("{0}?search={1}&cat=0", SearchUrl, HttpUtility.UrlEncode (searchString)); + } - var request = CreateHttpRequest(new Uri(episodeSearchUrl)); - var response = await client.SendAsync(request); - var results = await response.Content.ReadAsStringAsync(); + var request = CreateHttpRequest (new Uri (episodeSearchUrl)); + var response = await client.SendAsync (request); + var results = await response.Content.ReadAsStringAsync (); - CQ dom = results; + CQ dom = results; - var rows = dom["#highlight > tbody > tr"]; + var rows = dom ["#highlight > tbody > tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); + foreach (var row in rows.Skip(1)) { + var release = new ReleaseInfo (); - var qRow = row.Cq(); - var qLink = qRow.Find("a.torrent_name_link").First(); + var qRow = row.Cq (); + var qLink = qRow.Find ("a.torrent_name_link").First (); - release.MinimumRatio = 1; - release.MinimumSeedTime = 172800; - release.Title = qLink.Attr("title"); - release.Description = release.Title; - release.Guid = new Uri(BaseUrl + qLink.Attr("href")); - release.Comments = release.Guid; - release.Link = new Uri(BaseUrl + qRow.Find("td.table_links > a").First().Attr("href")); + release.MinimumRatio = 1; + release.MinimumSeedTime = 172800; + release.Title = qLink.Attr ("title"); + release.Description = release.Title; + release.Guid = new Uri (BaseUrl + qLink.Attr ("href")); + release.Comments = release.Guid; + release.Link = new Uri (BaseUrl + qRow.Find ("td.table_links > a").First ().Attr ("href")); - DateTime pubDate; - var dateString = qRow.Find("td.table_added").Text().Trim(); - if (dateString.StartsWith("Today ")) - pubDate = (DateTime.UtcNow + TimeSpan.Parse(dateString.Split(' ')[1])).ToLocalTime(); - else if (dateString.StartsWith("Yesterday ")) - pubDate = (DateTime.UtcNow + TimeSpan.Parse(dateString.Split(' ')[1]) - TimeSpan.FromDays(1)).ToLocalTime(); - else - pubDate = DateTime.ParseExact(dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); - release.PublishDate = pubDate; + DateTime pubDate; + var dateString = qRow.Find ("td.table_added").Text ().Trim (); + if (dateString.StartsWith ("Today ")) + pubDate = (DateTime.UtcNow + TimeSpan.Parse (dateString.Split (' ') [1])).ToLocalTime (); + else if (dateString.StartsWith ("Yesterday ")) + pubDate = (DateTime.UtcNow + TimeSpan.Parse (dateString.Split (' ') [1]) - TimeSpan.FromDays (1)).ToLocalTime (); + else + pubDate = DateTime.ParseExact (dateString, "d-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime (); + release.PublishDate = pubDate; - release.Seeders = int.Parse(qRow.Find("td.table_seeders").Text().Trim()); - release.Peers = int.Parse(qRow.Find("td.table_leechers").Text().Trim()) + release.Seeders; + release.Seeders = int.Parse (qRow.Find ("td.table_seeders").Text ().Trim ()); + release.Peers = int.Parse (qRow.Find ("td.table_leechers").Text ().Trim ()) + release.Seeders; - var sizeCol = qRow.Find("td.table_size")[0]; - var sizeVal = float.Parse(sizeCol.ChildNodes[0].NodeValue.Trim()); - var sizeUnit = sizeCol.ChildNodes[2].NodeValue.Trim(); - release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); + var sizeCol = qRow.Find ("td.table_size") [0]; + var sizeVal = float.Parse (sizeCol.ChildNodes [0].NodeValue.Trim ()); + var sizeUnit = sizeCol.ChildNodes [2].NodeValue.Trim (); + release.Size = ReleaseInfo.GetBytes (sizeUnit, sizeVal); - releases.Add(release); - } - } + releases.Add (release); + } + } - return releases.ToArray(); - } + return releases.ToArray (); + } - public async Task Download(Uri link) - { - var request = CreateHttpRequest(link); - var response = await client.SendAsync(request); - var bytes = await response.Content.ReadAsByteArrayAsync(); - return bytes; - } - } + public async Task Download (Uri link) + { + var request = CreateHttpRequest (link); + var response = await client.SendAsync (request); + var bytes = await response.Content.ReadAsByteArrayAsync (); + return bytes; + } + } } diff --git a/src/Jackett/Indexers/IPTorrents.cs b/src/Jackett/Indexers/IPTorrents.cs index 2636a379e..5de4080ee 100644 --- a/src/Jackett/Indexers/IPTorrents.cs +++ b/src/Jackett/Indexers/IPTorrents.cs @@ -11,191 +11,181 @@ using System.Web; namespace Jackett.Indexers { - public class IPTorrents : IndexerInterface - { + public class IPTorrents : IndexerInterface + { - public event Action OnSaveConfigurationRequested; + public event Action OnSaveConfigurationRequested; - public string DisplayName { get { return "IPTorrents"; } } + public string DisplayName { get { return "IPTorrents"; } } - public string DisplayDescription { get { return "Always a step ahead"; } } + public string DisplayDescription { get { return "Always a step ahead"; } } - public Uri SiteLink { get { return new Uri(BaseUrl); } } + public Uri SiteLink { get { return new Uri (BaseUrl); } } - public bool IsConfigured { get; private set; } + public bool IsConfigured { get; private set; } - static string chromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; + static string chromeUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; - static string BaseUrl = "https://iptorrents.com"; + static string BaseUrl = "https://iptorrents.com"; - string SearchUrl = BaseUrl + "/t?q="; + string SearchUrl = BaseUrl + "/t?q="; - CookieContainer cookies; - HttpClientHandler handler; - HttpClient client; + CookieContainer cookies; + HttpClientHandler handler; + HttpClient client; - public IPTorrents() - { - IsConfigured = false; - cookies = new CookieContainer(); - handler = new HttpClientHandler - { - CookieContainer = cookies, - AllowAutoRedirect = true, - UseCookies = true, - }; - client = new HttpClient(handler); - } + public IPTorrents () + { + IsConfigured = false; + cookies = new CookieContainer (); + handler = new HttpClientHandler { + CookieContainer = cookies, + AllowAutoRedirect = true, + UseCookies = true, + }; + client = new HttpClient (handler); + } - public async Task GetConfigurationForSetup() - { - await client.GetAsync(new Uri(BaseUrl)); - var config = new ConfigurationDataBasicLogin(); - return (ConfigurationData)config; - } + public async Task GetConfigurationForSetup () + { + await client.GetAsync (new Uri (BaseUrl)); + var config = new ConfigurationDataBasicLogin (); + return (ConfigurationData)config; + } - public async Task ApplyConfiguration(JToken configJson) - { + public async Task ApplyConfiguration (JToken configJson) + { - var config = new ConfigurationDataBasicLogin(); - config.LoadValuesFromJson(configJson); + var config = new ConfigurationDataBasicLogin (); + config.LoadValuesFromJson (configJson); - var pairs = new Dictionary - { - { "username", config.Username.Value}, - { "password", config.Password.Value} - }; + var pairs = new Dictionary { + { "username", config.Username.Value }, + { "password", config.Password.Value } + }; - var content = new FormUrlEncodedContent(pairs); - var message = new HttpRequestMessage(); - message.Method = HttpMethod.Post; - message.Content = content; - message.RequestUri = new Uri(BaseUrl); - message.Headers.Referrer = new Uri(BaseUrl); - message.Headers.UserAgent.ParseAdd(chromeUserAgent); + var content = new FormUrlEncodedContent (pairs); + var message = new HttpRequestMessage (); + message.Method = HttpMethod.Post; + message.Content = content; + message.RequestUri = new Uri (BaseUrl); + message.Headers.Referrer = new Uri (BaseUrl); + message.Headers.UserAgent.ParseAdd (chromeUserAgent); - var response = await client.SendAsync(message); - var responseContent = await response.Content.ReadAsStringAsync(); + var response = await client.SendAsync (message); + var responseContent = await response.Content.ReadAsStringAsync (); - if (!responseContent.Contains("/my.php")) - { - CQ dom = responseContent; - var messageEl = dom["body > div"].First(); - var errorMessage = messageEl.Text().Trim(); - throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); - } - else - { - var configSaveData = new JObject(); - configSaveData["cookies"] = new JArray(( - from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() - select cookie.Name + ":" + cookie.Value - ).ToArray()); + if (!responseContent.Contains ("/my.php")) { + CQ dom = responseContent; + var messageEl = dom ["body > div"].First (); + var errorMessage = messageEl.Text ().Trim (); + throw new ExceptionWithConfigData (errorMessage, (ConfigurationData)config); + } else { + var configSaveData = new JObject (); + configSaveData ["cookies"] = cookies.ToJson (SiteLink); - if (OnSaveConfigurationRequested != null) - OnSaveConfigurationRequested(this, configSaveData); + if (OnSaveConfigurationRequested != null) + OnSaveConfigurationRequested (this, configSaveData); - IsConfigured = true; - } + IsConfigured = true; + } - } + } - HttpRequestMessage CreateHttpRequest(Uri uri) - { - var message = new HttpRequestMessage(); - message.Method = HttpMethod.Get; - message.RequestUri = uri; - message.Headers.UserAgent.ParseAdd(chromeUserAgent); - return message; - } + HttpRequestMessage CreateHttpRequest (Uri uri) + { + var message = new HttpRequestMessage (); + message.Method = HttpMethod.Get; + message.RequestUri = uri; + message.Headers.UserAgent.ParseAdd (chromeUserAgent); + return message; + } - public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) - { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); - IsConfigured = true; - } + public void LoadFromSavedConfiguration (Newtonsoft.Json.Linq.JToken jsonConfig) + { + cookies.FillFromJson (new Uri (BaseUrl), (JArray)jsonConfig ["cookies"]); + IsConfigured = true; + } - public async Task PerformQuery(TorznabQuery query) - { + public async Task PerformQuery (TorznabQuery query) + { - List releases = new List(); + List releases = new List (); - foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) - { + foreach (var title in query.ShowTitles ?? new string[] { string.Empty }) { - var searchString = title + " " + query.GetEpisodeSearchString(); - var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); + var searchString = title + " " + query.GetEpisodeSearchString (); + var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode (searchString); - var request = CreateHttpRequest(new Uri(episodeSearchUrl)); - var response = await client.SendAsync(request); - var results = await response.Content.ReadAsStringAsync(); + var request = CreateHttpRequest (new Uri (episodeSearchUrl)); + var response = await client.SendAsync (request); + var results = await response.Content.ReadAsStringAsync (); - CQ dom = results; + CQ dom = results; - var rows = dom["table.torrents > tbody > tr"]; - foreach (var row in rows.Skip(1)) - { - var release = new ReleaseInfo(); + var rows = dom ["table.torrents > tbody > tr"]; + foreach (var row in rows.Skip(1)) { + var release = new ReleaseInfo (); - var qRow = row.Cq(); + var qRow = row.Cq (); - var qTitleLink = qRow.Find("a.t_title").First(); - release.Title = qTitleLink.Text().Trim(); - release.Description = release.Title; - release.Guid = new Uri(BaseUrl + qTitleLink.Attr("href")); - release.Comments = release.Guid; + var qTitleLink = qRow.Find ("a.t_title").First (); + release.Title = qTitleLink.Text ().Trim (); + release.Description = release.Title; + release.Guid = new Uri (BaseUrl + qTitleLink.Attr ("href")); + release.Comments = release.Guid; - DateTime pubDate; - var descString = qRow.Find(".t_ctime").Text(); - var dateString = descString.Split('|').Last().Trim(); - dateString = dateString.Split(new string[] { " by " }, StringSplitOptions.None)[0]; - var dateValue = float.Parse(dateString.Split(' ')[0]); - var dateUnit = dateString.Split(' ')[1]; - if (dateUnit.Contains("minute")) - pubDate = DateTime.Now - TimeSpan.FromMinutes(dateValue); - else if (dateUnit.Contains("hour")) - pubDate = DateTime.Now - TimeSpan.FromHours(dateValue); - else if (dateUnit.Contains("day")) - pubDate = DateTime.Now - TimeSpan.FromDays(dateValue); - else if (dateUnit.Contains("week")) - pubDate = DateTime.Now - TimeSpan.FromDays(7 * dateValue); - else if (dateUnit.Contains("month")) - pubDate = DateTime.Now - TimeSpan.FromDays(30 * dateValue); - else if (dateUnit.Contains("year")) - pubDate = DateTime.Now - TimeSpan.FromDays(365 * dateValue); - else - pubDate = DateTime.MinValue; - release.PublishDate = pubDate; + DateTime pubDate; + var descString = qRow.Find (".t_ctime").Text (); + var dateString = descString.Split ('|').Last ().Trim (); + dateString = dateString.Split (new string[] { " by " }, StringSplitOptions.None) [0]; + var dateValue = float.Parse (dateString.Split (' ') [0]); + var dateUnit = dateString.Split (' ') [1]; + if (dateUnit.Contains ("minute")) + pubDate = DateTime.Now - TimeSpan.FromMinutes (dateValue); + else if (dateUnit.Contains ("hour")) + pubDate = DateTime.Now - TimeSpan.FromHours (dateValue); + else if (dateUnit.Contains ("day")) + pubDate = DateTime.Now - TimeSpan.FromDays (dateValue); + else if (dateUnit.Contains ("week")) + pubDate = DateTime.Now - TimeSpan.FromDays (7 * dateValue); + else if (dateUnit.Contains ("month")) + pubDate = DateTime.Now - TimeSpan.FromDays (30 * dateValue); + else if (dateUnit.Contains ("year")) + pubDate = DateTime.Now - TimeSpan.FromDays (365 * dateValue); + else + pubDate = DateTime.MinValue; + release.PublishDate = pubDate; - var qLink = row.ChildElements.ElementAt(3).Cq().Children("a"); - release.Link = new Uri(BaseUrl + qLink.Attr("href")); + var qLink = row.ChildElements.ElementAt (3).Cq ().Children ("a"); + release.Link = new Uri (BaseUrl + qLink.Attr ("href")); - var sizeStr = row.ChildElements.ElementAt(5).Cq().Text().Trim(); - var sizeVal = float.Parse(sizeStr.Split(' ')[0]); - var sizeUnit = sizeStr.Split(' ')[1]; - release.Size = ReleaseInfo.GetBytes(sizeUnit, sizeVal); + var sizeStr = row.ChildElements.ElementAt (5).Cq ().Text ().Trim (); + var sizeVal = float.Parse (sizeStr.Split (' ') [0]); + var sizeUnit = sizeStr.Split (' ') [1]; + release.Size = ReleaseInfo.GetBytes (sizeUnit, sizeVal); - release.Seeders = int.Parse(qRow.Find(".t_seeders").Text().Trim()); - release.Peers = int.Parse(qRow.Find(".t_leechers").Text().Trim()) + release.Seeders; + release.Seeders = int.Parse (qRow.Find (".t_seeders").Text ().Trim ()); + release.Peers = int.Parse (qRow.Find (".t_leechers").Text ().Trim ()) + release.Seeders; - releases.Add(release); - } + releases.Add (release); + } - } + } - return releases.ToArray(); + return releases.ToArray (); - } + } - public async Task Download(Uri link) - { - var request = CreateHttpRequest(link); - var response = await client.SendAsync(request); - var bytes = await response.Content.ReadAsByteArrayAsync(); - return bytes; - } - } + public async Task Download (Uri link) + { + var request = CreateHttpRequest (link); + var response = await client.SendAsync (request); + var bytes = await response.Content.ReadAsByteArrayAsync (); + return bytes; + } + } } diff --git a/src/Jackett/Indexers/MoreThanTV.cs b/src/Jackett/Indexers/MoreThanTV.cs index c07397c08..ddccf772b 100644 --- a/src/Jackett/Indexers/MoreThanTV.cs +++ b/src/Jackett/Indexers/MoreThanTV.cs @@ -47,6 +47,8 @@ namespace Jackett.Indexers HttpClientHandler handler; HttpClient client; + string cookieHeader; + public MoreThanTV() { IsConfigured = false; @@ -68,22 +70,36 @@ namespace Jackett.Indexers public async Task ApplyConfiguration(JToken configJson) { - var config = new ConfigurationDataBasicLogin(); config.LoadValuesFromJson(configJson); - var pairs = new Dictionary - { - { "username", config.Username.Value}, - { "password", config.Password.Value}, - { "login", "Log in" }, - { "keeplogged", "1" } - }; + var pairs = new Dictionary { + { "username", config.Username.Value }, + { "password", config.Password.Value }, + { "login", "Log in" }, + { "keeplogged", "1" } + }; var content = new FormUrlEncodedContent(pairs); - var response = await client.PostAsync(LoginUrl, content); - var responseContent = await response.Content.ReadAsStringAsync(); + string responseContent; + JArray cookieJArray; + + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + // If Windows use .net http + var response = await client.PostAsync(LoginUrl, content); + responseContent = await response.Content.ReadAsStringAsync(); + cookieJArray = cookies.ToJson(SiteLink); + } + else + { + // If UNIX system use curl + var response = await CurlHelper.Shared.PostAsync(LoginUrl, pairs); + responseContent = Encoding.UTF8.GetString(response.Content); + cookieHeader = response.CookieHeader; + cookieJArray = new JArray(response.CookiesFlat); + } if (!responseContent.Contains("logout.php?")) { @@ -91,15 +107,13 @@ namespace Jackett.Indexers dom["#loginform > table"].Remove(); var errorMessage = dom["#loginform"].Text().Trim().Replace("\n\t", " "); throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config); + } else { - var configSaveData = new JObject(); - configSaveData["cookies"] = new JArray(( - from cookie in cookies.GetCookies(new Uri(BaseUrl)).Cast() - select cookie.Name + ":" + cookie.Value - ).ToArray()); + var configSaveData = new JObject(); + configSaveData["cookies"] = cookieJArray; if (OnSaveConfigurationRequested != null) OnSaveConfigurationRequested(this, configSaveData); @@ -107,9 +121,10 @@ namespace Jackett.Indexers } } - public void LoadFromSavedConfiguration(Newtonsoft.Json.Linq.JToken jsonConfig) + public void LoadFromSavedConfiguration(JToken jsonConfig) { - cookies.FillFromJson(new Uri(BaseUrl), (JArray)jsonConfig["cookies"]); + cookies.FillFromJson(SiteLink, (JArray)jsonConfig["cookies"]); + cookieHeader = cookies.GetCookieHeader(SiteLink); IsConfigured = true; } @@ -133,7 +148,18 @@ namespace Jackett.Indexers var searchString = title + " " + query.GetEpisodeSearchString(); var episodeSearchUrl = SearchUrl + HttpUtility.UrlEncode(searchString); - var results = await client.GetStringAsync(episodeSearchUrl); + + string results; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + results = await client.GetStringAsync(episodeSearchUrl); + } + else + { + var response = await CurlHelper.Shared.GetAsync(episodeSearchUrl, cookieHeader); + results = Encoding.UTF8.GetString(response.Content); + } + var json = JObject.Parse(results); foreach (JObject r in json["response"]["results"]) { @@ -176,9 +202,18 @@ namespace Jackett.Indexers return new DateTime(unixStart.Ticks + unixTimeStampInTicks); } - public Task Download(Uri link) + public async Task Download(Uri link) { - return client.GetByteArrayAsync(link); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + return await client.GetByteArrayAsync(link); + } + else + { + var response = await CurlHelper.Shared.GetAsync(link.ToString(), cookieHeader); + return response.Content; + } + } } } diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index c6d358b05..defff711b 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -1,5 +1,5 @@  - + Debug @@ -60,10 +60,6 @@ ..\packages\modernhttpclient.2.3.0\lib\Portable-Net45+WinRT45+WP8+WPA81\ModernHttpClient.dll - - False - ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.3.2.0.0\lib\net45\NLog.dll @@ -79,6 +75,9 @@ + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + @@ -116,6 +115,7 @@ + @@ -203,7 +203,12 @@ - + + + {74420A79-CC16-442C-8B1E-7C1B913844F0} + CurlSharp + + False diff --git a/src/Jackett/Program.cs b/src/Jackett/Program.cs index 0008b3249..bffac90ea 100644 --- a/src/Jackett/Program.cs +++ b/src/Jackett/Program.cs @@ -14,93 +14,84 @@ using System.Windows.Forms; namespace Jackett { - class Program - { - public static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); + class Program + { + public static string AppConfigDirectory = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), "Jackett"); - public static Server ServerInstance { get; private set; } + public static Server ServerInstance { get; private set; } - public static bool IsFirstRun { get; private set; } + public static bool IsFirstRun { get; private set; } - public static Logger LoggerInstance { get; private set; } + public static Logger LoggerInstance { get; private set; } - public static ManualResetEvent ExitEvent { get; private set; } + public static ManualResetEvent ExitEvent { get; private set; } - static void Main(string[] args) - { - ExitEvent = new ManualResetEvent(false); + static void Main (string[] args) + { + ExitEvent = new ManualResetEvent (false); - try - { - if (!Directory.Exists(AppConfigDirectory)) - { - IsFirstRun = true; - Directory.CreateDirectory(AppConfigDirectory); - } - Console.WriteLine("App config/log directory: " + AppConfigDirectory); - } - catch (Exception ex) - { - MessageBox.Show("Could not create settings directory."); - Application.Exit(); - return; - } + try { + if (!Directory.Exists (AppConfigDirectory)) { + IsFirstRun = true; + Directory.CreateDirectory (AppConfigDirectory); + } + Console.WriteLine ("App config/log directory: " + AppConfigDirectory); + } catch (Exception ex) { + MessageBox.Show ("Could not create settings directory."); + Application.Exit (); + return; + } - var logConfig = new LoggingConfiguration(); + var logConfig = new LoggingConfiguration (); - var logFile = new FileTarget(); - logConfig.AddTarget("file", logFile); - logFile.FileName = Path.Combine(AppConfigDirectory, "log.txt"); - logFile.Layout = "${longdate} ${level} ${message} \n ${exception:format=ToString}\n"; - var logFileRule = new LoggingRule("*", LogLevel.Debug, logFile); - logConfig.LoggingRules.Add(logFileRule); + var logFile = new FileTarget (); + logConfig.AddTarget ("file", logFile); + logFile.FileName = Path.Combine (AppConfigDirectory, "log.txt"); + logFile.Layout = "${longdate} ${level} ${message} \n ${exception:format=ToString}\n"; + var logFileRule = new LoggingRule ("*", LogLevel.Debug, logFile); + logConfig.LoggingRules.Add (logFileRule); - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - var logAlert = new MessageBoxTarget(); - logConfig.AddTarget("alert", logAlert); - logAlert.Layout = "${message}"; - logAlert.Caption = "Alert"; - var logAlertRule = new LoggingRule("*", LogLevel.Fatal, logAlert); - logConfig.LoggingRules.Add(logAlertRule); - } + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + var logAlert = new MessageBoxTarget (); + logConfig.AddTarget ("alert", logAlert); + logAlert.Layout = "${message}"; + logAlert.Caption = "Alert"; + var logAlertRule = new LoggingRule ("*", LogLevel.Fatal, logAlert); + logConfig.LoggingRules.Add (logAlertRule); + } - var logConsole = new ConsoleTarget(); - logConfig.AddTarget("console", logConsole); - logConsole.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; - var logConsoleRule = new LoggingRule("*", LogLevel.Debug, logConsole); - logConfig.LoggingRules.Add(logConsoleRule); + var logConsole = new ConsoleTarget (); + logConfig.AddTarget ("console", logConsole); + logConsole.Layout = "${longdate} ${level} ${message} ${exception:format=ToString}"; + var logConsoleRule = new LoggingRule ("*", LogLevel.Debug, logConsole); + logConfig.LoggingRules.Add (logConsoleRule); - LogManager.Configuration = logConfig; - LoggerInstance = LogManager.GetCurrentClassLogger(); + LogManager.Configuration = logConfig; + LoggerInstance = LogManager.GetCurrentClassLogger (); - var serverTask = Task.Run(async () => - { - ServerInstance = new Server(); - await ServerInstance.Start(); - }); + var serverTask = Task.Run (async () => { + ServerInstance = new Server (); + await ServerInstance.Start (); + }); - try - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - Application.Run(new Main()); - } - catch (Exception ex) - { + try { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + Application.Run (new Main ()); + } catch (Exception ex) { - } + } - Console.WriteLine("Running in headless mode."); + Console.WriteLine ("Running in headless mode."); - Task.WaitAll(serverTask); - Console.WriteLine("Server thread exit"); - } + Task.WaitAll (serverTask); + Console.WriteLine ("Server thread exit"); + } - static public void RestartAsAdmin() - { - var startInfo = new ProcessStartInfo(Application.ExecutablePath.ToString()) { Verb = "runas" }; - Process.Start(startInfo); - Environment.Exit(0); - } - } + static public void RestartAsAdmin () + { + var startInfo = new ProcessStartInfo (Application.ExecutablePath.ToString ()) { Verb = "runas" }; + Process.Start (startInfo); + Environment.Exit (0); + } + } } diff --git a/src/Jackett/Server.cs b/src/Jackett/Server.cs index dc0e28a78..101d4d374 100644 --- a/src/Jackett/Server.cs +++ b/src/Jackett/Server.cs @@ -60,26 +60,26 @@ namespace Jackett } catch (HttpListenerException ex) { - var errorStr = "App must be ran as Admin for permission to use port " - + Port + Environment.NewLine - + "Restart app with admin privileges?"; - - Program.LoggerInstance.FatalException("Failed to start HTTP server", ex); - - if (Environment.OSVersion.Platform == PlatformID.Win32NT) + if (ex.ErrorCode == 5) { - var dialogResult = MessageBox.Show(errorStr, "Error", MessageBoxButtons.YesNo); - if (dialogResult == DialogResult.No) + var errorStr = "App must be ran as admin for permission to use port " + + Port + Environment.NewLine + "Restart app with admin privileges?"; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - Program.LoggerInstance.FatalException("App must be ran as Admin for permission to use port " + Port, ex); - Application.Exit(); - return; - } - else - { - Program.RestartAsAdmin(); + var dialogResult = MessageBox.Show(errorStr, "Error", MessageBoxButtons.YesNo); + if (dialogResult == DialogResult.No) + { + Application.Exit(); + return; + } + else + { + Program.RestartAsAdmin(); + } } } + else + Program.LoggerInstance.FatalException("Failed to start HTTP server. " + ex.Message, ex); } catch (Exception ex) { @@ -95,7 +95,9 @@ namespace Jackett Process.Start("http://127.0.0.1:" + Port); #endif } - catch (Exception) { } + catch (Exception) + { + } while (true) { @@ -152,14 +154,18 @@ namespace Jackett var errorBytes = Encoding.UTF8.GetBytes(exception.Message); await context.Response.OutputStream.WriteAsync(errorBytes, 0, errorBytes.Length); } - catch (Exception) { } + catch (Exception) + { + } } try { context.Response.Close(); } - catch (Exception) { } + catch (Exception) + { + } }