1 /* FTP Functions
2    $Revision: 1.5 $
3    $Date: 2003/03/10 22:31:26 $
4    vim: sw=4 ts=4
5 */
6 
7 #define _XOPEN_SOURCE 500
8 #if defined(__DragonFly__)
9 #define __BSD_VISIBLE 1 /* for h_addr */
10 #endif
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <ctype.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netdb.h>
23 #include <time.h>
24 #include <arpa/inet.h>
25 #include <fnmatch.h>
26 #include <string.h>
27 #include "ftp.h"
28 #include "quftp.h"
29 #include "text.h"
30 
31 /*
32  * Global Variables
33  */
34 
35 /* STAT or LIST Formats
36  * %P	UNIX style permissions
37  * %L	Number of hard links
38  * %O	Owner
39  * %G	Group
40  * %S	Size
41  * %N	File Name
42  *
43  * %Y	Year
44  * %M	Month name
45  * %n	Month number
46  * %D	Day of month
47  * %h	Hour
48  * %m	Minute
49  * %s	Second
50  */
51 
52 char *stat_formats[] = {
53 	/* drwxr-xr-x   2 ftp      ftp          1024 Jan 23 21:37 incoming */
54 	"%P %L %O %G %S %M %D %h:%m %N",
55 
56 	/* d--x--x--x   2 ftp      ftp          1024 Oct 17  1998 bin */
57 	"%P %L %O %G %S %M %D %Y %N"
58 };
59 
ftp_new(void)60 struct ftpconnection *ftp_new(void) {
61 	struct ftpconnection *connection;
62 	connection = malloc(sizeof(struct ftpconnection));
63 	log(LOG_CALLS, "Creating new ftp structure at %p", connection);
64 
65 	memset(connection->hostname, 0, 64);
66 	memset(connection->system, 0, 128);
67 	memset(connection->username, 0, 32);
68 	memset(connection->password, 0, 32);
69 	memset(connection->remotedir, 0, 256);
70 	memset(connection->localdir, 0, 256);
71 	connection->port = 0;
72 	connection->status = STATUS_NEW;
73 	connection->controlfd = 0;
74 	connection->datafd = 0;
75 	connection->dataconfd = 0;
76 	return connection;
77 }
78 
ftp_connect(struct ftpconnection * connection)79 int ftp_connect(struct ftpconnection *connection) {
80 	struct hostent *hp;
81 	int response, len = 128;
82 	int readynow = 0;
83 	char *ipaddr;
84 	char resultstring[4096];
85 	struct sockaddr_in controladdr;
86 	log(LOG_CALLS, "%p", connection);
87 	if (connection->status < STATUS_WAIT_CONNECT) {
88 		return -1;
89 	}
90 	if (!connection->hostname || !*connection->hostname) {
91 		log(LOG_CRITICAL, "Must initialize struct ftpconnection first\n");
92 		return -1;
93 	}
94 	if (!(hp = (struct hostent *)gethostbyname(connection->hostname))) {
95 		log(LOG_ALERT, "Can't resolve %s: %s\n", connection->hostname, HERROR);
96 		return -1;
97 	}
98 
99 	if ((connection->controlfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
100 		perror("socket");
101 		exit(0);
102 	}
103 	log(LOG_MESSAGE, "Resolving %s", connection->hostname);
104 	fflush(stdout);
105 	memset(&controladdr, 0, sizeof(controladdr));
106 	controladdr.sin_family = AF_INET;
107 	controladdr.sin_port = htons(connection->port);
108 	memcpy((char *)&controladdr.sin_addr, hp->h_addr, hp->h_length);
109 	ipaddr = inet_ntoa(controladdr.sin_addr);
110 	log(LOG_MESSAGE, "%s resolves to %s", connection->hostname, ipaddr);
111 	if (connect(connection->controlfd, (SOCKADDR *)&controladdr, sizeof(controladdr)) < 0) {
112 		log(LOG_ALERT, "Connection refused to %s\n", connection->hostname);
113 		return -1;
114 	}
115 	if (getsockname(connection->controlfd, (SOCKADDR *)&controladdr,&len)< 0) {
116 		perror("getsockname");
117 		exit(0);
118 	}
119 	connection->localip = controladdr.sin_addr.s_addr;
120 	connection->status = STATUS_WAIT_LOGIN;
121 	while (!readynow) {
122 		response = ftp_getrc(connection, resultstring, 4096, 0);
123 		switch (response) {
124 			case 120 : log(LOG_ALERT, "Service not yet ready.. waiting for 15 seconds");
125 				   sleep(15);
126 				   break;
127 			case 220 : readynow = 1;
128 				   log(LOG_NOTICE, "Connected to %s on port %d",
129 					connection->hostname, connection->port);
130 				   break;
131 			default  : log(LOG_ALERT, "%s", ftp_error_message(response));
132 				   return response;
133 				   break;
134 		}
135 	}
136 	return 0;
137 }
138 
ftp_disconnect(struct ftpconnection * connection)139 int ftp_disconnect(struct ftpconnection *connection) {
140 	if (connection->status >= STATUS_IDLE) {
141 		int response;
142 		response = ftp_sendline(connection, "QUIT\r\n");
143 		response = ftp_getrc(connection, NULL, 0, 0);
144 		if (response == 500)
145 			log(LOG_MESSAGE, "Braindead server doesn't understand QUIT.. closing connection\n");
146 		if (close(connection->controlfd) < 0) {
147 			perror("close");
148 			exit(0);
149 		}
150 	}
151 	if (connection->hostname)
152 		log(LOG_NOTICE, "Disconnected from %s", connection->hostname);
153 	connection->controlfd = 0;
154 	return 0;
155 }
156 
ftp_reset(struct ftpconnection * connection)157 int ftp_reset(struct ftpconnection *connection) {
158 	if (connection->status >= STATUS_WAIT_LOGIN) {
159 		log(LOG_WARNING, "Still connected. Call ftp_disconnect() first!\n");
160 		return 1;
161 	}
162 	memset(connection, 0, sizeof(struct ftpconnection));
163 	connection->status = STATUS_NEW;
164 	return 0;
165 }
166 
ftp_readline(struct ftpconnection * connection)167 char *ftp_readline(struct ftpconnection *connection) {
168 	int n = 0;
169 	int length = 0;
170 	char *temp, *buffer;
171 	static char *read_line = 0;
172 
173 	if (read_line != 0) free(read_line);
174 	read_line = (char *)NULL;
175 
176 	buffer = (char *)malloc(MAX_LINE_SIZE);
177 
178 	if (connection->controlfd <= 0) {
179 		log(LOG_CRITICAL, "ftp_readline: Not connected\n");
180 		return 0;
181 	}
182 	temp = buffer;
183 	while ((n = read(connection->controlfd, temp, 1)) > 0) {
184 		if (*temp == '\r') continue;
185 		if (*temp == '\n') break;
186 		if (*temp == '\0') break;
187 		if (length == MAX_LINE_SIZE) break;
188 		temp++; length++;
189 	}
190 	if (n < 0) {
191 		perror("read");
192 		exit(0);
193 	}
194 	if (n == 0)
195 	{
196 		log(LOG_WARNING, "FTP server disconnected");
197 		return NULL;
198 	}
199 	read_line = (char *)malloc(length + 1);
200 	strncpy(read_line, buffer, length);
201 	read_line[length] = '\0';
202 	log_hex(LOG_DATA, "Read", read_line, length);
203 	return read_line;
204 }
205 
ftp_sendline(struct ftpconnection * connection,char * line)206 int ftp_sendline(struct ftpconnection *connection, char *line) {
207 	int n = 0;
208 	int size;
209 	if (!line || !*line) return 0;
210 	size = strlen(line);
211 	if (size == 0) return 0;
212 	if (connection->status <= STATUS_WAIT_CONNECT) {
213 		log(LOG_CRITICAL, "ftp_sendline: Not connected\n");
214 		return 0;
215 	}
216 	log_hex(LOG_DATA, "Sent", line, size);
217 	if ((n = write(connection->controlfd, line, size)) < 0) {
218 		perror("ftp_sendline: write");
219 	}
220 	return n;
221 }
222 
ftp_getrc(struct ftpconnection * connection,char * data,int max_size,int print_line)223 int ftp_getrc(struct ftpconnection *connection, char *data, int max_size, int print_line) {
224 	char *line;
225 	int response;
226 
227 	if (connection->status <= STATUS_WAIT_CONNECT) {
228 		log(LOG_CRITICAL, "ftp_getrc: Not connected");
229 		return 0;
230 	}
231 	while ((line = ftp_readline(connection))) {
232 		if (!*line) {
233 			log(LOG_CRITICAL, "Big bad error.. empty string returned by ftp_readline\n");
234 			break;
235 		}
236 		if (print_line)
237 		{
238 			if (line[0] == ' ')
239 				log(LOG_WARNING, "%s", (char *)(line + 1));
240 			else
241 				log(LOG_WARNING, "%s", (char *)(line + 4));
242 		}
243 		if (IS_NUMBER(line[0]) && IS_NUMBER(line[1]) && IS_NUMBER(line[2]) && line[3] == ' ')
244 			break;
245 	}
246 	if (!line || !*line) return 0;
247 	sscanf(line, "%d ", &response);
248 	log(LOG_INFO, "ftp_getrc() = %d", response);
249 	if (data)
250 		strncpy(data, (line + 4), max_size);
251 	if (response >= 100)
252 		return response;
253 	return 0;
254 }
255 
ftp_parse_pasv(char * line,char * address)256 int ftp_parse_pasv(char *line, char *address) {
257 	int h1, h2, h3, h4, p1, p2, port;
258 	if (line == NULL) return 0;
259 	sscanf(line, "%i,%i,%i,%i,%i,%i", &h1, &h2, &h3, &h4, &p1, &p2);
260 	port = (p1 << 8) + p2;
261 	sprintf(address, "%d.%d.%d.%d", h1, h2, h3, h4);
262 	return port;
263 }
264 
ftp_parse_permissions(char * perm)265 int ftp_parse_permissions(char *perm) {
266 	int permissions = 0;
267 	if (perm[1] != 'r' && perm[1] != '-') return -1;
268 	if (perm[0] == 'd') permissions |= 2048;
269 	if (perm[1] == 'r') permissions |= 256;
270 	if (perm[2] == 'w') permissions |= 128;
271 	if (perm[3] == 'x') permissions |= 64;
272 	if (perm[4] == 'r') permissions |= 32;
273 	if (perm[5] == 'w') permissions |= 16;
274 	if (perm[6] == 'x') permissions |= 8;
275 	if (perm[7] == 'r') permissions |= 4;
276 	if (perm[8] == 'w') permissions |= 2;
277 	if (perm[9] == 'x') permissions |= 1;
278 	return permissions;
279 }
280 
ftp_check_ready(struct ftpconnection * connection,int print)281 int ftp_check_ready(struct ftpconnection *connection, int print) {
282 	if (connection->status <= STATUS_WAIT_CONNECT) {
283 		if (print) log(LOG_CRITICAL, "Not connected\n");
284 		return 0;
285 	}
286 	if (connection->status == STATUS_WAIT_LOGIN) {
287 		if (print) log(LOG_ALERT, "Not logged in\n");
288 		return 0;
289 	}
290 	if (connection->status == STATUS_ERROR) {
291 		if (print) log(LOG_ALERT, "Connection is in error state!\n");
292 		return 0;
293 	}
294 	if (connection->status >= STATUS_WAITING) {
295 		if (print) log(LOG_ALERT, "Server is busy. Please wait\n");
296 		return 0;
297 	}
298 	return 1;
299 }
300 
ftp_stat(struct ftpconnection * connection,char * filename,struct filedetails * details)301 int ftp_stat(struct ftpconnection *connection, char *filename, struct filedetails *details) {
302 	char *buffer = NULL;
303 	int result = 0;
304 	if (!details) return -1;
305 	log(LOG_CALLS, "\"%s\"", filename);
306 	if (!ftp_check_ready(connection, 1)) return -1;
307 	if (details) memset(details, 0, sizeof(struct filedetails));
308 	buffer = (char *)malloc(strlen(filename) + 15);
309 	sprintf(buffer, "STAT %s\r\n", filename);
310 	ftp_sendline(connection, buffer);
311 	free(buffer);
312 	buffer = ftp_readline(connection);
313 	result = atoi(buffer);
314 	switch (result) {
315 		case 211 :
316 		case 212 :
317 		case 213 :
318 		case 250 : break;
319 		case 500 : log(LOG_ALERT, "Server doesn't understand STAT\n"); return result; break;
320 		case 501 : log(LOG_ALERT, "Bad parameters to STAT\n"); return result; break;
321 		case 502 : log(LOG_ALERT, "Server doesn't understand STAT\n"); return result; break;
322 		case 421 : log(LOG_ALERT, "Service not available\n"); return result; break;
323 		default  : log(LOG_ALERT, "Unknown response to STAT: %d\n", result); return result; break;
324 	}
325 	if (buffer[3] == '-') {
326 		/* Read a line at a time */
327 		while ((buffer = ftp_readline(connection))) {
328 			if (strstr(buffer, "total ") == buffer) continue;
329 			break;
330 		}
331 		if (buffer[0] == '2' && buffer[1] == '1') return 1;
332 		if (!buffer) {
333 			log(LOG_CRITICAL, "Disconnected!\n");
334 			ftp_disconnect(connection);
335 			return 1;
336 		}
337 		if (strstr(buffer, "/bin/ls") != 0) {
338 			ftp_readline(connection);
339 			return 10;
340 		}
341 		if (ftp_split_ls(buffer, details) == 1) {;
342 			ftp_strip_illegal(details->filename);
343 			ftp_getrc(connection, NULL, 0, 0);
344 			return 0;
345 		} else {
346 			ftp_getrc(connection, NULL, 0, 0);
347 			return 1;
348 		}
349 	} else {
350 		log(LOG_ALERT, "Bad response to STAT: %s\n", buffer);
351 	}
352 	return 0;
353 }
354 
ftp_split_ls(char * buffer,struct filedetails * details)355 int ftp_split_ls(char *buffer, struct filedetails *details) {
356 	int stat_index, complete_match = 0;
357 
358 	if (!buffer || !*buffer) return 0;
359 
360 	/* Try matching STAT output */
361 	stat_index = 0;
362 	while (stat_formats[stat_index]) {
363 		char *format_p, *buffer_p;
364 		complete_match = 1;
365 		buffer_p = buffer;
366 		format_p = stat_formats[stat_index];
367 
368 		while (*format_p) {
369 			while (*buffer_p == ' ' || *buffer_p == '\t')
370 				buffer_p++;				/* Skip whitespace */
371 			if (*format_p == '%') {
372 				switch (*++format_p) {
373 					case '%' : if (*buffer_p == '%') {	/* %% means a literal % character */
374 								   buffer_p++;
375 							   } else {
376 								   complete_match = 0;
377 							   }
378 							   break;
379 					case 'P' : { char *permissions_p; /* UNIX style permissions */
380 							   char *permissions = (char *)malloc(4096);
381 							   memset(permissions, 0, 4096);
382 							   permissions_p = permissions;
383 							   format_p++;
384 							   while (*buffer_p && (*buffer_p != *format_p))
385 								   *permissions_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
386 							   details->permissions = ftp_parse_permissions(permissions);
387 							   if (details->permissions == 0) complete_match = 0;
388 							   free(permissions);
389 							   break; }
390 					case 'L' : { char *links_p; /* UNIX style links */
391 							   char *links = (char *)malloc(4096);
392 							   memset(links, 0, 4096);
393 							   links_p = links;
394 							   format_p++;
395 							   while (*buffer_p && (*buffer_p != *format_p))
396 								   *links_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
397 							   for (links_p = links; *links_p; links_p++)
398 								   if (*links_p < '0' || *links_p > '9') complete_match = 0;
399 							   details->links = atoi(links);
400 							   free(links);
401 							   break; }
402 					case 'O' : { char *owner_p; /* UNIX style owner */
403 							   char *owner = (char *)malloc(4096);
404 							   memset(owner, 0, 4096);
405 							   owner_p = owner;
406 							   format_p++;
407 							   while (*buffer_p && (*buffer_p != *format_p))
408 								   *owner_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
409 							   strncpy(details->owner, owner, 63);
410 							   free(owner);
411 							   break; }
412 					case 'G' : { char *group_p; /* UNIX style group */
413 							   char *group = (char *)malloc(4096);
414 							   memset(group, 0, 4096);
415 							   group_p = group;
416 							   format_p++;
417 							   while (*buffer_p && (*buffer_p != *format_p))
418 								   *group_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
419 							   strncpy(details->group, group, 63);
420 							   free(group);
421 							   break; }
422 					case 'S' : { char *size_p; /* UNIX style size */
423 							   char *size = (char *)malloc(4096);
424 							   memset(size, 0, 4096);
425 							   size_p = size;
426 							   format_p++;
427 							   while (*buffer_p && (*buffer_p != *format_p))
428 								   *size_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
429 							   for (size_p = size; *size_p; size_p++)
430 								   if (*size_p < '0' || *size_p > '9') complete_match = 0;
431 							   details->size = atol(size);
432 							   free(size);
433 							   break; }
434 					case 'N' : { char *filename_p; /* UNIX style filename */
435 							   char *filename = (char *)malloc(4096);
436 							   memset(filename, 0, 4096);
437 							   filename_p = filename;
438 							   format_p++;
439 							   while (*buffer_p && (*buffer_p != *format_p))
440 								   *filename_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
441 							   strncpy(details->filename, filename, 254);
442 							   free(filename);
443 							   break; }
444 					case 'Y' : { char *year_p; /* UNIX style year */
445 							   char *year = (char *)malloc(4096);
446 							   memset(year, 0, 4096);
447 							   year_p = year;
448 							   format_p++;
449 							   while (*buffer_p && (*buffer_p != *format_p))
450 								   *year_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
451 							   for (year_p = year; *year_p; year_p++)
452 								   if (*year_p < '0' || *year_p > '9') complete_match = 0;
453 							   free(year);
454 							   break; }
455 					case 'M' : { char *month_p; /* UNIX style month name */
456 							   char *month = (char *)malloc(4096);
457 							   memset(month, 0, 4096);
458 							   month_p = month;
459 							   format_p++;
460 							   while (*buffer_p && (*buffer_p != *format_p))
461 								   *month_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
462 							   free(month);
463 							   break; }
464 					case 'n' : { char *month_p; /* UNIX style month number */
465 							   char *month = (char *)malloc(4096);
466 							   memset(month, 0, 4096);
467 							   month_p = month;
468 							   format_p++;
469 							   while (*buffer_p && (*buffer_p != *format_p))
470 								   *month_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
471 							   for (month_p = month; *month_p; month_p++)
472 								   if (*month_p < '0' || *month_p > '9') complete_match = 0;
473 							   free(month);
474 							   break; }
475 					case 'm' : { char *minute_p; /* UNIX style minute number */
476 							   char *minute = (char *)malloc(4096);
477 							   memset(minute, 0, 4096);
478 							   minute_p = minute;
479 							   format_p++;
480 							   while (*buffer_p && (*buffer_p != *format_p))
481 								   *minute_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
482 							   for (minute_p = minute; *minute_p; minute_p++)
483 								   if (*minute_p < '0' || *minute_p > '9') complete_match = 0;
484 							   free(minute);
485 							   break; }
486 					case 'D' : { char *mday_p; /* UNIX style mday number */
487 							   char *mday = (char *)malloc(4096);
488 							   memset(mday, 0, 4096);
489 							   mday_p = mday;
490 							   format_p++;
491 							   while (*buffer_p && (*buffer_p != *format_p))
492 								   *mday_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
493 							   for (mday_p = mday; *mday_p; mday_p++)
494 								   if (*mday_p < '0' || *mday_p > '9') complete_match = 0;
495 							   free(mday);
496 							   break; }
497 					case 's' : { char *second_p; /* UNIX style second number */
498 							   char *second = (char *)malloc(4096);
499 							   memset(second, 0, 4096);
500 							   second_p = second;
501 							   format_p++;
502 							   while (*buffer_p && (*buffer_p != *format_p))
503 								   *second_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
504 							   for (second_p = second; *second_p; second_p++)
505 								   if (*second_p < '0' || *second_p > '9') complete_match = 0;
506 							   free(second);
507 							   break; }
508 					case 'h' : { char *hour_p; /* UNIX style hour number */
509 							   char *hour = (char *)malloc(4096);
510 							   memset(hour, 0, 4096);
511 							   hour_p = hour;
512 							   format_p++;
513 							   while (*buffer_p && (*buffer_p != *format_p))
514 								   *hour_p++ = *buffer_p++; /* Loop and grab everything up until the next character in the format */
515 							   for (hour_p = hour; *hour_p; hour_p++)
516 								   if (*hour_p < '0' || *hour_p > '9') complete_match = 0;
517 							   free(hour);
518 							   break; }
519 					default  : log(LOG_CRITICAL, "Unknown character %c in STAT format description\n", *format_p);
520 							   break;
521 				}
522 			}
523 			if (complete_match == 0) break;
524 			if (!*format_p++) break;
525 		}
526 		if (complete_match == 1) break;
527 		stat_index++;
528 	}
529 	return complete_match;
530 }
531 
ftp_delete(struct ftpconnection * connection,char * filename)532 int ftp_delete(struct ftpconnection *connection, char *filename)  {
533 	int result;
534 	char line[4096];
535 	char resultstring[4096];
536 	if (!filename) return 0;
537 	if (!ftp_check_ready(connection, 1)) return 0;
538 	sprintf(line, "DELE %s\r\n", filename);
539 	ftp_sendline(connection, line);
540 	result = ftp_getrc(connection, resultstring, 4096, 0);
541 	switch (result) {
542 		case 250 : log(LOG_INFO, "Deleted %s\n", filename); return 1; break;
543 		case 450 : log(LOG_ALERT, "Can't delete %s: %s\n", filename, resultstring); break;
544 		case 421 : log(LOG_ALERT, "%s\n", resultstring); break;
545 		case 500 : log(LOG_ALERT, "This server does not support the DELE command\n"); break;
546 		case 501 : log(LOG_ALERT, "Invalid parameters to DELE command\n"); break;
547 		case 502 : log(LOG_ALERT, "This server does not support the DELE command\n"); break;
548 		case 530 : log(LOG_ALERT, "Not logged in correctly\n"); break;
549 		case 550 : log(LOG_ALERT, "Can't delete %s: %s\n", filename, resultstring); break;
550 		case 553 : log(LOG_ALERT, "Not allowed to delete %s\n", filename); break;
551 		default  : log(LOG_ALERT, "Unrecognised response to DELE: %d %s\n", result, resultstring);
552 			   break;
553 	}
554 	return 0;
555 }
556 
ftp_glob(struct ftpconnection * connection,char * wildcard,int status)557 char *ftp_glob(struct ftpconnection *connection, char *wildcard, int status) {
558 	static int index = 0;
559 	static char pathname[4096], working[4096];
560 	int response;
561 	static char *return_list[500];
562 	char *retstring;
563 	if (!ftp_check_ready(connection, 1)) return NULL;
564 	if (status == 0) {
565 		memset(pathname, 0, 4096);
566 		memset(working, 0, 4096);
567 		memset(return_list, 0, sizeof(*return_list) * 500);
568 		// Separate the path and filename
569 		index = strlen(wildcard);
570 		while (index) {
571 			if (wildcard[index] == '/') {
572 				strncpy(pathname, wildcard, index + 1);
573 				strncpy(working, &wildcard[index + 1], 4096);
574 				break;
575 			}
576 			index--;
577 		}
578 		if (strlen(working) == 0) strncpy(working, wildcard, 4096);
579 		response = ftp_nlst(connection, pathname, return_list, 500);
580 		if (response <= 0) return NULL;
581 		index = 0;
582 	}
583 	while (return_list[index] != NULL) {
584 		int eflags = FNM_PATHNAME | FNM_PERIOD | (1 << 3);
585 		if (fnmatch(wildcard, return_list[index], eflags) != 0) {
586 			index++;
587 			continue;
588 		}
589 		retstring = (char *)strdup(return_list[index]);
590 		return_list[index] = 0;
591 		index++;
592 		return retstring;
593 	}
594 	return NULL;
595 }
596 
ftp_exists(struct ftpconnection * connection,char * filename)597 int ftp_exists(struct ftpconnection *connection, char *filename) {
598 	/* Check if a file exists on the server */
599 	/* Return codes
600 	   < 0		Don't know
601 	     0		Doesn't exist
602 	   > 0		Does exist
603 	 */
604 	char line[4096];
605 	int result;
606 
607 	if (!filename) return 0;
608 	if (!ftp_check_ready(connection, 1)) return 0;
609 
610 	log(LOG_CALLS, "(%p, %s)", connection, filename);
611 	sprintf(line, "STAT %s\r\n", filename);
612 	ftp_sendline(connection, line);
613 	result = ftp_getrc(connection, NULL, 0, 0);
614 	switch (result) {
615 		case 213 : return 1;
616 		case 211 : return 1;
617 		case 212 : return 1;
618 		case 421 : log(LOG_ALERT, "STAT error.. %d\n", result); return -1; break;
619 		case 450 : return 0;
620 		case 500 : break;
621 		case 501 : break;
622 		case 502 : break;
623 		case 530 : log(LOG_ALERT, "Not logged in correctly\n"); return -1; break;
624 		default  : break;
625 	 }
626 	return -1;
627 }
628 
ftp_error_message(int error)629 char *ftp_error_message(int error) {
630 	switch(error) {
631 		case 110 : return "Restart marker reply"; break;
632 		case 120 : return "Service ready in nnn minutes."; break;
633 		case 125 : return "Data connection already open; transfer starting."; break;
634 		case 150 : return "File status okay; about to open data connection."; break;
635 		case 200 : return "Command okay."; break;
636 		case 202 : return "Command not implemented, superfluous at this site."; break;
637 		case 211 : return "System status, or system help reply."; break;
638 		case 212 : return "Directory status."; break;
639 		case 213 : return "File status."; break;
640 		case 214 : return "Help message."; break;
641 		case 215 : return "NAME system type."; break;
642 		case 220 : return "Service ready for new user."; break;
643 		case 221 : return "Service closing control connection."; break;
644 		case 225 : return "Data connection open; no transfer in progress."; break;
645 		case 226 : return "Closing data connection successfully."; break;
646 		case 227 : return "Entering Passive Mode (h1,h2,h3,h4,p1,p2)."; break;
647 		case 230 : return "User logged in, proceed."; break;
648 		case 250 : return "Requested file action okay, completed."; break;
649 		case 257 : return "PATHNAME created."; break;
650 		case 331 : return "User name okay, need password."; break;
651 		case 332 : return "Need account for login."; break;
652 		case 350 : return "Requested file action pending further information."; break;
653 		case 421 : return "Service not available, closing control connection."; break;
654 		case 425 : return "Can't open data connection."; break;
655 		case 426 : return "Connection closed; transfer aborted."; break;
656 		case 450 : return "Requested file action not taken - File unavailable."; break;
657 		case 451 : return "Requested action aborted: local error in processing."; break;
658 		case 452 : return "Requested action not taken - Insufficient storage space in system."; break;
659 		case 500 : return "Syntax error, command unrecognized."; break;
660 		case 501 : return "Syntax error in parameters or arguments."; break;
661 		case 502 : return "Command not implemented."; break;
662 		case 503 : return "Bad sequence of commands."; break;
663 		case 504 : return "Command not implemented for that parameter."; break;
664 		case 530 : return "Not logged in."; break;
665 		case 532 : return "Need account for storing files."; break;
666 		case 550 : return "Requested action not taken - File unavailable."; break;
667 		case 551 : return "Requested action aborted: page type unknown."; break;
668 		case 552 : return "Requested file action aborted - Exceeded storage allocation"; break;
669 		case 553 : return "Requested action not taken - File name not allowed."; break;
670 		default  : return "Unknown error";
671 	}
672 }
673 
674