Search code examples
urlftpautohotkey

Valid URL for an FTP site with username containing @


I want to create a valid URL to send to Windows File Explorer (or other file managers like TotalCommander) using the format:

ftp://username:[email protected]/folder/

In Explorer, it works with very straight username and password. But I receive errors (or Explorer just display the My Document instead of the FTP site) when password contains certain special characters. I played with URI encoding to encode the password with some success but not 100% reliable.

Can someone help me finding the correct requirements for a valid FTP URL including username and password? Thanks.

Here is a sample of the code using AutoHotkey "Run" command (on Windows 7 64-bit environment):

#NoEnv
#SingleInstance force

strFTPUrl := "ftp://www.jeanlalonde.ca"

strLoginName := "[email protected]"
strPassword := "********"

StringReplace, strFTPUrl, strFTPUrl, % "ftp://", % "ftp://" . strLoginName . ":" . UriEncode(strPassword) . "@"

; Before: ftp://ftp.jeanlalonde.ca
; After: ftp://[email protected]:********@ftp.jeanlalonde.ca
MsgBox, %strFTPUrl%

Run, Explorer "%strFTPUrl%"

return


;------------------------------------------------------------
UriEncode(str)
; from GoogleTranslate by Mikhail Kuropyatnikov
; http://www.autohotkey.net/~sumon/GoogleTranslate.ahk
;------------------------------------------------------------
{ 
   b_Format := A_FormatInteger 
   data := "" 
   SetFormat,Integer,H 
   SizeInBytes := StrPutVar(str,var,"utf-8")
   Loop, %SizeInBytes%
   {
   ch := NumGet(var,A_Index-1,"UChar")
   If (ch=0)
      Break
   if ((ch>0x7f) || (ch<0x30) || (ch=0x3d))
      s .= "%" . ((StrLen(c:=SubStr(ch,3))<2) ? "0" . c : c)
   Else
      s .= Chr(ch)
   }   
   SetFormat,Integer,%b_format% 
   return s 
} 
;------------------------------------------------------------


;------------------------------------------------------------
StrPutVar(string, ByRef var, encoding)
;------------------------------------------------------------
{
    ; Ensure capacity.
    SizeInBytes := VarSetCapacity( var, StrPut(string, encoding)
        ; StrPut returns char count, but VarSetCapacity needs bytes.
        * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
    ; Copy or convert the string.
    StrPut(string, &var, encoding)
   Return SizeInBytes 
}
;------------------------------------------------------------

Solution

  • If there are special characters (@ being one) in the username too (not only in the password), you have to URL-encode the username too, the same way you URL-encode the password.

    That means you have to apply the UriEncode to strLoginName, the same way you apply it to strPassword.

    And you need to update the UriEncode to encode the @, as it does not.

    The code for @ is 0x40.

    if ((ch>0x7f) || (ch<0x30) || (ch=0x3d) || (ch=0x40))
    

    (Though you can compare to @ literally too: ch="@").