Advertisement
Guest User

FTP by Basshunter

a guest
Nov 2nd, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 8.59 KB | None | 0 0
  1. // Very very basic FTP by Basshunter
  2.  
  3. #if defined ftp_included
  4.     #endinput
  5. #endif
  6. #define ftp_included
  7. #pragma library ftp
  8.  
  9. #include <a_samp>
  10. #include <socket>
  11. #tryinclude <sscanf2>
  12.  
  13. #undef INVALID_SOCKET
  14. #define INVALID_SOCKET Socket:(-1) // warning miatt
  15.  
  16. #define INVALID_FTP_ID -1
  17. #define MAX_FTP 255
  18. #define MAX_PATH_LEN 255
  19. #define MAX_USER_LEN 32
  20. #define MAX_PASS_LEN 32
  21. #define MAX_IPV4_LEN 15 // 4*3 szám + 3 pont
  22.  
  23. #define NO_REASON 0
  24. #define NEED_ACCOUNT_FOR_LOGIN 1
  25. #define USERNAME_OK_NEED_PASSWORD 2
  26. #define INVALID_USERNAME_OR_PASSWORD 3
  27. #define CONNECTION_TIMED_OUT 4
  28. #define NOT_LOGGED_IN 5
  29.  
  30. forward OnFTPConnected(ftpId);
  31. forward OnFTPDisconnected(ftpId, reason);
  32. forward OnFTPReceiveCode(ftpId, code);
  33. forward OnFTPFileNotFound(ftpId, file[]);
  34. forward OnFileDownloaded(ftpId, file[], savedAs[]);
  35.  
  36. enum ftpEnum {
  37.     bool:Active,
  38.     bool:Connected,
  39.     bool:Downloading,
  40.     bool:PasswordGived,
  41.     Socket:SocketId,
  42.     Socket:DataSocketId,
  43.     File[MAX_PATH_LEN],
  44.     SaveAs[MAX_PATH_LEN]
  45. }
  46.  
  47. new ftpData[MAX_FTP][ftpEnum];
  48.  
  49. stock CreateFTP(host[], port, user[] = "", pass[] = "") {
  50.     new ftpId = 0;
  51.     for (; ftpId < MAX_FTP; ftpId++) if (!ftpData[ftpId][Active]) break;
  52.     if (ftpId == MAX_FTP) return INVALID_FTP_ID;
  53.     ftpData[ftpId][SocketId] = socket_create(TCP);
  54.     ftpData[ftpId][DataSocketId] = socket_create(TCP);
  55.     if (is_socket_valid(ftpData[ftpId][SocketId]) && is_socket_valid(ftpData[ftpId][DataSocketId])) {
  56.         socket_connect(ftpData[ftpId][SocketId], host, port);
  57.         new formatstring[256] = "";
  58.         if (strlen(user) > 0) {
  59.             format(formatstring, sizeof(formatstring), "USER %s\r\n", user);
  60.         }
  61.         if (strlen(pass) > 0) {
  62.             format(formatstring, sizeof(formatstring), "%sPASS %s\r\n", formatstring, pass);
  63.             ftpData[ftpId][PasswordGived] = true;
  64.         }
  65.         else ftpData[ftpId][PasswordGived] = false;
  66.         format(formatstring, sizeof(formatstring), "%sCWD /\r\nPWD\r\n", formatstring);
  67.         socket_send(ftpData[ftpId][SocketId], formatstring, strlen(formatstring));
  68.         ftpData[ftpId][Active] = true;
  69.         ftpData[ftpId][Connected] = false;
  70.         ftpData[ftpId][Downloading] = false;
  71.         ftpData[ftpId][File][0] = '\0';
  72.         ftpData[ftpId][SaveAs][0] = '\0';
  73.         return ftpId;
  74.     }
  75.     return INVALID_FTP_ID;
  76. }
  77.  
  78. stock DestroyFTP(ftpId, reason = NO_REASON) {
  79.     if (!ftpData[ftpId][Active]) return 1;
  80.     if (is_socket_valid(ftpData[ftpId][SocketId])) {
  81.         socket_send(ftpData[ftpId][SocketId], "QUIT\r\n", strlen("QUIT\r\n"));
  82.         socket_destroy(ftpData[ftpId][SocketId]);
  83.     }
  84.     if (is_socket_valid(ftpData[ftpId][DataSocketId])) {
  85.         socket_send(ftpData[ftpId][DataSocketId], "QUIT\r\n", strlen("QUIT\r\n"));
  86.         socket_destroy(ftpData[ftpId][DataSocketId]);
  87.     }
  88.     ftpData[ftpId][Connected] = false;
  89.     ftpData[ftpId][File][0] = '\0';
  90.     ftpData[ftpId][SaveAs][0] = '\0';
  91.     ftpData[ftpId][Active] = false;
  92.     CallRemoteFunction("OnFTPDisconnected", "ii", ftpId, reason);
  93.     return 0;
  94. }
  95.  
  96. stock DownloadFTP(ftpId, file[], saveAs[], bool:binary = false) {
  97.     // Mondanám, hogy a letöltés még szebb lenne pl egy queue-val de m1 :D
  98.     if (!ftpData[ftpId][Active] || ftpData[ftpId][Downloading]) return 0;
  99.     memcpy(ftpData[ftpId][File], file, 0, MAX_PATH_LEN * 4, MAX_PATH_LEN);
  100.     memcpy(ftpData[ftpId][SaveAs], saveAs, 0, MAX_PATH_LEN * 4, MAX_PATH_LEN);
  101.     new formatstring[128];
  102.     format(formatstring, sizeof(formatstring), "TYPE %c\r\nPASV\r\n", binary ? 'I' : 'A');
  103.     socket_send(ftpData[ftpId][SocketId], formatstring, strlen(formatstring));
  104.     ftpData[ftpId][Downloading] = true;
  105.     return 1;
  106. }
  107.  
  108. public onSocketAnswer(Socket:id, data[], data_len) {
  109.     // FTP id behatárolása
  110.     new
  111.         bool:dataSocket = false,
  112.         ftpId = 0;
  113.     for (; ftpId < MAX_FTP; ftpId++) {
  114.         if (ftpData[ftpId][SocketId] == id) break;
  115.         if (ftpData[ftpId][DataSocketId] == id) {
  116.             dataSocket = true;
  117.             break;
  118.         }
  119.     }
  120.     if (ftpId == INVALID_FTP_ID) return 1;
  121.     if (!ftpData[ftpId][Connected] && !ftpData[ftpId][PasswordGived]) {
  122.         CallRemoteFunction("OnFTPConnected", "i", ftpId);
  123.         ftpData[ftpId][Connected] = true;
  124.     }
  125.     if (dataSocket) {
  126.         if (ftpData[ftpId][File][0] != '\0') {
  127.             //printf("[FTP #%i DATA] %s", ftpId, data);
  128.             new File:downloaded = fopen(ftpData[ftpId][SaveAs], io_write);
  129.             //fwrite(downloaded, data);
  130.             //for (new i = 0; i < data_len; i++) printf("%i", getarg(1,i));
  131.             for (new i = 0; i < data_len; i++) {
  132.                 fputchar(downloaded, data[i] & 255, false);
  133.                 //printf("%i", data[i] & 255);
  134.             }
  135.             fclose(downloaded);
  136.             new tmpFile[MAX_PATH_LEN], tmpSaveAs[MAX_PATH_LEN];
  137.             format(tmpFile, MAX_PATH_LEN, ftpData[ftpId][File]);
  138.             format(tmpSaveAs, MAX_PATH_LEN, ftpData[ftpId][SaveAs]);
  139.             ftpData[ftpId][File][0] = '\0';
  140.             ftpData[ftpId][SaveAs][0] = '\0';
  141.             ftpData[ftpId][Downloading] = false;
  142.             CallRemoteFunction("OnFileDownloaded", "iss", ftpId, tmpFile, tmpSaveAs);
  143.         }
  144.     }
  145.     else {
  146.         new File:temp = ftemp();
  147.         fwrite(temp, data);
  148.         fseek(temp, 0, seek_start); // fájl elejére ugrás
  149.         new line[256];
  150.         // Soronként olvasás...
  151.         while (fread(temp, line, sizeof(line)) && ftpData[ftpId][Active]) {
  152.             new code = GetFTPCode(line);
  153.             switch (code) {
  154.                 // https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
  155.                 // Alkalmazva a teljesség igénye nélkül... :D
  156.                 case 227: {
  157.                     new host[MAX_IPV4_LEN], port;
  158.                     GetIPAndPort(line, host, MAX_IPV4_LEN, port);
  159.                     if (port) {
  160.                         printf("[FTP #%i] Szerver altal felkinalt port: %s:%i", ftpId, host, port);
  161.                         ftpData[ftpId][DataSocketId] = socket_create(TCP);
  162.                         if (is_socket_valid(ftpData[ftpId][DataSocketId])) {
  163.                             socket_connect(ftpData[ftpId][DataSocketId], host, port);
  164.                             if (strlen(ftpData[ftpId][File])) {
  165.                                 format(line, sizeof(line), "RETR %s\r\n", ftpData[ftpId][File]);
  166.                                 socket_send(ftpData[ftpId][SocketId], line, strlen(line));
  167.                             }
  168.                         }
  169.                     }
  170.                 }
  171.                 // 230 User logged in
  172.                 case 230: {
  173.                     if (!ftpData[ftpId][Connected] && ftpData[ftpId][PasswordGived]) {
  174.                         CallRemoteFunction("OnFTPConnected", "i", ftpId);
  175.                         ftpData[ftpId][Connected] = true;
  176.                     }
  177.                 }
  178.                 // 331 User name okay, need password.
  179.                 case 331: if (!ftpData[ftpId][PasswordGived]) DestroyFTP(ftpId, USERNAME_OK_NEED_PASSWORD);
  180.                 // 332 Need account for login.
  181.                 case 332: DestroyFTP(ftpId, NEED_ACCOUNT_FOR_LOGIN);
  182.                 // 421 Connection timed out
  183.                 case 421: DestroyFTP(ftpId, CONNECTION_TIMED_OUT);
  184.                 // 430 Invalid username or password
  185.                 case 430: DestroyFTP(ftpId, INVALID_USERNAME_OR_PASSWORD);
  186.                 // 530 Not logged in
  187.                 case 530: DestroyFTP(ftpId, NOT_LOGGED_IN);
  188.                 // 550 File not found
  189.                 case 550: {
  190.                     CallRemoteFunction("OnFTPFileNotFound", "is", ftpId, ftpData[ftpId][File]);
  191.                     //printf("[FTP #%i] Fájl nem található: %s", ftpId, ftpData[ftpId][File]);
  192.                     ftpData[ftpId][File][0] = '\0';
  193.                     ftpData[ftpId][SaveAs][0] = '\0';
  194.                     ftpData[ftpId][Downloading] = false;
  195.                 }
  196.                 default: CallRemoteFunction("OnFTPReceiveCode", "ii", ftpId, code);
  197.             }
  198.         }
  199.         fclose(temp);
  200.     }
  201.     return 1;
  202. }
  203.  
  204. // Segédfüggvények...
  205.  
  206. // Megmondja, milyen szám van a sztring elején
  207. stock GetFTPCode(string[]) {
  208.     new code;
  209.     for (new i = 0; '0' <= string[i] <= '9'; i++) code = code * 10 + string[i] - '0';
  210.     return code;
  211. }
  212.  
  213. // A PASV által adott válaszból megmondja a hostot és a portot
  214. stock GetIPAndPort(PASVResponse[], host[], len, &port) {
  215.     // www.serv-u.com/respcode.asp?resp=227
  216.     new h[4], p[2];
  217.     // Az sscanf2 pluginban van ilyen alias így biztos nem lesz összekeverve a régebbi pawn verzióval
  218.     #if defined unformat
  219.         // Van egy újranyitott topikja a nemzetközi fórumon, ott néztem utána hogy kell használni
  220.         // P<elválasztó karakterek>, {kihagyás}, a<típus>[méret] tömb
  221.         unformat(PASVResponse, "P<(),>{s[255]}a<i>[4]a<i>[2]", h, p);
  222.     #else
  223.         // Nagyon nagyon alap, nagyon nagyon feltéve, hogy jó a bemenet! :D
  224.         new bool:openBracket = false, delims = 0, ch, i = 0;
  225.         while ((ch = PASVResponse[i++])) {
  226.             switch(ch) {
  227.                 case '(': openBracket = true;
  228.                 case ',': delims++;
  229.                 case ')': if (openBracket) break;
  230.                 case '0'..'9': {
  231.                     if (!openBracket) continue;
  232.                     if (delims < 4) h[delims] = h[delims] * 10 + ch - '0';
  233.                     else p[delims-4] = p[delims-4] * 10 + ch - '0';
  234.                 }
  235.             }
  236.         }
  237.     #endif
  238.     format(host, len, "%i.%i.%i.%i", h[0], h[1], h[2], h[3]);
  239.     port = (p[0] * 256) + p[1];
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement