hyerob

pastebin_api_sync.ahk

Apr 4th, 2019
1,068
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;README (INSTRUCTIONS START ON LINE 47; CODE STARTS ON LINE 197)
  2. ;
  3. ;Pastebin API Hotkeys (MS Windows only) for syncing files and folders
  4. ;AutoHotkey V2 32-Bit program (Compatible with 64-bit MS Windows)
  5. ;
  6. ;FIRST THINGS FIRST
  7. ;
  8. ;1. Since this is a program for backing up and syncing files (i.e., not for
  9. ;sharing them), we recommend that you have a Pro membership to pastebin.com so
  10. ;that you can have unlimited private pastes. Regular members can only have 2
  11. ;private pastes. Of course, regular members can paste publicly, but that is
  12. ;probably not what you want to do.
  13. ;
  14. ;FEATURES:
  15. ;
  16. ;0. Correctly handles UTF-8 http request responses from pastebin.com
  17. ;1. Syncs specified files and folder to reflect updated files, deleted files,
  18. ;and changed filenames on pastebin.com (creates timestamped backup copies locally
  19. ;of all changed, deleted, and renamed files)(currenty supports files that match
  20. ;extensions .txt, .md, .ahk, .xml, .py, .pl, .php, .ps1, .js, .csv, and
  21. ;.tsv -- More extensions can be added by simply adjusting the regular expression
  22. ;on lines 597 and 624)
  23. ;2. Backup pastes based on regular expression (creates time_stamped local folder
  24. ;of downloaded pastes)
  25. ;3. Delete pastes based on regular expression (creates timestamped backup copies
  26. ;stored locally)
  27. ;4. List pastes based on regular expression
  28. ;5. Log into Pastebin.com (automates your browser through programmatic key
  29. ;strokes) (currently works when Opera is default browser)
  30. ;6. Add files/folders to your sync path via hotkey (highlight files/folders with
  31. ;mouse and press hotkey)
  32. ;7. Remove files/folders to your sync path via hotkey (highlight files/folders
  33. ;with mouse and press hotkey)
  34. ;8. Display help message
  35. ;
  36. ;HOTKEYS (numbers correspond to the above 1 through 8):
  37. ;
  38. ;1. Create or sync new paste from files/folders = ^!1 (Ctrl+Alt+1)
  39. ;2. Backup pastes = ^!2 (Ctrl+Alt+2)
  40. ;3. Delete pastes = ^!3 (Ctrl+Alt+3)
  41. ;4. List pastes = ^!4 (Ctrl+Alt+4)
  42. ;5. Log into pastebin = ^!5 (Ctrl+Alt+5)
  43. ;6. Add files/folders to sync file = ^!6 (Ctrl+Alt+6)
  44. ;7. Remove files/folders from sync file = ^!7 (Ctrl+Alt+7)
  45. ;8. Help message = ^!h (Ctrl+Alt+h)
  46. ;
  47. ;HOW TO USE:
  48. ;
  49. ;1. Download the latest version of AutoHotkey Version 2 (as of 2019-1-23)
  50. ;https://www.autohotkey.com/download/2.0/AutoHotkey_2.0-a100-52515e2.zip
  51. ;
  52. ;2. Unzip the file "AutoHotkey_2.0-a100-52515e2.zip"
  53. ;
  54. ;3. Double click the folder "AutoHotkey_2.0-a100-52515e2"
  55. ;
  56. ;4. Copy the executable "AutoHotkeyU32.exe" and place it a separate folder.
  57. ;
  58. ;5. Put this file "pastebin_api.ahk" in the same folder as the
  59. ;"AutoHotkeyU32.exe" executable.
  60. ;
  61. ;6. Create a folder called "configuration"
  62. ;
  63. ;7. In the "configuration" folder, create the "pastebin.txt" configuration file
  64. ;(see lines 77-126 for more information on this step.
  65. ;
  66. ;8. In the "configuration" folder, create a "sync.txt" file (see lines 128-144)
  67. ;
  68. ;9. In the folder containing the "AutoHotkeyU32.exe" executable, open Windows
  69. ;Powershell by clicking File -> Open Windows Powershell from Windows Explorer.
  70. ;
  71. ;10. Type ".\AutoHotkeyU32.exe pastebin_api.ahk"
  72. ;
  73. ;11. Use the Hotkeys in lines 38-45 to interact with the Pastebin.com API
  74. ;
  75. ;CONFIGURATION & EXTRA INFORMATION:
  76. ;
  77. ;1. Configuration information is stored in local file:
  78. ;configuration/pastebin.txt
  79. ;
  80. ;Please create the folder "configuration" in the same folder as the script, and
  81. ;then create the "pastebin.txt" configuration file in the "configuration" folder
  82. ;you just created.
  83. ;
  84. ;###Sample configuration configuration/pastebin.txt file (lines 85-92). Please
  85. ;create a similar one###
  86. ;api_dev_key=APIKEY
  87. ;api_user_name=USERNAME
  88. ;api_user_password=PASSWORD
  89. ;api_user_key=
  90. ;api_paste_format=text
  91. ;api_paste_private=2
  92. ;api_paste_expire_date=N
  93. ;#########################################################################
  94. ;
  95. ;Get your api_dev_key by logging into Pastebin.com and going to
  96. ;https://pastebin.com/api
  97. ;
  98. ;api_user_name is your Pastebin.com login username.
  99. ;
  100. ;api_user_password is your Pastebin.com login password.
  101. ;
  102. ;If the api_user_key is blank, the program will automatically generate it and
  103. ;store it after starting the program. If you already have an api_user_key, enter
  104. ;it after the "=" sign. No whitespace allowed.
  105. ;
  106. ;Valid api_paste_format values are available at https://pastebin.com/api
  107. ;An api_paste_format of "text" means "no syntax highlighting"
  108. ;
  109. ;Valid api_paste_private values are 0, 1, 2, which mean public, unlisted, and
  110. ;private, respectively.
  111. ;
  112. ;Value api_paste_expire_date values are the following:
  113. ;N = Never
  114. ;10M = 10 Minutes
  115. ;1H = 1 Hour
  116. ;1D = 1 Day
  117. ;1W = 1 Week
  118. ;2W = 2 Weeks
  119. ;1M = 1 Month
  120. ;6M = 6 Months
  121. ;1Y = 1 Year
  122. ;
  123. ;2. The program will not make any changes to existing Pastebin.com pastes
  124. ;without first backing up the existing file locally. If the backup fails, the
  125. ;thread will exit and nothing will be changed to the paste at Pastebin.com. This
  126. ;is important when overwriting, appending to, and deleting pastes.
  127. ;
  128. ;3. Files and folders to sync are stored in local file: configuration/sync.txt
  129. ;
  130. ;Please put the full path to the file or folder on separate lines (line breaks
  131. ;separating each file and folder entry), or use the hotkeys to add or remove
  132. ;files/folders (Add files/folders = Ctrl+Alt+6; Remove files/folders =
  133. ;Ctrl+Alt+7).
  134. ;
  135. ;4. Files and folders are synced by checking md5 checksums and filenames. md5
  136. ;checksums and filenames are automatically stored locally in your working
  137. ;directory in a file located at  sync_checksums/md5checksums_names.txt. When a
  138. ;file subject to syncing is changed, deleted, or renamed, the checksum/names will
  139. ;not match any of the checksums/names in the md5checksum_names.txt file,
  140. ;indicating that it needs to be synced. After syncing it, the checksums/names in
  141. ;the md5checksum_names.txt file are updated. This step requires no action by the
  142. ;user. If something goes wrong during the process, please check the
  143. ;pastebin_backup folder for the previous version of the md5checksum_names.txt
  144. ;file.
  145. ;
  146. ;CURRENTLY KNOWN LIMITATIONS:
  147. ;
  148. ;1. When files are overwritten for the sync operation, the original Pastebin.com
  149. ;link is deleted and a new link is generated and written to the sync response
  150. ;pop-up. Furthermore, when syncing a file, it is overwritten silently (the
  151. ;overwritten file is backed up locally to the pastebin_backup folder).
  152. ;2. Since the pastebin.com API does not support folders, please ensure that
  153. ;there are no files with duplicated names in your sync folder. In the event that
  154. ;there are duplicated names and something gets deleted from pastebin.com, please
  155. ;check your local pastebin_backup folder for timestamped backups.
  156. ;3. This program only supports up to 1,000 files since this is the limitation
  157. ;imposed by the pastebin.com API when retrieving a list of pastes.
  158. ;4. Since md5 checksums are recalculated every time the program is run, it is
  159. ;expected that there will be performance slowdowns when syncing hundreds of
  160. ;files.
  161. ;5. This program works with UTF-8 encoded files. If your files use another
  162. ;encoding, strange things may happen.
  163. ;6. Due to the nature of the pastebin.com service, original file permissions and
  164. ;attributes such as modification date are not reflected in files downloaded or
  165. ;backed up from pastebin.com
  166. ;7. The pastebin.com API seems to remove trailing carriage returns and newlines
  167. ;from pastes, so if your paste require that these carriage returns and newlines
  168. ;be maintained (for example, C language files), then please be forewarned about
  169. ;this.
  170. ;8. Due to the nature of the pastebin.com service, it only handles text-based
  171. ;files up to 10 MB (500 KB for non-pro members).
  172. ;
  173. ;SUPPORT
  174. ;No support is provided.
  175. ;
  176. ;LICENSE
  177. ;
  178. ;This software is completely free. You can do whatever you want with it.
  179. ;
  180. ;LEGAL DISCLAIMER
  181. ;
  182. ;Short Version
  183. ;USE AT YOUR OWN RISK.
  184. ;
  185. ;Long Version
  186. ;THIS SOFTWARE IS PROVIDED FOR THE PURPOSE OF ILLUSTRATION ONLY AND IS NOT
  187. ;INTENDED TO BE USED IN A PRODUCTION ENVIRONMENT.
  188. ;
  189. ;THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  190. ;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  191. ;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  192. ;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  193. ;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  194. ;FROM, OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS
  195. ;IN THIS SOFTWARE.
  196.  
  197. ;###########CODE STARTS HERE####################
  198.  
  199. ;#Warn  ; Enable warnings to assist with detecting common errors.
  200. SendMode("Input")  ; Recommended for new scripts due to its superior speed and reliability.
  201. SetWorkingDir(A_ScriptDir)  ; Ensures a consistent starting directory.
  202.  
  203. ;AUTOHOTKEY V2 32-BIT SCRIPT
  204.  
  205. ;##########Default settings#####################
  206. pastebin_backup_dir := A_WorkingDir . '\pastebin_backup\'
  207. If !DirExist(pastebin_backup_dir)
  208. {
  209.     DirCreate(pastebin_backup_dir)
  210. }
  211. ;##########Get Pastebin.com credentials#####################
  212. credentials_file := A_WorkingDir . '\configuration\pastebin.txt'
  213. If !FileExist(credentials_file)
  214. {
  215.     MsgBox("You need to create your credentials file at:`n`n" . credentials_file . "`n`nCheck the help information provided at the top of the script for instructions on creating this file.")
  216.     ExitApp()
  217. }
  218. api_dev_key := ''
  219. api_user_name := ''
  220. api_user_password := ''
  221. api_user_key := ''
  222. api_paste_format := ''
  223. api_paste_private := ''
  224. api_paste_expire_date := ''
  225. Loop Read, credentials_file
  226. {
  227.     line := StrSplit(A_LoopReadLine, "=")
  228.     If line[1] = 'api_dev_key'
  229.     {
  230.         api_dev_key := line[2]
  231.     }
  232.     Else If line[1] = 'api_user_name'
  233.     {
  234.         api_user_name := line[2]
  235.     }
  236.     Else If line[1] = 'api_user_password'
  237.     {
  238.         api_user_password := line[2]
  239.     }
  240.     Else If line[1] = 'api_user_key'
  241.     {
  242.         api_user_key := line[2]
  243.     }
  244.     Else If line[1] = 'api_paste_format'
  245.     {
  246.         api_paste_format := line[2]
  247.     }
  248.     Else If line[1] = 'api_paste_private'
  249.     {
  250.         api_paste_private := line[2]
  251.     }
  252.     Else If line[1] = 'api_paste_expire_date'
  253.     {
  254.         api_paste_expire_date := line[2]
  255.     }
  256. }
  257.  
  258. If !api_user_key
  259. {
  260.     result := MsgBox("No api_user_key! Would you like to generate one? (Press Yes or No)",, "YesNo")
  261.     If result = "Yes"
  262.     {
  263.         api_user_name := UriEncode(api_user_name)
  264.         api_user_password := UriEncode(api_user_password)      
  265.         post_fields := 'api_dev_key=' . api_dev_key . '&api_user_name=' . api_user_name . '&api_user_password=' . api_user_password
  266.         url := "https://pastebin.com/api/api_login.php"
  267.         HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  268.         HttpObj.Open("POST", url)
  269.         HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  270.         HttpObj.Send(post_fields)
  271.        
  272.         ; Check response
  273.        
  274.         backup_file := pastebin_backup_dir . "pastebin.txt"
  275.         response := HttpObj.ResponseText
  276.         status := HttpObj.Status
  277.         If status = '200'
  278.         {
  279.             api_user_key := response
  280.             FileCopy(credentials_file, backup_file, '1')
  281.             If !(FileExist(backup_file) And FileGetSize(backup_file) And CheckAgeConfig(credentials_file, backup_file))
  282.             {
  283.                 MsgBox("Local backup of " . credentials_file . " failed! Aborting overwrite...")
  284.                 CheckKeyState()
  285.                 Exit()
  286.             }
  287.             FileDelete(credentials_file)
  288.             content := "api_dev_key=" . api_dev_key . "`napi_user_name=" . api_user_name . "`napi_user_password=" . api_user_password . "`napi_user_key=" . api_user_key . "`napi_paste_format=" . api_paste_format . "`napi_paste_private=" . api_paste_private . "`napi_paste_expire_date=" . api_paste_expire_date
  289.             FileAppend(content, credentials_file)
  290.             MsgBox('api_user_key ' . api_user_key . ' appended to `n' . credentials_file)
  291.         }
  292.         Else
  293.         {
  294.             MsgBox("There was a problem generating the api_user_key. Make sure your credentials file is correct or try again a little later.")
  295.             CheckKeyState()
  296.             Exit()
  297.         }
  298.     }
  299.     Else
  300.     {
  301.         CheckKeyState()
  302.         Exit()
  303.     }
  304.  
  305. }
  306.  
  307. ;##########Get files and folders for syncing#####
  308. sync_file := A_WorkingDir . '\configuration\sync.txt'
  309. If !FileExist(sync_file)
  310. {
  311.     MsgBox("You need to create your sync file at:`n`n" . sync_file . "`n`nCheck the help information provided at the top of the script for instructions on creating this file.")
  312.     ExitApp()
  313. }
  314. files_folders := Trim(FileRead(sync_file, "UTF-8"), "`n`r")
  315.  
  316. ;##########Get md5 checksums#####################
  317. md5checksums_names := ''
  318. md5checksums_dir := A_WorkingDir . '\sync_checksums'
  319. md5checksums_names_file := md5checksums_dir . '\md5checksums_names.txt'
  320. If !DirExist(md5checksums_dir)
  321. {
  322.     DirCreate(md5checksums_dir)
  323.     FileAppend(md5checksums_names, md5checksums_names_file, "UTF-8")
  324. }
  325. Else If (FileExist(md5checksums_names_file))
  326. {
  327.     md5checksums_names := RTrim(FileRead(md5checksums_names_file, "UTF-8"), "`n`r")
  328. }
  329. Else
  330. {
  331.     MsgBox("The checksums file is missing from " . md5checksums_dir . ". To fix this error, you may need to delete " . md5checksums_dir . " including any files in it and start again.")
  332.     ExitApp()
  333. }
  334.  
  335. ;##########Utility functions#####################
  336.  
  337. OpenWindowPastebin(win_title, tab_title, run_command, username, password)
  338. {
  339.     If WinExist(win_title)
  340.     {
  341.         WinActivate(win_title)
  342.         Sleep(150)
  343.         If WinActive(tab_title)
  344.         {
  345.             Loop 23
  346.             {
  347.                 SendInput("{Tab}")
  348.                 Sleep(150)
  349.             }
  350.             SendInput(username)
  351.             Sleep(500)
  352.             SendInput("{Tab}")
  353.             Sleep(250)
  354.             SendInput(password)
  355.             Sleep(500)
  356.             SendInput("{Enter}")
  357.             Sleep(250)
  358.             Return
  359.         }
  360.         Loop 9
  361.         {
  362.             SendInput("{Ctrl down}{" . A_Index . "}")
  363.             Sleep(200)
  364.             SendInput("{Ctrl up}")
  365.             Sleep(200)
  366.             If WinActive(tab_title)
  367.             {
  368.                 Loop 23
  369.                 {
  370.                     SendInput("{Tab}")
  371.                     Sleep(150)
  372.                 }
  373.                 SendInput(username)
  374.                 Sleep(500)
  375.                 SendInput("{Tab}")
  376.                 Sleep(250)
  377.                 SendInput(password)
  378.                 Sleep(500)
  379.                 SendInput("{Enter}")
  380.                 Sleep(250)
  381.                 Return
  382.             }
  383.         }
  384.         Run(run_command)
  385.         While !WinActive(tab_title)
  386.         {
  387.             Sleep(100)
  388.         }
  389.         Sleep(7000)
  390.         Loop 23
  391.         {
  392.             SendInput("{Tab}")
  393.             Sleep(150)
  394.         }
  395.         SendInput(username)
  396.         Sleep(500)
  397.         SendInput("{Tab}")
  398.         Sleep(250)
  399.         SendInput(password)
  400.         Sleep(500)
  401.         SendInput("{Enter}")
  402.         Sleep(250)
  403.         Return
  404.     }
  405.     Else
  406.     {
  407.         Run(run_command)
  408.         While !WinActive(tab_title)
  409.         {
  410.             Sleep(100)
  411.         }
  412.         Sleep(7000)
  413.         Loop 23
  414.         {
  415.             SendInput("{Tab}")
  416.             Sleep(150)
  417.         }
  418.         SendInput(username)
  419.         Sleep(500)
  420.         SendInput("{Tab}")
  421.         Sleep(250)
  422.         SendInput(password)
  423.         Sleep(500)
  424.         SendInput("{Enter}")
  425.         Sleep(250)
  426.         Return
  427.     }
  428. }
  429.  
  430. CheckAge(file)
  431. {
  432.     ; check that file modification date is < 10 seconds old
  433.    
  434.     time_now := A_Now
  435.     file_mod_time := FileGetTime(file, "M")
  436.     age := DateDiff(time_now, file_mod_time, "seconds")
  437.     If age < 10
  438.     {
  439.         Return(True)
  440.     }
  441.     Else
  442.     {
  443.         Return(False)
  444.     }
  445. }
  446.  
  447. CheckAgeConfig(orig, copy)
  448. {
  449.     ; check that file modification date is the same
  450.    
  451.     orig_mod_time := FileGetTime(orig, "M")
  452.     copy_mod_time := FileGetTime(copy, "M")
  453.     age := DateDiff(orig_mod_time, copy_mod_time, "seconds")
  454.     If age = 0
  455.     {
  456.         Return(True)
  457.     }
  458.     Else
  459.     {
  460.         Return(False)
  461.     }
  462. }
  463.  
  464. CheckKeyState()
  465. {
  466.     Sleep(1000)
  467.     While 1
  468.     {
  469.         if GetKeyState("Control")
  470.         {
  471.             MsgBox("Control key is down")
  472.             Continue
  473.         }
  474.         if GetKeyState("Alt")
  475.         {
  476.             MsgBox("Alt key is down")
  477.             Continue
  478.         }
  479.         Break
  480.     }
  481. }
  482.  
  483. UriEncode(string)
  484. {
  485.     string := RegExReplace(string, "%([025789ACD]{2})", "%25$1")
  486.     string := RegExReplace(string, "'", "%27")
  487.     string := RegExReplace(string, '"', "%22")
  488.    string := RegExReplace(string, "\\", "%5C")
  489.    string := RegExReplace(string, "\n", "%0A")
  490.    string := RegExReplace(string, "\r", "%0D")
  491.    string := RegExReplace(string, "\(", "%28")
  492.    string := RegExReplace(string, "\)", "%29")
  493.    oSC := ComObjCreate("ScriptControl")
  494.    oSC.Language := "JScript"
  495.     Script := 'var Encoded = encodeURIComponent(' . '"' . string . '")'
  496.     oSC.ExecuteStatement(Script)
  497.     string := oSC.Eval("Encoded")
  498.     string := RegExReplace(string, "%2527", "%27")
  499.    string := RegExReplace(string, "%2522", "%22")
  500.    string := RegExReplace(string, "%255C", "%5C")
  501.    string := RegExReplace(string, "%250A", "%0A")
  502.    string := RegExReplace(string, "%250D", "%0D")
  503.    string := RegExReplace(string, "%2528", "%28")
  504.    string := RegExReplace(string, "%2529", "%29")
  505.    string := RegExReplace(string, "%2525([025789ACD]{2})", "%25$1")
  506.     Return(string)
  507. }
  508.  
  509. BcryptMd5(string)
  510. {
  511.    Static BCRYPT_MD5_ALGORITHM := "MD5"
  512.    Static BCRYPT_HASH_LENGTH   := "HashDigestLength"
  513.  
  514.    If !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
  515.        throw Exception("Failed to load bcrypt.dll", -1)
  516.  
  517.    If (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_MD5_ALGORITHM, "ptr", 0, "uint", 0) != 0)
  518.        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)
  519.  
  520.    If (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
  521.        throw Exception("BCryptGetProperty: " NT_STATUS, -1)
  522.  
  523.    VarSetCapacity(pbInput, StrPut(string, "UTF-8"), 0) && cbInput := StrPut(string, &pbInput, "UTF-8") - 1, VarSetCapacity(pbHash, cbHash, 0)
  524.    If (NT_STATUS := DllCall("bcrypt\BCryptHash", "ptr", hAlgo, "ptr", 0, "uint", 0, "ptr", &pbInput, "uint", cbInput, "ptr", &pbHash, "uint", cbHash) != 0)
  525.        throw Exception("BCryptHash: " NT_STATUS, -1)
  526.  
  527.    Loop cbHash
  528.        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))
  529.  
  530.    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
  531.    DllCall("FreeLibrary", "ptr", hBCRYPT)
  532.  
  533.    Return(hash)
  534. }
  535.  
  536. BcryptMd5File(filename)
  537. {
  538.    static BCRYPT_MD5_ALGORITHM := "MD5"
  539.    static BCRYPT_HASH_LENGTH   := "HashDigestLength"
  540.  
  541.    if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
  542.        throw Exception("Failed to load bcrypt.dll", -1)
  543.  
  544.    if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_MD5_ALGORITHM, "ptr", 0, "uint", 0) != 0)
  545.        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)
  546.  
  547.    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
  548.        throw Exception("BCryptGetProperty: " NT_STATUS, -1)
  549.  
  550.    VarSetCapacity(pbHash, cbHash, 0)
  551.    if !(f := FileOpen(filename, "r", "UTF-8"))
  552.        throw Exception("Failed to open file: " filename, -1)
  553.    f.Seek(0)
  554.    while (dataread := f.RawRead(data, 262144))
  555.        if (NT_STATUS := DllCall("bcrypt\BCryptHash", "ptr", hAlgo, "ptr", 0, "uint", 0, "ptr", &data, "uint", dataread, "ptr", &pbHash, "uint", cbHash) != 0)
  556.            throw Exception("BCryptHash: " NT_STATUS, -1)
  557.    f.Close()
  558.  
  559.    Loop cbHash
  560.        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))
  561.  
  562.    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
  563.    DllCall("FreeLibrary", "ptr", hBCRYPT)
  564.  
  565.    Return hash
  566. }
  567.  
  568. ;#########Pastebin hotkeys###################
  569.  
  570. ; File & folder sync
  571. ^!1::
  572.     global api_dev_key
  573.     global api_user_key
  574.     global api_paste_format
  575.     global api_paste_private
  576.     global api_paste_expire_date
  577.     global pastebin_backup_dir
  578.     global files_folders
  579.     global md5checksums_names
  580.     global md5checksums_names_file
  581.    
  582.     paste_results := '' ; summary of files pasted
  583.     paste_count := 0
  584.     paste_errors := 0
  585.     delete_count := 0
  586.     delete_errors := 0
  587.     delete_results := ''
  588.    
  589.     files := []
  590.     files_unique := {}
  591.    
  592.     newMd5checksums_names := ''
  593.     Loop Parse, files_folders, "`n", "`r"
  594.     {
  595.         If !InStr(FileGetAttrib(A_LoopField), "D")
  596.         {
  597.              If RegExMatch(A_LoopField, "\.txt$|\.md$|\.ahk$|\.p[ylhs][p1]?$|\.html?$|\.js$|\.[ct]sv$")
  598.              {
  599.                 RegExMatch(A_LoopField, "[^\\]*$", match) ; get file name only (no path)
  600.                 file_name := match[0]
  601.                 file_md5checksum := BcryptMd5File(A_LoopField)
  602.                 file_md5checksum_name := file_md5checksum . '::' . file_name
  603.                 file_md5checksum_name_regex := RegExReplace(file_md5checksum_name , "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1') ; escape regex
  604.                 If RegExMatch(md5checksums_names, '(?m)^' . file_md5checksum_name_regex . '$')
  605.                 {
  606.                     newMd5checksums_names .= file_md5checksum_name . '`n'
  607.                     Continue
  608.                 }
  609.                 Else
  610.                 {
  611.                     files.Push(A_LoopField)
  612.                     newMd5checksums_names .= file_md5checksum_name . '`n'
  613.                     files_unique[match[0]] := 1
  614.                     ; Clearer to write files_unique[file_name] := 1 ??
  615.                 }
  616.             }
  617.         }
  618.         Else
  619.         {
  620.             Loop Files, A_LoopField . "\*.*", "FDR"
  621.             {
  622.                 If !InStr(FileGetAttrib(A_LoopFileFullPath), "D")
  623.                 {
  624.                      If RegExMatch(A_LoopFileFullPath, "\.txt$|\.md$|\.ahk$|\.p[ylhs][p1]?$|\.html?$|\.js$|\.[ct]sv$")
  625.                     {
  626.                         RegExMatch(A_LoopFileFullPath, "[^\\]*$", match) ; get file name only
  627.                         file_name := match[0]
  628.                         file_md5checksum := BcryptMd5File(A_LoopFileFullPath)
  629.                         file_md5checksum_name := file_md5checksum . '::' . file_name
  630.                         file_md5checksum_name_regex := RegExReplace(file_md5checksum_name , "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1') ; escape regex
  631.                         If RegExMatch(md5checksums_names, '(?m)^' . file_md5checksum_name_regex . '$')
  632.                         {
  633.                             newMd5checksums_names .= file_md5checksum_name . '`n'
  634.                             Continue
  635.                         }
  636.                         Else
  637.                         {
  638.                             files.Push(A_LoopFileFullPath)
  639.                             newMd5checksums_names .= file_md5checksum_name . '`n'
  640.                             files_unique[match[0]] := 1
  641.                             ; Clearer to write files_unique[file_name] := 1 ??
  642.                         }
  643.                     }
  644.                 }
  645.             }
  646.         }
  647.     }
  648.    
  649.     backup_names_file := pastebin_backup_dir . "\md5checksums_names.txt"
  650.     FileCopy(md5checksums_names_file, backup_names_file, '1')
  651.     If !(FileExist(backup_names_file) And CheckAgeConfig(md5checksums_names_file, backup_names_file))
  652.     {
  653.         MsgBox("Local backup of " . md5checksums_names_file . " failed! Aborting sync...")
  654.         CheckKeyState()
  655.         Exit()
  656.     }
  657.     FileDelete(md5checksums_names_file)
  658.     FileAppend(newMd5checksums_names, md5checksums_names_file, "UTF-8")
  659.    
  660.     ; Post each file
  661.     ; If there are no files with duplicate names, we can grab the pastes list only once
  662.     ; So we need to create a flag
  663.    
  664.     list_flag := 0
  665.     list_loop := 1
  666.    
  667.     If files.Length() = files_unique.Length()
  668.     {
  669.         ; No duplicate names
  670.         list_flag := 1
  671.     }
  672.     list_matches := []
  673.        
  674.     Loop files.Length()
  675.     {
  676.         match_pos := RegExMatch(files[A_Index], "[^\\]*$", match) ; get file name only (no path)
  677.         api_paste_name := match[0]
  678.         api_paste_code := FileRead(files[A_Index], "UTF-8")
  679.         ; NEED TO STRIP OFF NEWLINES BECAUSE PASTEBIN.COM STRIPS OFF ALL TRAILING NEWLINES FROM API-BASED PASTES
  680.         api_paste_code_stripped := RegExReplace(api_paste_code, '(?:\r?\n)*$', '')
  681.        
  682.         ; Check to see if the file already exists by calling API for existing pastes
  683.        
  684.         If list_loop
  685.         {
  686.             api_results_limit := '1000'
  687.             api_option := 'list'
  688.             post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_results_limit=' . api_results_limit
  689.             url := "https://pastebin.com/api/api_post.php"
  690.             HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  691.             HttpObj.Open("POST", url)
  692.             HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  693.             HttpObj.Send(post_fields)
  694.  
  695.             ; Check response
  696.            
  697.             stream := ComObjCreate("adodb.stream")
  698.             stream.Type := 1
  699.             stream.Mode := 3
  700.             stream.Open()
  701.             stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  702.             stream.Position := 0
  703.             stream.Type := 2
  704.             stream.Charset := 'UTF-8'
  705.             response := stream.ReadText()
  706.             stream.Close()
  707.             status := HttpObj.Status
  708.            
  709.             If !status = '200'
  710.             {
  711.                 result := MsgBox("Http request failure in file listing for " . api_paste_name . "! Error code: " . status . "`nPlease make sure your configuration file is correct.`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  712.                 If result = "Yes"
  713.                 {
  714.                     paste_errors++
  715.                     Continue
  716.                 }
  717.                 Else
  718.                 {
  719.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  720.                     MsgBox(paste_results)
  721.                     CheckKeyState()
  722.                     Exit()
  723.                 }
  724.             }
  725.             If !(InStr(response,"paste"))
  726.             {
  727.                 result := MsgBox("Could not get list of pastes to compare file names for " . api_paste_name . "! Error code: " . status . "`nPlease make sure your configuration file is correct.`nResponse: " . response . "`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  728.                 If result = "Yes"
  729.                 {
  730.                     paste_errors++
  731.                     Continue
  732.                 }
  733.                 Else
  734.                 {
  735.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  736.                     MsgBox(paste_results)
  737.                     CheckKeyState()
  738.                     Exit()
  739.                 }
  740.             }
  741.            
  742.             ; Check to see if the file name already exists
  743.            
  744.             api_paste_key := '' ; We will extract this in order to use it when backing up and overwriting files
  745.             start_pos := 1
  746.             find_pos := ''
  747.             regexp := 's)<paste_key>.*?</paste_title>'
  748.             Loop
  749.             {
  750.                 find_pos := RegExMatch(response, regexp, match, start_pos)
  751.                 If find_pos
  752.                 {
  753.                     list_matches.Push(match[0])
  754.                     start_pos := match.Pos(0) + match.Len(0)
  755.                 }
  756.             } Until find_pos = 0
  757.             If list_flag
  758.             {
  759.                 list_loop := 0
  760.             }
  761.         }
  762.         exists := 0
  763.         Loop list_matches.Length()
  764.         {
  765.             string := list_matches[A_Index]
  766.             api_paste_name_regex := RegExReplace(api_paste_name, "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1')
  767.             If RegExMatch(string, '<paste_title>' . api_paste_name_regex . '</paste_title>')
  768.             {
  769.                 match_pos := RegExMatch(string, '<paste_key>(.*?)</paste_key>', match)
  770.                 api_paste_key := match[1]
  771.                 exists := 1
  772.                 Break
  773.             }
  774.         }
  775.         If exists = 1
  776.         {
  777.             ; Overwrite it, but first create backup of it locally
  778.            
  779.             api_option := 'show_paste'
  780.             post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . api_paste_key
  781.             url := "https://pastebin.com/api/api_raw.php"
  782.             HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  783.             HttpObj.Open("POST", url)
  784.             HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  785.             HttpObj.Send(post_fields)
  786.            
  787.             ; Check response
  788.            
  789.             status := HttpObj.Status
  790.             If !status = '200'
  791.             {
  792.                 result := MsgBox("Http request failure in file backup for " . api_paste_name . "! Error code: " . status "`nOriginal file not overwritten.`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  793.                 If result = "Yes"
  794.                 {
  795.                     paste_errors++
  796.                     Continue
  797.                 }
  798.                 Else
  799.                 {
  800.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  801.                     MsgBox(paste_results)
  802.                     CheckKeyState()
  803.                     Exit()
  804.                 }
  805.             }
  806.            
  807.             ; Decode bytes (WinHttp.WinHttpRequest.5.1 ResponseText wrongly decodes encoding)
  808.            
  809.             stream := ComObjCreate("adodb.stream")
  810.             stream.Type := 1
  811.             stream.Mode := 3
  812.             stream.Open()
  813.             stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  814.             stream.Position := 0
  815.             stream.Type := 2
  816.             stream.Charset := 'UTF-8'
  817.             response := stream.ReadText()
  818.             stream.Close()
  819.            
  820.             ; Create backup
  821.             backup_file := pastebin_backup_dir . api_paste_name
  822.             t := A_NOW
  823.             ts := FormatTime(t, "_yyyyMMdd-HHmmss")
  824.             backup_file := RegExReplace(backup_file, '(.*?)(\.[^.]*$)', '$1' . ts . '$2')
  825.             FileDelete(backup_file)
  826.             FileAppend(response, backup_file, "UTF-8")
  827.            
  828.             If !(FileExist(backup_file) And CheckAge(backup_file))
  829.             {
  830.                 result := MsgBox("Local backup of " . api_paste_name . "failed! Aborting overwrite. Do you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  831.                 If result = "Yes"
  832.                 {
  833.                     paste_errors++
  834.                     Continue
  835.                 }
  836.                 Else
  837.                 {
  838.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  839.                     MsgBox(paste_results)
  840.                     CheckKeyState()
  841.                     Exit()
  842.                 }
  843.             }
  844.            
  845.             ; Delete paste (Irreversible in event of interruption between delete and paste!)
  846.            
  847.             api_option := 'delete'
  848.             post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . api_paste_key
  849.             url := "https://pastebin.com/api/api_post.php"
  850.             HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  851.             HttpObj.Open("POST", url)
  852.             HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  853.             HttpObj.Send(post_fields)
  854.            
  855.             ; Check response
  856.            
  857.             response := HttpObj.ResponseText
  858.             status := HttpObj.Status
  859.             If !status = '200'
  860.             {
  861.                 result := MsgBox("Http request failure deleting " . api_paste_name . " for overwrite! Error code: " . status . "`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  862.                 If result = "Yes"
  863.                 {
  864.                     paste_errors++
  865.                     Continue
  866.                 }
  867.                 Else
  868.                 {
  869.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  870.                     MsgBox(paste_results)
  871.                     CheckKeyState()
  872.                     Exit()
  873.                 }
  874.             }
  875.             If !(InStr(response,"removed"))
  876.             {
  877.                 result := MsgBox("Overwrite failure occurred for " . api_paste_name . " ! File not overwritten.`nResponse: " . response . "`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  878.                 If result = "Yes"
  879.                 {
  880.                     paste_errors++
  881.                     Continue
  882.                 }
  883.                 Else
  884.                 {
  885.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  886.                     MsgBox(paste_results)
  887.                     CheckKeyState()
  888.                     Exit()
  889.                 }
  890.             }
  891.                
  892.         }
  893.        
  894.         ; Create paste
  895.        
  896.         api_option := 'paste'
  897.         paste_name := api_paste_name
  898.         api_paste_name := UriEncode(api_paste_name)
  899.         api_paste_code := UriEncode(api_paste_code)
  900.         post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_paste_private=' . api_paste_private . '&api_paste_name=' . api_paste_name . '&api_paste_expire_date=' . api_paste_expire_date . '&api_paste_format=' . api_paste_format . '&api_dev_key=' . api_dev_key . '&api_paste_code=' . api_paste_code
  901.         ;MsgBox(post_fields)
  902.         ;Exit()
  903.         url := "https://pastebin.com/api/api_post.php"
  904.         HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  905.         HttpObj.Open("POST", url)
  906.         HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  907.         HttpObj.Send(post_fields)
  908.        
  909.         ; Check response
  910.        
  911.         response := HttpObj.ResponseText
  912.         status := HttpObj.Status
  913.         If !status = '200'
  914.         {
  915.             result := MsgBox("Http request failure in paste for " . paste_name . " ! Error code: " . status . "`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  916.             If result = "Yes"
  917.             {
  918.                 paste_errors++
  919.                 Continue
  920.             }
  921.             Else
  922.             {
  923.                 paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  924.                 MsgBox(paste_results)
  925.                 CheckKeyState()
  926.                 Exit()
  927.             }
  928.         }
  929.         If !(InStr(response,"pastebin"))
  930.         {
  931.             result := MsgBox("Paste failure occurred for " . paste_name . " ! Error code: " . status . "`nResponse: " . response . "`nDo you want to try to continue pasting the rest of the files? This error may occur repeatedly.",, "YesNo")
  932.             If result = "Yes"
  933.             {
  934.                 paste_errors++
  935.                 Continue
  936.             }
  937.             Else
  938.             {
  939.                 paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  940.                 MsgBox(paste_results)
  941.                 CheckKeyState()
  942.                 Exit()
  943.             }
  944.         }
  945.         Else
  946.         {
  947.             paste_results .= A_Tab . paste_name . ":" . A_Tab . response . "`n"
  948.             paste_count++
  949.         }
  950.     }
  951.    
  952.     ; Delete files from Pastebin that have been deleted from sync folders
  953.    
  954.     start_pos := 1
  955.     find_pos := ''
  956.     current_files := []
  957.     regexp := 'm)::(.*)$'
  958.     Loop
  959.     {
  960.         find_pos := RegExMatch(md5checksums_names, regexp, match, start_pos)
  961.         If find_pos
  962.         {
  963.             current_files.Push(match[1])
  964.             start_pos := match.Pos(0) + match.Len(0)
  965.         }
  966.     } Until find_pos = 0
  967.    
  968.     delete_files := []
  969.     Loop current_files.Length()
  970.     {
  971.         current_file_regex := RegExReplace(current_files[A_Index], "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1')
  972.         If !RegExMatch(newMd5checksums_names, 'm)::' . current_file_regex . '$')
  973.         {
  974.             delete_files.Push(current_files[A_Index])
  975.         }
  976.     }
  977.    
  978.     ; Get list of files on Pastebin.com
  979.    
  980.     api_results_limit := '1000'
  981.     api_option := 'list'
  982.     post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_results_limit=' . api_results_limit
  983.     url := "https://pastebin.com/api/api_post.php"
  984.     HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  985.     HttpObj.Open("POST", url)
  986.     HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  987.     HttpObj.Send(post_fields)
  988.  
  989.     ; Check response
  990.    
  991.     stream := ComObjCreate("adodb.stream")
  992.     stream.Type := 1
  993.     stream.Mode := 3
  994.     stream.Open()
  995.     stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  996.     stream.Position := 0
  997.     stream.Type := 2
  998.     stream.Charset := 'UTF-8'
  999.     response := stream.ReadText()
  1000.     stream.Close()
  1001.     status := HttpObj.Status
  1002.    
  1003.     If !status = '200'
  1004.     {
  1005.         error_message := "Http request failure in retrieving pastes listing for syncing files! Error code: " . status . "`nPossibly a network error occurred. Please try again later by deleting files via regular expression hotkey Ctrl+Alt+3.`n`n"
  1006.         paste_results := error_message . paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1007.         MsgBox(paste_results)
  1008.         Exit()
  1009.     }
  1010.     If !(InStr(response,"paste"))
  1011.     {
  1012.         error_message := "Http request failure in retrieving pastes listing for syncing files! Error code: " . status . "`nPossibly a network error occurred. Please try again later by deleting files via regular expression hotkey Ctrl+Alt+3.`n`n"
  1013.         paste_results := error_message . paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1014.         MsgBox(paste_results)
  1015.         Exit()
  1016.    }
  1017.    
  1018.    ; Get keys for delete_files
  1019.    
  1020.    start_pos := 1
  1021.     find_pos := ''
  1022.     list_matches := []
  1023.     regexp := 's)<paste_key>.*?</paste_title>'
  1024.     Loop
  1025.     {
  1026.         find_pos := RegExMatch(response, regexp, match, start_pos)
  1027.         If find_pos
  1028.         {
  1029.             list_matches.Push(match[0])
  1030.             start_pos := match.Pos(0) + match.Len(0)
  1031.         }
  1032.     } Until find_pos = 0
  1033.    
  1034.    delete_keys := [] ; We will extract this in order to use it when backing up and deleting files
  1035.     delete_titles := []
  1036.     exists := 0
  1037.     Loop delete_files.Length()
  1038.     {
  1039.         api_paste_name := delete_files[A_Index]
  1040.         Loop list_matches.Length()
  1041.         {
  1042.             string := list_matches[A_Index]
  1043.             api_paste_name_regex := RegExReplace(api_paste_name, "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1')
  1044.             If RegExMatch(string, '<paste_title>' . api_paste_name_regex . '</paste_title>')
  1045.             {
  1046.                 match_pos := RegExMatch(string, '<paste_key>(.*?)</paste_key>', match)
  1047.                 delete_keys.Push(match[1])
  1048.                 delete_titles.Push(api_paste_name)
  1049.                 exists := 1
  1050.                 Break
  1051.             }
  1052.         }
  1053.     }
  1054.    
  1055.     If exists
  1056.     {
  1057.         ; Create local backups
  1058.         Loop delete_keys.Length()
  1059.         {
  1060.             api_option := 'show_paste'
  1061.             post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . delete_keys[A_Index]
  1062.             url := "https://pastebin.com/api/api_raw.php"
  1063.             HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1064.             HttpObj.Open("POST", url)
  1065.             HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1066.             HttpObj.Send(post_fields)
  1067.            
  1068.             ; Check response
  1069.            
  1070.             status := HttpObj.Status
  1071.             If !status = '200'
  1072.             {
  1073.                 result := MsgBox("Http request failure in " . delete_titles[A_Index] . " backup before delete! Error code: " . status . "`nDo you want to continue deleting the rest of the files?",, "YesNo")
  1074.                 If result = "Yes"
  1075.                 {
  1076.                     delete_errors++
  1077.                     Continue
  1078.                 }
  1079.                 Else
  1080.                 {
  1081.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1082.                     MsgBox(paste_results)
  1083.                     CheckKeyState()
  1084.                     Exit()
  1085.                 }
  1086.             }
  1087.            
  1088.             ; Decode bytes (WinHttp.WinHttpRequest.5.1 ResponseText wrongly decodes encoding)
  1089.            
  1090.             stream := ComObjCreate("adodb.stream")
  1091.             stream.Type := 1
  1092.             stream.Mode := 3
  1093.             stream.Open()
  1094.             stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1095.             stream.Position := 0
  1096.             stream.Type := 2
  1097.             stream.Charset := 'UTF-8'
  1098.             response := stream.ReadText()
  1099.             stream.Close()
  1100.            
  1101.             ; Write paste to local backup directory
  1102.            
  1103.             backup_file := pastebin_backup_dir . delete_titles[A_Index]
  1104.             t := A_NOW
  1105.             ts := FormatTime(t, "_yyyyMMdd-HHmmss")
  1106.             backup_file := RegExReplace(backup_file, '(.*?)(\.[^.]*$)', '$1' . ts . '$2')
  1107.             FileDelete(backup_file)
  1108.             FileAppend(response, backup_file, "UTF-8")
  1109.            
  1110.             If !(FileExist(backup_file) And CheckAge(backup_file))
  1111.             {
  1112.                 result := MsgBox("Local backup of " . delete_titles[A_Index] . "failed! File not deleted from Pastebin.com.`nDo you want to continue deleting the rest of the files?",, "YesNo")
  1113.                 If result = "Yes"
  1114.                 {
  1115.                     delete_errors++
  1116.                     Continue
  1117.                 }
  1118.                 Else
  1119.                 {
  1120.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1121.                     MsgBox(paste_results)
  1122.                     CheckKeyState()
  1123.                     Exit()
  1124.                 }
  1125.             }
  1126.         }
  1127.        
  1128.         ; Delete pastes from Pastebin.com
  1129.        
  1130.         Loop delete_keys.Length()
  1131.         {
  1132.             api_option := 'delete'
  1133.             post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . delete_keys[A_Index]
  1134.             url := "https://pastebin.com/api/api_post.php"
  1135.             HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1136.             HttpObj.Open("POST", url)
  1137.             HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1138.             HttpObj.Send(post_fields)
  1139.            
  1140.             ; Check response
  1141.            
  1142.             response := HttpObj.ResponseText
  1143.             status := HttpObj.Status
  1144.             If !status = '200'
  1145.             {
  1146.                 result := MsgBox("Http request failure during delete! " . delete_titles[A_Index] . " not deleted. Error code: " . status . "`nDo you want to continue deleting the rest of the files?", "YesNo")
  1147.                 If result = "Yes"
  1148.                 {
  1149.                     delete_errors++
  1150.                     Continue
  1151.                 }
  1152.                 Else
  1153.                 {
  1154.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1155.                     MsgBox(paste_results)
  1156.                     CheckKeyState()
  1157.                     Exit()
  1158.                 }
  1159.             }
  1160.             If !(InStr(response,"removed"))
  1161.             {
  1162.                 result := MsgBox("Delete failure occurred! " . delete_titles[A_Index] . " not deleted.`nResponse: " . response . "`nDo you want to continue deleting the rest of the files?", "YesNo")
  1163.                 If result = "Yes"
  1164.                 {
  1165.                     delete_errors++
  1166.                     Continue
  1167.                 }
  1168.                 Else
  1169.                 {
  1170.                     paste_results := paste_count . " file(s) were pasted to pastebin.com with " . ++paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1171.                     MsgBox(paste_results)
  1172.                     CheckKeyState()
  1173.                     Exit()
  1174.                 }
  1175.             }
  1176.             delete_count++
  1177.             delete_results .= A_Tab . delete_titles[A_Index] . '`n'
  1178.         }
  1179.     }
  1180.    
  1181.     paste_results := "Results summary (also copied to your computer's clipboard):`n`n" . paste_count . " file(s) were pasted to pastebin.com with " . paste_errors . " error(s)!`n" . paste_results . "`n" . delete_count . " files were deleted from pastebin.com with " . delete_errors . " error(s)!`n" . delete_results
  1182.     Clipboard := paste_results
  1183.     MsgBox(paste_results)
  1184.     CheckKeyState()
  1185.     Reload ; Necessary for syncing correctly
  1186. Return
  1187.  
  1188. ; Backup pastes based on regular expression
  1189. ^!2::
  1190.     global api_dev_key
  1191.     global api_user_key
  1192.    
  1193.     ; Create backup folder
  1194.     time_stamp := A_Now
  1195.     paste_backup_dir := A_WorkingDir . '\paste_backup_' . time_stamp . '\'
  1196.     If !DirExist(paste_backup_dir)
  1197.     {
  1198.         DirCreate(paste_backup_dir)
  1199.     }
  1200.    
  1201.     ; Get regexp
  1202.    
  1203.     Gui := GuiCreate(, "Enter a search query (e.g., regex) for files to backup")
  1204.     Gui.Add("Text",, "Search query:")
  1205.     Gui.Add("Edit", "w400 vsearch")
  1206.     Gui.Add("Button", "default", "OK").OnEvent("Click", () => ProcessUserInputBackup(Gui))
  1207.     Gui.Add("Button", "x+5", "Cancel").OnEvent("Click", () => CancelUserInputBackup(Gui))
  1208.     Gui.OnEvent("Close", "ProcessUserInputBackup")
  1209.     Gui.OnEvent("Close", "CancelUserInputBackup")
  1210.     Gui.Show()
  1211.     Sleep(300)
  1212.     ProcessUserInputBackup(this)
  1213.     {
  1214.         global paste_backup_dir
  1215.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1216.         regexp := saved.search
  1217.        
  1218.         ; Get list of all pastes
  1219.        
  1220.         api_results_limit := '1000'
  1221.         api_option := 'list'
  1222.         post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_results_limit=' . api_results_limit
  1223.         url := "https://pastebin.com/api/api_post.php"
  1224.         HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1225.         HttpObj.Open("POST", url)
  1226.         HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1227.         HttpObj.Send(post_fields)
  1228.        
  1229.         ; Check response
  1230.        
  1231.         stream := ComObjCreate("adodb.stream")
  1232.         stream.Type := 1
  1233.         stream.Mode := 3
  1234.         stream.Open()
  1235.         stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1236.         stream.Position := 0
  1237.         stream.Type := 2
  1238.         stream.Charset := 'UTF-8'
  1239.         response := stream.ReadText()
  1240.         stream.Close()
  1241.         status := HttpObj.Status
  1242.        
  1243.         If !status = '200'
  1244.         {
  1245.             MsgBox("Http request failure in file listing! Error code: " . status . "`nPlease make sure your configuration file is correct.")
  1246.             CheckKeyState()
  1247.             Exit()
  1248.         }
  1249.         If !(InStr(response,"paste"))
  1250.         {
  1251.             MsgBox("Could not get list of pastes to compare file names.`nPlease make sure your configuration file is correct.`n" . response)
  1252.             CheckKeyState()
  1253.             Exit()
  1254.         }
  1255.        
  1256.         ; Check to see if regexp matches any paste titles
  1257.        
  1258.         ; First grab titles and keys
  1259.        
  1260.         api_paste_key := '' ; We will extract this in order to use it when backing up
  1261.         start_pos := 1
  1262.         find_pos := ''
  1263.         matches := []
  1264.         response_regexp := 's)<paste_key>.*?</paste_title>'
  1265.         Loop
  1266.         {
  1267.             find_pos := RegExMatch(response, response_regexp, match, start_pos)
  1268.             If find_pos
  1269.             {
  1270.                 matches.Push(match[0])
  1271.                 start_pos := match.Pos(0) + match.Len(0)
  1272.             }
  1273.         } Until find_pos = 0
  1274.         exists := 0
  1275.         titles := []
  1276.         keys := []
  1277.         Loop matches.Length()
  1278.         {
  1279.             string := matches[A_Index]
  1280.             match_pos := RegExMatch(string, '<paste_title>(.*?)</paste_title>', title_match)
  1281.             title_match := title_match[1]
  1282.             If RegExMatch(title_match, regexp)
  1283.             {
  1284.                 match_pos := RegExMatch(string, '<paste_key>(.*?)</paste_key>', match)
  1285.                 keys.Push(match[1])
  1286.                 ;match_pos := RegExMatch(string, '<paste_title>(.*?)</paste_title>', match)
  1287.                 ;titles.Push(match[1])
  1288.                 titles.Push(title_match)
  1289.                 exists := 1
  1290.             }
  1291.         }
  1292.         If exists
  1293.         {
  1294.             ; Print out files that match and confirm backup
  1295.             message := "Do you want to backup all of these files?`nList of files also copied to your computer's clipboard.`n"
  1296.             Loop titles.Length()
  1297.             {
  1298.                 message .= titles[A_Index] . '`n'
  1299.             }
  1300.             Clipboard := message
  1301.             result := MsgBox(message,, "YesNo")
  1302.             If result = "Yes"
  1303.             {
  1304.                 ; Create local backups
  1305.                
  1306.                 backup_count := 0
  1307.                 backup_names := ""
  1308.                 errors := 0
  1309.                 Loop keys.Length()
  1310.                 {
  1311.                     api_option := 'show_paste'
  1312.                     post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . keys[A_Index]
  1313.                     url := "https://pastebin.com/api/api_raw.php"
  1314.                     HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1315.                     HttpObj.Open("POST", url)
  1316.                     HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1317.                     HttpObj.Send(post_fields)
  1318.                    
  1319.                     ; Check response
  1320.                    
  1321.                     status := HttpObj.Status
  1322.                     If !status = '200'
  1323.                     {
  1324.                         result := MsgBox("Http request failure in " . titles[A_Index] . " backup! Error code: " . status . "`nDo you want to continue with the rest of the backups?",, "YesNo")
  1325.                         If result = "Yes"
  1326.                         {
  1327.                             errors++
  1328.                             Continue
  1329.                         }
  1330.                         Else
  1331.                         {
  1332.                             MsgBox(backup_count . " pastes backed up from Pastebin.com.`n" . ++errors . "occurred.`nBackups stored in local timestamped backups folder:`n" . backup_names)
  1333.                             CheckKeyState()
  1334.                             Exit()
  1335.                         }
  1336.                     }
  1337.                    
  1338.                     ; Decode bytes (WinHttp.WinHttpRequest.5.1 ResponseText wrongly decodes encoding)
  1339.                    
  1340.                     stream := ComObjCreate("adodb.stream")
  1341.                     stream.Type := 1
  1342.                     stream.Mode := 3
  1343.                     stream.Open()
  1344.                     stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1345.                     stream.Position := 0
  1346.                     stream.Type := 2
  1347.                     stream.Charset := 'UTF-8'
  1348.                     response := stream.ReadText()
  1349.                     stream.Close()
  1350.                    
  1351.                     ; Write paste to local backup directory
  1352.                    
  1353.                     backup_file := paste_backup_dir . titles[A_Index]
  1354.                     FileDelete(backup_file)
  1355.                     FileAppend(response, backup_file, "UTF-8")
  1356.                    
  1357.                     If !(FileExist(backup_file) And CheckAge(backup_file))
  1358.                     {
  1359.                         result := MsgBox("Local backup of " . titles[A_Index] . "failed! File not backed up from Pastebin.com.`nDo you want to continue with the rest of the backups?",, "YesNo")
  1360.                         If result = "Yes"
  1361.                         {
  1362.                             errors++
  1363.                             Continue
  1364.                         }
  1365.                         Else
  1366.                         {
  1367.                             MsgBox(backup_count . " pastes backed up from Pastebin.com.`n" . ++errors . "occurred.`nBackups stored in local timestamped backups folder:`n" . backup_names)
  1368.                             CheckKeyState()
  1369.                             Exit()
  1370.                         }
  1371.                     }
  1372.                     backup_count++
  1373.                     backup_names .= '`t' . titles[A_Index] . '`n'
  1374.                 }
  1375.                 If backup_count = keys.Length()
  1376.                 {
  1377.                     MsgBox(backup_count . " pastes backed up from Pastebin.com.`nBackups stored in local timestamped backups folder:`n" . backup_names)
  1378.                 }
  1379.                 Else
  1380.                 {
  1381.                     MsgBox(backup_count . " pastes backed up from Pastebin.com.`n" . errors . "occurred.`nBackups stored in local timestamped backups folder:`n" . backup_names)
  1382.                 }
  1383.             }
  1384.             Else
  1385.             {
  1386.                 DirDelete(paste_backup_dir)
  1387.                 MsgBox("Backup aborted by user. No pastes backed up.")
  1388.                 CheckKeyState()
  1389.                 Exit()
  1390.             }
  1391.         }
  1392.         Else
  1393.         {
  1394.             MsgBox("No pastes match that search query! Nothing backed up!")
  1395.             CheckKeyState()
  1396.             Exit()
  1397.         }
  1398.     }
  1399.     CancelUserInputBackup(this)
  1400.     {
  1401.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1402.         CheckKeyState()
  1403.         Exit()
  1404.     }
  1405. Return
  1406.  
  1407. ; Delete pastes based on regular expression
  1408. ^!3::
  1409.     global api_dev_key
  1410.     global api_user_key
  1411.     global pastebin_backup_dir
  1412.    
  1413.     ; Get regexp
  1414.    
  1415.     Gui := GuiCreate(, "Enter a search query (e.g., regex) for files to delete")
  1416.     Gui.Add("Text",, "Search query:")
  1417.     Gui.Add("Edit", "w400 vsearch")
  1418.     Gui.Add("Button", "default", "OK").OnEvent("Click", () => ProcessUserInputDelete(Gui))
  1419.     Gui.Add("Button", "x+5", "Cancel").OnEvent("Click", () => CancelUserInputDelete(Gui))
  1420.     Gui.OnEvent("Close", "ProcessUserInputDelete")
  1421.     Gui.OnEvent("Close", "CancelUserInputDelete")
  1422.     Gui.Show()
  1423.     Sleep(300)
  1424.     ProcessUserInputDelete(this)
  1425.     {
  1426.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1427.         regexp := saved.search
  1428.        
  1429.         ; Get list of all pastes
  1430.        
  1431.         api_results_limit := '1000'
  1432.         api_option := 'list'
  1433.         post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_results_limit=' . api_results_limit
  1434.         url := "https://pastebin.com/api/api_post.php"
  1435.         HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1436.         HttpObj.Open("POST", url)
  1437.         HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1438.         HttpObj.Send(post_fields)
  1439.        
  1440.         ; Check response
  1441.        
  1442.         stream := ComObjCreate("adodb.stream")
  1443.         stream.Type := 1
  1444.         stream.Mode := 3
  1445.         stream.Open()
  1446.         stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1447.         stream.Position := 0
  1448.         stream.Type := 2
  1449.         stream.Charset := 'UTF-8'
  1450.         response := stream.ReadText()
  1451.         stream.Close()
  1452.    
  1453.         status := HttpObj.Status
  1454.         If !status = '200'
  1455.         {
  1456.             MsgBox("Http request failure in file listing! Error code: " . status . "`nPlease make sure your configuration file is correct.")
  1457.             CheckKeyState()
  1458.             Exit()
  1459.         }
  1460.         If !(InStr(response,"paste"))
  1461.         {
  1462.             MsgBox("Could not get list of pastes to compare file names.`nPlease make sure your configuration file is correct.`n" . response)
  1463.             CheckKeyState()
  1464.             Exit()
  1465.         }
  1466.        
  1467.         ; Check to see if regexp matches any paste titles
  1468.        
  1469.         ; First grab titles and keys
  1470.        
  1471.         api_paste_key := '' ; We will extract this in order to use it when backing up and overwriting files
  1472.         start_pos := 1
  1473.         find_pos := ''
  1474.         matches := []
  1475.         response_regexp := 's)<paste_key>.*?</paste_title>'
  1476.         Loop
  1477.         {
  1478.             find_pos := RegExMatch(response, response_regexp, match, start_pos)
  1479.             If find_pos
  1480.             {
  1481.                 matches.Push(match[0])
  1482.                 start_pos := match.Pos(0) + match.Len(0)
  1483.             }
  1484.         } Until find_pos = 0
  1485.         exists := 0
  1486.         titles := []
  1487.         keys := []
  1488.         Loop matches.Length()
  1489.         {
  1490.             string := matches[A_Index]
  1491.             match_pos := RegExMatch(string, '<paste_title>(.*?)</paste_title>', title_match)
  1492.             title_match := title_match[1]
  1493.             If RegExMatch(title_match, regexp)
  1494.             {
  1495.                 match_pos := RegExMatch(string, '<paste_key>(.*?)</paste_key>', match)
  1496.                 keys.Push(match[1])
  1497.                 ;match_pos := RegExMatch(string, '<paste_title>(.*?)</paste_title>', match)
  1498.                 ;titles.Push(match[1])
  1499.                 titles.Push(title_match)
  1500.                 exists := 1
  1501.             }
  1502.         }
  1503.         If exists
  1504.         {
  1505.             ; Print out files that match and confirm delete
  1506.             message := "Do you want to delete all of these files? (Backups are still made locally.)`nList of files also copied to your computer's clipboard.`n"
  1507.             Loop titles.Length()
  1508.             {
  1509.                 message .= titles[A_Index] . '`n'
  1510.             }
  1511.             Clipboard := message
  1512.             result := MsgBox(message,, "YesNo")
  1513.             If result = "Yes"
  1514.             {
  1515.                 ; Create local backups
  1516.                 delete_count := 0
  1517.                 delete_errors := 0
  1518.                 delete_names := ''
  1519.                 Loop keys.Length()
  1520.                 {
  1521.                     api_option := 'show_paste'
  1522.                     post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . keys[A_Index]
  1523.                     url := "https://pastebin.com/api/api_raw.php"
  1524.                     HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1525.                     HttpObj.Open("POST", url)
  1526.                     HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1527.                     HttpObj.Send(post_fields)
  1528.                    
  1529.                     ; Check response
  1530.                    
  1531.                     status := HttpObj.Status
  1532.                     If !status = '200'
  1533.                     {
  1534.                         result := MsgBox("Http request failure in " . titles[A_Index] . " backup before delete! Error code: " . status . "`nDo you want to continue deleting the rest of the files?",, "YesNo")
  1535.                         If result = "Yes"
  1536.                         {
  1537.                             delete_errors++
  1538.                             Continue
  1539.                         }
  1540.                         Else
  1541.                         {
  1542.                             MsgBox(delete_count . " pastes deleted from Pastebin.com.`n" . ++delete_errors . "occurred.`nThe following files were deleted:`n" . delete_names)
  1543.                             CheckKeyState()
  1544.                             Exit()
  1545.                         }
  1546.                     }
  1547.                    
  1548.                     ; Decode bytes (WinHttp.WinHttpRequest.5.1 ResponseText wrongly decodes encoding)
  1549.                    
  1550.                     stream := ComObjCreate("adodb.stream")
  1551.                     stream.Type := 1
  1552.                     stream.Mode := 3
  1553.                     stream.Open()
  1554.                     stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1555.                     stream.Position := 0
  1556.                     stream.Type := 2
  1557.                     stream.Charset := 'UTF-8'
  1558.                     response := stream.ReadText()
  1559.                     stream.Close()
  1560.                    
  1561.                     ; Write paste to local backup directory
  1562.                    
  1563.                     backup_file := pastebin_backup_dir . titles[A_Index]
  1564.                     t := A_NOW
  1565.                     ts := FormatTime(t, "_yyyyMMdd-HHmmss")
  1566.                     backup_file := RegExReplace(backup_file, '(.*?)(\.[^.]*$)', '$1' . ts . '$2')
  1567.                     FileDelete(backup_file)
  1568.                     FileAppend(response, backup_file, "UTF-8")
  1569.                    
  1570.                     If !(FileExist(backup_file) And CheckAge(backup_file))
  1571.                     {
  1572.                         result := MsgBox("Local backup of " . titles[A_Index] . "failed! File not deleted from Pastebin.com.`nDo you want to continue deleting the rest of the files?",, "YesNo")
  1573.                         If result = "Yes"
  1574.                         {
  1575.                             delete_errors++
  1576.                             Continue
  1577.                         }
  1578.                         Else
  1579.                         {
  1580.                             MsgBox(delete_count . " pastes deleted from Pastebin.com.`n" . ++delete_errors . "occurred.`nThe following files were deleted:`n" . delete_names)
  1581.                             CheckKeyState()
  1582.                             Exit()
  1583.                         }
  1584.                     }
  1585.                 }
  1586.                
  1587.                 ; Delete pastes from Pastebin.com
  1588.                
  1589.                 Loop keys.Length()
  1590.                 {
  1591.                     api_option := 'delete'
  1592.                     post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_paste_key=' . keys[A_Index]
  1593.                     url := "https://pastebin.com/api/api_post.php"
  1594.                     HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1595.                     HttpObj.Open("POST", url)
  1596.                     HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1597.                     HttpObj.Send(post_fields)
  1598.                    
  1599.                     ; Check response
  1600.                    
  1601.                     response := HttpObj.ResponseText
  1602.                     status := HttpObj.Status
  1603.                     If !status = '200'
  1604.                     {
  1605.                         result := MsgBox("Http request failure during delete! " . titles[A_Index] . " not deleted. Error code: " . status . "`nDo you want to continue deleting the rest of the files?", "YesNo")
  1606.                         If result = "Yes"
  1607.                         {
  1608.                             delete_errors++
  1609.                             Continue
  1610.                         }
  1611.                         Else
  1612.                         {
  1613.                             MsgBox(delete_count . " pastes deleted from Pastebin.com.`n" . ++delete_errors . "occurred.`nThe following files were deleted:`n" . delete_names)
  1614.                             CheckKeyState()
  1615.                             Exit()
  1616.                         }
  1617.                     }
  1618.                     If !(InStr(response,"removed"))
  1619.                     {
  1620.                         result := MsgBox("Delete failure occurred! " . titles[A_Index] . " not deleted.`nResponse: " . response . "`nDo you want to continue deleting the rest of the files?", "YesNo")
  1621.                         If result = "Yes"
  1622.                         {
  1623.                             delete_errors++
  1624.                             Continue
  1625.                         }
  1626.                         Else
  1627.                         {
  1628.                             MsgBox(delete_count . " pastes deleted from Pastebin.com.`n" . ++delete_errors . "occurred.`nThe following files were deleted:`n" . delete_names)
  1629.                             CheckKeyState()
  1630.                             Exit()
  1631.                         }
  1632.                     }
  1633.                     delete_count++
  1634.                     delete_names .= '`t' . titles[A_Index] . '`n'
  1635.                 }
  1636.                 If delete_count = keys.Length()
  1637.                 {
  1638.                     MsgBox(delete_count . " pastes deleted from Pastebin.com.:`n" . delete_names)
  1639.                 }
  1640.                 Else
  1641.                 {
  1642.                     MsgBox(delete_count . " pastes deleted from Pastebin.com.`n" . errors . "occurred.`nThe following files were deleted:`n" . delete_names)
  1643.                 }
  1644.             }
  1645.             Else
  1646.             {
  1647.                 DirDelete(paste_backup_dir)
  1648.                 MsgBox("Delete aborted by user. No pastes deleted.")
  1649.                 CheckKeyState()
  1650.                 Exit()
  1651.             }
  1652.         }
  1653.         Else
  1654.         {
  1655.             MsgBox("No pastes match that search query! Nothing deleted!")
  1656.             CheckKeyState()
  1657.             Exit()
  1658.         }
  1659.     }
  1660.     CancelUserInputDelete(this)
  1661.     {
  1662.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1663.         CheckKeyState()
  1664.         Exit()
  1665.     }
  1666. Return
  1667.  
  1668. ; List pastes based on regular expression
  1669. ^!4::
  1670.     global api_dev_key
  1671.     global api_user_key
  1672.    
  1673.     ; Get regex for listing pastes
  1674.    
  1675.     Gui := GuiCreate(, "Enter search query for listing pastes")
  1676.     Gui.Add("Text",, "Please enter search query (regular expression):")
  1677.     Gui.Add("Edit", "w400 vsearch")
  1678.     Gui.Add("Button", "default", "OK").OnEvent("Click", () => ProcessUserInputList(Gui))
  1679.     Gui.Add("Button", "x+5", "Cancel").OnEvent("Click", () => CancelUserInputList(Gui))
  1680.     Gui.OnEvent("Close", "ProcessUserInputList")
  1681.     Gui.OnEvent("Close", "CancelUserInputList")
  1682.     Gui.Show()
  1683.     Sleep(300)
  1684.     ProcessUserInputList(this)
  1685.     {
  1686.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1687.         regexp_search := saved.search
  1688.        
  1689.         ; Check to see if the file exists by calling API for existing pastes
  1690.        
  1691.         api_results_limit := '1000'
  1692.         api_option := 'list'
  1693.         post_fields := 'api_option=' . api_option . '&api_user_key=' . api_user_key . '&api_dev_key=' . api_dev_key . '&api_results_limit=' . api_results_limit
  1694.         url := "https://pastebin.com/api/api_post.php"
  1695.         HttpObj := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  1696.         HttpObj.Open("POST", url)
  1697.         HttpObj.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
  1698.         HttpObj.Send(post_fields)
  1699.        
  1700.         ; Check response
  1701.        
  1702.         stream := ComObjCreate("adodb.stream")
  1703.         stream.Type := 1
  1704.         stream.Mode := 3
  1705.         stream.Open()
  1706.         stream.Write(HttpObj.ResponseBody) ; get bytes from ResponseBody
  1707.         stream.Position := 0
  1708.         stream.Type := 2
  1709.         stream.Charset := 'UTF-8'
  1710.         response := stream.ReadText()
  1711.         stream.Close()
  1712.         status := HttpObj.Status
  1713.        
  1714.         If !status = '200'
  1715.         {
  1716.             MsgBox("Http request failure in file listing! Error code: " . status . "`nPlease make sure your configuration file is correct.")
  1717.             CheckKeyState()
  1718.             Exit()
  1719.         }
  1720.         If !(InStr(response,"paste"))
  1721.         {
  1722.             MsgBox("Could not get list of pastes to compare file names.`nPlease make sure your configuration file is correct.`n" . response)
  1723.             CheckKeyState()
  1724.             Exit()
  1725.         }
  1726.        
  1727.         ; Check to see if any filenames match the regular expression
  1728.        
  1729.         start_pos := 1
  1730.         find_pos := ''
  1731.         matches := []
  1732.         response_regexp := 's)<paste_key>.*?</paste_title>'
  1733.         Loop
  1734.         {
  1735.             find_pos := RegExMatch(response, response_regexp, match, start_pos)
  1736.             If find_pos
  1737.             {
  1738.                 matches.Push(match[0])
  1739.                 start_pos := match.Pos(0) + match.Len(0)
  1740.             }
  1741.         } Until find_pos = 0
  1742.         list_results := ''
  1743.         result_count := 0
  1744.         Loop matches.Length()
  1745.         {
  1746.             string := matches[A_Index]
  1747.             match_pos := RegExMatch(string, '<paste_title>(.*?)</paste_title>', title_match)
  1748.             title_match := title_match[1]
  1749.             If RegExMatch(title_match, regexp_search)
  1750.             {
  1751.                 match_pos := RegExMatch(string, '<paste_key>(.*?)</paste_key>', key_match)
  1752.                 key_match := "https://pastebin.com/" . key_match[1]
  1753.                 list_results .= title_match . '`n' . key_match . '`n`n'
  1754.                 result_count++
  1755.             }
  1756.         }
  1757.         list_results := 'You have ' . result_count . ' pastes.`n`n' . list_results
  1758.         If list_results
  1759.         {
  1760.             Clipboard := list_results
  1761.             MsgBox(result_count . ' search results copied to clipboard.')
  1762.             CheckKeyState()
  1763.             Exit()
  1764.         }
  1765.         Else
  1766.         {
  1767.             MsgBox('0 search results.')
  1768.             CheckKeyState()
  1769.             Exit()
  1770.         }
  1771.     }
  1772.     CancelUserInputList(this)
  1773.     {
  1774.         saved := this.Submit()  ; Save the contents of named controls into an object.
  1775.         CheckKeyState()
  1776.         Exit()
  1777.     }
  1778. Return
  1779.  
  1780. ; Login to Pastebin.com (Default browser is Opera)
  1781. ^!5::
  1782.     global api_user_name
  1783.     global api_user_password
  1784.     win_title := "ahk_class Chrome_WidgetWin_1" ; Opera (found with Window Spy)
  1785.     tab_title := "Pastebin.com - Login Page"
  1786.     run_command := "https://pastebin.com/login"
  1787.     OpenWindowPastebin(win_title, tab_title, run_command, api_user_name, api_user_password)
  1788.     CheckKeyState()
  1789. Return
  1790.  
  1791. ; Add files/folders to the configuration/sync.txt file
  1792. ^!6::
  1793.     global sync_file
  1794.     global files_folders
  1795.     global pastebin_backup_dir
  1796.    
  1797.     old_clipboard := ClipboardAll
  1798.     Clipboard := ""
  1799.     SendInput("^c")
  1800.     Clipwait(1.0)
  1801.     If ErrorLevel
  1802.     {
  1803.         MsgBox("Clipboard operation failed!")
  1804.         Clipboard := old_clipboard
  1805.         CheckKeyState()
  1806.         Exit()
  1807.     }
  1808.     new_files_folders := files_folders
  1809.     Loop Parse, Clipboard, "`n", "`r"
  1810.     {
  1811.         new_files_folders .= "`r`n" . A_LoopField
  1812.     }
  1813.    
  1814.     backup_sync_file := pastebin_backup_dir . "\sync.txt"
  1815.     FileCopy(sync_file, backup_sync_file, '1')
  1816.     If !(FileExist(backup_sync_file) And CheckAgeConfig(sync_file, backup_sync_file))
  1817.     {
  1818.         MsgBox("Local backup of " . sync_file . " failed! Aborting sync file update...")
  1819.         Clipboard := old_clipboard
  1820.         CheckKeyState()
  1821.         Exit()
  1822.     }
  1823.     FileDelete(sync_file)
  1824.     FileAppend(new_files_folders, sync_file, "UTF-8")
  1825.     MsgBox("Your sync file contains the following files:`n" . new_files_folders)
  1826.     CheckKeyState()
  1827.     Reload
  1828. Return
  1829.  
  1830. ; Remove files/folders to the configuration/sync.txt file
  1831. ^!7::
  1832.     global sync_file
  1833.     global files_folders
  1834.     global pastebin_backup_dir
  1835.    
  1836.     old_clipboard := ClipboardAll
  1837.     Clipboard := ""
  1838.     SendInput("^c")
  1839.     Clipwait(1.0)
  1840.     If ErrorLevel
  1841.     {
  1842.         MsgBox("Clipboard operation failed!")
  1843.         Clipboard := old_clipboard
  1844.         CheckKeyState()
  1845.         Exit()
  1846.     }
  1847.     remove_files_folders := Clipboard
  1848.     new_files_folders := ""
  1849.     Loop Parse, files_folders, "`n", "`r"
  1850.     {
  1851.         path := A_LoopField
  1852.         path := RegExReplace(path, "([\.\^\$\*\+\?\(\)\[\{\\\|])", '\$1') ;escape path for regex
  1853.         If !RegExMatch(remove_files_folders, "m)^" . path . "$")
  1854.         {
  1855.             new_files_folders .= A_LoopField . "`r`n"
  1856.         }
  1857.     }
  1858.     new_files_folders := RTrim(new_files_folders, "`r`n")
  1859.    
  1860.     backup_sync_file := pastebin_backup_dir . "\sync.txt"
  1861.     FileCopy(sync_file, backup_sync_file, '1')
  1862.     If !(FileExist(backup_sync_file) And CheckAgeConfig(sync_file, backup_sync_file))
  1863.     {
  1864.         MsgBox("Local backup of " . sync_file . " failed! Aborting sync file update...")
  1865.         Clipboard := old_clipboard
  1866.         CheckKeyState()
  1867.         Exit()
  1868.     }
  1869.     FileDelete(sync_file)
  1870.     FileAppend(new_files_folders, sync_file, "UTF-8")
  1871.     remove_files_folders := RTrim(remove_files_folders, "`n`r")
  1872.     MsgBox("Removed the following files and folders to your sync file:`n" . remove_files_folders)
  1873.     CheckKeyState()
  1874.     Reload
  1875. Return
  1876.  
  1877. ; Help message
  1878. ^!h::
  1879.     help_message := "1. Sync your files/folders = ^!1 (Ctrl+Alt+1)`n2. Backup pastes = ^!2 (Ctrl+Alt+2)`n3. Delete pastes = ^!3 (Ctrl+Alt+3)`n4. List pastes = ^!4 (Ctrl+Alt+4)`n5. Log into pastebin.com (Opera only) = ^!5 (Ctrl+Alt+5)`n6. Add to sync path = ^!6 (Ctrl+Alt+6)`n7. Remove from sync path = ^!7 (Ctrl+Alt+7)`n8. Help message = ^!h (Ctrl+Alt+h)"
  1880.     MsgBox(help_message)
  1881.     CheckKeyState()
  1882. Return
Add Comment
Please, Sign In to add comment