comparison lib/rfc959.c @ 1:8b1883341c6f

Initial revision
author masneyb
date Mon, 05 Aug 2002 19:46:57 +0000
parents
children 5551ab2301fe
comparison
equal deleted inserted replaced
0:674ed97069fd 1:8b1883341c6f
1 /*****************************************************************************/
2 /* rfc959.c - General purpose routines for the FTP protocol (RFC 959) */
3 /* Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org> */
4 /* */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program; if not, write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
18 /*****************************************************************************/
19
20 #include "gftp.h"
21
22 static int rfc959_connect ( gftp_request * request );
23 static void rfc959_disconnect ( gftp_request * request );
24 static long rfc959_get_file ( gftp_request * request,
25 const char *filename,
26 FILE * fd,
27 off_t startsize );
28 static int rfc959_put_file ( gftp_request * request,
29 const char *filename,
30 FILE * fd,
31 off_t startsize,
32 off_t totalsize );
33 static long rfc959_transfer_file ( gftp_request *fromreq,
34 const char *fromfile,
35 off_t fromsize,
36 gftp_request *toreq,
37 const char *tofile,
38 off_t tosize );
39 static int rfc959_end_transfer ( gftp_request * request );
40 static int rfc959_list_files ( gftp_request * request );
41 static int rfc959_set_data_type ( gftp_request * request,
42 int data_type );
43 static off_t rfc959_get_file_size ( gftp_request * request,
44 const char *filename );
45 static int rfc959_data_connection_new ( gftp_request * request );
46 static int rfc959_accept_active_connection ( gftp_request * request );
47 static int rfc959_send_command ( gftp_request * request,
48 const char *command );
49 static int write_to_socket ( gftp_request *request,
50 const char *command );
51 static int rfc959_read_response ( gftp_request * request );
52 static int rfc959_chdir ( gftp_request * request,
53 const char *directory );
54 static int rfc959_rmdir ( gftp_request * request,
55 const char *directory );
56 static int rfc959_rmfile ( gftp_request * request,
57 const char *file );
58 static int rfc959_mkdir ( gftp_request * request,
59 const char *directory );
60 static int rfc959_rename ( gftp_request * request,
61 const char *oldname,
62 const char *newname );
63 static int rfc959_chmod ( gftp_request * request,
64 const char *file,
65 int mode );
66 static int rfc959_site ( gftp_request * request,
67 const char *command );
68 static char *parse_ftp_proxy_string ( gftp_request * request );
69
70 void
71 rfc959_init (gftp_request * request)
72 {
73 g_return_if_fail (request != NULL);
74
75 request->protonum = GFTP_FTP_NUM;
76 request->init = rfc959_init;
77 request->destroy = NULL;
78 request->connect = rfc959_connect;
79 request->disconnect = rfc959_disconnect;
80 request->get_file = rfc959_get_file;
81 request->put_file = rfc959_put_file;
82 request->transfer_file = rfc959_transfer_file;
83 request->get_next_file_chunk = NULL;
84 request->put_next_file_chunk = NULL;
85 request->end_transfer = rfc959_end_transfer;
86 request->list_files = rfc959_list_files;
87 request->get_next_file = rfc959_get_next_file;
88 request->set_data_type = rfc959_set_data_type;
89 request->get_file_size = rfc959_get_file_size;
90 request->chdir = rfc959_chdir;
91 request->rmdir = rfc959_rmdir;
92 request->rmfile = rfc959_rmfile;
93 request->mkdir = rfc959_mkdir;
94 request->rename = rfc959_rename;
95 request->chmod = rfc959_chmod;
96 request->set_file_time = NULL;
97 request->site = rfc959_site;
98 request->parse_url = NULL;
99 request->url_prefix = "ftp";
100 request->protocol_name = "FTP";
101 request->need_hostport = 1;
102 request->need_userpass = 1;
103 request->use_cache = 1;
104 request->use_threads = 1;
105 request->always_connected = 0;
106 gftp_set_config_options (request);
107 }
108
109
110 static int
111 rfc959_connect (gftp_request * request)
112 {
113 char tempchar, *startpos, *endpos, *tempstr, *dir;
114 int sock, ret, resp;
115
116 g_return_val_if_fail (request != NULL, -2);
117 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
118 g_return_val_if_fail (request->hostname != NULL, -2);
119 g_return_val_if_fail (request->username != NULL, -2);
120
121 if (request->sockfd != NULL)
122 return (0);
123
124 if ((sock = gftp_connect_server (request, "ftp")) < 0)
125 return (-1);
126
127 if ((request->sockfd = fdopen (sock, "rb")) == NULL)
128 {
129 request->logging_function (gftp_logging_error, request->user_data,
130 _("Cannot fdopen() socket: %s\n"),
131 g_strerror (errno));
132 close (sock);
133 return (-2);
134 }
135
136 if ((request->sockfd_write = fdopen (dup (sock), "wb")) == NULL)
137 {
138 request->logging_function (gftp_logging_error, request->user_data,
139 _("Cannot fdopen() socket: %s\n"),
140 g_strerror (errno));
141 gftp_disconnect (request);
142 return (-2);
143 }
144
145 /* Get the banner */
146 if (rfc959_read_response (request) != '2')
147 {
148 gftp_disconnect (request);
149 return (-2);
150 }
151
152 /* Login the proxy server if available */
153 if (request->use_proxy)
154 {
155 resp = '3';
156 startpos = endpos = tempstr = parse_ftp_proxy_string (request);
157 while ((resp == '3' || resp == '2') && *startpos != '\0')
158 {
159 if (*endpos == '\n' || *endpos == '\0')
160 {
161 tempchar = *(endpos + 1);
162 if (*endpos != '\0')
163 *(endpos + 1) = '\0';
164 if ((resp = rfc959_send_command (request, startpos)) < 0)
165 return (-2);
166 if (*endpos != '\0')
167 *(endpos + 1) = tempchar;
168 else
169 break;
170 startpos = endpos + 1;
171 }
172 endpos++;
173 }
174 g_free (tempstr);
175 }
176 else
177 {
178 tempstr = g_strconcat ("USER ", request->username, "\r\n", NULL);
179 resp = rfc959_send_command (request, tempstr);
180 g_free (tempstr);
181 if (resp < 0)
182 return (-2);
183 if (resp == '3')
184 {
185 tempstr = g_strconcat ("PASS ", request->password, "\r\n", NULL);
186 resp = rfc959_send_command (request, tempstr);
187 g_free (tempstr);
188 if (resp < 0)
189 return (-2);
190 }
191 if (resp == '3' && request->account)
192 {
193 tempstr = g_strconcat ("ACCT ", request->account, "\r\n", NULL);
194 resp = rfc959_send_command (request, tempstr);
195 g_free (tempstr);
196 if (resp < 0)
197 return (-2);
198 }
199 }
200
201 if (resp != '2')
202 {
203 gftp_disconnect (request);
204 return (-2);
205 }
206
207 if (request->data_type == GFTP_TYPE_BINARY)
208 tempstr = "TYPE I\r\n";
209 else
210 tempstr = "TYPE A\r\n";
211
212 if (rfc959_send_command (request, tempstr) < 0)
213 return (-2);
214
215 ret = -1;
216 if (request->directory != NULL && *request->directory != '\0')
217 {
218 ret = rfc959_chdir (request, request->directory);
219 if (request->sockfd == NULL)
220 return (-2);
221 }
222
223 if (ret != 0)
224 {
225 if (rfc959_send_command (request, "PWD\r\n") != '2' ||
226 request->sockfd == NULL)
227 {
228 gftp_disconnect (request);
229 return (-2);
230 }
231
232 if ((tempstr = strchr (request->last_ftp_response, '"')) == NULL)
233 {
234 gftp_disconnect (request);
235 return (-2);
236 }
237 dir = tempstr + 1;
238
239 if ((tempstr = strchr (dir, '"')) == NULL)
240 {
241 gftp_disconnect (request);
242 return (0);
243 }
244 if (tempstr != NULL)
245 *tempstr = '\0';
246
247 request->directory = g_malloc (strlen (dir) + 1);
248 strcpy (request->directory, dir);
249 }
250
251 if (request->sockfd == NULL)
252 return (-2);
253
254 return (0);
255 }
256
257
258 static void
259 rfc959_disconnect (gftp_request * request)
260 {
261 g_return_if_fail (request != NULL);
262 g_return_if_fail (request->protonum == GFTP_FTP_NUM);
263
264 if (request->sockfd != NULL)
265 {
266 request->logging_function (gftp_logging_misc, request->user_data,
267 _("Disconnecting from site %s\n"),
268 request->hostname);
269 fclose (request->sockfd);
270 fclose (request->sockfd_write);
271 request->sockfd = request->sockfd_write = NULL;
272 if (request->datafd)
273 {
274 fclose (request->datafd);
275 request->datafd = NULL;
276 }
277 }
278 }
279
280
281 static long
282 rfc959_get_file (gftp_request * request, const char *filename, FILE * fd,
283 off_t startsize)
284 {
285 char *command, *tempstr, resp;
286 int ret, flags;
287
288 g_return_val_if_fail (request != NULL, -2);
289 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
290 g_return_val_if_fail (filename != NULL, -2);
291 g_return_val_if_fail (request->sockfd != NULL, -2);
292
293 if (fd != NULL)
294 request->datafd = fd;
295
296 if (request->datafd == NULL &&
297 (ret = rfc959_data_connection_new (request)) < 0)
298 return (ret);
299
300 flags = fcntl (fileno (request->datafd), F_GETFL, 0);
301 if (fcntl (fileno (request->datafd), F_SETFL, flags | O_NONBLOCK) < 0)
302 {
303 fclose (request->datafd);
304 request->datafd = NULL;
305 return (-1);
306 }
307
308 if (startsize > 0)
309 {
310 command = g_strdup_printf ("REST %ld\r\n", startsize);
311 resp = rfc959_send_command (request, command);
312 g_free (command);
313
314 if (resp != '3')
315 {
316 fclose (request->datafd);
317 request->datafd = NULL;
318 return (-2);
319 }
320 }
321
322 tempstr = g_strconcat ("RETR ", filename, "\r\n", NULL);
323 ret = rfc959_send_command (request, tempstr);
324 g_free (tempstr);
325
326 if (ret != '1')
327 {
328 fclose (request->datafd);
329 request->datafd = NULL;
330 return (-2);
331 }
332
333 if (request->transfer_type == gftp_transfer_active &&
334 (ret = rfc959_accept_active_connection (request)) < 0)
335 return (ret);
336
337 if ((tempstr = strrchr (request->last_ftp_response, '(')) == NULL)
338 {
339 tempstr = request->last_ftp_response + 4;
340 while (!isdigit ((int) *tempstr) && *tempstr != '\0')
341 tempstr++;
342 }
343 else
344 tempstr++;
345
346 return (strtol (tempstr, NULL, 10) + startsize);
347 }
348
349
350 static int
351 rfc959_put_file (gftp_request * request, const char *filename, FILE * fd,
352 off_t startsize, off_t totalsize)
353 {
354 char *command, *tempstr, resp;
355 int ret, flags;
356
357 g_return_val_if_fail (request != NULL, -2);
358 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
359 g_return_val_if_fail (filename != NULL, -2);
360 g_return_val_if_fail (request->sockfd != NULL, -2);
361
362 if (fd != NULL)
363 fd = request->datafd;
364
365 if (request->datafd == NULL &&
366 (ret = rfc959_data_connection_new (request)) < 0)
367 return (ret);
368
369 flags = fcntl (fileno (request->datafd), F_GETFL, 0);
370 if (fcntl (fileno (request->datafd), F_SETFL, flags | O_NONBLOCK) < 0)
371 {
372 fclose (request->datafd);
373 request->datafd = NULL;
374 return (-1);
375 }
376
377 if (startsize > 0)
378 {
379 command = g_strdup_printf ("REST %ld\r\n", startsize);
380 resp = rfc959_send_command (request, command);
381 g_free (command);
382 if (resp != '3')
383 {
384 fclose (request->datafd);
385 request->datafd = NULL;
386 return (-2);
387 }
388 }
389
390 tempstr = g_strconcat ("STOR ", filename, "\r\n", NULL);
391 ret = rfc959_send_command (request, tempstr);
392 g_free (tempstr);
393 if (ret != '1')
394 {
395 fclose (request->datafd);
396 request->datafd = NULL;
397 return (-2);
398 }
399
400 if (request->transfer_type == gftp_transfer_active &&
401 (ret = rfc959_accept_active_connection (request)) < 0)
402 return (ret);
403
404 return (0);
405 }
406
407 static long
408 rfc959_transfer_file (gftp_request *fromreq, const char *fromfile,
409 off_t fromsize, gftp_request *toreq,
410 const char *tofile, off_t tosize)
411 {
412 char *tempstr, *pos, *endpos;
413
414 g_return_val_if_fail (fromreq != NULL, -2);
415 g_return_val_if_fail (fromfile != NULL, -2);
416 g_return_val_if_fail (toreq != NULL, -2);
417 g_return_val_if_fail (tofile != NULL, -2);
418 g_return_val_if_fail (fromreq->sockfd != NULL, -2);
419 g_return_val_if_fail (toreq->sockfd != NULL, -2);
420
421 fromreq->transfer_type = gftp_transfer_passive;
422 toreq->transfer_type = gftp_transfer_active;
423
424 if (rfc959_send_command (fromreq, "PASV\r\n") != '2' ||
425 fromreq->sockfd == NULL)
426 return (-2);
427
428 pos = fromreq->last_ftp_response + 4;
429 while (!isdigit ((int) *pos) && *pos != '\0')
430 pos++;
431 if (*pos == '\0')
432 return (-2);
433
434 endpos = pos;
435 while (*endpos != ')' && *endpos != '\0')
436 endpos++;
437 if (*endpos == ')')
438 *endpos = '\0';
439
440 tempstr = g_strconcat ("PORT ", pos, "\r\n", NULL);
441 g_free (tempstr);
442 if (rfc959_send_command (toreq, tempstr) != '2')
443 return (-2);
444
445 tempstr = g_strconcat ("RETR ", fromfile, "\r\n", NULL);
446 g_free (tempstr);
447 if (write_to_socket (fromreq, tempstr) < 0)
448 return (-1);
449
450 tempstr = g_strconcat ("STOR ", tofile, "\r\n", NULL);
451 g_free (tempstr);
452 if (write_to_socket (toreq, tempstr) < 0)
453 return (-1);
454
455 if (rfc959_read_response (fromreq) < 0)
456 return (-2);
457 if (rfc959_read_response (toreq) < 0)
458 return (-2);
459
460 return (0);
461 }
462
463
464 static int
465 rfc959_end_transfer (gftp_request * request)
466 {
467 g_return_val_if_fail (request != NULL, -2);
468 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
469 g_return_val_if_fail (request->sockfd != NULL, -2);
470
471 if (request->datafd)
472 {
473 fclose (request->datafd);
474 request->datafd = NULL;
475 }
476 return (rfc959_read_response (request) == '2' ? 0 : -2);
477 }
478
479
480 static int
481 rfc959_list_files (gftp_request * request)
482 {
483 char *tempstr, parms[3];
484 int ret;
485
486 g_return_val_if_fail (request != NULL, -2);
487 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
488 g_return_val_if_fail (request->sockfd != NULL, -2);
489
490 if ((ret = rfc959_data_connection_new (request)) < 0)
491 return (ret);
492
493 *parms = '\0';
494 strcat (parms, show_hidden_files ? "a" : "");
495 strcat (parms, resolve_symlinks ? "L" : "");
496 tempstr = g_strconcat ("LIST", *parms != '\0' ? " -" : "", parms, "\r\n",
497 NULL);
498
499 ret = rfc959_send_command (request, tempstr);
500 g_free (tempstr);
501
502 if (ret != '1')
503 return (-2);
504
505 ret = 0;
506 if (request->transfer_type == gftp_transfer_active)
507 ret = rfc959_accept_active_connection (request);
508
509 return (ret);
510 }
511
512
513 int
514 rfc959_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd)
515 {
516 char tempstr[255];
517 size_t len;
518
519 g_return_val_if_fail (request != NULL, -2);
520 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
521 g_return_val_if_fail (fle != NULL, -2);
522 g_return_val_if_fail (fd != NULL, -2);
523
524 if (request->last_dir_entry)
525 {
526 g_free (request->last_dir_entry);
527 request->last_dir_entry = NULL;
528 }
529 do
530 {
531 /* I don't run select() here because select could return
532 successfully saying there is data, but the fgets call could block if
533 there is no carriage return */
534 if (!fgets (tempstr, sizeof (tempstr), fd))
535 {
536 gftp_file_destroy (fle);
537 if (ferror (fd))
538 gftp_disconnect (request);
539 return (-2);
540 }
541 tempstr[sizeof (tempstr) - 1] = '\0';
542
543 if (gftp_parse_ls (tempstr, fle) != 0)
544 {
545 if (strncmp (tempstr, "total", strlen("total")) != 0 &&
546 strncmp (tempstr, _("total"), strlen(_("total"))) != 0)
547 request->logging_function (gftp_logging_misc, request->user_data,
548 _("Warning: Cannot parse listing %s\n"),
549 tempstr);
550 gftp_file_destroy (fle);
551 continue;
552 }
553 else
554 break;
555 }
556 while (1);
557
558 len = strlen (tempstr);
559 if (!request->cached)
560 {
561 request->last_dir_entry = g_malloc (len + 1);
562 strcpy (request->last_dir_entry, tempstr);
563 request->last_dir_entry_len = len;
564 }
565 return (len);
566 }
567
568
569 static int
570 rfc959_set_data_type (gftp_request * request, int data_type)
571 {
572 char *tempstr;
573
574 g_return_val_if_fail (request != NULL, -2);
575 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
576
577 if (request->sockfd != NULL && request->data_type != data_type)
578 {
579 if (data_type == GFTP_TYPE_BINARY)
580 tempstr = "TYPE I\r\n";
581 else
582 tempstr = "TYPE A\r\n";
583
584 if (rfc959_send_command (request, tempstr) != '2')
585 return (-2);
586 }
587 request->data_type = data_type;
588 return (0);
589 }
590
591
592 static off_t
593 rfc959_get_file_size (gftp_request * request, const char *filename)
594 {
595 char *tempstr;
596 int ret;
597
598 g_return_val_if_fail (request != NULL, 0);
599 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
600 g_return_val_if_fail (filename != NULL, 0);
601 g_return_val_if_fail (request->sockfd != NULL, 0);
602
603 tempstr = g_strconcat ("SIZE ", filename, "\r\n", NULL);
604 ret = rfc959_send_command (request, tempstr);
605 g_free (tempstr);
606 if (ret < 0)
607 return (-2);
608
609 if (*request->last_ftp_response != '2')
610 return (0);
611 return (strtol (request->last_ftp_response + 4, NULL, 10));
612 }
613
614
615 static int
616 rfc959_data_connection_new (gftp_request * request)
617 {
618 char *pos, *pos1, resp, *command;
619 struct sockaddr_in data_addr;
620 size_t data_addr_len;
621 unsigned int temp[6];
622 unsigned char ad[6];
623 int i, sock;
624
625 g_return_val_if_fail (request != NULL, -2);
626 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
627 g_return_val_if_fail (request->sockfd != NULL, -2);
628
629 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
630 {
631 request->logging_function (gftp_logging_error, request->user_data,
632 _("Failed to create a socket: %s\n"),
633 g_strerror (errno));
634 gftp_disconnect (request);
635 return (-1);
636 }
637
638 data_addr_len = sizeof (data_addr);
639 memset (&data_addr, 0, data_addr_len);
640 data_addr.sin_family = AF_INET;
641
642 if (request->transfer_type == gftp_transfer_passive)
643 {
644 if ((resp = rfc959_send_command (request, "PASV\r\n")) != '2')
645 {
646 if (request->sockfd == NULL)
647 return (-2);
648
649 request->transfer_type = gftp_transfer_active;
650 return (rfc959_data_connection_new (request));
651 }
652 pos = request->last_ftp_response + 4;
653 while (!isdigit ((int) *pos) && *pos != '\0')
654 pos++;
655 if (*pos == '\0')
656 {
657 gftp_disconnect (request);
658 close (sock);
659 return (-2);
660 }
661 if (sscanf (pos, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
662 &temp[3], &temp[4], &temp[5]) != 6)
663 {
664 gftp_disconnect (request);
665 close (sock);
666 return (-2);
667 }
668 for (i = 0; i < 6; i++)
669 ad[i] = (unsigned char) (temp[i] & 0xff);
670
671 memcpy (&data_addr.sin_addr, &ad[0], 4);
672 memcpy (&data_addr.sin_port, &ad[4], 2);
673 if (connect (sock, (struct sockaddr *) &data_addr, data_addr_len) == -1)
674 {
675 request->logging_function (gftp_logging_error, request->user_data,
676 _("Cannot create a data connection: %s\n"),
677 g_strerror (errno));
678 gftp_disconnect (request);
679 close (sock);
680 return (-1);
681 }
682 }
683 else
684 {
685 getsockname (fileno (request->sockfd), (struct sockaddr *) &data_addr,
686 &data_addr_len);
687 data_addr.sin_port = 0;
688 if (bind (sock, (struct sockaddr *) &data_addr, data_addr_len) == -1)
689 {
690 request->logging_function (gftp_logging_error, request->user_data,
691 _("Cannot bind a port: %s\n"),
692 g_strerror (errno));
693 gftp_disconnect (request);
694 close (sock);
695 return (-1);
696 }
697
698 getsockname (sock, (struct sockaddr *) &data_addr, &data_addr_len);
699 if (listen (sock, 1) == -1)
700 {
701 request->logging_function (gftp_logging_error, request->user_data,
702 _("Cannot listen on port %d: %s\n"),
703 ntohs (data_addr.sin_port),
704 g_strerror (errno));
705 gftp_disconnect (request);
706 close (sock);
707 return (-1);
708 }
709 pos = (char *) &data_addr.sin_addr;
710 pos1 = (char *) &data_addr.sin_port;
711 command = g_strdup_printf ("PORT %u,%u,%u,%u,%u,%u\r\n",
712 pos[0] & 0xff, pos[1] & 0xff, pos[2] & 0xff,
713 pos[3] & 0xff, pos1[0] & 0xff,
714 pos1[1] & 0xff);
715 resp = rfc959_send_command (request, command);
716 g_free (command);
717 if (resp != '2')
718 {
719 gftp_disconnect (request);
720 close (sock);
721 return (-2);
722 }
723 }
724
725 if ((request->datafd = fdopen (sock, "rb+")) == NULL)
726 {
727 request->logging_function (gftp_logging_error, request->user_data,
728 _("Cannot fdopen() socket: %s\n"),
729 g_strerror (errno));
730 gftp_disconnect (request);
731 return (-2);
732 }
733
734 return (0);
735 }
736
737
738 static int
739 rfc959_accept_active_connection (gftp_request * request)
740 {
741 struct sockaddr_in cli_addr;
742 size_t cli_addr_len;
743 int infd;
744
745 g_return_val_if_fail (request != NULL, -2);
746 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
747 g_return_val_if_fail (request->datafd != NULL, -2);
748 g_return_val_if_fail (request->transfer_type == gftp_transfer_active, -2);
749
750 cli_addr_len = sizeof (cli_addr);
751 if ((infd = accept (fileno (request->datafd), (struct sockaddr *) &cli_addr,
752 &cli_addr_len)) == -1)
753 {
754 request->logging_function (gftp_logging_error, request->user_data,
755 _("Cannot accept connection from server: %s\n"),
756 g_strerror (errno));
757 gftp_disconnect (request);
758 return (-1);
759 }
760
761 fclose (request->datafd);
762
763 if ((request->datafd = fdopen (infd, "rb+")) == NULL)
764 {
765 request->logging_function (gftp_logging_error, request->user_data,
766 _("Cannot fdopen() socket: %s\n"),
767 g_strerror (errno));
768 gftp_disconnect (request);
769 return (-2);
770 }
771 return (0);
772 }
773
774
775 static int
776 rfc959_send_command (gftp_request * request, const char *command)
777 {
778 g_return_val_if_fail (request != NULL, -2);
779 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
780 g_return_val_if_fail (command != NULL, -2);
781 g_return_val_if_fail (request->sockfd != NULL, -2);
782
783 if (strncmp (command, "PASS", 4) == 0)
784 {
785 request->logging_function (gftp_logging_send, request->user_data,
786 "PASS xxxx\n");
787 }
788 else if (strncmp (command, "ACCT", 4) == 0)
789 {
790 request->logging_function (gftp_logging_send, request->user_data,
791 "ACCT xxxx\n");
792 }
793 else
794 {
795 request->logging_function (gftp_logging_send, request->user_data, "%s",
796 command);
797 }
798
799 if (write_to_socket (request, command) < 0)
800 {
801 gftp_disconnect (request);
802 return (-1);
803 }
804
805 return (rfc959_read_response (request));
806 }
807
808 static int
809 write_to_socket (gftp_request *request, const char *command)
810 {
811 struct timeval tv;
812 fd_set fset;
813
814 FD_ZERO (&fset);
815 FD_SET (fileno (request->sockfd_write), &fset);
816 tv.tv_sec = request->network_timeout;
817 tv.tv_usec = 0;
818 if (!select (fileno (request->sockfd_write) + 1, NULL, &fset, NULL, &tv))
819 {
820 request->logging_function (gftp_logging_error, request->user_data,
821 _("Connection to %s timed out\n"),
822 request->hostname);
823 gftp_disconnect (request);
824 return (-1);
825 }
826
827 fwrite (command, strlen (command), 1, request->sockfd_write);
828 if (ferror (request->sockfd_write))
829 {
830 request->logging_function (gftp_logging_error, request->user_data,
831 _("Error: Could not write to socket: %s\n"),
832 g_strerror (errno));
833 gftp_disconnect (request);
834 return (-1);
835 }
836
837 fflush (request->sockfd_write);
838 if (ferror (request->sockfd_write))
839 {
840 request->logging_function (gftp_logging_error, request->user_data,
841 _("Error: Could not write to socket: %s\n"),
842 g_strerror (errno));
843 gftp_disconnect (request);
844 return (-1);
845 }
846
847 return (0);
848 }
849
850
851
852 static int
853 rfc959_read_response (gftp_request * request)
854 {
855 char tempstr[255], code[4];
856
857 g_return_val_if_fail (request != NULL, -2);
858 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
859 g_return_val_if_fail (request->sockfd != NULL, -2);
860
861 *code = '\0';
862 if (request->last_ftp_response)
863 {
864 g_free (request->last_ftp_response);
865 request->last_ftp_response = NULL;
866 }
867
868 do
869 {
870 /* I don't run select() here because select could return
871 successfully saying there is data, but the fgets call could block if
872 there is no carriage return */
873 if (!fgets (tempstr, sizeof (tempstr), request->sockfd))
874 break;
875 tempstr[strlen (tempstr) - 1] = '\0';
876 if (tempstr[strlen (tempstr) - 1] == '\r')
877 tempstr[strlen (tempstr) - 1] = '\0';
878 if (isdigit ((int) *tempstr) && isdigit ((int) *(tempstr + 1))
879 && isdigit ((int) *(tempstr + 2)))
880 {
881 strncpy (code, tempstr, 3);
882 code[3] = ' ';
883 }
884 request->logging_function (gftp_logging_recv, request->user_data,
885 "%s\n", tempstr);
886 }
887 while (strncmp (code, tempstr, 4) != 0);
888
889 if (ferror (request->sockfd))
890 {
891 request->logging_function (gftp_logging_send, request->user_data,
892 "Error reading from socket: %s\n",
893 g_strerror (errno));
894 gftp_disconnect (request);
895 return (-1);
896 }
897
898 request->last_ftp_response = g_malloc (strlen (tempstr) + 1);
899 strcpy (request->last_ftp_response, tempstr);
900
901 if (*request->last_ftp_response == '4')
902 gftp_disconnect (request);
903
904 return (*request->last_ftp_response);
905 }
906
907
908 static int
909 rfc959_chdir (gftp_request * request, const char *directory)
910 {
911 char ret, *tempstr, *dir;
912
913 g_return_val_if_fail (request != NULL, -2);
914 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
915 g_return_val_if_fail (directory != NULL, -2);
916
917 if (strcmp (directory, "..") == 0)
918 ret = rfc959_send_command (request, "CDUP\r\n");
919 else
920 {
921 tempstr = g_strconcat ("CWD ", directory, "\r\n", NULL);
922 ret = rfc959_send_command (request, tempstr);
923 g_free (tempstr);
924 }
925
926 if (ret != '2')
927 return (-2);
928
929 if (directory != request->directory)
930 {
931 if (request->directory)
932 {
933 g_free (request->directory);
934 request->directory = NULL;
935 }
936
937 if (rfc959_send_command (request, "PWD\r\n") != '2')
938 return (-2);
939
940 tempstr = strchr (request->last_ftp_response, '"');
941 if (tempstr != NULL)
942 dir = tempstr + 1;
943 else
944 return (-2);
945
946 tempstr = strchr (dir, '"');
947 if (tempstr != NULL)
948 *tempstr = '\0';
949 else
950 {
951 gftp_disconnect (request);
952 return (-2);
953 }
954
955 request->directory = g_malloc (strlen (dir) + 1);
956 strcpy (request->directory, dir);
957 }
958
959 return (0);
960 }
961
962
963 static int
964 rfc959_rmdir (gftp_request * request, const char *directory)
965 {
966 char *tempstr, ret;
967
968 g_return_val_if_fail (request != NULL, -2);
969 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
970 g_return_val_if_fail (directory != NULL, -2);
971 g_return_val_if_fail (request->sockfd != NULL, -2);
972
973 tempstr = g_strconcat ("RMD ", directory, "\r\n", NULL);
974 ret = rfc959_send_command (request, tempstr);
975 g_free (tempstr);
976 return (ret == '2' ? 0 : -2);
977 }
978
979
980 static int
981 rfc959_rmfile (gftp_request * request, const char *file)
982 {
983 char *tempstr, ret;
984
985 g_return_val_if_fail (request != NULL, -2);
986 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
987 g_return_val_if_fail (file != NULL, -2);
988 g_return_val_if_fail (request->sockfd != NULL, -2);
989
990 tempstr = g_strconcat ("DELE ", file, "\r\n", NULL);
991 ret = rfc959_send_command (request, tempstr);
992 g_free (tempstr);
993 return (ret == '2' ? 0 : -2);
994 }
995
996
997 static int
998 rfc959_mkdir (gftp_request * request, const char *directory)
999 {
1000 char *tempstr, ret;
1001
1002 g_return_val_if_fail (request != NULL, -2);
1003 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
1004 g_return_val_if_fail (directory != NULL, -2);
1005 g_return_val_if_fail (request->sockfd != NULL, -2);
1006
1007 tempstr = g_strconcat ("MKD ", directory, "\r\n", NULL);
1008 ret = rfc959_send_command (request, tempstr);
1009 g_free (tempstr);
1010 return (ret == '2' ? 0 : -2);
1011 }
1012
1013
1014 static int
1015 rfc959_rename (gftp_request * request, const char *oldname,
1016 const char *newname)
1017 {
1018 char *tempstr, ret;
1019
1020 g_return_val_if_fail (request != NULL, -2);
1021 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
1022 g_return_val_if_fail (oldname != NULL, -2);
1023 g_return_val_if_fail (newname != NULL, -2);
1024 g_return_val_if_fail (request->sockfd != NULL, -2);
1025
1026 tempstr = g_strconcat ("RNFR ", oldname, "\r\n", NULL);
1027 ret = rfc959_send_command (request, tempstr);
1028 g_free (tempstr);
1029 if (ret != '3')
1030 return (-2);
1031
1032 tempstr = g_strconcat ("RNTO ", newname, "\r\n", NULL);
1033 ret = rfc959_send_command (request, tempstr);
1034 g_free (tempstr);
1035 return (ret == '2' ? 0 : -2);
1036 }
1037
1038
1039 static int
1040 rfc959_chmod (gftp_request * request, const char *file, int mode)
1041 {
1042 char *tempstr, ret;
1043
1044 g_return_val_if_fail (request != NULL, -2);
1045 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
1046 g_return_val_if_fail (file != NULL, -2);
1047 g_return_val_if_fail (request->sockfd != NULL, -2);
1048
1049 tempstr = g_malloc (strlen (file) + (mode / 10) + 16);
1050 sprintf (tempstr, "SITE CHMOD %d %s\r\n", mode, file);
1051 ret = rfc959_send_command (request, tempstr);
1052 g_free (tempstr);
1053 return (ret == '2' ? 0 : -2);
1054 }
1055
1056
1057 static int
1058 rfc959_site (gftp_request * request, const char *command)
1059 {
1060 char *tempstr, ret;
1061
1062 g_return_val_if_fail (request != NULL, -2);
1063 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, -2);
1064 g_return_val_if_fail (command != NULL, -2);
1065 g_return_val_if_fail (request->sockfd != NULL, -2);
1066
1067 tempstr = g_strconcat ("SITE ", command, "\r\n", NULL);
1068 ret = rfc959_send_command (request, tempstr);
1069 g_free (tempstr);
1070 return (request->sockfd != NULL ? ret : -2);
1071 }
1072
1073
1074 static char *
1075 parse_ftp_proxy_string (gftp_request * request)
1076 {
1077 char *startpos, *endpos, *oldstr, *newstr, *newval, *tempport;
1078
1079 g_return_val_if_fail (request != NULL, NULL);
1080 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, NULL);
1081
1082 newstr = g_malloc (1);
1083 *newstr = '\0';
1084 startpos = endpos = request->proxy_config;
1085 while (*endpos != '\0')
1086 {
1087 tempport = NULL;
1088 if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'p')
1089 {
1090 switch (tolower ((int) *(endpos + 2)))
1091 {
1092 case 'u':
1093 newval = request->proxy_username;
1094 break;
1095 case 'p':
1096 newval = request->proxy_password;
1097 break;
1098 case 'h':
1099 newval = request->proxy_hostname;
1100 break;
1101 case 'o':
1102 tempport = g_strdup_printf ("%d", request->proxy_port);
1103 newval = tempport;
1104 break;
1105 case 'a':
1106 newval = request->proxy_account;
1107 break;
1108 default:
1109 endpos++;
1110 continue;
1111 }
1112 }
1113 else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'h')
1114 {
1115 switch (tolower ((int) *(endpos + 2)))
1116 {
1117 case 'u':
1118 newval = request->username;
1119 break;
1120 case 'p':
1121 newval = request->password;
1122 break;
1123 case 'h':
1124 newval = request->hostname;
1125 break;
1126 case 'o':
1127 tempport = g_strdup_printf ("%d", request->port);
1128 newval = tempport;
1129 break;
1130 case 'a':
1131 newval = request->account;
1132 break;
1133 default:
1134 endpos++;
1135 continue;
1136 }
1137 }
1138 else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'n')
1139 {
1140 *endpos = '\0';
1141 oldstr = newstr;
1142 newstr = g_strconcat (oldstr, startpos, "\r\n", NULL);
1143 g_free (oldstr);
1144 endpos += 2;
1145 startpos = endpos;
1146 continue;
1147 }
1148 else
1149 {
1150 endpos++;
1151 continue;
1152 }
1153
1154 *endpos = '\0';
1155 oldstr = newstr;
1156 if (!newval)
1157 newstr = g_strconcat (oldstr, startpos, NULL);
1158 else
1159 newstr = g_strconcat (oldstr, startpos, newval, NULL);
1160 if (tempport)
1161 {
1162 g_free (tempport);
1163 tempport = NULL;
1164 }
1165 g_free (oldstr);
1166 endpos += 3;
1167 startpos = endpos;
1168 }
1169 return (newstr);
1170 }
1171