-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJavaFtpClient.java
More file actions
350 lines (290 loc) · 10.3 KB
/
JavaFtpClient.java
File metadata and controls
350 lines (290 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
package FTP.Client;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Scanner;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import FTP.Util.Util;
/**
* Cliente FTP interactivo de consola.
* <p>
* Proporciona una interfaz de línea de comandos para conectarse a un servidor FTP
* y realizar operaciones como:
* <ul>
* <li>Listar, subir y descargar archivos</li>
* <li>Crear y eliminar directorios</li>
* <li>Renombrar archivos y directorios</li>
* <li>Navegar por el sistema de archivos remoto</li>
* </ul>
* <p>
* Soporta modos de transferencia ACTIVE y PASSIVE.
*
* @author Eduardo Díaz Sánchez
* @version 1.0
*/
public class JavaFtpClient {
/**
* Punto de entrada principal del cliente FTP.
* Establece conexión con el servidor, autentica al usuario y presenta un menú interactivo.
*
* @param args Argumentos de línea de comandos (no utilizados)
*/
public static void main(String[] args) {
FTPClient ftpClient = null;
ClientFunctions clientFunctions = null;
String[] hostname, userCredentials;
int replyCode, dataPort, option;
boolean login;
String mode;
boolean exit = false;
System.out.println("Cliente FTP iniciado");
try (Scanner sc = new Scanner(System.in)) {
hostname = captureHostname(sc);
boolean useTls = askUseTls(sc);
ftpClient = useTls ? new FTPSClient(false) : new FTPClient();
clientFunctions = new ClientFunctions(ftpClient);
// Configurar encoding UTF-8 para soportar acentos, ñ, etc.
ftpClient.setControlEncoding("UTF-8");
ftpClient.connect(hostname[0], Integer.parseInt(hostname[1]));
replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
throw new IOException("Error de conexión: " + replyCode);
}
System.out.println("\n" + ftpClient.getReplyString());
userCredentials = inputUserCredentials(sc);
login = ftpClient.login(userCredentials[0], userCredentials[1]);
if (!login) {
replyCode = ftpClient.getReplyCode();
throw new SecurityException("Autenticación fallida: " + replyCode);
}
Util.printGreenColor("\n" + ftpClient.getReplyString());
// Configurar modo binario (crítico para PDFs, ZIPs, imágenes)
ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
Util.printGreenColor("\nModo de transferencia binaria activado");
mode = selectMode(sc);
if (mode.equals("PASSIVE")) {
handlerPasiveMode(ftpClient, sc);
} else if (mode.equals("ACTIVE")) {
dataPort = handlerActiveMode(ftpClient, sc);
} else {
Util.printRedColor("Error: Modo de conexión elegido desconocido");
}
ftpClient.sendCommand("SYST"); // Llamamos a SYST manualmente
System.out.println("\nSYST Response: " + ftpClient.getReplyString());
do {
showMenu();
System.out.print("\nSeleccione una opción \n:> ");
try {
option = Integer.parseInt(sc.nextLine().trim());
} catch (NumberFormatException e) {
option = -1;
}
switch (option) {
case 1:
System.out.println("\nListar archivos");
clientFunctions.listFiles();
break;
case 2:
System.out.println("\nSubir archivo");
clientFunctions.uploadFile(sc);
break;
case 3:
System.out.println("\nDescargar archivo");
clientFunctions.downloadFile(sc);
break;
case 4:
System.out.println("\nEliminar archivo");
clientFunctions.deleteFile(sc);
break;
case 5:
System.out.println("\nCrear directorio");
clientFunctions.createDirectory(sc);
break;
case 6:
System.out.println("\nEliminar directorio");
clientFunctions.deleteDirectory(sc);
break;
case 7:
System.out.println("\nRenombrar archivo/directorio");
clientFunctions.renameFile(sc);
break;
case 8:
System.out.println("\nCambiar directorio de trabajo");
clientFunctions.changeWorkingDirectory(sc);
break;
case 9:
System.out.println("\nCambiar al directorio superior");
clientFunctions.changeToParentDirectory();
break;
case 10:
System.out.println("\nSaliendo del cliente FTP");
exit = true;
break;
default:
Util.printRedColor("\nOpción no válida");
break;
}
} while (!exit);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
} finally {
try {
if (ftpClient != null) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
System.out.println("Error al cerrar conexión: " + e.getMessage());
}
}
}
/**
* Pregunta si usar FTPS (AUTH TLS).
*/
private static boolean askUseTls(Scanner sc) {
System.out.println("\n¿Usar FTPS (AUTH TLS)? s/N");
System.out.print(":> ");
String input = sc.nextLine().trim();
return "s".equalsIgnoreCase(input) || "si".equalsIgnoreCase(input) || "y".equalsIgnoreCase(input);
}
/**
* Solicita y captura el hostname y puerto del servidor FTP.
*
* @param sc Scanner para leer entrada del usuario
* @return Array con [hostname, puerto]
*/
private static String[] captureHostname(Scanner sc) {
String hostname = "localhost";
String port = "21";
String input = null;
System.out.println("\nIntroduce el hostname del servidor FTP (localhost por defecto)");
System.out.print(":> ");
input = sc.nextLine().trim();
if (input != null && !input.trim().isEmpty())
hostname = input;
System.out.println("\nIntroduce el puerto (puerto 21 por defecto)");
System.out.print(":> ");
input = sc.nextLine().trim();
if (input != null && !input.trim().isEmpty())
port = input;
return new String[] {hostname, port};
}
/**
* Solicita las credenciales del usuario (nombre y contraseña).
*
* @param sc Scanner para leer entrada del usuario
* @return Array con [username, password]
*/
private static String[] inputUserCredentials(Scanner sc) {
String input = null;
String user = "";
String pass = "";
do {
System.out.println("\nIntroduce el nombre de usuario");
System.out.print(":> ");
input = sc.nextLine().trim();
if (input == null || input.trim().isEmpty()) {
Util.printRedColor("\nError: El nombre de usuario no puede estar vacío");
input = null;
}
} while (input == null);
user = input;
do {
System.out.println("\nIntroduce la contraseña");
System.out.print(":> ");
input = sc.nextLine().trim();
if (input == null || input.trim().isEmpty()) {
Util.printRedColor("Error: La contraseña no puede estar vacía");
input = null;
}
} while (input == null);
pass = input;
return new String[] {user, pass};
}
/**
* Solicita al usuario seleccionar el modo de transferencia de datos.
*
* @param sc Scanner para leer entrada del usuario
* @return "PASSIVE" o "ACTIVE"
*/
private static String selectMode(Scanner sc) {
String mode = "PASSIVE";
String input = null;
do {
System.out.println("Introduce el modo de conexión PASSIVE/ACTIVE");
System.out.print(":> ");
input = sc.nextLine().trim();
if (input == null || input.trim().isEmpty()) {
Util.printRedColor("\nError: El campo no puede estar vacío, elige un modo de conexión: PASSIVE/ACTIVE");
input = null;
} else if (!input.toUpperCase().matches("PASSIVE|ACTIVE")) {
Util.printRedColor("\nError: Debe elegir un modo de conexión CORECTO: PASSIVE/ACTIVE");
input = null;
}
} while (input == null);
mode = input.toUpperCase();
return mode;
}
/**
* Configura el cliente FTP en modo pasivo.
* En este modo, el servidor abre un puerto y el cliente se conecta a él.
*
* @param ftpClient Cliente FTP a configurar
* @param sc Scanner para entrada del usuario (no utilizado en modo pasivo)
* @throws IOException Si ocurre un error de comunicación
*/
public static void handlerPasiveMode(FTPClient ftpClient, Scanner sc) throws IOException {
ftpClient.enterLocalPassiveMode();
ftpClient.sendCommand("PASV");
Util.printGreenColor("\nModo pasivo configurado");
}
/**
* Configura el cliente FTP en modo activo.
* En este modo, el cliente abre un puerto y el servidor se conecta a él.
*
* @param ftpClient Cliente FTP a configurar
* @param sc Scanner para solicitar puerto de datos al usuario
* @return Puerto de datos abierto por el cliente
* @throws IOException Si ocurre un error de comunicación
*/
public static int handlerActiveMode(FTPClient ftpClient, Scanner sc) throws IOException {
InetAddress inetAdress;
String hostAddress, comandoPort;
int dataPort, p1, p2;
// Obtener la dirección IP local del cliente
inetAdress = ftpClient.getLocalAddress();
hostAddress = inetAdress.getHostAddress().replace(".", ",");
// Pedir al usuario que elija un puerto para la conexión de datos
System.out.println("\nPuerto para datos (ej. 5500 o superior)");
System.out.print(":> ");
dataPort = Integer.parseInt(sc.nextLine());
// Calcular la parte alta y baja del puerto
p1 = dataPort / 256;
p2 = dataPort % 256;
// Construir el comando PORT con la IP del cliente y el puerto
comandoPort = String.format("PORT %s,%d,%d", hostAddress, p1, p2);
// Cambiar a modo activo
ftpClient.enterLocalActiveMode();
// Enviar manualmente el comando PORT al servidor
ftpClient.sendCommand(comandoPort);
Util.printGreenColor("\nModo activo configurado");
return dataPort; // Devuelve el puerto que el cliente abrió
}
/**
* Muestra el menú de opciones disponibles para el cliente FTP.
*/
public static void showMenu() {
System.out.println("\n=== Menú FTP ===");
System.out.println("[1] Listar archivos");
System.out.println("[2] Subir archivo");
System.out.println("[3] Descargar archivo");
System.out.println("[4] Eliminar archivo");
System.out.println("[5] Crear directorio");
System.out.println("[6] Eliminar directorio");
System.out.println("[7] Renombrar archivo/directorio");
System.out.println("[8] Cambiar directorio de trabajo");
System.out.println("[9] Cambiar al directorio superior");
System.out.println("[10] Salir");
}
}