# # # Windows native FTP/HTTP/HTTPS file downloader # (c) Copyright 2017 Eugene Kabanov # # See the file "LICENSE", included in this # distribution, for details about the copyright. # ## This module implements native Windows FTP/HTTP/HTTPS downloading feature, ## using ``urlmon.UrlDownloadToFile()``. ## ## when not (defined(windows) or defined(nimdoc)): {.error: "Platform is not supported.".} import os type DownloadOptions* = enum ## Available download options optUseCache, ## Use Windows cache. optUseProgressCallback, ## Report progress via callback. optIgnoreSecurity ## Ignore HTTPS security problems. DownloadStatus* = enum ## Available download status sent to ``progress`` callback. statusProxyDetecting, ## Automatic Proxy detection. statusCookieSent ## Cookie will be sent with request. statusResolving, ## Resolving URL with DNS. statusConnecting, ## Establish connection to server. statusRedirecting ## HTTP redirection pending. statusRequesting, ## Sending request to server. statusMimetypeAvailable, ## Mimetype received from server. statusBeginDownloading, ## Download process starting. statusDownloading, ## Download process pending. statusEndDownloading, ## Download process finished. statusCacheAvailable ## File found in Windows cache. statusUnsupported ## Unsupported status. statusError ## Error happens. DownloadProgressCallback* = proc(status: DownloadStatus, progress: uint, progressMax: uint, message: string) ## Progress callback. ## ## status ## Indicate current stage of downloading process. ## ## progress ## Number of bytes currently downloaded. Available only, if ``status`` is ## ``statusBeginDownloading``, ``statusDownloading`` or ## ``statusEndDownloading``. ## ## progressMax ## Number of bytes expected to download. Available only, if ``status`` is ## ``statusBeginDownloading``, ``statusDownloading`` or ## ``statusEndDownloading``. ## ## message ## Status message, which depends on ``status`` code. ## ## Available messages' values: ## ## statusResolving ## URL hostname to be resolved. ## statusConnecting ## IP address ## statusMimetypeAvailable ## Downloading resource MIME type. ## statusCacheAvailable ## Path to filename stored in Windows cache. type UUID = array[4, uint32] LONG = clong ULONG = culong HRESULT = clong DWORD = uint32 OLECHAR = uint16 OLESTR = ptr OLECHAR LPWSTR = OLESTR UINT = cuint REFIID = ptr UUID const E_NOINTERFACE = 0x80004002'i32 E_NOTIMPL = 0x80004001'i32 S_OK = 0x00000000'i32 CP_UTF8 = 65001'u32 IID_IUnknown = UUID([0'u32, 0'u32, 192'u32, 1174405120'u32]) IID_IBindStatusCallback = UUID([2045430209'u32, 298760953'u32, 2852160140'u32, 195644160'u32]) BINDF_GETNEWESTVERSION = 0x00000010'u32 BINDF_IGNORESECURITYPROBLEM = 0x00000100'u32 BINDF_RESYNCHRONIZE = 0x00000200'u32 BINDF_NO_UI = 0x00000800'u32 BINDF_SILENTOPERATION = 0x00001000'u32 BINDF_PRAGMA_NO_CACHE = 0x00002000'u32 ERROR_FILE_NOT_FOUND = 2 ERROR_ACCESS_DENIED = 5 BINDSTATUS_FINDINGRESOURCE = 1 BINDSTATUS_CONNECTING = 2 BINDSTATUS_REDIRECTING = 3 BINDSTATUS_BEGINDOWNLOADDATA = 4 BINDSTATUS_DOWNLOADINGDATA = 5 BINDSTATUS_ENDDOWNLOADDATA = 6 BINDSTATUS_SENDINGREQUEST = 11 BINDSTATUS_MIMETYPEAVAILABLE = 13 BINDSTATUS_CACHEFILENAMEAVAILABLE = 14 BINDSTATUS_PROXYDETECTING = 32 BINDSTATUS_COOKIE_SENT = 34 type STGMEDIUM = object tymed: DWORD pstg: pointer pUnkForRelease: pointer SECURITY_ATTRIBUTES = object nLength*: uint32 lpSecurityDescriptor*: pointer bInheritHandle*: int32 BINDINFO = object cbSize: ULONG stgmedData: STGMEDIUM szExtraInfo: LPWSTR grfBindInfoF: DWORD dwBindVerb: DWORD szCustomVerb: LPWSTR cbstgmedData: DWORD dwOptions: DWORD dwOptionsFlags: DWORD dwCodePage: DWORD securityAttributes: SECURITY_ATTRIBUTES iid: UUID pUnk: pointer dwReserved: DWORD IBindStatusCallback = object vtable: ptr IBindStatusCallbackVTable options: set[DownloadOptions] objectRefCount: ULONG binfoFlags: DWORD progressCallback: DownloadProgressCallback PIBindStatusCallback = ptr IBindStatusCallback LPBINDSTATUSCALLBACK = PIBindStatusCallback IBindStatusCallbackVTable = object QueryInterface: proc (self: PIBindStatusCallback, riid: ptr UUID, pvObject: ptr pointer): HRESULT {.gcsafe,stdcall.} AddRef: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} Release: proc(self: PIBindStatusCallback): ULONG {.gcsafe, stdcall.} OnStartBinding: proc(self: PIBindStatusCallback, dwReserved: DWORD, pib: pointer): HRESULT {.gcsafe, stdcall.} GetPriority: proc(self: PIBindStatusCallback, pnPriority: ptr LONG): HRESULT {.gcsafe, stdcall.} OnLowResource: proc(self: PIBindStatusCallback, dwReserved: DWORD): HRESULT {.gcsafe, stdcall.} OnProgress: proc(self: PIBindStatusCallback, ulProgress: ULONG, ulProgressMax: ULONG, ulStatusCode: ULONG, szStatusText: LPWSTR): HRESULT {.gcsafe, stdcall.} OnStopBinding: proc(self: PIBindStatusCallback, hresult: HRESULT, szError: LPWSTR): HRESULT {.gcsafe, stdcall.} GetBindInfo: proc(self: PIBindStatusCallback, grfBINDF: ptr DWORD, pbindinfo: p
discard """
  errormsg: "cannot use symbol of kind 'var' as a 'param'"
  line: 20
"""

# bug #3158

type
  MyData = object
      x: int

template newDataWindow(data: ref MyData): untyped =
    proc testProc(data: ref MyData) =
        echo "Hello, ", data.x
    testProc(data)

var d: ref MyData
new(d)
d.x = 10
newDataWindow(d)
BINDF_PRAGMA_NO_CACHE or BINDF_NO_UI or BINDF_SILENTOPERATION if optIgnoreSecurity in options: bstatus.binfoFlags = bstatus.binfoFlags or BINDF_IGNORESECURITYPROBLEM if not isNil(progresscb): bstatus.options.incl(optUseProgressCallback) bstatus.progressCallback = progresscb let res = URLDownloadToFile(nil, bszUrl, bszFile, 0, addr bstatus) if FAILED(res): freeBindStatusCallback(bstatus) freeBstring(bszUrl) freeBstring(bszFile) raiseOsError(OSErrorCode(res)) freeBindStatusCallback(bstatus) freeBstring(bszUrl) freeBstring(bszFile) when isMainModule: proc progress(status: DownloadStatus, progress: uint, progressMax: uint, message: string) {.procvar,gcsafe.} = const downset: set[DownloadStatus] = {statusBeginDownloading, statusDownloading, statusEndDownloading} if status in downset: var message = "Downloaded " & $progress & " of " & $progressMax & "\c" stdout.write(message) else: echo "Status [" & $status & "] message = [" & $message & "]" downloadToFile("https://nim-lang.org/download/mingw64-6.3.0.7z", "test.zip", {optUseCache}, progress)